blob: 51b785aebb2edf98e699e981278ba9b7e6c91abb [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";
Nagaraju Gorugantidccee2b2018-09-25 08:51:06 -050028constexpr auto nscdService = "nscd.service";
Nagaraju Goruganti59287f02018-10-12 07:00:20 -050029constexpr auto LDAPscheme = "ldap";
30constexpr auto LDAPSscheme = "ldaps";
Ratan Guptaab4fcb42019-04-29 19:39:51 +053031constexpr auto certObjPath = "/xyz/openbmc_project/certs/client/ldap/1";
32constexpr auto certRootPath = "/xyz/openbmc_project/certs/client/ldap";
manojkiranedaa47fe4e2019-05-23 21:28:33 +053033constexpr auto authObjPath = "/xyz/openbmc_project/certs/authority/ldap";
Ratan Guptaab4fcb42019-04-29 19:39:51 +053034constexpr auto certIface = "xyz.openbmc_project.Certs.Certificate";
35constexpr auto certProperty = "CertificateString";
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050036
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050037using namespace phosphor::logging;
38using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Ratan Gupta95a29312019-02-18 20:34:10 +053039namespace fs = std::filesystem;
Ratan Gupta7b04c352019-04-12 21:46:29 +053040
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -050041using Argument = xyz::openbmc_project::Common::InvalidArgument;
Ratan Gupta27d4c012019-04-12 13:03:35 +053042using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
43using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed;
Ratan Gupta7b04c352019-04-12 21:46:29 +053044using PrivilegeMappingExists = sdbusplus::xyz::openbmc_project::User::Common::
45 Error::PrivilegeMappingExists;
Nagaraju Gorugantif1940d92018-09-18 05:05:50 -050046
47using Line = std::string;
48using Key = std::string;
49using Val = std::string;
50using ConfigInfo = std::map<Key, Val>;
51
Nagaraju Goruganti997f5e02018-08-30 03:05:11 -050052Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
Ratan Gupta22f13f12019-04-29 15:36:40 +053053 const char* caCertFile, const char* certFile, bool secureLDAP,
Patrick Williamse6500a42021-05-01 05:58:23 -050054 std::string ldapServerURI, std::string ldapBindDN,
55 std::string ldapBaseDN, std::string&& ldapBindDNPassword,
56 ConfigIface::SearchScope ldapSearchScope,
57 ConfigIface::Type ldapType, bool ldapServiceEnabled,
Ratan Guptaaeaf9412019-02-11 04:41:52 -060058 std::string userNameAttr, std::string groupNameAttr,
59 ConfigMgr& parent) :
60 Ifaces(bus, path, true),
Patrick Williamse6500a42021-05-01 05:58:23 -050061 secureLDAP(secureLDAP), ldapBindPassword(std::move(ldapBindDNPassword)),
Ratan Gupta22f13f12019-04-29 15:36:40 +053062 tlsCacertFile(caCertFile), tlsCertFile(certFile), configFilePath(filePath),
63 objectPath(path), bus(bus), parent(parent),
64 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
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530109Config::Config(sdbusplus::bus::bus& 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) :
Ratan Gupta21e88cb2019-04-12 17:15:52 +0530112 Ifaces(bus, path, true),
Ravi Tejad5884042019-06-10 02:35:22 -0500113 secureLDAP(false), tlsCacertFile(caCertFile), tlsCertFile(certFile),
114 configFilePath(filePath), 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
Ratan Gupta22f13f12019-04-29 15:36:40 +0530140void Config::certificateInstalled(sdbusplus::message::message& msg)
141{
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 {
156 log<level::ERR>(e.what());
157 elog<InternalFailure>();
158 }
159}
160
Ratan Guptaab4fcb42019-04-29 19:39:51 +0530161void Config::certificateChanged(sdbusplus::message::message& msg)
162{
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 {
174
175 writeConfig();
176 }
177 parent.startOrStopService(nslcdService, enabled());
178 }
179 catch (const InternalFailure& e)
180 {
181 throw;
182 }
183 catch (const std::exception& e)
184 {
185 log<level::ERR>(e.what());
186 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";
274 confData << "map passwd loginShell \"/bin/bash\"\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";
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 }
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500365 if (isValidLDAPURI(value, LDAPSscheme))
Nagaraju Gorugantib26799a2018-09-28 13:12:19 -0500366 {
Nagaraju Goruganti59287f02018-10-12 07:00:20 -0500367 secureLDAP = true;
368 }
369 else if (isValidLDAPURI(value, LDAPscheme))
370 {
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
Patrick Williamse6500a42021-05-01 05:58:23 -0500534ConfigIface::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>
643void Config::save(Archive& archive, const std::uint32_t version) const
644{
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>
656void Config::load(Archive& archive, const std::uint32_t version)
657{
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
Patrick Williamse6500a42021-05-01 05:58:23 -0500720 if (isValidLDAPURI(ldapServerURI(), LDAPscheme))
Ravi Tejad5884042019-06-10 02:35:22 -0500721 {
722 secureLDAP = false;
723 }
Patrick Williamse6500a42021-05-01 05:58:23 -0500724 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 }
732 catch (cereal::Exception& e)
733 {
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