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 std::string passwd; 741 passwd.assign(reinterpret_cast<const char*>(userPassword), 0, 742 maxIpmi20PasswordSize); 743 744 int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str()); 745 // Clear sensitive data 746 OPENSSL_cleanse(&passwd, passwd.length()); 747 748 switch (retval) 749 { 750 case PAM_SUCCESS: 751 { 752 return ccSuccess; 753 } 754 case PAM_AUTHTOK_ERR: 755 { 756 log<level::DEBUG>("Bad authentication token"); 757 return ccInvalidFieldRequest; 758 } 759 default: 760 { 761 log<level::DEBUG>("Failed to update password", 762 entry("USER-ID=%d", (uint8_t)userId)); 763 return ccUnspecifiedError; 764 } 765 } 766 } 767 768 Cc UserAccess::setUserEnabledState(const uint8_t userId, 769 const bool& enabledState) 770 { 771 if (!isValidUserId(userId)) 772 { 773 return ccParmOutOfRange; 774 } 775 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 776 userLock{*userMutex}; 777 UserInfo* userInfo = getUserInfo(userId); 778 std::string userName; 779 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 780 ipmiMaxUserName); 781 if (userName.empty()) 782 { 783 log<level::DEBUG>("User name not set / invalid"); 784 return ccUnspecifiedError; 785 } 786 if (userInfo->userEnabled != enabledState) 787 { 788 std::string userPath = std::string(userObjBasePath) + "/" + userName; 789 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface, 790 userEnabledProperty, enabledState); 791 userInfo->userEnabled = enabledState; 792 try 793 { 794 writeUserData(); 795 } 796 catch (const std::exception& e) 797 { 798 log<level::DEBUG>("Write user data failed"); 799 return ccUnspecifiedError; 800 } 801 } 802 return ccSuccess; 803 } 804 805 Cc UserAccess::setUserPayloadAccess(const uint8_t chNum, 806 const uint8_t operation, 807 const uint8_t userId, 808 const PayloadAccess& payloadAccess) 809 { 810 constexpr uint8_t enable = 0x0; 811 constexpr uint8_t disable = 0x1; 812 813 if (!isValidChannel(chNum)) 814 { 815 return ccInvalidFieldRequest; 816 } 817 if (!isValidUserId(userId)) 818 { 819 return ccParmOutOfRange; 820 } 821 if (operation != enable && operation != disable) 822 { 823 return ccInvalidFieldRequest; 824 } 825 // Check operation & payloadAccess if required. 826 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 827 userLock{*userMutex}; 828 UserInfo* userInfo = getUserInfo(userId); 829 830 if (operation == enable) 831 { 832 userInfo->payloadAccess[chNum].stdPayloadEnables1 |= 833 payloadAccess.stdPayloadEnables1; 834 835 userInfo->payloadAccess[chNum].oemPayloadEnables1 |= 836 payloadAccess.oemPayloadEnables1; 837 } 838 else 839 { 840 userInfo->payloadAccess[chNum].stdPayloadEnables1 &= 841 ~(payloadAccess.stdPayloadEnables1); 842 843 userInfo->payloadAccess[chNum].oemPayloadEnables1 &= 844 ~(payloadAccess.oemPayloadEnables1); 845 } 846 847 try 848 { 849 writeUserData(); 850 } 851 catch (const std::exception& e) 852 { 853 log<level::ERR>("Write user data failed"); 854 return ccUnspecifiedError; 855 } 856 return ccSuccess; 857 } 858 859 Cc UserAccess::setUserPrivilegeAccess(const uint8_t userId, const uint8_t chNum, 860 const UserPrivAccess& privAccess, 861 const bool& otherPrivUpdates) 862 { 863 if (!isValidChannel(chNum)) 864 { 865 return ccInvalidFieldRequest; 866 } 867 if (!isValidUserId(userId)) 868 { 869 return ccParmOutOfRange; 870 } 871 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 872 userLock{*userMutex}; 873 UserInfo* userInfo = getUserInfo(userId); 874 std::string userName; 875 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 876 ipmiMaxUserName); 877 if (userName.empty()) 878 { 879 log<level::DEBUG>("User name not set / invalid"); 880 return ccUnspecifiedError; 881 } 882 std::string priv = convertToSystemPrivilege( 883 static_cast<CommandPrivilege>(privAccess.privilege)); 884 uint8_t syncIndex = getUsrMgmtSyncIndex(); 885 if (chNum == syncIndex && 886 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege) 887 { 888 std::string userPath = std::string(userObjBasePath) + "/" + userName; 889 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface, 890 userPrivProperty, priv); 891 } 892 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege; 893 894 if (otherPrivUpdates) 895 { 896 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled; 897 userInfo->userPrivAccess[chNum].linkAuthEnabled = 898 privAccess.linkAuthEnabled; 899 userInfo->userPrivAccess[chNum].accessCallback = 900 privAccess.accessCallback; 901 } 902 try 903 { 904 writeUserData(); 905 } 906 catch (const std::exception& e) 907 { 908 log<level::DEBUG>("Write user data failed"); 909 return ccUnspecifiedError; 910 } 911 return ccSuccess; 912 } 913 914 uint8_t UserAccess::getUserId(const std::string& userName) 915 { 916 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 917 userLock{*userMutex}; 918 checkAndReloadUserData(); 919 // user index 0 is reserved, starts with 1 920 size_t usrIndex = 1; 921 for (; usrIndex <= ipmiMaxUsers; ++usrIndex) 922 { 923 std::string curName( 924 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 925 ipmiMaxUserName); 926 if (userName == curName) 927 { 928 break; // found the entry 929 } 930 } 931 if (usrIndex > ipmiMaxUsers) 932 { 933 log<level::DEBUG>("User not found", 934 entry("USER_NAME=%s", userName.c_str())); 935 return invalidUserId; 936 } 937 938 return usrIndex; 939 } 940 941 Cc UserAccess::getUserName(const uint8_t userId, std::string& userName) 942 { 943 if (!isValidUserId(userId)) 944 { 945 return ccParmOutOfRange; 946 } 947 UserInfo* userInfo = getUserInfo(userId); 948 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 949 ipmiMaxUserName); 950 return ccSuccess; 951 } 952 953 bool UserAccess::isIpmiInAvailableGroupList() 954 { 955 if (std::find(availableGroups.begin(), availableGroups.end(), 956 ipmiGrpName) != availableGroups.end()) 957 { 958 return true; 959 } 960 if (availableGroups.empty()) 961 { 962 // available groups shouldn't be empty, re-query 963 getSystemPrivAndGroups(); 964 if (std::find(availableGroups.begin(), availableGroups.end(), 965 ipmiGrpName) != availableGroups.end()) 966 { 967 return true; 968 } 969 } 970 return false; 971 } 972 973 Cc UserAccess::setUserName(const uint8_t userId, const std::string& userName) 974 { 975 if (!isValidUserId(userId)) 976 { 977 return ccParmOutOfRange; 978 } 979 980 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 981 userLock{*userMutex}; 982 std::string oldUser; 983 getUserName(userId, oldUser); 984 985 if (oldUser == userName) 986 { 987 // requesting to set the same user name, return success. 988 return ccSuccess; 989 } 990 991 bool validUser = isValidUserName(userName); 992 UserInfo* userInfo = getUserInfo(userId); 993 if (userName.empty() && !oldUser.empty()) 994 { 995 // Delete existing user 996 std::string userPath = std::string(userObjBasePath) + "/" + oldUser; 997 try 998 { 999 auto method = bus.new_method_call( 1000 getUserServiceName().c_str(), userPath.c_str(), 1001 deleteUserInterface, deleteUserMethod); 1002 auto reply = bus.call(method); 1003 } 1004 catch (const sdbusplus::exception::SdBusError& e) 1005 { 1006 log<level::DEBUG>("Failed to excute method", 1007 entry("METHOD=%s", deleteUserMethod), 1008 entry("PATH=%s", userPath.c_str())); 1009 return ccUnspecifiedError; 1010 } 1011 deleteUserIndex(userId); 1012 } 1013 else if (oldUser.empty() && !userName.empty() && validUser) 1014 { 1015 try 1016 { 1017 if (!isIpmiInAvailableGroupList()) 1018 { 1019 return ccUnspecifiedError; 1020 } 1021 // Create new user 1022 auto method = bus.new_method_call( 1023 getUserServiceName().c_str(), userMgrObjBasePath, 1024 userMgrInterface, createUserMethod); 1025 method.append(userName.c_str(), availableGroups, "", false); 1026 auto reply = bus.call(method); 1027 } 1028 catch (const sdbusplus::exception::SdBusError& e) 1029 { 1030 log<level::DEBUG>("Failed to excute method", 1031 entry("METHOD=%s", createUserMethod), 1032 entry("PATH=%s", userMgrObjBasePath)); 1033 return ccUnspecifiedError; 1034 } 1035 1036 std::memset(userInfo->userName, 0, sizeof(userInfo->userName)); 1037 std::memcpy(userInfo->userName, 1038 static_cast<const void*>(userName.data()), userName.size()); 1039 userInfo->userInSystem = true; 1040 } 1041 else if (oldUser != userName && validUser) 1042 { 1043 try 1044 { 1045 // User rename 1046 auto method = bus.new_method_call( 1047 getUserServiceName().c_str(), userMgrObjBasePath, 1048 userMgrInterface, renameUserMethod); 1049 method.append(oldUser.c_str(), userName.c_str()); 1050 auto reply = bus.call(method); 1051 } 1052 catch (const sdbusplus::exception::SdBusError& e) 1053 { 1054 log<level::DEBUG>("Failed to excute method", 1055 entry("METHOD=%s", renameUserMethod), 1056 entry("PATH=%s", userMgrObjBasePath)); 1057 return ccUnspecifiedError; 1058 } 1059 std::fill(static_cast<uint8_t*>(userInfo->userName), 1060 static_cast<uint8_t*>(userInfo->userName) + 1061 sizeof(userInfo->userName), 1062 0); 1063 1064 std::memset(userInfo->userName, 0, sizeof(userInfo->userName)); 1065 std::memcpy(userInfo->userName, 1066 static_cast<const void*>(userName.data()), userName.size()); 1067 1068 ipmiRenameUserEntryPassword(oldUser, userName); 1069 userInfo->userInSystem = true; 1070 } 1071 else if (!validUser) 1072 { 1073 return ccInvalidFieldRequest; 1074 } 1075 try 1076 { 1077 writeUserData(); 1078 } 1079 catch (const std::exception& e) 1080 { 1081 log<level::DEBUG>("Write user data failed"); 1082 return ccUnspecifiedError; 1083 } 1084 return ccSuccess; 1085 } 1086 1087 static constexpr const char* jsonUserName = "user_name"; 1088 static constexpr const char* jsonPriv = "privilege"; 1089 static constexpr const char* jsonIpmiEnabled = "ipmi_enabled"; 1090 static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled"; 1091 static constexpr const char* jsonAccCallbk = "access_callback"; 1092 static constexpr const char* jsonUserEnabled = "user_enabled"; 1093 static constexpr const char* jsonUserInSys = "user_in_system"; 1094 static constexpr const char* jsonFixedUser = "fixed_user_name"; 1095 static constexpr const char* payloadEnabledStr = "payload_enabled"; 1096 static constexpr const char* stdPayloadStr = "std_payload"; 1097 static constexpr const char* oemPayloadStr = "OEM_payload"; 1098 1099 /** @brief to construct a JSON object from the given payload access details. 1100 * 1101 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input) 1102 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input) 1103 * 1104 * @details Sample output JSON object format : 1105 * "payload_enabled":{ 1106 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1107 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1108 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1109 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1110 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1111 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1112 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1113 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1114 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1115 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1116 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1117 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1118 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1119 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1120 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1121 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1122 * } 1123 */ 1124 static const Json constructJsonPayloadEnables( 1125 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1126 stdPayload, 1127 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1128 oemPayload) 1129 { 1130 Json jsonPayloadEnabled; 1131 1132 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++) 1133 { 1134 std::ostringstream stdPayloadStream; 1135 std::ostringstream oemPayloadStream; 1136 1137 stdPayloadStream << stdPayloadStr << payloadNum; 1138 oemPayloadStream << oemPayloadStr << payloadNum; 1139 1140 jsonPayloadEnabled.push_back(Json::object_t::value_type( 1141 stdPayloadStream.str(), stdPayload[payloadNum])); 1142 1143 jsonPayloadEnabled.push_back(Json::object_t::value_type( 1144 oemPayloadStream.str(), oemPayload[payloadNum])); 1145 } 1146 return jsonPayloadEnabled; 1147 } 1148 1149 void UserAccess::readPayloadAccessFromUserInfo( 1150 const UserInfo& userInfo, 1151 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload, 1152 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload) 1153 { 1154 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++) 1155 { 1156 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1157 { 1158 stdPayload[payloadNum][chIndex] = 1159 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum]; 1160 1161 oemPayload[payloadNum][chIndex] = 1162 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum]; 1163 } 1164 } 1165 } 1166 1167 void UserAccess::updatePayloadAccessInUserInfo( 1168 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1169 stdPayload, 1170 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1171 oemPayload, 1172 UserInfo& userInfo) 1173 { 1174 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1175 { 1176 // Ensure that reserved/unsupported payloads are marked to zero. 1177 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset(); 1178 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset(); 1179 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset(); 1180 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset(); 1181 // Update SOL status as it is the only supported payload currently. 1182 userInfo.payloadAccess[chIndex] 1183 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] = 1184 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex]; 1185 } 1186 } 1187 1188 void UserAccess::readUserData() 1189 { 1190 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1191 userLock{*userMutex}; 1192 1193 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary); 1194 if (!iUsrData.good()) 1195 { 1196 log<level::ERR>("Error in reading IPMI user data file"); 1197 throw std::ios_base::failure("Error opening IPMI user data file"); 1198 } 1199 1200 Json jsonUsersTbl = Json::array(); 1201 jsonUsersTbl = Json::parse(iUsrData, nullptr, false); 1202 1203 if (jsonUsersTbl.size() != ipmiMaxUsers) 1204 { 1205 log<level::ERR>( 1206 "Error in reading IPMI user data file - User count issues"); 1207 throw std::runtime_error( 1208 "Corrupted IPMI user data file - invalid user count"); 1209 } 1210 1211 // user index 0 is reserved, starts with 1 1212 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1213 { 1214 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0. 1215 if (userInfo.is_null()) 1216 { 1217 log<level::ERR>("Error in reading IPMI user data file - " 1218 "user info corrupted"); 1219 throw std::runtime_error( 1220 "Corrupted IPMI user data file - invalid user info"); 1221 } 1222 std::string userName = userInfo[jsonUserName].get<std::string>(); 1223 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 1224 userName.c_str(), ipmiMaxUserName); 1225 1226 std::vector<std::string> privilege = 1227 userInfo[jsonPriv].get<std::vector<std::string>>(); 1228 std::vector<bool> ipmiEnabled = 1229 userInfo[jsonIpmiEnabled].get<std::vector<bool>>(); 1230 std::vector<bool> linkAuthEnabled = 1231 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>(); 1232 std::vector<bool> accessCallback = 1233 userInfo[jsonAccCallbk].get<std::vector<bool>>(); 1234 1235 // Payload Enables Processing. 1236 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1237 stdPayload = {}; 1238 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1239 oemPayload = {}; 1240 try 1241 { 1242 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr); 1243 for (auto payloadNum = 0; payloadNum < payloadsPerByte; 1244 payloadNum++) 1245 { 1246 std::ostringstream stdPayloadStream; 1247 std::ostringstream oemPayloadStream; 1248 1249 stdPayloadStream << stdPayloadStr << payloadNum; 1250 oemPayloadStream << oemPayloadStr << payloadNum; 1251 1252 stdPayload[payloadNum] = 1253 jsonPayloadEnabled[stdPayloadStream.str()] 1254 .get<std::array<bool, ipmiMaxChannels>>(); 1255 oemPayload[payloadNum] = 1256 jsonPayloadEnabled[oemPayloadStream.str()] 1257 .get<std::array<bool, ipmiMaxChannels>>(); 1258 1259 if (stdPayload[payloadNum].size() != ipmiMaxChannels || 1260 oemPayload[payloadNum].size() != ipmiMaxChannels) 1261 { 1262 log<level::ERR>("Error in reading IPMI user data file - " 1263 "payload properties corrupted"); 1264 throw std::runtime_error( 1265 "Corrupted IPMI user data file - payload properties"); 1266 } 1267 } 1268 } 1269 catch (Json::out_of_range& e) 1270 { 1271 // Key not found in 'userInfo'; possibly an old JSON file. Use 1272 // default values for all payloads, and SOL payload default is true. 1273 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true); 1274 } 1275 1276 if (privilege.size() != ipmiMaxChannels || 1277 ipmiEnabled.size() != ipmiMaxChannels || 1278 linkAuthEnabled.size() != ipmiMaxChannels || 1279 accessCallback.size() != ipmiMaxChannels) 1280 { 1281 log<level::ERR>("Error in reading IPMI user data file - " 1282 "properties corrupted"); 1283 throw std::runtime_error( 1284 "Corrupted IPMI user data file - properties"); 1285 } 1286 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1287 { 1288 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege = 1289 static_cast<uint8_t>( 1290 convertToIPMIPrivilege(privilege[chIndex])); 1291 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled = 1292 ipmiEnabled[chIndex]; 1293 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled = 1294 linkAuthEnabled[chIndex]; 1295 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback = 1296 accessCallback[chIndex]; 1297 } 1298 updatePayloadAccessInUserInfo(stdPayload, oemPayload, 1299 usersTbl.user[usrIndex]); 1300 usersTbl.user[usrIndex].userEnabled = 1301 userInfo[jsonUserEnabled].get<bool>(); 1302 usersTbl.user[usrIndex].userInSystem = 1303 userInfo[jsonUserInSys].get<bool>(); 1304 usersTbl.user[usrIndex].fixedUserName = 1305 userInfo[jsonFixedUser].get<bool>(); 1306 } 1307 1308 log<level::DEBUG>("User data read from IPMI data file"); 1309 iUsrData.close(); 1310 // Update the timestamp 1311 fileLastUpdatedTime = getUpdatedFileTime(); 1312 return; 1313 } 1314 1315 void UserAccess::writeUserData() 1316 { 1317 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1318 userLock{*userMutex}; 1319 1320 Json jsonUsersTbl = Json::array(); 1321 // user index 0 is reserved, starts with 1 1322 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1323 { 1324 Json jsonUserInfo; 1325 jsonUserInfo[jsonUserName] = std::string( 1326 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 1327 ipmiMaxUserName); 1328 std::vector<std::string> privilege(ipmiMaxChannels); 1329 std::vector<bool> ipmiEnabled(ipmiMaxChannels); 1330 std::vector<bool> linkAuthEnabled(ipmiMaxChannels); 1331 std::vector<bool> accessCallback(ipmiMaxChannels); 1332 1333 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1334 stdPayload; 1335 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1336 oemPayload; 1337 1338 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1339 { 1340 privilege[chIndex] = 1341 convertToSystemPrivilege(static_cast<CommandPrivilege>( 1342 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege)); 1343 ipmiEnabled[chIndex] = 1344 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled; 1345 linkAuthEnabled[chIndex] = 1346 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled; 1347 accessCallback[chIndex] = 1348 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback; 1349 } 1350 jsonUserInfo[jsonPriv] = privilege; 1351 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled; 1352 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled; 1353 jsonUserInfo[jsonAccCallbk] = accessCallback; 1354 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled; 1355 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem; 1356 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName; 1357 1358 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload, 1359 oemPayload); 1360 Json jsonPayloadEnabledInfo = 1361 constructJsonPayloadEnables(stdPayload, oemPayload); 1362 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo; 1363 1364 jsonUsersTbl.push_back(jsonUserInfo); 1365 } 1366 1367 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"}; 1368 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC, 1369 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 1370 if (fd < 0) 1371 { 1372 log<level::ERR>("Error in creating temporary IPMI user data file"); 1373 throw std::ios_base::failure( 1374 "Error in creating temporary IPMI user data file"); 1375 } 1376 const auto& writeStr = jsonUsersTbl.dump(); 1377 if (write(fd, writeStr.c_str(), writeStr.size()) != 1378 static_cast<ssize_t>(writeStr.size())) 1379 { 1380 close(fd); 1381 log<level::ERR>("Error in writing temporary IPMI user data file"); 1382 throw std::ios_base::failure( 1383 "Error in writing temporary IPMI user data file"); 1384 } 1385 close(fd); 1386 1387 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0) 1388 { 1389 log<level::ERR>("Error in renaming temporary IPMI user data file"); 1390 throw std::runtime_error("Error in renaming IPMI user data file"); 1391 } 1392 // Update the timestamp 1393 fileLastUpdatedTime = getUpdatedFileTime(); 1394 return; 1395 } 1396 1397 bool UserAccess::addUserEntry(const std::string& userName, 1398 const std::string& sysPriv, const bool& enabled) 1399 { 1400 UsersTbl* userData = getUsersTblPtr(); 1401 size_t freeIndex = 0xFF; 1402 // user index 0 is reserved, starts with 1 1403 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1404 { 1405 std::string curName( 1406 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 1407 ipmiMaxUserName); 1408 if (userName == curName) 1409 { 1410 log<level::DEBUG>("User name exists", 1411 entry("USER_NAME=%s", userName.c_str())); 1412 return false; // user name exists. 1413 } 1414 1415 if ((!userData->user[usrIndex].userInSystem) && 1416 (userData->user[usrIndex].userName[0] == '\0') && 1417 (freeIndex == 0xFF)) 1418 { 1419 freeIndex = usrIndex; 1420 } 1421 } 1422 if (freeIndex == 0xFF) 1423 { 1424 log<level::ERR>("No empty slots found"); 1425 return false; 1426 } 1427 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName), 1428 userName.c_str(), ipmiMaxUserName); 1429 uint8_t priv = 1430 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) & 1431 privMask; 1432 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1433 { 1434 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv; 1435 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true; 1436 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled = 1437 true; 1438 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true; 1439 } 1440 userData->user[freeIndex].userInSystem = true; 1441 userData->user[freeIndex].userEnabled = enabled; 1442 1443 return true; 1444 } 1445 1446 void UserAccess::deleteUserIndex(const size_t& usrIdx) 1447 { 1448 UsersTbl* userData = getUsersTblPtr(); 1449 1450 std::string userName( 1451 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1452 ipmiMaxUserName); 1453 ipmiClearUserEntryPassword(userName); 1454 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName), 1455 static_cast<uint8_t*>(userData->user[usrIdx].userName) + 1456 sizeof(userData->user[usrIdx].userName), 1457 0); 1458 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1459 { 1460 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess; 1461 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false; 1462 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false; 1463 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false; 1464 } 1465 userData->user[usrIdx].userInSystem = false; 1466 userData->user[usrIdx].userEnabled = false; 1467 return; 1468 } 1469 1470 void UserAccess::checkAndReloadUserData() 1471 { 1472 std::time_t updateTime = getUpdatedFileTime(); 1473 if (updateTime != fileLastUpdatedTime || updateTime == -EIO) 1474 { 1475 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1476 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1477 readUserData(); 1478 } 1479 return; 1480 } 1481 1482 UsersTbl* UserAccess::getUsersTblPtr() 1483 { 1484 // reload data before using it. 1485 checkAndReloadUserData(); 1486 return &usersTbl; 1487 } 1488 1489 void UserAccess::getSystemPrivAndGroups() 1490 { 1491 std::map<std::string, PrivAndGroupType> properties; 1492 try 1493 { 1494 auto method = bus.new_method_call( 1495 getUserServiceName().c_str(), userMgrObjBasePath, 1496 dBusPropertiesInterface, getAllPropertiesMethod); 1497 method.append(userMgrInterface); 1498 1499 auto reply = bus.call(method); 1500 reply.read(properties); 1501 } 1502 catch (const sdbusplus::exception::SdBusError& e) 1503 { 1504 log<level::DEBUG>("Failed to excute method", 1505 entry("METHOD=%s", getAllPropertiesMethod), 1506 entry("PATH=%s", userMgrObjBasePath)); 1507 return; 1508 } 1509 for (const auto& t : properties) 1510 { 1511 auto key = t.first; 1512 if (key == allPrivProperty) 1513 { 1514 availablePrivileges = std::get<std::vector<std::string>>(t.second); 1515 } 1516 else if (key == allGrpProperty) 1517 { 1518 availableGroups = std::get<std::vector<std::string>>(t.second); 1519 } 1520 } 1521 // TODO: Implement Supported Privilege & Groups verification logic 1522 return; 1523 } 1524 1525 std::time_t UserAccess::getUpdatedFileTime() 1526 { 1527 struct stat fileStat; 1528 if (stat(ipmiUserDataFile, &fileStat) != 0) 1529 { 1530 log<level::DEBUG>("Error in getting last updated time stamp"); 1531 return -EIO; 1532 } 1533 return fileStat.st_mtime; 1534 } 1535 1536 void UserAccess::getUserProperties(const DbusUserObjProperties& properties, 1537 std::vector<std::string>& usrGrps, 1538 std::string& usrPriv, bool& usrEnabled) 1539 { 1540 for (const auto& t : properties) 1541 { 1542 std::string key = t.first; 1543 if (key == userPrivProperty) 1544 { 1545 usrPriv = std::get<std::string>(t.second); 1546 } 1547 else if (key == userGrpProperty) 1548 { 1549 usrGrps = std::get<std::vector<std::string>>(t.second); 1550 } 1551 else if (key == userEnabledProperty) 1552 { 1553 usrEnabled = std::get<bool>(t.second); 1554 } 1555 } 1556 return; 1557 } 1558 1559 int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs, 1560 std::vector<std::string>& usrGrps, 1561 std::string& usrPriv, bool& usrEnabled) 1562 { 1563 auto usrObj = userObjs.find(usersInterface); 1564 if (usrObj != userObjs.end()) 1565 { 1566 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled); 1567 return 0; 1568 } 1569 return -EIO; 1570 } 1571 1572 void UserAccess::cacheUserDataFile() 1573 { 1574 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1575 userLock{*userMutex}; 1576 try 1577 { 1578 readUserData(); 1579 } 1580 catch (const std::ios_base::failure& e) 1581 { // File is empty, create it for the first time 1582 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1583 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1584 // user index 0 is reserved, starts with 1 1585 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex) 1586 { 1587 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1588 { 1589 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege = 1590 privNoAccess; 1591 usersTbl.user[userIndex] 1592 .payloadAccess[chIndex] 1593 .stdPayloadEnables1[static_cast<uint8_t>( 1594 ipmi::PayloadType::SOL)] = true; 1595 } 1596 } 1597 writeUserData(); 1598 } 1599 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile); 1600 // Register it for single object and single process either netipimd / 1601 // host-ipmid 1602 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock()) 1603 { 1604 log<level::DEBUG>("Registering signal handler"); 1605 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>( 1606 bus, 1607 sdbusplus::bus::match::rules::type::signal() + 1608 sdbusplus::bus::match::rules::interface(dBusObjManager) + 1609 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 1610 [&](sdbusplus::message::message& msg) { 1611 userUpdatedSignalHandler(*this, msg); 1612 }); 1613 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>( 1614 bus, 1615 sdbusplus::bus::match::rules::type::signal() + 1616 sdbusplus::bus::match::rules::interface(userMgrInterface) + 1617 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 1618 [&](sdbusplus::message::message& msg) { 1619 userUpdatedSignalHandler(*this, msg); 1620 }); 1621 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>( 1622 bus, 1623 sdbusplus::bus::match::rules::type::signal() + 1624 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) + 1625 sdbusplus::bus::match::rules::interface( 1626 dBusPropertiesInterface) + 1627 sdbusplus::bus::match::rules::member(propertiesChangedSignal) + 1628 sdbusplus::bus::match::rules::argN(0, usersInterface), 1629 [&](sdbusplus::message::message& msg) { 1630 userUpdatedSignalHandler(*this, msg); 1631 }); 1632 signalHndlrObject = true; 1633 } 1634 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs; 1635 try 1636 { 1637 auto method = bus.new_method_call(getUserServiceName().c_str(), 1638 userMgrObjBasePath, dBusObjManager, 1639 getManagedObjectsMethod); 1640 auto reply = bus.call(method); 1641 reply.read(managedObjs); 1642 } 1643 catch (const sdbusplus::exception::SdBusError& e) 1644 { 1645 log<level::DEBUG>("Failed to excute method", 1646 entry("METHOD=%s", getSubTreeMethod), 1647 entry("PATH=%s", userMgrObjBasePath)); 1648 return; 1649 } 1650 bool updateRequired = false; 1651 UsersTbl* userData = &usersTbl; 1652 // user index 0 is reserved, starts with 1 1653 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx) 1654 { 1655 if ((userData->user[usrIdx].userInSystem) && 1656 (userData->user[usrIdx].userName[0] != '\0')) 1657 { 1658 std::vector<std::string> usrGrps; 1659 std::string usrPriv; 1660 1661 std::string userName( 1662 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1663 ipmiMaxUserName); 1664 std::string usersPath = 1665 std::string(userObjBasePath) + "/" + userName; 1666 1667 auto usrObj = managedObjs.find(usersPath); 1668 if (usrObj != managedObjs.end()) 1669 { 1670 bool usrEnabled = false; 1671 1672 // User exist. Lets check and update other fileds 1673 getUserObjProperties(usrObj->second, usrGrps, usrPriv, 1674 usrEnabled); 1675 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) == 1676 usrGrps.end()) 1677 { 1678 updateRequired = true; 1679 // Group "ipmi" is removed so lets remove user in IPMI 1680 deleteUserIndex(usrIdx); 1681 } 1682 else 1683 { 1684 // Group "ipmi" is present so lets update other properties 1685 // in IPMI 1686 uint8_t priv = 1687 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask; 1688 // Update all channels priv, only if it is not equivalent to 1689 // getUsrMgmtSyncIndex() 1690 if (userData->user[usrIdx] 1691 .userPrivAccess[getUsrMgmtSyncIndex()] 1692 .privilege != priv) 1693 { 1694 updateRequired = true; 1695 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 1696 ++chIndex) 1697 { 1698 userData->user[usrIdx] 1699 .userPrivAccess[chIndex] 1700 .privilege = priv; 1701 } 1702 } 1703 if (userData->user[usrIdx].userEnabled != usrEnabled) 1704 { 1705 updateRequired = true; 1706 userData->user[usrIdx].userEnabled = usrEnabled; 1707 } 1708 } 1709 1710 // We are done with this obj. lets delete from MAP 1711 managedObjs.erase(usrObj); 1712 } 1713 else 1714 { 1715 updateRequired = true; 1716 deleteUserIndex(usrIdx); 1717 } 1718 } 1719 } 1720 1721 // Walk through remnaining managedObj users list 1722 // Add them to ipmi data base 1723 for (const auto& usrObj : managedObjs) 1724 { 1725 std::vector<std::string> usrGrps; 1726 std::string usrPriv, userName; 1727 bool usrEnabled = false; 1728 std::string usrObjPath = std::string(usrObj.first); 1729 if (getUserNameFromPath(usrObj.first.str, userName) != 0) 1730 { 1731 log<level::ERR>("Error in user object path"); 1732 continue; 1733 } 1734 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled); 1735 // Add 'ipmi' group users 1736 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) != 1737 usrGrps.end()) 1738 { 1739 updateRequired = true; 1740 // CREATE NEW USER 1741 if (true != addUserEntry(userName, usrPriv, usrEnabled)) 1742 { 1743 break; 1744 } 1745 } 1746 } 1747 1748 if (updateRequired) 1749 { 1750 // All userData slots update done. Lets write the data 1751 writeUserData(); 1752 } 1753 1754 return; 1755 } 1756 } // namespace ipmi 1757