1e1f4db62SRatan Gupta #include "ldap_config_mgr.hpp"
2e1f4db62SRatan Gupta 
39638afb9SPatrick Williams #include "ldap_config.hpp"
4e1f4db62SRatan Gupta #include "utils.hpp"
59638afb9SPatrick Williams 
6e1f4db62SRatan Gupta #include <filesystem>
7e1f4db62SRatan Gupta #include <fstream>
8e1f4db62SRatan Gupta #include <sstream>
9e1f4db62SRatan Gupta 
10e1f4db62SRatan Gupta namespace phosphor
11e1f4db62SRatan Gupta {
12e1f4db62SRatan Gupta namespace ldap
13e1f4db62SRatan Gupta {
14e1f4db62SRatan Gupta 
15372c5668SAlexander Filippov constexpr auto nslcdService = "nslcd.service";
16e1f4db62SRatan Gupta constexpr auto nscdService = "nscd.service";
17*78d85042SNan Zhou constexpr auto ldapScheme = "ldap";
18*78d85042SNan Zhou constexpr auto ldapsScheme = "ldaps";
19e1f4db62SRatan Gupta 
20e1f4db62SRatan Gupta using namespace phosphor::logging;
21e1f4db62SRatan Gupta using namespace sdbusplus::xyz::openbmc_project::Common::Error;
22e1f4db62SRatan Gupta namespace fs = std::filesystem;
23e1f4db62SRatan Gupta using Argument = xyz::openbmc_project::Common::InvalidArgument;
24c5481d1cSRatan Gupta using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
25c5481d1cSRatan Gupta using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
26e1f4db62SRatan Gupta 
27e1f4db62SRatan Gupta using Line = std::string;
28e1f4db62SRatan Gupta using Key = std::string;
29e1f4db62SRatan Gupta using Val = std::string;
30e1f4db62SRatan Gupta using ConfigInfo = std::map<Key, Val>;
31e1f4db62SRatan Gupta 
32e1f4db62SRatan Gupta void ConfigMgr::startOrStopService(const std::string& service, bool start)
33e1f4db62SRatan Gupta {
34e1f4db62SRatan Gupta     if (start)
35e1f4db62SRatan Gupta     {
36e1f4db62SRatan Gupta         restartService(service);
37e1f4db62SRatan Gupta     }
38e1f4db62SRatan Gupta     else
39e1f4db62SRatan Gupta     {
40e1f4db62SRatan Gupta         stopService(service);
41e1f4db62SRatan Gupta     }
42e1f4db62SRatan Gupta }
43e1f4db62SRatan Gupta 
44e1f4db62SRatan Gupta void ConfigMgr::restartService(const std::string& service)
45e1f4db62SRatan Gupta {
46e1f4db62SRatan Gupta     try
47e1f4db62SRatan Gupta     {
48e1f4db62SRatan Gupta         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
49e1f4db62SRatan Gupta                                           SYSTEMD_INTERFACE, "RestartUnit");
50e1f4db62SRatan Gupta         method.append(service.c_str(), "replace");
51e1f4db62SRatan Gupta         bus.call_noreply(method);
52e1f4db62SRatan Gupta     }
53b3ef4e1aSPatrick Williams     catch (const sdbusplus::exception_t& ex)
54e1f4db62SRatan Gupta     {
55e1f4db62SRatan Gupta         log<level::ERR>("Failed to restart service",
56e1f4db62SRatan Gupta                         entry("SERVICE=%s", service.c_str()),
57e1f4db62SRatan Gupta                         entry("ERR=%s", ex.what()));
58e1f4db62SRatan Gupta         elog<InternalFailure>();
59e1f4db62SRatan Gupta     }
60e1f4db62SRatan Gupta }
61e1f4db62SRatan Gupta void ConfigMgr::stopService(const std::string& service)
62e1f4db62SRatan Gupta {
63e1f4db62SRatan Gupta     try
64e1f4db62SRatan Gupta     {
65e1f4db62SRatan Gupta         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
66e1f4db62SRatan Gupta                                           SYSTEMD_INTERFACE, "StopUnit");
67e1f4db62SRatan Gupta         method.append(service.c_str(), "replace");
68e1f4db62SRatan Gupta         bus.call_noreply(method);
69e1f4db62SRatan Gupta     }
70b3ef4e1aSPatrick Williams     catch (const sdbusplus::exception_t& ex)
71e1f4db62SRatan Gupta     {
72e1f4db62SRatan Gupta         log<level::ERR>("Failed to stop service",
73e1f4db62SRatan Gupta                         entry("SERVICE=%s", service.c_str()),
74e1f4db62SRatan Gupta                         entry("ERR=%s", ex.what()));
75e1f4db62SRatan Gupta         elog<InternalFailure>();
76e1f4db62SRatan Gupta     }
77e1f4db62SRatan Gupta }
78e1f4db62SRatan Gupta 
79e1f4db62SRatan Gupta std::string ConfigMgr::createConfig(
80e6500a49SPatrick Williams     std::string ldapServerURI, std::string ldapBindDN, std::string ldapBaseDN,
81e6500a49SPatrick Williams     std::string ldapBindDNPassword, CreateIface::SearchScope ldapSearchScope,
82e6500a49SPatrick Williams     CreateIface::Create::Type ldapType, std::string groupNameAttribute,
83e1f4db62SRatan Gupta     std::string userNameAttribute)
84e1f4db62SRatan Gupta {
85e1f4db62SRatan Gupta     bool secureLDAP = false;
86e1f4db62SRatan Gupta 
87*78d85042SNan Zhou     if (isValidLDAPURI(ldapServerURI, ldapsScheme))
88e1f4db62SRatan Gupta     {
89e1f4db62SRatan Gupta         secureLDAP = true;
90e1f4db62SRatan Gupta     }
91*78d85042SNan Zhou     else if (isValidLDAPURI(ldapServerURI, ldapScheme))
92e1f4db62SRatan Gupta     {
93e1f4db62SRatan Gupta         secureLDAP = false;
94e1f4db62SRatan Gupta     }
95e1f4db62SRatan Gupta     else
96e1f4db62SRatan Gupta     {
97e1f4db62SRatan Gupta         log<level::ERR>("bad LDAP Server URI",
98e6500a49SPatrick Williams                         entry("LDAPSERVERURI=%s", ldapServerURI.c_str()));
99e6500a49SPatrick Williams         elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
100e6500a49SPatrick Williams                               Argument::ARGUMENT_VALUE(ldapServerURI.c_str()));
101e1f4db62SRatan Gupta     }
102e1f4db62SRatan Gupta 
103e1f4db62SRatan Gupta     if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
104e1f4db62SRatan Gupta     {
105e1f4db62SRatan Gupta         log<level::ERR>("LDAP server's CA certificate not provided",
106e1f4db62SRatan Gupta                         entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
107e1f4db62SRatan Gupta         elog<NoCACertificate>();
108e1f4db62SRatan Gupta     }
109e1f4db62SRatan Gupta 
110e6500a49SPatrick Williams     if (ldapBindDN.empty())
111e1f4db62SRatan Gupta     {
112e1f4db62SRatan Gupta         log<level::ERR>("Not a valid LDAP BINDDN",
113e6500a49SPatrick Williams                         entry("LDAPBINDDN=%s", ldapBindDN.c_str()));
114e1f4db62SRatan Gupta         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBindDN"),
115e6500a49SPatrick Williams                               Argument::ARGUMENT_VALUE(ldapBindDN.c_str()));
116e1f4db62SRatan Gupta     }
117e1f4db62SRatan Gupta 
118e6500a49SPatrick Williams     if (ldapBaseDN.empty())
119e1f4db62SRatan Gupta     {
120e1f4db62SRatan Gupta         log<level::ERR>("Not a valid LDAP BASEDN",
121e6500a49SPatrick Williams                         entry("LDAPBASEDN=%s", ldapBaseDN.c_str()));
122e1f4db62SRatan Gupta         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBaseDN"),
123e6500a49SPatrick Williams                               Argument::ARGUMENT_VALUE(ldapBaseDN.c_str()));
124e1f4db62SRatan Gupta     }
125e1f4db62SRatan Gupta 
12627d4c011SRatan Gupta     // With current implementation we support only two default LDAP server.
12727d4c011SRatan Gupta     // which will be always there but when the support comes for additional
12827d4c011SRatan Gupta     // account providers then the create config would be used to create the
12927d4c011SRatan Gupta     // additional config.
130e1f4db62SRatan Gupta 
13127d4c011SRatan Gupta     std::string objPath;
13227d4c011SRatan Gupta 
133e6500a49SPatrick Williams     if (static_cast<ConfigIface::Type>(ldapType) == ConfigIface::Type::OpenLdap)
13427d4c011SRatan Gupta     {
13527d4c011SRatan Gupta         openLDAPConfigPtr.reset(nullptr);
13627d4c011SRatan Gupta         objPath = openLDAPDbusObjectPath;
13727d4c011SRatan Gupta         openLDAPConfigPtr = std::make_unique<Config>(
138e1f4db62SRatan Gupta             bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
139e6500a49SPatrick Williams             tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
140e6500a49SPatrick Williams             ldapBaseDN, std::move(ldapBindDNPassword),
141e6500a49SPatrick Williams             static_cast<ConfigIface::SearchScope>(ldapSearchScope),
142e6500a49SPatrick Williams             static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
143e1f4db62SRatan Gupta             userNameAttribute, *this);
14427d4c011SRatan Gupta     }
14527d4c011SRatan Gupta     else
14627d4c011SRatan Gupta     {
14727d4c011SRatan Gupta         ADConfigPtr.reset(nullptr);
148*78d85042SNan Zhou         objPath = adDbusObjectPath;
14927d4c011SRatan Gupta         ADConfigPtr = std::make_unique<Config>(
15027d4c011SRatan Gupta             bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
151e6500a49SPatrick Williams             tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
152e6500a49SPatrick Williams             ldapBaseDN, std::move(ldapBindDNPassword),
153e6500a49SPatrick Williams             static_cast<ConfigIface::SearchScope>(ldapSearchScope),
154e6500a49SPatrick Williams             static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
15527d4c011SRatan Gupta             userNameAttribute, *this);
15627d4c011SRatan Gupta     }
157e1f4db62SRatan Gupta     restartService(nscdService);
158e1f4db62SRatan Gupta     return objPath;
159e1f4db62SRatan Gupta }
160e1f4db62SRatan Gupta 
16127d4c011SRatan Gupta void ConfigMgr::createDefaultObjects()
162e1f4db62SRatan Gupta {
16327d4c011SRatan Gupta     if (!openLDAPConfigPtr)
164e1f4db62SRatan Gupta     {
16527d4c011SRatan Gupta         openLDAPConfigPtr = std::make_unique<Config>(
16627d4c011SRatan Gupta             bus, openLDAPDbusObjectPath.c_str(), configFilePath.c_str(),
167ab4fcb4cSRatan Gupta             tlsCacertFile.c_str(), tlsCertFile.c_str(),
168ab4fcb4cSRatan Gupta             ConfigIface::Type::OpenLdap, *this);
16921e88cb5SRatan Gupta         openLDAPConfigPtr->emit_object_added();
170e1f4db62SRatan Gupta     }
17127d4c011SRatan Gupta     if (!ADConfigPtr)
172e1f4db62SRatan Gupta     {
17327d4c011SRatan Gupta         ADConfigPtr = std::make_unique<Config>(
174*78d85042SNan Zhou             bus, adDbusObjectPath.c_str(), configFilePath.c_str(),
175ab4fcb4cSRatan Gupta             tlsCacertFile.c_str(), tlsCertFile.c_str(),
176ab4fcb4cSRatan Gupta             ConfigIface::Type::ActiveDirectory, *this);
17721e88cb5SRatan Gupta         ADConfigPtr->emit_object_added();
17821e88cb5SRatan Gupta     }
17921e88cb5SRatan Gupta }
18021e88cb5SRatan Gupta 
181c5481d1cSRatan Gupta bool ConfigMgr::enableService(Config& config, bool value)
182c5481d1cSRatan Gupta {
183c5481d1cSRatan Gupta     if (value)
184c5481d1cSRatan Gupta     {
185c5481d1cSRatan Gupta         if (openLDAPConfigPtr && openLDAPConfigPtr->enabled())
186c5481d1cSRatan Gupta         {
187c5481d1cSRatan Gupta             elog<NotAllowed>(NotAllowedArgument::REASON(
188c5481d1cSRatan Gupta                 "OpenLDAP service is already active"));
189c5481d1cSRatan Gupta         }
190c5481d1cSRatan Gupta         if (ADConfigPtr && ADConfigPtr->enabled())
191c5481d1cSRatan Gupta         {
192c5481d1cSRatan Gupta             elog<NotAllowed>(NotAllowedArgument::REASON(
193c5481d1cSRatan Gupta                 "ActiveDirectory service is already active"));
194c5481d1cSRatan Gupta         }
195c5481d1cSRatan Gupta     }
196c5481d1cSRatan Gupta     return config.enableService(value);
197c5481d1cSRatan Gupta }
198c5481d1cSRatan Gupta 
19921e88cb5SRatan Gupta void ConfigMgr::restore()
20021e88cb5SRatan Gupta {
20121e88cb5SRatan Gupta     createDefaultObjects();
20221e88cb5SRatan Gupta     // Restore the ldap config and their mappings
20321e88cb5SRatan Gupta     if (ADConfigPtr->deserialize())
20421e88cb5SRatan Gupta     {
2057b04c352SRatan Gupta         // Restore the role mappings
2067b04c352SRatan Gupta         ADConfigPtr->restoreRoleMapping();
20721e88cb5SRatan Gupta         ADConfigPtr->emit_object_added();
20821e88cb5SRatan Gupta     }
20921e88cb5SRatan Gupta     if (openLDAPConfigPtr->deserialize())
21021e88cb5SRatan Gupta     {
2117b04c352SRatan Gupta         // Restore the role mappings
2127b04c352SRatan Gupta         openLDAPConfigPtr->restoreRoleMapping();
21321e88cb5SRatan Gupta         openLDAPConfigPtr->emit_object_added();
214e1f4db62SRatan Gupta     }
215372c5668SAlexander Filippov 
216372c5668SAlexander Filippov     startOrStopService(phosphor::ldap::nslcdService,
217372c5668SAlexander Filippov                        ADConfigPtr->enabled() || openLDAPConfigPtr->enabled());
218e1f4db62SRatan Gupta }
219e1f4db62SRatan Gupta 
220e1f4db62SRatan Gupta } // namespace ldap
221e1f4db62SRatan Gupta } // namespace phosphor
222