blob: 66805419b8d67b86cbd23ac039c3fdd0b40ab43b [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
43void Config::writeConfig()
44{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050045 std::stringstream confData;
46 confData << "uid root\n";
47 confData << "gid root\n\n";
48 confData << "ldap_version 3\n\n";
49 confData << "timelimit 30\n";
50 confData << "bind_timelimit 30\n";
51 confData << "pagesize 1000\n";
52 confData << "referrals off\n\n";
53 confData << "uri " << lDAPServerURI() << "\n\n";
54 confData << "base " << lDAPBaseDN() << "\n\n";
55 confData << "binddn " << lDAPBindDN() << "\n";
56 confData << "bindpw " << lDAPBINDDNpassword() << "\n\n";
57 switch (lDAPSearchScope())
58 {
59 case ldap_base::Config::SearchScope::sub:
60 confData << "scope sub\n\n";
61 break;
62 case ldap_base::Config::SearchScope::one:
63 confData << "scope one\n\n";
64 break;
65 case ldap_base::Config::SearchScope::base:
66 confData << "scope base\n\n";
67 break;
68 }
69 confData << "base passwd " << lDAPBaseDN() << "\n";
70 confData << "base shadow " << lDAPBaseDN() << "\n\n";
71 if (secureLDAP() == true)
72 {
73 confData << "ssl on\n";
74 confData << "tls_reqcert allow\n";
75 confData << "tls_cert /etc/nslcd/certs/cert.pem\n";
76 }
77 else
78 {
79 confData << "ssl off\n\n";
80 }
81 if (lDAPType() == ldap_base::Config::Type::ActiveDirectory)
82 {
83 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
84 "(!(objectClass=computer)))\n";
85 confData
86 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
87 "(objectclass=groupofuniquenames))\n";
88 confData << "map passwd uid sAMAccountName\n";
89 confData << "map passwd uidNumber "
90 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
91 confData << "map passwd gidNumber primaryGroupID\n";
92 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
93 confData << "map passwd gecos displayName\n";
94 confData << "map passwd loginShell \"/bin/bash\"\n";
95 confData << "map group gidNumber primaryGroupID\n";
96 confData << "map group gidNumber "
97 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
98 confData << "map group cn sAMAccountName\n";
99 }
100 else if (lDAPType() == ldap_base::Config::Type::OpenLdap)
101 {
102 confData << "filter passwd (objectclass=*)\n";
103 confData << "map passwd uid cn\n";
104 confData << "map passwd gecos displayName\n";
105 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500106 try
107 {
108 std::fstream stream(configFilePath.c_str(), std::fstream::out);
109 stream << confData.str();
110 stream.flush();
111 stream.close();
112 }
113 catch (const std::exception& e)
114 {
115 log<level::ERR>(e.what());
116 elog<InternalFailure>();
117 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500118 return;
119}
120
121bool Config::secureLDAP(bool value)
122{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500123 bool val = false;
124 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500125 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500126 if (value == secureLDAP())
127 {
128 return value;
129 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500130
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500131 val = ConfigIface::secureLDAP(value);
132 writeConfig();
133 parent.restartService(nslcdService);
134 }
135 catch (const InternalFailure& e)
136 {
137 throw;
138 }
139 catch (const std::exception& e)
140 {
141 log<level::ERR>(e.what());
142 elog<InternalFailure>();
143 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500144
145 return val;
146}
147
148std::string Config::lDAPServerURI(std::string value)
149{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500150 std::string val;
151 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500152 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500153 if (value == lDAPServerURI())
154 {
155 return value;
156 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500157
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500158 val = ConfigIface::lDAPServerURI(value);
159 writeConfig();
160 parent.restartService(nslcdService);
161 }
162 catch (const InternalFailure& e)
163 {
164 throw;
165 }
166 catch (const std::exception& e)
167 {
168 log<level::ERR>(e.what());
169 elog<InternalFailure>();
170 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500171
172 return val;
173}
174
175std::string Config::lDAPBindDN(std::string value)
176{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500177 std::string val;
178 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500179 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500180 if (value == lDAPBindDN())
181 {
182 return value;
183 }
184
185 val = ConfigIface::lDAPBindDN(value);
186 writeConfig();
187 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500188 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500189 catch (const InternalFailure& e)
190 {
191 throw;
192 }
193 catch (const std::exception& e)
194 {
195 log<level::ERR>(e.what());
196 elog<InternalFailure>();
197 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500198 return val;
199}
200
201std::string Config::lDAPBaseDN(std::string value)
202{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500203 std::string val;
204 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500205 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500206 if (value == lDAPBaseDN())
207 {
208 return value;
209 }
210
211 val = ConfigIface::lDAPBaseDN(value);
212 writeConfig();
213 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500214 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500215 catch (const InternalFailure& e)
216 {
217 throw;
218 }
219 catch (const std::exception& e)
220 {
221 log<level::ERR>(e.what());
222 elog<InternalFailure>();
223 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500224 return val;
225}
226
227std::string Config::lDAPBINDDNpassword(std::string value)
228{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500229 std::string val;
230 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500231 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500232 if (value == lDAPBINDDNpassword())
233 {
234 return value;
235 }
236
237 val = ConfigIface::lDAPBINDDNpassword(value);
238 writeConfig();
239 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500240 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500241 catch (const InternalFailure& e)
242 {
243 throw;
244 }
245 catch (const std::exception& e)
246 {
247 log<level::ERR>(e.what());
248 elog<InternalFailure>();
249 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500250 return val;
251}
252
253ldap_base::Config::SearchScope
254 Config::lDAPSearchScope(ldap_base::Config::SearchScope value)
255{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500256 ldap_base::Config::SearchScope val;
257 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500258 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500259 if (value == lDAPSearchScope())
260 {
261 return value;
262 }
263
264 val = ConfigIface::lDAPSearchScope(value);
265 writeConfig();
266 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500267 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500268 catch (const InternalFailure& e)
269 {
270 throw;
271 }
272 catch (const std::exception& e)
273 {
274 log<level::ERR>(e.what());
275 elog<InternalFailure>();
276 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500277 return val;
278}
279
280ldap_base::Config::Type Config::lDAPType(ldap_base::Config::Type value)
281{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500282 ldap_base::Config::Type val;
283 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500284 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500285 if (value == lDAPType())
286 {
287 return value;
288 }
289
290 val = ConfigIface::lDAPType(value);
291 writeConfig();
292 parent.restartService(nslcdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500293 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500294 catch (const InternalFailure& e)
295 {
296 throw;
297 }
298 catch (const std::exception& e)
299 {
300 log<level::ERR>(e.what());
301 elog<InternalFailure>();
302 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500303 return val;
304}
305
306void ConfigMgr::restartService(const std::string& service)
307{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500308 try
309 {
310 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
311 SYSTEMD_INTERFACE, "RestartUnit");
312 method.append(service.c_str(), "replace");
313 bus.call_noreply(method);
314 }
315 catch (const sdbusplus::exception::SdBusError& ex)
316 {
317 log<level::ERR>("Failed to restart nslcd service",
318 entry("ERR=%s", ex.what()));
319 elog<InternalFailure>();
320 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500321}
322
323std::string
324 ConfigMgr::createConfig(bool secureLDAP, std::string lDAPServerURI,
325 std::string lDAPBindDN, std::string lDAPBaseDN,
326 std::string lDAPBINDDNpassword,
327 ldap_base::Create::SearchScope lDAPSearchScope,
328 ldap_base::Create::Type lDAPType)
329{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500330 // TODO Validate parameters passed-in.
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500331 // With current implementation we support only one LDAP server.
332 configPtr.reset(nullptr);
333
334 auto objPath = std::string(LDAP_CONFIG_DBUS_OBJ_PATH);
335 configPtr = std::make_unique<Config>(
336 bus, objPath.c_str(), LDAP_CONFIG_FILE, secureLDAP, lDAPServerURI,
337 lDAPBindDN, lDAPBaseDN, lDAPBINDDNpassword,
338 static_cast<ldap_base::Config::SearchScope>(lDAPSearchScope),
339 static_cast<ldap_base::Config::Type>(lDAPType), *this);
340
341 return objPath;
342}
343
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500344void ConfigMgr::restore(const char* filePath)
345{
346 if (!fs::exists(filePath))
347 {
348 log<level::ERR>("Config file doesn't exists",
349 entry("LDAP_CONFIG_FILE=%s", LDAP_CONFIG_FILE));
350 return;
351 }
352
353 ConfigInfo configValues;
354
355 try
356 {
357 std::fstream stream(filePath, std::fstream::in);
358 Line line;
359 // read characters from stream and places them into line
360 while (std::getline(stream, line))
361 {
362 // remove leading and trailing extra spaces
363 auto firstScan = line.find_first_not_of(' ');
364 auto first =
365 (firstScan == std::string::npos ? line.length() : firstScan);
366 auto last = line.find_last_not_of(' ');
367 line = line.substr(first, last - first + 1);
368 // reduce multiple spaces between two words to a single space
369 auto pred = [](char a, char b) {
370 return (a == b && a == ' ') ? true : false;
371 };
372
373 auto lastPos = std::unique(line.begin(), line.end(), pred);
374
375 line.erase(lastPos, line.end());
376
377 // Ignore if line is empty or starts with '#'
378 if (line.empty() || line.at(0) == '#')
379 {
380 continue;
381 }
382
383 Key key;
384 std::istringstream isLine(line);
385 // extract characters from isLine and stores them into
386 // key until the delimitation character ' ' is found.
387 // If the delimiter is found, it is extracted and discarded
388 // the next input operation will begin after it.
389 if (std::getline(isLine, key, ' '))
390 {
391 Val value;
392 // extract characters after delimitation character ' '
393 if (std::getline(isLine, value, ' '))
394 {
395 // skip line if it starts with "base shadow" or
396 // "base passwd" because we would have 3 entries
397 // ("base lDAPBaseDN" , "base passwd lDAPBaseDN" and
398 // "base shadow lDAPBaseDN") for the property "lDAPBaseDN",
399 // one is enough to restore it.
400
401 if ((key == "base") &&
402 (value == "passwd" || value == "shadow"))
403 {
404 continue;
405 }
406 // skip the line if it starts with "map passwd".
407 // if config type is AD "map group" entry would be add to
408 // the map configValues. For OpenLdap config file no map
409 // entry would be there.
410 if ((key == "map") && (value == "passwd"))
411 {
412 continue;
413 }
414 configValues[key] = value;
415 }
416 }
417 }
418
419 // extract properties from configValues map
420 bool secureLDAP;
421 if (configValues["ssl"] == "on")
422 {
423 secureLDAP = true;
424 }
425 else
426 {
427 secureLDAP = false;
428 }
429
430 ldap_base::Create::SearchScope lDAPSearchScope;
431 if (configValues["scope"] == "sub")
432 {
433 lDAPSearchScope = ldap_base::Create::SearchScope::sub;
434 }
435 else if (configValues["scope"] == "one")
436 {
437 lDAPSearchScope = ldap_base::Create::SearchScope::one;
438 }
439 else
440 {
441 lDAPSearchScope = ldap_base::Create::SearchScope::base;
442 }
443
444 ldap_base::Create::Type lDAPType;
445 // If the file is having a line which starts with "map group"
446 if (configValues["map"] == "group")
447 {
448 lDAPType = ldap_base::Create::Type::ActiveDirectory;
449 }
450 else
451 {
452 lDAPType = ldap_base::Create::Type::OpenLdap;
453 }
454
455 createConfig(
456 secureLDAP, std::move(configValues["uri"]),
457 std::move(configValues["binddn"]), std::move(configValues["base"]),
458 std::move(configValues["bindpw"]), lDAPSearchScope, lDAPType);
459 }
460 catch (const InvalidArgument& e)
461 {
462 // Don't throw - we don't want to create a D-Bus
463 // object upon finding empty values in config, as
464 // this can be a default config.
465 }
466 catch (const InternalFailure& e)
467 {
468 throw;
469 }
470 catch (const std::exception& e)
471 {
472 log<level::ERR>(e.what());
473 elog<InternalFailure>();
474 }
475}
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500476} // namespace ldap
477} // namespace phosphor