blob: 3a4ed2e88f37f99e0986c10fc14593bedd61c595 [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";
11
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050012using namespace phosphor::logging;
13using namespace sdbusplus::xyz::openbmc_project::Common::Error;
14namespace fs = std::experimental::filesystem;
15
16using Line = std::string;
17using Key = std::string;
18using Val = std::string;
19using ConfigInfo = std::map<Key, Val>;
20
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050021Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
22 bool secureLDAP, std::string lDAPServerURI,
23 std::string lDAPBindDN, std::string lDAPBaseDN,
24 std::string lDAPBindDNpassword,
25 ldap_base::Config::SearchScope lDAPSearchScope,
26 ldap_base::Config::Type lDAPType, ConfigMgr& parent) :
27 ConfigIface(bus, path, true),
28 configFilePath(filePath), bus(bus), parent(parent)
29{
30 ConfigIface::secureLDAP(secureLDAP);
31 ConfigIface::lDAPServerURI(lDAPServerURI);
32 ConfigIface::lDAPBindDN(lDAPBindDN);
33 ConfigIface::lDAPBaseDN(lDAPBaseDN);
34 ConfigIface::lDAPBINDDNpassword(lDAPBindDNpassword);
35 ConfigIface::lDAPSearchScope(lDAPSearchScope);
36 ConfigIface::lDAPType(lDAPType);
37 writeConfig();
38 parent.restartService(nslcdService);
39 // Emit deferred signal.
40 this->emit_object_added();
41}
42
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -050043void Config::delete_()
44{
45 parent.deleteObject();
46}
47
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050048void Config::writeConfig()
49{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050050 std::stringstream confData;
51 confData << "uid root\n";
52 confData << "gid root\n\n";
53 confData << "ldap_version 3\n\n";
54 confData << "timelimit 30\n";
55 confData << "bind_timelimit 30\n";
56 confData << "pagesize 1000\n";
57 confData << "referrals off\n\n";
58 confData << "uri " << lDAPServerURI() << "\n\n";
59 confData << "base " << lDAPBaseDN() << "\n\n";
60 confData << "binddn " << lDAPBindDN() << "\n";
61 confData << "bindpw " << lDAPBINDDNpassword() << "\n\n";
62 switch (lDAPSearchScope())
63 {
64 case ldap_base::Config::SearchScope::sub:
65 confData << "scope sub\n\n";
66 break;
67 case ldap_base::Config::SearchScope::one:
68 confData << "scope one\n\n";
69 break;
70 case ldap_base::Config::SearchScope::base:
71 confData << "scope base\n\n";
72 break;
73 }
74 confData << "base passwd " << lDAPBaseDN() << "\n";
75 confData << "base shadow " << lDAPBaseDN() << "\n\n";
76 if (secureLDAP() == true)
77 {
78 confData << "ssl on\n";
79 confData << "tls_reqcert allow\n";
80 confData << "tls_cert /etc/nslcd/certs/cert.pem\n";
81 }
82 else
83 {
84 confData << "ssl off\n\n";
85 }
86 if (lDAPType() == ldap_base::Config::Type::ActiveDirectory)
87 {
88 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
89 "(!(objectClass=computer)))\n";
90 confData
91 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
92 "(objectclass=groupofuniquenames))\n";
93 confData << "map passwd uid sAMAccountName\n";
94 confData << "map passwd uidNumber "
95 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
96 confData << "map passwd gidNumber primaryGroupID\n";
97 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
98 confData << "map passwd gecos displayName\n";
99 confData << "map passwd loginShell \"/bin/bash\"\n";
100 confData << "map group gidNumber primaryGroupID\n";
101 confData << "map group gidNumber "
102 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
103 confData << "map group cn sAMAccountName\n";
104 }
105 else if (lDAPType() == ldap_base::Config::Type::OpenLdap)
106 {
107 confData << "filter passwd (objectclass=*)\n";
108 confData << "map passwd uid cn\n";
109 confData << "map passwd gecos displayName\n";
110 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500111 try
112 {
113 std::fstream stream(configFilePath.c_str(), std::fstream::out);
114 stream << confData.str();
115 stream.flush();
116 stream.close();
117 }
118 catch (const std::exception& e)
119 {
120 log<level::ERR>(e.what());
121 elog<InternalFailure>();
122 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500123 return;
124}
125
126bool Config::secureLDAP(bool value)
127{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500128 bool val = false;
129 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500130 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500131 if (value == secureLDAP())
132 {
133 return value;
134 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500135
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500136 val = ConfigIface::secureLDAP(value);
137 writeConfig();
138 parent.restartService(nslcdService);
139 }
140 catch (const InternalFailure& e)
141 {
142 throw;
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
150 return val;
151}
152
153std::string Config::lDAPServerURI(std::string value)
154{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500155 std::string val;
156 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500157 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500158 if (value == lDAPServerURI())
159 {
160 return value;
161 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500162
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500163 val = ConfigIface::lDAPServerURI(value);
164 writeConfig();
165 parent.restartService(nslcdService);
166 }
167 catch (const InternalFailure& e)
168 {
169 throw;
170 }
171 catch (const std::exception& e)
172 {
173 log<level::ERR>(e.what());
174 elog<InternalFailure>();
175 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500176
177 return val;
178}
179
180std::string Config::lDAPBindDN(std::string value)
181{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500182 std::string val;
183 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500184 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500185 if (value == lDAPBindDN())
186 {
187 return value;
188 }
189
190 val = ConfigIface::lDAPBindDN(value);
191 writeConfig();
192 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500193 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500194 catch (const InternalFailure& e)
195 {
196 throw;
197 }
198 catch (const std::exception& e)
199 {
200 log<level::ERR>(e.what());
201 elog<InternalFailure>();
202 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500203 return val;
204}
205
206std::string Config::lDAPBaseDN(std::string value)
207{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500208 std::string val;
209 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500210 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500211 if (value == lDAPBaseDN())
212 {
213 return value;
214 }
215
216 val = ConfigIface::lDAPBaseDN(value);
217 writeConfig();
218 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500219 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500220 catch (const InternalFailure& e)
221 {
222 throw;
223 }
224 catch (const std::exception& e)
225 {
226 log<level::ERR>(e.what());
227 elog<InternalFailure>();
228 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500229 return val;
230}
231
232std::string Config::lDAPBINDDNpassword(std::string value)
233{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500234 std::string val;
235 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500236 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500237 if (value == lDAPBINDDNpassword())
238 {
239 return value;
240 }
241
242 val = ConfigIface::lDAPBINDDNpassword(value);
243 writeConfig();
244 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500245 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500246 catch (const InternalFailure& e)
247 {
248 throw;
249 }
250 catch (const std::exception& e)
251 {
252 log<level::ERR>(e.what());
253 elog<InternalFailure>();
254 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500255 return val;
256}
257
258ldap_base::Config::SearchScope
259 Config::lDAPSearchScope(ldap_base::Config::SearchScope value)
260{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500261 ldap_base::Config::SearchScope val;
262 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500263 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500264 if (value == lDAPSearchScope())
265 {
266 return value;
267 }
268
269 val = ConfigIface::lDAPSearchScope(value);
270 writeConfig();
271 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500272 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500273 catch (const InternalFailure& e)
274 {
275 throw;
276 }
277 catch (const std::exception& e)
278 {
279 log<level::ERR>(e.what());
280 elog<InternalFailure>();
281 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500282 return val;
283}
284
285ldap_base::Config::Type Config::lDAPType(ldap_base::Config::Type value)
286{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500287 ldap_base::Config::Type val;
288 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500289 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500290 if (value == lDAPType())
291 {
292 return value;
293 }
294
295 val = ConfigIface::lDAPType(value);
296 writeConfig();
297 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500298 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500299 catch (const InternalFailure& e)
300 {
301 throw;
302 }
303 catch (const std::exception& e)
304 {
305 log<level::ERR>(e.what());
306 elog<InternalFailure>();
307 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500308 return val;
309}
310
311void ConfigMgr::restartService(const std::string& service)
312{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500313 try
314 {
315 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
316 SYSTEMD_INTERFACE, "RestartUnit");
317 method.append(service.c_str(), "replace");
318 bus.call_noreply(method);
319 }
320 catch (const sdbusplus::exception::SdBusError& ex)
321 {
322 log<level::ERR>("Failed to restart nslcd service",
323 entry("ERR=%s", ex.what()));
324 elog<InternalFailure>();
325 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500326}
327
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -0500328void ConfigMgr::deleteObject()
329{
330 configPtr.reset(nullptr);
331}
332
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500333std::string
334 ConfigMgr::createConfig(bool secureLDAP, std::string lDAPServerURI,
335 std::string lDAPBindDN, std::string lDAPBaseDN,
336 std::string lDAPBINDDNpassword,
337 ldap_base::Create::SearchScope lDAPSearchScope,
338 ldap_base::Create::Type lDAPType)
339{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500340 // TODO Validate parameters passed-in.
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500341 // With current implementation we support only one LDAP server.
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -0500342 deleteObject();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500343
344 auto objPath = std::string(LDAP_CONFIG_DBUS_OBJ_PATH);
345 configPtr = std::make_unique<Config>(
346 bus, objPath.c_str(), LDAP_CONFIG_FILE, secureLDAP, lDAPServerURI,
347 lDAPBindDN, lDAPBaseDN, lDAPBINDDNpassword,
348 static_cast<ldap_base::Config::SearchScope>(lDAPSearchScope),
349 static_cast<ldap_base::Config::Type>(lDAPType), *this);
350
351 return objPath;
352}
353
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500354void ConfigMgr::restore(const char* filePath)
355{
356 if (!fs::exists(filePath))
357 {
358 log<level::ERR>("Config file doesn't exists",
359 entry("LDAP_CONFIG_FILE=%s", LDAP_CONFIG_FILE));
360 return;
361 }
362
363 ConfigInfo configValues;
364
365 try
366 {
367 std::fstream stream(filePath, std::fstream::in);
368 Line line;
369 // read characters from stream and places them into line
370 while (std::getline(stream, line))
371 {
372 // remove leading and trailing extra spaces
373 auto firstScan = line.find_first_not_of(' ');
374 auto first =
375 (firstScan == std::string::npos ? line.length() : firstScan);
376 auto last = line.find_last_not_of(' ');
377 line = line.substr(first, last - first + 1);
378 // reduce multiple spaces between two words to a single space
379 auto pred = [](char a, char b) {
380 return (a == b && a == ' ') ? true : false;
381 };
382
383 auto lastPos = std::unique(line.begin(), line.end(), pred);
384
385 line.erase(lastPos, line.end());
386
387 // Ignore if line is empty or starts with '#'
388 if (line.empty() || line.at(0) == '#')
389 {
390 continue;
391 }
392
393 Key key;
394 std::istringstream isLine(line);
395 // extract characters from isLine and stores them into
396 // key until the delimitation character ' ' is found.
397 // If the delimiter is found, it is extracted and discarded
398 // the next input operation will begin after it.
399 if (std::getline(isLine, key, ' '))
400 {
401 Val value;
402 // extract characters after delimitation character ' '
403 if (std::getline(isLine, value, ' '))
404 {
405 // skip line if it starts with "base shadow" or
406 // "base passwd" because we would have 3 entries
407 // ("base lDAPBaseDN" , "base passwd lDAPBaseDN" and
408 // "base shadow lDAPBaseDN") for the property "lDAPBaseDN",
409 // one is enough to restore it.
410
411 if ((key == "base") &&
412 (value == "passwd" || value == "shadow"))
413 {
414 continue;
415 }
416 // skip the line if it starts with "map passwd".
417 // if config type is AD "map group" entry would be add to
418 // the map configValues. For OpenLdap config file no map
419 // entry would be there.
420 if ((key == "map") && (value == "passwd"))
421 {
422 continue;
423 }
424 configValues[key] = value;
425 }
426 }
427 }
428
429 // extract properties from configValues map
430 bool secureLDAP;
431 if (configValues["ssl"] == "on")
432 {
433 secureLDAP = true;
434 }
435 else
436 {
437 secureLDAP = false;
438 }
439
440 ldap_base::Create::SearchScope lDAPSearchScope;
441 if (configValues["scope"] == "sub")
442 {
443 lDAPSearchScope = ldap_base::Create::SearchScope::sub;
444 }
445 else if (configValues["scope"] == "one")
446 {
447 lDAPSearchScope = ldap_base::Create::SearchScope::one;
448 }
449 else
450 {
451 lDAPSearchScope = ldap_base::Create::SearchScope::base;
452 }
453
454 ldap_base::Create::Type lDAPType;
455 // If the file is having a line which starts with "map group"
456 if (configValues["map"] == "group")
457 {
458 lDAPType = ldap_base::Create::Type::ActiveDirectory;
459 }
460 else
461 {
462 lDAPType = ldap_base::Create::Type::OpenLdap;
463 }
464
465 createConfig(
466 secureLDAP, std::move(configValues["uri"]),
467 std::move(configValues["binddn"]), std::move(configValues["base"]),
468 std::move(configValues["bindpw"]), lDAPSearchScope, lDAPType);
469 }
470 catch (const InvalidArgument& e)
471 {
472 // Don't throw - we don't want to create a D-Bus
473 // object upon finding empty values in config, as
474 // this can be a default config.
475 }
476 catch (const InternalFailure& e)
477 {
478 throw;
479 }
480 catch (const std::exception& e)
481 {
482 log<level::ERR>(e.what());
483 elog<InternalFailure>();
484 }
485}
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500486} // namespace ldap
487} // namespace phosphor