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