blob: 222793efd30364d242b75c447d63114f778990f5 [file] [log] [blame]
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -05001#include "ldap_configuration.hpp"
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -05002#include <experimental/filesystem>
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -05003#include <fstream>
4#include <sstream>
5
6namespace phosphor
7{
8namespace ldap
9{
10constexpr auto nslcdService = "nslcd.service";
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050011constexpr auto nscdService = "nscd.service";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050012
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050013using namespace phosphor::logging;
14using namespace sdbusplus::xyz::openbmc_project::Common::Error;
15namespace fs = std::experimental::filesystem;
16
17using Line = std::string;
18using Key = std::string;
19using Val = std::string;
20using ConfigInfo = std::map<Key, Val>;
21
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050022Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
23 bool secureLDAP, std::string lDAPServerURI,
24 std::string lDAPBindDN, std::string lDAPBaseDN,
25 std::string lDAPBindDNpassword,
26 ldap_base::Config::SearchScope lDAPSearchScope,
27 ldap_base::Config::Type lDAPType, ConfigMgr& parent) :
28 ConfigIface(bus, path, true),
29 configFilePath(filePath), bus(bus), parent(parent)
30{
31 ConfigIface::secureLDAP(secureLDAP);
32 ConfigIface::lDAPServerURI(lDAPServerURI);
33 ConfigIface::lDAPBindDN(lDAPBindDN);
34 ConfigIface::lDAPBaseDN(lDAPBaseDN);
35 ConfigIface::lDAPBINDDNpassword(lDAPBindDNpassword);
36 ConfigIface::lDAPSearchScope(lDAPSearchScope);
37 ConfigIface::lDAPType(lDAPType);
38 writeConfig();
39 parent.restartService(nslcdService);
40 // Emit deferred signal.
41 this->emit_object_added();
42}
43
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -050044void Config::delete_()
45{
46 parent.deleteObject();
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050047 try
48 {
49 fs::copy_file(defaultNslcdFile, LDAP_CONFIG_FILE,
50 fs::copy_options::overwrite_existing);
51 fs::copy_file(nsSwitchFile, LDAPNsSwitchFile,
52 fs::copy_options::overwrite_existing);
53 fs::copy_file(linuxNsSwitchFile, nsSwitchFile,
54 fs::copy_options::overwrite_existing);
55 }
56 catch (const std::exception& e)
57 {
58 log<level::ERR>("Failed to rename Config Files while deleting Object",
59 entry("ERR=%s", e.what()));
60 elog<InternalFailure>();
61 }
62
63 parent.restartService(nscdService);
64 parent.stopService(nslcdService);
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -050065}
66
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050067void Config::writeConfig()
68{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050069 std::stringstream confData;
70 confData << "uid root\n";
71 confData << "gid root\n\n";
72 confData << "ldap_version 3\n\n";
73 confData << "timelimit 30\n";
74 confData << "bind_timelimit 30\n";
75 confData << "pagesize 1000\n";
76 confData << "referrals off\n\n";
77 confData << "uri " << lDAPServerURI() << "\n\n";
78 confData << "base " << lDAPBaseDN() << "\n\n";
79 confData << "binddn " << lDAPBindDN() << "\n";
80 confData << "bindpw " << lDAPBINDDNpassword() << "\n\n";
81 switch (lDAPSearchScope())
82 {
83 case ldap_base::Config::SearchScope::sub:
84 confData << "scope sub\n\n";
85 break;
86 case ldap_base::Config::SearchScope::one:
87 confData << "scope one\n\n";
88 break;
89 case ldap_base::Config::SearchScope::base:
90 confData << "scope base\n\n";
91 break;
92 }
93 confData << "base passwd " << lDAPBaseDN() << "\n";
94 confData << "base shadow " << lDAPBaseDN() << "\n\n";
95 if (secureLDAP() == true)
96 {
97 confData << "ssl on\n";
98 confData << "tls_reqcert allow\n";
99 confData << "tls_cert /etc/nslcd/certs/cert.pem\n";
100 }
101 else
102 {
103 confData << "ssl off\n\n";
104 }
105 if (lDAPType() == ldap_base::Config::Type::ActiveDirectory)
106 {
107 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
108 "(!(objectClass=computer)))\n";
109 confData
110 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
111 "(objectclass=groupofuniquenames))\n";
112 confData << "map passwd uid sAMAccountName\n";
113 confData << "map passwd uidNumber "
114 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
115 confData << "map passwd gidNumber primaryGroupID\n";
116 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
117 confData << "map passwd gecos displayName\n";
118 confData << "map passwd loginShell \"/bin/bash\"\n";
119 confData << "map group gidNumber primaryGroupID\n";
120 confData << "map group gidNumber "
121 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
122 confData << "map group cn sAMAccountName\n";
123 }
124 else if (lDAPType() == ldap_base::Config::Type::OpenLdap)
125 {
126 confData << "filter passwd (objectclass=*)\n";
127 confData << "map passwd uid cn\n";
128 confData << "map passwd gecos displayName\n";
129 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500130 try
131 {
132 std::fstream stream(configFilePath.c_str(), std::fstream::out);
133 stream << confData.str();
134 stream.flush();
135 stream.close();
136 }
137 catch (const std::exception& e)
138 {
139 log<level::ERR>(e.what());
140 elog<InternalFailure>();
141 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500142 return;
143}
144
145bool Config::secureLDAP(bool value)
146{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500147 bool val = false;
148 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500149 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500150 if (value == secureLDAP())
151 {
152 return value;
153 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500154
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500155 val = ConfigIface::secureLDAP(value);
156 writeConfig();
157 parent.restartService(nslcdService);
158 }
159 catch (const InternalFailure& e)
160 {
161 throw;
162 }
163 catch (const std::exception& e)
164 {
165 log<level::ERR>(e.what());
166 elog<InternalFailure>();
167 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500168
169 return val;
170}
171
172std::string Config::lDAPServerURI(std::string value)
173{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500174 std::string val;
175 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500176 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500177 if (value == lDAPServerURI())
178 {
179 return value;
180 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500181
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500182 val = ConfigIface::lDAPServerURI(value);
183 writeConfig();
184 parent.restartService(nslcdService);
185 }
186 catch (const InternalFailure& e)
187 {
188 throw;
189 }
190 catch (const std::exception& e)
191 {
192 log<level::ERR>(e.what());
193 elog<InternalFailure>();
194 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500195
196 return val;
197}
198
199std::string Config::lDAPBindDN(std::string value)
200{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500201 std::string val;
202 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500203 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500204 if (value == lDAPBindDN())
205 {
206 return value;
207 }
208
209 val = ConfigIface::lDAPBindDN(value);
210 writeConfig();
211 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500212 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500213 catch (const InternalFailure& e)
214 {
215 throw;
216 }
217 catch (const std::exception& e)
218 {
219 log<level::ERR>(e.what());
220 elog<InternalFailure>();
221 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500222 return val;
223}
224
225std::string Config::lDAPBaseDN(std::string value)
226{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500227 std::string val;
228 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500229 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500230 if (value == lDAPBaseDN())
231 {
232 return value;
233 }
234
235 val = ConfigIface::lDAPBaseDN(value);
236 writeConfig();
237 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500238 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500239 catch (const InternalFailure& e)
240 {
241 throw;
242 }
243 catch (const std::exception& e)
244 {
245 log<level::ERR>(e.what());
246 elog<InternalFailure>();
247 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500248 return val;
249}
250
251std::string Config::lDAPBINDDNpassword(std::string value)
252{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500253 std::string val;
254 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500255 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500256 if (value == lDAPBINDDNpassword())
257 {
258 return value;
259 }
260
261 val = ConfigIface::lDAPBINDDNpassword(value);
262 writeConfig();
263 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500264 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500265 catch (const InternalFailure& e)
266 {
267 throw;
268 }
269 catch (const std::exception& e)
270 {
271 log<level::ERR>(e.what());
272 elog<InternalFailure>();
273 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500274 return val;
275}
276
277ldap_base::Config::SearchScope
278 Config::lDAPSearchScope(ldap_base::Config::SearchScope value)
279{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500280 ldap_base::Config::SearchScope val;
281 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500282 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500283 if (value == lDAPSearchScope())
284 {
285 return value;
286 }
287
288 val = ConfigIface::lDAPSearchScope(value);
289 writeConfig();
290 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500291 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500292 catch (const InternalFailure& e)
293 {
294 throw;
295 }
296 catch (const std::exception& e)
297 {
298 log<level::ERR>(e.what());
299 elog<InternalFailure>();
300 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500301 return val;
302}
303
304ldap_base::Config::Type Config::lDAPType(ldap_base::Config::Type value)
305{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500306 ldap_base::Config::Type val;
307 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500308 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500309 if (value == lDAPType())
310 {
311 return value;
312 }
313
314 val = ConfigIface::lDAPType(value);
315 writeConfig();
316 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500317 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500318 catch (const InternalFailure& e)
319 {
320 throw;
321 }
322 catch (const std::exception& e)
323 {
324 log<level::ERR>(e.what());
325 elog<InternalFailure>();
326 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500327 return val;
328}
329
330void ConfigMgr::restartService(const std::string& service)
331{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500332 try
333 {
334 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
335 SYSTEMD_INTERFACE, "RestartUnit");
336 method.append(service.c_str(), "replace");
337 bus.call_noreply(method);
338 }
339 catch (const sdbusplus::exception::SdBusError& ex)
340 {
341 log<level::ERR>("Failed to restart nslcd service",
342 entry("ERR=%s", ex.what()));
343 elog<InternalFailure>();
344 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500345}
346
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500347void ConfigMgr::stopService(const std::string& service)
348{
349 try
350 {
351 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
352 SYSTEMD_INTERFACE, "StopUnit");
353 method.append(service.c_str(), "replace");
354 bus.call_noreply(method);
355 }
356 catch (const sdbusplus::exception::SdBusError& ex)
357 {
358 log<level::ERR>("Failed to stop nslcd service",
359 entry("ERR=%s", ex.what()));
360 elog<InternalFailure>();
361 }
362}
363
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -0500364void ConfigMgr::deleteObject()
365{
366 configPtr.reset(nullptr);
367}
368
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500369std::string
370 ConfigMgr::createConfig(bool secureLDAP, std::string lDAPServerURI,
371 std::string lDAPBindDN, std::string lDAPBaseDN,
372 std::string lDAPBINDDNpassword,
373 ldap_base::Create::SearchScope lDAPSearchScope,
374 ldap_base::Create::Type lDAPType)
375{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500376 // TODO Validate parameters passed-in.
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500377 // With current implementation we support only one LDAP server.
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -0500378 deleteObject();
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500379 try
380 {
381 fs::copy_file(nsSwitchFile, linuxNsSwitchFile,
382 fs::copy_options::overwrite_existing);
383 fs::copy_file(LDAPNsSwitchFile, nsSwitchFile,
384 fs::copy_options::overwrite_existing);
385 }
386 catch (const std::exception& e)
387 {
388 log<level::ERR>("Failed to rename Config Files while creating Object",
389 entry("ERR=%s", e.what()));
390 elog<InternalFailure>();
391 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500392
393 auto objPath = std::string(LDAP_CONFIG_DBUS_OBJ_PATH);
394 configPtr = std::make_unique<Config>(
395 bus, objPath.c_str(), LDAP_CONFIG_FILE, secureLDAP, lDAPServerURI,
396 lDAPBindDN, lDAPBaseDN, lDAPBINDDNpassword,
397 static_cast<ldap_base::Config::SearchScope>(lDAPSearchScope),
398 static_cast<ldap_base::Config::Type>(lDAPType), *this);
399
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500400 restartService(nslcdService);
401 restartService(nscdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500402 return objPath;
403}
404
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500405void ConfigMgr::restore(const char* filePath)
406{
407 if (!fs::exists(filePath))
408 {
409 log<level::ERR>("Config file doesn't exists",
410 entry("LDAP_CONFIG_FILE=%s", LDAP_CONFIG_FILE));
411 return;
412 }
413
414 ConfigInfo configValues;
415
416 try
417 {
418 std::fstream stream(filePath, std::fstream::in);
419 Line line;
420 // read characters from stream and places them into line
421 while (std::getline(stream, line))
422 {
423 // remove leading and trailing extra spaces
424 auto firstScan = line.find_first_not_of(' ');
425 auto first =
426 (firstScan == std::string::npos ? line.length() : firstScan);
427 auto last = line.find_last_not_of(' ');
428 line = line.substr(first, last - first + 1);
429 // reduce multiple spaces between two words to a single space
430 auto pred = [](char a, char b) {
431 return (a == b && a == ' ') ? true : false;
432 };
433
434 auto lastPos = std::unique(line.begin(), line.end(), pred);
435
436 line.erase(lastPos, line.end());
437
438 // Ignore if line is empty or starts with '#'
439 if (line.empty() || line.at(0) == '#')
440 {
441 continue;
442 }
443
444 Key key;
445 std::istringstream isLine(line);
446 // extract characters from isLine and stores them into
447 // key until the delimitation character ' ' is found.
448 // If the delimiter is found, it is extracted and discarded
449 // the next input operation will begin after it.
450 if (std::getline(isLine, key, ' '))
451 {
452 Val value;
453 // extract characters after delimitation character ' '
454 if (std::getline(isLine, value, ' '))
455 {
456 // skip line if it starts with "base shadow" or
457 // "base passwd" because we would have 3 entries
458 // ("base lDAPBaseDN" , "base passwd lDAPBaseDN" and
459 // "base shadow lDAPBaseDN") for the property "lDAPBaseDN",
460 // one is enough to restore it.
461
462 if ((key == "base") &&
463 (value == "passwd" || value == "shadow"))
464 {
465 continue;
466 }
467 // skip the line if it starts with "map passwd".
468 // if config type is AD "map group" entry would be add to
469 // the map configValues. For OpenLdap config file no map
470 // entry would be there.
471 if ((key == "map") && (value == "passwd"))
472 {
473 continue;
474 }
475 configValues[key] = value;
476 }
477 }
478 }
479
480 // extract properties from configValues map
481 bool secureLDAP;
482 if (configValues["ssl"] == "on")
483 {
484 secureLDAP = true;
485 }
486 else
487 {
488 secureLDAP = false;
489 }
490
491 ldap_base::Create::SearchScope lDAPSearchScope;
492 if (configValues["scope"] == "sub")
493 {
494 lDAPSearchScope = ldap_base::Create::SearchScope::sub;
495 }
496 else if (configValues["scope"] == "one")
497 {
498 lDAPSearchScope = ldap_base::Create::SearchScope::one;
499 }
500 else
501 {
502 lDAPSearchScope = ldap_base::Create::SearchScope::base;
503 }
504
505 ldap_base::Create::Type lDAPType;
506 // If the file is having a line which starts with "map group"
507 if (configValues["map"] == "group")
508 {
509 lDAPType = ldap_base::Create::Type::ActiveDirectory;
510 }
511 else
512 {
513 lDAPType = ldap_base::Create::Type::OpenLdap;
514 }
515
516 createConfig(
517 secureLDAP, std::move(configValues["uri"]),
518 std::move(configValues["binddn"]), std::move(configValues["base"]),
519 std::move(configValues["bindpw"]), lDAPSearchScope, lDAPType);
520 }
521 catch (const InvalidArgument& e)
522 {
523 // Don't throw - we don't want to create a D-Bus
524 // object upon finding empty values in config, as
525 // this can be a default config.
526 }
527 catch (const InternalFailure& e)
528 {
529 throw;
530 }
531 catch (const std::exception& e)
532 {
533 log<level::ERR>(e.what());
534 elog<InternalFailure>();
535 }
536}
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500537} // namespace ldap
538} // namespace phosphor