blob: 77726eeeaf39160b835a57613ae19342b8d21882 [file] [log] [blame]
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -05001#include "ldap_configuration.hpp"
Ratan Gupta95a29312019-02-18 20:34:10 +05302#include "ldap_serialize.hpp"
Nagaraju Goruganti59287f02018-10-12 07:00:20 -05003#include "utils.hpp"
Ratan Gupta95a29312019-02-18 20:34:10 +05304#include <filesystem>
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -05005#include <fstream>
6#include <sstream>
7
8namespace phosphor
9{
10namespace ldap
11{
12constexpr auto nslcdService = "nslcd.service";
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050013constexpr auto nscdService = "nscd.service";
Nagaraju Goruganti59287f02018-10-12 07:00:20 -050014constexpr auto LDAPscheme = "ldap";
15constexpr auto LDAPSscheme = "ldaps";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050016
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050017using namespace phosphor::logging;
18using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta95a29312019-02-18 20:34:10 +053019namespace fs = std::filesystem;
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050020using Argument = xyz::openbmc_project::Common::InvalidArgument;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050021
22using Line = std::string;
23using Key = std::string;
24using Val = std::string;
25using ConfigInfo = std::map<Key, Val>;
26
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050027Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -060028 const char* caCertFile, bool secureLDAP,
29 std::string lDAPServerURI, std::string lDAPBindDN,
30 std::string lDAPBaseDN, std::string&& lDAPBindDNPassword,
Ratan Guptaaeaf9412019-02-11 04:41:52 -060031 ConfigIface::SearchScope lDAPSearchScope,
32 ConfigIface::Type lDAPType, bool lDAPServiceEnabled,
33 std::string userNameAttr, std::string groupNameAttr,
34 ConfigMgr& parent) :
35 Ifaces(bus, path, true),
Ratan Gupta3a1c2742019-03-20 06:49:42 +053036 secureLDAP(secureLDAP), lDAPBindPassword(std::move(lDAPBindDNPassword)),
37 configFilePath(filePath), tlsCacertFile(caCertFile), bus(bus),
38 parent(parent)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050039{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050040 ConfigIface::lDAPServerURI(lDAPServerURI);
41 ConfigIface::lDAPBindDN(lDAPBindDN);
42 ConfigIface::lDAPBaseDN(lDAPBaseDN);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050043 ConfigIface::lDAPSearchScope(lDAPSearchScope);
44 ConfigIface::lDAPType(lDAPType);
Ratan Guptaaeaf9412019-02-11 04:41:52 -060045 EnableIface::enabled(lDAPServiceEnabled);
46 ConfigIface::userNameAttribute(userNameAttr);
47 ConfigIface::groupNameAttribute(groupNameAttr);
Ratan Gupta3a1c2742019-03-20 06:49:42 +053048 // Don't update the bindDN password under ConfigIface::
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050049 writeConfig();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050050 // Emit deferred signal.
51 this->emit_object_added();
Ratan Guptaaeaf9412019-02-11 04:41:52 -060052 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050053}
54
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -050055void Config::delete_()
56{
57 parent.deleteObject();
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050058 try
59 {
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -060060 fs::path configDir = fs::path(configFilePath.c_str()).parent_path();
61
62 fs::copy_file(configDir / defaultNslcdFile, LDAP_CONFIG_FILE,
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050063 fs::copy_options::overwrite_existing);
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050064 }
65 catch (const std::exception& e)
66 {
67 log<level::ERR>("Failed to rename Config Files while deleting Object",
68 entry("ERR=%s", e.what()));
69 elog<InternalFailure>();
70 }
71
72 parent.restartService(nscdService);
73 parent.stopService(nslcdService);
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -050074}
75
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050076void Config::writeConfig()
77{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050078 std::stringstream confData;
Ratan Gupta9891f2f2018-10-06 12:07:35 +053079 auto isPwdTobeWritten = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -060080 std::string userNameAttr;
Ratan Gupta9891f2f2018-10-06 12:07:35 +053081
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050082 confData << "uid root\n";
83 confData << "gid root\n\n";
84 confData << "ldap_version 3\n\n";
85 confData << "timelimit 30\n";
86 confData << "bind_timelimit 30\n";
87 confData << "pagesize 1000\n";
88 confData << "referrals off\n\n";
89 confData << "uri " << lDAPServerURI() << "\n\n";
90 confData << "base " << lDAPBaseDN() << "\n\n";
91 confData << "binddn " << lDAPBindDN() << "\n";
Ratan Gupta3a1c2742019-03-20 06:49:42 +053092 if (!lDAPBindPassword.empty())
Nagaraju Goruganti15675472018-10-05 07:03:05 -050093 {
Ratan Gupta3a1c2742019-03-20 06:49:42 +053094 confData << "bindpw " << lDAPBindPassword << "\n";
Ratan Gupta9891f2f2018-10-06 12:07:35 +053095 isPwdTobeWritten = true;
Nagaraju Goruganti15675472018-10-05 07:03:05 -050096 }
97 confData << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050098 switch (lDAPSearchScope())
99 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600100 case ConfigIface::SearchScope::sub:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500101 confData << "scope sub\n\n";
102 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600103 case ConfigIface::SearchScope::one:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500104 confData << "scope one\n\n";
105 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600106 case ConfigIface::SearchScope::base:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500107 confData << "scope base\n\n";
108 break;
109 }
110 confData << "base passwd " << lDAPBaseDN() << "\n";
111 confData << "base shadow " << lDAPBaseDN() << "\n\n";
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600112 if (secureLDAP == true)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500113 {
114 confData << "ssl on\n";
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600115 confData << "tls_reqcert hard\n";
116 confData << "tls_cacertFile " << tlsCacertFile.c_str() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500117 }
118 else
119 {
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500120 confData << "ssl off\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500121 }
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500122 confData << "\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600123 if (lDAPType() == ConfigIface::Type::ActiveDirectory)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500124 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600125 if (ConfigIface::userNameAttribute().empty())
126 {
127 ConfigIface::userNameAttribute("sAMAccountName");
128 }
129 if (ConfigIface::groupNameAttribute().empty())
130 {
131 ConfigIface::groupNameAttribute("primaryGroupID");
132 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500133 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
134 "(!(objectClass=computer)))\n";
135 confData
136 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
137 "(objectclass=groupofuniquenames))\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600138 confData << "map passwd uid "
139 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500140 confData << "map passwd uidNumber "
141 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600142 confData << "map passwd gidNumber "
143 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500144 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
145 confData << "map passwd gecos displayName\n";
146 confData << "map passwd loginShell \"/bin/bash\"\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500147 confData << "map group gidNumber "
148 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600149 confData << "map group cn "
150 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500151 }
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600152 else if (lDAPType() == ConfigIface::Type::OpenLdap)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500153 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600154 if (ConfigIface::userNameAttribute().empty())
155 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500156 ConfigIface::userNameAttribute("cn");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600157 }
158 if (ConfigIface::groupNameAttribute().empty())
159 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500160 ConfigIface::groupNameAttribute("gidNumber");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600161 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500162 confData << "filter passwd (objectclass=*)\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500163 confData << "map passwd gecos displayName\n";
Nagaraju Goruganti808eda42018-10-10 08:48:12 -0500164 confData << "filter group (objectclass=posixGroup)\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600165 confData << "map passwd uid "
166 << ConfigIface::userNameAttribute() << "\n";
167 confData << "map passwd gidNumber "
168 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500169 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500170 try
171 {
172 std::fstream stream(configFilePath.c_str(), std::fstream::out);
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530173 // remove the read permission from others if password is being written.
174 // nslcd forces this behaviour.
175 auto permission = fs::perms::owner_read | fs::perms::owner_write |
176 fs::perms::group_read;
177 if (isPwdTobeWritten)
178 {
179 fs::permissions(configFilePath, permission);
180 }
181 else
182 {
183 fs::permissions(configFilePath,
184 permission | fs::perms::others_read);
185 }
186
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500187 stream << confData.str();
188 stream.flush();
189 stream.close();
190 }
191 catch (const std::exception& e)
192 {
193 log<level::ERR>(e.what());
194 elog<InternalFailure>();
195 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500196 return;
197}
198
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530199std::string Config::lDAPBindDNPassword(std::string value)
200{
201 // Don't update the D-bus object, this is just to
202 // facilitate if user wants to change the bind dn password
203 // once d-bus object gets created.
204 lDAPBindPassword = value;
205 try
206 {
207 writeConfig();
208 parent.startOrStopService(nslcdService, enabled());
209 }
210 catch (const InternalFailure& e)
211 {
212 throw;
213 }
214 catch (const std::exception& e)
215 {
216 log<level::ERR>(e.what());
217 elog<InternalFailure>();
218 }
219 return value;
220}
221
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500222std::string Config::lDAPServerURI(std::string value)
223{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500224 std::string val;
225 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500226 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500227 if (value == lDAPServerURI())
228 {
229 return value;
230 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500231 if (isValidLDAPURI(value, LDAPSscheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500232 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500233 secureLDAP = true;
234 }
235 else if (isValidLDAPURI(value, LDAPscheme))
236 {
237 secureLDAP = false;
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600238 }
239 else
240 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500241 log<level::ERR>("bad LDAP Server URI",
242 entry("LDAPSERVERURI=%s", value.c_str()));
243 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
244 Argument::ARGUMENT_VALUE(value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500245 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600246
247 if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
248 {
249 log<level::ERR>("LDAP server's CA certificate not provided",
250 entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
251 elog<NoCACertificate>();
252 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500253 val = ConfigIface::lDAPServerURI(value);
254 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600255 parent.startOrStopService(nslcdService, enabled());
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500256 }
257 catch (const InternalFailure& e)
258 {
259 throw;
260 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500261 catch (const InvalidArgument& e)
262 {
263 throw;
264 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600265 catch (const NoCACertificate& e)
266 {
267 throw;
268 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500269 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
277std::string Config::lDAPBindDN(std::string value)
278{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500279 std::string val;
280 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500281 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500282 if (value == lDAPBindDN())
283 {
284 return value;
285 }
286
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500287 if (value.empty())
288 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500289 log<level::ERR>("Not a valid LDAP BINDDN",
290 entry("LDAPBINDDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500291 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"),
292 Argument::ARGUMENT_VALUE(value.c_str()));
293 }
294
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500295 val = ConfigIface::lDAPBindDN(value);
296 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600297 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500298 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500299 catch (const InternalFailure& e)
300 {
301 throw;
302 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600303 catch (const InvalidArgument& e)
304 {
305 throw;
306 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500307 catch (const std::exception& e)
308 {
309 log<level::ERR>(e.what());
310 elog<InternalFailure>();
311 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500312 return val;
313}
314
315std::string Config::lDAPBaseDN(std::string value)
316{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500317 std::string val;
318 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500319 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500320 if (value == lDAPBaseDN())
321 {
322 return value;
323 }
324
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500325 if (value.empty())
326 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500327 log<level::ERR>("Not a valid LDAP BASEDN",
328 entry("BASEDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500329 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"),
330 Argument::ARGUMENT_VALUE(value.c_str()));
331 }
332
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500333 val = ConfigIface::lDAPBaseDN(value);
334 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600335 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500336 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500337 catch (const InternalFailure& e)
338 {
339 throw;
340 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600341 catch (const InvalidArgument& e)
342 {
343 throw;
344 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500345 catch (const std::exception& e)
346 {
347 log<level::ERR>(e.what());
348 elog<InternalFailure>();
349 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500350 return val;
351}
352
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600353ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500354{
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600355 ConfigIface::SearchScope val;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500356 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500357 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500358 if (value == lDAPSearchScope())
359 {
360 return value;
361 }
362
363 val = ConfigIface::lDAPSearchScope(value);
364 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600365 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500366 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500367 catch (const InternalFailure& e)
368 {
369 throw;
370 }
371 catch (const std::exception& e)
372 {
373 log<level::ERR>(e.what());
374 elog<InternalFailure>();
375 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500376 return val;
377}
378
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600379ConfigIface::Type Config::lDAPType(ConfigIface::Type value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500380{
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600381 ConfigIface::Type val;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500382 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500383 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500384 if (value == lDAPType())
385 {
386 return value;
387 }
388
389 val = ConfigIface::lDAPType(value);
390 writeConfig();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600391 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500392 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500393 catch (const InternalFailure& e)
394 {
395 throw;
396 }
397 catch (const std::exception& e)
398 {
399 log<level::ERR>(e.what());
400 elog<InternalFailure>();
401 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500402 return val;
403}
404
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600405bool Config::enabled(bool value)
406{
407 bool isEnable;
408 try
409 {
410 if (value == enabled())
411 {
412 return value;
413 }
414 isEnable = EnableIface::enabled(value);
Ratan Gupta95a29312019-02-18 20:34:10 +0530415 // save the enabled property.
416 serialize(*this, parent.dbusPersistentPath);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600417 parent.startOrStopService(nslcdService, value);
418 }
419 catch (const InternalFailure& e)
420 {
421 throw;
422 }
423 catch (const std::exception& e)
424 {
425 log<level::ERR>(e.what());
426 elog<InternalFailure>();
427 }
428 return isEnable;
429}
430
431std::string Config::userNameAttribute(std::string value)
432{
433 std::string val;
434 try
435 {
436 if (value == userNameAttribute())
437 {
438 return value;
439 }
440
441 val = ConfigIface::userNameAttribute(value);
442 writeConfig();
443 parent.startOrStopService(nslcdService, enabled());
444 }
445 catch (const InternalFailure& e)
446 {
447 throw;
448 }
449 catch (const std::exception& e)
450 {
451 log<level::ERR>(e.what());
452 elog<InternalFailure>();
453 }
454 return val;
455}
456
457std::string Config::groupNameAttribute(std::string value)
458{
459 std::string val;
460 try
461 {
462 if (value == groupNameAttribute())
463 {
464 return value;
465 }
466
467 val = ConfigIface::groupNameAttribute(value);
468 writeConfig();
469 parent.startOrStopService(nslcdService, enabled());
470 }
471 catch (const InternalFailure& e)
472 {
473 throw;
474 }
475 catch (const std::exception& e)
476 {
477 log<level::ERR>(e.what());
478 elog<InternalFailure>();
479 }
480 return val;
481}
482
483void ConfigMgr::startOrStopService(const std::string& service, bool start)
484{
485 if (start)
486 {
487 restartService(service);
488 }
489 else
490 {
491 stopService(service);
492 }
493}
494
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500495void ConfigMgr::restartService(const std::string& service)
496{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500497 try
498 {
499 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
500 SYSTEMD_INTERFACE, "RestartUnit");
501 method.append(service.c_str(), "replace");
502 bus.call_noreply(method);
503 }
504 catch (const sdbusplus::exception::SdBusError& ex)
505 {
Ratan Guptaa9297522019-02-20 15:47:32 +0530506 log<level::ERR>("Failed to restart service",
507 entry("SERVICE=%s", service.c_str()),
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500508 entry("ERR=%s", ex.what()));
509 elog<InternalFailure>();
510 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500511}
512
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500513void ConfigMgr::stopService(const std::string& service)
514{
515 try
516 {
517 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
518 SYSTEMD_INTERFACE, "StopUnit");
519 method.append(service.c_str(), "replace");
520 bus.call_noreply(method);
521 }
522 catch (const sdbusplus::exception::SdBusError& ex)
523 {
Ratan Guptaa9297522019-02-20 15:47:32 +0530524 log<level::ERR>("Failed to stop service",
525 entry("SERVICE=%s", service.c_str()),
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500526 entry("ERR=%s", ex.what()));
527 elog<InternalFailure>();
528 }
529}
530
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -0500531void ConfigMgr::deleteObject()
532{
533 configPtr.reset(nullptr);
534}
535
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600536std::string ConfigMgr::createConfig(
537 std::string lDAPServerURI, std::string lDAPBindDN, std::string lDAPBaseDN,
538 std::string lDAPBindDNPassword, CreateIface::SearchScope lDAPSearchScope,
539 CreateIface::Create::Type lDAPType, std::string groupNameAttribute,
540 std::string userNameAttribute)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500541{
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600542 bool secureLDAP = false;
543
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500544 if (isValidLDAPURI(lDAPServerURI, LDAPSscheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500545 {
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600546 secureLDAP = true;
547 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500548 else if (isValidLDAPURI(lDAPServerURI, LDAPscheme))
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600549 {
550 secureLDAP = false;
551 }
552 else
553 {
554 log<level::ERR>("bad LDAP Server URI",
555 entry("LDAPSERVERURI=%s", lDAPServerURI.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500556 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
557 Argument::ARGUMENT_VALUE(lDAPServerURI.c_str()));
558 }
559
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600560 if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
561 {
562 log<level::ERR>("LDAP server's CA certificate not provided",
563 entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
564 elog<NoCACertificate>();
565 }
566
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500567 if (lDAPBindDN.empty())
568 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500569 log<level::ERR>("Not a valid LDAP BINDDN",
570 entry("LDAPBINDDN=%s", lDAPBindDN.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500571 elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBindDN"),
572 Argument::ARGUMENT_VALUE(lDAPBindDN.c_str()));
573 }
574
575 if (lDAPBaseDN.empty())
576 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500577 log<level::ERR>("Not a valid LDAP BASEDN",
578 entry("LDAPBASEDN=%s", lDAPBaseDN.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500579 elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBaseDN"),
580 Argument::ARGUMENT_VALUE(lDAPBaseDN.c_str()));
581 }
582
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500583 // With current implementation we support only one LDAP server.
Nagaraju Goruganti24194bd2018-09-18 09:55:09 -0500584 deleteObject();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500585
586 auto objPath = std::string(LDAP_CONFIG_DBUS_OBJ_PATH);
587 configPtr = std::make_unique<Config>(
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600588 bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
589 secureLDAP, lDAPServerURI, lDAPBindDN, lDAPBaseDN,
590 std::move(lDAPBindDNPassword),
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600591 static_cast<ConfigIface::SearchScope>(lDAPSearchScope),
592 static_cast<ConfigIface::Type>(lDAPType), false, groupNameAttribute,
593 userNameAttribute, *this);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500594
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -0500595 restartService(nscdService);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500596 return objPath;
597}
598
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500599void ConfigMgr::restore(const char* filePath)
600{
601 if (!fs::exists(filePath))
602 {
603 log<level::ERR>("Config file doesn't exists",
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600604 entry("LDAP_CONFIG_FILE=%s", configFilePath.c_str()));
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500605 return;
606 }
607
608 ConfigInfo configValues;
609
610 try
611 {
612 std::fstream stream(filePath, std::fstream::in);
613 Line line;
614 // read characters from stream and places them into line
615 while (std::getline(stream, line))
616 {
617 // remove leading and trailing extra spaces
618 auto firstScan = line.find_first_not_of(' ');
619 auto first =
620 (firstScan == std::string::npos ? line.length() : firstScan);
621 auto last = line.find_last_not_of(' ');
622 line = line.substr(first, last - first + 1);
623 // reduce multiple spaces between two words to a single space
624 auto pred = [](char a, char b) {
625 return (a == b && a == ' ') ? true : false;
626 };
627
628 auto lastPos = std::unique(line.begin(), line.end(), pred);
629
630 line.erase(lastPos, line.end());
631
632 // Ignore if line is empty or starts with '#'
633 if (line.empty() || line.at(0) == '#')
634 {
635 continue;
636 }
637
638 Key key;
639 std::istringstream isLine(line);
640 // extract characters from isLine and stores them into
641 // key until the delimitation character ' ' is found.
642 // If the delimiter is found, it is extracted and discarded
643 // the next input operation will begin after it.
644 if (std::getline(isLine, key, ' '))
645 {
646 Val value;
647 // extract characters after delimitation character ' '
648 if (std::getline(isLine, value, ' '))
649 {
650 // skip line if it starts with "base shadow" or
651 // "base passwd" because we would have 3 entries
652 // ("base lDAPBaseDN" , "base passwd lDAPBaseDN" and
653 // "base shadow lDAPBaseDN") for the property "lDAPBaseDN",
654 // one is enough to restore it.
655
656 if ((key == "base") &&
657 (value == "passwd" || value == "shadow"))
658 {
659 continue;
660 }
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600661
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500662 // if config type is AD "map group" entry would be add to
663 // the map configValues. For OpenLdap config file no map
664 // entry would be there.
665 if ((key == "map") && (value == "passwd"))
666 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600667 key = key + "_" + value;
668 if (std::getline(isLine, value, ' '))
669 {
670 key += "_" + value;
671 }
672 std::getline(isLine, value, ' ');
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500673 }
674 configValues[key] = value;
675 }
676 }
677 }
678
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600679 CreateIface::SearchScope lDAPSearchScope;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500680 if (configValues["scope"] == "sub")
681 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600682 lDAPSearchScope = CreateIface::SearchScope::sub;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500683 }
684 else if (configValues["scope"] == "one")
685 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600686 lDAPSearchScope = CreateIface::SearchScope::one;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500687 }
688 else
689 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600690 lDAPSearchScope = CreateIface::SearchScope::base;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500691 }
692
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600693 CreateIface::Type lDAPType;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500694 // If the file is having a line which starts with "map group"
695 if (configValues["map"] == "group")
696 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600697 lDAPType = CreateIface::Type::ActiveDirectory;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500698 }
699 else
700 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600701 lDAPType = CreateIface::Type::OpenLdap;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500702 }
703
Ratan Guptac9c86a22018-10-18 00:47:01 +0530704 // Don't create the config object if either of the field is empty.
705 if (configValues["uri"] == "" || configValues["binddn"] == "" ||
706 configValues["base"] == "")
707 {
708 log<level::INFO>(
709 "LDAP config parameter value missing",
710 entry("URI=%s", configValues["uri"].c_str()),
711 entry("BASEDN=%s", configValues["base"].c_str()),
712 entry("BINDDN=%s", configValues["binddn"].c_str()));
713 return;
714 }
715
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600716 createConfig(std::move(configValues["uri"]),
717 std::move(configValues["binddn"]),
718 std::move(configValues["base"]),
719 std::move(configValues["bindpw"]), lDAPSearchScope,
720 lDAPType, std::move(configValues["map_passwd_uid"]),
721 std::move(configValues["map_passwd_gidNumber"]));
Ratan Gupta95a29312019-02-18 20:34:10 +0530722
723 // Get the enabled property value from the persistent location
724 if (!deserialize(dbusPersistentPath, *configPtr))
725 {
726 log<level::INFO>(
727 "Deserialization Failed, continue with service disable");
728 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500729 }
730 catch (const InvalidArgument& e)
731 {
732 // Don't throw - we don't want to create a D-Bus
733 // object upon finding empty values in config, as
734 // this can be a default config.
735 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600736 catch (const NoCACertificate& e)
737 {
738 // Don't throw - we don't want to create a D-Bus
739 // object upon finding "ssl on" without having tls_cacertFile in place,
740 // as this can be a default config.
741 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500742 catch (const InternalFailure& e)
743 {
744 throw;
745 }
746 catch (const std::exception& e)
747 {
748 log<level::ERR>(e.what());
749 elog<InternalFailure>();
750 }
751}
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500752} // namespace ldap
753} // namespace phosphor