blob: f0630f6cac028e71eae1cbcdaf00ca23e9cd5a6a [file] [log] [blame]
#include "ldap_config_mgr.hpp"
#include "ldap_config.hpp"
#include "utils.hpp"
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/lg2.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
#include <filesystem>
#include <fstream>
#include <sstream>
namespace phosphor
{
namespace ldap
{
constexpr auto systemdBusname = "org.freedesktop.systemd1";
constexpr auto systemdObjPath = "/org/freedesktop/systemd1";
constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
constexpr auto nslcdService = "nslcd.service";
constexpr auto nscdService = "nscd.service";
constexpr auto ldapScheme = "ldap";
constexpr auto ldapsScheme = "ldaps";
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
namespace fs = std::filesystem;
using Argument = xyz::openbmc_project::Common::InvalidArgument;
using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
using Line = std::string;
using Key = std::string;
using Val = std::string;
using ConfigInfo = std::map<Key, 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
{
auto method = bus.new_method_call(systemdBusname, systemdObjPath,
systemdInterface, "RestartUnit");
method.append(service.c_str(), "replace");
bus.call_noreply(method);
}
catch (const sdbusplus::exception_t& ex)
{
lg2::error("Failed to restart service {SERVICE}: {ERR}", "SERVICE",
service, "ERR", ex);
elog<InternalFailure>();
}
}
void ConfigMgr::stopService(const std::string& service)
{
try
{
auto method = bus.new_method_call(systemdBusname, systemdObjPath,
systemdInterface, "StopUnit");
method.append(service.c_str(), "replace");
bus.call_noreply(method);
}
catch (const sdbusplus::exception_t& ex)
{
lg2::error("Failed to stop service {SERVICE}: {ERR}", "SERVICE",
service, "ERR", ex);
elog<InternalFailure>();
}
}
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;
if (isValidLDAPURI(ldapServerURI, ldapsScheme))
{
secureLDAP = true;
}
else if (isValidLDAPURI(ldapServerURI, ldapScheme))
{
secureLDAP = false;
}
else
{
lg2::error("Bad LDAP Server URI {URI}", "URI", ldapServerURI);
elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
Argument::ARGUMENT_VALUE(ldapServerURI.c_str()));
}
if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
{
lg2::error("LDAP server CA certificate not found at {PATH}", "PATH",
tlsCacertFile);
elog<NoCACertificate>();
}
if (ldapBindDN.empty())
{
lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN",
ldapBindDN);
elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBindDN"),
Argument::ARGUMENT_VALUE(ldapBindDN.c_str()));
}
if (ldapBaseDN.empty())
{
lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN",
ldapBaseDN);
elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBaseDN"),
Argument::ARGUMENT_VALUE(ldapBaseDN.c_str()));
}
// With current implementation we support only two default LDAP server.
// which will be always there but when the support comes for additional
// account providers then the create config would be used to create the
// additional config.
std::string objPath;
if (static_cast<ConfigIface::Type>(ldapType) == ConfigIface::Type::OpenLdap)
{
openLDAPConfigPtr.reset(nullptr);
objPath = openLDAPDbusObjectPath;
openLDAPConfigPtr = std::make_unique<Config>(
bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
ldapBaseDN, std::move(ldapBindDNPassword),
static_cast<ConfigIface::SearchScope>(ldapSearchScope),
static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
userNameAttribute, *this);
}
else
{
ADConfigPtr.reset(nullptr);
objPath = adDbusObjectPath;
ADConfigPtr = std::make_unique<Config>(
bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
ldapBaseDN, std::move(ldapBindDNPassword),
static_cast<ConfigIface::SearchScope>(ldapSearchScope),
static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
userNameAttribute, *this);
}
restartService(nscdService);
return objPath;
}
void ConfigMgr::createDefaultObjects()
{
if (!openLDAPConfigPtr)
{
openLDAPConfigPtr = std::make_unique<Config>(
bus, openLDAPDbusObjectPath.c_str(), configFilePath.c_str(),
tlsCacertFile.c_str(), tlsCertFile.c_str(),
ConfigIface::Type::OpenLdap, *this);
openLDAPConfigPtr->emit_object_added();
}
if (!ADConfigPtr)
{
ADConfigPtr = std::make_unique<Config>(
bus, adDbusObjectPath.c_str(), configFilePath.c_str(),
tlsCacertFile.c_str(), tlsCertFile.c_str(),
ConfigIface::Type::ActiveDirectory, *this);
ADConfigPtr->emit_object_added();
}
}
bool ConfigMgr::enableService(Config& config, bool value)
{
if (value)
{
if (openLDAPConfigPtr && openLDAPConfigPtr->enabled())
{
elog<NotAllowed>(NotAllowedArgument::REASON(
"OpenLDAP service is already active"));
}
if (ADConfigPtr && ADConfigPtr->enabled())
{
elog<NotAllowed>(NotAllowedArgument::REASON(
"ActiveDirectory service is already active"));
}
}
return config.enableService(value);
}
void ConfigMgr::restore()
{
createDefaultObjects();
// Restore the ldap config and their mappings
if (ADConfigPtr->deserialize())
{
// Restore the role mappings
ADConfigPtr->restoreRoleMapping();
ADConfigPtr->emit_object_added();
}
if (openLDAPConfigPtr->deserialize())
{
// Restore the role mappings
openLDAPConfigPtr->restoreRoleMapping();
openLDAPConfigPtr->emit_object_added();
}
startOrStopService(phosphor::ldap::nslcdService,
ADConfigPtr->enabled() || openLDAPConfigPtr->enabled());
}
} // namespace ldap
} // namespace phosphor