xref: /openbmc/phosphor-user-manager/phosphor-ldap-config/ldap_config_mgr.cpp (revision 11ec666bef0767eb1ef6024e69be02717c852138)
1 #include "ldap_config_mgr.hpp"
2 
3 #include "ldap_config.hpp"
4 #include "utils.hpp"
5 
6 #include <filesystem>
7 #include <fstream>
8 #include <sstream>
9 
10 namespace phosphor
11 {
12 namespace ldap
13 {
14 
15 constexpr auto nslcdService = "nslcd.service";
16 constexpr auto nscdService = "nscd.service";
17 constexpr auto ldapScheme = "ldap";
18 constexpr auto ldapsScheme = "ldaps";
19 
20 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
21 namespace fs = std::filesystem;
22 using Argument = xyz::openbmc_project::Common::InvalidArgument;
23 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
24 using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
25 
26 using Line = std::string;
27 using Key = std::string;
28 using Val = std::string;
29 using ConfigInfo = std::map<Key, Val>;
30 
31 void ConfigMgr::startOrStopService(const std::string& service, bool start)
32 {
33     if (start)
34     {
35         restartService(service);
36     }
37     else
38     {
39         stopService(service);
40     }
41 }
42 
43 void ConfigMgr::restartService(const std::string& service)
44 {
45     try
46     {
47         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
48                                           SYSTEMD_INTERFACE, "RestartUnit");
49         method.append(service.c_str(), "replace");
50         bus.call_noreply(method);
51     }
52     catch (const sdbusplus::exception_t& ex)
53     {
54         lg2::error("Failed to restart service {SERVICE}: {ERR}", "SERVICE",
55                    service, "ERR", ex);
56         elog<InternalFailure>();
57     }
58 }
59 void ConfigMgr::stopService(const std::string& service)
60 {
61     try
62     {
63         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
64                                           SYSTEMD_INTERFACE, "StopUnit");
65         method.append(service.c_str(), "replace");
66         bus.call_noreply(method);
67     }
68     catch (const sdbusplus::exception_t& ex)
69     {
70         lg2::error("Failed to stop service {SERVICE}: {ERR}", "SERVICE",
71                    service, "ERR", ex);
72         elog<InternalFailure>();
73     }
74 }
75 
76 std::string ConfigMgr::createConfig(
77     std::string ldapServerURI, std::string ldapBindDN, std::string ldapBaseDN,
78     std::string ldapBindDNPassword, CreateIface::SearchScope ldapSearchScope,
79     CreateIface::Create::Type ldapType, std::string groupNameAttribute,
80     std::string userNameAttribute)
81 {
82     bool secureLDAP = false;
83 
84     if (isValidLDAPURI(ldapServerURI, ldapsScheme))
85     {
86         secureLDAP = true;
87     }
88     else if (isValidLDAPURI(ldapServerURI, ldapScheme))
89     {
90         secureLDAP = false;
91     }
92     else
93     {
94         lg2::error("Bad LDAP Server URI {URI}", "URI", ldapServerURI);
95         elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
96                               Argument::ARGUMENT_VALUE(ldapServerURI.c_str()));
97     }
98 
99     if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
100     {
101         lg2::error("LDAP server CA certificate not found at {PATH}", "PATH",
102                    tlsCacertFile);
103         elog<NoCACertificate>();
104     }
105 
106     if (ldapBindDN.empty())
107     {
108         lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN",
109                    ldapBindDN);
110         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBindDN"),
111                               Argument::ARGUMENT_VALUE(ldapBindDN.c_str()));
112     }
113 
114     if (ldapBaseDN.empty())
115     {
116         lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN",
117                    ldapBaseDN);
118         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBaseDN"),
119                               Argument::ARGUMENT_VALUE(ldapBaseDN.c_str()));
120     }
121 
122     // With current implementation we support only two default LDAP server.
123     // which will be always there but when the support comes for additional
124     // account providers then the create config would be used to create the
125     // additional config.
126 
127     std::string objPath;
128 
129     if (static_cast<ConfigIface::Type>(ldapType) == ConfigIface::Type::OpenLdap)
130     {
131         openLDAPConfigPtr.reset(nullptr);
132         objPath = openLDAPDbusObjectPath;
133         openLDAPConfigPtr = std::make_unique<Config>(
134             bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
135             tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
136             ldapBaseDN, std::move(ldapBindDNPassword),
137             static_cast<ConfigIface::SearchScope>(ldapSearchScope),
138             static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
139             userNameAttribute, *this);
140     }
141     else
142     {
143         ADConfigPtr.reset(nullptr);
144         objPath = adDbusObjectPath;
145         ADConfigPtr = std::make_unique<Config>(
146             bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(),
147             tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN,
148             ldapBaseDN, std::move(ldapBindDNPassword),
149             static_cast<ConfigIface::SearchScope>(ldapSearchScope),
150             static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute,
151             userNameAttribute, *this);
152     }
153     restartService(nscdService);
154     return objPath;
155 }
156 
157 void ConfigMgr::createDefaultObjects()
158 {
159     if (!openLDAPConfigPtr)
160     {
161         openLDAPConfigPtr = std::make_unique<Config>(
162             bus, openLDAPDbusObjectPath.c_str(), configFilePath.c_str(),
163             tlsCacertFile.c_str(), tlsCertFile.c_str(),
164             ConfigIface::Type::OpenLdap, *this);
165         openLDAPConfigPtr->emit_object_added();
166     }
167     if (!ADConfigPtr)
168     {
169         ADConfigPtr = std::make_unique<Config>(
170             bus, adDbusObjectPath.c_str(), configFilePath.c_str(),
171             tlsCacertFile.c_str(), tlsCertFile.c_str(),
172             ConfigIface::Type::ActiveDirectory, *this);
173         ADConfigPtr->emit_object_added();
174     }
175 }
176 
177 bool ConfigMgr::enableService(Config& config, bool value)
178 {
179     if (value)
180     {
181         if (openLDAPConfigPtr && openLDAPConfigPtr->enabled())
182         {
183             elog<NotAllowed>(NotAllowedArgument::REASON(
184                 "OpenLDAP service is already active"));
185         }
186         if (ADConfigPtr && ADConfigPtr->enabled())
187         {
188             elog<NotAllowed>(NotAllowedArgument::REASON(
189                 "ActiveDirectory service is already active"));
190         }
191     }
192     return config.enableService(value);
193 }
194 
195 void ConfigMgr::restore()
196 {
197     createDefaultObjects();
198     // Restore the ldap config and their mappings
199     if (ADConfigPtr->deserialize())
200     {
201         // Restore the role mappings
202         ADConfigPtr->restoreRoleMapping();
203         ADConfigPtr->emit_object_added();
204     }
205     if (openLDAPConfigPtr->deserialize())
206     {
207         // Restore the role mappings
208         openLDAPConfigPtr->restoreRoleMapping();
209         openLDAPConfigPtr->emit_object_added();
210     }
211 
212     startOrStopService(phosphor::ldap::nslcdService,
213                        ADConfigPtr->enabled() || openLDAPConfigPtr->enabled());
214 }
215 
216 } // namespace ldap
217 } // namespace phosphor
218