blob: 4edbed7576f877ff1472c863e2d861da6bb8700b [file] [log] [blame]
#include "ldap_config_mgr.hpp"
#include "ldap_configuration.hpp"
#include "ldap_serialize.hpp"
#include "utils.hpp"
#include <filesystem>
#include <fstream>
#include <sstream>
namespace phosphor
{
namespace ldap
{
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 Line = std::string;
using Key = std::string;
using Val = std::string;
using ConfigInfo = std::map<Key, Val>;
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,
ConfigIface::SearchScope lDAPSearchScope,
ConfigIface::Type lDAPType, bool lDAPServiceEnabled,
std::string userNameAttr, std::string groupNameAttr,
ConfigMgr& parent) :
Ifaces(bus, path, true),
secureLDAP(secureLDAP), lDAPBindPassword(std::move(lDAPBindDNPassword)),
configFilePath(filePath), tlsCacertFile(caCertFile), bus(bus),
parent(parent)
{
ConfigIface::lDAPServerURI(lDAPServerURI);
ConfigIface::lDAPBindDN(lDAPBindDN);
ConfigIface::lDAPBaseDN(lDAPBaseDN);
ConfigIface::lDAPSearchScope(lDAPSearchScope);
ConfigIface::lDAPType(lDAPType);
EnableIface::enabled(lDAPServiceEnabled);
ConfigIface::userNameAttribute(userNameAttr);
ConfigIface::groupNameAttribute(groupNameAttr);
// Don't update the bindDN password under ConfigIface::
writeConfig();
// Emit deferred signal.
this->emit_object_added();
parent.startOrStopService(nslcdService, enabled());
}
void Config::delete_()
{
parent.deleteObject();
try
{
fs::path configDir = fs::path(configFilePath.c_str()).parent_path();
fs::copy_file(configDir / defaultNslcdFile, LDAP_CONFIG_FILE,
fs::copy_options::overwrite_existing);
}
catch (const std::exception& e)
{
log<level::ERR>("Failed to rename Config Files while deleting Object",
entry("ERR=%s", e.what()));
elog<InternalFailure>();
}
parent.restartService(nscdService);
parent.stopService(nslcdService);
}
void Config::writeConfig()
{
std::stringstream confData;
auto isPwdTobeWritten = false;
std::string userNameAttr;
confData << "uid root\n";
confData << "gid root\n\n";
confData << "ldap_version 3\n\n";
confData << "timelimit 30\n";
confData << "bind_timelimit 30\n";
confData << "pagesize 1000\n";
confData << "referrals off\n\n";
confData << "uri " << lDAPServerURI() << "\n\n";
confData << "base " << lDAPBaseDN() << "\n\n";
confData << "binddn " << lDAPBindDN() << "\n";
if (!lDAPBindPassword.empty())
{
confData << "bindpw " << lDAPBindPassword << "\n";
isPwdTobeWritten = true;
}
confData << "\n";
switch (lDAPSearchScope())
{
case ConfigIface::SearchScope::sub:
confData << "scope sub\n\n";
break;
case ConfigIface::SearchScope::one:
confData << "scope one\n\n";
break;
case ConfigIface::SearchScope::base:
confData << "scope base\n\n";
break;
}
confData << "base passwd " << lDAPBaseDN() << "\n";
confData << "base shadow " << lDAPBaseDN() << "\n\n";
if (secureLDAP == true)
{
confData << "ssl on\n";
confData << "tls_reqcert hard\n";
confData << "tls_cacertFile " << tlsCacertFile.c_str() << "\n";
}
else
{
confData << "ssl off\n";
}
confData << "\n";
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 "
<< ConfigIface::userNameAttribute() << "\n";
confData << "map passwd uidNumber "
"objectSid:S-1-5-21-3623811015-3361044348-30300820\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 "
"objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
confData << "map group cn "
<< ConfigIface::userNameAttribute() << "\n";
}
else if (lDAPType() == ConfigIface::Type::OpenLdap)
{
if (ConfigIface::userNameAttribute().empty())
{
ConfigIface::userNameAttribute("cn");
}
if (ConfigIface::groupNameAttribute().empty())
{
ConfigIface::groupNameAttribute("gidNumber");
}
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
{
std::fstream stream(configFilePath.c_str(), std::fstream::out);
// remove the read permission from others if password is being written.
// nslcd forces this behaviour.
auto permission = fs::perms::owner_read | fs::perms::owner_write |
fs::perms::group_read;
if (isPwdTobeWritten)
{
fs::permissions(configFilePath, permission);
}
else
{
fs::permissions(configFilePath,
permission | fs::perms::others_read);
}
stream << confData.str();
stream.flush();
stream.close();
}
catch (const std::exception& e)
{
log<level::ERR>(e.what());
elog<InternalFailure>();
}
return;
}
std::string Config::lDAPBindDNPassword(std::string value)
{
// Don't update the D-bus object, this is just to
// facilitate if user wants to change the bind dn password
// once d-bus object gets created.
lDAPBindPassword = value;
try
{
writeConfig();
parent.startOrStopService(nslcdService, enabled());
}
catch (const InternalFailure& e)
{
throw;
}
catch (const std::exception& e)
{
log<level::ERR>(e.what());
elog<InternalFailure>();
}
return value;
}
std::string Config::lDAPServerURI(std::string value)
{
std::string val;
try
{
if (value == lDAPServerURI())
{
return value;
}
if (isValidLDAPURI(value, LDAPSscheme))
{
secureLDAP = true;
}
else if (isValidLDAPURI(value, LDAPscheme))
{
secureLDAP = false;
}
else
{
log<level::ERR>("bad LDAP Server URI",
entry("LDAPSERVERURI=%s", value.c_str()));
elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
Argument::ARGUMENT_VALUE(value.c_str()));
}
if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
{
log<level::ERR>("LDAP server's CA certificate not provided",
entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
elog<NoCACertificate>();
}
val = ConfigIface::lDAPServerURI(value);
writeConfig();
parent.startOrStopService(nslcdService, enabled());
}
catch (const InternalFailure& e)
{
throw;
}
catch (const InvalidArgument& e)
{
throw;
}
catch (const NoCACertificate& e)
{
throw;
}
catch (const std::exception& e)
{
log<level::ERR>(e.what());
elog<InternalFailure>();
}
return val;
}
std::string Config::lDAPBindDN(std::string value)
{
std::string val;
try
{
if (value == lDAPBindDN())
{
return value;
}
if (value.empty())
{
log<level::ERR>("Not a valid LDAP BINDDN",
entry("LDAPBINDDN=%s", value.c_str()));
elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"),
Argument::ARGUMENT_VALUE(value.c_str()));
}
val = ConfigIface::lDAPBindDN(value);
writeConfig();
parent.startOrStopService(nslcdService, enabled());
}
catch (const InternalFailure& e)
{
throw;
}
catch (const InvalidArgument& e)
{
throw;
}
catch (const std::exception& e)
{
log<level::ERR>(e.what());
elog<InternalFailure>();
}
return val;
}
std::string Config::lDAPBaseDN(std::string value)
{
std::string val;
try
{
if (value == lDAPBaseDN())
{
return value;
}
if (value.empty())
{
log<level::ERR>("Not a valid LDAP BASEDN",
entry("BASEDN=%s", value.c_str()));
elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"),
Argument::ARGUMENT_VALUE(value.c_str()));
}
val = ConfigIface::lDAPBaseDN(value);
writeConfig();
parent.startOrStopService(nslcdService, enabled());
}
catch (const InternalFailure& e)
{
throw;
}
catch (const InvalidArgument& e)
{
throw;
}
catch (const std::exception& e)
{
log<level::ERR>(e.what());
elog<InternalFailure>();
}
return val;
}
ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value)
{
ConfigIface::SearchScope val;
try
{
if (value == lDAPSearchScope())
{
return value;
}
val = ConfigIface::lDAPSearchScope(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;
}
ConfigIface::Type Config::lDAPType(ConfigIface::Type value)
{
ConfigIface::Type val;
try
{
if (value == lDAPType())
{
return value;
}
val = ConfigIface::lDAPType(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;
}
bool Config::enabled(bool value)
{
bool isEnable;
try
{
if (value == enabled())
{
return value;
}
isEnable = EnableIface::enabled(value);
// save the enabled property.
serialize(*this, parent.dbusPersistentPath);
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)
{
throw;
}
catch (const std::exception& e)
{
log<level::ERR>(e.what());
elog<InternalFailure>();
}
return val;
}
} // namespace ldap
} // namespace phosphor