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