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 #include "user_mgmt.hpp" 17 18 #include "apphandler.hpp" 19 #include "channel_layer.hpp" 20 #include "channel_mgmt.hpp" 21 22 #include <security/pam_appl.h> 23 #include <sys/stat.h> 24 #include <unistd.h> 25 26 #include <boost/interprocess/sync/named_recursive_mutex.hpp> 27 #include <boost/interprocess/sync/scoped_lock.hpp> 28 #include <cerrno> 29 #include <fstream> 30 #include <nlohmann/json.hpp> 31 #include <phosphor-logging/elog-errors.hpp> 32 #include <phosphor-logging/log.hpp> 33 #include <regex> 34 #include <sdbusplus/bus/match.hpp> 35 #include <sdbusplus/server/object.hpp> 36 #include <variant> 37 #include <xyz/openbmc_project/Common/error.hpp> 38 #include <xyz/openbmc_project/User/Common/error.hpp> 39 40 namespace ipmi 41 { 42 43 // TODO: Move D-Bus & Object Manager related stuff, to common files 44 // D-Bus property related 45 static constexpr const char* dBusPropertiesInterface = 46 "org.freedesktop.DBus.Properties"; 47 static constexpr const char* getAllPropertiesMethod = "GetAll"; 48 static constexpr const char* propertiesChangedSignal = "PropertiesChanged"; 49 static constexpr const char* setPropertiesMethod = "Set"; 50 51 // Object Manager related 52 static constexpr const char* dBusObjManager = 53 "org.freedesktop.DBus.ObjectManager"; 54 static constexpr const char* getManagedObjectsMethod = "GetManagedObjects"; 55 // Object Manager signals 56 static constexpr const char* intfAddedSignal = "InterfacesAdded"; 57 static constexpr const char* intfRemovedSignal = "InterfacesRemoved"; 58 59 // Object Mapper related 60 static constexpr const char* objMapperService = 61 "xyz.openbmc_project.ObjectMapper"; 62 static constexpr const char* objMapperPath = 63 "/xyz/openbmc_project/object_mapper"; 64 static constexpr const char* objMapperInterface = 65 "xyz.openbmc_project.ObjectMapper"; 66 static constexpr const char* getSubTreeMethod = "GetSubTree"; 67 static constexpr const char* getObjectMethod = "GetObject"; 68 69 static constexpr const char* ipmiUserMutex = "ipmi_usr_mutex"; 70 static constexpr const char* ipmiMutexCleanupLockFile = 71 "/var/lib/ipmi/ipmi_usr_mutex_cleanup"; 72 static constexpr const char* ipmiUserDataFile = "/var/lib/ipmi/ipmi_user.json"; 73 static constexpr const char* ipmiGrpName = "ipmi"; 74 static constexpr size_t privNoAccess = 0xF; 75 static constexpr size_t privMask = 0xF; 76 77 // User manager related 78 static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user"; 79 static constexpr const char* userObjBasePath = "/xyz/openbmc_project/user"; 80 static constexpr const char* userMgrInterface = 81 "xyz.openbmc_project.User.Manager"; 82 static constexpr const char* usersInterface = 83 "xyz.openbmc_project.User.Attributes"; 84 static constexpr const char* deleteUserInterface = 85 "xyz.openbmc_project.Object.Delete"; 86 87 static constexpr const char* createUserMethod = "CreateUser"; 88 static constexpr const char* deleteUserMethod = "Delete"; 89 static constexpr const char* renameUserMethod = "RenameUser"; 90 // User manager signal memebers 91 static constexpr const char* userRenamedSignal = "UserRenamed"; 92 // Mgr interface properties 93 static constexpr const char* allPrivProperty = "AllPrivileges"; 94 static constexpr const char* allGrpProperty = "AllGroups"; 95 // User interface properties 96 static constexpr const char* userPrivProperty = "UserPrivilege"; 97 static constexpr const char* userGrpProperty = "UserGroups"; 98 static constexpr const char* userEnabledProperty = "UserEnabled"; 99 100 static std::array<std::string, (PRIVILEGE_OEM + 1)> ipmiPrivIndex = { 101 "priv-reserved", // PRIVILEGE_RESERVED - 0 102 "priv-callback", // PRIVILEGE_CALLBACK - 1 103 "priv-user", // PRIVILEGE_USER - 2 104 "priv-operator", // PRIVILEGE_OPERATOR - 3 105 "priv-admin", // PRIVILEGE_ADMIN - 4 106 "priv-custom" // PRIVILEGE_OEM - 5 107 }; 108 109 using namespace phosphor::logging; 110 using Json = nlohmann::json; 111 112 using PrivAndGroupType = std::variant<std::string, std::vector<std::string>>; 113 114 using NoResource = 115 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource; 116 117 using InternalFailure = 118 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 119 120 std::unique_ptr<sdbusplus::bus::match_t> userUpdatedSignal 121 __attribute__((init_priority(101))); 122 std::unique_ptr<sdbusplus::bus::match_t> userMgrRenamedSignal 123 __attribute__((init_priority(101))); 124 std::unique_ptr<sdbusplus::bus::match_t> userPropertiesSignal 125 __attribute__((init_priority(101))); 126 127 // TODO: Below code can be removed once it is moved to common layer libmiscutil 128 std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf, 129 const std::string& path) 130 { 131 auto mapperCall = bus.new_method_call(objMapperService, objMapperPath, 132 objMapperInterface, getObjectMethod); 133 134 mapperCall.append(path); 135 mapperCall.append(std::vector<std::string>({intf})); 136 137 auto mapperResponseMsg = bus.call(mapperCall); 138 139 std::map<std::string, std::vector<std::string>> mapperResponse; 140 mapperResponseMsg.read(mapperResponse); 141 142 if (mapperResponse.begin() == mapperResponse.end()) 143 { 144 throw sdbusplus::exception::SdBusError( 145 -EIO, "ERROR in reading the mapper response"); 146 } 147 148 return mapperResponse.begin()->first; 149 } 150 151 void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service, 152 const std::string& objPath, const std::string& interface, 153 const std::string& property, 154 const DbusUserPropVariant& value) 155 { 156 try 157 { 158 auto method = 159 bus.new_method_call(service.c_str(), objPath.c_str(), 160 dBusPropertiesInterface, setPropertiesMethod); 161 method.append(interface, property, value); 162 bus.call(method); 163 } 164 catch (const sdbusplus::exception::SdBusError& e) 165 { 166 log<level::ERR>("Failed to set property", 167 entry("PROPERTY=%s", property.c_str()), 168 entry("PATH=%s", objPath.c_str()), 169 entry("INTERFACE=%s", interface.c_str())); 170 throw; 171 } 172 } 173 174 static std::string getUserServiceName() 175 { 176 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 177 static std::string userMgmtService; 178 if (userMgmtService.empty()) 179 { 180 try 181 { 182 userMgmtService = 183 ipmi::getUserService(bus, userMgrInterface, userMgrObjBasePath); 184 } 185 catch (const sdbusplus::exception::SdBusError& e) 186 { 187 userMgmtService.clear(); 188 } 189 } 190 return userMgmtService; 191 } 192 193 UserAccess& getUserAccessObject() 194 { 195 static UserAccess userAccess; 196 return userAccess; 197 } 198 199 int getUserNameFromPath(const std::string& path, std::string& userName) 200 { 201 constexpr size_t length = strlen(userObjBasePath); 202 if (((length + 1) >= path.size()) || 203 path.compare(0, length, userObjBasePath)) 204 { 205 return -EINVAL; 206 } 207 userName.assign(path, length + 1, path.size()); 208 return 0; 209 } 210 211 void userUpdateHelper(UserAccess& usrAccess, const UserUpdateEvent& userEvent, 212 const std::string& userName, const std::string& priv, 213 const bool& enabled, const std::string& newUserName) 214 { 215 UsersTbl* userData = usrAccess.getUsersTblPtr(); 216 if (userEvent == UserUpdateEvent::userCreated) 217 { 218 if (usrAccess.addUserEntry(userName, priv, enabled) == false) 219 { 220 return; 221 } 222 } 223 else 224 { 225 // user index 0 is reserved, starts with 1 226 size_t usrIndex = 1; 227 for (; usrIndex <= ipmiMaxUsers; ++usrIndex) 228 { 229 std::string curName( 230 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 231 ipmiMaxUserName); 232 if (userName == curName) 233 { 234 break; // found the entry 235 } 236 } 237 if (usrIndex > ipmiMaxUsers) 238 { 239 log<level::DEBUG>("User not found for signal", 240 entry("USER_NAME=%s", userName.c_str()), 241 entry("USER_EVENT=%d", userEvent)); 242 return; 243 } 244 switch (userEvent) 245 { 246 case UserUpdateEvent::userDeleted: 247 { 248 usrAccess.deleteUserIndex(usrIndex); 249 break; 250 } 251 case UserUpdateEvent::userPrivUpdated: 252 { 253 uint8_t userPriv = 254 static_cast<uint8_t>( 255 UserAccess::convertToIPMIPrivilege(priv)) & 256 privMask; 257 // Update all channels privileges, only if it is not equivalent 258 // to getUsrMgmtSyncIndex() 259 if (userData->user[usrIndex] 260 .userPrivAccess[UserAccess::getUsrMgmtSyncIndex()] 261 .privilege != userPriv) 262 { 263 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 264 ++chIndex) 265 { 266 userData->user[usrIndex] 267 .userPrivAccess[chIndex] 268 .privilege = userPriv; 269 } 270 } 271 break; 272 } 273 case UserUpdateEvent::userRenamed: 274 { 275 std::fill( 276 static_cast<uint8_t*>(userData->user[usrIndex].userName), 277 static_cast<uint8_t*>(userData->user[usrIndex].userName) + 278 sizeof(userData->user[usrIndex].userName), 279 0); 280 std::strncpy( 281 reinterpret_cast<char*>(userData->user[usrIndex].userName), 282 newUserName.c_str(), ipmiMaxUserName); 283 ipmiRenameUserEntryPassword(userName, newUserName); 284 break; 285 } 286 case UserUpdateEvent::userStateUpdated: 287 { 288 userData->user[usrIndex].userEnabled = enabled; 289 break; 290 } 291 default: 292 { 293 log<level::ERR>("Unhandled user event", 294 entry("USER_EVENT=%d", userEvent)); 295 return; 296 } 297 } 298 } 299 usrAccess.writeUserData(); 300 log<level::DEBUG>("User event handled successfully", 301 entry("USER_NAME=%s", userName.c_str()), 302 entry("USER_EVENT=%d", userEvent)); 303 304 return; 305 } 306 307 void userUpdatedSignalHandler(UserAccess& usrAccess, 308 sdbusplus::message::message& msg) 309 { 310 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 311 std::string signal = msg.get_member(); 312 std::string userName, priv, newUserName; 313 std::vector<std::string> groups; 314 bool enabled = false; 315 UserUpdateEvent userEvent = UserUpdateEvent::reservedEvent; 316 if (signal == intfAddedSignal) 317 { 318 DbusUserObjPath objPath; 319 DbusUserObjValue objValue; 320 msg.read(objPath, objValue); 321 getUserNameFromPath(objPath.str, userName); 322 if (usrAccess.getUserObjProperties(objValue, groups, priv, enabled) != 323 0) 324 { 325 return; 326 } 327 if (std::find(groups.begin(), groups.end(), ipmiGrpName) == 328 groups.end()) 329 { 330 return; 331 } 332 userEvent = UserUpdateEvent::userCreated; 333 } 334 else if (signal == intfRemovedSignal) 335 { 336 DbusUserObjPath objPath; 337 std::vector<std::string> interfaces; 338 msg.read(objPath, interfaces); 339 getUserNameFromPath(objPath.str, userName); 340 userEvent = UserUpdateEvent::userDeleted; 341 } 342 else if (signal == userRenamedSignal) 343 { 344 msg.read(userName, newUserName); 345 userEvent = UserUpdateEvent::userRenamed; 346 } 347 else if (signal == propertiesChangedSignal) 348 { 349 getUserNameFromPath(msg.get_path(), userName); 350 } 351 else 352 { 353 log<level::ERR>("Unknown user update signal", 354 entry("SIGNAL=%s", signal.c_str())); 355 return; 356 } 357 358 if (signal.empty() || userName.empty() || 359 (signal == userRenamedSignal && newUserName.empty())) 360 { 361 log<level::ERR>("Invalid inputs received"); 362 return; 363 } 364 365 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 366 userLock{*(usrAccess.userMutex)}; 367 usrAccess.checkAndReloadUserData(); 368 369 if (signal == propertiesChangedSignal) 370 { 371 std::string intfName; 372 DbusUserObjProperties chProperties; 373 msg.read(intfName, chProperties); // skip reading 3rd argument. 374 for (const auto& prop : chProperties) 375 { 376 userEvent = UserUpdateEvent::reservedEvent; 377 std::string member = prop.first; 378 if (member == userPrivProperty) 379 { 380 priv = std::get<std::string>(prop.second); 381 userEvent = UserUpdateEvent::userPrivUpdated; 382 } 383 else if (member == userGrpProperty) 384 { 385 groups = std::get<std::vector<std::string>>(prop.second); 386 userEvent = UserUpdateEvent::userGrpUpdated; 387 } 388 else if (member == userEnabledProperty) 389 { 390 enabled = std::get<bool>(prop.second); 391 userEvent = UserUpdateEvent::userStateUpdated; 392 } 393 // Process based on event type. 394 if (userEvent == UserUpdateEvent::userGrpUpdated) 395 { 396 if (std::find(groups.begin(), groups.end(), ipmiGrpName) == 397 groups.end()) 398 { 399 // remove user from ipmi user list. 400 userUpdateHelper(usrAccess, UserUpdateEvent::userDeleted, 401 userName, priv, enabled, newUserName); 402 } 403 else 404 { 405 DbusUserObjProperties properties; 406 try 407 { 408 auto method = bus.new_method_call( 409 getUserServiceName().c_str(), msg.get_path(), 410 dBusPropertiesInterface, getAllPropertiesMethod); 411 method.append(usersInterface); 412 auto reply = bus.call(method); 413 reply.read(properties); 414 } 415 catch (const sdbusplus::exception::SdBusError& e) 416 { 417 log<level::DEBUG>( 418 "Failed to excute method", 419 entry("METHOD=%s", getAllPropertiesMethod), 420 entry("PATH=%s", msg.get_path())); 421 return; 422 } 423 usrAccess.getUserProperties(properties, groups, priv, 424 enabled); 425 // add user to ipmi user list. 426 userUpdateHelper(usrAccess, UserUpdateEvent::userCreated, 427 userName, priv, enabled, newUserName); 428 } 429 } 430 else if (userEvent != UserUpdateEvent::reservedEvent) 431 { 432 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled, 433 newUserName); 434 } 435 } 436 } 437 else if (userEvent != UserUpdateEvent::reservedEvent) 438 { 439 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled, 440 newUserName); 441 } 442 return; 443 } 444 445 UserAccess::~UserAccess() 446 { 447 if (signalHndlrObject) 448 { 449 userUpdatedSignal.reset(); 450 userMgrRenamedSignal.reset(); 451 userPropertiesSignal.reset(); 452 sigHndlrLock.unlock(); 453 } 454 } 455 456 UserAccess::UserAccess() : bus(ipmid_get_sd_bus_connection()) 457 { 458 std::ofstream mutexCleanUpFile; 459 mutexCleanUpFile.open(ipmiMutexCleanupLockFile, 460 std::ofstream::out | std::ofstream::app); 461 if (!mutexCleanUpFile.good()) 462 { 463 log<level::DEBUG>("Unable to open mutex cleanup file"); 464 return; 465 } 466 mutexCleanUpFile.close(); 467 mutexCleanupLock = boost::interprocess::file_lock(ipmiMutexCleanupLockFile); 468 if (mutexCleanupLock.try_lock()) 469 { 470 boost::interprocess::named_recursive_mutex::remove(ipmiUserMutex); 471 } 472 mutexCleanupLock.lock_sharable(); 473 userMutex = std::make_unique<boost::interprocess::named_recursive_mutex>( 474 boost::interprocess::open_or_create, ipmiUserMutex); 475 476 cacheUserDataFile(); 477 getSystemPrivAndGroups(); 478 } 479 480 UserInfo* UserAccess::getUserInfo(const uint8_t userId) 481 { 482 checkAndReloadUserData(); 483 return &usersTbl.user[userId]; 484 } 485 486 void UserAccess::setUserInfo(const uint8_t userId, UserInfo* userInfo) 487 { 488 checkAndReloadUserData(); 489 std::copy(reinterpret_cast<uint8_t*>(userInfo), 490 reinterpret_cast<uint8_t*>(userInfo) + sizeof(*userInfo), 491 reinterpret_cast<uint8_t*>(&usersTbl.user[userId])); 492 writeUserData(); 493 } 494 495 bool UserAccess::isValidChannel(const uint8_t chNum) 496 { 497 return (chNum < ipmiMaxChannels); 498 } 499 500 bool UserAccess::isValidUserId(const uint8_t userId) 501 { 502 return ((userId <= ipmiMaxUsers) && (userId != reservedUserId)); 503 } 504 505 bool UserAccess::isValidPrivilege(const uint8_t priv) 506 { 507 // Callback privilege is deprecated in OpenBMC 508 return (isValidPrivLimit(priv) || priv == privNoAccess); 509 } 510 511 uint8_t UserAccess::getUsrMgmtSyncIndex() 512 { 513 // Identify the IPMI channel used to assign system user privilege levels 514 // in phosphor-user-manager. The default value is IPMI Channel 1. To 515 // assign a different channel add: 516 // "is_management_nic" : true 517 // into the channel_config.json file describing the assignment of the IPMI 518 // channels. It is only necessary to add the string above to ONE record in 519 // the channel_config.json file. All other records will be automatically 520 // assigned a "false" value. 521 return getChannelConfigObject().getManagementNICID(); 522 } 523 524 CommandPrivilege UserAccess::convertToIPMIPrivilege(const std::string& value) 525 { 526 auto iter = std::find(ipmiPrivIndex.begin(), ipmiPrivIndex.end(), value); 527 if (iter == ipmiPrivIndex.end()) 528 { 529 if (value == "") 530 { 531 return static_cast<CommandPrivilege>(privNoAccess); 532 } 533 log<level::ERR>("Error in converting to IPMI privilege", 534 entry("PRIV=%s", value.c_str())); 535 throw std::out_of_range("Out of range - convertToIPMIPrivilege"); 536 } 537 else 538 { 539 return static_cast<CommandPrivilege>( 540 std::distance(ipmiPrivIndex.begin(), iter)); 541 } 542 } 543 544 std::string UserAccess::convertToSystemPrivilege(const CommandPrivilege& value) 545 { 546 if (value == static_cast<CommandPrivilege>(privNoAccess)) 547 { 548 return ""; 549 } 550 try 551 { 552 return ipmiPrivIndex.at(value); 553 } 554 catch (const std::out_of_range& e) 555 { 556 log<level::ERR>("Error in converting to system privilege", 557 entry("PRIV=%d", static_cast<uint8_t>(value))); 558 throw std::out_of_range("Out of range - convertToSystemPrivilege"); 559 } 560 } 561 562 bool UserAccess::isValidUserName(const std::string& userName) 563 { 564 if (userName.empty()) 565 { 566 log<level::ERR>("userName is empty"); 567 return false; 568 } 569 if (!std::regex_match(userName.c_str(), 570 std::regex("[a-zA-z_][a-zA-Z_0-9]*"))) 571 { 572 log<level::ERR>("Unsupported characters in user name"); 573 return false; 574 } 575 if (userName == "root") 576 { 577 log<level::ERR>("Invalid user name - root"); 578 return false; 579 } 580 std::map<DbusUserObjPath, DbusUserObjValue> properties; 581 try 582 { 583 auto method = bus.new_method_call(getUserServiceName().c_str(), 584 userMgrObjBasePath, dBusObjManager, 585 getManagedObjectsMethod); 586 auto reply = bus.call(method); 587 reply.read(properties); 588 } 589 catch (const sdbusplus::exception::SdBusError& e) 590 { 591 log<level::ERR>("Failed to excute method", 592 entry("METHOD=%s", getSubTreeMethod), 593 entry("PATH=%s", userMgrObjBasePath)); 594 return false; 595 } 596 597 std::string usersPath = std::string(userObjBasePath) + "/" + userName; 598 if (properties.find(usersPath) != properties.end()) 599 { 600 log<level::DEBUG>("User name already exists", 601 entry("USER_NAME=%s", userName.c_str())); 602 return false; 603 } 604 605 return true; 606 } 607 608 /** @brief Information exchanged by pam module and application. 609 * 610 * @param[in] numMsg - length of the array of pointers,msg. 611 * 612 * @param[in] msg - pointer to an array of pointers to pam_message structure 613 * 614 * @param[out] resp - struct pam response array 615 * 616 * @param[in] appdataPtr - member of pam_conv structure 617 * 618 * @return the response in pam response structure. 619 */ 620 621 static int pamFunctionConversation(int numMsg, const struct pam_message** msg, 622 struct pam_response** resp, void* appdataPtr) 623 { 624 if (appdataPtr == nullptr) 625 { 626 return PAM_AUTH_ERR; 627 } 628 size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1; 629 char* pass = reinterpret_cast<char*>(malloc(passSize)); 630 std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize); 631 632 *resp = reinterpret_cast<pam_response*>( 633 calloc(numMsg, sizeof(struct pam_response))); 634 635 for (int i = 0; i < numMsg; ++i) 636 { 637 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) 638 { 639 continue; 640 } 641 resp[i]->resp = pass; 642 } 643 return PAM_SUCCESS; 644 } 645 646 /** @brief Updating the PAM password 647 * 648 * @param[in] username - username in string 649 * 650 * @param[in] password - new password in string 651 * 652 * @return status 653 */ 654 655 int pamUpdatePasswd(const char* username, const char* password) 656 { 657 const struct pam_conv localConversation = {pamFunctionConversation, 658 const_cast<char*>(password)}; 659 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start 660 661 int retval = 662 pam_start("passwd", username, &localConversation, &localAuthHandle); 663 664 if (retval != PAM_SUCCESS) 665 { 666 return retval; 667 } 668 669 retval = pam_chauthtok(localAuthHandle, PAM_SILENT); 670 if (retval != PAM_SUCCESS) 671 { 672 pam_end(localAuthHandle, retval); 673 return retval; 674 } 675 676 return pam_end(localAuthHandle, PAM_SUCCESS); 677 } 678 679 bool pamUserCheckAuthenticate(std::string_view username, 680 std::string_view password) 681 { 682 const struct pam_conv localConversation = { 683 pamFunctionConversation, const_cast<char*>(password.data())}; 684 685 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start 686 687 if (pam_start("dropbear", username.data(), &localConversation, 688 &localAuthHandle) != PAM_SUCCESS) 689 { 690 log<level::ERR>("User Authentication Failure"); 691 return false; 692 } 693 694 int retval = pam_authenticate(localAuthHandle, 695 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); 696 697 if (retval != PAM_SUCCESS) 698 { 699 log<level::DEBUG>("pam_authenticate returned failure", 700 entry("ERROR=%d", retval)); 701 702 pam_end(localAuthHandle, retval); 703 return false; 704 } 705 706 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) != 707 PAM_SUCCESS) 708 { 709 pam_end(localAuthHandle, PAM_SUCCESS); 710 return false; 711 } 712 713 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) 714 { 715 return false; 716 } 717 return true; 718 } 719 720 Cc UserAccess::setSpecialUserPassword(const std::string& userName, 721 const std::string& userPassword) 722 { 723 if (pamUpdatePasswd(userName.c_str(), userPassword.c_str()) != PAM_SUCCESS) 724 { 725 log<level::DEBUG>("Failed to update password"); 726 return ccUnspecifiedError; 727 } 728 return ccSuccess; 729 } 730 731 Cc UserAccess::setUserPassword(const uint8_t userId, const char* userPassword) 732 { 733 std::string userName; 734 if (ipmiUserGetUserName(userId, userName) != ccSuccess) 735 { 736 log<level::DEBUG>("User Name not found", 737 entry("USER-ID=%d", (uint8_t)userId)); 738 return ccParmOutOfRange; 739 } 740 741 ipmi::SecureString passwd; 742 passwd.assign(reinterpret_cast<const char*>(userPassword), 0, 743 maxIpmi20PasswordSize); 744 int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str()); 745 746 switch (retval) 747 { 748 case PAM_SUCCESS: 749 { 750 return ccSuccess; 751 } 752 case PAM_AUTHTOK_ERR: 753 { 754 log<level::DEBUG>("Bad authentication token"); 755 return ccInvalidFieldRequest; 756 } 757 default: 758 { 759 log<level::DEBUG>("Failed to update password", 760 entry("USER-ID=%d", (uint8_t)userId)); 761 return ccUnspecifiedError; 762 } 763 } 764 } 765 766 Cc UserAccess::setUserEnabledState(const uint8_t userId, 767 const bool& enabledState) 768 { 769 if (!isValidUserId(userId)) 770 { 771 return ccParmOutOfRange; 772 } 773 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 774 userLock{*userMutex}; 775 UserInfo* userInfo = getUserInfo(userId); 776 std::string userName; 777 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 778 ipmiMaxUserName); 779 if (userName.empty()) 780 { 781 log<level::DEBUG>("User name not set / invalid"); 782 return ccUnspecifiedError; 783 } 784 if (userInfo->userEnabled != enabledState) 785 { 786 std::string userPath = std::string(userObjBasePath) + "/" + userName; 787 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface, 788 userEnabledProperty, enabledState); 789 userInfo->userEnabled = enabledState; 790 try 791 { 792 writeUserData(); 793 } 794 catch (const std::exception& e) 795 { 796 log<level::DEBUG>("Write user data failed"); 797 return ccUnspecifiedError; 798 } 799 } 800 return ccSuccess; 801 } 802 803 Cc UserAccess::setUserPayloadAccess(const uint8_t chNum, 804 const uint8_t operation, 805 const uint8_t userId, 806 const PayloadAccess& payloadAccess) 807 { 808 constexpr uint8_t enable = 0x0; 809 constexpr uint8_t disable = 0x1; 810 811 if (!isValidChannel(chNum)) 812 { 813 return ccInvalidFieldRequest; 814 } 815 if (!isValidUserId(userId)) 816 { 817 return ccParmOutOfRange; 818 } 819 if (operation != enable && operation != disable) 820 { 821 return ccInvalidFieldRequest; 822 } 823 // Check operation & payloadAccess if required. 824 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 825 userLock{*userMutex}; 826 UserInfo* userInfo = getUserInfo(userId); 827 828 if (operation == enable) 829 { 830 userInfo->payloadAccess[chNum].stdPayloadEnables1 |= 831 payloadAccess.stdPayloadEnables1; 832 833 userInfo->payloadAccess[chNum].oemPayloadEnables1 |= 834 payloadAccess.oemPayloadEnables1; 835 } 836 else 837 { 838 userInfo->payloadAccess[chNum].stdPayloadEnables1 &= 839 ~(payloadAccess.stdPayloadEnables1); 840 841 userInfo->payloadAccess[chNum].oemPayloadEnables1 &= 842 ~(payloadAccess.oemPayloadEnables1); 843 } 844 845 try 846 { 847 writeUserData(); 848 } 849 catch (const std::exception& e) 850 { 851 log<level::ERR>("Write user data failed"); 852 return ccUnspecifiedError; 853 } 854 return ccSuccess; 855 } 856 857 Cc UserAccess::setUserPrivilegeAccess(const uint8_t userId, const uint8_t chNum, 858 const UserPrivAccess& privAccess, 859 const bool& otherPrivUpdates) 860 { 861 if (!isValidChannel(chNum)) 862 { 863 return ccInvalidFieldRequest; 864 } 865 if (!isValidUserId(userId)) 866 { 867 return ccParmOutOfRange; 868 } 869 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 870 userLock{*userMutex}; 871 UserInfo* userInfo = getUserInfo(userId); 872 std::string userName; 873 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 874 ipmiMaxUserName); 875 if (userName.empty()) 876 { 877 log<level::DEBUG>("User name not set / invalid"); 878 return ccUnspecifiedError; 879 } 880 std::string priv = convertToSystemPrivilege( 881 static_cast<CommandPrivilege>(privAccess.privilege)); 882 uint8_t syncIndex = getUsrMgmtSyncIndex(); 883 if (chNum == syncIndex && 884 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege) 885 { 886 std::string userPath = std::string(userObjBasePath) + "/" + userName; 887 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface, 888 userPrivProperty, priv); 889 } 890 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege; 891 892 if (otherPrivUpdates) 893 { 894 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled; 895 userInfo->userPrivAccess[chNum].linkAuthEnabled = 896 privAccess.linkAuthEnabled; 897 userInfo->userPrivAccess[chNum].accessCallback = 898 privAccess.accessCallback; 899 } 900 try 901 { 902 writeUserData(); 903 } 904 catch (const std::exception& e) 905 { 906 log<level::DEBUG>("Write user data failed"); 907 return ccUnspecifiedError; 908 } 909 return ccSuccess; 910 } 911 912 uint8_t UserAccess::getUserId(const std::string& userName) 913 { 914 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 915 userLock{*userMutex}; 916 checkAndReloadUserData(); 917 // user index 0 is reserved, starts with 1 918 size_t usrIndex = 1; 919 for (; usrIndex <= ipmiMaxUsers; ++usrIndex) 920 { 921 std::string curName( 922 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 923 ipmiMaxUserName); 924 if (userName == curName) 925 { 926 break; // found the entry 927 } 928 } 929 if (usrIndex > ipmiMaxUsers) 930 { 931 log<level::DEBUG>("User not found", 932 entry("USER_NAME=%s", userName.c_str())); 933 return invalidUserId; 934 } 935 936 return usrIndex; 937 } 938 939 Cc UserAccess::getUserName(const uint8_t userId, std::string& userName) 940 { 941 if (!isValidUserId(userId)) 942 { 943 return ccParmOutOfRange; 944 } 945 UserInfo* userInfo = getUserInfo(userId); 946 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 947 ipmiMaxUserName); 948 return ccSuccess; 949 } 950 951 bool UserAccess::isIpmiInAvailableGroupList() 952 { 953 if (std::find(availableGroups.begin(), availableGroups.end(), 954 ipmiGrpName) != availableGroups.end()) 955 { 956 return true; 957 } 958 if (availableGroups.empty()) 959 { 960 // available groups shouldn't be empty, re-query 961 getSystemPrivAndGroups(); 962 if (std::find(availableGroups.begin(), availableGroups.end(), 963 ipmiGrpName) != availableGroups.end()) 964 { 965 return true; 966 } 967 } 968 return false; 969 } 970 971 Cc UserAccess::setUserName(const uint8_t userId, const std::string& userName) 972 { 973 if (!isValidUserId(userId)) 974 { 975 return ccParmOutOfRange; 976 } 977 978 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 979 userLock{*userMutex}; 980 std::string oldUser; 981 getUserName(userId, oldUser); 982 983 if (oldUser == userName) 984 { 985 // requesting to set the same user name, return success. 986 return ccSuccess; 987 } 988 989 bool validUser = isValidUserName(userName); 990 UserInfo* userInfo = getUserInfo(userId); 991 if (userName.empty() && !oldUser.empty()) 992 { 993 // Delete existing user 994 std::string userPath = std::string(userObjBasePath) + "/" + oldUser; 995 try 996 { 997 auto method = bus.new_method_call( 998 getUserServiceName().c_str(), userPath.c_str(), 999 deleteUserInterface, deleteUserMethod); 1000 auto reply = bus.call(method); 1001 } 1002 catch (const sdbusplus::exception::SdBusError& e) 1003 { 1004 log<level::DEBUG>("Failed to excute method", 1005 entry("METHOD=%s", deleteUserMethod), 1006 entry("PATH=%s", userPath.c_str())); 1007 return ccUnspecifiedError; 1008 } 1009 deleteUserIndex(userId); 1010 } 1011 else if (oldUser.empty() && !userName.empty() && validUser) 1012 { 1013 try 1014 { 1015 if (!isIpmiInAvailableGroupList()) 1016 { 1017 return ccUnspecifiedError; 1018 } 1019 // Create new user 1020 auto method = bus.new_method_call( 1021 getUserServiceName().c_str(), userMgrObjBasePath, 1022 userMgrInterface, createUserMethod); 1023 method.append(userName.c_str(), availableGroups, "", false); 1024 auto reply = bus.call(method); 1025 } 1026 catch (const sdbusplus::exception::SdBusError& e) 1027 { 1028 log<level::DEBUG>("Failed to excute method", 1029 entry("METHOD=%s", createUserMethod), 1030 entry("PATH=%s", userMgrObjBasePath)); 1031 return ccUnspecifiedError; 1032 } 1033 1034 std::memset(userInfo->userName, 0, sizeof(userInfo->userName)); 1035 std::memcpy(userInfo->userName, 1036 static_cast<const void*>(userName.data()), userName.size()); 1037 userInfo->userInSystem = true; 1038 } 1039 else if (oldUser != userName && validUser) 1040 { 1041 try 1042 { 1043 // User rename 1044 auto method = bus.new_method_call( 1045 getUserServiceName().c_str(), userMgrObjBasePath, 1046 userMgrInterface, renameUserMethod); 1047 method.append(oldUser.c_str(), userName.c_str()); 1048 auto reply = bus.call(method); 1049 } 1050 catch (const sdbusplus::exception::SdBusError& e) 1051 { 1052 log<level::DEBUG>("Failed to excute method", 1053 entry("METHOD=%s", renameUserMethod), 1054 entry("PATH=%s", userMgrObjBasePath)); 1055 return ccUnspecifiedError; 1056 } 1057 std::fill(static_cast<uint8_t*>(userInfo->userName), 1058 static_cast<uint8_t*>(userInfo->userName) + 1059 sizeof(userInfo->userName), 1060 0); 1061 1062 std::memset(userInfo->userName, 0, sizeof(userInfo->userName)); 1063 std::memcpy(userInfo->userName, 1064 static_cast<const void*>(userName.data()), userName.size()); 1065 1066 ipmiRenameUserEntryPassword(oldUser, userName); 1067 userInfo->userInSystem = true; 1068 } 1069 else if (!validUser) 1070 { 1071 return ccInvalidFieldRequest; 1072 } 1073 try 1074 { 1075 writeUserData(); 1076 } 1077 catch (const std::exception& e) 1078 { 1079 log<level::DEBUG>("Write user data failed"); 1080 return ccUnspecifiedError; 1081 } 1082 return ccSuccess; 1083 } 1084 1085 static constexpr const char* jsonUserName = "user_name"; 1086 static constexpr const char* jsonPriv = "privilege"; 1087 static constexpr const char* jsonIpmiEnabled = "ipmi_enabled"; 1088 static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled"; 1089 static constexpr const char* jsonAccCallbk = "access_callback"; 1090 static constexpr const char* jsonUserEnabled = "user_enabled"; 1091 static constexpr const char* jsonUserInSys = "user_in_system"; 1092 static constexpr const char* jsonFixedUser = "fixed_user_name"; 1093 static constexpr const char* payloadEnabledStr = "payload_enabled"; 1094 static constexpr const char* stdPayloadStr = "std_payload"; 1095 static constexpr const char* oemPayloadStr = "OEM_payload"; 1096 1097 /** @brief to construct a JSON object from the given payload access details. 1098 * 1099 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input) 1100 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input) 1101 * 1102 * @details Sample output JSON object format : 1103 * "payload_enabled":{ 1104 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1105 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1106 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1107 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1108 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1109 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1110 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1111 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1112 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1113 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1114 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1115 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1116 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1117 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1118 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1119 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1120 * } 1121 */ 1122 static const Json constructJsonPayloadEnables( 1123 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1124 stdPayload, 1125 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1126 oemPayload) 1127 { 1128 Json jsonPayloadEnabled; 1129 1130 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++) 1131 { 1132 std::ostringstream stdPayloadStream; 1133 std::ostringstream oemPayloadStream; 1134 1135 stdPayloadStream << stdPayloadStr << payloadNum; 1136 oemPayloadStream << oemPayloadStr << payloadNum; 1137 1138 jsonPayloadEnabled.push_back(Json::object_t::value_type( 1139 stdPayloadStream.str(), stdPayload[payloadNum])); 1140 1141 jsonPayloadEnabled.push_back(Json::object_t::value_type( 1142 oemPayloadStream.str(), oemPayload[payloadNum])); 1143 } 1144 return jsonPayloadEnabled; 1145 } 1146 1147 void UserAccess::readPayloadAccessFromUserInfo( 1148 const UserInfo& userInfo, 1149 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload, 1150 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload) 1151 { 1152 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++) 1153 { 1154 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1155 { 1156 stdPayload[payloadNum][chIndex] = 1157 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum]; 1158 1159 oemPayload[payloadNum][chIndex] = 1160 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum]; 1161 } 1162 } 1163 } 1164 1165 void UserAccess::updatePayloadAccessInUserInfo( 1166 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1167 stdPayload, 1168 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1169 oemPayload, 1170 UserInfo& userInfo) 1171 { 1172 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1173 { 1174 // Ensure that reserved/unsupported payloads are marked to zero. 1175 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset(); 1176 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset(); 1177 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset(); 1178 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset(); 1179 // Update SOL status as it is the only supported payload currently. 1180 userInfo.payloadAccess[chIndex] 1181 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] = 1182 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex]; 1183 } 1184 } 1185 1186 void UserAccess::readUserData() 1187 { 1188 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1189 userLock{*userMutex}; 1190 1191 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary); 1192 if (!iUsrData.good()) 1193 { 1194 log<level::ERR>("Error in reading IPMI user data file"); 1195 throw std::ios_base::failure("Error opening IPMI user data file"); 1196 } 1197 1198 Json jsonUsersTbl = Json::array(); 1199 jsonUsersTbl = Json::parse(iUsrData, nullptr, false); 1200 1201 if (jsonUsersTbl.size() != ipmiMaxUsers) 1202 { 1203 log<level::ERR>( 1204 "Error in reading IPMI user data file - User count issues"); 1205 throw std::runtime_error( 1206 "Corrupted IPMI user data file - invalid user count"); 1207 } 1208 1209 // user index 0 is reserved, starts with 1 1210 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1211 { 1212 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0. 1213 if (userInfo.is_null()) 1214 { 1215 log<level::ERR>("Error in reading IPMI user data file - " 1216 "user info corrupted"); 1217 throw std::runtime_error( 1218 "Corrupted IPMI user data file - invalid user info"); 1219 } 1220 std::string userName = userInfo[jsonUserName].get<std::string>(); 1221 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 1222 userName.c_str(), ipmiMaxUserName); 1223 1224 std::vector<std::string> privilege = 1225 userInfo[jsonPriv].get<std::vector<std::string>>(); 1226 std::vector<bool> ipmiEnabled = 1227 userInfo[jsonIpmiEnabled].get<std::vector<bool>>(); 1228 std::vector<bool> linkAuthEnabled = 1229 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>(); 1230 std::vector<bool> accessCallback = 1231 userInfo[jsonAccCallbk].get<std::vector<bool>>(); 1232 1233 // Payload Enables Processing. 1234 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1235 stdPayload = {}; 1236 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1237 oemPayload = {}; 1238 try 1239 { 1240 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr); 1241 for (auto payloadNum = 0; payloadNum < payloadsPerByte; 1242 payloadNum++) 1243 { 1244 std::ostringstream stdPayloadStream; 1245 std::ostringstream oemPayloadStream; 1246 1247 stdPayloadStream << stdPayloadStr << payloadNum; 1248 oemPayloadStream << oemPayloadStr << payloadNum; 1249 1250 stdPayload[payloadNum] = 1251 jsonPayloadEnabled[stdPayloadStream.str()] 1252 .get<std::array<bool, ipmiMaxChannels>>(); 1253 oemPayload[payloadNum] = 1254 jsonPayloadEnabled[oemPayloadStream.str()] 1255 .get<std::array<bool, ipmiMaxChannels>>(); 1256 1257 if (stdPayload[payloadNum].size() != ipmiMaxChannels || 1258 oemPayload[payloadNum].size() != ipmiMaxChannels) 1259 { 1260 log<level::ERR>("Error in reading IPMI user data file - " 1261 "payload properties corrupted"); 1262 throw std::runtime_error( 1263 "Corrupted IPMI user data file - payload properties"); 1264 } 1265 } 1266 } 1267 catch (Json::out_of_range& e) 1268 { 1269 // Key not found in 'userInfo'; possibly an old JSON file. Use 1270 // default values for all payloads, and SOL payload default is true. 1271 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true); 1272 } 1273 1274 if (privilege.size() != ipmiMaxChannels || 1275 ipmiEnabled.size() != ipmiMaxChannels || 1276 linkAuthEnabled.size() != ipmiMaxChannels || 1277 accessCallback.size() != ipmiMaxChannels) 1278 { 1279 log<level::ERR>("Error in reading IPMI user data file - " 1280 "properties corrupted"); 1281 throw std::runtime_error( 1282 "Corrupted IPMI user data file - properties"); 1283 } 1284 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1285 { 1286 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege = 1287 static_cast<uint8_t>( 1288 convertToIPMIPrivilege(privilege[chIndex])); 1289 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled = 1290 ipmiEnabled[chIndex]; 1291 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled = 1292 linkAuthEnabled[chIndex]; 1293 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback = 1294 accessCallback[chIndex]; 1295 } 1296 updatePayloadAccessInUserInfo(stdPayload, oemPayload, 1297 usersTbl.user[usrIndex]); 1298 usersTbl.user[usrIndex].userEnabled = 1299 userInfo[jsonUserEnabled].get<bool>(); 1300 usersTbl.user[usrIndex].userInSystem = 1301 userInfo[jsonUserInSys].get<bool>(); 1302 usersTbl.user[usrIndex].fixedUserName = 1303 userInfo[jsonFixedUser].get<bool>(); 1304 } 1305 1306 log<level::DEBUG>("User data read from IPMI data file"); 1307 iUsrData.close(); 1308 // Update the timestamp 1309 fileLastUpdatedTime = getUpdatedFileTime(); 1310 return; 1311 } 1312 1313 void UserAccess::writeUserData() 1314 { 1315 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1316 userLock{*userMutex}; 1317 1318 Json jsonUsersTbl = Json::array(); 1319 // user index 0 is reserved, starts with 1 1320 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1321 { 1322 Json jsonUserInfo; 1323 jsonUserInfo[jsonUserName] = std::string( 1324 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 1325 ipmiMaxUserName); 1326 std::vector<std::string> privilege(ipmiMaxChannels); 1327 std::vector<bool> ipmiEnabled(ipmiMaxChannels); 1328 std::vector<bool> linkAuthEnabled(ipmiMaxChannels); 1329 std::vector<bool> accessCallback(ipmiMaxChannels); 1330 1331 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1332 stdPayload; 1333 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1334 oemPayload; 1335 1336 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1337 { 1338 privilege[chIndex] = 1339 convertToSystemPrivilege(static_cast<CommandPrivilege>( 1340 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege)); 1341 ipmiEnabled[chIndex] = 1342 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled; 1343 linkAuthEnabled[chIndex] = 1344 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled; 1345 accessCallback[chIndex] = 1346 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback; 1347 } 1348 jsonUserInfo[jsonPriv] = privilege; 1349 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled; 1350 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled; 1351 jsonUserInfo[jsonAccCallbk] = accessCallback; 1352 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled; 1353 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem; 1354 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName; 1355 1356 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload, 1357 oemPayload); 1358 Json jsonPayloadEnabledInfo = 1359 constructJsonPayloadEnables(stdPayload, oemPayload); 1360 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo; 1361 1362 jsonUsersTbl.push_back(jsonUserInfo); 1363 } 1364 1365 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"}; 1366 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC, 1367 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 1368 if (fd < 0) 1369 { 1370 log<level::ERR>("Error in creating temporary IPMI user data file"); 1371 throw std::ios_base::failure( 1372 "Error in creating temporary IPMI user data file"); 1373 } 1374 const auto& writeStr = jsonUsersTbl.dump(); 1375 if (write(fd, writeStr.c_str(), writeStr.size()) != 1376 static_cast<ssize_t>(writeStr.size())) 1377 { 1378 close(fd); 1379 log<level::ERR>("Error in writing temporary IPMI user data file"); 1380 throw std::ios_base::failure( 1381 "Error in writing temporary IPMI user data file"); 1382 } 1383 close(fd); 1384 1385 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0) 1386 { 1387 log<level::ERR>("Error in renaming temporary IPMI user data file"); 1388 throw std::runtime_error("Error in renaming IPMI user data file"); 1389 } 1390 // Update the timestamp 1391 fileLastUpdatedTime = getUpdatedFileTime(); 1392 return; 1393 } 1394 1395 bool UserAccess::addUserEntry(const std::string& userName, 1396 const std::string& sysPriv, const bool& enabled) 1397 { 1398 UsersTbl* userData = getUsersTblPtr(); 1399 size_t freeIndex = 0xFF; 1400 // user index 0 is reserved, starts with 1 1401 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1402 { 1403 std::string curName( 1404 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 1405 ipmiMaxUserName); 1406 if (userName == curName) 1407 { 1408 log<level::DEBUG>("User name exists", 1409 entry("USER_NAME=%s", userName.c_str())); 1410 return false; // user name exists. 1411 } 1412 1413 if ((!userData->user[usrIndex].userInSystem) && 1414 (userData->user[usrIndex].userName[0] == '\0') && 1415 (freeIndex == 0xFF)) 1416 { 1417 freeIndex = usrIndex; 1418 } 1419 } 1420 if (freeIndex == 0xFF) 1421 { 1422 log<level::ERR>("No empty slots found"); 1423 return false; 1424 } 1425 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName), 1426 userName.c_str(), ipmiMaxUserName); 1427 uint8_t priv = 1428 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) & 1429 privMask; 1430 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1431 { 1432 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv; 1433 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true; 1434 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled = 1435 true; 1436 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true; 1437 } 1438 userData->user[freeIndex].userInSystem = true; 1439 userData->user[freeIndex].userEnabled = enabled; 1440 1441 return true; 1442 } 1443 1444 void UserAccess::deleteUserIndex(const size_t& usrIdx) 1445 { 1446 UsersTbl* userData = getUsersTblPtr(); 1447 1448 std::string userName( 1449 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1450 ipmiMaxUserName); 1451 ipmiClearUserEntryPassword(userName); 1452 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName), 1453 static_cast<uint8_t*>(userData->user[usrIdx].userName) + 1454 sizeof(userData->user[usrIdx].userName), 1455 0); 1456 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1457 { 1458 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess; 1459 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false; 1460 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false; 1461 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false; 1462 } 1463 userData->user[usrIdx].userInSystem = false; 1464 userData->user[usrIdx].userEnabled = false; 1465 return; 1466 } 1467 1468 void UserAccess::checkAndReloadUserData() 1469 { 1470 std::time_t updateTime = getUpdatedFileTime(); 1471 if (updateTime != fileLastUpdatedTime || updateTime == -EIO) 1472 { 1473 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1474 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1475 readUserData(); 1476 } 1477 return; 1478 } 1479 1480 UsersTbl* UserAccess::getUsersTblPtr() 1481 { 1482 // reload data before using it. 1483 checkAndReloadUserData(); 1484 return &usersTbl; 1485 } 1486 1487 void UserAccess::getSystemPrivAndGroups() 1488 { 1489 std::map<std::string, PrivAndGroupType> properties; 1490 try 1491 { 1492 auto method = bus.new_method_call( 1493 getUserServiceName().c_str(), userMgrObjBasePath, 1494 dBusPropertiesInterface, getAllPropertiesMethod); 1495 method.append(userMgrInterface); 1496 1497 auto reply = bus.call(method); 1498 reply.read(properties); 1499 } 1500 catch (const sdbusplus::exception::SdBusError& e) 1501 { 1502 log<level::DEBUG>("Failed to excute method", 1503 entry("METHOD=%s", getAllPropertiesMethod), 1504 entry("PATH=%s", userMgrObjBasePath)); 1505 return; 1506 } 1507 for (const auto& t : properties) 1508 { 1509 auto key = t.first; 1510 if (key == allPrivProperty) 1511 { 1512 availablePrivileges = std::get<std::vector<std::string>>(t.second); 1513 } 1514 else if (key == allGrpProperty) 1515 { 1516 availableGroups = std::get<std::vector<std::string>>(t.second); 1517 } 1518 } 1519 // TODO: Implement Supported Privilege & Groups verification logic 1520 return; 1521 } 1522 1523 std::time_t UserAccess::getUpdatedFileTime() 1524 { 1525 struct stat fileStat; 1526 if (stat(ipmiUserDataFile, &fileStat) != 0) 1527 { 1528 log<level::DEBUG>("Error in getting last updated time stamp"); 1529 return -EIO; 1530 } 1531 return fileStat.st_mtime; 1532 } 1533 1534 void UserAccess::getUserProperties(const DbusUserObjProperties& properties, 1535 std::vector<std::string>& usrGrps, 1536 std::string& usrPriv, bool& usrEnabled) 1537 { 1538 for (const auto& t : properties) 1539 { 1540 std::string key = t.first; 1541 if (key == userPrivProperty) 1542 { 1543 usrPriv = std::get<std::string>(t.second); 1544 } 1545 else if (key == userGrpProperty) 1546 { 1547 usrGrps = std::get<std::vector<std::string>>(t.second); 1548 } 1549 else if (key == userEnabledProperty) 1550 { 1551 usrEnabled = std::get<bool>(t.second); 1552 } 1553 } 1554 return; 1555 } 1556 1557 int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs, 1558 std::vector<std::string>& usrGrps, 1559 std::string& usrPriv, bool& usrEnabled) 1560 { 1561 auto usrObj = userObjs.find(usersInterface); 1562 if (usrObj != userObjs.end()) 1563 { 1564 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled); 1565 return 0; 1566 } 1567 return -EIO; 1568 } 1569 1570 void UserAccess::cacheUserDataFile() 1571 { 1572 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1573 userLock{*userMutex}; 1574 try 1575 { 1576 readUserData(); 1577 } 1578 catch (const std::ios_base::failure& e) 1579 { // File is empty, create it for the first time 1580 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1581 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1582 // user index 0 is reserved, starts with 1 1583 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex) 1584 { 1585 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1586 { 1587 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege = 1588 privNoAccess; 1589 usersTbl.user[userIndex] 1590 .payloadAccess[chIndex] 1591 .stdPayloadEnables1[static_cast<uint8_t>( 1592 ipmi::PayloadType::SOL)] = true; 1593 } 1594 } 1595 writeUserData(); 1596 } 1597 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile); 1598 // Register it for single object and single process either netipimd / 1599 // host-ipmid 1600 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock()) 1601 { 1602 log<level::DEBUG>("Registering signal handler"); 1603 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>( 1604 bus, 1605 sdbusplus::bus::match::rules::type::signal() + 1606 sdbusplus::bus::match::rules::interface(dBusObjManager) + 1607 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 1608 [&](sdbusplus::message::message& msg) { 1609 userUpdatedSignalHandler(*this, msg); 1610 }); 1611 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>( 1612 bus, 1613 sdbusplus::bus::match::rules::type::signal() + 1614 sdbusplus::bus::match::rules::interface(userMgrInterface) + 1615 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 1616 [&](sdbusplus::message::message& msg) { 1617 userUpdatedSignalHandler(*this, msg); 1618 }); 1619 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>( 1620 bus, 1621 sdbusplus::bus::match::rules::type::signal() + 1622 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) + 1623 sdbusplus::bus::match::rules::interface( 1624 dBusPropertiesInterface) + 1625 sdbusplus::bus::match::rules::member(propertiesChangedSignal) + 1626 sdbusplus::bus::match::rules::argN(0, usersInterface), 1627 [&](sdbusplus::message::message& msg) { 1628 userUpdatedSignalHandler(*this, msg); 1629 }); 1630 signalHndlrObject = true; 1631 } 1632 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs; 1633 try 1634 { 1635 auto method = bus.new_method_call(getUserServiceName().c_str(), 1636 userMgrObjBasePath, dBusObjManager, 1637 getManagedObjectsMethod); 1638 auto reply = bus.call(method); 1639 reply.read(managedObjs); 1640 } 1641 catch (const sdbusplus::exception::SdBusError& e) 1642 { 1643 log<level::DEBUG>("Failed to excute method", 1644 entry("METHOD=%s", getSubTreeMethod), 1645 entry("PATH=%s", userMgrObjBasePath)); 1646 return; 1647 } 1648 bool updateRequired = false; 1649 UsersTbl* userData = &usersTbl; 1650 // user index 0 is reserved, starts with 1 1651 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx) 1652 { 1653 if ((userData->user[usrIdx].userInSystem) && 1654 (userData->user[usrIdx].userName[0] != '\0')) 1655 { 1656 std::vector<std::string> usrGrps; 1657 std::string usrPriv; 1658 1659 std::string userName( 1660 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1661 ipmiMaxUserName); 1662 std::string usersPath = 1663 std::string(userObjBasePath) + "/" + userName; 1664 1665 auto usrObj = managedObjs.find(usersPath); 1666 if (usrObj != managedObjs.end()) 1667 { 1668 bool usrEnabled = false; 1669 1670 // User exist. Lets check and update other fileds 1671 getUserObjProperties(usrObj->second, usrGrps, usrPriv, 1672 usrEnabled); 1673 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) == 1674 usrGrps.end()) 1675 { 1676 updateRequired = true; 1677 // Group "ipmi" is removed so lets remove user in IPMI 1678 deleteUserIndex(usrIdx); 1679 } 1680 else 1681 { 1682 // Group "ipmi" is present so lets update other properties 1683 // in IPMI 1684 uint8_t priv = 1685 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask; 1686 // Update all channels priv, only if it is not equivalent to 1687 // getUsrMgmtSyncIndex() 1688 if (userData->user[usrIdx] 1689 .userPrivAccess[getUsrMgmtSyncIndex()] 1690 .privilege != priv) 1691 { 1692 updateRequired = true; 1693 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 1694 ++chIndex) 1695 { 1696 userData->user[usrIdx] 1697 .userPrivAccess[chIndex] 1698 .privilege = priv; 1699 } 1700 } 1701 if (userData->user[usrIdx].userEnabled != usrEnabled) 1702 { 1703 updateRequired = true; 1704 userData->user[usrIdx].userEnabled = usrEnabled; 1705 } 1706 } 1707 1708 // We are done with this obj. lets delete from MAP 1709 managedObjs.erase(usrObj); 1710 } 1711 else 1712 { 1713 updateRequired = true; 1714 deleteUserIndex(usrIdx); 1715 } 1716 } 1717 } 1718 1719 // Walk through remnaining managedObj users list 1720 // Add them to ipmi data base 1721 for (const auto& usrObj : managedObjs) 1722 { 1723 std::vector<std::string> usrGrps; 1724 std::string usrPriv, userName; 1725 bool usrEnabled = false; 1726 std::string usrObjPath = std::string(usrObj.first); 1727 if (getUserNameFromPath(usrObj.first.str, userName) != 0) 1728 { 1729 log<level::ERR>("Error in user object path"); 1730 continue; 1731 } 1732 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled); 1733 // Add 'ipmi' group users 1734 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) != 1735 usrGrps.end()) 1736 { 1737 updateRequired = true; 1738 // CREATE NEW USER 1739 if (true != addUserEntry(userName, usrPriv, usrEnabled)) 1740 { 1741 break; 1742 } 1743 } 1744 } 1745 1746 if (updateRequired) 1747 { 1748 // All userData slots update done. Lets write the data 1749 writeUserData(); 1750 } 1751 1752 return; 1753 } 1754 } // namespace ipmi 1755