From 145778897e36f407773844b3b96847ff10306ee8 Mon Sep 17 00:00:00 2001 From: AppaRao Puli Date: Thu, 2 Apr 2020 17:06:07 +0530 Subject: [PATCH] Adding channel specific privilege to network - Adding the channel access information to the network interface object. This privilege will be used in channel specific authorization. - Get supported priv from user manager service dynamically. - Signal handling for capturing the supported priv list changes from user managerment. Tested-by: Verified channel access through ipmitool get/set channel access command Change-Id: I3b592a19363eef684e31d5f7c34dad8f2f9211df Signed-off-by: AppaRao Puli Signed-off-by: Yong Li Signed-off-by: Johnathan Mantey Signed-off-by: Ramya Narayana --- src/ethernet_interface.cpp | 124 +++++++++++++++++++++++++++++++++++++ src/ethernet_interface.hpp | 37 ++++++++++- src/network_manager.cpp | 102 ++++++++++++++++++++++++++++++ src/network_manager.hpp | 9 +++ 4 files changed, 271 insertions(+), 1 deletion(-) diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp index 2e15803..1145773 100644 --- a/src/ethernet_interface.cpp +++ b/src/ethernet_interface.cpp @@ -48,6 +48,10 @@ constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/"; constexpr auto METHOD_GET = "Get"; +static constexpr const char* networkChannelCfgFile = + "/var/channel_intf_data.json"; +static constexpr const char* defaultChannelPriv = "priv-admin"; + struct EthernetIntfSocket { EthernetIntfSocket(int domain, int type, int protocol) @@ -132,6 +136,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); #endif + getChannelPrivilege(intfName); // Emit deferred signal. if (emitSignal) @@ -1322,5 +1327,124 @@ std::string EthernetInterface::defaultGateway6(std::string gateway) return gw; } + +nlohmann::json EthernetInterface::readJsonFile(const std::string& configFile) +{ + std::ifstream jsonFile(configFile); + if (!jsonFile.good()) + { + log("JSON file not found"); + return nullptr; + } + + nlohmann::json data = nullptr; + try + { + data = nlohmann::json::parse(jsonFile, nullptr, false); + } + catch (nlohmann::json::parse_error& e) + { + log("Corrupted channel config.", + entry("MSG: %s", e.what())); + throw std::runtime_error("Corrupted channel config file"); + } + + return data; +} + +int EthernetInterface::writeJsonFile(const std::string& configFile, + const nlohmann::json& jsonData) +{ + std::ofstream jsonFile(configFile); + if (!jsonFile.good()) + { + log("JSON file open failed", + entry("FILE=%s", networkChannelCfgFile)); + return -1; + } + + // Write JSON to file + jsonFile << jsonData; + + jsonFile.flush(); + return 0; +} + +std::string + EthernetInterface::getChannelPrivilege(const std::string& interfaceName) +{ + std::string priv(defaultChannelPriv); + std::string retPriv; + + nlohmann::json jsonData = readJsonFile(networkChannelCfgFile); + if (jsonData != nullptr) + { + try + { + priv = jsonData[interfaceName].get(); + retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv)); + return retPriv; + } + catch (const nlohmann::json::exception& e) + { + jsonData[interfaceName] = priv; + } + } + else + { + jsonData[interfaceName] = priv; + } + + if (writeJsonFile(networkChannelCfgFile, jsonData) != 0) + { + log("Error in write JSON data to file", + entry("FILE=%s", networkChannelCfgFile)); + elog(); + } + + retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv)); + + return retPriv; +} + +std::string EthernetInterface::maxPrivilege(std::string priv) +{ + std::string intfName = interfaceName(); + + if (manager.supportedPrivList.empty()) + { + // Populate the supported privilege list + manager.initSupportedPrivilges(); + } + + if (!priv.empty() && (std::find(manager.supportedPrivList.begin(), + manager.supportedPrivList.end(), + priv) == manager.supportedPrivList.end())) + { + log("Invalid privilege"); + elog(Argument::ARGUMENT_NAME("Privilege"), + Argument::ARGUMENT_VALUE(priv.c_str())); + } + + if (ChannelAccessIntf::maxPrivilege() == priv) + { + // No change in privilege so just return. + return priv; + } + + nlohmann::json jsonData = readJsonFile(networkChannelCfgFile); + jsonData[intfName] = priv; + + if (writeJsonFile(networkChannelCfgFile, jsonData) != 0) + { + log("Error in write JSON data to file", + entry("FILE=%s", networkChannelCfgFile)); + elog(); + } + + // Property change signal will be sent + return ChannelAccessIntf::maxPrivilege(std::move(priv)); +} + } // namespace network } // namespace phosphor diff --git a/src/ethernet_interface.hpp b/src/ethernet_interface.hpp index 0fe3778..fa5c889 100644 --- a/src/ethernet_interface.hpp +++ b/src/ethernet_interface.hpp @@ -2,11 +2,14 @@ #include "types.hpp" #include "util.hpp" +#include "xyz/openbmc_project/Channel/ChannelAccess/server.hpp" #include "xyz/openbmc_project/Network/IP/Create/server.hpp" #include "xyz/openbmc_project/Network/Neighbor/CreateStatic/server.hpp" #include +#include #include +#include #include #include #include @@ -23,7 +26,8 @@ using Ifaces = sdbusplus::server::object::object< sdbusplus::xyz::openbmc_project::Network::server::MACAddress, sdbusplus::xyz::openbmc_project::Network::IP::server::Create, sdbusplus::xyz::openbmc_project::Network::Neighbor::server::CreateStatic, - sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>; + sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll, + sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess>; using IP = sdbusplus::xyz::openbmc_project::Network::server::IP; @@ -31,11 +35,14 @@ using EthernetInterfaceIntf = sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface; using MacAddressIntf = sdbusplus::xyz::openbmc_project::Network::server::MACAddress; +using ChannelAccessIntf = + sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess; using ServerList = std::vector; using ObjectPath = sdbusplus::message::object_path; namespace fs = std::filesystem; +using DbusVariant = std::variant>; class Manager; // forward declaration of network manager. @@ -240,6 +247,14 @@ class EthernetInterface : public Ifaces std::string defaultGateway6(std::string gateway) override; using EthernetInterfaceIntf::dhcpEnabled; + /** @brief sets the channel maxium privilege. + * @param[in] value - Channel privilege which needs to be set on the + * system. + * @returns privilege of the interface or throws an error. + */ + std::string maxPrivilege(std::string value) override; + + using ChannelAccessIntf::maxPrivilege; using EthernetInterfaceIntf::interfaceName; using EthernetInterfaceIntf::linkUp; using EthernetInterfaceIntf::mtu; @@ -372,6 +387,26 @@ class EthernetInterface : public Ifaces * @returns true/false value if the NIC is enabled */ bool queryNicEnabled() const; + + /** @brief gets the channel privilege. + * @param[in] interfaceName - Network interface name. + * @returns privilege of the interface + */ + std::string getChannelPrivilege(const std::string& interfaceName); + + /** @brief reads the channel access info from file. + * @param[in] configFile - channel access filename + * @returns json file data + */ + nlohmann::json readJsonFile(const std::string& configFile); + + /** @brief writes the channel access info to file. + * @param[in] configFile - channel access filename + * @param[in] jsonData - json data to write + * @returns success or failure + */ + int writeJsonFile(const std::string& configFile, + const nlohmann::json& jsonData); }; } // namespace network diff --git a/src/network_manager.cpp b/src/network_manager.cpp index fe59f0b..01a99a3 100644 --- a/src/network_manager.cpp +++ b/src/network_manager.cpp @@ -39,6 +39,13 @@ extern std::unique_ptr refreshObjectTimer; using namespace phosphor::logging; using namespace sdbusplus::xyz::openbmc_project::Common::Error; +static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user"; +static constexpr const char* userMgrInterface = + "xyz.openbmc_project.User.Manager"; +static constexpr const char* propNameAllPrivileges = "AllPrivileges"; + +std::unique_ptr usrMgmtSignal(nullptr); + Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath, const std::string& path) : details::VLANCreateIface(bus, objPath, true), @@ -46,6 +53,101 @@ Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath, { fs::path confDir(path); setConfDir(confDir); + initSupportedPrivilges(); +} + +std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf, + const std::string& path) +{ + auto mapperCall = + bus.new_method_call("xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetObject"); + + mapperCall.append(path); + mapperCall.append(std::vector({intf})); + + auto mapperResponseMsg = bus.call(mapperCall); + + std::map> mapperResponse; + mapperResponseMsg.read(mapperResponse); + + if (mapperResponse.begin() == mapperResponse.end()) + { + throw std::runtime_error("ERROR in reading the mapper response"); + } + + return mapperResponse.begin()->first; +} + +std::string Manager::getUserServiceName() +{ + static std::string userMgmtService; + if (userMgmtService.empty()) + { + try + { + userMgmtService = + getUserService(bus, userMgrInterface, userMgrObjBasePath); + } + catch (const std::exception& e) + { + log("Exception caught in getUserServiceName."); + userMgmtService.clear(); + } + } + return userMgmtService; +} + +void Manager::initSupportedPrivilges() +{ + std::string userServiceName = getUserServiceName(); + if (!userServiceName.empty()) + { + auto method = bus.new_method_call( + getUserServiceName().c_str(), userMgrObjBasePath, + "org.freedesktop.DBus.Properties", "Get"); + method.append(userMgrInterface, propNameAllPrivileges); + + auto reply = bus.call(method); + if (reply.is_method_error()) + { + log("get-property AllPrivileges failed", + entry("OBJPATH:%s", userMgrObjBasePath), + entry("INTERFACE:%s", userMgrInterface)); + return; + } + + std::variant> result; + reply.read(result); + + supportedPrivList = std::get>(result); + } + + // Resgister the signal + if (usrMgmtSignal == nullptr) + { + log("Registering User.Manager propertychange signal."); + usrMgmtSignal = std::make_unique( + bus, + sdbusplus::bus::match::rules::propertiesChanged(userMgrObjBasePath, + userMgrInterface), + [&](sdbusplus::message::message& msg) { + log("UserMgr properties changed signal"); + std::map props; + std::string iface; + msg.read(iface, props); + for (const auto& t : props) + { + if (t.first == propNameAllPrivileges) + { + supportedPrivList = + std::get>(t.second); + } + } + }); + } + return; } bool Manager::createDefaultNetworkFiles(bool force) diff --git a/src/network_manager.hpp b/src/network_manager.hpp index fb3cc32..0c3d49b 100644 --- a/src/network_manager.hpp +++ b/src/network_manager.hpp @@ -156,6 +156,12 @@ class Manager : public details::VLANCreateIface return routeTable; } + /** supported privilege list **/ + std::vector supportedPrivList; + + /** @brief initializes the supportedPrivilege List */ + void initSupportedPrivilges(); + protected: /** @brief Persistent sdbusplus DBus bus connection. */ sdbusplus::bus::bus& bus; @@ -181,6 +187,9 @@ class Manager : public details::VLANCreateIface /** @brief The routing table */ route::Table routeTable; + + /** Get the user management service name dynamically **/ + std::string getUserServiceName(); }; } // namespace network -- 2.25.1