diff options
-rw-r--r-- | phosphor-ldap-config/ldap_configuration.cpp | 210 | ||||
-rw-r--r-- | phosphor-ldap-config/ldap_configuration.hpp | 71 | ||||
-rw-r--r-- | test/ldap_config_test.cpp | 80 | ||||
-rw-r--r-- | user_mgr.cpp | 201 | ||||
-rw-r--r-- | user_mgr.hpp | 57 |
5 files changed, 526 insertions, 93 deletions
diff --git a/phosphor-ldap-config/ldap_configuration.cpp b/phosphor-ldap-config/ldap_configuration.cpp index a54db9b..413998a 100644 --- a/phosphor-ldap-config/ldap_configuration.cpp +++ b/phosphor-ldap-config/ldap_configuration.cpp @@ -27,9 +27,11 @@ Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath, const char* caCertFile, bool secureLDAP, std::string lDAPServerURI, std::string lDAPBindDN, std::string lDAPBaseDN, std::string&& lDAPBindDNPassword, - ldap_base::Config::SearchScope lDAPSearchScope, - ldap_base::Config::Type lDAPType, ConfigMgr& parent) : - ConfigIface(bus, path, true), + ConfigIface::SearchScope lDAPSearchScope, + ConfigIface::Type lDAPType, bool lDAPServiceEnabled, + std::string userNameAttr, std::string groupNameAttr, + ConfigMgr& parent) : + Ifaces(bus, path, true), secureLDAP(secureLDAP), configFilePath(filePath), tlsCacertFile(caCertFile), lDAPBindDNPassword(std::move(lDAPBindDNPassword)), bus(bus), parent(parent) { @@ -38,9 +40,13 @@ Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath, ConfigIface::lDAPBaseDN(lDAPBaseDN); ConfigIface::lDAPSearchScope(lDAPSearchScope); ConfigIface::lDAPType(lDAPType); + EnableIface::enabled(lDAPServiceEnabled); + ConfigIface::userNameAttribute(userNameAttr); + ConfigIface::groupNameAttribute(groupNameAttr); writeConfig(); // Emit deferred signal. this->emit_object_added(); + parent.startOrStopService(nslcdService, enabled()); } void Config::delete_() @@ -68,6 +74,7 @@ void Config::writeConfig() { std::stringstream confData; auto isPwdTobeWritten = false; + std::string userNameAttr; confData << "uid root\n"; confData << "gid root\n\n"; @@ -87,13 +94,13 @@ void Config::writeConfig() confData << "\n"; switch (lDAPSearchScope()) { - case ldap_base::Config::SearchScope::sub: + case ConfigIface::SearchScope::sub: confData << "scope sub\n\n"; break; - case ldap_base::Config::SearchScope::one: + case ConfigIface::SearchScope::one: confData << "scope one\n\n"; break; - case ldap_base::Config::SearchScope::base: + case ConfigIface::SearchScope::base: confData << "scope base\n\n"; break; } @@ -110,30 +117,52 @@ void Config::writeConfig() confData << "ssl off\n"; } confData << "\n"; - if (lDAPType() == ldap_base::Config::Type::ActiveDirectory) + if (lDAPType() == ConfigIface::Type::ActiveDirectory) { + if (ConfigIface::userNameAttribute().empty()) + { + ConfigIface::userNameAttribute("sAMAccountName"); + } + if (ConfigIface::groupNameAttribute().empty()) + { + ConfigIface::groupNameAttribute("primaryGroupID"); + } confData << "filter passwd (&(objectClass=user)(objectClass=person)" "(!(objectClass=computer)))\n"; confData << "filter group (|(objectclass=group)(objectclass=groupofnames) " "(objectclass=groupofuniquenames))\n"; - confData << "map passwd uid sAMAccountName\n"; + confData << "map passwd uid " + << ConfigIface::userNameAttribute() << "\n"; confData << "map passwd uidNumber " "objectSid:S-1-5-21-3623811015-3361044348-30300820\n"; - confData << "map passwd gidNumber primaryGroupID\n"; + confData << "map passwd gidNumber " + << ConfigIface::groupNameAttribute() << "\n"; confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n"; confData << "map passwd gecos displayName\n"; confData << "map passwd loginShell \"/bin/bash\"\n"; - confData << "map group gidNumber primaryGroupID\n"; confData << "map group gidNumber " "objectSid:S-1-5-21-3623811015-3361044348-30300820\n"; - confData << "map group cn sAMAccountName\n"; + confData << "map group cn " + << ConfigIface::userNameAttribute() << "\n"; } - else if (lDAPType() == ldap_base::Config::Type::OpenLdap) + else if (lDAPType() == ConfigIface::Type::OpenLdap) { + if (ConfigIface::userNameAttribute().empty()) + { + ConfigIface::userNameAttribute("uid"); + } + if (ConfigIface::groupNameAttribute().empty()) + { + ConfigIface::groupNameAttribute("gid"); + } confData << "filter passwd (objectclass=*)\n"; confData << "map passwd gecos displayName\n"; confData << "filter group (objectclass=posixGroup)\n"; + confData << "map passwd uid " + << ConfigIface::userNameAttribute() << "\n"; + confData << "map passwd gidNumber " + << ConfigIface::groupNameAttribute() << "\n"; } try { @@ -197,7 +226,7 @@ std::string Config::lDAPServerURI(std::string value) } val = ConfigIface::lDAPServerURI(value); writeConfig(); - parent.restartService(nslcdService); + parent.startOrStopService(nslcdService, enabled()); } catch (const InternalFailure& e) { @@ -239,7 +268,7 @@ std::string Config::lDAPBindDN(std::string value) val = ConfigIface::lDAPBindDN(value); writeConfig(); - parent.restartService(nslcdService); + parent.startOrStopService(nslcdService, enabled()); } catch (const InternalFailure& e) { @@ -277,7 +306,7 @@ std::string Config::lDAPBaseDN(std::string value) val = ConfigIface::lDAPBaseDN(value); writeConfig(); - parent.restartService(nslcdService); + parent.startOrStopService(nslcdService, enabled()); } catch (const InternalFailure& e) { @@ -295,10 +324,9 @@ std::string Config::lDAPBaseDN(std::string value) return val; } -ldap_base::Config::SearchScope - Config::lDAPSearchScope(ldap_base::Config::SearchScope value) +ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value) { - ldap_base::Config::SearchScope val; + ConfigIface::SearchScope val; try { if (value == lDAPSearchScope()) @@ -308,7 +336,7 @@ ldap_base::Config::SearchScope val = ConfigIface::lDAPSearchScope(value); writeConfig(); - parent.restartService(nslcdService); + parent.startOrStopService(nslcdService, enabled()); } catch (const InternalFailure& e) { @@ -322,9 +350,9 @@ ldap_base::Config::SearchScope return val; } -ldap_base::Config::Type Config::lDAPType(ldap_base::Config::Type value) +ConfigIface::Type Config::lDAPType(ConfigIface::Type value) { - ldap_base::Config::Type val; + ConfigIface::Type val; try { if (value == lDAPType()) @@ -334,7 +362,83 @@ ldap_base::Config::Type Config::lDAPType(ldap_base::Config::Type value) val = ConfigIface::lDAPType(value); writeConfig(); - parent.restartService(nslcdService); + parent.startOrStopService(nslcdService, enabled()); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log<level::ERR>(e.what()); + elog<InternalFailure>(); + } + return val; +} + +bool Config::enabled(bool value) +{ + bool isEnable; + try + { + if (value == enabled()) + { + return value; + } + isEnable = EnableIface::enabled(value); + parent.startOrStopService(nslcdService, value); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log<level::ERR>(e.what()); + elog<InternalFailure>(); + } + return isEnable; +} + +std::string Config::userNameAttribute(std::string value) +{ + std::string val; + try + { + if (value == userNameAttribute()) + { + return value; + } + + val = ConfigIface::userNameAttribute(value); + writeConfig(); + parent.startOrStopService(nslcdService, enabled()); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log<level::ERR>(e.what()); + elog<InternalFailure>(); + } + return val; +} + +std::string Config::groupNameAttribute(std::string value) +{ + std::string val; + try + { + if (value == groupNameAttribute()) + { + return value; + } + + val = ConfigIface::groupNameAttribute(value); + writeConfig(); + parent.startOrStopService(nslcdService, enabled()); } catch (const InternalFailure& e) { @@ -348,6 +452,18 @@ ldap_base::Config::Type Config::lDAPType(ldap_base::Config::Type value) return val; } +void ConfigMgr::startOrStopService(const std::string& service, bool start) +{ + if (start) + { + restartService(service); + } + else + { + stopService(service); + } +} + void ConfigMgr::restartService(const std::string& service) { try @@ -389,12 +505,11 @@ void ConfigMgr::deleteObject() configPtr.reset(nullptr); } -std::string - ConfigMgr::createConfig(std::string lDAPServerURI, std::string lDAPBindDN, - std::string lDAPBaseDN, - std::string lDAPBindDNPassword, - ldap_base::Create::SearchScope lDAPSearchScope, - ldap_base::Create::Type lDAPType) +std::string ConfigMgr::createConfig( + std::string lDAPServerURI, std::string lDAPBindDN, std::string lDAPBaseDN, + std::string lDAPBindDNPassword, CreateIface::SearchScope lDAPSearchScope, + CreateIface::Create::Type lDAPType, std::string groupNameAttribute, + std::string userNameAttribute) { bool secureLDAP = false; @@ -445,10 +560,10 @@ std::string bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(), secureLDAP, lDAPServerURI, lDAPBindDN, lDAPBaseDN, std::move(lDAPBindDNPassword), - static_cast<ldap_base::Config::SearchScope>(lDAPSearchScope), - static_cast<ldap_base::Config::Type>(lDAPType), *this); + static_cast<ConfigIface::SearchScope>(lDAPSearchScope), + static_cast<ConfigIface::Type>(lDAPType), false, groupNameAttribute, + userNameAttribute, *this); - restartService(nslcdService); restartService(nscdService); return objPath; } @@ -515,42 +630,47 @@ void ConfigMgr::restore(const char* filePath) { continue; } - // skip the line if it starts with "map passwd". + // if config type is AD "map group" entry would be add to // the map configValues. For OpenLdap config file no map // entry would be there. if ((key == "map") && (value == "passwd")) { - continue; + key = key + "_" + value; + if (std::getline(isLine, value, ' ')) + { + key += "_" + value; + } + std::getline(isLine, value, ' '); } configValues[key] = value; } } } - ldap_base::Create::SearchScope lDAPSearchScope; + CreateIface::SearchScope lDAPSearchScope; if (configValues["scope"] == "sub") { - lDAPSearchScope = ldap_base::Create::SearchScope::sub; + lDAPSearchScope = CreateIface::SearchScope::sub; } else if (configValues["scope"] == "one") { - lDAPSearchScope = ldap_base::Create::SearchScope::one; + lDAPSearchScope = CreateIface::SearchScope::one; } else { - lDAPSearchScope = ldap_base::Create::SearchScope::base; + lDAPSearchScope = CreateIface::SearchScope::base; } - ldap_base::Create::Type lDAPType; + CreateIface::Type lDAPType; // If the file is having a line which starts with "map group" if (configValues["map"] == "group") { - lDAPType = ldap_base::Create::Type::ActiveDirectory; + lDAPType = CreateIface::Type::ActiveDirectory; } else { - lDAPType = ldap_base::Create::Type::OpenLdap; + lDAPType = CreateIface::Type::OpenLdap; } // Don't create the config object if either of the field is empty. @@ -565,10 +685,12 @@ void ConfigMgr::restore(const char* filePath) return; } - createConfig( - std::move(configValues["uri"]), std::move(configValues["binddn"]), - std::move(configValues["base"]), std::move(configValues["bindpw"]), - lDAPSearchScope, lDAPType); + createConfig(std::move(configValues["uri"]), + std::move(configValues["binddn"]), + std::move(configValues["base"]), + std::move(configValues["bindpw"]), lDAPSearchScope, + lDAPType, std::move(configValues["map_passwd_uid"]), + std::move(configValues["map_passwd_gidNumber"])); } catch (const InvalidArgument& e) { diff --git a/phosphor-ldap-config/ldap_configuration.hpp b/phosphor-ldap-config/ldap_configuration.hpp index ad2c52a..0d69f08 100644 --- a/phosphor-ldap-config/ldap_configuration.hpp +++ b/phosphor-ldap-config/ldap_configuration.hpp @@ -2,6 +2,7 @@ #include "config.h" #include <xyz/openbmc_project/Object/Delete/server.hpp> +#include <xyz/openbmc_project/Object/Enable/server.hpp> #include <xyz/openbmc_project/User/Ldap/Config/server.hpp> #include <xyz/openbmc_project/User/Ldap/Create/server.hpp> #include <xyz/openbmc_project/Common/error.hpp> @@ -21,10 +22,13 @@ static constexpr auto nsSwitchFile = "nsswitch.conf"; using namespace phosphor::logging; using namespace sdbusplus::xyz::openbmc_project::Common::Error; -namespace ldap_base = sdbusplus::xyz::openbmc_project::User::Ldap::server; -using ConfigIface = sdbusplus::server::object::object< - ldap_base::Config, sdbusplus::xyz::openbmc_project::Object::server::Delete>; -using CreateIface = sdbusplus::server::object::object<ldap_base::Create>; +using ConfigIface = sdbusplus::xyz::openbmc_project::User::Ldap::server::Config; +using EnableIface = sdbusplus::xyz::openbmc_project::Object::server::Enable; +using DeleteIface = sdbusplus::xyz::openbmc_project::Object::server::Delete; +using Ifaces = + sdbusplus::server::object::object<ConfigIface, EnableIface, DeleteIface>; +using CreateIface = sdbusplus::server::object::object< + sdbusplus::xyz::openbmc_project::User::Ldap::server::Create>; class ConfigMgr; @@ -33,7 +37,7 @@ class ConfigMgr; * @details concrete implementation of xyz.openbmc_project.User.Ldap.Config * API, in order to provide LDAP configuration. */ -class Config : public ConfigIface +class Config : public Ifaces { public: Config() = delete; @@ -55,7 +59,14 @@ class Config : public ConfigIface * @param[in] lDAPBindDNPassword - credentials with which to bind. * @param[in] lDAPSearchScope - the search scope. * @param[in] lDAPType - Specifies the LDAP server type which can be AD - or openLDAP. + * or openLDAP. + * @param[in] lDAPServiceEnabled - Specifies whether the service would be + * enabled or not. + * @param[in] groupNameAttribute - Specifies attribute name that contains + * the name of the Group in the LDAP server. + * @param[in] userNameAttribute - Specifies attribute name that contains + * the username in the LDAP server. + * * @param[in] parent - parent of config object. */ @@ -63,15 +74,19 @@ class Config : public ConfigIface const char* caCertFile, bool secureLDAP, std::string lDAPServerURI, std::string lDAPBindDN, std::string lDAPBaseDN, std::string&& lDAPBindDNPassword, - ldap_base::Config::SearchScope lDAPSearchScope, - ldap_base::Config::Type lDAPType, ConfigMgr& parent); + ConfigIface::SearchScope lDAPSearchScope, ConfigIface::Type lDAPType, + bool lDAPServiceEnabled, std::string groupNameAttribute, + std::string userNameAttribute, ConfigMgr& parent); + using ConfigIface::groupNameAttribute; using ConfigIface::lDAPBaseDN; using ConfigIface::lDAPBindDN; using ConfigIface::lDAPSearchScope; using ConfigIface::lDAPServerURI; using ConfigIface::lDAPType; using ConfigIface::setPropertyByName; + using ConfigIface::userNameAttribute; + using EnableIface::enabled; /** @brief Update the Server URI property. * @param[in] value - lDAPServerURI value to be updated. @@ -95,14 +110,32 @@ class Config : public ConfigIface * @param[in] value - lDAPSearchScope value to be updated. * @returns value of changed lDAPSearchScope. */ - ldap_base::Config::SearchScope - lDAPSearchScope(ldap_base::Config::SearchScope value) override; + ConfigIface::SearchScope + lDAPSearchScope(ConfigIface::SearchScope value) override; /** @brief Update the LDAP Type property. * @param[in] value - lDAPType value to be updated. * @returns value of changed lDAPType. */ - ldap_base::Config::Type lDAPType(ldap_base::Config::Type value) override; + ConfigIface::Type lDAPType(ConfigIface::Type value) override; + + /** @brief Update the ldapServiceEnabled property. + * @param[in] value - ldapServiceEnabled value to be updated. + * @returns value of changed ldapServiceEnabled. + */ + bool enabled(bool value) override; + + /** @brief Update the userNameAttribute property. + * @param[in] value - userNameAttribute value to be updated. + * @returns value of changed userNameAttribute. + */ + std::string userNameAttribute(std::string value) override; + + /** @brief Update the groupNameAttribute property. + * @param[in] value - groupNameAttribute value to be updated. + * @returns value of changed groupNameAttribute. + */ + std::string groupNameAttribute(std::string value) override; /** @brief Delete this D-bus object. */ @@ -175,13 +208,19 @@ class ConfigMgr : public CreateIface * @param[in] lDAPSearchScope - the search scope. * @param[in] lDAPType - Specifies the LDAP server type which can be AD or openLDAP. + * @param[in] groupNameAttribute - Specifies attribute name that contains + * the name of the Group in the LDAP server. + * @param[in] usernameAttribute - Specifies attribute name that contains + * the username in the LDAP server. * @returns the object path of the D-Bus object created. */ std::string createConfig(std::string lDAPServerURI, std::string lDAPBindDN, std::string lDAPBaseDN, std::string lDAPBindDNPassword, - ldap_base::Create::SearchScope lDAPSearchScope, - ldap_base::Create::Type lDAPType) override; + CreateIface::SearchScope lDAPSearchScope, + CreateIface::Type lDAPType, + std::string groupNameAttribute, + std::string userNameAttribute) override; /** @brief restarts given service * @param[in] service - Service to be restarted. @@ -193,6 +232,12 @@ class ConfigMgr : public CreateIface */ virtual void stopService(const std::string& service); + /** @brief start or stop the service depending on the given value + * @param[in] service - Service to be start/stop. + * @param[in] value - true to start the service otherwise stop. + */ + virtual void startOrStopService(const std::string& service, bool value); + /** @brief delete the config D-Bus object. */ void deleteObject(); diff --git a/test/ldap_config_test.cpp b/test/ldap_config_test.cpp index 819a8cf..0f22b8f 100644 --- a/test/ldap_config_test.cpp +++ b/test/ldap_config_test.cpp @@ -93,11 +93,11 @@ TEST_F(TestLDAPConfig, testCreate) tlsCacertfile.c_str()); EXPECT_CALL(manager, restartService("nslcd.service")).Times(1); EXPECT_CALL(manager, restartService("nscd.service")).Times(1); - manager.createConfig("ldap://9.194.251.136/", "cn=Users,dc=com", - "cn=Users,dc=corp", "MyLdap12", - ldap_base::Create::SearchScope::sub, - ldap_base::Create::Type::ActiveDirectory); - + manager.createConfig( + "ldap://9.194.251.136/", "cn=Users,dc=com", "cn=Users,dc=corp", + "MyLdap12", ldap_base::Create::SearchScope::sub, + ldap_base::Create::Type::ActiveDirectory, "uid", "gid"); + manager.getConfigPtr()->enabled(true); EXPECT_TRUE(fs::exists(configFilePath)); EXPECT_EQ(manager.getConfigPtr()->lDAPServerURI(), "ldap://9.194.251.136/"); EXPECT_EQ(manager.getConfigPtr()->lDAPBindDN(), "cn=Users,dc=com"); @@ -106,6 +106,8 @@ TEST_F(TestLDAPConfig, testCreate) ldap_base::Config::SearchScope::sub); EXPECT_EQ(manager.getConfigPtr()->lDAPType(), ldap_base::Config::Type::ActiveDirectory); + EXPECT_EQ(manager.getConfigPtr()->userNameAttribute(), "uid"); + EXPECT_EQ(manager.getConfigPtr()->groupNameAttribute(), "gid"); } TEST_F(TestLDAPConfig, testRestores) @@ -120,12 +122,13 @@ TEST_F(TestLDAPConfig, testRestores) EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(1); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); - managerPtr->createConfig("ldap://9.194.251.138/", "cn=Users,dc=com", - "cn=Users,dc=corp", "MyLdap12", - ldap_base::Create::SearchScope::sub, - ldap_base::Create::Type::ActiveDirectory); + managerPtr->createConfig( + "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", + "MyLdap12", ldap_base::Create::SearchScope::sub, + ldap_base::Create::Type::ActiveDirectory, "uid", "gid"); + managerPtr->getConfigPtr()->enabled(true); EXPECT_TRUE(fs::exists(configFilePath)); // Delete LDAP configuration managerPtr->deleteObject(); @@ -141,6 +144,8 @@ TEST_F(TestLDAPConfig, testRestores) ldap_base::Config::SearchScope::sub); EXPECT_EQ(managerPtr->getConfigPtr()->lDAPType(), ldap_base::Config::Type::ActiveDirectory); + EXPECT_EQ(managerPtr->getConfigPtr()->userNameAttribute(), "uid"); + EXPECT_EQ(managerPtr->getConfigPtr()->groupNameAttribute(), "gid"); delete managerPtr; } @@ -156,13 +161,14 @@ TEST_F(TestLDAPConfig, testLDAPServerURI) EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); - managerPtr->createConfig("ldap://9.194.251.138/", "cn=Users,dc=com", - "cn=Users,dc=corp", "MyLdap12", - ldap_base::Create::SearchScope::sub, - ldap_base::Create::Type::ActiveDirectory); + managerPtr->createConfig( + "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", + "MyLdap12", ldap_base::Create::SearchScope::sub, + ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); + managerPtr->getConfigPtr()->enabled(true); // Change LDAP Server URI managerPtr->getConfigPtr()->lDAPServerURI("ldap://9.194.251.139/"); EXPECT_EQ(managerPtr->getConfigPtr()->lDAPServerURI(), @@ -195,13 +201,14 @@ TEST_F(TestLDAPConfig, testLDAPBindDN) EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); - managerPtr->createConfig("ldap://9.194.251.138/", "cn=Users,dc=com", - "cn=Users,dc=corp", "MyLdap12", - ldap_base::Create::SearchScope::sub, - ldap_base::Create::Type::ActiveDirectory); + managerPtr->createConfig( + "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", + "MyLdap12", ldap_base::Create::SearchScope::sub, + ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); + managerPtr->getConfigPtr()->enabled(true); // Change LDAP BindDN managerPtr->getConfigPtr()->lDAPBindDN( "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); @@ -242,12 +249,13 @@ TEST_F(TestLDAPConfig, testLDAPBaseDN) EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); - managerPtr->createConfig("ldap://9.194.251.138/", "cn=Users,dc=com", - "cn=Users,dc=corp", "MyLdap12", - ldap_base::Create::SearchScope::sub, - ldap_base::Create::Type::ActiveDirectory); + managerPtr->createConfig( + "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", + "MyLdap12", ldap_base::Create::SearchScope::sub, + ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); + managerPtr->getConfigPtr()->enabled(true); // Change LDAP BaseDN managerPtr->getConfigPtr()->lDAPBaseDN( "cn=Administrator,cn=Users,dc=corp,dc=ibm,dc=com"); @@ -288,12 +296,13 @@ TEST_F(TestLDAPConfig, testSearchScope) EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); - managerPtr->createConfig("ldap://9.194.251.138/", "cn=Users,dc=com", - "cn=Users,dc=corp", "MyLdap12", - ldap_base::Create::SearchScope::sub, - ldap_base::Create::Type::ActiveDirectory); + managerPtr->createConfig( + "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", + "MyLdap12", ldap_base::Create::SearchScope::sub, + ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); + managerPtr->getConfigPtr()->enabled(true); // Change LDAP SearchScope managerPtr->getConfigPtr()->lDAPSearchScope( ldap_base::Config::SearchScope::one); @@ -321,12 +330,13 @@ TEST_F(TestLDAPConfig, testLDAPType) EXPECT_FALSE(fs::exists(configFilePath)); MockConfigMgr* managerPtr = new MockConfigMgr( bus, LDAP_CONFIG_ROOT, configFilePath.c_str(), tlsCacertfile.c_str()); - EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(3); + EXPECT_CALL(*managerPtr, restartService("nslcd.service")).Times(2); EXPECT_CALL(*managerPtr, restartService("nscd.service")).Times(2); - managerPtr->createConfig("ldap://9.194.251.138/", "cn=Users,dc=com", - "cn=Users,dc=corp", "MyLdap12", - ldap_base::Create::SearchScope::sub, - ldap_base::Create::Type::ActiveDirectory); + managerPtr->createConfig( + "ldap://9.194.251.138/", "cn=Users,dc=com", "cn=Users,dc=corp", + "MyLdap12", ldap_base::Create::SearchScope::sub, + ldap_base::Create::Type::ActiveDirectory, "attr1", "attr2"); + managerPtr->getConfigPtr()->enabled(true); // Change LDAP type managerPtr->getConfigPtr()->lDAPType(ldap_base::Config::Type::OpenLdap); EXPECT_EQ(managerPtr->getConfigPtr()->lDAPType(), diff --git a/user_mgr.cpp b/user_mgr.cpp index 1cbd43a..47edf7d 100644 --- a/user_mgr.cpp +++ b/user_mgr.cpp @@ -64,6 +64,18 @@ static constexpr const char *unlockTimeout = "unlock_time"; static constexpr const char *pamPasswdConfigFile = "/etc/pam.d/common-password"; static constexpr const char *pamAuthConfigFile = "/etc/pam.d/common-auth"; +// Object Manager related +static constexpr const char *ldapMgrObjBasePath = + "/xyz/openbmc_project/user/ldap"; + +// Object Mapper related +static constexpr const char *objMapperService = + "xyz.openbmc_project.ObjectMapper"; +static constexpr const char *objMapperPath = + "/xyz/openbmc_project/object_mapper"; +static constexpr const char *objMapperInterface = + "xyz.openbmc_project.ObjectMapper"; + using namespace phosphor::logging; using InsufficientPermission = sdbusplus::xyz::openbmc_project::Common::Error::InsufficientPermission; @@ -77,7 +89,6 @@ using UserNameDoesNotExist = sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameDoesNotExist; using UserNameGroupFail = sdbusplus::xyz::openbmc_project::User::Common::Error::UserNameGroupFail; - using NoResource = sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource; @@ -815,6 +826,194 @@ std::vector<std::string> UserMgr::getUsersInGroup(const std::string &groupName) return usersInGroup; } +DbusUserObj UserMgr::getPrivilegeMapperObject(void) +{ + DbusUserObj objects; + try + { + std::string basePath = "/xyz/openbmc_project/user/ldap"; + std::string interface = "xyz.openbmc_project.User.PrivilegeMapper"; + + auto ldapMgmtService = + getServiceName(std::move(basePath), std::move(interface)); + + auto method = bus.new_method_call( + ldapMgmtService.c_str(), ldapMgrObjBasePath, + "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); + + auto reply = bus.call(method); + reply.read(objects); + } + catch (const InternalFailure &e) + { + log<level::ERR>("Unable to get the User Service", + entry("WHAT=%s", e.what())); + throw; + } + catch (const sdbusplus::exception::SdBusError &e) + { + log<level::ERR>( + "Failed to excute method", entry("METHOD=%s", "GetManagedObjects"), + entry("PATH=%s", ldapMgrObjBasePath), entry("WHAT=%s", e.what())); + throw; + } + return objects; +} + +std::string UserMgr::getLdapGroupName(const std::string &userName) +{ + struct passwd pwd + { + }; + struct passwd *pwdPtr = nullptr; + auto buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (buflen < -1) + { + // Use a default size if there is no hard limit suggested by sysconf() + buflen = 1024; + } + std::vector<char> buffer(buflen); + gid_t gid = 0; + + auto status = + getpwnam_r(userName.c_str(), &pwd, buffer.data(), buflen, &pwdPtr); + // On success, getpwnam_r() returns zero, and set *pwdPtr to pwd. + // If no matching password record was found, these functions return 0 + // and store NULL in *pwdPtr + if (!status && (&pwd == pwdPtr)) + { + gid = pwd.pw_gid; + } + else + { + log<level::ERR>("User does not exist", + entry("USER_NAME=%s", userName.c_str())); + elog<UserNameDoesNotExist>(); + } + + struct group *groups = nullptr; + std::string ldapGroupName; + + while ((groups = getgrent()) != NULL) + { + if (groups->gr_gid == gid) + { + ldapGroupName = groups->gr_name; + break; + } + } + // Call endgrent() to close the group database. + endgrent(); + + return ldapGroupName; +} + +std::string UserMgr::getServiceName(std::string &&path, std::string &&intf) +{ + auto mapperCall = bus.new_method_call(objMapperService, objMapperPath, + objMapperInterface, "GetObject"); + + mapperCall.append(std::move(path)); + mapperCall.append(std::vector<std::string>({std::move(intf)})); + + auto mapperResponseMsg = bus.call(mapperCall); + + if (mapperResponseMsg.is_method_error()) + { + log<level::ERR>("Error in mapper call"); + elog<InternalFailure>(); + } + + std::map<std::string, std::vector<std::string>> mapperResponse; + mapperResponseMsg.read(mapperResponse); + + if (mapperResponse.begin() == mapperResponse.end()) + { + log<level::ERR>("Invalid response from mapper"); + elog<InternalFailure>(); + } + + return mapperResponse.begin()->first; +} + +UserInfoMap UserMgr::getUserInfo(std::string userName) +{ + UserInfoMap userInfo; + // Check whether the given user is local user or not. + if (isUserExist(userName) == true) + { + const auto &user = usersList[userName]; + userInfo.emplace("UserPrivilege", user.get()->userPrivilege()); + userInfo.emplace("UserGroups", user.get()->userGroups()); + userInfo.emplace("UserEnabled", user.get()->userEnabled()); + userInfo.emplace("UserLockedForFailedAttempt", + user.get()->userLockedForFailedAttempt()); + userInfo.emplace("RemoteUser", false); + } + else + { + std::string ldapGroupName = getLdapGroupName(userName); + if (ldapGroupName.empty()) + { + log<level::ERR>("Unable to get group name", + entry("USER_NAME=%s", userName.c_str())); + elog<InternalFailure>(); + } + + DbusUserObj objects = getPrivilegeMapperObject(); + + std::string privilege; + std::string groupName; + + try + { + for (const auto &objpath : objects) + { + auto iter = objpath.second.find( + "xyz.openbmc_project.User.PrivilegeMapperEntry"); + if (iter == objpath.second.end()) + { + log<level::ERR>( + "Error in finding privilege mapper entry interface"); + elog<InternalFailure>(); + } + for (const auto &property : iter->second) + { + auto value = + sdbusplus::message::variant_ns::get<std::string>( + property.second); + if (property.first == "GroupName") + { + groupName = value; + } + else if (property.first == "Privilege") + { + privilege = value; + } + if (groupName == ldapGroupName) + { + userInfo["UserPrivilege"] = privilege; + } + } + } + auto priv = std::get<std::string>(userInfo["UserPrivilege"]); + if (priv.empty()) + { + log<level::ERR>("LDAP group privilege mapping does not exist"); + } + } + catch (const std::bad_variant_access &e) + { + log<level::ERR>("Error while accessing variant", + entry("WHAT=%s", e.what())); + elog<InternalFailure>(); + } + userInfo.emplace("RemoteUser", true); + } + + return userInfo; +} + void UserMgr::initUserObjects(void) { // All user management lock has to be based on /etc/shadow diff --git a/user_mgr.hpp b/user_mgr.hpp index c1673f1..c78174d 100644 --- a/user_mgr.hpp +++ b/user_mgr.hpp @@ -19,6 +19,7 @@ #include <xyz/openbmc_project/User/Manager/server.hpp> #include <xyz/openbmc_project/User/AccountPolicy/server.hpp> #include <unordered_map> +#include <variant> #include "users.hpp" namespace phosphor @@ -32,6 +33,27 @@ using UserSSHLists = using AccountPolicyIface = sdbusplus::xyz::openbmc_project::User::server::AccountPolicy; +using Privilege = std::string; +using GroupList = std::vector<std::string>; +using UserEnabled = bool; +using PropertyName = std::string; + +using UserInfo = std::variant<Privilege, GroupList, UserEnabled>; +using UserInfoMap = std::map<PropertyName, UserInfo>; + +using DbusUserObjPath = sdbusplus::message::object_path; + +using DbusUserPropVariant = sdbusplus::message::variant<Privilege>; + +using DbusUserObjProperties = + std::vector<std::pair<PropertyName, DbusUserPropVariant>>; + +using Interface = std::string; + +using DbusUserObjValue = std::map<Interface, DbusUserObjProperties>; + +using DbusUserObj = std::map<DbusUserObjPath, DbusUserObjValue>; + /** @class UserMgr * @brief Responsible for managing user accounts over the D-Bus interface. */ @@ -141,6 +163,17 @@ class UserMgr : public UserMgrIface, AccountPolicyIface bool userLockedForFailedAttempt(const std::string &userName, const bool &value); + /** @brief returns user info + * Checks if user is local user, then returns map of properties of user. + * like user privilege, list of user groups, user enabled state and user + * locked state. If its not local user, then it checks if its a ldap user, + * then it gets the privilege mapping of the LDAP group. + * + * @param[in] - user name + * @return - map of user properties + **/ + UserInfoMap getUserInfo(std::string userName) override; + private: /** @brief sdbusplus handler */ sdbusplus::bus::bus &bus; @@ -275,6 +308,30 @@ class UserMgr : public UserMgrIface, AccountPolicyIface int setPamModuleArgValue(const std::string &moduleName, const std::string &argName, const std::string &argValue); + + /** @brief get service name + * method to get dbus service name + * + * @param[in] path - object path + * @param[in] intf - interface + * @return - service name + */ + std::string getServiceName(std::string &&path, std::string &&intf); + + /** @brief get LDAP group name + * method to get LDAP group name for the given LDAP user + * + * @param[in] - userName + * @return - group name + */ + std::string getLdapGroupName(const std::string &userName); + + /** @brief get privilege mapper object + * method to get dbus privilege mapper object + * + * @return - map of user object + */ + DbusUserObj getPrivilegeMapperObject(void); }; } // namespace user |