Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 1 | #include "ldap_config_mgr.hpp" |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 2 | |
Patrick Williams | 9638afb | 2021-02-22 17:16:24 -0600 | [diff] [blame] | 3 | #include "ldap_config.hpp" |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 4 | #include "utils.hpp" |
Patrick Williams | 9638afb | 2021-02-22 17:16:24 -0600 | [diff] [blame] | 5 | |
Jiaqing Zhao | e8d664d | 2022-07-05 21:22:54 +0800 | [diff] [blame] | 6 | #include <phosphor-logging/elog-errors.hpp> |
| 7 | #include <phosphor-logging/elog.hpp> |
| 8 | #include <phosphor-logging/lg2.hpp> |
| 9 | #include <xyz/openbmc_project/Common/error.hpp> |
| 10 | |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 11 | #include <filesystem> |
| 12 | #include <fstream> |
| 13 | #include <sstream> |
| 14 | |
| 15 | namespace phosphor |
| 16 | { |
| 17 | namespace ldap |
| 18 | { |
| 19 | |
Ravi Teja | af1594c | 2024-04-27 13:11:54 -0500 | [diff] [blame] | 20 | constexpr auto systemdBusname = "org.freedesktop.systemd1"; |
| 21 | constexpr auto systemdObjPath = "/org/freedesktop/systemd1"; |
| 22 | constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager"; |
| 23 | |
Alexander Filippov | 372c566 | 2021-06-30 20:23:39 +0300 | [diff] [blame] | 24 | constexpr auto nslcdService = "nslcd.service"; |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 25 | constexpr auto nscdService = "nscd.service"; |
Nan Zhou | 78d8504 | 2022-08-29 17:50:22 +0000 | [diff] [blame] | 26 | constexpr auto ldapScheme = "ldap"; |
| 27 | constexpr auto ldapsScheme = "ldaps"; |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 28 | |
Jiaqing Zhao | e8d664d | 2022-07-05 21:22:54 +0800 | [diff] [blame] | 29 | using namespace phosphor::logging; |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 30 | using namespace sdbusplus::xyz::openbmc_project::Common::Error; |
| 31 | namespace fs = std::filesystem; |
| 32 | using Argument = xyz::openbmc_project::Common::InvalidArgument; |
Ratan Gupta | c5481d1 | 2019-04-12 18:31:05 +0530 | [diff] [blame] | 33 | using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed; |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 34 | |
| 35 | using Line = std::string; |
| 36 | using Key = std::string; |
| 37 | using Val = std::string; |
| 38 | using ConfigInfo = std::map<Key, Val>; |
| 39 | |
| 40 | void ConfigMgr::startOrStopService(const std::string& service, bool start) |
| 41 | { |
| 42 | if (start) |
| 43 | { |
| 44 | restartService(service); |
| 45 | } |
| 46 | else |
| 47 | { |
| 48 | stopService(service); |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | void ConfigMgr::restartService(const std::string& service) |
| 53 | { |
| 54 | try |
| 55 | { |
Ravi Teja | af1594c | 2024-04-27 13:11:54 -0500 | [diff] [blame] | 56 | auto method = bus.new_method_call(systemdBusname, systemdObjPath, |
| 57 | systemdInterface, "RestartUnit"); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 58 | method.append(service.c_str(), "replace"); |
| 59 | bus.call_noreply(method); |
| 60 | } |
Patrick Williams | b3ef4e1 | 2022-07-22 19:26:55 -0500 | [diff] [blame] | 61 | catch (const sdbusplus::exception_t& ex) |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 62 | { |
Jiaqing Zhao | 11ec666 | 2022-07-05 20:55:34 +0800 | [diff] [blame] | 63 | lg2::error("Failed to restart service {SERVICE}: {ERR}", "SERVICE", |
| 64 | service, "ERR", ex); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 65 | elog<InternalFailure>(); |
| 66 | } |
| 67 | } |
| 68 | void ConfigMgr::stopService(const std::string& service) |
| 69 | { |
| 70 | try |
| 71 | { |
Ravi Teja | af1594c | 2024-04-27 13:11:54 -0500 | [diff] [blame] | 72 | auto method = bus.new_method_call(systemdBusname, systemdObjPath, |
| 73 | systemdInterface, "StopUnit"); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 74 | method.append(service.c_str(), "replace"); |
| 75 | bus.call_noreply(method); |
| 76 | } |
Patrick Williams | b3ef4e1 | 2022-07-22 19:26:55 -0500 | [diff] [blame] | 77 | catch (const sdbusplus::exception_t& ex) |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 78 | { |
Jiaqing Zhao | 11ec666 | 2022-07-05 20:55:34 +0800 | [diff] [blame] | 79 | lg2::error("Failed to stop service {SERVICE}: {ERR}", "SERVICE", |
| 80 | service, "ERR", ex); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 81 | elog<InternalFailure>(); |
| 82 | } |
| 83 | } |
| 84 | |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 85 | std::string ConfigMgr::createConfig( |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 86 | std::string ldapServerURI, std::string ldapBindDN, std::string ldapBaseDN, |
| 87 | std::string ldapBindDNPassword, CreateIface::SearchScope ldapSearchScope, |
| 88 | CreateIface::Create::Type ldapType, std::string groupNameAttribute, |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 89 | std::string userNameAttribute) |
| 90 | { |
| 91 | bool secureLDAP = false; |
| 92 | |
Nan Zhou | 78d8504 | 2022-08-29 17:50:22 +0000 | [diff] [blame] | 93 | if (isValidLDAPURI(ldapServerURI, ldapsScheme)) |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 94 | { |
| 95 | secureLDAP = true; |
| 96 | } |
Nan Zhou | 78d8504 | 2022-08-29 17:50:22 +0000 | [diff] [blame] | 97 | else if (isValidLDAPURI(ldapServerURI, ldapScheme)) |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 98 | { |
| 99 | secureLDAP = false; |
| 100 | } |
| 101 | else |
| 102 | { |
Jiaqing Zhao | 11ec666 | 2022-07-05 20:55:34 +0800 | [diff] [blame] | 103 | lg2::error("Bad LDAP Server URI {URI}", "URI", ldapServerURI); |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 104 | elog<InvalidArgument>(Argument::ARGUMENT_NAME("ldapServerURI"), |
| 105 | Argument::ARGUMENT_VALUE(ldapServerURI.c_str())); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | if (secureLDAP && !fs::exists(tlsCacertFile.c_str())) |
| 109 | { |
Jiaqing Zhao | 11ec666 | 2022-07-05 20:55:34 +0800 | [diff] [blame] | 110 | lg2::error("LDAP server CA certificate not found at {PATH}", "PATH", |
| 111 | tlsCacertFile); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 112 | elog<NoCACertificate>(); |
| 113 | } |
| 114 | |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 115 | if (ldapBindDN.empty()) |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 116 | { |
Jiaqing Zhao | 11ec666 | 2022-07-05 20:55:34 +0800 | [diff] [blame] | 117 | lg2::error("'{BINDDN}' is not a valid LDAP BindDN", "BINDDN", |
| 118 | ldapBindDN); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 119 | elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBindDN"), |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 120 | Argument::ARGUMENT_VALUE(ldapBindDN.c_str())); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 121 | } |
| 122 | |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 123 | if (ldapBaseDN.empty()) |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 124 | { |
Jiaqing Zhao | 11ec666 | 2022-07-05 20:55:34 +0800 | [diff] [blame] | 125 | lg2::error("'{BASEDN}' is not a valid LDAP BaseDN", "BASEDN", |
| 126 | ldapBaseDN); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 127 | elog<InvalidArgument>(Argument::ARGUMENT_NAME("LDAPBaseDN"), |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 128 | Argument::ARGUMENT_VALUE(ldapBaseDN.c_str())); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 129 | } |
| 130 | |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 131 | // With current implementation we support only two default LDAP server. |
| 132 | // which will be always there but when the support comes for additional |
| 133 | // account providers then the create config would be used to create the |
| 134 | // additional config. |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 135 | |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 136 | std::string objPath; |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 137 | |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 138 | if (static_cast<ConfigIface::Type>(ldapType) == ConfigIface::Type::OpenLdap) |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 139 | { |
| 140 | openLDAPConfigPtr.reset(nullptr); |
| 141 | objPath = openLDAPDbusObjectPath; |
| 142 | openLDAPConfigPtr = std::make_unique<Config>( |
| 143 | bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(), |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 144 | tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN, |
| 145 | ldapBaseDN, std::move(ldapBindDNPassword), |
| 146 | static_cast<ConfigIface::SearchScope>(ldapSearchScope), |
| 147 | static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute, |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 148 | userNameAttribute, *this); |
| 149 | } |
| 150 | else |
| 151 | { |
| 152 | ADConfigPtr.reset(nullptr); |
Nan Zhou | 78d8504 | 2022-08-29 17:50:22 +0000 | [diff] [blame] | 153 | objPath = adDbusObjectPath; |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 154 | ADConfigPtr = std::make_unique<Config>( |
| 155 | bus, objPath.c_str(), configFilePath.c_str(), tlsCacertFile.c_str(), |
Patrick Williams | e6500a4 | 2021-05-01 05:58:23 -0500 | [diff] [blame] | 156 | tlsCertFile.c_str(), secureLDAP, ldapServerURI, ldapBindDN, |
| 157 | ldapBaseDN, std::move(ldapBindDNPassword), |
| 158 | static_cast<ConfigIface::SearchScope>(ldapSearchScope), |
| 159 | static_cast<ConfigIface::Type>(ldapType), false, groupNameAttribute, |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 160 | userNameAttribute, *this); |
| 161 | } |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 162 | restartService(nscdService); |
| 163 | return objPath; |
| 164 | } |
| 165 | |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 166 | void ConfigMgr::createDefaultObjects() |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 167 | { |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 168 | if (!openLDAPConfigPtr) |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 169 | { |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 170 | openLDAPConfigPtr = std::make_unique<Config>( |
| 171 | bus, openLDAPDbusObjectPath.c_str(), configFilePath.c_str(), |
Ratan Gupta | ab4fcb4 | 2019-04-29 19:39:51 +0530 | [diff] [blame] | 172 | tlsCacertFile.c_str(), tlsCertFile.c_str(), |
| 173 | ConfigIface::Type::OpenLdap, *this); |
Ratan Gupta | 21e88cb | 2019-04-12 17:15:52 +0530 | [diff] [blame] | 174 | openLDAPConfigPtr->emit_object_added(); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 175 | } |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 176 | if (!ADConfigPtr) |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 177 | { |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 178 | ADConfigPtr = std::make_unique<Config>( |
Nan Zhou | 78d8504 | 2022-08-29 17:50:22 +0000 | [diff] [blame] | 179 | bus, adDbusObjectPath.c_str(), configFilePath.c_str(), |
Ratan Gupta | ab4fcb4 | 2019-04-29 19:39:51 +0530 | [diff] [blame] | 180 | tlsCacertFile.c_str(), tlsCertFile.c_str(), |
| 181 | ConfigIface::Type::ActiveDirectory, *this); |
Ratan Gupta | 21e88cb | 2019-04-12 17:15:52 +0530 | [diff] [blame] | 182 | ADConfigPtr->emit_object_added(); |
| 183 | } |
| 184 | } |
| 185 | |
Ratan Gupta | c5481d1 | 2019-04-12 18:31:05 +0530 | [diff] [blame] | 186 | bool ConfigMgr::enableService(Config& config, bool value) |
| 187 | { |
| 188 | if (value) |
| 189 | { |
| 190 | if (openLDAPConfigPtr && openLDAPConfigPtr->enabled()) |
| 191 | { |
| 192 | elog<NotAllowed>(NotAllowedArgument::REASON( |
| 193 | "OpenLDAP service is already active")); |
| 194 | } |
| 195 | if (ADConfigPtr && ADConfigPtr->enabled()) |
| 196 | { |
| 197 | elog<NotAllowed>(NotAllowedArgument::REASON( |
| 198 | "ActiveDirectory service is already active")); |
| 199 | } |
| 200 | } |
| 201 | return config.enableService(value); |
| 202 | } |
| 203 | |
Ratan Gupta | 21e88cb | 2019-04-12 17:15:52 +0530 | [diff] [blame] | 204 | void ConfigMgr::restore() |
| 205 | { |
| 206 | createDefaultObjects(); |
| 207 | // Restore the ldap config and their mappings |
| 208 | if (ADConfigPtr->deserialize()) |
| 209 | { |
Ratan Gupta | 7b04c35 | 2019-04-12 21:46:29 +0530 | [diff] [blame] | 210 | // Restore the role mappings |
| 211 | ADConfigPtr->restoreRoleMapping(); |
Ratan Gupta | 21e88cb | 2019-04-12 17:15:52 +0530 | [diff] [blame] | 212 | ADConfigPtr->emit_object_added(); |
| 213 | } |
| 214 | if (openLDAPConfigPtr->deserialize()) |
| 215 | { |
Ratan Gupta | 7b04c35 | 2019-04-12 21:46:29 +0530 | [diff] [blame] | 216 | // Restore the role mappings |
| 217 | openLDAPConfigPtr->restoreRoleMapping(); |
Ratan Gupta | 21e88cb | 2019-04-12 17:15:52 +0530 | [diff] [blame] | 218 | openLDAPConfigPtr->emit_object_added(); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 219 | } |
Alexander Filippov | 372c566 | 2021-06-30 20:23:39 +0300 | [diff] [blame] | 220 | |
| 221 | startOrStopService(phosphor::ldap::nslcdService, |
| 222 | ADConfigPtr->enabled() || openLDAPConfigPtr->enabled()); |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 223 | } |
Ratan Gupta | 27d4c01 | 2019-04-12 13:03:35 +0530 | [diff] [blame] | 224 | |
Ratan Gupta | e1f4db6 | 2019-04-11 18:57:42 +0530 | [diff] [blame] | 225 | } // namespace ldap |
| 226 | } // namespace phosphor |