blob: b7bd4c6c9186b63db5f45cce0a05aafd779c8165 [file] [log] [blame]
Ratan Gupta37fb3fe2019-04-13 12:54:18 +05301#include "ldap_config.hpp"
Patrick Williams9638afb2021-02-22 17:16:24 -06002
3#include "ldap_config_mgr.hpp"
4#include "ldap_mapper_serialize.hpp"
Nagaraju Goruganti59287f02018-10-12 07:00:20 -05005#include "utils.hpp"
Ratan Gupta21e88cb2019-04-12 17:15:52 +05306
Patrick Williams9638afb2021-02-22 17:16:24 -06007#include <cereal/archives/binary.hpp>
Ratan Gupta21e88cb2019-04-12 17:15:52 +05308#include <cereal/types/string.hpp>
9#include <cereal/types/vector.hpp>
Ratan Gupta7b04c352019-04-12 21:46:29 +053010#include <xyz/openbmc_project/Common/error.hpp>
11#include <xyz/openbmc_project/User/Common/error.hpp>
Patrick Williams9638afb2021-02-22 17:16:24 -060012
Ratan Gupta95a29312019-02-18 20:34:10 +053013#include <filesystem>
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050014#include <fstream>
15#include <sstream>
16
Ratan Gupta21e88cb2019-04-12 17:15:52 +053017// Register class version
18// From cereal documentation;
19// "This macro should be placed at global scope"
20CEREAL_CLASS_VERSION(phosphor::ldap::Config, CLASS_VERSION);
21
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050022namespace phosphor
23{
24namespace ldap
25{
Ratan Guptae1f4db62019-04-11 18:57:42 +053026
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050027constexpr auto nslcdService = "nslcd.service";
Nan Zhou78d85042022-08-29 17:50:22 +000028constexpr auto ldapScheme = "ldap";
29constexpr auto ldapsScheme = "ldaps";
Ratan Guptaab4fcb42019-04-29 19:39:51 +053030constexpr auto certObjPath = "/xyz/openbmc_project/certs/client/ldap/1";
31constexpr auto certRootPath = "/xyz/openbmc_project/certs/client/ldap";
manojkiranedaa47fe4e2019-05-23 21:28:33 +053032constexpr auto authObjPath = "/xyz/openbmc_project/certs/authority/ldap";
Ratan Guptaab4fcb42019-04-29 19:39:51 +053033constexpr auto certIface = "xyz.openbmc_project.Certs.Certificate";
34constexpr auto certProperty = "CertificateString";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050035
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050036using namespace phosphor::logging;
37using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta95a29312019-02-18 20:34:10 +053038namespace fs = std::filesystem;
Ratan Gupta7b04c352019-04-12 21:46:29 +053039
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050040using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta27d4c012019-04-12 13:03:35 +053041using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
42using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Ratan Gupta7b04c352019-04-12 21:46:29 +053043using PrivilegeMappingExists = sdbusplus::xyz::openbmc_project::User::Common::
44 Error::PrivilegeMappingExists;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050045
46using Line = std::string;
47using Key = std::string;
48using Val = std::string;
49using ConfigInfo = std::map<Key, Val>;
50
Patrick Williamsb3ef4e12022-07-22 19:26:55 -050051Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
Ratan Gupta22f13f12019-04-29 15:36:40 +053052 const char* caCertFile, const char* certFile, bool secureLDAP,
Patrick Williamse6500a42021-05-01 05:58:23 -050053 std::string ldapServerURI, std::string ldapBindDN,
54 std::string ldapBaseDN, std::string&& ldapBindDNPassword,
55 ConfigIface::SearchScope ldapSearchScope,
56 ConfigIface::Type ldapType, bool ldapServiceEnabled,
Ratan Guptaaeaf9412019-02-11 04:41:52 -060057 std::string userNameAttr, std::string groupNameAttr,
58 ConfigMgr& parent) :
Patrick Williams224559b2022-04-05 16:10:39 -050059 Ifaces(bus, path, Ifaces::action::defer_emit),
Patrick Williamse6500a42021-05-01 05:58:23 -050060 secureLDAP(secureLDAP), ldapBindPassword(std::move(ldapBindDNPassword)),
Ratan Gupta22f13f12019-04-29 15:36:40 +053061 tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
62 objectPath(path), bus(bus), parent(parent),
63 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +053064 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +053065 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +053066 std::placeholders::_1)),
manojkiranedaa47fe4e2019-05-23 21:28:33 +053067
68 cacertificateInstalledSignal(
69 bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
70 std::bind(std::mem_fn(&Config::certificateInstalled), this,
71 std::placeholders::_1)),
72
Ratan Guptaab4fcb42019-04-29 19:39:51 +053073 certificateChangedSignal(
74 bus,
75 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
76 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +053077 std::placeholders::_1))
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050078{
Patrick Williamse6500a42021-05-01 05:58:23 -050079 ConfigIface::ldapServerURI(ldapServerURI);
80 ConfigIface::ldapBindDN(ldapBindDN);
81 ConfigIface::ldapBaseDN(ldapBaseDN);
82 ConfigIface::ldapSearchScope(ldapSearchScope);
83 ConfigIface::ldapType(ldapType);
84 EnableIface::enabled(ldapServiceEnabled);
Ratan Guptaaeaf9412019-02-11 04:41:52 -060085 ConfigIface::userNameAttribute(userNameAttr);
86 ConfigIface::groupNameAttribute(groupNameAttr);
Ratan Gupta21e88cb2019-04-12 17:15:52 +053087 // NOTE: Don't update the bindDN password under ConfigIface
Ratan Guptaec117542019-04-25 18:38:29 +053088 if (enabled())
89 {
90 writeConfig();
91 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +053092 // 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
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530101 serialize();
102
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500103 // Emit deferred signal.
104 this->emit_object_added();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600105 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500106}
107
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500108Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530109 const char* caCertFile, const char* certFile,
Patrick Williamse6500a42021-05-01 05:58:23 -0500110 ConfigIface::Type ldapType, ConfigMgr& parent) :
Patrick Williams224559b2022-04-05 16:10:39 -0500111 Ifaces(bus, path, Ifaces::action::defer_emit),
Ravi Tejad5884042019-06-10 02:35:22 -0500112 secureLDAP(false), tlsCacertFile(caCertFile), tlsCertFile(certFile),
113 configFilePath(filePath), objectPath(path), bus(bus), parent(parent),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530114 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530115 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530116 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530117 std::placeholders::_1)),
manojkiranedaa47fe4e2019-05-23 21:28:33 +0530118 cacertificateInstalledSignal(
119 bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
120 std::bind(std::mem_fn(&Config::certificateInstalled), this,
121 std::placeholders::_1)),
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530122 certificateChangedSignal(
123 bus,
124 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
125 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +0530126 std::placeholders::_1))
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530127{
Patrick Williamse6500a42021-05-01 05:58:23 -0500128 ConfigIface::ldapType(ldapType);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530129
130 configPersistPath = parent.dbusPersistentPath;
131 configPersistPath += objectPath;
132
133 // create the persistent directory
134 fs::create_directories(configPersistPath);
135
136 configPersistPath += "/config";
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530137}
138
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500139void Config::certificateInstalled(sdbusplus::message_t& /*msg*/)
Ratan Gupta22f13f12019-04-29 15:36:40 +0530140{
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
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500160void Config::certificateChanged(sdbusplus::message_t& msg)
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530161{
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530162 std::string objectName;
Patrick Williamsfdf09372020-05-13 18:01:45 -0500163 std::map<std::string, std::variant<std::string>> msgData;
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530164 msg.read(objectName, msgData);
165 auto valPropMap = msgData.find(certProperty);
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530166 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530167 if (valPropMap != msgData.end())
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530168 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530169 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 }
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530187 }
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530188 }
189}
190
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500191void Config::writeConfig()
192{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500193 std::stringstream confData;
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530194 auto isPwdTobeWritten = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600195 std::string userNameAttr;
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530196
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500197 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";
Patrick Williamse6500a42021-05-01 05:58:23 -0500204 confData << "uri " << ldapServerURI() << "\n\n";
205 confData << "base " << ldapBaseDN() << "\n\n";
206 confData << "binddn " << ldapBindDN() << "\n";
207 if (!ldapBindPassword.empty())
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500208 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500209 confData << "bindpw " << ldapBindPassword << "\n";
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530210 isPwdTobeWritten = true;
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500211 }
212 confData << "\n";
Patrick Williamse6500a42021-05-01 05:58:23 -0500213 switch (ldapSearchScope())
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500214 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600215 case ConfigIface::SearchScope::sub:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500216 confData << "scope sub\n\n";
217 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600218 case ConfigIface::SearchScope::one:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500219 confData << "scope one\n\n";
220 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600221 case ConfigIface::SearchScope::base:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500222 confData << "scope base\n\n";
223 break;
224 }
Patrick Williamse6500a42021-05-01 05:58:23 -0500225 confData << "base passwd " << ldapBaseDN() << "\n";
226 confData << "base shadow " << ldapBaseDN() << "\n\n";
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600227 if (secureLDAP == true)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500228 {
229 confData << "ssl on\n";
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600230 confData << "tls_reqcert hard\n";
Zbigniew Kurzynski5d00cf22019-10-03 12:10:20 +0200231 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 }
Ratan Gupta22f13f12019-04-29 15:36:40 +0530239 if (fs::exists(tlsCertFile.c_str()))
240 {
241 confData << "tls_cert " << tlsCertFile.c_str() << "\n";
242 confData << "tls_key " << tlsCertFile.c_str() << "\n";
243 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500244 }
245 else
246 {
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500247 confData << "ssl off\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500248 }
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500249 confData << "\n";
Patrick Williamse6500a42021-05-01 05:58:23 -0500250 if (ldapType() == ConfigIface::Type::ActiveDirectory)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500251 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600252 if (ConfigIface::userNameAttribute().empty())
253 {
254 ConfigIface::userNameAttribute("sAMAccountName");
255 }
256 if (ConfigIface::groupNameAttribute().empty())
257 {
258 ConfigIface::groupNameAttribute("primaryGroupID");
259 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500260 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
261 "(!(objectClass=computer)))\n";
262 confData
263 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
264 "(objectclass=groupofuniquenames))\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600265 confData << "map passwd uid "
266 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500267 confData << "map passwd uidNumber "
268 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600269 confData << "map passwd gidNumber "
270 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500271 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
272 confData << "map passwd gecos displayName\n";
Jiaqing Zhao69570e52022-06-07 22:51:17 +0800273 confData << "map passwd loginShell \"/bin/sh\"\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500274 confData << "map group gidNumber "
275 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600276 confData << "map group cn "
277 << ConfigIface::userNameAttribute() << "\n";
Ravi Teja3a003e22020-08-11 11:13:17 -0500278 confData << "nss_initgroups_ignoreusers ALLLOCAL\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500279 }
Patrick Williamse6500a42021-05-01 05:58:23 -0500280 else if (ldapType() == ConfigIface::Type::OpenLdap)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500281 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600282 if (ConfigIface::userNameAttribute().empty())
283 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500284 ConfigIface::userNameAttribute("cn");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600285 }
286 if (ConfigIface::groupNameAttribute().empty())
287 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500288 ConfigIface::groupNameAttribute("gidNumber");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600289 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500290 confData << "filter passwd (objectclass=*)\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500291 confData << "map passwd gecos displayName\n";
Nagaraju Goruganti808eda42018-10-10 08:48:12 -0500292 confData << "filter group (objectclass=posixGroup)\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600293 confData << "map passwd uid "
294 << ConfigIface::userNameAttribute() << "\n";
295 confData << "map passwd gidNumber "
296 << ConfigIface::groupNameAttribute() << "\n";
Jiaqing Zhao69570e52022-06-07 22:51:17 +0800297 confData << "map passwd loginShell \"/bin/sh\"\n";
Ravi Teja3a003e22020-08-11 11:13:17 -0500298 confData << "nss_initgroups_ignoreusers ALLLOCAL\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500299 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500300 try
301 {
302 std::fstream stream(configFilePath.c_str(), std::fstream::out);
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530303 // 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
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500317 stream << confData.str();
318 stream.flush();
319 stream.close();
320 }
321 catch (const std::exception& e)
322 {
323 log<level::ERR>(e.what());
324 elog<InternalFailure>();
325 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500326 return;
327}
328
Patrick Williamse6500a42021-05-01 05:58:23 -0500329std::string Config::ldapBindDNPassword(std::string value)
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530330{
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.
Patrick Williamse6500a42021-05-01 05:58:23 -0500334 ldapBindPassword = value;
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530335 try
336 {
Ratan Guptaec117542019-04-25 18:38:29 +0530337 if (enabled())
338 {
339 writeConfig();
340 parent.startOrStopService(nslcdService, enabled());
341 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530342 serialize();
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530343 }
344 catch (const InternalFailure& e)
345 {
346 throw;
347 }
348 catch (const std::exception& e)
349 {
350 log<level::ERR>(e.what());
351 elog<InternalFailure>();
352 }
353 return value;
354}
355
Patrick Williamse6500a42021-05-01 05:58:23 -0500356std::string Config::ldapServerURI(std::string value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500357{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500358 std::string val;
359 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500360 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500361 if (value == ldapServerURI())
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500362 {
363 return value;
364 }
Nan Zhou78d85042022-08-29 17:50:22 +0000365 if (isValidLDAPURI(value, ldapsScheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500366 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500367 secureLDAP = true;
368 }
Nan Zhou78d85042022-08-29 17:50:22 +0000369 else if (isValidLDAPURI(value, ldapScheme))
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500370 {
371 secureLDAP = false;
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600372 }
373 else
374 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500375 log<level::ERR>("bad LDAP Server URI",
376 entry("LDAPSERVERURI=%s", value.c_str()));
Patrick Williamse6500a42021-05-01 05:58:23 -0500377 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500378 Argument::ARGUMENT_VALUE(value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500379 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600380
381 if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
382 {
383 log<level::ERR>("LDAP server's CA certificate not provided",
384 entry("TLSCACERTFILE=%s", tlsCacertFile.c_str()));
385 elog<NoCACertificate>();
386 }
Patrick Williamse6500a42021-05-01 05:58:23 -0500387 val = ConfigIface::ldapServerURI(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530388 if (enabled())
389 {
390 writeConfig();
391 parent.startOrStopService(nslcdService, enabled());
392 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530393 // save the object.
394 serialize();
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500395 }
396 catch (const InternalFailure& e)
397 {
398 throw;
399 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500400 catch (const InvalidArgument& e)
401 {
402 throw;
403 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600404 catch (const NoCACertificate& e)
405 {
406 throw;
407 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500408 catch (const std::exception& e)
409 {
410 log<level::ERR>(e.what());
411 elog<InternalFailure>();
412 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500413 return val;
414}
415
Patrick Williamse6500a42021-05-01 05:58:23 -0500416std::string Config::ldapBindDN(std::string value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500417{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500418 std::string val;
419 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500420 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500421 if (value == ldapBindDN())
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500422 {
423 return value;
424 }
425
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500426 if (value.empty())
427 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500428 log<level::ERR>("Not a valid LDAP BINDDN",
429 entry("LDAPBINDDN=%s", value.c_str()));
Patrick Williamse6500a42021-05-01 05:58:23 -0500430 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapBindDN"),
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500431 Argument::ARGUMENT_VALUE(value.c_str()));
432 }
433
Patrick Williamse6500a42021-05-01 05:58:23 -0500434 val = ConfigIface::ldapBindDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530435 if (enabled())
436 {
437 writeConfig();
438 parent.startOrStopService(nslcdService, enabled());
439 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530440 // save the object.
441 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500442 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500443 catch (const InternalFailure& e)
444 {
445 throw;
446 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600447 catch (const InvalidArgument& e)
448 {
449 throw;
450 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500451 catch (const std::exception& e)
452 {
453 log<level::ERR>(e.what());
454 elog<InternalFailure>();
455 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500456 return val;
457}
458
Patrick Williamse6500a42021-05-01 05:58:23 -0500459std::string Config::ldapBaseDN(std::string value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500460{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500461 std::string val;
462 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500463 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500464 if (value == ldapBaseDN())
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500465 {
466 return value;
467 }
468
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500469 if (value.empty())
470 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500471 log<level::ERR>("Not a valid LDAP BASEDN",
472 entry("BASEDN=%s", value.c_str()));
Patrick Williamse6500a42021-05-01 05:58:23 -0500473 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapBaseDN"),
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500474 Argument::ARGUMENT_VALUE(value.c_str()));
475 }
476
Patrick Williamse6500a42021-05-01 05:58:23 -0500477 val = ConfigIface::ldapBaseDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530478 if (enabled())
479 {
480 writeConfig();
481 parent.startOrStopService(nslcdService, enabled());
482 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530483 // save the object.
484 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500485 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500486 catch (const InternalFailure& e)
487 {
488 throw;
489 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600490 catch (const InvalidArgument& e)
491 {
492 throw;
493 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500494 catch (const std::exception& e)
495 {
496 log<level::ERR>(e.what());
497 elog<InternalFailure>();
498 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500499 return val;
500}
501
Patrick Williamse6500a42021-05-01 05:58:23 -0500502ConfigIface::SearchScope Config::ldapSearchScope(ConfigIface::SearchScope value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500503{
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600504 ConfigIface::SearchScope val;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500505 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500506 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500507 if (value == ldapSearchScope())
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500508 {
509 return value;
510 }
511
Patrick Williamse6500a42021-05-01 05:58:23 -0500512 val = ConfigIface::ldapSearchScope(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530513 if (enabled())
514 {
515 writeConfig();
516
517 parent.startOrStopService(nslcdService, enabled());
518 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530519 // save the object.
520 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500521 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500522 catch (const InternalFailure& e)
523 {
524 throw;
525 }
526 catch (const std::exception& e)
527 {
528 log<level::ERR>(e.what());
529 elog<InternalFailure>();
530 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500531 return val;
532}
533
Ratan Gupta0b1ad3d2022-01-09 14:09:35 +0530534ConfigIface::Type Config::ldapType(ConfigIface::Type /*value*/)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500535{
Ratan Gupta27d4c012019-04-12 13:03:35 +0530536 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Patrick Williamse6500a42021-05-01 05:58:23 -0500537 return ldapType();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500538}
539
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600540bool Config::enabled(bool value)
541{
Ratan Guptac5481d12019-04-12 18:31:05 +0530542 if (value == enabled())
543 {
544 return value;
545 }
546 // Let parent decide that can we enable this config.
547 // It may happen that other config is already enabled,
548 // Current implementation support only one config can
549 // be active at a time.
550 return parent.enableService(*this, value);
551}
552
553bool Config::enableService(bool value)
554{
555 bool isEnable = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600556 try
557 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600558 isEnable = EnableIface::enabled(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530559 if (isEnable)
560 {
561 writeConfig();
562 }
Ratan Guptaec117542019-04-25 18:38:29 +0530563 parent.startOrStopService(nslcdService, value);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530564 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600565 }
566 catch (const InternalFailure& e)
567 {
568 throw;
569 }
570 catch (const std::exception& e)
571 {
572 log<level::ERR>(e.what());
573 elog<InternalFailure>();
574 }
575 return isEnable;
576}
577
578std::string Config::userNameAttribute(std::string value)
579{
580 std::string val;
581 try
582 {
583 if (value == userNameAttribute())
584 {
585 return value;
586 }
587
588 val = ConfigIface::userNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530589 if (enabled())
590 {
591 writeConfig();
592
593 parent.startOrStopService(nslcdService, enabled());
594 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530595 // save the object.
596 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600597 }
598 catch (const InternalFailure& e)
599 {
600 throw;
601 }
602 catch (const std::exception& e)
603 {
604 log<level::ERR>(e.what());
605 elog<InternalFailure>();
606 }
607 return val;
608}
609
610std::string Config::groupNameAttribute(std::string value)
611{
612 std::string val;
613 try
614 {
615 if (value == groupNameAttribute())
616 {
617 return value;
618 }
619
620 val = ConfigIface::groupNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530621 if (enabled())
622 {
623 writeConfig();
624
625 parent.startOrStopService(nslcdService, enabled());
626 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530627 // save the object.
628 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600629 }
630 catch (const InternalFailure& e)
631 {
632 throw;
633 }
634 catch (const std::exception& e)
635 {
636 log<level::ERR>(e.what());
637 elog<InternalFailure>();
638 }
639 return val;
640}
641
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530642template <class Archive>
Ratan Gupta0b1ad3d2022-01-09 14:09:35 +0530643void Config::save(Archive& archive, const std::uint32_t /*version*/) const
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530644{
645 archive(this->enabled());
Patrick Williamse6500a42021-05-01 05:58:23 -0500646 archive(ldapServerURI());
647 archive(ldapBindDN());
648 archive(ldapBaseDN());
649 archive(ldapSearchScope());
650 archive(ldapBindPassword);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530651 archive(userNameAttribute());
652 archive(groupNameAttribute());
653}
654
655template <class Archive>
Ratan Gupta0b1ad3d2022-01-09 14:09:35 +0530656void Config::load(Archive& archive, const std::uint32_t /*version*/)
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530657{
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530658 bool bVal;
659 archive(bVal);
660 EnableIface::enabled(bVal);
661
662 std::string str;
663 archive(str);
Patrick Williamse6500a42021-05-01 05:58:23 -0500664 ConfigIface::ldapServerURI(str);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530665
666 archive(str);
Patrick Williamse6500a42021-05-01 05:58:23 -0500667 ConfigIface::ldapBindDN(str);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530668
669 archive(str);
Patrick Williamse6500a42021-05-01 05:58:23 -0500670 ConfigIface::ldapBaseDN(str);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530671
672 ConfigIface::SearchScope scope;
673 archive(scope);
Patrick Williamse6500a42021-05-01 05:58:23 -0500674 ConfigIface::ldapSearchScope(scope);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530675
676 archive(str);
Patrick Williamse6500a42021-05-01 05:58:23 -0500677 ldapBindPassword = str;
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530678
679 archive(str);
680 ConfigIface::userNameAttribute(str);
681
682 archive(str);
683 ConfigIface::groupNameAttribute(str);
684}
685
686void Config::serialize()
687{
Ravi Teja59dba442019-05-20 09:31:28 -0500688
689 if (!fs::exists(configPersistPath.c_str()))
690 {
691 std::ofstream os(configPersistPath.string(),
692 std::ios::binary | std::ios::out);
693 auto permission = fs::perms::owner_read | fs::perms::owner_write |
694 fs::perms::group_read;
695 fs::permissions(configPersistPath, permission);
696 cereal::BinaryOutputArchive oarchive(os);
697 oarchive(*this);
698 }
699 else
700 {
701 std::ofstream os(configPersistPath.string(),
702 std::ios::binary | std::ios::out);
703 cereal::BinaryOutputArchive oarchive(os);
704 oarchive(*this);
705 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530706 return;
707}
708
709bool Config::deserialize()
710{
711 try
712 {
713 if (fs::exists(configPersistPath))
714 {
715 std::ifstream is(configPersistPath.c_str(),
716 std::ios::in | std::ios::binary);
717 cereal::BinaryInputArchive iarchive(is);
718 iarchive(*this);
Ravi Tejad5884042019-06-10 02:35:22 -0500719
Nan Zhou78d85042022-08-29 17:50:22 +0000720 if (isValidLDAPURI(ldapServerURI(), ldapScheme))
Ravi Tejad5884042019-06-10 02:35:22 -0500721 {
722 secureLDAP = false;
723 }
Nan Zhou78d85042022-08-29 17:50:22 +0000724 else if (isValidLDAPURI(ldapServerURI(), ldapsScheme))
Ravi Tejad5884042019-06-10 02:35:22 -0500725 {
726 secureLDAP = true;
727 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530728 return true;
729 }
730 return false;
731 }
Patrick Williamsd019e3d2021-10-06 12:46:55 -0500732 catch (const cereal::Exception& e)
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530733 {
734 log<level::ERR>(e.what());
735 std::error_code ec;
736 fs::remove(configPersistPath, ec);
737 return false;
738 }
739 catch (const fs::filesystem_error& e)
740 {
741 return false;
742 }
743}
744
Ratan Gupta7b04c352019-04-12 21:46:29 +0530745ObjectPath Config::create(std::string groupName, std::string privilege)
746{
747 checkPrivilegeMapper(groupName);
748 checkPrivilegeLevel(privilege);
749
750 entryId++;
751
752 // Object path for the LDAP group privilege mapper entry
753 fs::path mapperObjectPath = objectPath;
754 mapperObjectPath /= "role_map";
755 mapperObjectPath /= std::to_string(entryId);
756
757 fs::path persistPath = parent.dbusPersistentPath;
758 persistPath += mapperObjectPath;
759
760 // Create mapping for LDAP privilege mapper entry
761 auto entry = std::make_unique<LDAPMapperEntry>(
762 bus, mapperObjectPath.string().c_str(), persistPath.string().c_str(),
763 groupName, privilege, *this);
764
765 phosphor::ldap::serialize(*entry, std::move(persistPath));
766
767 PrivilegeMapperList.emplace(entryId, std::move(entry));
768 return mapperObjectPath.string();
769}
770
771void Config::deletePrivilegeMapper(Id id)
772{
773 fs::path mapperObjectPath = objectPath;
774 mapperObjectPath /= "role_map";
775 mapperObjectPath /= std::to_string(id);
776
777 fs::path persistPath = parent.dbusPersistentPath;
778 persistPath += std::move(mapperObjectPath);
779
780 // Delete the persistent representation of the privilege mapper.
781 fs::remove(std::move(persistPath));
782
783 PrivilegeMapperList.erase(id);
784}
785void Config::checkPrivilegeMapper(const std::string& groupName)
786{
787 if (groupName.empty())
788 {
789 log<level::ERR>("Group name is empty");
790 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Group name"),
791 Argument::ARGUMENT_VALUE("Null"));
792 }
793
794 for (const auto& val : PrivilegeMapperList)
795 {
796 if (val.second.get()->groupName() == groupName)
797 {
798 log<level::ERR>("Group name already exists");
799 elog<PrivilegeMappingExists>();
800 }
801 }
802}
803
804void Config::checkPrivilegeLevel(const std::string& privilege)
805{
806 if (privilege.empty())
807 {
808 log<level::ERR>("Privilege level is empty");
809 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
810 Argument::ARGUMENT_VALUE("Null"));
811 }
812
813 if (std::find(privMgr.begin(), privMgr.end(), privilege) == privMgr.end())
814 {
815 log<level::ERR>("Invalid privilege");
816 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
817 Argument::ARGUMENT_VALUE(privilege.c_str()));
818 }
819}
820
821void Config::restoreRoleMapping()
822{
823 namespace fs = std::filesystem;
824 fs::path dir = parent.dbusPersistentPath;
825 dir += objectPath;
826 dir /= "role_map";
827
828 if (!fs::exists(dir) || fs::is_empty(dir))
829 {
830 return;
831 }
832
833 for (auto& file : fs::directory_iterator(dir))
834 {
835 std::string id = file.path().filename().c_str();
836 size_t idNum = std::stol(id);
837
838 auto entryPath = objectPath + '/' + "role_map" + '/' + id;
839 auto persistPath = parent.dbusPersistentPath + entryPath;
840 auto entry = std::make_unique<LDAPMapperEntry>(
841 bus, entryPath.c_str(), persistPath.c_str(), *this);
842 if (phosphor::ldap::deserialize(file.path(), *entry))
843 {
844 entry->Interfaces::emit_object_added();
845 PrivilegeMapperList.emplace(idNum, std::move(entry));
846 if (idNum > entryId)
847 {
848 entryId = idNum;
849 }
850 }
851 }
852}
853
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500854} // namespace ldap
855} // namespace phosphor