blob: 746f324cd0e90cd3d9d2d0a26d7d1b35edf28b17 [file] [log] [blame]
Ratan Guptae1f4db62019-04-11 18:57:42 +05301#include "ldap_config_mgr.hpp"
Ratan Gupta37fb3fe2019-04-13 12:54:18 +05302#include "ldap_config.hpp"
3#include "ldap_config_serialize.hpp"
Nagaraju Goruganti59287f02018-10-12 07:00:20 -05004#include "utils.hpp"
Ratan Gupta95a29312019-02-18 20:34:10 +05305#include <filesystem>
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -05006#include <fstream>
7#include <sstream>
8
9namespace phosphor
10{
11namespace ldap
12{
Ratan Guptae1f4db62019-04-11 18:57:42 +053013
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050014constexpr auto nslcdService = "nslcd.service";
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050015constexpr auto nscdService = "nscd.service";
Nagaraju Goruganti59287f02018-10-12 07:00:20 -050016constexpr auto LDAPscheme = "ldap";
17constexpr auto LDAPSscheme = "ldaps";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050018
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050019using namespace phosphor::logging;
20using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta95a29312019-02-18 20:34:10 +053021namespace fs = std::filesystem;
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050022using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta27d4c012019-04-12 13:03:35 +053023using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
24using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050025
26using Line = std::string;
27using Key = std::string;
28using Val = std::string;
29using ConfigInfo = std::map<Key, Val>;
30
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050031Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -060032 const char* caCertFile, bool secureLDAP,
33 std::string lDAPServerURI, std::string lDAPBindDN,
34 std::string lDAPBaseDN, std::string&& lDAPBindDNPassword,
Ratan Guptaaeaf9412019-02-11 04:41:52 -060035 ConfigIface::SearchScope lDAPSearchScope,
36 ConfigIface::Type lDAPType, bool lDAPServiceEnabled,
37 std::string userNameAttr, std::string groupNameAttr,
38 ConfigMgr& parent) :
39 Ifaces(bus, path, true),
Ratan Gupta3a1c2742019-03-20 06:49:42 +053040 secureLDAP(secureLDAP), lDAPBindPassword(std::move(lDAPBindDNPassword)),
41 configFilePath(filePath), tlsCacertFile(caCertFile), bus(bus),
42 parent(parent)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050043{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050044 ConfigIface::lDAPServerURI(lDAPServerURI);
45 ConfigIface::lDAPBindDN(lDAPBindDN);
46 ConfigIface::lDAPBaseDN(lDAPBaseDN);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050047 ConfigIface::lDAPSearchScope(lDAPSearchScope);
48 ConfigIface::lDAPType(lDAPType);
Ratan Guptaaeaf9412019-02-11 04:41:52 -060049 EnableIface::enabled(lDAPServiceEnabled);
50 ConfigIface::userNameAttribute(userNameAttr);
51 ConfigIface::groupNameAttribute(groupNameAttr);
Ratan Gupta3a1c2742019-03-20 06:49:42 +053052 // Don't update the bindDN password under ConfigIface::
Ratan Guptaec117542019-04-25 18:38:29 +053053 if (enabled())
54 {
55 writeConfig();
56 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050057 // Emit deferred signal.
58 this->emit_object_added();
Ratan Guptaaeaf9412019-02-11 04:41:52 -060059 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050060}
61
62void Config::writeConfig()
63{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050064 std::stringstream confData;
Ratan Gupta9891f2f2018-10-06 12:07:35 +053065 auto isPwdTobeWritten = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -060066 std::string userNameAttr;
Ratan Gupta9891f2f2018-10-06 12:07:35 +053067
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050068 confData << "uid root\n";
69 confData << "gid root\n\n";
70 confData << "ldap_version 3\n\n";
71 confData << "timelimit 30\n";
72 confData << "bind_timelimit 30\n";
73 confData << "pagesize 1000\n";
74 confData << "referrals off\n\n";
75 confData << "uri " << lDAPServerURI() << "\n\n";
76 confData << "base " << lDAPBaseDN() << "\n\n";
77 confData << "binddn " << lDAPBindDN() << "\n";
Ratan Gupta3a1c2742019-03-20 06:49:42 +053078 if (!lDAPBindPassword.empty())
Nagaraju Goruganti15675472018-10-05 07:03:05 -050079 {
Ratan Gupta3a1c2742019-03-20 06:49:42 +053080 confData << "bindpw " << lDAPBindPassword << "\n";
Ratan Gupta9891f2f2018-10-06 12:07:35 +053081 isPwdTobeWritten = true;
Nagaraju Goruganti15675472018-10-05 07:03:05 -050082 }
83 confData << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050084 switch (lDAPSearchScope())
85 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -060086 case ConfigIface::SearchScope::sub:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050087 confData << "scope sub\n\n";
88 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -060089 case ConfigIface::SearchScope::one:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050090 confData << "scope one\n\n";
91 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -060092 case ConfigIface::SearchScope::base:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050093 confData << "scope base\n\n";
94 break;
95 }
96 confData << "base passwd " << lDAPBaseDN() << "\n";
97 confData << "base shadow " << lDAPBaseDN() << "\n\n";
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -060098 if (secureLDAP == true)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050099 {
100 confData << "ssl on\n";
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600101 confData << "tls_reqcert hard\n";
102 confData << "tls_cacertFile " << tlsCacertFile.c_str() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500103 }
104 else
105 {
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500106 confData << "ssl off\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500107 }
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500108 confData << "\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600109 if (lDAPType() == ConfigIface::Type::ActiveDirectory)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500110 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600111 if (ConfigIface::userNameAttribute().empty())
112 {
113 ConfigIface::userNameAttribute("sAMAccountName");
114 }
115 if (ConfigIface::groupNameAttribute().empty())
116 {
117 ConfigIface::groupNameAttribute("primaryGroupID");
118 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500119 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
120 "(!(objectClass=computer)))\n";
121 confData
122 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
123 "(objectclass=groupofuniquenames))\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600124 confData << "map passwd uid "
125 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500126 confData << "map passwd uidNumber "
127 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600128 confData << "map passwd gidNumber "
129 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500130 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
131 confData << "map passwd gecos displayName\n";
132 confData << "map passwd loginShell \"/bin/bash\"\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500133 confData << "map group gidNumber "
134 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600135 confData << "map group cn "
136 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500137 }
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600138 else if (lDAPType() == ConfigIface::Type::OpenLdap)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500139 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600140 if (ConfigIface::userNameAttribute().empty())
141 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500142 ConfigIface::userNameAttribute("cn");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600143 }
144 if (ConfigIface::groupNameAttribute().empty())
145 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500146 ConfigIface::groupNameAttribute("gidNumber");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600147 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500148 confData << "filter passwd (objectclass=*)\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500149 confData << "map passwd gecos displayName\n";
Nagaraju Goruganti808eda42018-10-10 08:48:12 -0500150 confData << "filter group (objectclass=posixGroup)\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600151 confData << "map passwd uid "
152 << ConfigIface::userNameAttribute() << "\n";
153 confData << "map passwd gidNumber "
154 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500155 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500156 try
157 {
158 std::fstream stream(configFilePath.c_str(), std::fstream::out);
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530159 // remove the read permission from others if password is being written.
160 // nslcd forces this behaviour.
161 auto permission = fs::perms::owner_read | fs::perms::owner_write |
162 fs::perms::group_read;
163 if (isPwdTobeWritten)
164 {
165 fs::permissions(configFilePath, permission);
166 }
167 else
168 {
169 fs::permissions(configFilePath,
170 permission | fs::perms::others_read);
171 }
172
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500173 stream << confData.str();
174 stream.flush();
175 stream.close();
176 }
177 catch (const std::exception& e)
178 {
179 log<level::ERR>(e.what());
180 elog<InternalFailure>();
181 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500182 return;
183}
184
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530185std::string Config::lDAPBindDNPassword(std::string value)
186{
187 // Don't update the D-bus object, this is just to
188 // facilitate if user wants to change the bind dn password
189 // once d-bus object gets created.
190 lDAPBindPassword = value;
191 try
192 {
Ratan Guptaec117542019-04-25 18:38:29 +0530193 if (enabled())
194 {
195 writeConfig();
196 parent.startOrStopService(nslcdService, enabled());
197 }
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530198 }
199 catch (const InternalFailure& e)
200 {
201 throw;
202 }
203 catch (const std::exception& e)
204 {
205 log<level::ERR>(e.what());
206 elog<InternalFailure>();
207 }
208 return value;
209}
210
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500211std::string Config::lDAPServerURI(std::string value)
212{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500213 std::string val;
214 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500215 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500216 if (value == lDAPServerURI())
217 {
218 return value;
219 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500220 if (isValidLDAPURI(value, LDAPSscheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500221 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500222 secureLDAP = true;
223 }
224 else if (isValidLDAPURI(value, LDAPscheme))
225 {
226 secureLDAP = false;
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600227 }
228 else
229 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500230 log<level::ERR>("bad LDAP Server URI",
231 entry("LDAPSERVERURI=%s", value.c_str()));
232 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
233 Argument::ARGUMENT_VALUE(value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500234 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600235
236 if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
237 {
238 log<level::ERR>("LDAP server's CA certificate not provided",
239 entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
240 elog<NoCACertificate>();
241 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500242 val = ConfigIface::lDAPServerURI(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530243 if (enabled())
244 {
245 writeConfig();
246 parent.startOrStopService(nslcdService, enabled());
247 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500248 }
249 catch (const InternalFailure& e)
250 {
251 throw;
252 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500253 catch (const InvalidArgument& e)
254 {
255 throw;
256 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600257 catch (const NoCACertificate& e)
258 {
259 throw;
260 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500261 catch (const std::exception& e)
262 {
263 log<level::ERR>(e.what());
264 elog<InternalFailure>();
265 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500266 return val;
267}
268
269std::string Config::lDAPBindDN(std::string value)
270{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500271 std::string val;
272 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500273 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500274 if (value == lDAPBindDN())
275 {
276 return value;
277 }
278
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500279 if (value.empty())
280 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500281 log<level::ERR>("Not a valid LDAP BINDDN",
282 entry("LDAPBINDDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500283 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"),
284 Argument::ARGUMENT_VALUE(value.c_str()));
285 }
286
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500287 val = ConfigIface::lDAPBindDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530288 if (enabled())
289 {
290 writeConfig();
291 parent.startOrStopService(nslcdService, enabled());
292 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500293 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500294 catch (const InternalFailure& e)
295 {
296 throw;
297 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600298 catch (const InvalidArgument& e)
299 {
300 throw;
301 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500302 catch (const std::exception& e)
303 {
304 log<level::ERR>(e.what());
305 elog<InternalFailure>();
306 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500307 return val;
308}
309
310std::string Config::lDAPBaseDN(std::string value)
311{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500312 std::string val;
313 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500314 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500315 if (value == lDAPBaseDN())
316 {
317 return value;
318 }
319
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500320 if (value.empty())
321 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500322 log<level::ERR>("Not a valid LDAP BASEDN",
323 entry("BASEDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500324 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"),
325 Argument::ARGUMENT_VALUE(value.c_str()));
326 }
327
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500328 val = ConfigIface::lDAPBaseDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530329 if (enabled())
330 {
331 writeConfig();
332 parent.startOrStopService(nslcdService, enabled());
333 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500334 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500335 catch (const InternalFailure& e)
336 {
337 throw;
338 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600339 catch (const InvalidArgument& e)
340 {
341 throw;
342 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500343 catch (const std::exception& e)
344 {
345 log<level::ERR>(e.what());
346 elog<InternalFailure>();
347 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500348 return val;
349}
350
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600351ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500352{
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600353 ConfigIface::SearchScope val;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500354 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500355 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500356 if (value == lDAPSearchScope())
357 {
358 return value;
359 }
360
361 val = ConfigIface::lDAPSearchScope(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530362 if (enabled())
363 {
364 writeConfig();
365
366 parent.startOrStopService(nslcdService, enabled());
367 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500368 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500369 catch (const InternalFailure& e)
370 {
371 throw;
372 }
373 catch (const std::exception& e)
374 {
375 log<level::ERR>(e.what());
376 elog<InternalFailure>();
377 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500378 return val;
379}
380
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600381ConfigIface::Type Config::lDAPType(ConfigIface::Type value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500382{
Ratan Gupta27d4c012019-04-12 13:03:35 +0530383 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
384 return lDAPType();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500385}
386
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600387bool Config::enabled(bool value)
388{
389 bool isEnable;
390 try
391 {
392 if (value == enabled())
393 {
394 return value;
395 }
396 isEnable = EnableIface::enabled(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530397 if (isEnable)
398 {
399 writeConfig();
400 }
401 // TODO in later commit, one of the config would be active
402 // at any moment of time.
403 parent.startOrStopService(nslcdService, value);
Ratan Gupta95a29312019-02-18 20:34:10 +0530404 // save the enabled property.
405 serialize(*this, parent.dbusPersistentPath);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600406 }
407 catch (const InternalFailure& e)
408 {
409 throw;
410 }
411 catch (const std::exception& e)
412 {
413 log<level::ERR>(e.what());
414 elog<InternalFailure>();
415 }
416 return isEnable;
417}
418
419std::string Config::userNameAttribute(std::string value)
420{
421 std::string val;
422 try
423 {
424 if (value == userNameAttribute())
425 {
426 return value;
427 }
428
429 val = ConfigIface::userNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530430 if (enabled())
431 {
432 writeConfig();
433
434 parent.startOrStopService(nslcdService, enabled());
435 }
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600436 }
437 catch (const InternalFailure& e)
438 {
439 throw;
440 }
441 catch (const std::exception& e)
442 {
443 log<level::ERR>(e.what());
444 elog<InternalFailure>();
445 }
446 return val;
447}
448
449std::string Config::groupNameAttribute(std::string value)
450{
451 std::string val;
452 try
453 {
454 if (value == groupNameAttribute())
455 {
456 return value;
457 }
458
459 val = ConfigIface::groupNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530460 if (enabled())
461 {
462 writeConfig();
463
464 parent.startOrStopService(nslcdService, enabled());
465 }
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600466 }
467 catch (const InternalFailure& e)
468 {
469 throw;
470 }
471 catch (const std::exception& e)
472 {
473 log<level::ERR>(e.what());
474 elog<InternalFailure>();
475 }
476 return val;
477}
478
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500479} // namespace ldap
480} // namespace phosphor