blob: d01757a29c19ce7818e4793ac9f787a2a31b1d5a [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"
Nagaraju Goruganti59287f02018-10-12 07:00:20 -05003#include "utils.hpp"
Ratan Gupta21e88cb2019-04-12 17:15:52 +05304
5#include <cereal/types/string.hpp>
6#include <cereal/types/vector.hpp>
7#include <cereal/archives/binary.hpp>
Ratan Gupta7b04c352019-04-12 21:46:29 +05308#include "ldap_mapper_serialize.hpp"
9
10#include <xyz/openbmc_project/Common/error.hpp>
11#include <xyz/openbmc_project/User/Common/error.hpp>
Ratan Gupta95a29312019-02-18 20:34:10 +053012#include <filesystem>
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050013#include <fstream>
14#include <sstream>
15
Ratan Gupta21e88cb2019-04-12 17:15:52 +053016// Register class version
17// From cereal documentation;
18// "This macro should be placed at global scope"
19CEREAL_CLASS_VERSION(phosphor::ldap::Config, CLASS_VERSION);
20
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050021namespace phosphor
22{
23namespace ldap
24{
Ratan Guptae1f4db62019-04-11 18:57:42 +053025
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050026constexpr auto nslcdService = "nslcd.service";
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050027constexpr auto nscdService = "nscd.service";
Nagaraju Goruganti59287f02018-10-12 07:00:20 -050028constexpr auto LDAPscheme = "ldap";
29constexpr auto LDAPSscheme = "ldaps";
Ratan Guptaab4fcb42019-04-29 19:39:51 +053030constexpr auto certObjPath = "/xyz/openbmc_project/certs/client/ldap/1";
31constexpr auto certRootPath = "/xyz/openbmc_project/certs/client/ldap";
32constexpr auto certIface = "xyz.openbmc_project.Certs.Certificate";
33constexpr auto certProperty = "CertificateString";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050034
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050035using namespace phosphor::logging;
36using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta95a29312019-02-18 20:34:10 +053037namespace fs = std::filesystem;
Ratan Gupta7b04c352019-04-12 21:46:29 +053038
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050039using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta27d4c012019-04-12 13:03:35 +053040using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
41using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Ratan Gupta7b04c352019-04-12 21:46:29 +053042using PrivilegeMappingExists = sdbusplus::xyz::openbmc_project::User::Common::
43 Error::PrivilegeMappingExists;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050044
45using Line = std::string;
46using Key = std::string;
47using Val = std::string;
48using ConfigInfo = std::map<Key, Val>;
49
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050050Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
Ratan Gupta22f13f12019-04-29 15:36:40 +053051 const char* caCertFile, const char* certFile, bool secureLDAP,
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -060052 std::string lDAPServerURI, std::string lDAPBindDN,
53 std::string lDAPBaseDN, std::string&& lDAPBindDNPassword,
Ratan Guptaaeaf9412019-02-11 04:41:52 -060054 ConfigIface::SearchScope lDAPSearchScope,
55 ConfigIface::Type lDAPType, bool lDAPServiceEnabled,
56 std::string userNameAttr, std::string groupNameAttr,
57 ConfigMgr& parent) :
58 Ifaces(bus, path, true),
Ratan Gupta3a1c2742019-03-20 06:49:42 +053059 secureLDAP(secureLDAP), lDAPBindPassword(std::move(lDAPBindDNPassword)),
Ratan Gupta22f13f12019-04-29 15:36:40 +053060 tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
61 objectPath(path), bus(bus), parent(parent),
62 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +053063 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +053064 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +053065 std::placeholders::_1)),
66 certificateChangedSignal(
67 bus,
68 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
69 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +053070 std::placeholders::_1))
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050071{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050072 ConfigIface::lDAPServerURI(lDAPServerURI);
73 ConfigIface::lDAPBindDN(lDAPBindDN);
74 ConfigIface::lDAPBaseDN(lDAPBaseDN);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050075 ConfigIface::lDAPSearchScope(lDAPSearchScope);
76 ConfigIface::lDAPType(lDAPType);
Ratan Guptaaeaf9412019-02-11 04:41:52 -060077 EnableIface::enabled(lDAPServiceEnabled);
78 ConfigIface::userNameAttribute(userNameAttr);
79 ConfigIface::groupNameAttribute(groupNameAttr);
Ratan Gupta21e88cb2019-04-12 17:15:52 +053080 // NOTE: Don't update the bindDN password under ConfigIface
Ratan Guptaec117542019-04-25 18:38:29 +053081 if (enabled())
82 {
83 writeConfig();
84 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +053085 // save the config.
86 configPersistPath = parent.dbusPersistentPath;
87 configPersistPath += objectPath;
88
89 // create the persistent directory
90 fs::create_directories(configPersistPath);
91
92 configPersistPath += "/config";
93
Ratan Gupta21e88cb2019-04-12 17:15:52 +053094 serialize();
95
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050096 // Emit deferred signal.
97 this->emit_object_added();
Ratan Guptaaeaf9412019-02-11 04:41:52 -060098 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050099}
100
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530101Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530102 const char* caCertFile, const char* certFile,
103 ConfigIface::Type lDAPType, ConfigMgr& parent) :
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530104 Ifaces(bus, path, true),
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530105 tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
106 objectPath(path), bus(bus), parent(parent),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530107 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530108 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530109 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530110 std::placeholders::_1)),
111 certificateChangedSignal(
112 bus,
113 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
114 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +0530115 std::placeholders::_1))
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530116{
117 ConfigIface::lDAPType(lDAPType);
118
119 configPersistPath = parent.dbusPersistentPath;
120 configPersistPath += objectPath;
121
122 // create the persistent directory
123 fs::create_directories(configPersistPath);
124
125 configPersistPath += "/config";
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530126}
127
Ratan Gupta22f13f12019-04-29 15:36:40 +0530128void Config::certificateInstalled(sdbusplus::message::message& msg)
129{
130 try
131 {
132 if (enabled())
133 {
134 writeConfig();
135 }
136 parent.startOrStopService(nslcdService, enabled());
137 }
138 catch (const InternalFailure& e)
139 {
140 throw;
141 }
142 catch (const std::exception& e)
143 {
144 log<level::ERR>(e.what());
145 elog<InternalFailure>();
146 }
147}
148
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530149void Config::certificateChanged(sdbusplus::message::message& msg)
150{
151 // TODO: Property filtering needs to be done, we need to write
152 // the config only when the property is "Certificate String".
153 try
154 {
155 if (enabled())
156 {
157 writeConfig();
158 }
159 parent.startOrStopService(nslcdService, enabled());
160 }
161 catch (const InternalFailure& e)
162 {
163 throw;
164 }
165 catch (const std::exception& e)
166 {
167 log<level::ERR>(e.what());
168 elog<InternalFailure>();
169 }
170}
171
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500172void Config::writeConfig()
173{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500174 std::stringstream confData;
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530175 auto isPwdTobeWritten = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600176 std::string userNameAttr;
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530177
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500178 confData << "uid root\n";
179 confData << "gid root\n\n";
180 confData << "ldap_version 3\n\n";
181 confData << "timelimit 30\n";
182 confData << "bind_timelimit 30\n";
183 confData << "pagesize 1000\n";
184 confData << "referrals off\n\n";
185 confData << "uri " << lDAPServerURI() << "\n\n";
186 confData << "base " << lDAPBaseDN() << "\n\n";
187 confData << "binddn " << lDAPBindDN() << "\n";
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530188 if (!lDAPBindPassword.empty())
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500189 {
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530190 confData << "bindpw " << lDAPBindPassword << "\n";
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530191 isPwdTobeWritten = true;
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500192 }
193 confData << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500194 switch (lDAPSearchScope())
195 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600196 case ConfigIface::SearchScope::sub:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500197 confData << "scope sub\n\n";
198 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600199 case ConfigIface::SearchScope::one:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500200 confData << "scope one\n\n";
201 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600202 case ConfigIface::SearchScope::base:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500203 confData << "scope base\n\n";
204 break;
205 }
206 confData << "base passwd " << lDAPBaseDN() << "\n";
207 confData << "base shadow " << lDAPBaseDN() << "\n\n";
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600208 if (secureLDAP == true)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500209 {
210 confData << "ssl on\n";
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600211 confData << "tls_reqcert hard\n";
212 confData << "tls_cacertFile " << tlsCacertFile.c_str() << "\n";
Ratan Gupta22f13f12019-04-29 15:36:40 +0530213 if (fs::exists(tlsCertFile.c_str()))
214 {
215 confData << "tls_cert " << tlsCertFile.c_str() << "\n";
216 confData << "tls_key " << tlsCertFile.c_str() << "\n";
217 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500218 }
219 else
220 {
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500221 confData << "ssl off\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500222 }
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500223 confData << "\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600224 if (lDAPType() == ConfigIface::Type::ActiveDirectory)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500225 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600226 if (ConfigIface::userNameAttribute().empty())
227 {
228 ConfigIface::userNameAttribute("sAMAccountName");
229 }
230 if (ConfigIface::groupNameAttribute().empty())
231 {
232 ConfigIface::groupNameAttribute("primaryGroupID");
233 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500234 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
235 "(!(objectClass=computer)))\n";
236 confData
237 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
238 "(objectclass=groupofuniquenames))\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600239 confData << "map passwd uid "
240 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500241 confData << "map passwd uidNumber "
242 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600243 confData << "map passwd gidNumber "
244 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500245 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
246 confData << "map passwd gecos displayName\n";
247 confData << "map passwd loginShell \"/bin/bash\"\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500248 confData << "map group gidNumber "
249 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600250 confData << "map group cn "
251 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500252 }
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600253 else if (lDAPType() == ConfigIface::Type::OpenLdap)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500254 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600255 if (ConfigIface::userNameAttribute().empty())
256 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500257 ConfigIface::userNameAttribute("cn");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600258 }
259 if (ConfigIface::groupNameAttribute().empty())
260 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500261 ConfigIface::groupNameAttribute("gidNumber");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600262 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500263 confData << "filter passwd (objectclass=*)\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500264 confData << "map passwd gecos displayName\n";
Nagaraju Goruganti808eda42018-10-10 08:48:12 -0500265 confData << "filter group (objectclass=posixGroup)\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600266 confData << "map passwd uid "
267 << ConfigIface::userNameAttribute() << "\n";
268 confData << "map passwd gidNumber "
269 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500270 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500271 try
272 {
273 std::fstream stream(configFilePath.c_str(), std::fstream::out);
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530274 // remove the read permission from others if password is being written.
275 // nslcd forces this behaviour.
276 auto permission = fs::perms::owner_read | fs::perms::owner_write |
277 fs::perms::group_read;
278 if (isPwdTobeWritten)
279 {
280 fs::permissions(configFilePath, permission);
281 }
282 else
283 {
284 fs::permissions(configFilePath,
285 permission | fs::perms::others_read);
286 }
287
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500288 stream << confData.str();
289 stream.flush();
290 stream.close();
291 }
292 catch (const std::exception& e)
293 {
294 log<level::ERR>(e.what());
295 elog<InternalFailure>();
296 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500297 return;
298}
299
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530300std::string Config::lDAPBindDNPassword(std::string value)
301{
302 // Don't update the D-bus object, this is just to
303 // facilitate if user wants to change the bind dn password
304 // once d-bus object gets created.
305 lDAPBindPassword = value;
306 try
307 {
Ratan Guptaec117542019-04-25 18:38:29 +0530308 if (enabled())
309 {
310 writeConfig();
311 parent.startOrStopService(nslcdService, enabled());
312 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530313 serialize();
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530314 }
315 catch (const InternalFailure& e)
316 {
317 throw;
318 }
319 catch (const std::exception& e)
320 {
321 log<level::ERR>(e.what());
322 elog<InternalFailure>();
323 }
324 return value;
325}
326
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500327std::string Config::lDAPServerURI(std::string value)
328{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500329 std::string val;
330 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500331 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500332 if (value == lDAPServerURI())
333 {
334 return value;
335 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500336 if (isValidLDAPURI(value, LDAPSscheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500337 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500338 secureLDAP = true;
339 }
340 else if (isValidLDAPURI(value, LDAPscheme))
341 {
342 secureLDAP = false;
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600343 }
344 else
345 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500346 log<level::ERR>("bad LDAP Server URI",
347 entry("LDAPSERVERURI=%s", value.c_str()));
348 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
349 Argument::ARGUMENT_VALUE(value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500350 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600351
352 if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
353 {
354 log<level::ERR>("LDAP server's CA certificate not provided",
355 entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
356 elog<NoCACertificate>();
357 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500358 val = ConfigIface::lDAPServerURI(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530359 if (enabled())
360 {
361 writeConfig();
362 parent.startOrStopService(nslcdService, enabled());
363 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530364 // save the object.
365 serialize();
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500366 }
367 catch (const InternalFailure& e)
368 {
369 throw;
370 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500371 catch (const InvalidArgument& e)
372 {
373 throw;
374 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600375 catch (const NoCACertificate& e)
376 {
377 throw;
378 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500379 catch (const std::exception& e)
380 {
381 log<level::ERR>(e.what());
382 elog<InternalFailure>();
383 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500384 return val;
385}
386
387std::string Config::lDAPBindDN(std::string value)
388{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500389 std::string val;
390 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500391 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500392 if (value == lDAPBindDN())
393 {
394 return value;
395 }
396
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500397 if (value.empty())
398 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500399 log<level::ERR>("Not a valid LDAP BINDDN",
400 entry("LDAPBINDDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500401 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"),
402 Argument::ARGUMENT_VALUE(value.c_str()));
403 }
404
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500405 val = ConfigIface::lDAPBindDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530406 if (enabled())
407 {
408 writeConfig();
409 parent.startOrStopService(nslcdService, enabled());
410 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530411 // save the object.
412 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500413 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500414 catch (const InternalFailure& e)
415 {
416 throw;
417 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600418 catch (const InvalidArgument& e)
419 {
420 throw;
421 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500422 catch (const std::exception& e)
423 {
424 log<level::ERR>(e.what());
425 elog<InternalFailure>();
426 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500427 return val;
428}
429
430std::string Config::lDAPBaseDN(std::string value)
431{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500432 std::string val;
433 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500434 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500435 if (value == lDAPBaseDN())
436 {
437 return value;
438 }
439
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500440 if (value.empty())
441 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500442 log<level::ERR>("Not a valid LDAP BASEDN",
443 entry("BASEDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500444 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"),
445 Argument::ARGUMENT_VALUE(value.c_str()));
446 }
447
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500448 val = ConfigIface::lDAPBaseDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530449 if (enabled())
450 {
451 writeConfig();
452 parent.startOrStopService(nslcdService, enabled());
453 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530454 // save the object.
455 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500456 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500457 catch (const InternalFailure& e)
458 {
459 throw;
460 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600461 catch (const InvalidArgument& e)
462 {
463 throw;
464 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500465 catch (const std::exception& e)
466 {
467 log<level::ERR>(e.what());
468 elog<InternalFailure>();
469 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500470 return val;
471}
472
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600473ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500474{
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600475 ConfigIface::SearchScope val;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500476 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500477 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500478 if (value == lDAPSearchScope())
479 {
480 return value;
481 }
482
483 val = ConfigIface::lDAPSearchScope(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530484 if (enabled())
485 {
486 writeConfig();
487
488 parent.startOrStopService(nslcdService, enabled());
489 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530490 // save the object.
491 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500492 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500493 catch (const InternalFailure& e)
494 {
495 throw;
496 }
497 catch (const std::exception& e)
498 {
499 log<level::ERR>(e.what());
500 elog<InternalFailure>();
501 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500502 return val;
503}
504
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600505ConfigIface::Type Config::lDAPType(ConfigIface::Type value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500506{
Ratan Gupta27d4c012019-04-12 13:03:35 +0530507 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
508 return lDAPType();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500509}
510
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600511bool Config::enabled(bool value)
512{
Ratan Guptac5481d12019-04-12 18:31:05 +0530513 if (value == enabled())
514 {
515 return value;
516 }
517 // Let parent decide that can we enable this config.
518 // It may happen that other config is already enabled,
519 // Current implementation support only one config can
520 // be active at a time.
521 return parent.enableService(*this, value);
522}
523
524bool Config::enableService(bool value)
525{
526 bool isEnable = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600527 try
528 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600529 isEnable = EnableIface::enabled(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530530 if (isEnable)
531 {
532 writeConfig();
533 }
Ratan Guptaec117542019-04-25 18:38:29 +0530534 parent.startOrStopService(nslcdService, value);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530535 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600536 }
537 catch (const InternalFailure& e)
538 {
539 throw;
540 }
541 catch (const std::exception& e)
542 {
543 log<level::ERR>(e.what());
544 elog<InternalFailure>();
545 }
546 return isEnable;
547}
548
549std::string Config::userNameAttribute(std::string value)
550{
551 std::string val;
552 try
553 {
554 if (value == userNameAttribute())
555 {
556 return value;
557 }
558
559 val = ConfigIface::userNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530560 if (enabled())
561 {
562 writeConfig();
563
564 parent.startOrStopService(nslcdService, enabled());
565 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530566 // save the object.
567 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600568 }
569 catch (const InternalFailure& e)
570 {
571 throw;
572 }
573 catch (const std::exception& e)
574 {
575 log<level::ERR>(e.what());
576 elog<InternalFailure>();
577 }
578 return val;
579}
580
581std::string Config::groupNameAttribute(std::string value)
582{
583 std::string val;
584 try
585 {
586 if (value == groupNameAttribute())
587 {
588 return value;
589 }
590
591 val = ConfigIface::groupNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530592 if (enabled())
593 {
594 writeConfig();
595
596 parent.startOrStopService(nslcdService, enabled());
597 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530598 // save the object.
599 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600600 }
601 catch (const InternalFailure& e)
602 {
603 throw;
604 }
605 catch (const std::exception& e)
606 {
607 log<level::ERR>(e.what());
608 elog<InternalFailure>();
609 }
610 return val;
611}
612
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530613template <class Archive>
614void Config::save(Archive& archive, const std::uint32_t version) const
615{
616 archive(this->enabled());
617 archive(lDAPServerURI());
618 archive(lDAPBindDN());
619 archive(lDAPBaseDN());
620 archive(lDAPSearchScope());
621 archive(lDAPBindPassword);
622 archive(userNameAttribute());
623 archive(groupNameAttribute());
624}
625
626template <class Archive>
627void Config::load(Archive& archive, const std::uint32_t version)
628{
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530629 bool bVal;
630 archive(bVal);
631 EnableIface::enabled(bVal);
632
633 std::string str;
634 archive(str);
635 ConfigIface::lDAPServerURI(str);
636
637 archive(str);
638 ConfigIface::lDAPBindDN(str);
639
640 archive(str);
641 ConfigIface::lDAPBaseDN(str);
642
643 ConfigIface::SearchScope scope;
644 archive(scope);
645 ConfigIface::lDAPSearchScope(scope);
646
647 archive(str);
648 lDAPBindPassword = str;
649
650 archive(str);
651 ConfigIface::userNameAttribute(str);
652
653 archive(str);
654 ConfigIface::groupNameAttribute(str);
655}
656
657void Config::serialize()
658{
Ravi Teja59dba442019-05-20 09:31:28 -0500659
660 if (!fs::exists(configPersistPath.c_str()))
661 {
662 std::ofstream os(configPersistPath.string(),
663 std::ios::binary | std::ios::out);
664 auto permission = fs::perms::owner_read | fs::perms::owner_write |
665 fs::perms::group_read;
666 fs::permissions(configPersistPath, permission);
667 cereal::BinaryOutputArchive oarchive(os);
668 oarchive(*this);
669 }
670 else
671 {
672 std::ofstream os(configPersistPath.string(),
673 std::ios::binary | std::ios::out);
674 cereal::BinaryOutputArchive oarchive(os);
675 oarchive(*this);
676 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530677 return;
678}
679
680bool Config::deserialize()
681{
682 try
683 {
684 if (fs::exists(configPersistPath))
685 {
686 std::ifstream is(configPersistPath.c_str(),
687 std::ios::in | std::ios::binary);
688 cereal::BinaryInputArchive iarchive(is);
689 iarchive(*this);
690 return true;
691 }
692 return false;
693 }
694 catch (cereal::Exception& e)
695 {
696 log<level::ERR>(e.what());
697 std::error_code ec;
698 fs::remove(configPersistPath, ec);
699 return false;
700 }
701 catch (const fs::filesystem_error& e)
702 {
703 return false;
704 }
705}
706
Ratan Gupta7b04c352019-04-12 21:46:29 +0530707ObjectPath Config::create(std::string groupName, std::string privilege)
708{
709 checkPrivilegeMapper(groupName);
710 checkPrivilegeLevel(privilege);
711
712 entryId++;
713
714 // Object path for the LDAP group privilege mapper entry
715 fs::path mapperObjectPath = objectPath;
716 mapperObjectPath /= "role_map";
717 mapperObjectPath /= std::to_string(entryId);
718
719 fs::path persistPath = parent.dbusPersistentPath;
720 persistPath += mapperObjectPath;
721
722 // Create mapping for LDAP privilege mapper entry
723 auto entry = std::make_unique<LDAPMapperEntry>(
724 bus, mapperObjectPath.string().c_str(), persistPath.string().c_str(),
725 groupName, privilege, *this);
726
727 phosphor::ldap::serialize(*entry, std::move(persistPath));
728
729 PrivilegeMapperList.emplace(entryId, std::move(entry));
730 return mapperObjectPath.string();
731}
732
733void Config::deletePrivilegeMapper(Id id)
734{
735 fs::path mapperObjectPath = objectPath;
736 mapperObjectPath /= "role_map";
737 mapperObjectPath /= std::to_string(id);
738
739 fs::path persistPath = parent.dbusPersistentPath;
740 persistPath += std::move(mapperObjectPath);
741
742 // Delete the persistent representation of the privilege mapper.
743 fs::remove(std::move(persistPath));
744
745 PrivilegeMapperList.erase(id);
746}
747void Config::checkPrivilegeMapper(const std::string& groupName)
748{
749 if (groupName.empty())
750 {
751 log<level::ERR>("Group name is empty");
752 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Group name"),
753 Argument::ARGUMENT_VALUE("Null"));
754 }
755
756 for (const auto& val : PrivilegeMapperList)
757 {
758 if (val.second.get()->groupName() == groupName)
759 {
760 log<level::ERR>("Group name already exists");
761 elog<PrivilegeMappingExists>();
762 }
763 }
764}
765
766void Config::checkPrivilegeLevel(const std::string& privilege)
767{
768 if (privilege.empty())
769 {
770 log<level::ERR>("Privilege level is empty");
771 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
772 Argument::ARGUMENT_VALUE("Null"));
773 }
774
775 if (std::find(privMgr.begin(), privMgr.end(), privilege) == privMgr.end())
776 {
777 log<level::ERR>("Invalid privilege");
778 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
779 Argument::ARGUMENT_VALUE(privilege.c_str()));
780 }
781}
782
783void Config::restoreRoleMapping()
784{
785 namespace fs = std::filesystem;
786 fs::path dir = parent.dbusPersistentPath;
787 dir += objectPath;
788 dir /= "role_map";
789
790 if (!fs::exists(dir) || fs::is_empty(dir))
791 {
792 return;
793 }
794
795 for (auto& file : fs::directory_iterator(dir))
796 {
797 std::string id = file.path().filename().c_str();
798 size_t idNum = std::stol(id);
799
800 auto entryPath = objectPath + '/' + "role_map" + '/' + id;
801 auto persistPath = parent.dbusPersistentPath + entryPath;
802 auto entry = std::make_unique<LDAPMapperEntry>(
803 bus, entryPath.c_str(), persistPath.c_str(), *this);
804 if (phosphor::ldap::deserialize(file.path(), *entry))
805 {
806 entry->Interfaces::emit_object_added();
807 PrivilegeMapperList.emplace(idNum, std::move(entry));
808 if (idNum > entryId)
809 {
810 entryId = idNum;
811 }
812 }
813 }
814}
815
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500816} // namespace ldap
817} // namespace phosphor