1e1f4db62SRatan Gupta #include "ldap_config_mgr.hpp"
2e1f4db62SRatan Gupta 
39638afb9SPatrick Williams #include "ldap_config.hpp"
4e1f4db62SRatan Gupta #include "utils.hpp"
59638afb9SPatrick Williams 
6e8d664d1SJiaqing Zhao #include <phosphor-logging/elog-errors.hpp>
7e8d664d1SJiaqing Zhao #include <phosphor-logging/elog.hpp>
8e8d664d1SJiaqing Zhao #include <phosphor-logging/lg2.hpp>
9e8d664d1SJiaqing Zhao #include <xyz/openbmc_project/Common/error.hpp>
10e8d664d1SJiaqing Zhao 
11e1f4db62SRatan Gupta #include <filesystem>
12e1f4db62SRatan Gupta #include <fstream>
13e1f4db62SRatan Gupta #include <sstream>
14e1f4db62SRatan Gupta 
15e1f4db62SRatan Gupta namespace phosphor
16e1f4db62SRatan Gupta {
17e1f4db62SRatan Gupta namespace ldap
18e1f4db62SRatan Gupta {
19e1f4db62SRatan Gupta 
20*af1594c9SRavi Teja constexpr auto systemdBusname = "org.freedesktop.systemd1";
21*af1594c9SRavi Teja constexpr auto systemdObjPath = "/org/freedesktop/systemd1";
22*af1594c9SRavi Teja constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
23*af1594c9SRavi Teja 
24372c5668SAlexander Filippov constexpr auto nslcdService = "nslcd.service";
25e1f4db62SRatan Gupta constexpr auto nscdService = "nscd.service";
2678d85042SNan Zhou constexpr auto ldapScheme = "ldap";
2778d85042SNan Zhou constexpr auto ldapsScheme = "ldaps";
28e1f4db62SRatan Gupta 
29e8d664d1SJiaqing Zhao using namespace phosphor::logging;
30e1f4db62SRatan Gupta using namespace sdbusplus::xyz::openbmc_project::Common::Error;
31e1f4db62SRatan Gupta namespace fs = std::filesystem;
32e1f4db62SRatan Gupta using Argument = xyz::openbmc_project::Common::InvalidArgument;
33c5481d1cSRatan Gupta using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
34e1f4db62SRatan Gupta 
35e1f4db62SRatan Gupta using Line = std::string;
36e1f4db62SRatan Gupta using Key = std::string;
37e1f4db62SRatan Gupta using Val = std::string;
38e1f4db62SRatan Gupta using ConfigInfo = std::map<Key, Val>;
39e1f4db62SRatan Gupta 
startOrStopService(const std::string & service,bool start)40e1f4db62SRatan Gupta void ConfigMgr::startOrStopService(const std::string& service, bool start)
41e1f4db62SRatan Gupta {
42e1f4db62SRatan Gupta     if (start)
43e1f4db62SRatan Gupta     {
44e1f4db62SRatan Gupta         restartService(service);
45e1f4db62SRatan Gupta     }
46e1f4db62SRatan Gupta     else
47e1f4db62SRatan Gupta     {
48e1f4db62SRatan Gupta         stopService(service);
49e1f4db62SRatan Gupta     }
50e1f4db62SRatan Gupta }
51e1f4db62SRatan Gupta 
restartService(const std::string & service)52e1f4db62SRatan Gupta void ConfigMgr::restartService(const std::string& service)
53e1f4db62SRatan Gupta {
54e1f4db62SRatan Gupta     try
55e1f4db62SRatan Gupta     {
56*af1594c9SRavi Teja         auto method = bus.new_method_call(systemdBusname, systemdObjPath,
57*af1594c9SRavi Teja                                           systemdInterface, "RestartUnit");
58e1f4db62SRatan Gupta         method.append(service.c_str(), "replace");
59e1f4db62SRatan Gupta         bus.call_noreply(method);
60e1f4db62SRatan Gupta     }
61b3ef4e1aSPatrick Williams     catch (const sdbusplus::exception_t& ex)
62e1f4db62SRatan Gupta     {
6311ec666bSJiaqing Zhao         lg2::error("Failed to restart service {SERVICE}: {ERR}", "SERVICE",
6411ec666bSJiaqing Zhao                    service, "ERR", ex);
65e1f4db62SRatan Gupta         elog<InternalFailure>();
66e1f4db62SRatan Gupta     }
67e1f4db62SRatan Gupta }
stopService(const std::string & service)68e1f4db62SRatan Gupta void ConfigMgr::stopService(const std::string& service)
69e1f4db62SRatan Gupta {
70e1f4db62SRatan Gupta     try
71e1f4db62SRatan Gupta     {
72*af1594c9SRavi Teja         auto method = bus.new_method_call(systemdBusname, systemdObjPath,
73*af1594c9SRavi Teja                                           systemdInterface, "StopUnit");
74e1f4db62SRatan Gupta         method.append(service.c_str(), "replace");
75e1f4db62SRatan Gupta         bus.call_noreply(method);
76e1f4db62SRatan Gupta     }
77b3ef4e1aSPatrick Williams     catch (const sdbusplus::exception_t& ex)
78e1f4db62SRatan Gupta     {
7911ec666bSJiaqing Zhao         lg2::error("Failed to stop service {SERVICE}: {ERR}", "SERVICE",
8011ec666bSJiaqing Zhao                    service, "ERR", ex);
81e1f4db62SRatan Gupta         elog<InternalFailure>();
82e1f4db62SRatan Gupta     }
83e1f4db62SRatan Gupta }
84e1f4db62SRatan Gupta 
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)85e1f4db62SRatan Gupta std::string ConfigMgr::createConfig(
86e6500a49SPatrick Williams     std::string ldapServerURI, std::string ldapBindDN, std::string ldapBaseDN,
87e6500a49SPatrick Williams     std::string ldapBindDNPassword, CreateIface::SearchScope ldapSearchScope,
88e6500a49SPatrick Williams     CreateIface::Create::Type ldapType, std::string groupNameAttribute,
89e1f4db62SRatan Gupta     std::string userNameAttribute)
90e1f4db62SRatan Gupta {
91e1f4db62SRatan Gupta     bool secureLDAP = false;
92e1f4db62SRatan Gupta 
9378d85042SNan Zhou     if (isValidLDAPURI(ldapServerURI, ldapsScheme))
94e1f4db62SRatan Gupta     {
95e1f4db62SRatan Gupta         secureLDAP = true;
96e1f4db62SRatan Gupta     }
9778d85042SNan Zhou     else if (isValidLDAPURI(ldapServerURI, ldapScheme))
98e1f4db62SRatan Gupta     {
99e1f4db62SRatan Gupta         secureLDAP = false;
100e1f4db62SRatan Gupta     }
101e1f4db62SRatan Gupta     else
102e1f4db62SRatan Gupta     {
10311ec666bSJiaqing Zhao         lg2::error("Bad LDAP Server URI {URI}", "URI", ldapServerURI);
104e6500a49SPatrick Williams         elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
105e6500a49SPatrick Williams                               Argument::ARGUMENT_VALUE(ldapServerURI.c_str()));
106e1f4db62SRatan Gupta     }
107e1f4db62SRatan Gupta 
108e1f4db62SRatan Gupta     if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
109e1f4db62SRatan Gupta     {
11011ec666bSJiaqing Zhao         lg2::error("LDAP server CA certificate not found at {PATH}", "PATH",
11111ec666bSJiaqing Zhao                    tlsCacertFile);
112e1f4db62SRatan Gupta         elog<NoCACertificate>();
113e1f4db62SRatan Gupta     }
114e1f4db62SRatan Gupta 
115e6500a49SPatrick Williams     if (ldapBindDN.empty())
116e1f4db62SRatan Gupta     {
11711ec666bSJiaqing Zhao         lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN",
11811ec666bSJiaqing Zhao                    ldapBindDN);
119e1f4db62SRatan Gupta         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBindDN"),
120e6500a49SPatrick Williams                               Argument::ARGUMENT_VALUE(ldapBindDN.c_str()));
121e1f4db62SRatan Gupta     }
122e1f4db62SRatan Gupta 
123e6500a49SPatrick Williams     if (ldapBaseDN.empty())
124e1f4db62SRatan Gupta     {
12511ec666bSJiaqing Zhao         lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN",
12611ec666bSJiaqing Zhao                    ldapBaseDN);
127e1f4db62SRatan Gupta         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBaseDN"),
128e6500a49SPatrick Williams                               Argument::ARGUMENT_VALUE(ldapBaseDN.c_str()));
129e1f4db62SRatan Gupta     }
130e1f4db62SRatan Gupta 
13127d4c011SRatan Gupta     // With current implementation we support only two default LDAP server.
13227d4c011SRatan Gupta     // which will be always there but when the support comes for additional
13327d4c011SRatan Gupta     // account providers then the create config would be used to create the
13427d4c011SRatan Gupta     // additional config.
135e1f4db62SRatan Gupta 
13627d4c011SRatan Gupta     std::string objPath;
13727d4c011SRatan Gupta 
138e6500a49SPatrick Williams     if (static_cast<ConfigIface::Type>(ldapType) == ConfigIface::Type::OpenLdap)
13927d4c011SRatan Gupta     {
14027d4c011SRatan Gupta         openLDAPConfigPtr.reset(nullptr);
14127d4c011SRatan Gupta         objPath = openLDAPDbusObjectPath;
14227d4c011SRatan Gupta         openLDAPConfigPtr = std::make_unique<Config>(
143e1f4db62SRatan Gupta             bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
144e6500a49SPatrick Williams             tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
145e6500a49SPatrick Williams             ldapBaseDN, std::move(ldapBindDNPassword),
146e6500a49SPatrick Williams             static_cast<ConfigIface::SearchScope>(ldapSearchScope),
147e6500a49SPatrick Williams             static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
148e1f4db62SRatan Gupta             userNameAttribute, *this);
14927d4c011SRatan Gupta     }
15027d4c011SRatan Gupta     else
15127d4c011SRatan Gupta     {
15227d4c011SRatan Gupta         ADConfigPtr.reset(nullptr);
15378d85042SNan Zhou         objPath = adDbusObjectPath;
15427d4c011SRatan Gupta         ADConfigPtr = std::make_unique<Config>(
15527d4c011SRatan Gupta             bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
156e6500a49SPatrick Williams             tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
157e6500a49SPatrick Williams             ldapBaseDN, std::move(ldapBindDNPassword),
158e6500a49SPatrick Williams             static_cast<ConfigIface::SearchScope>(ldapSearchScope),
159e6500a49SPatrick Williams             static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
16027d4c011SRatan Gupta             userNameAttribute, *this);
16127d4c011SRatan Gupta     }
162e1f4db62SRatan Gupta     restartService(nscdService);
163e1f4db62SRatan Gupta     return objPath;
164e1f4db62SRatan Gupta }
165e1f4db62SRatan Gupta 
createDefaultObjects()16627d4c011SRatan Gupta void ConfigMgr::createDefaultObjects()
167e1f4db62SRatan Gupta {
16827d4c011SRatan Gupta     if (!openLDAPConfigPtr)
169e1f4db62SRatan Gupta     {
17027d4c011SRatan Gupta         openLDAPConfigPtr = std::make_unique<Config>(
17127d4c011SRatan Gupta             bus, openLDAPDbusObjectPath.c_str(), configFilePath.c_str(),
172ab4fcb4cSRatan Gupta             tlsCacertFile.c_str(), tlsCertFile.c_str(),
173ab4fcb4cSRatan Gupta             ConfigIface::Type::OpenLdap, *this);
17421e88cb5SRatan Gupta         openLDAPConfigPtr->emit_object_added();
175e1f4db62SRatan Gupta     }
17627d4c011SRatan Gupta     if (!ADConfigPtr)
177e1f4db62SRatan Gupta     {
17827d4c011SRatan Gupta         ADConfigPtr = std::make_unique<Config>(
17978d85042SNan Zhou             bus, adDbusObjectPath.c_str(), configFilePath.c_str(),
180ab4fcb4cSRatan Gupta             tlsCacertFile.c_str(), tlsCertFile.c_str(),
181ab4fcb4cSRatan Gupta             ConfigIface::Type::ActiveDirectory, *this);
18221e88cb5SRatan Gupta         ADConfigPtr->emit_object_added();
18321e88cb5SRatan Gupta     }
18421e88cb5SRatan Gupta }
18521e88cb5SRatan Gupta 
enableService(Config & config,bool value)186c5481d1cSRatan Gupta bool ConfigMgr::enableService(Config& config, bool value)
187c5481d1cSRatan Gupta {
188c5481d1cSRatan Gupta     if (value)
189c5481d1cSRatan Gupta     {
190c5481d1cSRatan Gupta         if (openLDAPConfigPtr && openLDAPConfigPtr->enabled())
191c5481d1cSRatan Gupta         {
192c5481d1cSRatan Gupta             elog<NotAllowed>(NotAllowedArgument::REASON(
193c5481d1cSRatan Gupta                 "OpenLDAP service is already active"));
194c5481d1cSRatan Gupta         }
195c5481d1cSRatan Gupta         if (ADConfigPtr && ADConfigPtr->enabled())
196c5481d1cSRatan Gupta         {
197c5481d1cSRatan Gupta             elog<NotAllowed>(NotAllowedArgument::REASON(
198c5481d1cSRatan Gupta                 "ActiveDirectory service is already active"));
199c5481d1cSRatan Gupta         }
200c5481d1cSRatan Gupta     }
201c5481d1cSRatan Gupta     return config.enableService(value);
202c5481d1cSRatan Gupta }
203c5481d1cSRatan Gupta 
restore()20421e88cb5SRatan Gupta void ConfigMgr::restore()
20521e88cb5SRatan Gupta {
20621e88cb5SRatan Gupta     createDefaultObjects();
20721e88cb5SRatan Gupta     // Restore the ldap config and their mappings
20821e88cb5SRatan Gupta     if (ADConfigPtr->deserialize())
20921e88cb5SRatan Gupta     {
2107b04c352SRatan Gupta         // Restore the role mappings
2117b04c352SRatan Gupta         ADConfigPtr->restoreRoleMapping();
21221e88cb5SRatan Gupta         ADConfigPtr->emit_object_added();
21321e88cb5SRatan Gupta     }
21421e88cb5SRatan Gupta     if (openLDAPConfigPtr->deserialize())
21521e88cb5SRatan Gupta     {
2167b04c352SRatan Gupta         // Restore the role mappings
2177b04c352SRatan Gupta         openLDAPConfigPtr->restoreRoleMapping();
21821e88cb5SRatan Gupta         openLDAPConfigPtr->emit_object_added();
219e1f4db62SRatan Gupta     }
220372c5668SAlexander Filippov 
221372c5668SAlexander Filippov     startOrStopService(phosphor::ldap::nslcdService,
222372c5668SAlexander Filippov                        ADConfigPtr->enabled() || openLDAPConfigPtr->enabled());
223e1f4db62SRatan Gupta }
224e1f4db62SRatan Gupta 
225e1f4db62SRatan Gupta } // namespace ldap
226e1f4db62SRatan Gupta } // namespace phosphor
227