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); 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, 1062 ipmiPrivIndex[PRIVILEGE_USER], false); 1063 auto reply = bus.call(method); 1064 } 1065 catch (const sdbusplus::exception_t& e) 1066 { 1067 log<level::DEBUG>("Failed to excute method", 1068 entry("METHOD=%s", createUserMethod), 1069 entry("PATH=%s", userMgrObjBasePath)); 1070 return ccUnspecifiedError; 1071 } 1072 1073 std::memset(userInfo->userName, 0, sizeof(userInfo->userName)); 1074 std::memcpy(userInfo->userName, 1075 static_cast<const void*>(userName.data()), userName.size()); 1076 userInfo->userInSystem = true; 1077 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1078 { 1079 userInfo->userPrivAccess[chIndex].privilege = 1080 static_cast<uint8_t>(PRIVILEGE_USER); 1081 } 1082 } 1083 else if (oldUser != userName && validUser) 1084 { 1085 try 1086 { 1087 // User rename 1088 auto method = bus.new_method_call( 1089 getUserServiceName().c_str(), userMgrObjBasePath, 1090 userMgrInterface, renameUserMethod); 1091 method.append(oldUser.c_str(), userName.c_str()); 1092 auto reply = bus.call(method); 1093 } 1094 catch (const sdbusplus::exception_t& e) 1095 { 1096 log<level::DEBUG>("Failed to excute method", 1097 entry("METHOD=%s", renameUserMethod), 1098 entry("PATH=%s", userMgrObjBasePath)); 1099 return ccUnspecifiedError; 1100 } 1101 std::fill(static_cast<uint8_t*>(userInfo->userName), 1102 static_cast<uint8_t*>(userInfo->userName) + 1103 sizeof(userInfo->userName), 1104 0); 1105 1106 std::memset(userInfo->userName, 0, sizeof(userInfo->userName)); 1107 std::memcpy(userInfo->userName, 1108 static_cast<const void*>(userName.data()), userName.size()); 1109 1110 ipmiRenameUserEntryPassword(oldUser, userName); 1111 userInfo->userInSystem = true; 1112 } 1113 else if (!validUser) 1114 { 1115 return ccInvalidFieldRequest; 1116 } 1117 try 1118 { 1119 writeUserData(); 1120 } 1121 catch (const std::exception& e) 1122 { 1123 log<level::DEBUG>("Write user data failed"); 1124 return ccUnspecifiedError; 1125 } 1126 return ccSuccess; 1127 } 1128 1129 static constexpr const char* jsonUserName = "user_name"; 1130 static constexpr const char* jsonPriv = "privilege"; 1131 static constexpr const char* jsonIpmiEnabled = "ipmi_enabled"; 1132 static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled"; 1133 static constexpr const char* jsonAccCallbk = "access_callback"; 1134 static constexpr const char* jsonUserEnabled = "user_enabled"; 1135 static constexpr const char* jsonUserInSys = "user_in_system"; 1136 static constexpr const char* jsonFixedUser = "fixed_user_name"; 1137 static constexpr const char* payloadEnabledStr = "payload_enabled"; 1138 static constexpr const char* stdPayloadStr = "std_payload"; 1139 static constexpr const char* oemPayloadStr = "OEM_payload"; 1140 1141 /** @brief to construct a JSON object from the given payload access details. 1142 * 1143 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input) 1144 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input) 1145 * 1146 * @details Sample output JSON object format : 1147 * "payload_enabled":{ 1148 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1149 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1150 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1151 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1152 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1153 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1154 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1155 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1156 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1157 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1158 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1159 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1160 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1161 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1162 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1163 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1164 * } 1165 */ 1166 static const Json constructJsonPayloadEnables( 1167 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1168 stdPayload, 1169 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1170 oemPayload) 1171 { 1172 Json jsonPayloadEnabled; 1173 1174 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++) 1175 { 1176 std::ostringstream stdPayloadStream; 1177 std::ostringstream oemPayloadStream; 1178 1179 stdPayloadStream << stdPayloadStr << payloadNum; 1180 oemPayloadStream << oemPayloadStr << payloadNum; 1181 1182 jsonPayloadEnabled.push_back(Json::object_t::value_type( 1183 stdPayloadStream.str(), stdPayload[payloadNum])); 1184 1185 jsonPayloadEnabled.push_back(Json::object_t::value_type( 1186 oemPayloadStream.str(), oemPayload[payloadNum])); 1187 } 1188 return jsonPayloadEnabled; 1189 } 1190 1191 void UserAccess::readPayloadAccessFromUserInfo( 1192 const UserInfo& userInfo, 1193 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload, 1194 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload) 1195 { 1196 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++) 1197 { 1198 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1199 { 1200 stdPayload[payloadNum][chIndex] = 1201 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum]; 1202 1203 oemPayload[payloadNum][chIndex] = 1204 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum]; 1205 } 1206 } 1207 } 1208 1209 void UserAccess::updatePayloadAccessInUserInfo( 1210 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1211 stdPayload, 1212 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&, 1213 UserInfo& userInfo) 1214 { 1215 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1216 { 1217 // Ensure that reserved/unsupported payloads are marked to zero. 1218 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset(); 1219 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset(); 1220 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset(); 1221 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset(); 1222 // Update SOL status as it is the only supported payload currently. 1223 userInfo.payloadAccess[chIndex] 1224 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] = 1225 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex]; 1226 } 1227 } 1228 1229 void UserAccess::readUserData() 1230 { 1231 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1232 userLock{*userMutex}; 1233 1234 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary); 1235 if (!iUsrData.good()) 1236 { 1237 log<level::ERR>("Error in reading IPMI user data file"); 1238 throw std::ios_base::failure("Error opening IPMI user data file"); 1239 } 1240 1241 Json jsonUsersTbl = Json::array(); 1242 jsonUsersTbl = Json::parse(iUsrData, nullptr, false); 1243 1244 if (jsonUsersTbl.size() != ipmiMaxUsers) 1245 { 1246 log<level::ERR>( 1247 "Error in reading IPMI user data file - User count issues"); 1248 throw std::runtime_error( 1249 "Corrupted IPMI user data file - invalid user count"); 1250 } 1251 1252 // user index 0 is reserved, starts with 1 1253 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1254 { 1255 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0. 1256 if (userInfo.is_null()) 1257 { 1258 log<level::ERR>("Error in reading IPMI user data file - " 1259 "user info corrupted"); 1260 throw std::runtime_error( 1261 "Corrupted IPMI user data file - invalid user info"); 1262 } 1263 std::string userName = userInfo[jsonUserName].get<std::string>(); 1264 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 1265 userName.c_str(), ipmiMaxUserName); 1266 1267 std::vector<std::string> privilege = 1268 userInfo[jsonPriv].get<std::vector<std::string>>(); 1269 std::vector<bool> ipmiEnabled = 1270 userInfo[jsonIpmiEnabled].get<std::vector<bool>>(); 1271 std::vector<bool> linkAuthEnabled = 1272 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>(); 1273 std::vector<bool> accessCallback = 1274 userInfo[jsonAccCallbk].get<std::vector<bool>>(); 1275 1276 // Payload Enables Processing. 1277 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1278 stdPayload = {}; 1279 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1280 oemPayload = {}; 1281 try 1282 { 1283 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr); 1284 for (auto payloadNum = 0; payloadNum < payloadsPerByte; 1285 payloadNum++) 1286 { 1287 std::ostringstream stdPayloadStream; 1288 std::ostringstream oemPayloadStream; 1289 1290 stdPayloadStream << stdPayloadStr << payloadNum; 1291 oemPayloadStream << oemPayloadStr << payloadNum; 1292 1293 stdPayload[payloadNum] = 1294 jsonPayloadEnabled[stdPayloadStream.str()] 1295 .get<std::array<bool, ipmiMaxChannels>>(); 1296 oemPayload[payloadNum] = 1297 jsonPayloadEnabled[oemPayloadStream.str()] 1298 .get<std::array<bool, ipmiMaxChannels>>(); 1299 1300 if (stdPayload[payloadNum].size() != ipmiMaxChannels || 1301 oemPayload[payloadNum].size() != ipmiMaxChannels) 1302 { 1303 log<level::ERR>("Error in reading IPMI user data file - " 1304 "payload properties corrupted"); 1305 throw std::runtime_error( 1306 "Corrupted IPMI user data file - payload properties"); 1307 } 1308 } 1309 } 1310 catch (const Json::out_of_range& e) 1311 { 1312 // Key not found in 'userInfo'; possibly an old JSON file. Use 1313 // default values for all payloads, and SOL payload default is true. 1314 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true); 1315 } 1316 1317 if (privilege.size() != ipmiMaxChannels || 1318 ipmiEnabled.size() != ipmiMaxChannels || 1319 linkAuthEnabled.size() != ipmiMaxChannels || 1320 accessCallback.size() != ipmiMaxChannels) 1321 { 1322 log<level::ERR>("Error in reading IPMI user data file - " 1323 "properties corrupted"); 1324 throw std::runtime_error( 1325 "Corrupted IPMI user data file - properties"); 1326 } 1327 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1328 { 1329 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege = 1330 static_cast<uint8_t>( 1331 convertToIPMIPrivilege(privilege[chIndex])); 1332 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled = 1333 ipmiEnabled[chIndex]; 1334 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled = 1335 linkAuthEnabled[chIndex]; 1336 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback = 1337 accessCallback[chIndex]; 1338 } 1339 updatePayloadAccessInUserInfo(stdPayload, oemPayload, 1340 usersTbl.user[usrIndex]); 1341 usersTbl.user[usrIndex].userEnabled = 1342 userInfo[jsonUserEnabled].get<bool>(); 1343 usersTbl.user[usrIndex].userInSystem = 1344 userInfo[jsonUserInSys].get<bool>(); 1345 usersTbl.user[usrIndex].fixedUserName = 1346 userInfo[jsonFixedUser].get<bool>(); 1347 } 1348 1349 log<level::DEBUG>("User data read from IPMI data file"); 1350 iUsrData.close(); 1351 // Update the timestamp 1352 fileLastUpdatedTime = getUpdatedFileTime(); 1353 return; 1354 } 1355 1356 void UserAccess::writeUserData() 1357 { 1358 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1359 userLock{*userMutex}; 1360 1361 Json jsonUsersTbl = Json::array(); 1362 // user index 0 is reserved, starts with 1 1363 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1364 { 1365 Json jsonUserInfo; 1366 jsonUserInfo[jsonUserName] = std::string( 1367 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 1368 ipmiMaxUserName); 1369 std::vector<std::string> privilege(ipmiMaxChannels); 1370 std::vector<bool> ipmiEnabled(ipmiMaxChannels); 1371 std::vector<bool> linkAuthEnabled(ipmiMaxChannels); 1372 std::vector<bool> accessCallback(ipmiMaxChannels); 1373 1374 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1375 stdPayload; 1376 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1377 oemPayload; 1378 1379 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1380 { 1381 privilege[chIndex] = 1382 convertToSystemPrivilege(static_cast<CommandPrivilege>( 1383 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege)); 1384 ipmiEnabled[chIndex] = 1385 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled; 1386 linkAuthEnabled[chIndex] = 1387 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled; 1388 accessCallback[chIndex] = 1389 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback; 1390 } 1391 jsonUserInfo[jsonPriv] = privilege; 1392 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled; 1393 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled; 1394 jsonUserInfo[jsonAccCallbk] = accessCallback; 1395 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled; 1396 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem; 1397 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName; 1398 1399 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload, 1400 oemPayload); 1401 Json jsonPayloadEnabledInfo = 1402 constructJsonPayloadEnables(stdPayload, oemPayload); 1403 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo; 1404 1405 jsonUsersTbl.push_back(jsonUserInfo); 1406 } 1407 1408 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"}; 1409 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC, 1410 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 1411 if (fd < 0) 1412 { 1413 log<level::ERR>("Error in creating temporary IPMI user data file"); 1414 throw std::ios_base::failure( 1415 "Error in creating temporary IPMI user data file"); 1416 } 1417 const auto& writeStr = jsonUsersTbl.dump(); 1418 if (write(fd, writeStr.c_str(), writeStr.size()) != 1419 static_cast<ssize_t>(writeStr.size())) 1420 { 1421 close(fd); 1422 log<level::ERR>("Error in writing temporary IPMI user data file"); 1423 throw std::ios_base::failure( 1424 "Error in writing temporary IPMI user data file"); 1425 } 1426 close(fd); 1427 1428 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0) 1429 { 1430 log<level::ERR>("Error in renaming temporary IPMI user data file"); 1431 throw std::runtime_error("Error in renaming IPMI user data file"); 1432 } 1433 // Update the timestamp 1434 fileLastUpdatedTime = getUpdatedFileTime(); 1435 return; 1436 } 1437 1438 bool UserAccess::addUserEntry(const std::string& userName, 1439 const std::string& sysPriv, const bool& enabled) 1440 { 1441 UsersTbl* userData = getUsersTblPtr(); 1442 size_t freeIndex = 0xFF; 1443 // user index 0 is reserved, starts with 1 1444 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1445 { 1446 std::string curName( 1447 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 1448 ipmiMaxUserName); 1449 if (userName == curName) 1450 { 1451 log<level::DEBUG>("User name exists", 1452 entry("USER_NAME=%s", userName.c_str())); 1453 return false; // user name exists. 1454 } 1455 1456 if ((!userData->user[usrIndex].userInSystem) && 1457 (userData->user[usrIndex].userName[0] == '\0') && 1458 (freeIndex == 0xFF)) 1459 { 1460 freeIndex = usrIndex; 1461 } 1462 } 1463 if (freeIndex == 0xFF) 1464 { 1465 log<level::ERR>("No empty slots found"); 1466 return false; 1467 } 1468 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName), 1469 userName.c_str(), ipmiMaxUserName); 1470 uint8_t priv = 1471 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) & 1472 privMask; 1473 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1474 { 1475 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv; 1476 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true; 1477 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled = 1478 true; 1479 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true; 1480 } 1481 userData->user[freeIndex].userInSystem = true; 1482 userData->user[freeIndex].userEnabled = enabled; 1483 1484 return true; 1485 } 1486 1487 void UserAccess::deleteUserIndex(const size_t& usrIdx) 1488 { 1489 UsersTbl* userData = getUsersTblPtr(); 1490 1491 std::string userName( 1492 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1493 ipmiMaxUserName); 1494 ipmiClearUserEntryPassword(userName); 1495 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName), 1496 static_cast<uint8_t*>(userData->user[usrIdx].userName) + 1497 sizeof(userData->user[usrIdx].userName), 1498 0); 1499 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1500 { 1501 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess; 1502 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false; 1503 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false; 1504 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false; 1505 } 1506 userData->user[usrIdx].userInSystem = false; 1507 userData->user[usrIdx].userEnabled = false; 1508 return; 1509 } 1510 1511 void UserAccess::checkAndReloadUserData() 1512 { 1513 std::timespec updateTime = getUpdatedFileTime(); 1514 if ((updateTime.tv_sec != fileLastUpdatedTime.tv_sec || 1515 updateTime.tv_nsec != fileLastUpdatedTime.tv_nsec) || 1516 (updateTime.tv_sec == 0 && updateTime.tv_nsec == 0)) 1517 { 1518 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1519 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1520 readUserData(); 1521 } 1522 return; 1523 } 1524 1525 UsersTbl* UserAccess::getUsersTblPtr() 1526 { 1527 // reload data before using it. 1528 checkAndReloadUserData(); 1529 return &usersTbl; 1530 } 1531 1532 void UserAccess::getSystemPrivAndGroups() 1533 { 1534 std::map<std::string, PrivAndGroupType> properties; 1535 try 1536 { 1537 auto method = bus.new_method_call( 1538 getUserServiceName().c_str(), userMgrObjBasePath, 1539 dBusPropertiesInterface, getAllPropertiesMethod); 1540 method.append(userMgrInterface); 1541 1542 auto reply = bus.call(method); 1543 reply.read(properties); 1544 } 1545 catch (const sdbusplus::exception_t& e) 1546 { 1547 log<level::DEBUG>("Failed to excute method", 1548 entry("METHOD=%s", getAllPropertiesMethod), 1549 entry("PATH=%s", userMgrObjBasePath)); 1550 return; 1551 } 1552 for (const auto& t : properties) 1553 { 1554 auto key = t.first; 1555 if (key == allPrivProperty) 1556 { 1557 availablePrivileges = std::get<std::vector<std::string>>(t.second); 1558 } 1559 else if (key == allGrpProperty) 1560 { 1561 availableGroups = std::get<std::vector<std::string>>(t.second); 1562 } 1563 } 1564 // TODO: Implement Supported Privilege & Groups verification logic 1565 return; 1566 } 1567 1568 std::timespec UserAccess::getUpdatedFileTime() 1569 { 1570 struct stat fileStat; 1571 if (stat(ipmiUserDataFile, &fileStat) != 0) 1572 { 1573 log<level::DEBUG>("Error in getting last updated time stamp"); 1574 return std::timespec{0, 0}; 1575 } 1576 return fileStat.st_mtim; 1577 } 1578 1579 void UserAccess::getUserProperties(const DbusUserObjProperties& properties, 1580 std::vector<std::string>& usrGrps, 1581 std::string& usrPriv, bool& usrEnabled) 1582 { 1583 for (const auto& t : properties) 1584 { 1585 std::string key = t.first; 1586 if (key == userPrivProperty) 1587 { 1588 usrPriv = std::get<std::string>(t.second); 1589 } 1590 else if (key == userGrpProperty) 1591 { 1592 usrGrps = std::get<std::vector<std::string>>(t.second); 1593 } 1594 else if (key == userEnabledProperty) 1595 { 1596 usrEnabled = std::get<bool>(t.second); 1597 } 1598 } 1599 return; 1600 } 1601 1602 int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs, 1603 std::vector<std::string>& usrGrps, 1604 std::string& usrPriv, bool& usrEnabled) 1605 { 1606 auto usrObj = userObjs.find(usersInterface); 1607 if (usrObj != userObjs.end()) 1608 { 1609 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled); 1610 return 0; 1611 } 1612 return -EIO; 1613 } 1614 1615 void UserAccess::cacheUserDataFile() 1616 { 1617 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1618 userLock{*userMutex}; 1619 try 1620 { 1621 readUserData(); 1622 } 1623 catch (const std::ios_base::failure& e) 1624 { // File is empty, create it for the first time 1625 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1626 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1627 // user index 0 is reserved, starts with 1 1628 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex) 1629 { 1630 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1631 { 1632 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege = 1633 privNoAccess; 1634 usersTbl.user[userIndex] 1635 .payloadAccess[chIndex] 1636 .stdPayloadEnables1[static_cast<uint8_t>( 1637 ipmi::PayloadType::SOL)] = true; 1638 } 1639 } 1640 writeUserData(); 1641 } 1642 // Create lock file if it does not exist 1643 int fd = open(ipmiUserSignalLockFile, O_CREAT | O_TRUNC | O_SYNC, 1644 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 1645 if (fd < 0) 1646 { 1647 log<level::ERR>("Error in creating IPMI user signal lock file"); 1648 throw std::ios_base::failure( 1649 "Error in creating temporary IPMI user signal lock file"); 1650 } 1651 close(fd); 1652 1653 sigHndlrLock = boost::interprocess::file_lock(ipmiUserSignalLockFile); 1654 // Register it for single object and single process either netipmid / 1655 // host-ipmid 1656 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock()) 1657 { 1658 log<level::DEBUG>("Registering signal handler"); 1659 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>( 1660 bus, 1661 sdbusplus::bus::match::rules::type::signal() + 1662 sdbusplus::bus::match::rules::interface(dBusObjManager) + 1663 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 1664 [&](sdbusplus::message_t& msg) { 1665 userUpdatedSignalHandler(*this, msg); 1666 }); 1667 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>( 1668 bus, 1669 sdbusplus::bus::match::rules::type::signal() + 1670 sdbusplus::bus::match::rules::interface(userMgrInterface) + 1671 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 1672 [&](sdbusplus::message_t& msg) { 1673 userUpdatedSignalHandler(*this, msg); 1674 }); 1675 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>( 1676 bus, 1677 sdbusplus::bus::match::rules::type::signal() + 1678 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) + 1679 sdbusplus::bus::match::rules::interface( 1680 dBusPropertiesInterface) + 1681 sdbusplus::bus::match::rules::member(propertiesChangedSignal) + 1682 sdbusplus::bus::match::rules::argN(0, usersInterface), 1683 [&](sdbusplus::message_t& msg) { 1684 userUpdatedSignalHandler(*this, msg); 1685 }); 1686 signalHndlrObject = true; 1687 } 1688 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs; 1689 try 1690 { 1691 auto method = bus.new_method_call(getUserServiceName().c_str(), 1692 userMgrObjBasePath, dBusObjManager, 1693 getManagedObjectsMethod); 1694 auto reply = bus.call(method); 1695 reply.read(managedObjs); 1696 } 1697 catch (const sdbusplus::exception_t& e) 1698 { 1699 log<level::DEBUG>("Failed to excute method", 1700 entry("METHOD=%s", getSubTreeMethod), 1701 entry("PATH=%s", userMgrObjBasePath)); 1702 return; 1703 } 1704 bool updateRequired = false; 1705 UsersTbl* userData = &usersTbl; 1706 // user index 0 is reserved, starts with 1 1707 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx) 1708 { 1709 if ((userData->user[usrIdx].userInSystem) && 1710 (userData->user[usrIdx].userName[0] != '\0')) 1711 { 1712 std::vector<std::string> usrGrps; 1713 std::string usrPriv; 1714 1715 std::string userName( 1716 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1717 ipmiMaxUserName); 1718 sdbusplus::message::object_path tempUserPath(userObjBasePath); 1719 tempUserPath /= userName; 1720 std::string usersPath(tempUserPath); 1721 1722 auto usrObj = managedObjs.find(usersPath); 1723 if (usrObj != managedObjs.end()) 1724 { 1725 bool usrEnabled = false; 1726 1727 // User exist. Lets check and update other fileds 1728 getUserObjProperties(usrObj->second, usrGrps, usrPriv, 1729 usrEnabled); 1730 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) == 1731 usrGrps.end()) 1732 { 1733 updateRequired = true; 1734 // Group "ipmi" is removed so lets remove user in IPMI 1735 deleteUserIndex(usrIdx); 1736 } 1737 else 1738 { 1739 // Group "ipmi" is present so lets update other properties 1740 // in IPMI 1741 uint8_t priv = 1742 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask; 1743 // Update all channels priv, only if it is not equivalent to 1744 // getUsrMgmtSyncIndex() 1745 if (userData->user[usrIdx] 1746 .userPrivAccess[getUsrMgmtSyncIndex()] 1747 .privilege != priv) 1748 { 1749 updateRequired = true; 1750 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 1751 ++chIndex) 1752 { 1753 userData->user[usrIdx] 1754 .userPrivAccess[chIndex] 1755 .privilege = priv; 1756 } 1757 } 1758 if (userData->user[usrIdx].userEnabled != usrEnabled) 1759 { 1760 updateRequired = true; 1761 userData->user[usrIdx].userEnabled = usrEnabled; 1762 } 1763 } 1764 1765 // We are done with this obj. lets delete from MAP 1766 managedObjs.erase(usrObj); 1767 } 1768 else 1769 { 1770 updateRequired = true; 1771 deleteUserIndex(usrIdx); 1772 } 1773 } 1774 } 1775 1776 // Walk through remnaining managedObj users list 1777 // Add them to ipmi data base 1778 for (const auto& usrObj : managedObjs) 1779 { 1780 std::vector<std::string> usrGrps; 1781 std::string usrPriv, userName; 1782 bool usrEnabled = false; 1783 std::string usrObjPath = std::string(usrObj.first); 1784 if (getUserNameFromPath(usrObj.first.str, userName) != 0) 1785 { 1786 log<level::ERR>("Error in user object path"); 1787 continue; 1788 } 1789 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled); 1790 // Add 'ipmi' group users 1791 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) != 1792 usrGrps.end()) 1793 { 1794 updateRequired = true; 1795 // CREATE NEW USER 1796 if (true != addUserEntry(userName, usrPriv, usrEnabled)) 1797 { 1798 break; 1799 } 1800 } 1801 } 1802 1803 if (updateRequired) 1804 { 1805 // All userData slots update done. Lets write the data 1806 writeUserData(); 1807 } 1808 1809 return; 1810 } 1811 } // namespace ipmi 1812