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