1 #include "ldap_config_mgr.hpp" 2 #include "ldap_config.hpp" 3 #include "ldap_config_serialize.hpp" 4 #include "utils.hpp" 5 #include <filesystem> 6 #include <fstream> 7 #include <sstream> 8 9 namespace phosphor 10 { 11 namespace ldap 12 { 13 14 constexpr auto nslcdService = "nslcd.service"; 15 constexpr auto nscdService = "nscd.service"; 16 constexpr auto LDAPscheme = "ldap"; 17 constexpr auto LDAPSscheme = "ldaps"; 18 19 using namespace phosphor::logging; 20 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 21 namespace fs = std::filesystem; 22 using Argument = xyz::openbmc_project::Common::InvalidArgument; 23 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 24 using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed; 25 26 using Line = std::string; 27 using Key = std::string; 28 using Val = std::string; 29 using ConfigInfo = std::map<Key, Val>; 30 31 Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath, 32 const char* caCertFile, bool secureLDAP, 33 std::string lDAPServerURI, std::string lDAPBindDN, 34 std::string lDAPBaseDN, std::string&& lDAPBindDNPassword, 35 ConfigIface::SearchScope lDAPSearchScope, 36 ConfigIface::Type lDAPType, bool lDAPServiceEnabled, 37 std::string userNameAttr, std::string groupNameAttr, 38 ConfigMgr& parent) : 39 Ifaces(bus, path, true), 40 secureLDAP(secureLDAP), lDAPBindPassword(std::move(lDAPBindDNPassword)), 41 configFilePath(filePath), tlsCacertFile(caCertFile), bus(bus), 42 parent(parent) 43 { 44 ConfigIface::lDAPServerURI(lDAPServerURI); 45 ConfigIface::lDAPBindDN(lDAPBindDN); 46 ConfigIface::lDAPBaseDN(lDAPBaseDN); 47 ConfigIface::lDAPSearchScope(lDAPSearchScope); 48 ConfigIface::lDAPType(lDAPType); 49 EnableIface::enabled(lDAPServiceEnabled); 50 ConfigIface::userNameAttribute(userNameAttr); 51 ConfigIface::groupNameAttribute(groupNameAttr); 52 // Don't update the bindDN password under ConfigIface:: 53 writeConfig(); 54 // Emit deferred signal. 55 this->emit_object_added(); 56 parent.startOrStopService(nslcdService, enabled()); 57 } 58 59 void Config::delete_() 60 { 61 parent.deleteObject(); 62 try 63 { 64 fs::path configDir = fs::path(configFilePath.c_str()).parent_path(); 65 66 fs::copy_file(configDir / defaultNslcdFile, LDAP_CONFIG_FILE, 67 fs::copy_options::overwrite_existing); 68 } 69 catch (const std::exception& e) 70 { 71 log<level::ERR>("Failed to rename Config Files while deleting Object", 72 entry("ERR=%s", e.what())); 73 elog<InternalFailure>(); 74 } 75 76 parent.restartService(nscdService); 77 parent.stopService(nslcdService); 78 } 79 80 void Config::writeConfig() 81 { 82 std::stringstream confData; 83 auto isPwdTobeWritten = false; 84 std::string userNameAttr; 85 86 confData << "uid root\n"; 87 confData << "gid root\n\n"; 88 confData << "ldap_version 3\n\n"; 89 confData << "timelimit 30\n"; 90 confData << "bind_timelimit 30\n"; 91 confData << "pagesize 1000\n"; 92 confData << "referrals off\n\n"; 93 confData << "uri " << lDAPServerURI() << "\n\n"; 94 confData << "base " << lDAPBaseDN() << "\n\n"; 95 confData << "binddn " << lDAPBindDN() << "\n"; 96 if (!lDAPBindPassword.empty()) 97 { 98 confData << "bindpw " << lDAPBindPassword << "\n"; 99 isPwdTobeWritten = true; 100 } 101 confData << "\n"; 102 switch (lDAPSearchScope()) 103 { 104 case ConfigIface::SearchScope::sub: 105 confData << "scope sub\n\n"; 106 break; 107 case ConfigIface::SearchScope::one: 108 confData << "scope one\n\n"; 109 break; 110 case ConfigIface::SearchScope::base: 111 confData << "scope base\n\n"; 112 break; 113 } 114 confData << "base passwd " << lDAPBaseDN() << "\n"; 115 confData << "base shadow " << lDAPBaseDN() << "\n\n"; 116 if (secureLDAP == true) 117 { 118 confData << "ssl on\n"; 119 confData << "tls_reqcert hard\n"; 120 confData << "tls_cacertFile " << tlsCacertFile.c_str() << "\n"; 121 } 122 else 123 { 124 confData << "ssl off\n"; 125 } 126 confData << "\n"; 127 if (lDAPType() == ConfigIface::Type::ActiveDirectory) 128 { 129 if (ConfigIface::userNameAttribute().empty()) 130 { 131 ConfigIface::userNameAttribute("sAMAccountName"); 132 } 133 if (ConfigIface::groupNameAttribute().empty()) 134 { 135 ConfigIface::groupNameAttribute("primaryGroupID"); 136 } 137 confData << "filter passwd (&(objectClass=user)(objectClass=person)" 138 "(!(objectClass=computer)))\n"; 139 confData 140 << "filter group (|(objectclass=group)(objectclass=groupofnames) " 141 "(objectclass=groupofuniquenames))\n"; 142 confData << "map passwd uid " 143 << ConfigIface::userNameAttribute() << "\n"; 144 confData << "map passwd uidNumber " 145 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n"; 146 confData << "map passwd gidNumber " 147 << ConfigIface::groupNameAttribute() << "\n"; 148 confData << "map passwd homeDirectory \"/home/$sAMAccountName\"\n"; 149 confData << "map passwd gecos displayName\n"; 150 confData << "map passwd loginShell \"/bin/bash\"\n"; 151 confData << "map group gidNumber " 152 "objectSid:S-1-5-21-3623811015-3361044348-30300820\n"; 153 confData << "map group cn " 154 << ConfigIface::userNameAttribute() << "\n"; 155 } 156 else if (lDAPType() == ConfigIface::Type::OpenLdap) 157 { 158 if (ConfigIface::userNameAttribute().empty()) 159 { 160 ConfigIface::userNameAttribute("cn"); 161 } 162 if (ConfigIface::groupNameAttribute().empty()) 163 { 164 ConfigIface::groupNameAttribute("gidNumber"); 165 } 166 confData << "filter passwd (objectclass=*)\n"; 167 confData << "map passwd gecos displayName\n"; 168 confData << "filter group (objectclass=posixGroup)\n"; 169 confData << "map passwd uid " 170 << ConfigIface::userNameAttribute() << "\n"; 171 confData << "map passwd gidNumber " 172 << ConfigIface::groupNameAttribute() << "\n"; 173 } 174 try 175 { 176 std::fstream stream(configFilePath.c_str(), std::fstream::out); 177 // remove the read permission from others if password is being written. 178 // nslcd forces this behaviour. 179 auto permission = fs::perms::owner_read | fs::perms::owner_write | 180 fs::perms::group_read; 181 if (isPwdTobeWritten) 182 { 183 fs::permissions(configFilePath, permission); 184 } 185 else 186 { 187 fs::permissions(configFilePath, 188 permission | fs::perms::others_read); 189 } 190 191 stream << confData.str(); 192 stream.flush(); 193 stream.close(); 194 } 195 catch (const std::exception& e) 196 { 197 log<level::ERR>(e.what()); 198 elog<InternalFailure>(); 199 } 200 return; 201 } 202 203 std::string Config::lDAPBindDNPassword(std::string value) 204 { 205 // Don't update the D-bus object, this is just to 206 // facilitate if user wants to change the bind dn password 207 // once d-bus object gets created. 208 lDAPBindPassword = value; 209 try 210 { 211 writeConfig(); 212 parent.startOrStopService(nslcdService, enabled()); 213 } 214 catch (const InternalFailure& e) 215 { 216 throw; 217 } 218 catch (const std::exception& e) 219 { 220 log<level::ERR>(e.what()); 221 elog<InternalFailure>(); 222 } 223 return value; 224 } 225 226 std::string Config::lDAPServerURI(std::string value) 227 { 228 std::string val; 229 try 230 { 231 if (value == lDAPServerURI()) 232 { 233 return value; 234 } 235 if (isValidLDAPURI(value, LDAPSscheme)) 236 { 237 secureLDAP = true; 238 } 239 else if (isValidLDAPURI(value, LDAPscheme)) 240 { 241 secureLDAP = false; 242 } 243 else 244 { 245 log<level::ERR>("bad LDAP Server URI", 246 entry("LDAPSERVERURI=%s", value.c_str())); 247 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPServerURI"), 248 Argument::ARGUMENT_VALUE(value.c_str())); 249 } 250 251 if (secureLDAP && !fs::exists(tlsCacertFile.c_str())) 252 { 253 log<level::ERR>("LDAP server's CA certificate not provided", 254 entry("TLSCACERTFILE=%s", tlsCacertFile.c_str())); 255 elog<NoCACertificate>(); 256 } 257 val = ConfigIface::lDAPServerURI(value); 258 writeConfig(); 259 parent.startOrStopService(nslcdService, enabled()); 260 } 261 catch (const InternalFailure& e) 262 { 263 throw; 264 } 265 catch (const InvalidArgument& e) 266 { 267 throw; 268 } 269 catch (const NoCACertificate& e) 270 { 271 throw; 272 } 273 catch (const std::exception& e) 274 { 275 log<level::ERR>(e.what()); 276 elog<InternalFailure>(); 277 } 278 return val; 279 } 280 281 std::string Config::lDAPBindDN(std::string value) 282 { 283 std::string val; 284 try 285 { 286 if (value == lDAPBindDN()) 287 { 288 return value; 289 } 290 291 if (value.empty()) 292 { 293 log<level::ERR>("Not a valid LDAP BINDDN", 294 entry("LDAPBINDDN=%s", value.c_str())); 295 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBindDN"), 296 Argument::ARGUMENT_VALUE(value.c_str())); 297 } 298 299 val = ConfigIface::lDAPBindDN(value); 300 writeConfig(); 301 parent.startOrStopService(nslcdService, enabled()); 302 } 303 catch (const InternalFailure& e) 304 { 305 throw; 306 } 307 catch (const InvalidArgument& e) 308 { 309 throw; 310 } 311 catch (const std::exception& e) 312 { 313 log<level::ERR>(e.what()); 314 elog<InternalFailure>(); 315 } 316 return val; 317 } 318 319 std::string Config::lDAPBaseDN(std::string value) 320 { 321 std::string val; 322 try 323 { 324 if (value == lDAPBaseDN()) 325 { 326 return value; 327 } 328 329 if (value.empty()) 330 { 331 log<level::ERR>("Not a valid LDAP BASEDN", 332 entry("BASEDN=%s", value.c_str())); 333 elog<InvalidArgument>(Argument::ARGUMENT_NAME("lDAPBaseDN"), 334 Argument::ARGUMENT_VALUE(value.c_str())); 335 } 336 337 val = ConfigIface::lDAPBaseDN(value); 338 writeConfig(); 339 parent.startOrStopService(nslcdService, enabled()); 340 } 341 catch (const InternalFailure& e) 342 { 343 throw; 344 } 345 catch (const InvalidArgument& e) 346 { 347 throw; 348 } 349 catch (const std::exception& e) 350 { 351 log<level::ERR>(e.what()); 352 elog<InternalFailure>(); 353 } 354 return val; 355 } 356 357 ConfigIface::SearchScope Config::lDAPSearchScope(ConfigIface::SearchScope value) 358 { 359 ConfigIface::SearchScope val; 360 try 361 { 362 if (value == lDAPSearchScope()) 363 { 364 return value; 365 } 366 367 val = ConfigIface::lDAPSearchScope(value); 368 writeConfig(); 369 parent.startOrStopService(nslcdService, enabled()); 370 } 371 catch (const InternalFailure& e) 372 { 373 throw; 374 } 375 catch (const std::exception& e) 376 { 377 log<level::ERR>(e.what()); 378 elog<InternalFailure>(); 379 } 380 return val; 381 } 382 383 ConfigIface::Type Config::lDAPType(ConfigIface::Type value) 384 { 385 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property")); 386 return lDAPType(); 387 } 388 389 bool Config::enabled(bool value) 390 { 391 bool isEnable; 392 try 393 { 394 if (value == enabled()) 395 { 396 return value; 397 } 398 isEnable = EnableIface::enabled(value); 399 // save the enabled property. 400 serialize(*this, parent.dbusPersistentPath); 401 parent.startOrStopService(nslcdService, value); 402 } 403 catch (const InternalFailure& e) 404 { 405 throw; 406 } 407 catch (const std::exception& e) 408 { 409 log<level::ERR>(e.what()); 410 elog<InternalFailure>(); 411 } 412 return isEnable; 413 } 414 415 std::string Config::userNameAttribute(std::string value) 416 { 417 std::string val; 418 try 419 { 420 if (value == userNameAttribute()) 421 { 422 return value; 423 } 424 425 val = ConfigIface::userNameAttribute(value); 426 writeConfig(); 427 parent.startOrStopService(nslcdService, enabled()); 428 } 429 catch (const InternalFailure& e) 430 { 431 throw; 432 } 433 catch (const std::exception& e) 434 { 435 log<level::ERR>(e.what()); 436 elog<InternalFailure>(); 437 } 438 return val; 439 } 440 441 std::string Config::groupNameAttribute(std::string value) 442 { 443 std::string val; 444 try 445 { 446 if (value == groupNameAttribute()) 447 { 448 return value; 449 } 450 451 val = ConfigIface::groupNameAttribute(value); 452 writeConfig(); 453 parent.startOrStopService(nslcdService, enabled()); 454 } 455 catch (const InternalFailure& e) 456 { 457 throw; 458 } 459 catch (const std::exception& e) 460 { 461 log<level::ERR>(e.what()); 462 elog<InternalFailure>(); 463 } 464 return val; 465 } 466 467 } // namespace ldap 468 } // namespace phosphor 469