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