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