1 #include "ldap_config_mgr.hpp"
2 
3 #include "ldap_config.hpp"
4 #include "utils.hpp"
5 
6 #include <phosphor-logging/elog-errors.hpp>
7 #include <phosphor-logging/elog.hpp>
8 #include <phosphor-logging/lg2.hpp>
9 #include <xyz/openbmc_project/Common/error.hpp>
10 
11 #include <filesystem>
12 #include <fstream>
13 #include <sstream>
14 
15 namespace phosphor
16 {
17 namespace ldap
18 {
19 
20 constexpr auto systemdBusname = "org.freedesktop.systemd1";
21 constexpr auto systemdObjPath = "/org/freedesktop/systemd1";
22 constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
23 
24 constexpr auto nslcdService = "nslcd.service";
25 constexpr auto nscdService = "nscd.service";
26 constexpr auto ldapScheme = "ldap";
27 constexpr auto ldapsScheme = "ldaps";
28 
29 using namespace phosphor::logging;
30 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
31 namespace fs = std::filesystem;
32 using Argument = xyz::openbmc_project::Common::InvalidArgument;
33 using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
34 
35 using Line = std::string;
36 using Key = std::string;
37 using Val = std::string;
38 using ConfigInfo = std::map<Key, Val>;
39 
startOrStopService(const std::string & service,bool start)40 void ConfigMgr::startOrStopService(const std::string& service, bool start)
41 {
42     if (start)
43     {
44         restartService(service);
45     }
46     else
47     {
48         stopService(service);
49     }
50 }
51 
restartService(const std::string & service)52 void ConfigMgr::restartService(const std::string& service)
53 {
54     try
55     {
56         auto method = bus.new_method_call(systemdBusname, systemdObjPath,
57                                           systemdInterface, "RestartUnit");
58         method.append(service.c_str(), "replace");
59         bus.call_noreply(method);
60     }
61     catch (const sdbusplus::exception_t& ex)
62     {
63         lg2::error("Failed to restart service {SERVICE}: {ERR}", "SERVICE",
64                    service, "ERR", ex);
65         elog<InternalFailure>();
66     }
67 }
stopService(const std::string & service)68 void ConfigMgr::stopService(const std::string& service)
69 {
70     try
71     {
72         auto method = bus.new_method_call(systemdBusname, systemdObjPath,
73                                           systemdInterface, "StopUnit");
74         method.append(service.c_str(), "replace");
75         bus.call_noreply(method);
76     }
77     catch (const sdbusplus::exception_t& ex)
78     {
79         lg2::error("Failed to stop service {SERVICE}: {ERR}", "SERVICE",
80                    service, "ERR", ex);
81         elog<InternalFailure>();
82     }
83 }
84 
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)85 std::string ConfigMgr::createConfig(
86     std::string ldapServerURI, std::string ldapBindDN, std::string ldapBaseDN,
87     std::string ldapBindDNPassword, CreateIface::SearchScope ldapSearchScope,
88     CreateIface::Create::Type ldapType, std::string groupNameAttribute,
89     std::string userNameAttribute)
90 {
91     bool secureLDAP = false;
92 
93     if (isValidLDAPURI(ldapServerURI, ldapsScheme))
94     {
95         secureLDAP = true;
96     }
97     else if (isValidLDAPURI(ldapServerURI, ldapScheme))
98     {
99         secureLDAP = false;
100     }
101     else
102     {
103         lg2::error("Bad LDAP Server URI {URI}", "URI", ldapServerURI);
104         elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
105                               Argument::ARGUMENT_VALUE(ldapServerURI.c_str()));
106     }
107 
108     if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
109     {
110         lg2::error("LDAP server CA certificate not found at {PATH}", "PATH",
111                    tlsCacertFile);
112         elog<NoCACertificate>();
113     }
114 
115     if (ldapBindDN.empty())
116     {
117         lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN",
118                    ldapBindDN);
119         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBindDN"),
120                               Argument::ARGUMENT_VALUE(ldapBindDN.c_str()));
121     }
122 
123     if (ldapBaseDN.empty())
124     {
125         lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN",
126                    ldapBaseDN);
127         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBaseDN"),
128                               Argument::ARGUMENT_VALUE(ldapBaseDN.c_str()));
129     }
130 
131     // With current implementation we support only two default LDAP server.
132     // which will be always there but when the support comes for additional
133     // account providers then the create config would be used to create the
134     // additional config.
135 
136     std::string objPath;
137 
138     if (static_cast<ConfigIface::Type>(ldapType) == ConfigIface::Type::OpenLdap)
139     {
140         openLDAPConfigPtr.reset(nullptr);
141         objPath = openLDAPDbusObjectPath;
142         openLDAPConfigPtr = std::make_unique<Config>(
143             bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
144             tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
145             ldapBaseDN, std::move(ldapBindDNPassword),
146             static_cast<ConfigIface::SearchScope>(ldapSearchScope),
147             static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
148             userNameAttribute, *this);
149     }
150     else
151     {
152         ADConfigPtr.reset(nullptr);
153         objPath = adDbusObjectPath;
154         ADConfigPtr = std::make_unique<Config>(
155             bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
156             tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
157             ldapBaseDN, std::move(ldapBindDNPassword),
158             static_cast<ConfigIface::SearchScope>(ldapSearchScope),
159             static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
160             userNameAttribute, *this);
161     }
162     restartService(nscdService);
163     return objPath;
164 }
165 
createDefaultObjects()166 void ConfigMgr::createDefaultObjects()
167 {
168     if (!openLDAPConfigPtr)
169     {
170         openLDAPConfigPtr = std::make_unique<Config>(
171             bus, openLDAPDbusObjectPath.c_str(), configFilePath.c_str(),
172             tlsCacertFile.c_str(), tlsCertFile.c_str(),
173             ConfigIface::Type::OpenLdap, *this);
174         openLDAPConfigPtr->emit_object_added();
175     }
176     if (!ADConfigPtr)
177     {
178         ADConfigPtr = std::make_unique<Config>(
179             bus, adDbusObjectPath.c_str(), configFilePath.c_str(),
180             tlsCacertFile.c_str(), tlsCertFile.c_str(),
181             ConfigIface::Type::ActiveDirectory, *this);
182         ADConfigPtr->emit_object_added();
183     }
184 }
185 
enableService(Config & config,bool value)186 bool ConfigMgr::enableService(Config& config, bool value)
187 {
188     if (value)
189     {
190         if (openLDAPConfigPtr && openLDAPConfigPtr->enabled())
191         {
192             elog<NotAllowed>(NotAllowedArgument::REASON(
193                 "OpenLDAP service is already active"));
194         }
195         if (ADConfigPtr && ADConfigPtr->enabled())
196         {
197             elog<NotAllowed>(NotAllowedArgument::REASON(
198                 "ActiveDirectory service is already active"));
199         }
200     }
201     return config.enableService(value);
202 }
203 
restore()204 void ConfigMgr::restore()
205 {
206     createDefaultObjects();
207     // Restore the ldap config and their mappings
208     if (ADConfigPtr->deserialize())
209     {
210         // Restore the role mappings
211         ADConfigPtr->restoreRoleMapping();
212         ADConfigPtr->emit_object_added();
213     }
214     if (openLDAPConfigPtr->deserialize())
215     {
216         // Restore the role mappings
217         openLDAPConfigPtr->restoreRoleMapping();
218         openLDAPConfigPtr->emit_object_added();
219     }
220 
221     startOrStopService(phosphor::ldap::nslcdService,
222                        ADConfigPtr->enabled() || openLDAPConfigPtr->enabled());
223 }
224 
225 } // namespace ldap
226 } // namespace phosphor
227