1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 #include "json_serializer.hpp" 18 #include "users.hpp" 19 20 #include <sys/wait.h> 21 #include <unistd.h> 22 23 #include <phosphor-logging/elog-errors.hpp> 24 #include <phosphor-logging/elog.hpp> 25 #include <phosphor-logging/lg2.hpp> 26 #include <sdbusplus/bus.hpp> 27 #include <sdbusplus/server/object.hpp> 28 #include <xyz/openbmc_project/Common/error.hpp> 29 #include <xyz/openbmc_project/User/AccountPolicy/server.hpp> 30 #include <xyz/openbmc_project/User/Manager/server.hpp> 31 #include <xyz/openbmc_project/User/MultiFactorAuthConfiguration/server.hpp> 32 #include <xyz/openbmc_project/User/TOTPState/server.hpp> 33 34 #include <span> 35 #include <string> 36 #include <unordered_map> 37 #include <variant> 38 #include <vector> 39 40 namespace phosphor 41 { 42 namespace user 43 { 44 45 inline constexpr size_t ipmiMaxUsers = 15; 46 inline constexpr size_t maxSystemUsers = 30; 47 inline constexpr uint8_t minPasswdLength = 8; 48 extern uint8_t maxPasswdLength; // MAX_PASSWORD_LENGTH; 49 inline constexpr size_t maxSystemGroupNameLength = 32; 50 inline constexpr size_t maxSystemGroupCount = 64; 51 52 using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager; 53 using UserSSHLists = 54 std::pair<std::vector<std::string>, std::vector<std::string>>; 55 using AccountPolicyIface = 56 sdbusplus::xyz::openbmc_project::User::server::AccountPolicy; 57 58 using MultiFactorAuthConfigurationIface = 59 sdbusplus::xyz::openbmc_project::User::server::MultiFactorAuthConfiguration; 60 61 using TOTPStateIface = sdbusplus::xyz::openbmc_project::User::server::TOTPState; 62 63 using Ifaces = sdbusplus::server::object_t<UserMgrIface, AccountPolicyIface, 64 MultiFactorAuthConfigurationIface, 65 TOTPStateIface>; 66 67 using Privilege = std::string; 68 using GroupList = std::vector<std::string>; 69 using UserEnabled = bool; 70 using PropertyName = std::string; 71 using ServiceEnabled = bool; 72 73 using UserInfo = std::variant<Privilege, GroupList, UserEnabled>; 74 using UserInfoMap = std::map<PropertyName, UserInfo>; 75 76 using DbusUserObjPath = sdbusplus::message::object_path; 77 78 using DbusUserPropVariant = std::variant<Privilege, ServiceEnabled>; 79 80 using DbusUserObjProperties = std::map<PropertyName, DbusUserPropVariant>; 81 82 using Interface = std::string; 83 84 using DbusUserObjValue = std::map<Interface, DbusUserObjProperties>; 85 86 using DbusUserObj = std::map<DbusUserObjPath, DbusUserObjValue>; 87 88 using MultiFactorAuthType = sdbusplus::common::xyz::openbmc_project::user:: 89 MultiFactorAuthConfiguration::Type; 90 std::string getCSVFromVector(std::span<const std::string> vec); 91 92 bool removeStringFromCSV(std::string& csvStr, const std::string& delStr); 93 94 template <typename... ArgTypes> 95 std::vector<std::string> executeCmd(const char* path, ArgTypes&&... tArgs) 96 { 97 int pipefd[2]; 98 99 if (pipe(pipefd) == -1) 100 { 101 lg2::error("Failed to create pipe: {ERROR}", "ERROR", strerror(errno)); 102 phosphor::logging::elog< 103 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>(); 104 return {}; 105 } 106 107 pid_t pid = fork(); 108 109 if (pid == -1) 110 { 111 lg2::error("Failed to fork process: {ERROR}", "ERROR", strerror(errno)); 112 phosphor::logging::elog< 113 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>(); 114 close(pipefd[0]); // Close read end of pipe 115 close(pipefd[1]); // Close write end of pipe 116 return {}; 117 } 118 119 if (pid == 0) // Child process 120 { 121 close(pipefd[0]); // Close read end of pipe 122 123 // Redirect write end of the pipe to stdout. 124 if (dup2(pipefd[1], STDOUT_FILENO) == -1) 125 { 126 lg2::error("Failed to redirect stdout: {ERROR}", "ERROR", 127 strerror(errno)); 128 _exit(EXIT_FAILURE); 129 } 130 close(pipefd[1]); // Close write end of pipe 131 132 std::vector<const char*> args = {path}; 133 (args.emplace_back(const_cast<const char*>(tArgs)), ...); 134 args.emplace_back(nullptr); 135 136 execv(path, const_cast<char* const*>(args.data())); 137 138 // If exec returns, an error occurred 139 lg2::error("Failed to execute command '{PATH}': {ERROR}", "PATH", path, 140 "ERROR", strerror(errno)); 141 _exit(EXIT_FAILURE); 142 } 143 144 // Parent process. 145 146 close(pipefd[1]); // Close write end of pipe 147 148 FILE* fp = fdopen(pipefd[0], "r"); 149 if (fp == nullptr) 150 { 151 lg2::error("Failed to open pipe for reading: {ERROR}", "ERROR", 152 strerror(errno)); 153 close(pipefd[0]); 154 phosphor::logging::elog< 155 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>(); 156 return {}; 157 } 158 159 std::vector<std::string> results; 160 char buffer[256]; 161 while (fgets(buffer, sizeof(buffer), fp) != nullptr) 162 { 163 std::string line = buffer; 164 if (!line.empty() && line.back() == '\n') 165 { 166 line.pop_back(); // Remove newline character 167 } 168 results.emplace_back(line); 169 } 170 171 fclose(fp); 172 close(pipefd[0]); 173 174 int status; 175 while (waitpid(pid, &status, 0) == -1) 176 { 177 // Need to retry on EINTR. 178 if (errno == EINTR) 179 { 180 continue; 181 } 182 183 lg2::error("Failed to wait for child process: {ERROR}", "ERROR", 184 strerror(errno)); 185 phosphor::logging::elog< 186 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>(); 187 return {}; 188 } 189 190 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 191 { 192 lg2::error("Command {PATH} execution failed, return code {RETCODE}", 193 "PATH", path, "RETCODE", WEXITSTATUS(status)); 194 phosphor::logging::elog< 195 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>(); 196 } 197 198 return results; 199 } 200 201 /** @class UserMgr 202 * @brief Responsible for managing user accounts over the D-Bus interface. 203 */ 204 class UserMgr : public Ifaces 205 { 206 public: 207 UserMgr() = delete; 208 ~UserMgr() = default; 209 UserMgr(const UserMgr&) = delete; 210 UserMgr& operator=(const UserMgr&) = delete; 211 UserMgr(UserMgr&&) = delete; 212 UserMgr& operator=(UserMgr&&) = delete; 213 214 /** @brief Constructs UserMgr object. 215 * 216 * @param[in] bus - sdbusplus handler 217 * @param[in] path - D-Bus path 218 */ 219 UserMgr(sdbusplus::bus_t& bus, const char* path); 220 221 /** @brief create user method. 222 * This method creates a new user as requested 223 * 224 * @param[in] userName - Name of the user which has to be created 225 * @param[in] groupNames - Group names list, to which user has to be added. 226 * @param[in] priv - Privilege of the user. 227 * @param[in] enabled - State of the user enabled / disabled. 228 */ 229 void createUser(std::string userName, std::vector<std::string> groupNames, 230 std::string priv, bool enabled) override; 231 232 /** @brief rename user method. 233 * This method renames the user as requested 234 * 235 * @param[in] userName - current name of the user 236 * @param[in] newUserName - new user name to which it has to be renamed. 237 */ 238 void renameUser(std::string userName, std::string newUserName) override; 239 240 /** @brief delete user method. 241 * This method deletes the user as requested 242 * 243 * @param[in] userName - Name of the user which has to be deleted 244 */ 245 void deleteUser(std::string userName); 246 247 /** @brief Update user groups & privilege. 248 * This method updates user groups & privilege 249 * 250 * @param[in] userName - user name, for which update is requested 251 * @param[in] groupName - Group to be updated.. 252 * @param[in] priv - Privilege to be updated. 253 */ 254 void updateGroupsAndPriv(const std::string& userName, 255 std::vector<std::string> groups, 256 const std::string& priv); 257 258 /** @brief Update user enabled state. 259 * This method enables / disables user 260 * 261 * @param[in] userName - user name, for which update is requested 262 * @param[in] enabled - enable / disable the user 263 */ 264 void userEnable(const std::string& userName, bool enabled); 265 266 /** @brief get user enabled state 267 * method to get user enabled state. 268 * 269 * @param[in] userName - name of the user 270 * @return - user enabled status (true/false) 271 */ 272 virtual bool isUserEnabled(const std::string& userName); 273 274 /** @brief update minimum password length requirement 275 * 276 * @param[in] val - minimum password length 277 * @return - minimum password length 278 */ 279 uint8_t minPasswordLength(uint8_t val) override; 280 281 /** @brief update old password history count 282 * 283 * @param[in] val - number of times old passwords has to be avoided 284 * @return - number of times old password has to be avoided 285 */ 286 uint8_t rememberOldPasswordTimes(uint8_t val) override; 287 288 /** @brief update maximum number of failed login attempt before locked 289 * out. 290 * 291 * @param[in] val - number of allowed attempt 292 * @return - number of allowed attempt 293 */ 294 uint16_t maxLoginAttemptBeforeLockout(uint16_t val) override; 295 296 /** @brief update timeout to unlock the account 297 * 298 * @param[in] val - value in seconds 299 * @return - value in seconds 300 */ 301 uint32_t accountUnlockTimeout(uint32_t val) override; 302 303 /** @brief parses the faillock output for locked user status 304 * 305 * @param[in] - output from faillock for the user 306 * @return - true / false indicating user locked / un-locked 307 **/ 308 bool parseFaillockForLockout( 309 const std::vector<std::string>& faillockOutput); 310 311 /** @brief lists user locked state for failed attempt 312 * 313 * @param[in] - user name 314 * @return - true / false indicating user locked / un-locked 315 **/ 316 virtual bool userLockedForFailedAttempt(const std::string& userName); 317 318 /** @brief lists user locked state for failed attempt 319 * 320 * @param[in]: user name 321 * @param[in]: value - false -unlock user account, true - no action taken 322 **/ 323 bool userLockedForFailedAttempt(const std::string& userName, 324 const bool& value); 325 326 /** @brief shows if the user's password is expired 327 * 328 * @param[in]: user name 329 * @return - true / false indicating user password expired 330 **/ 331 virtual bool userPasswordExpired(const std::string& userName); 332 333 /** @brief returns user info 334 * Checks if user is local user, then returns map of properties of user. 335 * like user privilege, list of user groups, user enabled state and user 336 * locked state. If its not local user, then it checks if its a ldap user, 337 * then it gets the privilege mapping of the LDAP group. 338 * 339 * @param[in] - user name 340 * @return - map of user properties 341 **/ 342 UserInfoMap getUserInfo(std::string userName) override; 343 344 /** @brief get IPMI user count 345 * method to get IPMI user count 346 * 347 * @return - returns user count 348 */ 349 virtual size_t getIpmiUsersCount(void); 350 351 void createGroup(std::string groupName) override; 352 353 void deleteGroup(std::string groupName) override; 354 MultiFactorAuthType enabled() const override 355 { 356 return MultiFactorAuthConfigurationIface::enabled(); 357 } 358 MultiFactorAuthType enabled(MultiFactorAuthType value, 359 bool skipSignal) override; 360 bool secretKeyRequired(std::string userName) override; 361 static std::vector<std::string> readAllGroupsOnSystem(); 362 void load(); 363 JsonSerializer& getSerializer() 364 { 365 return serializer; 366 } 367 368 protected: 369 /** @brief get pam argument value 370 * method to get argument value from pam configuration 371 * 372 * @param[in] moduleName - name of the module from where arg has to be read 373 * @param[in] argName - argument name 374 * @param[out] argValue - argument value 375 * 376 * @return 0 - success state of the function 377 */ 378 int getPamModuleArgValue(const std::string& moduleName, 379 const std::string& argName, std::string& argValue); 380 381 /** @brief get pam argument value 382 * method to get argument value from pam configuration 383 * 384 * @param[in] confFile - path of the module config file from where arg has 385 * to be read 386 * @param[in] argName - argument name 387 * @param[out] argValue - argument value 388 * 389 * @return 0 - success state of the function 390 */ 391 int getPamModuleConfValue(const std::string& confFile, 392 const std::string& argName, 393 std::string& argValue); 394 395 /** @brief set pam argument value 396 * method to set argument value in pam configuration 397 * 398 * @param[in] moduleName - name of the module in which argument value has 399 * to be set 400 * @param[in] argName - argument name 401 * @param[out] argValue - argument value 402 * 403 * @return 0 - success state of the function 404 */ 405 int setPamModuleArgValue(const std::string& moduleName, 406 const std::string& argName, 407 const std::string& argValue); 408 409 /** @brief set pam argument value 410 * method to set argument value in pam configuration 411 * 412 * @param[in] confFile - path of the module config file in which argument 413 * value has to be set 414 * @param[in] argName - argument name 415 * @param[out] argValue - argument value 416 * 417 * @return 0 - success state of the function 418 */ 419 int setPamModuleConfValue(const std::string& confFile, 420 const std::string& argName, 421 const std::string& argValue); 422 423 /** @brief check for user presence 424 * method to check for user existence 425 * 426 * @param[in] userName - name of the user 427 * @return -true if user exists and false if not. 428 */ 429 bool isUserExist(const std::string& userName); 430 431 size_t getNonIpmiUsersCount(); 432 433 /** @brief check user exists 434 * method to check whether user exist, and throw if not. 435 * 436 * @param[in] userName - name of the user 437 */ 438 void throwForUserDoesNotExist(const std::string& userName); 439 440 /** @brief check user does not exist 441 * method to check whether does not exist, and throw if exists. 442 * 443 * @param[in] userName - name of the user 444 */ 445 void throwForUserExists(const std::string& userName); 446 447 /** @brief check user name constraints 448 * method to check user name constraints and throw if failed. 449 * 450 * @param[in] userName - name of the user 451 * @param[in] groupNames - user groups 452 */ 453 void throwForUserNameConstraints( 454 const std::string& userName, 455 const std::vector<std::string>& groupNames); 456 457 /** @brief check group user count 458 * method to check max group user count, and throw if limit reached 459 * 460 * @param[in] groupNames - group name 461 */ 462 void throwForMaxGrpUserCount(const std::vector<std::string>& groupNames); 463 464 virtual void executeUserAdd(const char* userName, const char* groups, 465 bool sshRequested, bool enabled); 466 467 virtual void executeUserDelete(const char* userName); 468 469 /** @brief clear user's failure records 470 * method to clear user fail records and throw if failed. 471 * 472 * @param[in] userName - name of the user 473 */ 474 virtual void executeUserClearFailRecords(const char* userName); 475 476 virtual void executeUserRename(const char* userName, 477 const char* newUserName); 478 479 virtual void executeUserModify(const char* userName, const char* newGroups, 480 bool sshRequested); 481 482 virtual void executeUserModifyUserEnable(const char* userName, 483 bool enabled); 484 485 virtual void executeGroupCreation(const char* groupName); 486 487 virtual void executeGroupDeletion(const char* groupName); 488 489 virtual std::vector<std::string> getFailedAttempt(const char* userName); 490 491 /** @brief check for valid privielge 492 * method to check valid privilege, and throw if invalid 493 * 494 * @param[in] priv - privilege of the user 495 */ 496 void throwForInvalidPrivilege(const std::string& priv); 497 498 /** @brief check for valid groups 499 * method to check valid groups, and throw if invalid 500 * 501 * @param[in] groupNames - user groups 502 */ 503 void throwForInvalidGroups(const std::vector<std::string>& groupName); 504 505 void initializeAccountPolicy(); 506 507 /** @brief checks if the group creation meets all constraints 508 * @param groupName - group to check 509 */ 510 void checkCreateGroupConstraints(const std::string& groupName); 511 512 /** @brief checks if the group deletion meets all constraints 513 * @param groupName - group to check 514 */ 515 void checkDeleteGroupConstraints(const std::string& groupName); 516 517 /** @brief checks if the group name is legal and whether it's allowed to 518 * change. The daemon doesn't allow arbitrary group to be created 519 * @param groupName - group to check 520 */ 521 void checkAndThrowForDisallowedGroupCreation(const std::string& groupName); 522 523 private: 524 /** @brief sdbusplus handler */ 525 sdbusplus::bus_t& bus; 526 527 /** @brief object path */ 528 const std::string path; 529 530 /** @brief serializer for mfa */ 531 JsonSerializer serializer; 532 /** @brief privilege manager container */ 533 const std::vector<std::string> privMgr = {"priv-admin", "priv-operator", 534 "priv-user"}; 535 536 /** @brief groups manager container */ 537 std::vector<std::string> groupsMgr; 538 539 /** @brief map container to hold users object */ 540 541 std::unordered_map<std::string, std::unique_ptr<phosphor::user::Users>> 542 usersList; 543 544 /** @brief get users in group 545 * method to get group user list 546 * 547 * @param[in] groupName - group name 548 * 549 * @return userList - list of users in the group. 550 */ 551 std::vector<std::string> getUsersInGroup(const std::string& groupName); 552 553 /** @brief get user & SSH users list 554 * method to get the users and ssh users list. 555 * 556 *@return - vector of User & SSH user lists 557 */ 558 UserSSHLists getUserAndSshGrpList(void); 559 560 /** @brief initialize the user manager objects 561 * method to initialize the user manager objects accordingly 562 * 563 */ 564 void initUserObjects(void); 565 566 /** @brief get service name 567 * method to get dbus service name 568 * 569 * @param[in] path - object path 570 * @param[in] intf - interface 571 * @return - service name 572 */ 573 std::string getServiceName(std::string&& path, std::string&& intf); 574 575 /** @brief get primary group ID of specified user 576 * 577 * @param[in] - userName 578 * @return - primary group ID 579 */ 580 virtual gid_t getPrimaryGroup(const std::string& userName) const; 581 582 /** @brief check whether if the user is a member of the group 583 * 584 * @param[in] - userName 585 * @param[in] - ID of the user's primary group 586 * @param[in] - groupName 587 * @return - true if the user is a member of the group 588 */ 589 virtual bool isGroupMember(const std::string& userName, gid_t primaryGid, 590 const std::string& groupName) const; 591 592 protected: 593 /** @brief get privilege mapper object 594 * method to get dbus privilege mapper object 595 * 596 * @return - map of user object 597 */ 598 virtual DbusUserObj getPrivilegeMapperObject(void); 599 600 friend class TestUserMgr; 601 602 std::string faillockConfigFile; 603 std::string pwHistoryConfigFile; 604 std::string pwQualityConfigFile; 605 }; 606 607 } // namespace user 608 } // namespace phosphor 609