From 8a127e2054683479d3999ad99ba7ff76c193aa1a Mon Sep 17 00:00:00 2001 From: AppaRao Puli Date: Wed, 5 Sep 2018 14:16:54 +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 --- ethernet_interface.cpp | 116 +++++++++++++++++++++++++++++++++++++++++ ethernet_interface.hpp | 39 +++++++++++++- network_manager.cpp | 104 ++++++++++++++++++++++++++++++++++++ network_manager.hpp | 9 ++++ 4 files changed, 267 insertions(+), 1 deletion(-) diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp index 2375482..c3edd4b 100644 --- a/ethernet_interface.cpp +++ b/ethernet_interface.cpp @@ -37,6 +37,9 @@ using namespace phosphor::logging; using namespace sdbusplus::xyz::openbmc_project::Common::Error; using Argument = xyz::openbmc_project::Common::InvalidArgument; +static constexpr const char* networkChannelCfgFile = + "/var/channel_intf_data.json"; +static constexpr const char* defaultChannelPriv = "priv-admin"; EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath, bool dhcpEnabled, Manager& parent, @@ -56,6 +59,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus, EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo)); EthernetInterfaceIntf::speed(std::get<0>(ifInfo)); + getChannelPrivilege(intfName); // Emit deferred signal. if (emitSignal) @@ -823,5 +827,117 @@ void EthernetInterface::deleteAll() manager.writeToConfigurationFile(); } +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 (!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/ethernet_interface.hpp b/ethernet_interface.hpp index 60c56e3..3e4cf12 100644 --- a/ethernet_interface.hpp +++ b/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,10 +35,15 @@ 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; +using DbusVariant = + sdbusplus::message::variant>; + namespace fs = std::experimental::filesystem; class Manager; // forward declaration of network manager. @@ -195,6 +204,14 @@ class EthernetInterface : public Ifaces */ void deleteAll(); + /** @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::dHCPEnabled; using EthernetInterfaceIntf::interfaceName; using MacAddressIntf::mACAddress; @@ -291,6 +308,26 @@ class EthernetInterface : public Ifaces std::string objPath; friend class TestEthernetInterface; + + /** @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/network_manager.cpp b/network_manager.cpp index 043d7a2..75f4e5f 100644 --- a/network_manager.cpp +++ b/network_manager.cpp @@ -34,6 +34,13 @@ extern std::unique_ptr restartTimer; 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), @@ -41,6 +48,103 @@ 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; + } + + sdbusplus::message::variant> result; + reply.read(result); + + supportedPrivList = + sdbusplus::message::variant_ns::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 = sdbusplus::message::variant_ns::get< + std::vector>(t.second); + } + } + }); + } + return; } bool Manager::createDefaultNetworkFiles(bool force) diff --git a/network_manager.hpp b/network_manager.hpp index edb341f..e16b205 100644 --- a/network_manager.hpp +++ b/network_manager.hpp @@ -137,6 +137,9 @@ class Manager : public details::VLANCreateIface return (interfaces.find(intf) != interfaces.end()); } + /** supported privilege list **/ + std::vector supportedPrivList; + protected: /** @brief Persistent sdbusplus DBus bus connection. */ sdbusplus::bus::bus& bus; @@ -159,6 +162,12 @@ class Manager : public details::VLANCreateIface /** @brief Network Configuration directory. */ fs::path confDir; + + /** Get the user management service name dynamically **/ + std::string getUserServiceName(); + + /** @brief initializes the supportedPrivilege List */ + void initSupportedPrivilges(); }; } // namespace network -- 2.21.0