1 #include "ldap_config_mgr.hpp"
2 #include "ldap_config.hpp"
3 #include "utils.hpp"
4 
5 #include <cereal/types/string.hpp>
6 #include <cereal/types/vector.hpp>
7 #include <cereal/archives/binary.hpp>
8 #include "ldap_mapper_serialize.hpp"
9 
10 #include <xyz/openbmc_project/Common/error.hpp>
11 #include <xyz/openbmc_project/User/Common/error.hpp>
12 #include <filesystem>
13 #include <fstream>
14 #include <sstream>
15 
16 // Register class version
17 // From cereal documentation;
18 // "This macro should be placed at global scope"
19 CEREAL_CLASS_VERSION(phosphor::ldap::Config, CLASS_VERSION);
20 
21 namespace phosphor
22 {
23 namespace ldap
24 {
25 
26 constexpr auto nslcdService = "nslcd.service";
27 constexpr auto nscdService = "nscd.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::bus& 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, true),
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::bus& bus, const char* path, const char* filePath,
109                const char* caCertFile, const char* certFile,
110                ConfigIface::Type lDAPType, ConfigMgr& parent) :
111     Ifaces(bus, path, true),
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::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 
160 void Config::certificateChanged(sdbusplus::message::message& msg)
161 {
162     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);
166     {
167         if (valPropMap != msgData.end())
168         {
169             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             }
187         }
188     }
189 }
190 
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/bash\"\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     }
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     }
297     try
298     {
299         std::fstream stream(configFilePath.c_str(), std::fstream::out);
300         // 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 
314         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     }
323     return;
324 }
325 
326 std::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     {
334         if (enabled())
335         {
336             writeConfig();
337             parent.startOrStopService(nslcdService, enabled());
338         }
339         serialize();
340     }
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 
353 std::string Config::lDAPServerURI(std::string value)
354 {
355     std::string val;
356     try
357     {
358         if (value == lDAPServerURI())
359         {
360             return value;
361         }
362         if (isValidLDAPURI(value, LDAPSscheme))
363         {
364             secureLDAP = true;
365         }
366         else if (isValidLDAPURI(value, LDAPscheme))
367         {
368             secureLDAP = false;
369         }
370         else
371         {
372             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()));
376         }
377 
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         }
384         val = ConfigIface::lDAPServerURI(value);
385         if (enabled())
386         {
387             writeConfig();
388             parent.startOrStopService(nslcdService, enabled());
389         }
390         // save the object.
391         serialize();
392     }
393     catch (const InternalFailure& e)
394     {
395         throw;
396     }
397     catch (const InvalidArgument& e)
398     {
399         throw;
400     }
401     catch (const NoCACertificate& e)
402     {
403         throw;
404     }
405     catch (const std::exception& e)
406     {
407         log<level::ERR>(e.what());
408         elog<InternalFailure>();
409     }
410     return val;
411 }
412 
413 std::string Config::lDAPBindDN(std::string value)
414 {
415     std::string val;
416     try
417     {
418         if (value == lDAPBindDN())
419         {
420             return value;
421         }
422 
423         if (value.empty())
424         {
425             log<level::ERR>("Not a valid LDAP BINDDN",
426                             entry("LDAPBINDDN=%s", value.c_str()));
427             elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"),
428                                   Argument::ARGUMENT_VALUE(value.c_str()));
429         }
430 
431         val = ConfigIface::lDAPBindDN(value);
432         if (enabled())
433         {
434             writeConfig();
435             parent.startOrStopService(nslcdService, enabled());
436         }
437         // save the object.
438         serialize();
439     }
440     catch (const InternalFailure& e)
441     {
442         throw;
443     }
444     catch (const InvalidArgument& e)
445     {
446         throw;
447     }
448     catch (const std::exception& e)
449     {
450         log<level::ERR>(e.what());
451         elog<InternalFailure>();
452     }
453     return val;
454 }
455 
456 std::string Config::lDAPBaseDN(std::string value)
457 {
458     std::string val;
459     try
460     {
461         if (value == lDAPBaseDN())
462         {
463             return value;
464         }
465 
466         if (value.empty())
467         {
468             log<level::ERR>("Not a valid LDAP BASEDN",
469                             entry("BASEDN=%s", value.c_str()));
470             elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"),
471                                   Argument::ARGUMENT_VALUE(value.c_str()));
472         }
473 
474         val = ConfigIface::lDAPBaseDN(value);
475         if (enabled())
476         {
477             writeConfig();
478             parent.startOrStopService(nslcdService, enabled());
479         }
480         // save the object.
481         serialize();
482     }
483     catch (const InternalFailure& e)
484     {
485         throw;
486     }
487     catch (const InvalidArgument& e)
488     {
489         throw;
490     }
491     catch (const std::exception& e)
492     {
493         log<level::ERR>(e.what());
494         elog<InternalFailure>();
495     }
496     return val;
497 }
498 
499 ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value)
500 {
501     ConfigIface::SearchScope val;
502     try
503     {
504         if (value == lDAPSearchScope())
505         {
506             return value;
507         }
508 
509         val = ConfigIface::lDAPSearchScope(value);
510         if (enabled())
511         {
512             writeConfig();
513 
514             parent.startOrStopService(nslcdService, enabled());
515         }
516         // save the object.
517         serialize();
518     }
519     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     }
528     return val;
529 }
530 
531 ConfigIface::Type Config::lDAPType(ConfigIface::Type value)
532 {
533     elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
534     return lDAPType();
535 }
536 
537 bool Config::enabled(bool value)
538 {
539     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 
550 bool Config::enableService(bool value)
551 {
552     bool isEnable = false;
553     try
554     {
555         isEnable = EnableIface::enabled(value);
556         if (isEnable)
557         {
558             writeConfig();
559         }
560         parent.startOrStopService(nslcdService, value);
561         serialize();
562     }
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 
575 std::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);
586         if (enabled())
587         {
588             writeConfig();
589 
590             parent.startOrStopService(nslcdService, enabled());
591         }
592         // save the object.
593         serialize();
594     }
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 
607 std::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);
618         if (enabled())
619         {
620             writeConfig();
621 
622             parent.startOrStopService(nslcdService, enabled());
623         }
624         // save the object.
625         serialize();
626     }
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 
639 template <class Archive>
640 void 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 
652 template <class Archive>
653 void Config::load(Archive& archive, const std::uint32_t version)
654 {
655     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 
683 void Config::serialize()
684 {
685 
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     }
703     return;
704 }
705 
706 bool 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);
716 
717             if (isValidLDAPURI(lDAPServerURI(), LDAPscheme))
718             {
719                 secureLDAP = false;
720             }
721             else if (isValidLDAPURI(lDAPServerURI(), LDAPSscheme))
722             {
723                 secureLDAP = true;
724             }
725             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 
742 ObjectPath 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 
768 void 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 }
782 void 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 
801 void 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 
818 void 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 
851 } // namespace ldap
852 } // namespace phosphor
853