blob: e7fb645a5ee389f1a9fa3b8bffb546e93586b8b4 [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>
Jiaqing Zhaoe8d664d2022-07-05 21:22:54 +080010#include <phosphor-logging/elog-errors.hpp>
11#include <phosphor-logging/elog.hpp>
12#include <phosphor-logging/lg2.hpp>
Ratan Gupta7b04c352019-04-12 21:46:29 +053013#include <xyz/openbmc_project/Common/error.hpp>
14#include <xyz/openbmc_project/User/Common/error.hpp>
Patrick Williams9638afb2021-02-22 17:16:24 -060015
Ratan Gupta95a29312019-02-18 20:34:10 +053016#include <filesystem>
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050017#include <fstream>
18#include <sstream>
19
Ratan Gupta21e88cb2019-04-12 17:15:52 +053020// Register class version
21// From cereal documentation;
22// "This macro should be placed at global scope"
23CEREAL_CLASS_VERSION(phosphor::ldap::Config, CLASS_VERSION);
24
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050025namespace phosphor
26{
27namespace ldap
28{
Ratan Guptae1f4db62019-04-11 18:57:42 +053029
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050030constexpr auto nslcdService = "nslcd.service";
Nan Zhou78d85042022-08-29 17:50:22 +000031constexpr auto ldapScheme = "ldap";
32constexpr auto ldapsScheme = "ldaps";
Ratan Guptaab4fcb42019-04-29 19:39:51 +053033constexpr auto certObjPath = "/xyz/openbmc_project/certs/client/ldap/1";
34constexpr auto certRootPath = "/xyz/openbmc_project/certs/client/ldap";
Michal Orzel23f82c12023-07-27 15:28:02 +020035constexpr auto authObjPath = "/xyz/openbmc_project/certs/authority/truststore";
Ratan Guptaab4fcb42019-04-29 19:39:51 +053036constexpr auto certIface = "xyz.openbmc_project.Certs.Certificate";
37constexpr auto certProperty = "CertificateString";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050038
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050039using namespace phosphor::logging;
40using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta95a29312019-02-18 20:34:10 +053041namespace fs = std::filesystem;
Ratan Gupta7b04c352019-04-12 21:46:29 +053042
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050043using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta27d4c012019-04-12 13:03:35 +053044using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Ratan Gupta7b04c352019-04-12 21:46:29 +053045using PrivilegeMappingExists = sdbusplus::xyz::openbmc_project::User::Common::
46 Error::PrivilegeMappingExists;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050047
48using Line = std::string;
49using Key = std::string;
50using Val = std::string;
51using ConfigInfo = std::map<Key, Val>;
52
Patrick Williams16c2b682024-08-16 15:20:56 -040053Config::Config(
54 sdbusplus::bus_t& bus, const char* path, const char* filePath,
55 const char* caCertFile, const char* certFile, bool secureLDAP,
56 std::string ldapServerURI, std::string ldapBindDN, std::string ldapBaseDN,
57 std::string&& ldapBindDNPassword, ConfigIface::SearchScope ldapSearchScope,
58 ConfigIface::Type ldapType, bool ldapServiceEnabled,
59 std::string userNameAttr, std::string groupNameAttr, ConfigMgr& parent) :
60 Ifaces(bus, path, Ifaces::action::defer_emit), secureLDAP(secureLDAP),
61 ldapBindPassword(std::move(ldapBindDNPassword)), tlsCacertFile(caCertFile),
62 tlsCertFile(certFile), configFilePath(filePath), objectPath(path), bus(bus),
63 parent(parent),
Ratan Gupta22f13f12019-04-29 15:36:40 +053064 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +053065 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +053066 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +053067 std::placeholders::_1)),
manojkiranedaa47fe4e2019-05-23 21:28:33 +053068
69 cacertificateInstalledSignal(
70 bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
71 std::bind(std::mem_fn(&Config::certificateInstalled), this,
72 std::placeholders::_1)),
73
Ratan Guptaab4fcb42019-04-29 19:39:51 +053074 certificateChangedSignal(
75 bus,
76 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
77 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +053078 std::placeholders::_1))
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050079{
Patrick Williamse6500a42021-05-01 05:58:23 -050080 ConfigIface::ldapServerURI(ldapServerURI);
81 ConfigIface::ldapBindDN(ldapBindDN);
82 ConfigIface::ldapBaseDN(ldapBaseDN);
83 ConfigIface::ldapSearchScope(ldapSearchScope);
84 ConfigIface::ldapType(ldapType);
85 EnableIface::enabled(ldapServiceEnabled);
Ratan Guptaaeaf9412019-02-11 04:41:52 -060086 ConfigIface::userNameAttribute(userNameAttr);
87 ConfigIface::groupNameAttribute(groupNameAttr);
Ratan Gupta21e88cb2019-04-12 17:15:52 +053088 // NOTE: Don't update the bindDN password under ConfigIface
Ratan Guptaec117542019-04-25 18:38:29 +053089 if (enabled())
90 {
91 writeConfig();
92 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +053093 // save the config.
94 configPersistPath = parent.dbusPersistentPath;
95 configPersistPath += objectPath;
96
97 // create the persistent directory
98 fs::create_directories(configPersistPath);
99
100 configPersistPath += "/config";
101
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530102 serialize();
103
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500104 // Emit deferred signal.
105 this->emit_object_added();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600106 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500107}
108
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500109Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530110 const char* caCertFile, const char* certFile,
Patrick Williamse6500a42021-05-01 05:58:23 -0500111 ConfigIface::Type ldapType, ConfigMgr& parent) :
Patrick Williams16c2b682024-08-16 15:20:56 -0400112 Ifaces(bus, path, Ifaces::action::defer_emit), secureLDAP(false),
113 tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
114 objectPath(path), bus(bus), parent(parent),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530115 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530116 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530117 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530118 std::placeholders::_1)),
manojkiranedaa47fe4e2019-05-23 21:28:33 +0530119 cacertificateInstalledSignal(
120 bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
121 std::bind(std::mem_fn(&Config::certificateInstalled), this,
122 std::placeholders::_1)),
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530123 certificateChangedSignal(
124 bus,
125 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
126 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +0530127 std::placeholders::_1))
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530128{
Patrick Williamse6500a42021-05-01 05:58:23 -0500129 ConfigIface::ldapType(ldapType);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530130
131 configPersistPath = parent.dbusPersistentPath;
132 configPersistPath += objectPath;
133
134 // create the persistent directory
135 fs::create_directories(configPersistPath);
136
137 configPersistPath += "/config";
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530138}
139
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500140void Config::certificateInstalled(sdbusplus::message_t& /*msg*/)
Ratan Gupta22f13f12019-04-29 15:36:40 +0530141{
142 try
143 {
144 if (enabled())
145 {
146 writeConfig();
147 }
148 parent.startOrStopService(nslcdService, enabled());
149 }
150 catch (const InternalFailure& e)
151 {
152 throw;
153 }
154 catch (const std::exception& e)
155 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800156 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Gupta22f13f12019-04-29 15:36:40 +0530157 elog<InternalFailure>();
158 }
159}
160
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500161void Config::certificateChanged(sdbusplus::message_t& msg)
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530162{
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530163 std::string objectName;
Patrick Williamsfdf09372020-05-13 18:01:45 -0500164 std::map<std::string, std::variant<std::string>> msgData;
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530165 msg.read(objectName, msgData);
166 auto valPropMap = msgData.find(certProperty);
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530167 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530168 if (valPropMap != msgData.end())
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530169 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530170 try
171 {
172 if (enabled())
173 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530174 writeConfig();
175 }
176 parent.startOrStopService(nslcdService, enabled());
177 }
178 catch (const InternalFailure& e)
179 {
180 throw;
181 }
182 catch (const std::exception& e)
183 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800184 lg2::error("Exception: {ERR}", "ERR", e);
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530185 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800323 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500324 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800350 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530351 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800375 lg2::error("Bad LDAP Server URI {URI}", "URI", value);
Patrick Williamse6500a42021-05-01 05:58:23 -0500376 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"),
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500377 Argument::ARGUMENT_VALUE(value.c_str()));
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500378 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600379
380 if (secureLDAP && !fs::exists(tlsCacertFile.c_str()))
381 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800382 lg2::error("LDAP server CA certificate not found at {PATH}", "PATH",
383 tlsCacertFile);
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600384 elog<NoCACertificate>();
385 }
Patrick Williamse6500a42021-05-01 05:58:23 -0500386 val = ConfigIface::ldapServerURI(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530387 if (enabled())
388 {
389 writeConfig();
390 parent.startOrStopService(nslcdService, enabled());
391 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530392 // save the object.
393 serialize();
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500394 }
395 catch (const InternalFailure& e)
396 {
397 throw;
398 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500399 catch (const InvalidArgument& e)
400 {
401 throw;
402 }
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600403 catch (const NoCACertificate& e)
404 {
405 throw;
406 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500407 catch (const std::exception& e)
408 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800409 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500410 elog<InternalFailure>();
411 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500412 return val;
413}
414
Patrick Williamse6500a42021-05-01 05:58:23 -0500415std::string Config::ldapBindDN(std::string value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500416{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500417 std::string val;
418 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500419 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500420 if (value == ldapBindDN())
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500421 {
422 return value;
423 }
424
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500425 if (value.empty())
426 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800427 lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN",
428 value);
Patrick Williamse6500a42021-05-01 05:58:23 -0500429 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapBindDN"),
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500430 Argument::ARGUMENT_VALUE(value.c_str()));
431 }
432
Patrick Williamse6500a42021-05-01 05:58:23 -0500433 val = ConfigIface::ldapBindDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530434 if (enabled())
435 {
436 writeConfig();
437 parent.startOrStopService(nslcdService, enabled());
438 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530439 // save the object.
440 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500441 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500442 catch (const InternalFailure& e)
443 {
444 throw;
445 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600446 catch (const InvalidArgument& e)
447 {
448 throw;
449 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500450 catch (const std::exception& e)
451 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800452 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500453 elog<InternalFailure>();
454 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500455 return val;
456}
457
Patrick Williamse6500a42021-05-01 05:58:23 -0500458std::string Config::ldapBaseDN(std::string value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500459{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500460 std::string val;
461 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500462 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500463 if (value == ldapBaseDN())
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500464 {
465 return value;
466 }
467
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500468 if (value.empty())
469 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800470 lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN",
471 value);
Patrick Williamse6500a42021-05-01 05:58:23 -0500472 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapBaseDN"),
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500473 Argument::ARGUMENT_VALUE(value.c_str()));
474 }
475
Patrick Williamse6500a42021-05-01 05:58:23 -0500476 val = ConfigIface::ldapBaseDN(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530477 if (enabled())
478 {
479 writeConfig();
480 parent.startOrStopService(nslcdService, enabled());
481 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530482 // save the object.
483 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500484 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500485 catch (const InternalFailure& e)
486 {
487 throw;
488 }
Nagaraju Gorugantid514e5d2018-11-08 03:07:25 -0600489 catch (const InvalidArgument& e)
490 {
491 throw;
492 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500493 catch (const std::exception& e)
494 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800495 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500496 elog<InternalFailure>();
497 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500498 return val;
499}
500
Patrick Williamse6500a42021-05-01 05:58:23 -0500501ConfigIface::SearchScope Config::ldapSearchScope(ConfigIface::SearchScope value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500502{
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600503 ConfigIface::SearchScope val;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500504 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500505 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500506 if (value == ldapSearchScope())
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500507 {
508 return value;
509 }
510
Patrick Williamse6500a42021-05-01 05:58:23 -0500511 val = ConfigIface::ldapSearchScope(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530512 if (enabled())
513 {
514 writeConfig();
515
516 parent.startOrStopService(nslcdService, enabled());
517 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530518 // save the object.
519 serialize();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500520 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500521 catch (const InternalFailure& e)
522 {
523 throw;
524 }
525 catch (const std::exception& e)
526 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800527 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500528 elog<InternalFailure>();
529 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500530 return val;
531}
532
Ratan Gupta0b1ad3d2022-01-09 14:09:35 +0530533ConfigIface::Type Config::ldapType(ConfigIface::Type /*value*/)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500534{
Ratan Gupta27d4c012019-04-12 13:03:35 +0530535 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property"));
Patrick Williamse6500a42021-05-01 05:58:23 -0500536 return ldapType();
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500537}
538
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600539bool Config::enabled(bool value)
540{
Ratan Guptac5481d12019-04-12 18:31:05 +0530541 if (value == enabled())
542 {
543 return value;
544 }
545 // Let parent decide that can we enable this config.
546 // It may happen that other config is already enabled,
547 // Current implementation support only one config can
548 // be active at a time.
549 return parent.enableService(*this, value);
550}
551
552bool Config::enableService(bool value)
553{
554 bool isEnable = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600555 try
556 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600557 isEnable = EnableIface::enabled(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530558 if (isEnable)
559 {
560 writeConfig();
561 }
Ratan Guptaec117542019-04-25 18:38:29 +0530562 parent.startOrStopService(nslcdService, value);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530563 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600564 }
565 catch (const InternalFailure& e)
566 {
567 throw;
568 }
569 catch (const std::exception& e)
570 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800571 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600572 elog<InternalFailure>();
573 }
574 return isEnable;
575}
576
577std::string Config::userNameAttribute(std::string value)
578{
579 std::string val;
580 try
581 {
582 if (value == userNameAttribute())
583 {
584 return value;
585 }
586
587 val = ConfigIface::userNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530588 if (enabled())
589 {
590 writeConfig();
591
592 parent.startOrStopService(nslcdService, enabled());
593 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530594 // save the object.
595 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600596 }
597 catch (const InternalFailure& e)
598 {
599 throw;
600 }
601 catch (const std::exception& e)
602 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800603 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600604 elog<InternalFailure>();
605 }
606 return val;
607}
608
609std::string Config::groupNameAttribute(std::string value)
610{
611 std::string val;
612 try
613 {
614 if (value == groupNameAttribute())
615 {
616 return value;
617 }
618
619 val = ConfigIface::groupNameAttribute(value);
Ratan Guptaec117542019-04-25 18:38:29 +0530620 if (enabled())
621 {
622 writeConfig();
623
624 parent.startOrStopService(nslcdService, enabled());
625 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530626 // save the object.
627 serialize();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600628 }
629 catch (const InternalFailure& e)
630 {
631 throw;
632 }
633 catch (const std::exception& e)
634 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800635 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600636 elog<InternalFailure>();
637 }
638 return val;
639}
640
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530641template <class Archive>
Ratan Gupta0b1ad3d2022-01-09 14:09:35 +0530642void Config::save(Archive& archive, const std::uint32_t /*version*/) const
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530643{
644 archive(this->enabled());
Patrick Williamse6500a42021-05-01 05:58:23 -0500645 archive(ldapServerURI());
646 archive(ldapBindDN());
647 archive(ldapBaseDN());
648 archive(ldapSearchScope());
649 archive(ldapBindPassword);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530650 archive(userNameAttribute());
651 archive(groupNameAttribute());
652}
653
654template <class Archive>
Ratan Gupta0b1ad3d2022-01-09 14:09:35 +0530655void Config::load(Archive& archive, const std::uint32_t /*version*/)
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530656{
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530657 bool bVal;
658 archive(bVal);
659 EnableIface::enabled(bVal);
660
661 std::string str;
662 archive(str);
Patrick Williamse6500a42021-05-01 05:58:23 -0500663 ConfigIface::ldapServerURI(str);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530664
665 archive(str);
Patrick Williamse6500a42021-05-01 05:58:23 -0500666 ConfigIface::ldapBindDN(str);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530667
668 archive(str);
Patrick Williamse6500a42021-05-01 05:58:23 -0500669 ConfigIface::ldapBaseDN(str);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530670
671 ConfigIface::SearchScope scope;
672 archive(scope);
Patrick Williamse6500a42021-05-01 05:58:23 -0500673 ConfigIface::ldapSearchScope(scope);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530674
675 archive(str);
Patrick Williamse6500a42021-05-01 05:58:23 -0500676 ldapBindPassword = str;
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530677
678 archive(str);
679 ConfigIface::userNameAttribute(str);
680
681 archive(str);
682 ConfigIface::groupNameAttribute(str);
683}
684
685void Config::serialize()
686{
Ravi Teja59dba442019-05-20 09:31:28 -0500687 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 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530704 return;
705}
706
707bool 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);
Ravi Tejad5884042019-06-10 02:35:22 -0500717
Nan Zhou78d85042022-08-29 17:50:22 +0000718 if (isValidLDAPURI(ldapServerURI(), ldapScheme))
Ravi Tejad5884042019-06-10 02:35:22 -0500719 {
720 secureLDAP = false;
721 }
Nan Zhou78d85042022-08-29 17:50:22 +0000722 else if (isValidLDAPURI(ldapServerURI(), ldapsScheme))
Ravi Tejad5884042019-06-10 02:35:22 -0500723 {
724 secureLDAP = true;
725 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530726 return true;
727 }
728 return false;
729 }
Patrick Williamsd019e3d2021-10-06 12:46:55 -0500730 catch (const cereal::Exception& e)
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530731 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800732 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530733 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
Ratan Gupta7b04c352019-04-12 21:46:29 +0530743ObjectPath 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
769void 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}
783void Config::checkPrivilegeMapper(const std::string& groupName)
784{
785 if (groupName.empty())
786 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800787 lg2::error("Group name is empty");
Ratan Gupta7b04c352019-04-12 21:46:29 +0530788 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800796 lg2::error("Group name '{GROUPNAME}' already exists", "GROUPNAME",
797 groupName);
Ratan Gupta7b04c352019-04-12 21:46:29 +0530798 elog<PrivilegeMappingExists>();
799 }
800 }
801}
802
803void Config::checkPrivilegeLevel(const std::string& privilege)
804{
805 if (privilege.empty())
806 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800807 lg2::error("Privilege level is empty");
Ratan Gupta7b04c352019-04-12 21:46:29 +0530808 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800814 lg2::error("Invalid privilege '{PRIVILEGE}'", "PRIVILEGE", privilege);
815 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege"),
Ratan Gupta7b04c352019-04-12 21:46:29 +0530816 Argument::ARGUMENT_VALUE(privilege.c_str()));
817 }
818}
819
820void 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
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500853} // namespace ldap
854} // namespace phosphor