From 0b14c471fc77cbcb93f435a46878b25f57741e0e Mon Sep 17 00:00:00 2001 From: Tom Joseph Date: Sun, 30 Sep 2018 01:42:59 +0530 Subject: ldap: Add persistence for LDAP mapper D-Bus objects Change-Id: Ib8979a7c655f74c332d80e7fb221ef03e9a3f83c Signed-off-by: Tom Joseph --- configure.ac | 10 +++ phosphor-ldap-mapper/Makefile.am | 6 +- phosphor-ldap-mapper/ldap_mapper_entry.cpp | 17 ++++- phosphor-ldap-mapper/ldap_mapper_entry.hpp | 9 +++ phosphor-ldap-mapper/ldap_mapper_mgr.cpp | 37 ++++++++++ phosphor-ldap-mapper/ldap_mapper_mgr.hpp | 5 ++ phosphor-ldap-mapper/ldap_mapper_serialize.cpp | 95 ++++++++++++++++++++++++++ phosphor-ldap-mapper/ldap_mapper_serialize.hpp | 33 +++++++++ phosphor-ldap-mapper/main.cpp | 6 ++ 9 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 phosphor-ldap-mapper/ldap_mapper_serialize.cpp create mode 100644 phosphor-ldap-mapper/ldap_mapper_serialize.hpp diff --git a/configure.ac b/configure.ac index fa32305..c190307 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,16 @@ AC_ARG_VAR(LDAP_MAPPER_MANAGER_BUSNAME, [The Dbus busname LDAP privilege mapper AS_IF([test "x$LDAP_MAPPER_MANAGER_BUSNAME" == "x"], [LDAP_MAPPER_MANAGER_BUSNAME="xyz.openbmc_project.LDAP.PrivilegeMapper"]) AC_DEFINE_UNQUOTED([LDAP_MAPPER_MANAGER_BUSNAME], ["$LDAP_MAPPER_MANAGER_BUSNAME"], [The Dbus busname LDAP privilege mapper application]) +AC_ARG_VAR(LDAP_MAPPER_PERSIST_PATH, [Path of directory containing LDAP groups privilege mapping]) +AS_IF([test "x$LDAP_MAPPER_PERSIST_PATH" == "x"], \ + [LDAP_MAPPER_PERSIST_PATH="/var/lib/phosphor-ldap-mapper/groups"]) +AC_DEFINE_UNQUOTED([LDAP_MAPPER_PERSIST_PATH], ["$LDAP_MAPPER_PERSIST_PATH"], \ + [Path of directory containing LDAP groups privilege mapping]) + +AC_ARG_VAR(CLASS_VERSION, [Class version to register with Cereal]) +AS_IF([test "x$CLASS_VERSION" == "x"], [CLASS_VERSION=1]) +AC_DEFINE_UNQUOTED([CLASS_VERSION], [$CLASS_VERSION], [Class version to register with Cereal]) + # Default crypt algorithm to choose if one not found in shadow file # Per crypt(3), 1 is for MD5 AC_ARG_VAR(DEFAULT_CRYPT_ALGO, [The default crypt algorithm if one not found in shadow]) diff --git a/phosphor-ldap-mapper/Makefile.am b/phosphor-ldap-mapper/Makefile.am index 4aeca7b..c2896ba 100644 --- a/phosphor-ldap-mapper/Makefile.am +++ b/phosphor-ldap-mapper/Makefile.am @@ -1,12 +1,14 @@ sbin_PROGRAMS = phosphor-ldap-mapper noinst_HEADERS = ldap_mapper_mgr.hpp \ - ldap_mapper_entry.hpp + ldap_mapper_entry.hpp \ + ldap_mapper_serialize.hpp phosphor_ldap_mapper_SOURCES = \ main.cpp \ ldap_mapper_mgr.cpp \ - ldap_mapper_entry.cpp + ldap_mapper_entry.cpp \ + ldap_mapper_serialize.cpp phosphor_ldap_mapper_LDFLAGS = $(SDBUSPLUS_LIBS) \ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ diff --git a/phosphor-ldap-mapper/ldap_mapper_entry.cpp b/phosphor-ldap-mapper/ldap_mapper_entry.cpp index 64d3578..95f381d 100644 --- a/phosphor-ldap-mapper/ldap_mapper_entry.cpp +++ b/phosphor-ldap-mapper/ldap_mapper_entry.cpp @@ -7,6 +7,7 @@ #include "config.h" #include "ldap_mapper_entry.hpp" #include "ldap_mapper_mgr.hpp" +#include "ldap_mapper_serialize.hpp" namespace phosphor { @@ -31,6 +32,14 @@ LDAPMapperEntry::LDAPMapperEntry(sdbusplus::bus::bus &bus, const char *path, Ifaces::emit_object_added(); } +LDAPMapperEntry::LDAPMapperEntry(sdbusplus::bus::bus &bus, const char *path, + LDAPMapperMgr &parent) : + Ifaces(bus, path, true), + id(std::stol(std::experimental::filesystem::path(path).filename())), + manager(parent) +{ +} + void LDAPMapperEntry::delete_(void) { manager.deletePrivilegeMapper(id); @@ -44,7 +53,9 @@ std::string LDAPMapperEntry::groupName(std::string value) } manager.checkPrivilegeMapper(value); - return Ifaces::groupName(value); + auto val = Ifaces::groupName(value); + serialize(*this, id); + return val; } std::string LDAPMapperEntry::privilege(std::string value) @@ -55,7 +66,9 @@ std::string LDAPMapperEntry::privilege(std::string value) } manager.checkPrivilegeLevel(value); - return Ifaces::privilege(value); + auto val = Ifaces::privilege(value); + serialize(*this, id); + return val; } } // namespace user diff --git a/phosphor-ldap-mapper/ldap_mapper_entry.hpp b/phosphor-ldap-mapper/ldap_mapper_entry.hpp index 689639d..ea8a0bc 100644 --- a/phosphor-ldap-mapper/ldap_mapper_entry.hpp +++ b/phosphor-ldap-mapper/ldap_mapper_entry.hpp @@ -46,6 +46,15 @@ class LDAPMapperEntry : public Ifaces const std::string &groupName, const std::string &privilege, LDAPMapperMgr &parent); + /** @brief Constructs LDAP privilege mapper entry object + * + * @param[in] bus - sdbusplus handler + * @param[in] path - D-Bus path + * @param[in] parent - LDAP privilege mapper manager + */ + LDAPMapperEntry(sdbusplus::bus::bus &bus, const char *path, + LDAPMapperMgr &parent); + /** @brief Delete privilege mapper entry object * * This method deletes the privilege mapper entry. diff --git a/phosphor-ldap-mapper/ldap_mapper_mgr.cpp b/phosphor-ldap-mapper/ldap_mapper_mgr.cpp index 9fe40ad..a321331 100644 --- a/phosphor-ldap-mapper/ldap_mapper_mgr.cpp +++ b/phosphor-ldap-mapper/ldap_mapper_mgr.cpp @@ -5,6 +5,7 @@ #include #include "config.h" #include "ldap_mapper_mgr.hpp" +#include "ldap_mapper_serialize.hpp" namespace phosphor { @@ -38,6 +39,8 @@ ObjectPath LDAPMapperMgr::create(std::string groupName, std::string privilege) auto entry = std::make_unique( bus, mapperObject.c_str(), groupName, privilege, *this); + serialize(*entry, entryId); + PrivilegeMapperList.emplace(entryId, std::move(entry)); return mapperObject; @@ -45,6 +48,11 @@ ObjectPath LDAPMapperMgr::create(std::string groupName, std::string privilege) void LDAPMapperMgr::deletePrivilegeMapper(Id id) { + // Delete the persistent representation of the privilege mapper. + fs::path mapperPath(LDAP_MAPPER_PERSIST_PATH); + mapperPath /= std::to_string(id); + fs::remove(mapperPath); + PrivilegeMapperList.erase(id); } @@ -84,5 +92,34 @@ void LDAPMapperMgr::checkPrivilegeLevel(const std::string &privilege) } } +void LDAPMapperMgr::restore() +{ + namespace fs = std::experimental::filesystem; + + fs::path dir(LDAP_MAPPER_PERSIST_PATH); + if (!fs::exists(dir) || fs::is_empty(dir)) + { + return; + } + + for (auto &file : fs::directory_iterator(dir)) + { + std::string id = file.path().filename().c_str(); + size_t idNum = std::stol(id); + auto entryPath = std::string(mapperMgrRoot) + '/' + id; + auto entry = std::make_unique( + bus, entryPath.c_str(), *this); + if (deserialize(file.path(), *entry)) + { + entry->Ifaces::emit_object_added(); + PrivilegeMapperList.emplace(idNum, std::move(entry)); + if (idNum > entryId) + { + entryId = idNum; + } + } + } +} + } // namespace user } // namespace phosphor diff --git a/phosphor-ldap-mapper/ldap_mapper_mgr.hpp b/phosphor-ldap-mapper/ldap_mapper_mgr.hpp index 450626d..b2617ca 100644 --- a/phosphor-ldap-mapper/ldap_mapper_mgr.hpp +++ b/phosphor-ldap-mapper/ldap_mapper_mgr.hpp @@ -80,6 +80,11 @@ class LDAPMapperMgr : public MapperMgrIface */ void checkPrivilegeLevel(const std::string &privilege); + /** @brief Construct LDAP mapper entry D-Bus objects from their persisted + * representations. + */ + void restore(); + private: /** @brief sdbusplus handler */ sdbusplus::bus::bus &bus; diff --git a/phosphor-ldap-mapper/ldap_mapper_serialize.cpp b/phosphor-ldap-mapper/ldap_mapper_serialize.cpp new file mode 100644 index 0000000..534e0a1 --- /dev/null +++ b/phosphor-ldap-mapper/ldap_mapper_serialize.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include "config.h" +#include "ldap_mapper_serialize.hpp" + +// Register class version +// From cereal documentation; +// "This macro should be placed at global scope" +CEREAL_CLASS_VERSION(phosphor::user::LDAPMapperEntry, CLASS_VERSION); + +namespace phosphor +{ +namespace user +{ + +using namespace phosphor::logging; + +/** @brief Function required by Cereal to perform serialization. + * + * @tparam Archive - Cereal archive type (binary in this case). + * @param[in] archive - reference to cereal archive. + * @param[in] entry- const reference to LDAP mapper entry + * @param[in] version - Class version that enables handling a serialized data + * across code levels + */ +template +void save(Archive& archive, const LDAPMapperEntry& entry, + const std::uint32_t version) +{ + archive(entry.groupName(), entry.privilege()); +} + +/** @brief Function required by Cereal to perform deserialization. + * + * @tparam Archive - Cereal archive type (binary in our case). + * @param[in] archive - reference to cereal archive. + * @param[out] entry - LDAP mapper entry to be read + * @param[in] version - Class version that enables handling a serialized data + * across code levels + */ +template +void load(Archive& archive, LDAPMapperEntry& entry, const std::uint32_t version) +{ + std::string groupName{}; + std::string privilege{}; + + archive(groupName, privilege); + + entry.sdbusplus::xyz::openbmc_project::User::server::PrivilegeMapperEntry:: + groupName(groupName, true); + entry.sdbusplus::xyz::openbmc_project::User::server::PrivilegeMapperEntry:: + privilege(privilege, true); +} + +fs::path serialize(const LDAPMapperEntry& entry, Id id) +{ + fs::path dir(LDAP_MAPPER_PERSIST_PATH); + auto path = dir / std::to_string(id); + std::ofstream os(path.c_str(), std::ios::binary); + cereal::BinaryOutputArchive oarchive(os); + oarchive(entry); + return path; +} + +bool deserialize(const fs::path& path, LDAPMapperEntry& entry) +{ + try + { + if (fs::exists(path)) + { + std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); + cereal::BinaryInputArchive iarchive(is); + iarchive(entry); + return true; + } + return false; + } + catch (cereal::Exception& e) + { + log(e.what()); + fs::remove(path); + return false; + } + catch (const std::length_error& e) + { + log(e.what()); + fs::remove(path); + return false; + } +} + +} // namespace user +} // namespace phosphor diff --git a/phosphor-ldap-mapper/ldap_mapper_serialize.hpp b/phosphor-ldap-mapper/ldap_mapper_serialize.hpp new file mode 100644 index 0000000..f48f73c --- /dev/null +++ b/phosphor-ldap-mapper/ldap_mapper_serialize.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include "ldap_mapper_entry.hpp" + +namespace phosphor +{ +namespace user +{ + +namespace fs = std::experimental::filesystem; + +/** @brief Serialize and persist LDAP privilege mapper D-Bus object + * + * @param[in] entry - LDAP privilege mapper entry + * @param[in] id - filename of the persisted LDAP mapper entry + * + * @return fs::path - pathname of persisted error file + */ +fs::path serialize(const LDAPMapperEntry& entry, Id id); + +/** @brief Deserialize a persisted LDAP privilege mapper into a D-Bus object + * + * @param[in] path - pathname of persisted file + * @param[in/out] entry - reference to LDAP privilege mapper entry object + * which is the target of deserialization. + * + * @return bool - true if the deserialization was successful, false otherwise. + */ +bool deserialize(const fs::path& path, LDAPMapperEntry& entry); + +} // namespace user +} // namespace phosphor diff --git a/phosphor-ldap-mapper/main.cpp b/phosphor-ldap-mapper/main.cpp index b4a0650..15c9802 100644 --- a/phosphor-ldap-mapper/main.cpp +++ b/phosphor-ldap-mapper/main.cpp @@ -11,6 +11,12 @@ int main(int argc, char** argv) phosphor::user::LDAPMapperMgr mapperMgr(bus, phosphor::user::mapperMgrRoot); + // Create a directory to persist errors. + std::experimental::filesystem::create_directories(LDAP_MAPPER_PERSIST_PATH); + + // Restore the serialized LDAP group privilege mapping. + mapperMgr.restore(); + // Claim the bus name for the application bus.request_name(LDAP_MAPPER_MANAGER_BUSNAME); -- cgit v1.2.1