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