blob: aa984c63f0918fd576b38cd2ab813d86afa8ab94 [file] [log] [blame]
Ratan Guptae1f4db62019-04-11 18:57:42 +05301#include "ldap_config_mgr.hpp"
Ratan Gupta37fb3fe2019-04-13 12:54:18 +05302#include "ldap_config.hpp"
3#include "ldap_config_serialize.hpp"
Nagaraju Goruganti59287f02018-10-12 07:00:20 -05004#include "utils.hpp"
Ratan Gupta95a29312019-02-18 20:34:10 +05305#include <filesystem>
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -05006#include <fstream>
7#include <sstream>
8
9namespace phosphor
10{
11namespace ldap
12{
Ratan Guptae1f4db62019-04-11 18:57:42 +053013
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050014constexpr auto nslcdService = "nslcd.service";
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050015constexpr auto nscdService = "nscd.service";
Nagaraju Goruganti59287f02018-10-12 07:00:20 -050016constexpr auto LDAPscheme = "ldap";
17constexpr auto LDAPSscheme = "ldaps";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050018
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050019using namespace phosphor::logging;
20using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta95a29312019-02-18 20:34:10 +053021namespace fs = std::filesystem;
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050022using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta27d4c012019-04-12 13:03:35 +053023using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
24using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050025
26using Line = std::string;
27using Key = std::string;
28using Val = std::string;
29using ConfigInfo = std::map<Key, Val>;
30
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050031Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -060032 const char* caCertFile, bool secureLDAP,
33 std::string lDAPServerURI, std::string lDAPBindDN,
34 std::string lDAPBaseDN, std::string&& lDAPBindDNPassword,
Ratan Guptaaeaf9412019-02-11 04:41:52 -060035 ConfigIface::SearchScope lDAPSearchScope,
36 ConfigIface::Type lDAPType, bool lDAPServiceEnabled,
37 std::string userNameAttr, std::string groupNameAttr,
38 ConfigMgr& parent) :
39 Ifaces(bus, path, true),
Ratan Gupta3a1c2742019-03-20 06:49:42 +053040 secureLDAP(secureLDAP), lDAPBindPassword(std::move(lDAPBindDNPassword)),
41 configFilePath(filePath), tlsCacertFile(caCertFile), bus(bus),
42 parent(parent)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050043{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050044 ConfigIface::lDAPServerURI(lDAPServerURI);
45 ConfigIface::lDAPBindDN(lDAPBindDN);
46 ConfigIface::lDAPBaseDN(lDAPBaseDN);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050047 ConfigIface::lDAPSearchScope(lDAPSearchScope);
48 ConfigIface::lDAPType(lDAPType);
Ratan Guptaaeaf9412019-02-11 04:41:52 -060049 EnableIface::enabled(lDAPServiceEnabled);
50 ConfigIface::userNameAttribute(userNameAttr);
51 ConfigIface::groupNameAttribute(groupNameAttr);
Ratan Gupta3a1c2742019-03-20 06:49:42 +053052 // Don't update the bindDN password under ConfigIface::
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050053 writeConfig();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050054 // Emit deferred signal.
55 this->emit_object_added();
Ratan Guptaaeaf9412019-02-11 04:41:52 -060056 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050057}
58
59void Config::writeConfig()
60{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050061 std::stringstream confData;
Ratan Gupta9891f2f2018-10-06 12:07:35 +053062 auto isPwdTobeWritten = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -060063 std::string userNameAttr;
Ratan Gupta9891f2f2018-10-06 12:07:35 +053064
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050065 confData << "uid root\n";
66 confData << "gid root\n\n";
67 confData << "ldap_version 3\n\n";
68 confData << "timelimit 30\n";
69 confData << "bind_timelimit 30\n";
70 confData << "pagesize 1000\n";
71 confData << "referrals off\n\n";
72 confData << "uri " << lDAPServerURI() << "\n\n";
73 confData << "base " << lDAPBaseDN() << "\n\n";
74 confData << "binddn " << lDAPBindDN() << "\n";
Ratan Gupta3a1c2742019-03-20 06:49:42 +053075 if (!lDAPBindPassword.empty())
Nagaraju Goruganti15675472018-10-05 07:03:05 -050076 {
Ratan Gupta3a1c2742019-03-20 06:49:42 +053077 confData << "bindpw " << lDAPBindPassword << "\n";
Ratan Gupta9891f2f2018-10-06 12:07:35 +053078 isPwdTobeWritten = true;
Nagaraju Goruganti15675472018-10-05 07:03:05 -050079 }
80 confData << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050081 switch (lDAPSearchScope())
82 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -060083 case ConfigIface::SearchScope::sub:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050084 confData << "scope sub\n\n";
85 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -060086 case ConfigIface::SearchScope::one:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050087 confData << "scope one\n\n";
88 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -060089 case ConfigIface::SearchScope::base:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050090 confData << "scope base\n\n";
91 break;
92 }
93 confData << "base passwd " << lDAPBaseDN() << "\n";
94 confData << "base shadow " << lDAPBaseDN() << "\n\n";
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -060095 if (secureLDAP == true)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050096 {
97 confData << "ssl on\n";
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -060098 confData << "tls_reqcert hard\n";
99 confData << "tls_cacertFile " << tlsCacertFile.c_str() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500100 }
101 else
102 {
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500103 confData << "ssl off\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500104 }
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500105 confData << "\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600106 if (lDAPType() == ConfigIface::Type::ActiveDirectory)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500107 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600108 if (ConfigIface::userNameAttribute().empty())
109 {
110 ConfigIface::userNameAttribute("sAMAccountName");
111 }
112 if (ConfigIface::groupNameAttribute().empty())
113 {
114 ConfigIface::groupNameAttribute("primaryGroupID");
115 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500116 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
117 "(!(objectClass=computer)))\n";
118 confData
119 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
120 "(objectclass=groupofuniquenames))\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600121 confData << "map passwd uid "
122 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500123 confData << "map passwd uidNumber "
124 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600125 confData << "map passwd gidNumber "
126 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500127 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
128 confData << "map passwd gecos displayName\n";
129 confData << "map passwd loginShell \"/bin/bash\"\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500130 confData << "map group gidNumber "
131 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600132 confData << "map group cn "
133 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500134 }
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600135 else if (lDAPType() == ConfigIface::Type::OpenLdap)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500136 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600137 if (ConfigIface::userNameAttribute().empty())
138 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500139 ConfigIface::userNameAttribute("cn");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600140 }
141 if (ConfigIface::groupNameAttribute().empty())
142 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500143 ConfigIface::groupNameAttribute("gidNumber");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600144 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500145 confData << "filter passwd (objectclass=*)\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500146 confData << "map passwd gecos displayName\n";
Nagaraju Goruganti808eda42018-10-10 08:48:12 -0500147 confData << "filter group (objectclass=posixGroup)\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600148 confData << "map passwd uid "
149 << ConfigIface::userNameAttribute() << "\n";
150 confData << "map passwd gidNumber "
151 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500152 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500153 try
154 {
155 std::fstream stream(configFilePath.c_str(), std::fstream::out);
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530156 // remove the read permission from others if password is being written.
157 // nslcd forces this behaviour.
158 auto permission = fs::perms::owner_read | fs::perms::owner_write |
159 fs::perms::group_read;
160 if (isPwdTobeWritten)
161 {
162 fs::permissions(configFilePath, permission);
163 }
164 else
165 {
166 fs::permissions(configFilePath,
167 permission | fs::perms::others_read);
168 }
169
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500170 stream << confData.str();
171 stream.flush();
172 stream.close();
173 }
174 catch (const std::exception& e)
175 {
176 log<level::ERR>(e.what());
177 elog<InternalFailure>();
178 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500179 return;
180}
181
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530182std::string Config::lDAPBindDNPassword(std::string value)
183{
184 // Don't update the D-bus object, this is just to
185 // facilitate if user wants to change the bind dn password
186 // once d-bus object gets created.
187 lDAPBindPassword = value;
188 try
189 {
190 writeConfig();
191 parent.startOrStopService(nslcdService, enabled());
192 }
193 catch (const InternalFailure& e)
194 {
195 throw;
196 }
197 catch (const std::exception& e)
198 {
199 log<level::ERR>(e.what());
200 elog<InternalFailure>();
201 }
202 return value;
203}
204
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500205std::string Config::lDAPServerURI(std::string value)
206{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500207 std::string val;
208 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500209 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500210 if (value == lDAPServerURI())
211 {
212 return value;
213 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500214 if (isValidLDAPURI(value, LDAPSscheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500215 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500216 secureLDAP = true;
217 }
218 else if (isValidLDAPURI(value, LDAPscheme))
219 {
220 secureLDAP = false;
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600221 }
222 else
223 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500224 log<level::ERR>("bad LDAP Server URI",
225 entry("LDAPSERVERURI=%s", value.c_str()));
226 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
227 Argument::ARGUMENT_VALUE(value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500228 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600229
230 if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
231 {
232 log<level::ERR>("LDAP server's CA certificate not provided",
233 entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
234 elog<NoCACertificate>();
235 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500236 val = ConfigIface::lDAPServerURI(value);
237 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600238 parent.startOrStopService(nslcdService, enabled());
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500239 }
240 catch (const InternalFailure& e)
241 {
242 throw;
243 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500244 catch (const InvalidArgument& e)
245 {
246 throw;
247 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600248 catch (const NoCACertificate& e)
249 {
250 throw;
251 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500252 catch (const std::exception& e)
253 {
254 log<level::ERR>(e.what());
255 elog<InternalFailure>();
256 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500257 return val;
258}
259
260std::string Config::lDAPBindDN(std::string value)
261{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500262 std::string val;
263 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500264 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500265 if (value == lDAPBindDN())
266 {
267 return value;
268 }
269
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500270 if (value.empty())
271 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500272 log<level::ERR>("Not a valid LDAP BINDDN",
273 entry("LDAPBINDDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500274 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"),
275 Argument::ARGUMENT_VALUE(value.c_str()));
276 }
277
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500278 val = ConfigIface::lDAPBindDN(value);
279 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600280 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500281 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500282 catch (const InternalFailure& e)
283 {
284 throw;
285 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600286 catch (const InvalidArgument& e)
287 {
288 throw;
289 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500290 catch (const std::exception& e)
291 {
292 log<level::ERR>(e.what());
293 elog<InternalFailure>();
294 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500295 return val;
296}
297
298std::string Config::lDAPBaseDN(std::string value)
299{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500300 std::string val;
301 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500302 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500303 if (value == lDAPBaseDN())
304 {
305 return value;
306 }
307
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500308 if (value.empty())
309 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500310 log<level::ERR>("Not a valid LDAP BASEDN",
311 entry("BASEDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500312 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"),
313 Argument::ARGUMENT_VALUE(value.c_str()));
314 }
315
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500316 val = ConfigIface::lDAPBaseDN(value);
317 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600318 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500319 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500320 catch (const InternalFailure& e)
321 {
322 throw;
323 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600324 catch (const InvalidArgument& e)
325 {
326 throw;
327 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500328 catch (const std::exception& e)
329 {
330 log<level::ERR>(e.what());
331 elog<InternalFailure>();
332 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500333 return val;
334}
335
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600336ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500337{
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600338 ConfigIface::SearchScope val;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500339 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500340 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500341 if (value == lDAPSearchScope())
342 {
343 return value;
344 }
345
346 val = ConfigIface::lDAPSearchScope(value);
347 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600348 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500349 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500350 catch (const InternalFailure& e)
351 {
352 throw;
353 }
354 catch (const std::exception& e)
355 {
356 log<level::ERR>(e.what());
357 elog<InternalFailure>();
358 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500359 return val;
360}
361
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600362ConfigIface::Type Config::lDAPType(ConfigIface::Type value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500363{
Ratan Gupta27d4c012019-04-12 13:03:35 +0530364 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
365 return lDAPType();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500366}
367
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600368bool Config::enabled(bool value)
369{
370 bool isEnable;
371 try
372 {
373 if (value == enabled())
374 {
375 return value;
376 }
377 isEnable = EnableIface::enabled(value);
Ratan Gupta95a29312019-02-18 20:34:10 +0530378 // save the enabled property.
379 serialize(*this, parent.dbusPersistentPath);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600380 parent.startOrStopService(nslcdService, value);
381 }
382 catch (const InternalFailure& e)
383 {
384 throw;
385 }
386 catch (const std::exception& e)
387 {
388 log<level::ERR>(e.what());
389 elog<InternalFailure>();
390 }
391 return isEnable;
392}
393
394std::string Config::userNameAttribute(std::string value)
395{
396 std::string val;
397 try
398 {
399 if (value == userNameAttribute())
400 {
401 return value;
402 }
403
404 val = ConfigIface::userNameAttribute(value);
405 writeConfig();
406 parent.startOrStopService(nslcdService, enabled());
407 }
408 catch (const InternalFailure& e)
409 {
410 throw;
411 }
412 catch (const std::exception& e)
413 {
414 log<level::ERR>(e.what());
415 elog<InternalFailure>();
416 }
417 return val;
418}
419
420std::string Config::groupNameAttribute(std::string value)
421{
422 std::string val;
423 try
424 {
425 if (value == groupNameAttribute())
426 {
427 return value;
428 }
429
430 val = ConfigIface::groupNameAttribute(value);
431 writeConfig();
432 parent.startOrStopService(nslcdService, enabled());
433 }
434 catch (const InternalFailure& e)
435 {
436 throw;
437 }
438 catch (const std::exception& e)
439 {
440 log<level::ERR>(e.what());
441 elog<InternalFailure>();
442 }
443 return val;
444}
445
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500446} // namespace ldap
447} // namespace phosphor