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