1 #include "ldap_config.hpp"
2 
3 #include "ldap_config_mgr.hpp"
4 #include "ldap_mapper_serialize.hpp"
5 #include "utils.hpp"
6 
7 #include <cereal/archives/binary.hpp>
8 #include <cereal/types/string.hpp>
9 #include <cereal/types/vector.hpp>
10 #include <phosphor-logging/elog-errors.hpp>
11 #include <phosphor-logging/elog.hpp>
12 #include <phosphor-logging/lg2.hpp>
13 #include <xyz/openbmc_project/Common/error.hpp>
14 #include <xyz/openbmc_project/User/Common/error.hpp>
15 
16 #include <filesystem>
17 #include <fstream>
18 #include <sstream>
19 
20 // Register class version
21 // From cereal documentation;
22 // "This macro should be placed at global scope"
23 CEREAL_CLASS_VERSION(phosphor::ldap::Config, CLASS_VERSION);
24 
25 namespace phosphor
26 {
27 namespace ldap
28 {
29 
30 constexpr auto nslcdService = "nslcd.service";
31 constexpr auto ldapScheme = "ldap";
32 constexpr auto ldapsScheme = "ldaps";
33 constexpr auto certObjPath = "/xyz/openbmc_project/certs/client/ldap/1";
34 constexpr auto certRootPath = "/xyz/openbmc_project/certs/client/ldap";
35 constexpr auto authObjPath = "/xyz/openbmc_project/certs/authority/truststore";
36 constexpr auto certIface = "xyz.openbmc_project.Certs.Certificate";
37 constexpr auto certProperty = "CertificateString";
38 
39 using namespace phosphor::logging;
40 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
41 namespace fs = std::filesystem;
42 
43 using Argument = xyz::openbmc_project::Common::InvalidArgument;
44 using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
45 using PrivilegeMappingExists = sdbusplus::xyz::openbmc_project::User::Common::
46     Error::PrivilegeMappingExists;
47 
48 using Line = std::string;
49 using Key = std::string;
50 using Val = std::string;
51 using ConfigInfo = std::map<Key, Val>;
52 
Config(sdbusplus::bus_t & bus,const char * path,const char * filePath,const char * caCertFile,const char * certFile,bool secureLDAP,std::string ldapServerURI,std::string ldapBindDN,std::string ldapBaseDN,std::string && ldapBindDNPassword,ConfigIface::SearchScope ldapSearchScope,ConfigIface::Type ldapType,bool ldapServiceEnabled,std::string userNameAttr,std::string groupNameAttr,ConfigMgr & parent)53 Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
54                const char* caCertFile, const char* certFile, bool secureLDAP,
55                std::string ldapServerURI, std::string ldapBindDN,
56                std::string ldapBaseDN, std::string&& ldapBindDNPassword,
57                ConfigIface::SearchScope ldapSearchScope,
58                ConfigIface::Type ldapType, bool ldapServiceEnabled,
59                std::string userNameAttr, std::string groupNameAttr,
60                ConfigMgr& parent) :
61     Ifaces(bus, path, Ifaces::action::defer_emit),
62     secureLDAP(secureLDAP), ldapBindPassword(std::move(ldapBindDNPassword)),
63     tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
64     objectPath(path), bus(bus), parent(parent),
65     certificateInstalledSignal(
66         bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
67         std::bind(std::mem_fn(&Config::certificateInstalled), this,
68                   std::placeholders::_1)),
69 
70     cacertificateInstalledSignal(
71         bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
72         std::bind(std::mem_fn(&Config::certificateInstalled), this,
73                   std::placeholders::_1)),
74 
75     certificateChangedSignal(
76         bus,
77         sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
78         std::bind(std::mem_fn(&Config::certificateChanged), this,
79                   std::placeholders::_1))
80 {
81     ConfigIface::ldapServerURI(ldapServerURI);
82     ConfigIface::ldapBindDN(ldapBindDN);
83     ConfigIface::ldapBaseDN(ldapBaseDN);
84     ConfigIface::ldapSearchScope(ldapSearchScope);
85     ConfigIface::ldapType(ldapType);
86     EnableIface::enabled(ldapServiceEnabled);
87     ConfigIface::userNameAttribute(userNameAttr);
88     ConfigIface::groupNameAttribute(groupNameAttr);
89     // NOTE: Don't update the bindDN password under ConfigIface
90     if (enabled())
91     {
92         writeConfig();
93     }
94     // save the config.
95     configPersistPath = parent.dbusPersistentPath;
96     configPersistPath += objectPath;
97 
98     // create the persistent directory
99     fs::create_directories(configPersistPath);
100 
101     configPersistPath += "/config";
102 
103     serialize();
104 
105     // Emit deferred signal.
106     this->emit_object_added();
107     parent.startOrStopService(nslcdService, enabled());
108 }
109 
Config(sdbusplus::bus_t & bus,const char * path,const char * filePath,const char * caCertFile,const char * certFile,ConfigIface::Type ldapType,ConfigMgr & parent)110 Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
111                const char* caCertFile, const char* certFile,
112                ConfigIface::Type ldapType, ConfigMgr& parent) :
113     Ifaces(bus, path, Ifaces::action::defer_emit),
114     secureLDAP(false), tlsCacertFile(caCertFile), tlsCertFile(certFile),
115     configFilePath(filePath), objectPath(path), bus(bus), parent(parent),
116     certificateInstalledSignal(
117         bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
118         std::bind(std::mem_fn(&Config::certificateInstalled), this,
119                   std::placeholders::_1)),
120     cacertificateInstalledSignal(
121         bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
122         std::bind(std::mem_fn(&Config::certificateInstalled), this,
123                   std::placeholders::_1)),
124     certificateChangedSignal(
125         bus,
126         sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
127         std::bind(std::mem_fn(&Config::certificateChanged), this,
128                   std::placeholders::_1))
129 {
130     ConfigIface::ldapType(ldapType);
131 
132     configPersistPath = parent.dbusPersistentPath;
133     configPersistPath += objectPath;
134 
135     // create the persistent directory
136     fs::create_directories(configPersistPath);
137 
138     configPersistPath += "/config";
139 }
140 
certificateInstalled(sdbusplus::message_t &)141 void Config::certificateInstalled(sdbusplus::message_t& /*msg*/)
142 {
143     try
144     {
145         if (enabled())
146         {
147             writeConfig();
148         }
149         parent.startOrStopService(nslcdService, enabled());
150     }
151     catch (const InternalFailure& e)
152     {
153         throw;
154     }
155     catch (const std::exception& e)
156     {
157         lg2::error("Exception: {ERR}", "ERR", e);
158         elog<InternalFailure>();
159     }
160 }
161 
certificateChanged(sdbusplus::message_t & msg)162 void Config::certificateChanged(sdbusplus::message_t& msg)
163 {
164     std::string objectName;
165     std::map<std::string, std::variant<std::string>> msgData;
166     msg.read(objectName, msgData);
167     auto valPropMap = msgData.find(certProperty);
168     {
169         if (valPropMap != msgData.end())
170         {
171             try
172             {
173                 if (enabled())
174                 {
175                     writeConfig();
176                 }
177                 parent.startOrStopService(nslcdService, enabled());
178             }
179             catch (const InternalFailure& e)
180             {
181                 throw;
182             }
183             catch (const std::exception& e)
184             {
185                 lg2::error("Exception: {ERR}", "ERR", e);
186                 elog<InternalFailure>();
187             }
188         }
189     }
190 }
191 
writeConfig()192 void Config::writeConfig()
193 {
194     std::stringstream confData;
195     auto isPwdTobeWritten = false;
196     std::string userNameAttr;
197 
198     confData << "uid root\n";
199     confData << "gid root\n\n";
200     confData << "ldap_version 3\n\n";
201     confData << "timelimit 30\n";
202     confData << "bind_timelimit 30\n";
203     confData << "pagesize 1000\n";
204     confData << "referrals off\n\n";
205     confData << "uri " << ldapServerURI() << "\n\n";
206     confData << "base " << ldapBaseDN() << "\n\n";
207     confData << "binddn " << ldapBindDN() << "\n";
208     if (!ldapBindPassword.empty())
209     {
210         confData << "bindpw " << ldapBindPassword << "\n";
211         isPwdTobeWritten = true;
212     }
213     confData << "\n";
214     switch (ldapSearchScope())
215     {
216         case ConfigIface::SearchScope::sub:
217             confData << "scope sub\n\n";
218             break;
219         case ConfigIface::SearchScope::one:
220             confData << "scope one\n\n";
221             break;
222         case ConfigIface::SearchScope::base:
223             confData << "scope base\n\n";
224             break;
225     }
226     confData << "base passwd " << ldapBaseDN() << "\n";
227     confData << "base shadow " << ldapBaseDN() << "\n\n";
228     if (secureLDAP == true)
229     {
230         confData << "ssl on\n";
231         confData << "tls_reqcert hard\n";
232         if (fs::is_directory(tlsCacertFile.c_str()))
233         {
234             confData << "tls_cacertdir " << tlsCacertFile.c_str() << "\n";
235         }
236         else
237         {
238             confData << "tls_cacertfile " << tlsCacertFile.c_str() << "\n";
239         }
240         if (fs::exists(tlsCertFile.c_str()))
241         {
242             confData << "tls_cert " << tlsCertFile.c_str() << "\n";
243             confData << "tls_key " << tlsCertFile.c_str() << "\n";
244         }
245     }
246     else
247     {
248         confData << "ssl off\n";
249     }
250     confData << "\n";
251     if (ldapType() == ConfigIface::Type::ActiveDirectory)
252     {
253         if (ConfigIface::userNameAttribute().empty())
254         {
255             ConfigIface::userNameAttribute("sAMAccountName");
256         }
257         if (ConfigIface::groupNameAttribute().empty())
258         {
259             ConfigIface::groupNameAttribute("primaryGroupID");
260         }
261         confData << "filter passwd (&(objectClass=user)(objectClass=person)"
262                     "(!(objectClass=computer)))\n";
263         confData
264             << "filter group (|(objectclass=group)(objectclass=groupofnames) "
265                "(objectclass=groupofuniquenames))\n";
266         confData << "map passwd uid              "
267                  << ConfigIface::userNameAttribute() << "\n";
268         confData << "map passwd uidNumber        "
269                     "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
270         confData << "map passwd gidNumber        "
271                  << ConfigIface::groupNameAttribute() << "\n";
272         confData << "map passwd homeDirectory    \"/home/$sAMAccountName\"\n";
273         confData << "map passwd gecos            displayName\n";
274         confData << "map passwd loginShell       \"/bin/sh\"\n";
275         confData << "map group gidNumber         "
276                     "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
277         confData << "map group cn                "
278                  << ConfigIface::userNameAttribute() << "\n";
279         confData << "nss_initgroups_ignoreusers ALLLOCAL\n";
280     }
281     else if (ldapType() == ConfigIface::Type::OpenLdap)
282     {
283         if (ConfigIface::userNameAttribute().empty())
284         {
285             ConfigIface::userNameAttribute("cn");
286         }
287         if (ConfigIface::groupNameAttribute().empty())
288         {
289             ConfigIface::groupNameAttribute("gidNumber");
290         }
291         confData << "filter passwd (objectclass=*)\n";
292         confData << "map passwd gecos displayName\n";
293         confData << "filter group (objectclass=posixGroup)\n";
294         confData << "map passwd uid              "
295                  << ConfigIface::userNameAttribute() << "\n";
296         confData << "map passwd gidNumber        "
297                  << ConfigIface::groupNameAttribute() << "\n";
298         confData << "map passwd loginShell       \"/bin/sh\"\n";
299         confData << "nss_initgroups_ignoreusers ALLLOCAL\n";
300     }
301     try
302     {
303         std::fstream stream(configFilePath.c_str(), std::fstream::out);
304         // remove the read permission from others if password is being written.
305         // nslcd forces this behaviour.
306         auto permission = fs::perms::owner_read | fs::perms::owner_write |
307                           fs::perms::group_read;
308         if (isPwdTobeWritten)
309         {
310             fs::permissions(configFilePath, permission);
311         }
312         else
313         {
314             fs::permissions(configFilePath,
315                             permission | fs::perms::others_read);
316         }
317 
318         stream << confData.str();
319         stream.flush();
320         stream.close();
321     }
322     catch (const std::exception& e)
323     {
324         lg2::error("Exception: {ERR}", "ERR", e);
325         elog<InternalFailure>();
326     }
327     return;
328 }
329 
ldapBindDNPassword(std::string value)330 std::string Config::ldapBindDNPassword(std::string value)
331 {
332     // Don't update the D-bus object, this is just to
333     // facilitate if user wants to change the bind dn password
334     // once d-bus object gets created.
335     ldapBindPassword = value;
336     try
337     {
338         if (enabled())
339         {
340             writeConfig();
341             parent.startOrStopService(nslcdService, enabled());
342         }
343         serialize();
344     }
345     catch (const InternalFailure& e)
346     {
347         throw;
348     }
349     catch (const std::exception& e)
350     {
351         lg2::error("Exception: {ERR}", "ERR", e);
352         elog<InternalFailure>();
353     }
354     return value;
355 }
356 
ldapServerURI(std::string value)357 std::string Config::ldapServerURI(std::string value)
358 {
359     std::string val;
360     try
361     {
362         if (value == ldapServerURI())
363         {
364             return value;
365         }
366         if (isValidLDAPURI(value, ldapsScheme))
367         {
368             secureLDAP = true;
369         }
370         else if (isValidLDAPURI(value, ldapScheme))
371         {
372             secureLDAP = false;
373         }
374         else
375         {
376             lg2::error("Bad LDAP Server URI {URI}", "URI", value);
377             elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
378                                   Argument::ARGUMENT_VALUE(value.c_str()));
379         }
380 
381         if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
382         {
383             lg2::error("LDAP server CA certificate not found at {PATH}", "PATH",
384                        tlsCacertFile);
385             elog<NoCACertificate>();
386         }
387         val = ConfigIface::ldapServerURI(value);
388         if (enabled())
389         {
390             writeConfig();
391             parent.startOrStopService(nslcdService, enabled());
392         }
393         // save the object.
394         serialize();
395     }
396     catch (const InternalFailure& e)
397     {
398         throw;
399     }
400     catch (const InvalidArgument& e)
401     {
402         throw;
403     }
404     catch (const NoCACertificate& e)
405     {
406         throw;
407     }
408     catch (const std::exception& e)
409     {
410         lg2::error("Exception: {ERR}", "ERR", e);
411         elog<InternalFailure>();
412     }
413     return val;
414 }
415 
ldapBindDN(std::string value)416 std::string Config::ldapBindDN(std::string value)
417 {
418     std::string val;
419     try
420     {
421         if (value == ldapBindDN())
422         {
423             return value;
424         }
425 
426         if (value.empty())
427         {
428             lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN",
429                        value);
430             elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapBindDN"),
431                                   Argument::ARGUMENT_VALUE(value.c_str()));
432         }
433 
434         val = ConfigIface::ldapBindDN(value);
435         if (enabled())
436         {
437             writeConfig();
438             parent.startOrStopService(nslcdService, enabled());
439         }
440         // save the object.
441         serialize();
442     }
443     catch (const InternalFailure& e)
444     {
445         throw;
446     }
447     catch (const InvalidArgument& e)
448     {
449         throw;
450     }
451     catch (const std::exception& e)
452     {
453         lg2::error("Exception: {ERR}", "ERR", e);
454         elog<InternalFailure>();
455     }
456     return val;
457 }
458 
ldapBaseDN(std::string value)459 std::string Config::ldapBaseDN(std::string value)
460 {
461     std::string val;
462     try
463     {
464         if (value == ldapBaseDN())
465         {
466             return value;
467         }
468 
469         if (value.empty())
470         {
471             lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN",
472                        value);
473             elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapBaseDN"),
474                                   Argument::ARGUMENT_VALUE(value.c_str()));
475         }
476 
477         val = ConfigIface::ldapBaseDN(value);
478         if (enabled())
479         {
480             writeConfig();
481             parent.startOrStopService(nslcdService, enabled());
482         }
483         // save the object.
484         serialize();
485     }
486     catch (const InternalFailure& e)
487     {
488         throw;
489     }
490     catch (const InvalidArgument& e)
491     {
492         throw;
493     }
494     catch (const std::exception& e)
495     {
496         lg2::error("Exception: {ERR}", "ERR", e);
497         elog<InternalFailure>();
498     }
499     return val;
500 }
501 
ldapSearchScope(ConfigIface::SearchScope value)502 ConfigIface::SearchScope Config::ldapSearchScope(ConfigIface::SearchScope value)
503 {
504     ConfigIface::SearchScope val;
505     try
506     {
507         if (value == ldapSearchScope())
508         {
509             return value;
510         }
511 
512         val = ConfigIface::ldapSearchScope(value);
513         if (enabled())
514         {
515             writeConfig();
516 
517             parent.startOrStopService(nslcdService, enabled());
518         }
519         // save the object.
520         serialize();
521     }
522     catch (const InternalFailure& e)
523     {
524         throw;
525     }
526     catch (const std::exception& e)
527     {
528         lg2::error("Exception: {ERR}", "ERR", e);
529         elog<InternalFailure>();
530     }
531     return val;
532 }
533 
ldapType(ConfigIface::Type)534 ConfigIface::Type Config::ldapType(ConfigIface::Type /*value*/)
535 {
536     elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
537     return ldapType();
538 }
539 
enabled(bool value)540 bool Config::enabled(bool value)
541 {
542     if (value == enabled())
543     {
544         return value;
545     }
546     // Let parent decide that can we enable this config.
547     // It may happen that other config is already enabled,
548     // Current implementation support only one config can
549     // be active at a time.
550     return parent.enableService(*this, value);
551 }
552 
enableService(bool value)553 bool Config::enableService(bool value)
554 {
555     bool isEnable = false;
556     try
557     {
558         isEnable = EnableIface::enabled(value);
559         if (isEnable)
560         {
561             writeConfig();
562         }
563         parent.startOrStopService(nslcdService, value);
564         serialize();
565     }
566     catch (const InternalFailure& e)
567     {
568         throw;
569     }
570     catch (const std::exception& e)
571     {
572         lg2::error("Exception: {ERR}", "ERR", e);
573         elog<InternalFailure>();
574     }
575     return isEnable;
576 }
577 
userNameAttribute(std::string value)578 std::string Config::userNameAttribute(std::string value)
579 {
580     std::string val;
581     try
582     {
583         if (value == userNameAttribute())
584         {
585             return value;
586         }
587 
588         val = ConfigIface::userNameAttribute(value);
589         if (enabled())
590         {
591             writeConfig();
592 
593             parent.startOrStopService(nslcdService, enabled());
594         }
595         // save the object.
596         serialize();
597     }
598     catch (const InternalFailure& e)
599     {
600         throw;
601     }
602     catch (const std::exception& e)
603     {
604         lg2::error("Exception: {ERR}", "ERR", e);
605         elog<InternalFailure>();
606     }
607     return val;
608 }
609 
groupNameAttribute(std::string value)610 std::string Config::groupNameAttribute(std::string value)
611 {
612     std::string val;
613     try
614     {
615         if (value == groupNameAttribute())
616         {
617             return value;
618         }
619 
620         val = ConfigIface::groupNameAttribute(value);
621         if (enabled())
622         {
623             writeConfig();
624 
625             parent.startOrStopService(nslcdService, enabled());
626         }
627         // save the object.
628         serialize();
629     }
630     catch (const InternalFailure& e)
631     {
632         throw;
633     }
634     catch (const std::exception& e)
635     {
636         lg2::error("Exception: {ERR}", "ERR", e);
637         elog<InternalFailure>();
638     }
639     return val;
640 }
641 
642 template <class Archive>
save(Archive & archive,const std::uint32_t) const643 void Config::save(Archive& archive, const std::uint32_t /*version*/) const
644 {
645     archive(this->enabled());
646     archive(ldapServerURI());
647     archive(ldapBindDN());
648     archive(ldapBaseDN());
649     archive(ldapSearchScope());
650     archive(ldapBindPassword);
651     archive(userNameAttribute());
652     archive(groupNameAttribute());
653 }
654 
655 template <class Archive>
load(Archive & archive,const std::uint32_t)656 void Config::load(Archive& archive, const std::uint32_t /*version*/)
657 {
658     bool bVal;
659     archive(bVal);
660     EnableIface::enabled(bVal);
661 
662     std::string str;
663     archive(str);
664     ConfigIface::ldapServerURI(str);
665 
666     archive(str);
667     ConfigIface::ldapBindDN(str);
668 
669     archive(str);
670     ConfigIface::ldapBaseDN(str);
671 
672     ConfigIface::SearchScope scope;
673     archive(scope);
674     ConfigIface::ldapSearchScope(scope);
675 
676     archive(str);
677     ldapBindPassword = str;
678 
679     archive(str);
680     ConfigIface::userNameAttribute(str);
681 
682     archive(str);
683     ConfigIface::groupNameAttribute(str);
684 }
685 
serialize()686 void Config::serialize()
687 {
688     if (!fs::exists(configPersistPath.c_str()))
689     {
690         std::ofstream os(configPersistPath.string(),
691                          std::ios::binary | std::ios::out);
692         auto permission = fs::perms::owner_read | fs::perms::owner_write |
693                           fs::perms::group_read;
694         fs::permissions(configPersistPath, permission);
695         cereal::BinaryOutputArchive oarchive(os);
696         oarchive(*this);
697     }
698     else
699     {
700         std::ofstream os(configPersistPath.string(),
701                          std::ios::binary | std::ios::out);
702         cereal::BinaryOutputArchive oarchive(os);
703         oarchive(*this);
704     }
705     return;
706 }
707 
deserialize()708 bool Config::deserialize()
709 {
710     try
711     {
712         if (fs::exists(configPersistPath))
713         {
714             std::ifstream is(configPersistPath.c_str(),
715                              std::ios::in | std::ios::binary);
716             cereal::BinaryInputArchive iarchive(is);
717             iarchive(*this);
718 
719             if (isValidLDAPURI(ldapServerURI(), ldapScheme))
720             {
721                 secureLDAP = false;
722             }
723             else if (isValidLDAPURI(ldapServerURI(), ldapsScheme))
724             {
725                 secureLDAP = true;
726             }
727             return true;
728         }
729         return false;
730     }
731     catch (const cereal::Exception& e)
732     {
733         lg2::error("Exception: {ERR}", "ERR", e);
734         std::error_code ec;
735         fs::remove(configPersistPath, ec);
736         return false;
737     }
738     catch (const fs::filesystem_error& e)
739     {
740         return false;
741     }
742 }
743 
create(std::string groupName,std::string privilege)744 ObjectPath Config::create(std::string groupName, std::string privilege)
745 {
746     checkPrivilegeMapper(groupName);
747     checkPrivilegeLevel(privilege);
748 
749     entryId++;
750 
751     // Object path for the LDAP group privilege mapper entry
752     fs::path mapperObjectPath = objectPath;
753     mapperObjectPath /= "role_map";
754     mapperObjectPath /= std::to_string(entryId);
755 
756     fs::path persistPath = parent.dbusPersistentPath;
757     persistPath += mapperObjectPath;
758 
759     // Create mapping for LDAP privilege mapper entry
760     auto entry = std::make_unique<LDAPMapperEntry>(
761         bus, mapperObjectPath.string().c_str(), persistPath.string().c_str(),
762         groupName, privilege, *this);
763 
764     phosphor::ldap::serialize(*entry, std::move(persistPath));
765 
766     PrivilegeMapperList.emplace(entryId, std::move(entry));
767     return mapperObjectPath.string();
768 }
769 
deletePrivilegeMapper(Id id)770 void Config::deletePrivilegeMapper(Id id)
771 {
772     fs::path mapperObjectPath = objectPath;
773     mapperObjectPath /= "role_map";
774     mapperObjectPath /= std::to_string(id);
775 
776     fs::path persistPath = parent.dbusPersistentPath;
777     persistPath += std::move(mapperObjectPath);
778 
779     // Delete the persistent representation of the privilege mapper.
780     fs::remove(std::move(persistPath));
781 
782     PrivilegeMapperList.erase(id);
783 }
checkPrivilegeMapper(const std::string & groupName)784 void Config::checkPrivilegeMapper(const std::string& groupName)
785 {
786     if (groupName.empty())
787     {
788         lg2::error("Group name is empty");
789         elog<InvalidArgument>(Argument::ARGUMENT_NAME("Group name"),
790                               Argument::ARGUMENT_VALUE("Null"));
791     }
792 
793     for (const auto& val : PrivilegeMapperList)
794     {
795         if (val.second.get()->groupName() == groupName)
796         {
797             lg2::error("Group name '{GROUPNAME}' already exists", "GROUPNAME",
798                        groupName);
799             elog<PrivilegeMappingExists>();
800         }
801     }
802 }
803 
checkPrivilegeLevel(const std::string & privilege)804 void Config::checkPrivilegeLevel(const std::string& privilege)
805 {
806     if (privilege.empty())
807     {
808         lg2::error("Privilege level is empty");
809         elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
810                               Argument::ARGUMENT_VALUE("Null"));
811     }
812 
813     if (std::find(privMgr.begin(), privMgr.end(), privilege) == privMgr.end())
814     {
815         lg2::error("Invalid privilege '{PRIVILEGE}'", "PRIVILEGE", privilege);
816         elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege"),
817                               Argument::ARGUMENT_VALUE(privilege.c_str()));
818     }
819 }
820 
restoreRoleMapping()821 void Config::restoreRoleMapping()
822 {
823     namespace fs = std::filesystem;
824     fs::path dir = parent.dbusPersistentPath;
825     dir += objectPath;
826     dir /= "role_map";
827 
828     if (!fs::exists(dir) || fs::is_empty(dir))
829     {
830         return;
831     }
832 
833     for (auto& file : fs::directory_iterator(dir))
834     {
835         std::string id = file.path().filename().c_str();
836         size_t idNum = std::stol(id);
837 
838         auto entryPath = objectPath + '/' + "role_map" + '/' + id;
839         auto persistPath = parent.dbusPersistentPath + entryPath;
840         auto entry = std::make_unique<LDAPMapperEntry>(
841             bus, entryPath.c_str(), persistPath.c_str(), *this);
842         if (phosphor::ldap::deserialize(file.path(), *entry))
843         {
844             entry->Interfaces::emit_object_added();
845             PrivilegeMapperList.emplace(idNum, std::move(entry));
846             if (idNum > entryId)
847             {
848                 entryId = idNum;
849             }
850         }
851     }
852 }
853 
854 } // namespace ldap
855 } // namespace phosphor
856