blob: 913dae345274001f1fe9f344ab4c194d23dd7daf [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";
manojkiranedaa47fe4e2019-05-23 21:28:33 +053032constexpr auto authObjPath = "/xyz/openbmc_project/certs/authority/ldap";
Ratan Guptaab4fcb42019-04-29 19:39:51 +053033constexpr auto certIface = "xyz.openbmc_project.Certs.Certificate";
34constexpr auto certProperty = "CertificateString";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050035
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050036using namespace phosphor::logging;
37using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta95a29312019-02-18 20:34:10 +053038namespace fs = std::filesystem;
Ratan Gupta7b04c352019-04-12 21:46:29 +053039
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050040using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta27d4c012019-04-12 13:03:35 +053041using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
42using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Ratan Gupta7b04c352019-04-12 21:46:29 +053043using PrivilegeMappingExists = sdbusplus::xyz::openbmc_project::User::Common::
44 Error::PrivilegeMappingExists;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050045
46using Line = std::string;
47using Key = std::string;
48using Val = std::string;
49using ConfigInfo = std::map<Key, Val>;
50
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050051Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
Ratan Gupta22f13f12019-04-29 15:36:40 +053052 const char* caCertFile, const char* certFile, bool secureLDAP,
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -060053 std::string lDAPServerURI, std::string lDAPBindDN,
54 std::string lDAPBaseDN, std::string&& lDAPBindDNPassword,
Ratan Guptaaeaf9412019-02-11 04:41:52 -060055 ConfigIface::SearchScope lDAPSearchScope,
56 ConfigIface::Type lDAPType, bool lDAPServiceEnabled,
57 std::string userNameAttr, std::string groupNameAttr,
58 ConfigMgr& parent) :
59 Ifaces(bus, path, true),
Ratan Gupta3a1c2742019-03-20 06:49:42 +053060 secureLDAP(secureLDAP), lDAPBindPassword(std::move(lDAPBindDNPassword)),
Ratan Gupta22f13f12019-04-29 15:36:40 +053061 tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
62 objectPath(path), bus(bus), parent(parent),
63 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +053064 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +053065 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +053066 std::placeholders::_1)),
manojkiranedaa47fe4e2019-05-23 21:28:33 +053067
68 cacertificateInstalledSignal(
69 bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
70 std::bind(std::mem_fn(&Config::certificateInstalled), this,
71 std::placeholders::_1)),
72
Ratan Guptaab4fcb42019-04-29 19:39:51 +053073 certificateChangedSignal(
74 bus,
75 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
76 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +053077 std::placeholders::_1))
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050078{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050079 ConfigIface::lDAPServerURI(lDAPServerURI);
80 ConfigIface::lDAPBindDN(lDAPBindDN);
81 ConfigIface::lDAPBaseDN(lDAPBaseDN);
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050082 ConfigIface::lDAPSearchScope(lDAPSearchScope);
83 ConfigIface::lDAPType(lDAPType);
Ratan Guptaaeaf9412019-02-11 04:41:52 -060084 EnableIface::enabled(lDAPServiceEnabled);
85 ConfigIface::userNameAttribute(userNameAttr);
86 ConfigIface::groupNameAttribute(groupNameAttr);
Ratan Gupta21e88cb2019-04-12 17:15:52 +053087 // NOTE: Don't update the bindDN password under ConfigIface
Ratan Guptaec117542019-04-25 18:38:29 +053088 if (enabled())
89 {
90 writeConfig();
91 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +053092 // save the config.
93 configPersistPath = parent.dbusPersistentPath;
94 configPersistPath += objectPath;
95
96 // create the persistent directory
97 fs::create_directories(configPersistPath);
98
99 configPersistPath += "/config";
100
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530101 serialize();
102
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500103 // Emit deferred signal.
104 this->emit_object_added();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600105 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500106}
107
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530108Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530109 const char* caCertFile, const char* certFile,
110 ConfigIface::Type lDAPType, ConfigMgr& parent) :
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530111 Ifaces(bus, path, true),
Ravi Tejad5884042019-06-10 02:35:22 -0500112 secureLDAP(false), tlsCacertFile(caCertFile), tlsCertFile(certFile),
113 configFilePath(filePath), objectPath(path), bus(bus), parent(parent),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530114 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530115 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530116 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530117 std::placeholders::_1)),
manojkiranedaa47fe4e2019-05-23 21:28:33 +0530118 cacertificateInstalledSignal(
119 bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
120 std::bind(std::mem_fn(&Config::certificateInstalled), this,
121 std::placeholders::_1)),
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530122 certificateChangedSignal(
123 bus,
124 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
125 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +0530126 std::placeholders::_1))
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530127{
128 ConfigIface::lDAPType(lDAPType);
129
130 configPersistPath = parent.dbusPersistentPath;
131 configPersistPath += objectPath;
132
133 // create the persistent directory
134 fs::create_directories(configPersistPath);
135
136 configPersistPath += "/config";
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530137}
138
Ratan Gupta22f13f12019-04-29 15:36:40 +0530139void Config::certificateInstalled(sdbusplus::message::message& msg)
140{
141 try
142 {
143 if (enabled())
144 {
145 writeConfig();
146 }
147 parent.startOrStopService(nslcdService, enabled());
148 }
149 catch (const InternalFailure& e)
150 {
151 throw;
152 }
153 catch (const std::exception& e)
154 {
155 log<level::ERR>(e.what());
156 elog<InternalFailure>();
157 }
158}
159
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530160void Config::certificateChanged(sdbusplus::message::message& msg)
161{
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530162 std::string objectName;
163 std::map<std::string, sdbusplus::message::variant<std::string>> msgData;
164 msg.read(objectName, msgData);
165 auto valPropMap = msgData.find(certProperty);
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530166 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530167 if (valPropMap != msgData.end())
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530168 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530169 try
170 {
171 if (enabled())
172 {
173
174 writeConfig();
175 }
176 parent.startOrStopService(nslcdService, enabled());
177 }
178 catch (const InternalFailure& e)
179 {
180 throw;
181 }
182 catch (const std::exception& e)
183 {
184 log<level::ERR>(e.what());
185 elog<InternalFailure>();
186 }
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530187 }
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530188 }
189}
190
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500191void Config::writeConfig()
192{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500193 std::stringstream confData;
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530194 auto isPwdTobeWritten = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600195 std::string userNameAttr;
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530196
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500197 confData << "uid root\n";
198 confData << "gid root\n\n";
199 confData << "ldap_version 3\n\n";
200 confData << "timelimit 30\n";
201 confData << "bind_timelimit 30\n";
202 confData << "pagesize 1000\n";
203 confData << "referrals off\n\n";
204 confData << "uri " << lDAPServerURI() << "\n\n";
205 confData << "base " << lDAPBaseDN() << "\n\n";
206 confData << "binddn " << lDAPBindDN() << "\n";
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530207 if (!lDAPBindPassword.empty())
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500208 {
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530209 confData << "bindpw " << lDAPBindPassword << "\n";
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530210 isPwdTobeWritten = true;
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500211 }
212 confData << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500213 switch (lDAPSearchScope())
214 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600215 case ConfigIface::SearchScope::sub:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500216 confData << "scope sub\n\n";
217 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600218 case ConfigIface::SearchScope::one:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500219 confData << "scope one\n\n";
220 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600221 case ConfigIface::SearchScope::base:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500222 confData << "scope base\n\n";
223 break;
224 }
225 confData << "base passwd " << lDAPBaseDN() << "\n";
226 confData << "base shadow " << lDAPBaseDN() << "\n\n";
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600227 if (secureLDAP == true)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500228 {
229 confData << "ssl on\n";
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600230 confData << "tls_reqcert hard\n";
Zbigniew Kurzynski5d00cf22019-10-03 12:10:20 +0200231 if (fs::is_directory(tlsCacertFile.c_str()))
232 {
233 confData << "tls_cacertdir " << tlsCacertFile.c_str() << "\n";
234 }
235 else
236 {
237 confData << "tls_cacertfile " << tlsCacertFile.c_str() << "\n";
238 }
Ratan Gupta22f13f12019-04-29 15:36:40 +0530239 if (fs::exists(tlsCertFile.c_str()))
240 {
241 confData << "tls_cert " << tlsCertFile.c_str() << "\n";
242 confData << "tls_key " << tlsCertFile.c_str() << "\n";
243 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500244 }
245 else
246 {
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500247 confData << "ssl off\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500248 }
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500249 confData << "\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600250 if (lDAPType() == ConfigIface::Type::ActiveDirectory)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500251 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600252 if (ConfigIface::userNameAttribute().empty())
253 {
254 ConfigIface::userNameAttribute("sAMAccountName");
255 }
256 if (ConfigIface::groupNameAttribute().empty())
257 {
258 ConfigIface::groupNameAttribute("primaryGroupID");
259 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500260 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
261 "(!(objectClass=computer)))\n";
262 confData
263 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
264 "(objectclass=groupofuniquenames))\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600265 confData << "map passwd uid "
266 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500267 confData << "map passwd uidNumber "
268 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600269 confData << "map passwd gidNumber "
270 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500271 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
272 confData << "map passwd gecos displayName\n";
273 confData << "map passwd loginShell \"/bin/bash\"\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500274 confData << "map group gidNumber "
275 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600276 confData << "map group cn "
277 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500278 }
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600279 else if (lDAPType() == ConfigIface::Type::OpenLdap)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500280 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600281 if (ConfigIface::userNameAttribute().empty())
282 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500283 ConfigIface::userNameAttribute("cn");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600284 }
285 if (ConfigIface::groupNameAttribute().empty())
286 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500287 ConfigIface::groupNameAttribute("gidNumber");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600288 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500289 confData << "filter passwd (objectclass=*)\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500290 confData << "map passwd gecos displayName\n";
Nagaraju Goruganti808eda42018-10-10 08:48:12 -0500291 confData << "filter group (objectclass=posixGroup)\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600292 confData << "map passwd uid "
293 << ConfigIface::userNameAttribute() << "\n";
294 confData << "map passwd gidNumber "
295 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500296 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500297 try
298 {
299 std::fstream stream(configFilePath.c_str(), std::fstream::out);
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530300 // remove the read permission from others if password is being written.
301 // nslcd forces this behaviour.
302 auto permission = fs::perms::owner_read | fs::perms::owner_write |
303 fs::perms::group_read;
304 if (isPwdTobeWritten)
305 {
306 fs::permissions(configFilePath, permission);
307 }
308 else
309 {
310 fs::permissions(configFilePath,
311 permission | fs::perms::others_read);
312 }
313
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500314 stream << confData.str();
315 stream.flush();
316 stream.close();
317 }
318 catch (const std::exception& e)
319 {
320 log<level::ERR>(e.what());
321 elog<InternalFailure>();
322 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500323 return;
324}
325
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530326std::string Config::lDAPBindDNPassword(std::string value)
327{
328 // Don't update the D-bus object, this is just to
329 // facilitate if user wants to change the bind dn password
330 // once d-bus object gets created.
331 lDAPBindPassword = value;
332 try
333 {
Ratan Guptaec117542019-04-25 18:38:29 +0530334 if (enabled())
335 {
336 writeConfig();
337 parent.startOrStopService(nslcdService, enabled());
338 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530339 serialize();
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530340 }
341 catch (const InternalFailure& e)
342 {
343 throw;
344 }
345 catch (const std::exception& e)
346 {
347 log<level::ERR>(e.what());
348 elog<InternalFailure>();
349 }
350 return value;
351}
352
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500353std::string Config::lDAPServerURI(std::string value)
354{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500355 std::string val;
356 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500357 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500358 if (value == lDAPServerURI())
359 {
360 return value;
361 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500362 if (isValidLDAPURI(value, LDAPSscheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500363 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500364 secureLDAP = true;
365 }
366 else if (isValidLDAPURI(value, LDAPscheme))
367 {
368 secureLDAP = false;
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600369 }
370 else
371 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500372 log<level::ERR>("bad LDAP Server URI",
373 entry("LDAPSERVERURI=%s", value.c_str()));
374 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"),
375 Argument::ARGUMENT_VALUE(value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500376 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600377
378 if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
379 {
380 log<level::ERR>("LDAP server's CA certificate not provided",
381 entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
382 elog<NoCACertificate>();
383 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500384 val = ConfigIface::lDAPServerURI(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530385 if (enabled())
386 {
387 writeConfig();
388 parent.startOrStopService(nslcdService, enabled());
389 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530390 // save the object.
391 serialize();
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500392 }
393 catch (const InternalFailure& e)
394 {
395 throw;
396 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500397 catch (const InvalidArgument& e)
398 {
399 throw;
400 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600401 catch (const NoCACertificate& e)
402 {
403 throw;
404 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500405 catch (const std::exception& e)
406 {
407 log<level::ERR>(e.what());
408 elog<InternalFailure>();
409 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500410 return val;
411}
412
413std::string Config::lDAPBindDN(std::string value)
414{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500415 std::string val;
416 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500417 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500418 if (value == lDAPBindDN())
419 {
420 return value;
421 }
422
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500423 if (value.empty())
424 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500425 log<level::ERR>("Not a valid LDAP BINDDN",
426 entry("LDAPBINDDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500427 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"),
428 Argument::ARGUMENT_VALUE(value.c_str()));
429 }
430
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500431 val = ConfigIface::lDAPBindDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530432 if (enabled())
433 {
434 writeConfig();
435 parent.startOrStopService(nslcdService, enabled());
436 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530437 // save the object.
438 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500439 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500440 catch (const InternalFailure& e)
441 {
442 throw;
443 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600444 catch (const InvalidArgument& e)
445 {
446 throw;
447 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500448 catch (const std::exception& e)
449 {
450 log<level::ERR>(e.what());
451 elog<InternalFailure>();
452 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500453 return val;
454}
455
456std::string Config::lDAPBaseDN(std::string value)
457{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500458 std::string val;
459 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500460 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500461 if (value == lDAPBaseDN())
462 {
463 return value;
464 }
465
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500466 if (value.empty())
467 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500468 log<level::ERR>("Not a valid LDAP BASEDN",
469 entry("BASEDN=%s", value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500470 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"),
471 Argument::ARGUMENT_VALUE(value.c_str()));
472 }
473
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500474 val = ConfigIface::lDAPBaseDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530475 if (enabled())
476 {
477 writeConfig();
478 parent.startOrStopService(nslcdService, enabled());
479 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530480 // save the object.
481 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500482 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500483 catch (const InternalFailure& e)
484 {
485 throw;
486 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600487 catch (const InvalidArgument& e)
488 {
489 throw;
490 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500491 catch (const std::exception& e)
492 {
493 log<level::ERR>(e.what());
494 elog<InternalFailure>();
495 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500496 return val;
497}
498
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600499ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500500{
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600501 ConfigIface::SearchScope val;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500502 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500503 {
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500504 if (value == lDAPSearchScope())
505 {
506 return value;
507 }
508
509 val = ConfigIface::lDAPSearchScope(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530510 if (enabled())
511 {
512 writeConfig();
513
514 parent.startOrStopService(nslcdService, enabled());
515 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530516 // save the object.
517 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500518 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500519 catch (const InternalFailure& e)
520 {
521 throw;
522 }
523 catch (const std::exception& e)
524 {
525 log<level::ERR>(e.what());
526 elog<InternalFailure>();
527 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500528 return val;
529}
530
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600531ConfigIface::Type Config::lDAPType(ConfigIface::Type value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500532{
Ratan Gupta27d4c012019-04-12 13:03:35 +0530533 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
534 return lDAPType();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500535}
536
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600537bool Config::enabled(bool value)
538{
Ratan Guptac5481d12019-04-12 18:31:05 +0530539 if (value == enabled())
540 {
541 return value;
542 }
543 // Let parent decide that can we enable this config.
544 // It may happen that other config is already enabled,
545 // Current implementation support only one config can
546 // be active at a time.
547 return parent.enableService(*this, value);
548}
549
550bool Config::enableService(bool value)
551{
552 bool isEnable = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600553 try
554 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600555 isEnable = EnableIface::enabled(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530556 if (isEnable)
557 {
558 writeConfig();
559 }
Ratan Guptaec117542019-04-25 18:38:29 +0530560 parent.startOrStopService(nslcdService, value);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530561 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600562 }
563 catch (const InternalFailure& e)
564 {
565 throw;
566 }
567 catch (const std::exception& e)
568 {
569 log<level::ERR>(e.what());
570 elog<InternalFailure>();
571 }
572 return isEnable;
573}
574
575std::string Config::userNameAttribute(std::string value)
576{
577 std::string val;
578 try
579 {
580 if (value == userNameAttribute())
581 {
582 return value;
583 }
584
585 val = ConfigIface::userNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530586 if (enabled())
587 {
588 writeConfig();
589
590 parent.startOrStopService(nslcdService, enabled());
591 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530592 // save the object.
593 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600594 }
595 catch (const InternalFailure& e)
596 {
597 throw;
598 }
599 catch (const std::exception& e)
600 {
601 log<level::ERR>(e.what());
602 elog<InternalFailure>();
603 }
604 return val;
605}
606
607std::string Config::groupNameAttribute(std::string value)
608{
609 std::string val;
610 try
611 {
612 if (value == groupNameAttribute())
613 {
614 return value;
615 }
616
617 val = ConfigIface::groupNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530618 if (enabled())
619 {
620 writeConfig();
621
622 parent.startOrStopService(nslcdService, enabled());
623 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530624 // save the object.
625 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600626 }
627 catch (const InternalFailure& e)
628 {
629 throw;
630 }
631 catch (const std::exception& e)
632 {
633 log<level::ERR>(e.what());
634 elog<InternalFailure>();
635 }
636 return val;
637}
638
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530639template <class Archive>
640void Config::save(Archive& archive, const std::uint32_t version) const
641{
642 archive(this->enabled());
643 archive(lDAPServerURI());
644 archive(lDAPBindDN());
645 archive(lDAPBaseDN());
646 archive(lDAPSearchScope());
647 archive(lDAPBindPassword);
648 archive(userNameAttribute());
649 archive(groupNameAttribute());
650}
651
652template <class Archive>
653void Config::load(Archive& archive, const std::uint32_t version)
654{
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530655 bool bVal;
656 archive(bVal);
657 EnableIface::enabled(bVal);
658
659 std::string str;
660 archive(str);
661 ConfigIface::lDAPServerURI(str);
662
663 archive(str);
664 ConfigIface::lDAPBindDN(str);
665
666 archive(str);
667 ConfigIface::lDAPBaseDN(str);
668
669 ConfigIface::SearchScope scope;
670 archive(scope);
671 ConfigIface::lDAPSearchScope(scope);
672
673 archive(str);
674 lDAPBindPassword = str;
675
676 archive(str);
677 ConfigIface::userNameAttribute(str);
678
679 archive(str);
680 ConfigIface::groupNameAttribute(str);
681}
682
683void Config::serialize()
684{
Ravi Teja59dba442019-05-20 09:31:28 -0500685
686 if (!fs::exists(configPersistPath.c_str()))
687 {
688 std::ofstream os(configPersistPath.string(),
689 std::ios::binary | std::ios::out);
690 auto permission = fs::perms::owner_read | fs::perms::owner_write |
691 fs::perms::group_read;
692 fs::permissions(configPersistPath, permission);
693 cereal::BinaryOutputArchive oarchive(os);
694 oarchive(*this);
695 }
696 else
697 {
698 std::ofstream os(configPersistPath.string(),
699 std::ios::binary | std::ios::out);
700 cereal::BinaryOutputArchive oarchive(os);
701 oarchive(*this);
702 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530703 return;
704}
705
706bool Config::deserialize()
707{
708 try
709 {
710 if (fs::exists(configPersistPath))
711 {
712 std::ifstream is(configPersistPath.c_str(),
713 std::ios::in | std::ios::binary);
714 cereal::BinaryInputArchive iarchive(is);
715 iarchive(*this);
Ravi Tejad5884042019-06-10 02:35:22 -0500716
717 if (isValidLDAPURI(lDAPServerURI(), LDAPscheme))
718 {
719 secureLDAP = false;
720 }
721 else if (isValidLDAPURI(lDAPServerURI(), LDAPSscheme))
722 {
723 secureLDAP = true;
724 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530725 return true;
726 }
727 return false;
728 }
729 catch (cereal::Exception& e)
730 {
731 log<level::ERR>(e.what());
732 std::error_code ec;
733 fs::remove(configPersistPath, ec);
734 return false;
735 }
736 catch (const fs::filesystem_error& e)
737 {
738 return false;
739 }
740}
741
Ratan Gupta7b04c352019-04-12 21:46:29 +0530742ObjectPath Config::create(std::string groupName, std::string privilege)
743{
744 checkPrivilegeMapper(groupName);
745 checkPrivilegeLevel(privilege);
746
747 entryId++;
748
749 // Object path for the LDAP group privilege mapper entry
750 fs::path mapperObjectPath = objectPath;
751 mapperObjectPath /= "role_map";
752 mapperObjectPath /= std::to_string(entryId);
753
754 fs::path persistPath = parent.dbusPersistentPath;
755 persistPath += mapperObjectPath;
756
757 // Create mapping for LDAP privilege mapper entry
758 auto entry = std::make_unique<LDAPMapperEntry>(
759 bus, mapperObjectPath.string().c_str(), persistPath.string().c_str(),
760 groupName, privilege, *this);
761
762 phosphor::ldap::serialize(*entry, std::move(persistPath));
763
764 PrivilegeMapperList.emplace(entryId, std::move(entry));
765 return mapperObjectPath.string();
766}
767
768void Config::deletePrivilegeMapper(Id id)
769{
770 fs::path mapperObjectPath = objectPath;
771 mapperObjectPath /= "role_map";
772 mapperObjectPath /= std::to_string(id);
773
774 fs::path persistPath = parent.dbusPersistentPath;
775 persistPath += std::move(mapperObjectPath);
776
777 // Delete the persistent representation of the privilege mapper.
778 fs::remove(std::move(persistPath));
779
780 PrivilegeMapperList.erase(id);
781}
782void Config::checkPrivilegeMapper(const std::string& groupName)
783{
784 if (groupName.empty())
785 {
786 log<level::ERR>("Group name is empty");
787 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Group name"),
788 Argument::ARGUMENT_VALUE("Null"));
789 }
790
791 for (const auto& val : PrivilegeMapperList)
792 {
793 if (val.second.get()->groupName() == groupName)
794 {
795 log<level::ERR>("Group name already exists");
796 elog<PrivilegeMappingExists>();
797 }
798 }
799}
800
801void Config::checkPrivilegeLevel(const std::string& privilege)
802{
803 if (privilege.empty())
804 {
805 log<level::ERR>("Privilege level is empty");
806 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
807 Argument::ARGUMENT_VALUE("Null"));
808 }
809
810 if (std::find(privMgr.begin(), privMgr.end(), privilege) == privMgr.end())
811 {
812 log<level::ERR>("Invalid privilege");
813 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
814 Argument::ARGUMENT_VALUE(privilege.c_str()));
815 }
816}
817
818void Config::restoreRoleMapping()
819{
820 namespace fs = std::filesystem;
821 fs::path dir = parent.dbusPersistentPath;
822 dir += objectPath;
823 dir /= "role_map";
824
825 if (!fs::exists(dir) || fs::is_empty(dir))
826 {
827 return;
828 }
829
830 for (auto& file : fs::directory_iterator(dir))
831 {
832 std::string id = file.path().filename().c_str();
833 size_t idNum = std::stol(id);
834
835 auto entryPath = objectPath + '/' + "role_map" + '/' + id;
836 auto persistPath = parent.dbusPersistentPath + entryPath;
837 auto entry = std::make_unique<LDAPMapperEntry>(
838 bus, entryPath.c_str(), persistPath.c_str(), *this);
839 if (phosphor::ldap::deserialize(file.path(), *entry))
840 {
841 entry->Interfaces::emit_object_added();
842 PrivilegeMapperList.emplace(idNum, std::move(entry));
843 if (idNum > entryId)
844 {
845 entryId = idNum;
846 }
847 }
848 }
849}
850
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500851} // namespace ldap
852} // namespace phosphor