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