blob: d6cd6ddaf2450075bb6e3e6033e0b72e8718ab75 [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";
manojkiranedaa47fe4e2019-05-23 21:28:33 +053035constexpr auto authObjPath = "/xyz/openbmc_project/certs/authority/ldap";
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 Williamsb3ef4e12022-07-22 19:26:55 -050053Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
Ratan Gupta22f13f12019-04-29 15:36:40 +053054 const char* caCertFile, const char* certFile, bool secureLDAP,
Patrick Williamse6500a42021-05-01 05:58:23 -050055 std::string ldapServerURI, std::string ldapBindDN,
56 std::string ldapBaseDN, std::string&& ldapBindDNPassword,
57 ConfigIface::SearchScope ldapSearchScope,
58 ConfigIface::Type ldapType, bool ldapServiceEnabled,
Ratan Guptaaeaf9412019-02-11 04:41:52 -060059 std::string userNameAttr, std::string groupNameAttr,
60 ConfigMgr& parent) :
Patrick Williams224559b2022-04-05 16:10:39 -050061 Ifaces(bus, path, Ifaces::action::defer_emit),
Patrick Williamse6500a42021-05-01 05:58:23 -050062 secureLDAP(secureLDAP), ldapBindPassword(std::move(ldapBindDNPassword)),
Ratan Gupta22f13f12019-04-29 15:36:40 +053063 tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
64 objectPath(path), bus(bus), parent(parent),
65 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +053066 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +053067 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +053068 std::placeholders::_1)),
manojkiranedaa47fe4e2019-05-23 21:28:33 +053069
70 cacertificateInstalledSignal(
71 bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
72 std::bind(std::mem_fn(&Config::certificateInstalled), this,
73 std::placeholders::_1)),
74
Ratan Guptaab4fcb42019-04-29 19:39:51 +053075 certificateChangedSignal(
76 bus,
77 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
78 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +053079 std::placeholders::_1))
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050080{
Patrick Williamse6500a42021-05-01 05:58:23 -050081 ConfigIface::ldapServerURI(ldapServerURI);
82 ConfigIface::ldapBindDN(ldapBindDN);
83 ConfigIface::ldapBaseDN(ldapBaseDN);
84 ConfigIface::ldapSearchScope(ldapSearchScope);
85 ConfigIface::ldapType(ldapType);
86 EnableIface::enabled(ldapServiceEnabled);
Ratan Guptaaeaf9412019-02-11 04:41:52 -060087 ConfigIface::userNameAttribute(userNameAttr);
88 ConfigIface::groupNameAttribute(groupNameAttr);
Ratan Gupta21e88cb2019-04-12 17:15:52 +053089 // NOTE: Don't update the bindDN password under ConfigIface
Ratan Guptaec117542019-04-25 18:38:29 +053090 if (enabled())
91 {
92 writeConfig();
93 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +053094 // save the config.
95 configPersistPath = parent.dbusPersistentPath;
96 configPersistPath += objectPath;
97
98 // create the persistent directory
99 fs::create_directories(configPersistPath);
100
101 configPersistPath += "/config";
102
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530103 serialize();
104
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500105 // Emit deferred signal.
106 this->emit_object_added();
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600107 parent.startOrStopService(nslcdService, enabled());
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500108}
109
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500110Config::Config(sdbusplus::bus_t& bus, const char* path, const char* filePath,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530111 const char* caCertFile, const char* certFile,
Patrick Williamse6500a42021-05-01 05:58:23 -0500112 ConfigIface::Type ldapType, ConfigMgr& parent) :
Patrick Williams224559b2022-04-05 16:10:39 -0500113 Ifaces(bus, path, Ifaces::action::defer_emit),
Ravi Tejad5884042019-06-10 02:35:22 -0500114 secureLDAP(false), tlsCacertFile(caCertFile), tlsCertFile(certFile),
115 configFilePath(filePath), objectPath(path), bus(bus), parent(parent),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530116 certificateInstalledSignal(
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530117 bus, sdbusplus::bus::match::rules::interfacesAdded(certRootPath),
Ratan Gupta22f13f12019-04-29 15:36:40 +0530118 std::bind(std::mem_fn(&Config::certificateInstalled), this,
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530119 std::placeholders::_1)),
manojkiranedaa47fe4e2019-05-23 21:28:33 +0530120 cacertificateInstalledSignal(
121 bus, sdbusplus::bus::match::rules::interfacesAdded(authObjPath),
122 std::bind(std::mem_fn(&Config::certificateInstalled), this,
123 std::placeholders::_1)),
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530124 certificateChangedSignal(
125 bus,
126 sdbusplus::bus::match::rules::propertiesChanged(certObjPath, certIface),
127 std::bind(std::mem_fn(&Config::certificateChanged), this,
Ratan Gupta22f13f12019-04-29 15:36:40 +0530128 std::placeholders::_1))
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530129{
Patrick Williamse6500a42021-05-01 05:58:23 -0500130 ConfigIface::ldapType(ldapType);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530131
132 configPersistPath = parent.dbusPersistentPath;
133 configPersistPath += objectPath;
134
135 // create the persistent directory
136 fs::create_directories(configPersistPath);
137
138 configPersistPath += "/config";
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530139}
140
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500141void Config::certificateInstalled(sdbusplus::message_t& /*msg*/)
Ratan Gupta22f13f12019-04-29 15:36:40 +0530142{
143 try
144 {
145 if (enabled())
146 {
147 writeConfig();
148 }
149 parent.startOrStopService(nslcdService, enabled());
150 }
151 catch (const InternalFailure& e)
152 {
153 throw;
154 }
155 catch (const std::exception& e)
156 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800157 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Gupta22f13f12019-04-29 15:36:40 +0530158 elog<InternalFailure>();
159 }
160}
161
Patrick Williamsb3ef4e12022-07-22 19:26:55 -0500162void Config::certificateChanged(sdbusplus::message_t& msg)
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530163{
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530164 std::string objectName;
Patrick Williamsfdf09372020-05-13 18:01:45 -0500165 std::map<std::string, std::variant<std::string>> msgData;
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530166 msg.read(objectName, msgData);
167 auto valPropMap = msgData.find(certProperty);
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530168 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530169 if (valPropMap != msgData.end())
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530170 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530171 try
172 {
173 if (enabled())
174 {
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530175 writeConfig();
176 }
177 parent.startOrStopService(nslcdService, enabled());
178 }
179 catch (const InternalFailure& e)
180 {
181 throw;
182 }
183 catch (const std::exception& e)
184 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800185 lg2::error("Exception: {ERR}", "ERR", e);
manojkiraneda75b5a6f2019-05-28 16:23:11 +0530186 elog<InternalFailure>();
187 }
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530188 }
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530189 }
190}
191
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500192void Config::writeConfig()
193{
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500194 std::stringstream confData;
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530195 auto isPwdTobeWritten = false;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600196 std::string userNameAttr;
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530197
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500198 confData << "uid root\n";
199 confData << "gid root\n\n";
200 confData << "ldap_version 3\n\n";
201 confData << "timelimit 30\n";
202 confData << "bind_timelimit 30\n";
203 confData << "pagesize 1000\n";
204 confData << "referrals off\n\n";
Patrick Williamse6500a42021-05-01 05:58:23 -0500205 confData << "uri " << ldapServerURI() << "\n\n";
206 confData << "base " << ldapBaseDN() << "\n\n";
207 confData << "binddn " << ldapBindDN() << "\n";
208 if (!ldapBindPassword.empty())
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500209 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500210 confData << "bindpw " << ldapBindPassword << "\n";
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530211 isPwdTobeWritten = true;
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500212 }
213 confData << "\n";
Patrick Williamse6500a42021-05-01 05:58:23 -0500214 switch (ldapSearchScope())
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500215 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600216 case ConfigIface::SearchScope::sub:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500217 confData << "scope sub\n\n";
218 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600219 case ConfigIface::SearchScope::one:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500220 confData << "scope one\n\n";
221 break;
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600222 case ConfigIface::SearchScope::base:
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500223 confData << "scope base\n\n";
224 break;
225 }
Patrick Williamse6500a42021-05-01 05:58:23 -0500226 confData << "base passwd " << ldapBaseDN() << "\n";
227 confData << "base shadow " << ldapBaseDN() << "\n\n";
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600228 if (secureLDAP == true)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500229 {
230 confData << "ssl on\n";
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600231 confData << "tls_reqcert hard\n";
Zbigniew Kurzynski5d00cf22019-10-03 12:10:20 +0200232 if (fs::is_directory(tlsCacertFile.c_str()))
233 {
234 confData << "tls_cacertdir " << tlsCacertFile.c_str() << "\n";
235 }
236 else
237 {
238 confData << "tls_cacertfile " << tlsCacertFile.c_str() << "\n";
239 }
Ratan Gupta22f13f12019-04-29 15:36:40 +0530240 if (fs::exists(tlsCertFile.c_str()))
241 {
242 confData << "tls_cert " << tlsCertFile.c_str() << "\n";
243 confData << "tls_key " << tlsCertFile.c_str() << "\n";
244 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500245 }
246 else
247 {
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500248 confData << "ssl off\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500249 }
Nagaraju Goruganti15675472018-10-05 07:03:05 -0500250 confData << "\n";
Patrick Williamse6500a42021-05-01 05:58:23 -0500251 if (ldapType() == ConfigIface::Type::ActiveDirectory)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500252 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600253 if (ConfigIface::userNameAttribute().empty())
254 {
255 ConfigIface::userNameAttribute("sAMAccountName");
256 }
257 if (ConfigIface::groupNameAttribute().empty())
258 {
259 ConfigIface::groupNameAttribute("primaryGroupID");
260 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500261 confData << "filter passwd (&(objectClass=user)(objectClass=person)"
262 "(!(objectClass=computer)))\n";
263 confData
264 << "filter group (|(objectclass=group)(objectclass=groupofnames) "
265 "(objectclass=groupofuniquenames))\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600266 confData << "map passwd uid "
267 << ConfigIface::userNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500268 confData << "map passwd uidNumber "
269 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600270 confData << "map passwd gidNumber "
271 << ConfigIface::groupNameAttribute() << "\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500272 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n";
273 confData << "map passwd gecos displayName\n";
Jiaqing Zhao69570e52022-06-07 22:51:17 +0800274 confData << "map passwd loginShell \"/bin/sh\"\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500275 confData << "map group gidNumber "
276 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600277 confData << "map group cn "
278 << ConfigIface::userNameAttribute() << "\n";
Ravi Teja3a003e22020-08-11 11:13:17 -0500279 confData << "nss_initgroups_ignoreusers ALLLOCAL\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500280 }
Patrick Williamse6500a42021-05-01 05:58:23 -0500281 else if (ldapType() == ConfigIface::Type::OpenLdap)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500282 {
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600283 if (ConfigIface::userNameAttribute().empty())
284 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500285 ConfigIface::userNameAttribute("cn");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600286 }
287 if (ConfigIface::groupNameAttribute().empty())
288 {
raviteja-bc3f56c52019-04-02 11:09:04 -0500289 ConfigIface::groupNameAttribute("gidNumber");
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600290 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500291 confData << "filter passwd (objectclass=*)\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500292 confData << "map passwd gecos displayName\n";
Nagaraju Goruganti808eda42018-10-10 08:48:12 -0500293 confData << "filter group (objectclass=posixGroup)\n";
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600294 confData << "map passwd uid "
295 << ConfigIface::userNameAttribute() << "\n";
296 confData << "map passwd gidNumber "
297 << ConfigIface::groupNameAttribute() << "\n";
Jiaqing Zhao69570e52022-06-07 22:51:17 +0800298 confData << "map passwd loginShell \"/bin/sh\"\n";
Ravi Teja3a003e22020-08-11 11:13:17 -0500299 confData << "nss_initgroups_ignoreusers ALLLOCAL\n";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500300 }
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500301 try
302 {
303 std::fstream stream(configFilePath.c_str(), std::fstream::out);
Ratan Gupta9891f2f2018-10-06 12:07:35 +0530304 // remove the read permission from others if password is being written.
305 // nslcd forces this behaviour.
306 auto permission = fs::perms::owner_read | fs::perms::owner_write |
307 fs::perms::group_read;
308 if (isPwdTobeWritten)
309 {
310 fs::permissions(configFilePath, permission);
311 }
312 else
313 {
314 fs::permissions(configFilePath,
315 permission | fs::perms::others_read);
316 }
317
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500318 stream << confData.str();
319 stream.flush();
320 stream.close();
321 }
322 catch (const std::exception& e)
323 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800324 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500325 elog<InternalFailure>();
326 }
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500327 return;
328}
329
Patrick Williamse6500a42021-05-01 05:58:23 -0500330std::string Config::ldapBindDNPassword(std::string value)
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530331{
332 // Don't update the D-bus object, this is just to
333 // facilitate if user wants to change the bind dn password
334 // once d-bus object gets created.
Patrick Williamse6500a42021-05-01 05:58:23 -0500335 ldapBindPassword = value;
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530336 try
337 {
Ratan Guptaec117542019-04-25 18:38:29 +0530338 if (enabled())
339 {
340 writeConfig();
341 parent.startOrStopService(nslcdService, enabled());
342 }
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530343 serialize();
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530344 }
345 catch (const InternalFailure& e)
346 {
347 throw;
348 }
349 catch (const std::exception& e)
350 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800351 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Gupta3a1c2742019-03-20 06:49:42 +0530352 elog<InternalFailure>();
353 }
354 return value;
355}
356
Patrick Williamse6500a42021-05-01 05:58:23 -0500357std::string Config::ldapServerURI(std::string value)
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500358{
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500359 std::string val;
360 try
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500361 {
Patrick Williamse6500a42021-05-01 05:58:23 -0500362 if (value == ldapServerURI())
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500363 {
364 return value;
365 }
Nan Zhou78d85042022-08-29 17:50:22 +0000366 if (isValidLDAPURI(value, ldapsScheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500367 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500368 secureLDAP = true;
369 }
Nan Zhou78d85042022-08-29 17:50:22 +0000370 else if (isValidLDAPURI(value, ldapScheme))
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500371 {
372 secureLDAP = false;
Nagaraju Gorugantidb60f582018-11-08 03:14:48 -0600373 }
374 else
375 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800376 lg2::error("Bad LDAP Server URI {URI}", "URI", value);
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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800383 lg2::error("LDAP server CA certificate not found at {PATH}", "PATH",
384 tlsCacertFile);
Nagaraju Goruganti3b4d06a2018-11-08 03:13:38 -0600385 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800410 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500411 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800428 lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN",
429 value);
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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800453 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500454 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800471 lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN",
472 value);
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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800496 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500497 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800528 lg2::error("Exception: {ERR}", "ERR", e);
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -0500529 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800572 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600573 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800604 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600605 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800636 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Guptaaeaf9412019-02-11 04:41:52 -0600637 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800734 lg2::error("Exception: {ERR}", "ERR", e);
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530735 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800789 lg2::error("Group name is empty");
Ratan Gupta7b04c352019-04-12 21:46:29 +0530790 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 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800798 lg2::error("Group name '{GROUPNAME}' already exists", "GROUPNAME",
799 groupName);
Ratan Gupta7b04c352019-04-12 21:46:29 +0530800 elog<PrivilegeMappingExists>();
801 }
802 }
803}
804
805void Config::checkPrivilegeLevel(const std::string& privilege)
806{
807 if (privilege.empty())
808 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800809 lg2::error("Privilege level is empty");
Ratan Gupta7b04c352019-04-12 21:46:29 +0530810 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege level"),
811 Argument::ARGUMENT_VALUE("Null"));
812 }
813
814 if (std::find(privMgr.begin(), privMgr.end(), privilege) == privMgr.end())
815 {
Jiaqing Zhao11ec6662022-07-05 20:55:34 +0800816 lg2::error("Invalid privilege '{PRIVILEGE}'", "PRIVILEGE", privilege);
817 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege"),
Ratan Gupta7b04c352019-04-12 21:46:29 +0530818 Argument::ARGUMENT_VALUE(privilege.c_str()));
819 }
820}
821
822void Config::restoreRoleMapping()
823{
824 namespace fs = std::filesystem;
825 fs::path dir = parent.dbusPersistentPath;
826 dir += objectPath;
827 dir /= "role_map";
828
829 if (!fs::exists(dir) || fs::is_empty(dir))
830 {
831 return;
832 }
833
834 for (auto& file : fs::directory_iterator(dir))
835 {
836 std::string id = file.path().filename().c_str();
837 size_t idNum = std::stol(id);
838
839 auto entryPath = objectPath + '/' + "role_map" + '/' + id;
840 auto persistPath = parent.dbusPersistentPath + entryPath;
841 auto entry = std::make_unique<LDAPMapperEntry>(
842 bus, entryPath.c_str(), persistPath.c_str(), *this);
843 if (phosphor::ldap::deserialize(file.path(), *entry))
844 {
845 entry->Interfaces::emit_object_added();
846 PrivilegeMapperList.emplace(idNum, std::move(entry));
847 if (idNum > entryId)
848 {
849 entryId = idNum;
850 }
851 }
852 }
853}
854
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -0500855} // namespace ldap
856} // namespace phosphor