xref: /openbmc/phosphor-user-manager/phosphor-ldap-config/ldap_config.cpp (revision 11ec666bef0767eb1ef6024e69be02717c852138)
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 <xyz/openbmc_project/Common/error.hpp>
11 #include <xyz/openbmc_project/User/Common/error.hpp>
12 
13 #include <filesystem>
14 #include <fstream>
15 #include <sstream>
16 
17 // Register class version
18 // From cereal documentation;
19 // "This macro should be placed at global scope"
20 CEREAL_CLASS_VERSION(phosphor::ldap::Config, CLASS_VERSION);
21 
22 namespace phosphor
23 {
24 namespace ldap
25 {
26 
27 constexpr auto nslcdService = "nslcd.service";
28 constexpr auto ldapScheme = "ldap";
29 constexpr auto ldapsScheme = "ldaps";
30 constexpr auto certObjPath = "/xyz/openbmc_project/certs/client/ldap/1";
31 constexpr auto certRootPath = "/xyz/openbmc_project/certs/client/ldap";
32 constexpr auto authObjPath = "/xyz/openbmc_project/certs/authority/ldap";
33 constexpr auto certIface = "xyz.openbmc_project.Certs.Certificate";
34 constexpr auto certProperty = "CertificateString";
35 
36 using namespace phosphor::logging;
37 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
38 namespace fs = std::filesystem;
39 
40 using Argument = xyz::openbmc_project::Common::InvalidArgument;
41 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
42 using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
43 using PrivilegeMappingExists = sdbusplus::xyz::openbmc_project::User::Common::
44     Error::PrivilegeMappingExists;
45 
46 using Line = std::string;
47 using Key = std::string;
48 using Val = std::string;
49 using ConfigInfo = std::map<Key, Val>;
50 
51 Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
52                const char* caCertFile, const char* certFile, bool secureLDAP,
53                std::string ldapServerURI, std::string ldapBindDN,
54                std::string ldapBaseDN, std::string&& ldapBindDNPassword,
55                ConfigIface::SearchScope ldapSearchScope,
56                ConfigIface::Type ldapType, bool ldapServiceEnabled,
57                std::string userNameAttr, std::string groupNameAttr,
58                ConfigMgr& parent) :
59     Ifaces(bus, path, Ifaces::action::defer_emit),
60     secureLDAP(secureLDAP), ldapBindPassword(std::move(ldapBindDNPassword)),
61     tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
62     objectPath(path), bus(bus), parent(parent),
63     certificateInstalledSignal(
64         bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
65         std::bind(std::mem_fn(&Config::certificateInstalled), this,
66                   std::placeholders::_1)),
67 
68     cacertificateInstalledSignal(
69         bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
70         std::bind(std::mem_fn(&Config::certificateInstalled), this,
71                   std::placeholders::_1)),
72 
73     certificateChangedSignal(
74         bus,
75         sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
76         std::bind(std::mem_fn(&Config::certificateChanged), this,
77                   std::placeholders::_1))
78 {
79     ConfigIface::ldapServerURI(ldapServerURI);
80     ConfigIface::ldapBindDN(ldapBindDN);
81     ConfigIface::ldapBaseDN(ldapBaseDN);
82     ConfigIface::ldapSearchScope(ldapSearchScope);
83     ConfigIface::ldapType(ldapType);
84     EnableIface::enabled(ldapServiceEnabled);
85     ConfigIface::userNameAttribute(userNameAttr);
86     ConfigIface::groupNameAttribute(groupNameAttr);
87     // NOTE: Don't update the bindDN password under ConfigIface
88     if (enabled())
89     {
90         writeConfig();
91     }
92     // 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 
101     serialize();
102 
103     // Emit deferred signal.
104     this->emit_object_added();
105     parent.startOrStopService(nslcdService, enabled());
106 }
107 
108 Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
109                const char* caCertFile, const char* certFile,
110                ConfigIface::Type ldapType, ConfigMgr& parent) :
111     Ifaces(bus, path, Ifaces::action::defer_emit),
112     secureLDAP(false), tlsCacertFile(caCertFile), tlsCertFile(certFile),
113     configFilePath(filePath), objectPath(path), bus(bus), parent(parent),
114     certificateInstalledSignal(
115         bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
116         std::bind(std::mem_fn(&Config::certificateInstalled), this,
117                   std::placeholders::_1)),
118     cacertificateInstalledSignal(
119         bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
120         std::bind(std::mem_fn(&Config::certificateInstalled), this,
121                   std::placeholders::_1)),
122     certificateChangedSignal(
123         bus,
124         sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
125         std::bind(std::mem_fn(&Config::certificateChanged), this,
126                   std::placeholders::_1))
127 {
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";
137 }
138 
139 void Config::certificateInstalled(sdbusplus::message_t& /*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         lg2::error("Exception: {ERR}", "ERR", e);
156         elog<InternalFailure>();
157     }
158 }
159 
160 void Config::certificateChanged(sdbusplus::message_t& msg)
161 {
162     std::string objectName;
163     std::map<std::string, std::variant<std::string>> msgData;
164     msg.read(objectName, msgData);
165     auto valPropMap = msgData.find(certProperty);
166     {
167         if (valPropMap != msgData.end())
168         {
169             try
170             {
171                 if (enabled())
172                 {
173                     writeConfig();
174                 }
175                 parent.startOrStopService(nslcdService, enabled());
176             }
177             catch (const InternalFailure& e)
178             {
179                 throw;
180             }
181             catch (const std::exception& e)
182             {
183                 lg2::error("Exception: {ERR}", "ERR", e);
184                 elog<InternalFailure>();
185             }
186         }
187     }
188 }
189 
190 void Config::writeConfig()
191 {
192     std::stringstream confData;
193     auto isPwdTobeWritten = false;
194     std::string userNameAttr;
195 
196     confData << "uid root\n";
197     confData << "gid root\n\n";
198     confData << "ldap_version 3\n\n";
199     confData << "timelimit 30\n";
200     confData << "bind_timelimit 30\n";
201     confData << "pagesize 1000\n";
202     confData << "referrals off\n\n";
203     confData << "uri " << ldapServerURI() << "\n\n";
204     confData << "base " << ldapBaseDN() << "\n\n";
205     confData << "binddn " << ldapBindDN() << "\n";
206     if (!ldapBindPassword.empty())
207     {
208         confData << "bindpw " << ldapBindPassword << "\n";
209         isPwdTobeWritten = true;
210     }
211     confData << "\n";
212     switch (ldapSearchScope())
213     {
214         case ConfigIface::SearchScope::sub:
215             confData << "scope sub\n\n";
216             break;
217         case ConfigIface::SearchScope::one:
218             confData << "scope one\n\n";
219             break;
220         case ConfigIface::SearchScope::base:
221             confData << "scope base\n\n";
222             break;
223     }
224     confData << "base passwd " << ldapBaseDN() << "\n";
225     confData << "base shadow " << ldapBaseDN() << "\n\n";
226     if (secureLDAP == true)
227     {
228         confData << "ssl on\n";
229         confData << "tls_reqcert hard\n";
230         if (fs::is_directory(tlsCacertFile.c_str()))
231         {
232             confData << "tls_cacertdir " << tlsCacertFile.c_str() << "\n";
233         }
234         else
235         {
236             confData << "tls_cacertfile " << tlsCacertFile.c_str() << "\n";
237         }
238         if (fs::exists(tlsCertFile.c_str()))
239         {
240             confData << "tls_cert " << tlsCertFile.c_str() << "\n";
241             confData << "tls_key " << tlsCertFile.c_str() << "\n";
242         }
243     }
244     else
245     {
246         confData << "ssl off\n";
247     }
248     confData << "\n";
249     if (ldapType() == ConfigIface::Type::ActiveDirectory)
250     {
251         if (ConfigIface::userNameAttribute().empty())
252         {
253             ConfigIface::userNameAttribute("sAMAccountName");
254         }
255         if (ConfigIface::groupNameAttribute().empty())
256         {
257             ConfigIface::groupNameAttribute("primaryGroupID");
258         }
259         confData << "filter passwd (&(objectClass=user)(objectClass=person)"
260                     "(!(objectClass=computer)))\n";
261         confData
262             << "filter group (|(objectclass=group)(objectclass=groupofnames) "
263                "(objectclass=groupofuniquenames))\n";
264         confData << "map passwd uid              "
265                  << ConfigIface::userNameAttribute() << "\n";
266         confData << "map passwd uidNumber        "
267                     "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
268         confData << "map passwd gidNumber        "
269                  << ConfigIface::groupNameAttribute() << "\n";
270         confData << "map passwd homeDirectory    \"/home/$sAMAccountName\"\n";
271         confData << "map passwd gecos            displayName\n";
272         confData << "map passwd loginShell       \"/bin/sh\"\n";
273         confData << "map group gidNumber         "
274                     "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
275         confData << "map group cn                "
276                  << ConfigIface::userNameAttribute() << "\n";
277         confData << "nss_initgroups_ignoreusers ALLLOCAL\n";
278     }
279     else if (ldapType() == ConfigIface::Type::OpenLdap)
280     {
281         if (ConfigIface::userNameAttribute().empty())
282         {
283             ConfigIface::userNameAttribute("cn");
284         }
285         if (ConfigIface::groupNameAttribute().empty())
286         {
287             ConfigIface::groupNameAttribute("gidNumber");
288         }
289         confData << "filter passwd (objectclass=*)\n";
290         confData << "map passwd gecos displayName\n";
291         confData << "filter group (objectclass=posixGroup)\n";
292         confData << "map passwd uid              "
293                  << ConfigIface::userNameAttribute() << "\n";
294         confData << "map passwd gidNumber        "
295                  << ConfigIface::groupNameAttribute() << "\n";
296         confData << "map passwd loginShell       \"/bin/sh\"\n";
297         confData << "nss_initgroups_ignoreusers ALLLOCAL\n";
298     }
299     try
300     {
301         std::fstream stream(configFilePath.c_str(), std::fstream::out);
302         // remove the read permission from others if password is being written.
303         // nslcd forces this behaviour.
304         auto permission = fs::perms::owner_read | fs::perms::owner_write |
305                           fs::perms::group_read;
306         if (isPwdTobeWritten)
307         {
308             fs::permissions(configFilePath, permission);
309         }
310         else
311         {
312             fs::permissions(configFilePath,
313                             permission | fs::perms::others_read);
314         }
315 
316         stream << confData.str();
317         stream.flush();
318         stream.close();
319     }
320     catch (const std::exception& e)
321     {
322         lg2::error("Exception: {ERR}", "ERR", e);
323         elog<InternalFailure>();
324     }
325     return;
326 }
327 
328 std::string Config::ldapBindDNPassword(std::string value)
329 {
330     // Don't update the D-bus object, this is just to
331     // facilitate if user wants to change the bind dn password
332     // once d-bus object gets created.
333     ldapBindPassword = value;
334     try
335     {
336         if (enabled())
337         {
338             writeConfig();
339             parent.startOrStopService(nslcdService, enabled());
340         }
341         serialize();
342     }
343     catch (const InternalFailure& e)
344     {
345         throw;
346     }
347     catch (const std::exception& e)
348     {
349         lg2::error("Exception: {ERR}", "ERR", e);
350         elog<InternalFailure>();
351     }
352     return value;
353 }
354 
355 std::string Config::ldapServerURI(std::string value)
356 {
357     std::string val;
358     try
359     {
360         if (value == ldapServerURI())
361         {
362             return value;
363         }
364         if (isValidLDAPURI(value, ldapsScheme))
365         {
366             secureLDAP = true;
367         }
368         else if (isValidLDAPURI(value, ldapScheme))
369         {
370             secureLDAP = false;
371         }
372         else
373         {
374             lg2::error("Bad LDAP Server URI {URI}", "URI", value);
375             elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
376                                   Argument::ARGUMENT_VALUE(value.c_str()));
377         }
378 
379         if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
380         {
381             lg2::error("LDAP server CA certificate not found at {PATH}", "PATH",
382                        tlsCacertFile);
383             elog<NoCACertificate>();
384         }
385         val = ConfigIface::ldapServerURI(value);
386         if (enabled())
387         {
388             writeConfig();
389             parent.startOrStopService(nslcdService, enabled());
390         }
391         // save the object.
392         serialize();
393     }
394     catch (const InternalFailure& e)
395     {
396         throw;
397     }
398     catch (const InvalidArgument& e)
399     {
400         throw;
401     }
402     catch (const NoCACertificate& e)
403     {
404         throw;
405     }
406     catch (const std::exception& e)
407     {
408         lg2::error("Exception: {ERR}", "ERR", e);
409         elog<InternalFailure>();
410     }
411     return val;
412 }
413 
414 std::string Config::ldapBindDN(std::string value)
415 {
416     std::string val;
417     try
418     {
419         if (value == ldapBindDN())
420         {
421             return value;
422         }
423 
424         if (value.empty())
425         {
426             lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN",
427                        value);
428             elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapBindDN"),
429                                   Argument::ARGUMENT_VALUE(value.c_str()));
430         }
431 
432         val = ConfigIface::ldapBindDN(value);
433         if (enabled())
434         {
435             writeConfig();
436             parent.startOrStopService(nslcdService, enabled());
437         }
438         // save the object.
439         serialize();
440     }
441     catch (const InternalFailure& e)
442     {
443         throw;
444     }
445     catch (const InvalidArgument& e)
446     {
447         throw;
448     }
449     catch (const std::exception& e)
450     {
451         lg2::error("Exception: {ERR}", "ERR", e);
452         elog<InternalFailure>();
453     }
454     return val;
455 }
456 
457 std::string Config::ldapBaseDN(std::string value)
458 {
459     std::string val;
460     try
461     {
462         if (value == ldapBaseDN())
463         {
464             return value;
465         }
466 
467         if (value.empty())
468         {
469             lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN",
470                        value);
471             elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapBaseDN"),
472                                   Argument::ARGUMENT_VALUE(value.c_str()));
473         }
474 
475         val = ConfigIface::ldapBaseDN(value);
476         if (enabled())
477         {
478             writeConfig();
479             parent.startOrStopService(nslcdService, enabled());
480         }
481         // save the object.
482         serialize();
483     }
484     catch (const InternalFailure& e)
485     {
486         throw;
487     }
488     catch (const InvalidArgument& e)
489     {
490         throw;
491     }
492     catch (const std::exception& e)
493     {
494         lg2::error("Exception: {ERR}", "ERR", e);
495         elog<InternalFailure>();
496     }
497     return val;
498 }
499 
500 ConfigIface::SearchScope Config::ldapSearchScope(ConfigIface::SearchScope value)
501 {
502     ConfigIface::SearchScope val;
503     try
504     {
505         if (value == ldapSearchScope())
506         {
507             return value;
508         }
509 
510         val = ConfigIface::ldapSearchScope(value);
511         if (enabled())
512         {
513             writeConfig();
514 
515             parent.startOrStopService(nslcdService, enabled());
516         }
517         // save the object.
518         serialize();
519     }
520     catch (const InternalFailure& e)
521     {
522         throw;
523     }
524     catch (const std::exception& e)
525     {
526         lg2::error("Exception: {ERR}", "ERR", e);
527         elog<InternalFailure>();
528     }
529     return val;
530 }
531 
532 ConfigIface::Type Config::ldapType(ConfigIface::Type /*value*/)
533 {
534     elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
535     return ldapType();
536 }
537 
538 bool Config::enabled(bool value)
539 {
540     if (value == enabled())
541     {
542         return value;
543     }
544     // Let parent decide that can we enable this config.
545     // It may happen that other config is already enabled,
546     // Current implementation support only one config can
547     // be active at a time.
548     return parent.enableService(*this, value);
549 }
550 
551 bool Config::enableService(bool value)
552 {
553     bool isEnable = false;
554     try
555     {
556         isEnable = EnableIface::enabled(value);
557         if (isEnable)
558         {
559             writeConfig();
560         }
561         parent.startOrStopService(nslcdService, value);
562         serialize();
563     }
564     catch (const InternalFailure& e)
565     {
566         throw;
567     }
568     catch (const std::exception& e)
569     {
570         lg2::error("Exception: {ERR}", "ERR", e);
571         elog<InternalFailure>();
572     }
573     return isEnable;
574 }
575 
576 std::string Config::userNameAttribute(std::string value)
577 {
578     std::string val;
579     try
580     {
581         if (value == userNameAttribute())
582         {
583             return value;
584         }
585 
586         val = ConfigIface::userNameAttribute(value);
587         if (enabled())
588         {
589             writeConfig();
590 
591             parent.startOrStopService(nslcdService, enabled());
592         }
593         // save the object.
594         serialize();
595     }
596     catch (const InternalFailure& e)
597     {
598         throw;
599     }
600     catch (const std::exception& e)
601     {
602         lg2::error("Exception: {ERR}", "ERR", e);
603         elog<InternalFailure>();
604     }
605     return val;
606 }
607 
608 std::string Config::groupNameAttribute(std::string value)
609 {
610     std::string val;
611     try
612     {
613         if (value == groupNameAttribute())
614         {
615             return value;
616         }
617 
618         val = ConfigIface::groupNameAttribute(value);
619         if (enabled())
620         {
621             writeConfig();
622 
623             parent.startOrStopService(nslcdService, enabled());
624         }
625         // save the object.
626         serialize();
627     }
628     catch (const InternalFailure& e)
629     {
630         throw;
631     }
632     catch (const std::exception& e)
633     {
634         lg2::error("Exception: {ERR}", "ERR", e);
635         elog<InternalFailure>();
636     }
637     return val;
638 }
639 
640 template <class Archive>
641 void Config::save(Archive& archive, const std::uint32_t /*version*/) const
642 {
643     archive(this->enabled());
644     archive(ldapServerURI());
645     archive(ldapBindDN());
646     archive(ldapBaseDN());
647     archive(ldapSearchScope());
648     archive(ldapBindPassword);
649     archive(userNameAttribute());
650     archive(groupNameAttribute());
651 }
652 
653 template <class Archive>
654 void Config::load(Archive& archive, const std::uint32_t /*version*/)
655 {
656     bool bVal;
657     archive(bVal);
658     EnableIface::enabled(bVal);
659 
660     std::string str;
661     archive(str);
662     ConfigIface::ldapServerURI(str);
663 
664     archive(str);
665     ConfigIface::ldapBindDN(str);
666 
667     archive(str);
668     ConfigIface::ldapBaseDN(str);
669 
670     ConfigIface::SearchScope scope;
671     archive(scope);
672     ConfigIface::ldapSearchScope(scope);
673 
674     archive(str);
675     ldapBindPassword = str;
676 
677     archive(str);
678     ConfigIface::userNameAttribute(str);
679 
680     archive(str);
681     ConfigIface::groupNameAttribute(str);
682 }
683 
684 void Config::serialize()
685 {
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 
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 
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 
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 }
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 
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 
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