blob: c84927dc7c34ce583f3feaadd2c40faf32648772 [file] [log] [blame]
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -05001#include "ldap_configuration.hpp"
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -05002#include <ldap.h>
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -05003#include <experimental/filesystem>
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -05004#include <fstream>
5#include <sstream>
6
7namespace phosphor
8{
9namespace ldap
10{
11constexpr auto nslcdService = "nslcd.service";
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050012constexpr auto nscdService = "nscd.service";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050013
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050014using namespace phosphor::logging;
15using namespace sdbusplus::xyz::openbmc_project::Common::Error;
16namespace fs = std::experimental::filesystem;
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050017using Argument = xyz::openbmc_project::Common::InvalidArgument;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050018
19using Line = std::string;
20using Key = std::string;
21using Val = std::string;
22using ConfigInfo = std::map<Key, Val>;
23
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050024Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
25 bool secureLDAP, std::string lDAPServerURI,
26 std::string lDAPBindDN, std::string lDAPBaseDN,
27 std::string lDAPBindDNpassword,
28 ldap_base::Config::SearchScope lDAPSearchScope,
29 ldap_base::Config::Type lDAPType, ConfigMgr& parent) :
30 ConfigIface(bus, path, true),
31 configFilePath(filePath), bus(bus), parent(parent)
32{
33 ConfigIface::secureLDAP(secureLDAP);
34 ConfigIface::lDAPServerURI(lDAPServerURI);
35 ConfigIface::lDAPBindDN(lDAPBindDN);
36 ConfigIface::lDAPBaseDN(lDAPBaseDN);
37 ConfigIface::lDAPBINDDNpassword(lDAPBindDNpassword);
38 ConfigIface::lDAPSearchScope(lDAPSearchScope);
39 ConfigIface::lDAPType(lDAPType);
40 writeConfig();
41 parent.restartService(nslcdService);
42 // Emit deferred signal.
43 this->emit_object_added();
44}
45
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -050046void Config::delete_()
47{
48 parent.deleteObject();
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050049 try
50 {
51 fs::copy_file(defaultNslcdFile, LDAP_CONFIG_FILE,
52 fs::copy_options::overwrite_existing);
53 fs::copy_file(nsSwitchFile, LDAPNsSwitchFile,
54 fs::copy_options::overwrite_existing);
55 fs::copy_file(linuxNsSwitchFile, nsSwitchFile,
56 fs::copy_options::overwrite_existing);
57 }
58 catch (const std::exception& e)
59 {
60 log<level::ERR>("Failed to rename Config Files while deleting Object",
61 entry("ERR=%s", e.what()));
62 elog<InternalFailure>();
63 }
64
65 parent.restartService(nscdService);
66 parent.stopService(nslcdService);
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -050067}
68
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050069void Config::writeConfig()
70{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050071 std::stringstream confData;
72 confData << "uid root\n";
73 confData << "gid root\n\n";
74 confData << "ldap_version 3\n\n";
75 confData << "timelimit 30\n";
76 confData << "bind_timelimit 30\n";
77 confData << "pagesize 1000\n";
78 confData << "referrals off\n\n";
79 confData << "uri " << lDAPServerURI() << "\n\n";
80 confData << "base " << lDAPBaseDN() << "\n\n";
81 confData << "binddn " << lDAPBindDN() << "\n";
Nagaraju Goruganti15675472018-10-05 07:03:05 -050082 if (!lDAPBINDDNpassword().empty())
83 {
84 confData << "bindpw " << lDAPBINDDNpassword() << "\n";
85 }
86 confData << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050087 switch (lDAPSearchScope())
88 {
89 case ldap_base::Config::SearchScope::sub:
90 confData << "scope sub\n\n";
91 break;
92 case ldap_base::Config::SearchScope::one:
93 confData << "scope one\n\n";
94 break;
95 case ldap_base::Config::SearchScope::base:
96 confData << "scope base\n\n";
97 break;
98 }
99 confData << "base passwd " << lDAPBaseDN() << "\n";
100 confData << "base shadow " << lDAPBaseDN() << "\n\n";
101 if (secureLDAP() == true)
102 {
103 confData << "ssl on\n";
104 confData << "tls_reqcert allow\n";
105 confData << "tls_cert /etc/nslcd/certs/cert.pem\n";
106 }
107 else
108 {
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500109 confData << "ssl off\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500110 }
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500111 confData << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500112 if (lDAPType() == ldap_base::Config::Type::ActiveDirectory)
113 {
114 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
115 "(!(objectClass=computer)))\n";
116 confData
117 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
118 "(objectclass=groupofuniquenames))\n";
119 confData << "map passwd uid sAMAccountName\n";
120 confData << "map passwd uidNumber "
121 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
122 confData << "map passwd gidNumber primaryGroupID\n";
123 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
124 confData << "map passwd gecos displayName\n";
125 confData << "map passwd loginShell \"/bin/bash\"\n";
126 confData << "map group gidNumber primaryGroupID\n";
127 confData << "map group gidNumber "
128 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
129 confData << "map group cn sAMAccountName\n";
130 }
131 else if (lDAPType() == ldap_base::Config::Type::OpenLdap)
132 {
133 confData << "filter passwd (objectclass=*)\n";
134 confData << "map passwd uid cn\n";
135 confData << "map passwd gecos displayName\n";
136 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500137 try
138 {
139 std::fstream stream(configFilePath.c_str(), std::fstream::out);
140 stream << confData.str();
141 stream.flush();
142 stream.close();
143 }
144 catch (const std::exception& e)
145 {
146 log<level::ERR>(e.what());
147 elog<InternalFailure>();
148 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500149 return;
150}
151
152bool Config::secureLDAP(bool value)
153{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500154 bool val = false;
155 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500156 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500157 if (value == secureLDAP())
158 {
159 return value;
160 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500161
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500162 val = ConfigIface::secureLDAP(value);
163 writeConfig();
164 parent.restartService(nslcdService);
165 }
166 catch (const InternalFailure& e)
167 {
168 throw;
169 }
170 catch (const std::exception& e)
171 {
172 log<level::ERR>(e.what());
173 elog<InternalFailure>();
174 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500175
176 return val;
177}
178
179std::string Config::lDAPServerURI(std::string value)
180{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500181 std::string val;
182 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500183 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500184 if (value == lDAPServerURI())
185 {
186 return value;
187 }
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500188 if (!(ldap_is_ldap_url(value.c_str()) ||
189 ldap_is_ldaps_url(value.c_str())))
190 {
191 log<level::ERR>("Not a valid LDAP Server URI"),
192 entry("LDAPSERVERURI=%s", value.c_str());
193 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
194 Argument::ARGUMENT_VALUE(value.c_str()));
195 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500196 val = ConfigIface::lDAPServerURI(value);
197 writeConfig();
198 parent.restartService(nslcdService);
199 }
200 catch (const InternalFailure& e)
201 {
202 throw;
203 }
204 catch (const std::exception& e)
205 {
206 log<level::ERR>(e.what());
207 elog<InternalFailure>();
208 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500209
210 return val;
211}
212
213std::string Config::lDAPBindDN(std::string value)
214{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500215 std::string val;
216 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500217 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500218 if (value == lDAPBindDN())
219 {
220 return value;
221 }
222
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500223 if (value.empty())
224 {
225 log<level::ERR>("Not a valid LDAP BINDDN"),
226 entry("LDAPBINDDN=%s", value.c_str());
227 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"),
228 Argument::ARGUMENT_VALUE(value.c_str()));
229 }
230
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500231 val = ConfigIface::lDAPBindDN(value);
232 writeConfig();
233 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500234 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500235 catch (const InternalFailure& e)
236 {
237 throw;
238 }
239 catch (const std::exception& e)
240 {
241 log<level::ERR>(e.what());
242 elog<InternalFailure>();
243 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500244 return val;
245}
246
247std::string Config::lDAPBaseDN(std::string value)
248{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500249 std::string val;
250 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500251 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500252 if (value == lDAPBaseDN())
253 {
254 return value;
255 }
256
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500257 if (value.empty())
258 {
259 log<level::ERR>("Not a valid LDAP BASEDN"),
260 entry("BASEDN=%s", value.c_str());
261 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"),
262 Argument::ARGUMENT_VALUE(value.c_str()));
263 }
264
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500265 val = ConfigIface::lDAPBaseDN(value);
266 writeConfig();
267 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500268 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500269 catch (const InternalFailure& e)
270 {
271 throw;
272 }
273 catch (const std::exception& e)
274 {
275 log<level::ERR>(e.what());
276 elog<InternalFailure>();
277 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500278 return val;
279}
280
281std::string Config::lDAPBINDDNpassword(std::string value)
282{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500283 std::string val;
284 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500285 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500286 if (value == lDAPBINDDNpassword())
287 {
288 return value;
289 }
290
291 val = ConfigIface::lDAPBINDDNpassword(value);
292 writeConfig();
293 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500294 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500295 catch (const InternalFailure& e)
296 {
297 throw;
298 }
299 catch (const std::exception& e)
300 {
301 log<level::ERR>(e.what());
302 elog<InternalFailure>();
303 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500304 return val;
305}
306
307ldap_base::Config::SearchScope
308 Config::lDAPSearchScope(ldap_base::Config::SearchScope value)
309{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500310 ldap_base::Config::SearchScope val;
311 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500312 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500313 if (value == lDAPSearchScope())
314 {
315 return value;
316 }
317
318 val = ConfigIface::lDAPSearchScope(value);
319 writeConfig();
320 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500321 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500322 catch (const InternalFailure& e)
323 {
324 throw;
325 }
326 catch (const std::exception& e)
327 {
328 log<level::ERR>(e.what());
329 elog<InternalFailure>();
330 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500331 return val;
332}
333
334ldap_base::Config::Type Config::lDAPType(ldap_base::Config::Type value)
335{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500336 ldap_base::Config::Type val;
337 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500338 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500339 if (value == lDAPType())
340 {
341 return value;
342 }
343
344 val = ConfigIface::lDAPType(value);
345 writeConfig();
346 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500347 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500348 catch (const InternalFailure& e)
349 {
350 throw;
351 }
352 catch (const std::exception& e)
353 {
354 log<level::ERR>(e.what());
355 elog<InternalFailure>();
356 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500357 return val;
358}
359
360void ConfigMgr::restartService(const std::string& service)
361{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500362 try
363 {
364 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
365 SYSTEMD_INTERFACE, "RestartUnit");
366 method.append(service.c_str(), "replace");
367 bus.call_noreply(method);
368 }
369 catch (const sdbusplus::exception::SdBusError& ex)
370 {
371 log<level::ERR>("Failed to restart nslcd service",
372 entry("ERR=%s", ex.what()));
373 elog<InternalFailure>();
374 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500375}
376
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500377void ConfigMgr::stopService(const std::string& service)
378{
379 try
380 {
381 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
382 SYSTEMD_INTERFACE, "StopUnit");
383 method.append(service.c_str(), "replace");
384 bus.call_noreply(method);
385 }
386 catch (const sdbusplus::exception::SdBusError& ex)
387 {
388 log<level::ERR>("Failed to stop nslcd service",
389 entry("ERR=%s", ex.what()));
390 elog<InternalFailure>();
391 }
392}
393
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -0500394void ConfigMgr::deleteObject()
395{
396 configPtr.reset(nullptr);
397}
398
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500399std::string
400 ConfigMgr::createConfig(bool secureLDAP, std::string lDAPServerURI,
401 std::string lDAPBindDN, std::string lDAPBaseDN,
402 std::string lDAPBINDDNpassword,
403 ldap_base::Create::SearchScope lDAPSearchScope,
404 ldap_base::Create::Type lDAPType)
405{
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500406 if (!(ldap_is_ldap_url(lDAPServerURI.c_str()) ||
407 ldap_is_ldaps_url(lDAPServerURI.c_str())))
408 {
409 log<level::ERR>("Not a valid LDAP Server URI"),
410 entry("LDAPSERVERURI=%s", lDAPServerURI.c_str());
411 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
412 Argument::ARGUMENT_VALUE(lDAPServerURI.c_str()));
413 }
414
415 if (lDAPBindDN.empty())
416 {
417 log<level::ERR>("Not a valid LDAP BINDDN"),
418 entry("LDAPBINDDN=%s", lDAPBindDN.c_str());
419 elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBindDN"),
420 Argument::ARGUMENT_VALUE(lDAPBindDN.c_str()));
421 }
422
423 if (lDAPBaseDN.empty())
424 {
425 log<level::ERR>("Not a valid LDAP BASEDN"),
426 entry("LDAPBASEDN=%s", lDAPBaseDN.c_str());
427 elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBaseDN"),
428 Argument::ARGUMENT_VALUE(lDAPBaseDN.c_str()));
429 }
430
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500431 // With current implementation we support only one LDAP server.
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -0500432 deleteObject();
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500433 try
434 {
435 fs::copy_file(nsSwitchFile, linuxNsSwitchFile,
436 fs::copy_options::overwrite_existing);
437 fs::copy_file(LDAPNsSwitchFile, nsSwitchFile,
438 fs::copy_options::overwrite_existing);
439 }
440 catch (const std::exception& e)
441 {
442 log<level::ERR>("Failed to rename Config Files while creating Object",
443 entry("ERR=%s", e.what()));
444 elog<InternalFailure>();
445 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500446
447 auto objPath = std::string(LDAP_CONFIG_DBUS_OBJ_PATH);
448 configPtr = std::make_unique<Config>(
449 bus, objPath.c_str(), LDAP_CONFIG_FILE, secureLDAP, lDAPServerURI,
450 lDAPBindDN, lDAPBaseDN, lDAPBINDDNpassword,
451 static_cast<ldap_base::Config::SearchScope>(lDAPSearchScope),
452 static_cast<ldap_base::Config::Type>(lDAPType), *this);
453
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500454 restartService(nslcdService);
455 restartService(nscdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500456 return objPath;
457}
458
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500459void ConfigMgr::restore(const char* filePath)
460{
461 if (!fs::exists(filePath))
462 {
463 log<level::ERR>("Config file doesn't exists",
464 entry("LDAP_CONFIG_FILE=%s", LDAP_CONFIG_FILE));
465 return;
466 }
467
468 ConfigInfo configValues;
469
470 try
471 {
472 std::fstream stream(filePath, std::fstream::in);
473 Line line;
474 // read characters from stream and places them into line
475 while (std::getline(stream, line))
476 {
477 // remove leading and trailing extra spaces
478 auto firstScan = line.find_first_not_of(' ');
479 auto first =
480 (firstScan == std::string::npos ? line.length() : firstScan);
481 auto last = line.find_last_not_of(' ');
482 line = line.substr(first, last - first + 1);
483 // reduce multiple spaces between two words to a single space
484 auto pred = [](char a, char b) {
485 return (a == b && a == ' ') ? true : false;
486 };
487
488 auto lastPos = std::unique(line.begin(), line.end(), pred);
489
490 line.erase(lastPos, line.end());
491
492 // Ignore if line is empty or starts with '#'
493 if (line.empty() || line.at(0) == '#')
494 {
495 continue;
496 }
497
498 Key key;
499 std::istringstream isLine(line);
500 // extract characters from isLine and stores them into
501 // key until the delimitation character ' ' is found.
502 // If the delimiter is found, it is extracted and discarded
503 // the next input operation will begin after it.
504 if (std::getline(isLine, key, ' '))
505 {
506 Val value;
507 // extract characters after delimitation character ' '
508 if (std::getline(isLine, value, ' '))
509 {
510 // skip line if it starts with "base shadow" or
511 // "base passwd" because we would have 3 entries
512 // ("base lDAPBaseDN" , "base passwd lDAPBaseDN" and
513 // "base shadow lDAPBaseDN") for the property "lDAPBaseDN",
514 // one is enough to restore it.
515
516 if ((key == "base") &&
517 (value == "passwd" || value == "shadow"))
518 {
519 continue;
520 }
521 // skip the line if it starts with "map passwd".
522 // if config type is AD "map group" entry would be add to
523 // the map configValues. For OpenLdap config file no map
524 // entry would be there.
525 if ((key == "map") && (value == "passwd"))
526 {
527 continue;
528 }
529 configValues[key] = value;
530 }
531 }
532 }
533
534 // extract properties from configValues map
535 bool secureLDAP;
536 if (configValues["ssl"] == "on")
537 {
538 secureLDAP = true;
539 }
540 else
541 {
542 secureLDAP = false;
543 }
544
545 ldap_base::Create::SearchScope lDAPSearchScope;
546 if (configValues["scope"] == "sub")
547 {
548 lDAPSearchScope = ldap_base::Create::SearchScope::sub;
549 }
550 else if (configValues["scope"] == "one")
551 {
552 lDAPSearchScope = ldap_base::Create::SearchScope::one;
553 }
554 else
555 {
556 lDAPSearchScope = ldap_base::Create::SearchScope::base;
557 }
558
559 ldap_base::Create::Type lDAPType;
560 // If the file is having a line which starts with "map group"
561 if (configValues["map"] == "group")
562 {
563 lDAPType = ldap_base::Create::Type::ActiveDirectory;
564 }
565 else
566 {
567 lDAPType = ldap_base::Create::Type::OpenLdap;
568 }
569
570 createConfig(
571 secureLDAP, std::move(configValues["uri"]),
572 std::move(configValues["binddn"]), std::move(configValues["base"]),
573 std::move(configValues["bindpw"]), lDAPSearchScope, lDAPType);
574 }
575 catch (const InvalidArgument& e)
576 {
577 // Don't throw - we don't want to create a D-Bus
578 // object upon finding empty values in config, as
579 // this can be a default config.
580 }
581 catch (const InternalFailure& e)
582 {
583 throw;
584 }
585 catch (const std::exception& e)
586 {
587 log<level::ERR>(e.what());
588 elog<InternalFailure>();
589 }
590}
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500591} // namespace ldap
592} // namespace phosphor