From f1940d9e431eecfd900b2532d1255709fa416814 Mon Sep 17 00:00:00 2001 From: Nagaraju Goruganti Date: Tue, 18 Sep 2018 05:05:50 -0500 Subject: phosphor-ldap-conf: implement restore and add error handling Upon startup, restore D-Bus properties from LDAP config file if it exists. Change-Id: I63b5a41eec8937ddbd5e8b4471936376602b6b0e Signed-off-by: Nagaraju Goruganti --- phosphor-ldap-config/ldap_configuration.cpp | 359 +++++++++++++++++++++++----- phosphor-ldap-config/ldap_configuration.hpp | 30 ++- 2 files changed, 327 insertions(+), 62 deletions(-) diff --git a/phosphor-ldap-config/ldap_configuration.cpp b/phosphor-ldap-config/ldap_configuration.cpp index 06a4d5d..6680541 100644 --- a/phosphor-ldap-config/ldap_configuration.cpp +++ b/phosphor-ldap-config/ldap_configuration.cpp @@ -1,7 +1,5 @@ -#include -#include #include "ldap_configuration.hpp" -#include "config.h" +#include #include #include @@ -11,6 +9,15 @@ namespace ldap { constexpr auto nslcdService = "nslcd.service"; +using namespace phosphor::logging; +using namespace sdbusplus::xyz::openbmc_project::Common::Error; +namespace fs = std::experimental::filesystem; + +using Line = std::string; +using Key = std::string; +using Val = std::string; +using ConfigInfo = std::map; + Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath, bool secureLDAP, std::string lDAPServerURI, std::string lDAPBindDN, std::string lDAPBaseDN, @@ -35,7 +42,6 @@ Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath, void Config::writeConfig() { - std::fstream stream(configFilePath.c_str(), std::fstream::out); std::stringstream confData; confData << "uid root\n"; confData << "gid root\n\n"; @@ -97,117 +103,221 @@ void Config::writeConfig() confData << "map passwd uid cn\n"; confData << "map passwd gecos displayName\n"; } - stream << confData.str(); - stream.flush(); - stream.close(); + try + { + std::fstream stream(configFilePath.c_str(), std::fstream::out); + stream << confData.str(); + stream.flush(); + stream.close(); + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } return; } bool Config::secureLDAP(bool value) { - if (value == secureLDAP()) + bool val = false; + try { - return value; - } + if (value == secureLDAP()) + { + return value; + } - auto val = ConfigIface::secureLDAP(value); - writeConfig(); - parent.restartService(nslcdService); + val = ConfigIface::secureLDAP(value); + writeConfig(); + parent.restartService(nslcdService); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } return val; } std::string Config::lDAPServerURI(std::string value) { - if (value == lDAPServerURI()) + std::string val; + try { - return value; - } + if (value == lDAPServerURI()) + { + return value; + } - auto val = ConfigIface::lDAPServerURI(value); - writeConfig(); - parent.restartService(nslcdService); + val = ConfigIface::lDAPServerURI(value); + writeConfig(); + parent.restartService(nslcdService); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } return val; } std::string Config::lDAPBindDN(std::string value) { - if (value == lDAPBindDN()) + std::string val; + try { - return value; - } - - auto val = ConfigIface::lDAPBindDN(value); - writeConfig(); - parent.restartService(nslcdService); + if (value == lDAPBindDN()) + { + return value; + } + val = ConfigIface::lDAPBindDN(value); + writeConfig(); + parent.restartService(nslcdService); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } return val; } std::string Config::lDAPBaseDN(std::string value) { - if (value == lDAPBaseDN()) + std::string val; + try { - return value; - } - - auto val = ConfigIface::lDAPBaseDN(value); - writeConfig(); - parent.restartService(nslcdService); + if (value == lDAPBaseDN()) + { + return value; + } + val = ConfigIface::lDAPBaseDN(value); + writeConfig(); + parent.restartService(nslcdService); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } return val; } std::string Config::lDAPBINDDNpassword(std::string value) { - if (value == lDAPBINDDNpassword()) + std::string val; + try { - return value; - } - - auto val = ConfigIface::lDAPBINDDNpassword(value); - writeConfig(); - parent.restartService(nslcdService); + if (value == lDAPBINDDNpassword()) + { + return value; + } + val = ConfigIface::lDAPBINDDNpassword(value); + writeConfig(); + parent.restartService(nslcdService); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } return val; } ldap_base::Config::SearchScope Config::lDAPSearchScope(ldap_base::Config::SearchScope value) { - if (value == lDAPSearchScope()) + ldap_base::Config::SearchScope val; + try { - return value; - } - - auto val = ConfigIface::lDAPSearchScope(value); - writeConfig(); - parent.restartService(nslcdService); + if (value == lDAPSearchScope()) + { + return value; + } + val = ConfigIface::lDAPSearchScope(value); + writeConfig(); + parent.restartService(nslcdService); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } return val; } ldap_base::Config::Type Config::lDAPType(ldap_base::Config::Type value) { - if (value == lDAPType()) + ldap_base::Config::Type val; + try { - return value; - } - - auto val = ConfigIface::lDAPType(value); - writeConfig(); - parent.restartService(nslcdService); + if (value == lDAPType()) + { + return value; + } + val = ConfigIface::lDAPType(value); + writeConfig(); + parent.restartService(nslcdService); + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } return val; } void ConfigMgr::restartService(const std::string& service) { - auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, - SYSTEMD_INTERFACE, "RestartUnit"); - method.append(service.c_str(), "replace"); - bus.call_noreply(method); + try + { + auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, + SYSTEMD_INTERFACE, "RestartUnit"); + method.append(service.c_str(), "replace"); + bus.call_noreply(method); + } + catch (const sdbusplus::exception::SdBusError& ex) + { + log("Failed to restart nslcd service", + entry("ERR=%s", ex.what())); + elog(); + } } std::string @@ -217,6 +327,7 @@ std::string ldap_base::Create::SearchScope lDAPSearchScope, ldap_base::Create::Type lDAPType) { + // TODO Validate parameters passed-in. // With current implementation we support only one LDAP server. configPtr.reset(nullptr); @@ -230,5 +341,137 @@ std::string return objPath; } +void ConfigMgr::restore(const char* filePath) +{ + if (!fs::exists(filePath)) + { + log("Config file doesn't exists", + entry("LDAP_CONFIG_FILE=%s", LDAP_CONFIG_FILE)); + return; + } + + ConfigInfo configValues; + + try + { + std::fstream stream(filePath, std::fstream::in); + Line line; + // read characters from stream and places them into line + while (std::getline(stream, line)) + { + // remove leading and trailing extra spaces + auto firstScan = line.find_first_not_of(' '); + auto first = + (firstScan == std::string::npos ? line.length() : firstScan); + auto last = line.find_last_not_of(' '); + line = line.substr(first, last - first + 1); + // reduce multiple spaces between two words to a single space + auto pred = [](char a, char b) { + return (a == b && a == ' ') ? true : false; + }; + + auto lastPos = std::unique(line.begin(), line.end(), pred); + + line.erase(lastPos, line.end()); + + // Ignore if line is empty or starts with '#' + if (line.empty() || line.at(0) == '#') + { + continue; + } + + Key key; + std::istringstream isLine(line); + // extract characters from isLine and stores them into + // key until the delimitation character ' ' is found. + // If the delimiter is found, it is extracted and discarded + // the next input operation will begin after it. + if (std::getline(isLine, key, ' ')) + { + Val value; + // extract characters after delimitation character ' ' + if (std::getline(isLine, value, ' ')) + { + // skip line if it starts with "base shadow" or + // "base passwd" because we would have 3 entries + // ("base lDAPBaseDN" , "base passwd lDAPBaseDN" and + // "base shadow lDAPBaseDN") for the property "lDAPBaseDN", + // one is enough to restore it. + + if ((key == "base") && + (value == "passwd" || value == "shadow")) + { + 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; + } + configValues[key] = value; + } + } + } + + // extract properties from configValues map + bool secureLDAP; + if (configValues["ssl"] == "on") + { + secureLDAP = true; + } + else + { + secureLDAP = false; + } + + ldap_base::Create::SearchScope lDAPSearchScope; + if (configValues["scope"] == "sub") + { + lDAPSearchScope = ldap_base::Create::SearchScope::sub; + } + else if (configValues["scope"] == "one") + { + lDAPSearchScope = ldap_base::Create::SearchScope::one; + } + else + { + lDAPSearchScope = ldap_base::Create::SearchScope::base; + } + + ldap_base::Create::Type lDAPType; + // If the file is having a line which starts with "map group" + if (configValues["map"] == "group") + { + lDAPType = ldap_base::Create::Type::ActiveDirectory; + } + else + { + lDAPType = ldap_base::Create::Type::OpenLdap; + } + + createConfig( + secureLDAP, std::move(configValues["uri"]), + std::move(configValues["binddn"]), std::move(configValues["base"]), + std::move(configValues["bindpw"]), lDAPSearchScope, lDAPType); + } + catch (const InvalidArgument& e) + { + // Don't throw - we don't want to create a D-Bus + // object upon finding empty values in config, as + // this can be a default config. + } + catch (const InternalFailure& e) + { + throw; + } + catch (const std::exception& e) + { + log(e.what()); + elog(); + } +} } // namespace ldap } // namespace phosphor diff --git a/phosphor-ldap-config/ldap_configuration.hpp b/phosphor-ldap-config/ldap_configuration.hpp index f2bf02a..a0324c1 100644 --- a/phosphor-ldap-config/ldap_configuration.hpp +++ b/phosphor-ldap-config/ldap_configuration.hpp @@ -1,9 +1,14 @@ #pragma once -#include -#include +#include "config.h" #include #include +#include +#include +#include +#include +#include +#include #include namespace phosphor @@ -15,6 +20,8 @@ static constexpr auto nsSwitchFile = "/etc/nsswitch.conf"; static constexpr auto LDAPNsSwitchFile = "/etc/nsswitch_ldap.conf"; static constexpr auto linuxNsSwitchFile = "/etc/nsswitch_linux.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; using CreateIface = sdbusplus::server::object::object; @@ -144,9 +151,19 @@ class ConfigMgr : public CreateIface * @param[in] filePath - LDAP configuration file. */ ConfigMgr(sdbusplus::bus::bus& bus, const char* path) : - CreateIface(bus, path), bus(bus) + CreateIface(bus, path, true), bus(bus) { - // TODO restore config object if config file exists. + try + { + restore(LDAP_CONFIG_FILE); + emit_object_added(); + } + catch (const std::exception& e) + { + configPtr.reset(nullptr); + log(e.what()); + elog(); + } } /** @brief concrete implementation of the pure virtual funtion @@ -179,6 +196,11 @@ class ConfigMgr : public CreateIface /** @brief Pointer to a Config D-Bus object */ std::unique_ptr configPtr = nullptr; + + /** @brief Populate existing config into D-Bus properties + * @param[in] filePath - LDAP config file path + */ + virtual void restore(const char* filePath); }; } // namespace ldap } // namespace phosphor -- cgit v1.2.1