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::SdBusError& 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::SdBusError& 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::SdBusError& 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::SdBusError& 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_AUTH_ERR; 628 } 629 size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1; 630 char* pass = reinterpret_cast<char*>(malloc(passSize)); 631 std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize); 632 633 *resp = reinterpret_cast<pam_response*>( 634 calloc(numMsg, sizeof(struct pam_response))); 635 636 for (int i = 0; i < numMsg; ++i) 637 { 638 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) 639 { 640 continue; 641 } 642 resp[i]->resp = pass; 643 } 644 return PAM_SUCCESS; 645 } 646 647 /** @brief Updating the PAM password 648 * 649 * @param[in] username - username in string 650 * 651 * @param[in] password - new password in string 652 * 653 * @return status 654 */ 655 656 int pamUpdatePasswd(const char* username, const char* password) 657 { 658 const struct pam_conv localConversation = {pamFunctionConversation, 659 const_cast<char*>(password)}; 660 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start 661 662 int retval = 663 pam_start("passwd", username, &localConversation, &localAuthHandle); 664 665 if (retval != PAM_SUCCESS) 666 { 667 return retval; 668 } 669 670 retval = pam_chauthtok(localAuthHandle, PAM_SILENT); 671 if (retval != PAM_SUCCESS) 672 { 673 pam_end(localAuthHandle, retval); 674 return retval; 675 } 676 677 return pam_end(localAuthHandle, PAM_SUCCESS); 678 } 679 680 bool pamUserCheckAuthenticate(std::string_view username, 681 std::string_view password) 682 { 683 const struct pam_conv localConversation = { 684 pamFunctionConversation, const_cast<char*>(password.data())}; 685 686 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start 687 688 if (pam_start("dropbear", username.data(), &localConversation, 689 &localAuthHandle) != PAM_SUCCESS) 690 { 691 log<level::ERR>("User Authentication Failure"); 692 return false; 693 } 694 695 int retval = pam_authenticate(localAuthHandle, 696 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); 697 698 if (retval != PAM_SUCCESS) 699 { 700 log<level::DEBUG>("pam_authenticate returned failure", 701 entry("ERROR=%d", retval)); 702 703 pam_end(localAuthHandle, retval); 704 return false; 705 } 706 707 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) != 708 PAM_SUCCESS) 709 { 710 pam_end(localAuthHandle, PAM_SUCCESS); 711 return false; 712 } 713 714 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) 715 { 716 return false; 717 } 718 return true; 719 } 720 721 Cc UserAccess::setSpecialUserPassword(const std::string& userName, 722 const std::string& userPassword) 723 { 724 if (pamUpdatePasswd(userName.c_str(), userPassword.c_str()) != PAM_SUCCESS) 725 { 726 log<level::DEBUG>("Failed to update password"); 727 return ccUnspecifiedError; 728 } 729 return ccSuccess; 730 } 731 732 Cc UserAccess::setUserPassword(const uint8_t userId, const char* userPassword) 733 { 734 std::string userName; 735 if (ipmiUserGetUserName(userId, userName) != ccSuccess) 736 { 737 log<level::DEBUG>("User Name not found", 738 entry("USER-ID=%d", (uint8_t)userId)); 739 return ccParmOutOfRange; 740 } 741 742 ipmi::SecureString passwd; 743 passwd.assign(reinterpret_cast<const char*>(userPassword), 0, 744 maxIpmi20PasswordSize); 745 int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str()); 746 747 switch (retval) 748 { 749 case PAM_SUCCESS: 750 { 751 return ccSuccess; 752 } 753 case PAM_AUTHTOK_ERR: 754 { 755 log<level::DEBUG>("Bad authentication token"); 756 return ccInvalidFieldRequest; 757 } 758 default: 759 { 760 log<level::DEBUG>("Failed to update password", 761 entry("USER-ID=%d", (uint8_t)userId)); 762 return ccUnspecifiedError; 763 } 764 } 765 } 766 767 Cc UserAccess::setUserEnabledState(const uint8_t userId, 768 const bool& enabledState) 769 { 770 if (!isValidUserId(userId)) 771 { 772 return ccParmOutOfRange; 773 } 774 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 775 userLock{*userMutex}; 776 UserInfo* userInfo = getUserInfo(userId); 777 std::string userName; 778 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 779 ipmiMaxUserName); 780 if (userName.empty()) 781 { 782 log<level::DEBUG>("User name not set / invalid"); 783 return ccUnspecifiedError; 784 } 785 if (userInfo->userEnabled != enabledState) 786 { 787 std::string userPath = std::string(userObjBasePath) + "/" + userName; 788 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface, 789 userEnabledProperty, enabledState); 790 userInfo->userEnabled = enabledState; 791 try 792 { 793 writeUserData(); 794 } 795 catch (const std::exception& e) 796 { 797 log<level::DEBUG>("Write user data failed"); 798 return ccUnspecifiedError; 799 } 800 } 801 return ccSuccess; 802 } 803 804 Cc UserAccess::setUserPayloadAccess(const uint8_t chNum, 805 const uint8_t operation, 806 const uint8_t userId, 807 const PayloadAccess& payloadAccess) 808 { 809 constexpr uint8_t enable = 0x0; 810 constexpr uint8_t disable = 0x1; 811 812 if (!isValidChannel(chNum)) 813 { 814 return ccInvalidFieldRequest; 815 } 816 if (!isValidUserId(userId)) 817 { 818 return ccParmOutOfRange; 819 } 820 if (operation != enable && operation != disable) 821 { 822 return ccInvalidFieldRequest; 823 } 824 // Check operation & payloadAccess if required. 825 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 826 userLock{*userMutex}; 827 UserInfo* userInfo = getUserInfo(userId); 828 829 if (operation == enable) 830 { 831 userInfo->payloadAccess[chNum].stdPayloadEnables1 |= 832 payloadAccess.stdPayloadEnables1; 833 834 userInfo->payloadAccess[chNum].oemPayloadEnables1 |= 835 payloadAccess.oemPayloadEnables1; 836 } 837 else 838 { 839 userInfo->payloadAccess[chNum].stdPayloadEnables1 &= 840 ~(payloadAccess.stdPayloadEnables1); 841 842 userInfo->payloadAccess[chNum].oemPayloadEnables1 &= 843 ~(payloadAccess.oemPayloadEnables1); 844 } 845 846 try 847 { 848 writeUserData(); 849 } 850 catch (const std::exception& e) 851 { 852 log<level::ERR>("Write user data failed"); 853 return ccUnspecifiedError; 854 } 855 return ccSuccess; 856 } 857 858 Cc UserAccess::setUserPrivilegeAccess(const uint8_t userId, const uint8_t chNum, 859 const UserPrivAccess& privAccess, 860 const bool& otherPrivUpdates) 861 { 862 if (!isValidChannel(chNum)) 863 { 864 return ccInvalidFieldRequest; 865 } 866 if (!isValidUserId(userId)) 867 { 868 return ccParmOutOfRange; 869 } 870 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 871 userLock{*userMutex}; 872 UserInfo* userInfo = getUserInfo(userId); 873 std::string userName; 874 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 875 ipmiMaxUserName); 876 if (userName.empty()) 877 { 878 log<level::DEBUG>("User name not set / invalid"); 879 return ccUnspecifiedError; 880 } 881 std::string priv = convertToSystemPrivilege( 882 static_cast<CommandPrivilege>(privAccess.privilege)); 883 uint8_t syncIndex = getUsrMgmtSyncIndex(); 884 if (chNum == syncIndex && 885 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege) 886 { 887 std::string userPath = std::string(userObjBasePath) + "/" + userName; 888 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface, 889 userPrivProperty, priv); 890 } 891 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege; 892 893 if (otherPrivUpdates) 894 { 895 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled; 896 userInfo->userPrivAccess[chNum].linkAuthEnabled = 897 privAccess.linkAuthEnabled; 898 userInfo->userPrivAccess[chNum].accessCallback = 899 privAccess.accessCallback; 900 } 901 try 902 { 903 writeUserData(); 904 } 905 catch (const std::exception& e) 906 { 907 log<level::DEBUG>("Write user data failed"); 908 return ccUnspecifiedError; 909 } 910 return ccSuccess; 911 } 912 913 uint8_t UserAccess::getUserId(const std::string& userName) 914 { 915 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 916 userLock{*userMutex}; 917 checkAndReloadUserData(); 918 // user index 0 is reserved, starts with 1 919 size_t usrIndex = 1; 920 for (; usrIndex <= ipmiMaxUsers; ++usrIndex) 921 { 922 std::string curName( 923 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 924 ipmiMaxUserName); 925 if (userName == curName) 926 { 927 break; // found the entry 928 } 929 } 930 if (usrIndex > ipmiMaxUsers) 931 { 932 log<level::DEBUG>("User not found", 933 entry("USER_NAME=%s", userName.c_str())); 934 return invalidUserId; 935 } 936 937 return usrIndex; 938 } 939 940 Cc UserAccess::getUserName(const uint8_t userId, std::string& userName) 941 { 942 if (!isValidUserId(userId)) 943 { 944 return ccParmOutOfRange; 945 } 946 UserInfo* userInfo = getUserInfo(userId); 947 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 948 ipmiMaxUserName); 949 return ccSuccess; 950 } 951 952 bool UserAccess::isIpmiInAvailableGroupList() 953 { 954 if (std::find(availableGroups.begin(), availableGroups.end(), 955 ipmiGrpName) != availableGroups.end()) 956 { 957 return true; 958 } 959 if (availableGroups.empty()) 960 { 961 // available groups shouldn't be empty, re-query 962 getSystemPrivAndGroups(); 963 if (std::find(availableGroups.begin(), availableGroups.end(), 964 ipmiGrpName) != availableGroups.end()) 965 { 966 return true; 967 } 968 } 969 return false; 970 } 971 972 Cc UserAccess::setUserName(const uint8_t userId, const std::string& userName) 973 { 974 if (!isValidUserId(userId)) 975 { 976 return ccParmOutOfRange; 977 } 978 979 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 980 userLock{*userMutex}; 981 std::string oldUser; 982 getUserName(userId, oldUser); 983 984 if (oldUser == userName) 985 { 986 // requesting to set the same user name, return success. 987 return ccSuccess; 988 } 989 990 bool validUser = isValidUserName(userName); 991 UserInfo* userInfo = getUserInfo(userId); 992 if (userName.empty() && !oldUser.empty()) 993 { 994 // Delete existing user 995 std::string userPath = std::string(userObjBasePath) + "/" + oldUser; 996 try 997 { 998 auto method = bus.new_method_call( 999 getUserServiceName().c_str(), userPath.c_str(), 1000 deleteUserInterface, deleteUserMethod); 1001 auto reply = bus.call(method); 1002 } 1003 catch (const sdbusplus::exception::SdBusError& e) 1004 { 1005 log<level::DEBUG>("Failed to excute method", 1006 entry("METHOD=%s", deleteUserMethod), 1007 entry("PATH=%s", userPath.c_str())); 1008 return ccUnspecifiedError; 1009 } 1010 deleteUserIndex(userId); 1011 } 1012 else if (oldUser.empty() && !userName.empty() && validUser) 1013 { 1014 try 1015 { 1016 if (!isIpmiInAvailableGroupList()) 1017 { 1018 return ccUnspecifiedError; 1019 } 1020 // Create new user 1021 auto method = bus.new_method_call( 1022 getUserServiceName().c_str(), userMgrObjBasePath, 1023 userMgrInterface, createUserMethod); 1024 method.append(userName.c_str(), availableGroups, "", false); 1025 auto reply = bus.call(method); 1026 } 1027 catch (const sdbusplus::exception::SdBusError& e) 1028 { 1029 log<level::DEBUG>("Failed to excute method", 1030 entry("METHOD=%s", createUserMethod), 1031 entry("PATH=%s", userMgrObjBasePath)); 1032 return ccUnspecifiedError; 1033 } 1034 1035 std::memset(userInfo->userName, 0, sizeof(userInfo->userName)); 1036 std::memcpy(userInfo->userName, 1037 static_cast<const void*>(userName.data()), userName.size()); 1038 userInfo->userInSystem = true; 1039 } 1040 else if (oldUser != userName && validUser) 1041 { 1042 try 1043 { 1044 // User rename 1045 auto method = bus.new_method_call( 1046 getUserServiceName().c_str(), userMgrObjBasePath, 1047 userMgrInterface, renameUserMethod); 1048 method.append(oldUser.c_str(), userName.c_str()); 1049 auto reply = bus.call(method); 1050 } 1051 catch (const sdbusplus::exception::SdBusError& e) 1052 { 1053 log<level::DEBUG>("Failed to excute method", 1054 entry("METHOD=%s", renameUserMethod), 1055 entry("PATH=%s", userMgrObjBasePath)); 1056 return ccUnspecifiedError; 1057 } 1058 std::fill(static_cast<uint8_t*>(userInfo->userName), 1059 static_cast<uint8_t*>(userInfo->userName) + 1060 sizeof(userInfo->userName), 1061 0); 1062 1063 std::memset(userInfo->userName, 0, sizeof(userInfo->userName)); 1064 std::memcpy(userInfo->userName, 1065 static_cast<const void*>(userName.data()), userName.size()); 1066 1067 ipmiRenameUserEntryPassword(oldUser, userName); 1068 userInfo->userInSystem = true; 1069 } 1070 else if (!validUser) 1071 { 1072 return ccInvalidFieldRequest; 1073 } 1074 try 1075 { 1076 writeUserData(); 1077 } 1078 catch (const std::exception& e) 1079 { 1080 log<level::DEBUG>("Write user data failed"); 1081 return ccUnspecifiedError; 1082 } 1083 return ccSuccess; 1084 } 1085 1086 static constexpr const char* jsonUserName = "user_name"; 1087 static constexpr const char* jsonPriv = "privilege"; 1088 static constexpr const char* jsonIpmiEnabled = "ipmi_enabled"; 1089 static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled"; 1090 static constexpr const char* jsonAccCallbk = "access_callback"; 1091 static constexpr const char* jsonUserEnabled = "user_enabled"; 1092 static constexpr const char* jsonUserInSys = "user_in_system"; 1093 static constexpr const char* jsonFixedUser = "fixed_user_name"; 1094 static constexpr const char* payloadEnabledStr = "payload_enabled"; 1095 static constexpr const char* stdPayloadStr = "std_payload"; 1096 static constexpr const char* oemPayloadStr = "OEM_payload"; 1097 1098 /** @brief to construct a JSON object from the given payload access details. 1099 * 1100 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input) 1101 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input) 1102 * 1103 * @details Sample output JSON object format : 1104 * "payload_enabled":{ 1105 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1106 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1107 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1108 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1109 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1110 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1111 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1112 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1113 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1114 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1115 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1116 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1117 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1118 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1119 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1120 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>], 1121 * } 1122 */ 1123 static const Json constructJsonPayloadEnables( 1124 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1125 stdPayload, 1126 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1127 oemPayload) 1128 { 1129 Json jsonPayloadEnabled; 1130 1131 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++) 1132 { 1133 std::ostringstream stdPayloadStream; 1134 std::ostringstream oemPayloadStream; 1135 1136 stdPayloadStream << stdPayloadStr << payloadNum; 1137 oemPayloadStream << oemPayloadStr << payloadNum; 1138 1139 jsonPayloadEnabled.push_back(Json::object_t::value_type( 1140 stdPayloadStream.str(), stdPayload[payloadNum])); 1141 1142 jsonPayloadEnabled.push_back(Json::object_t::value_type( 1143 oemPayloadStream.str(), oemPayload[payloadNum])); 1144 } 1145 return jsonPayloadEnabled; 1146 } 1147 1148 void UserAccess::readPayloadAccessFromUserInfo( 1149 const UserInfo& userInfo, 1150 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload, 1151 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload) 1152 { 1153 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++) 1154 { 1155 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1156 { 1157 stdPayload[payloadNum][chIndex] = 1158 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum]; 1159 1160 oemPayload[payloadNum][chIndex] = 1161 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum]; 1162 } 1163 } 1164 } 1165 1166 void UserAccess::updatePayloadAccessInUserInfo( 1167 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1168 stdPayload, 1169 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& 1170 oemPayload, 1171 UserInfo& userInfo) 1172 { 1173 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1174 { 1175 // Ensure that reserved/unsupported payloads are marked to zero. 1176 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset(); 1177 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset(); 1178 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset(); 1179 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset(); 1180 // Update SOL status as it is the only supported payload currently. 1181 userInfo.payloadAccess[chIndex] 1182 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] = 1183 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex]; 1184 } 1185 } 1186 1187 void UserAccess::readUserData() 1188 { 1189 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1190 userLock{*userMutex}; 1191 1192 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary); 1193 if (!iUsrData.good()) 1194 { 1195 log<level::ERR>("Error in reading IPMI user data file"); 1196 throw std::ios_base::failure("Error opening IPMI user data file"); 1197 } 1198 1199 Json jsonUsersTbl = Json::array(); 1200 jsonUsersTbl = Json::parse(iUsrData, nullptr, false); 1201 1202 if (jsonUsersTbl.size() != ipmiMaxUsers) 1203 { 1204 log<level::ERR>( 1205 "Error in reading IPMI user data file - User count issues"); 1206 throw std::runtime_error( 1207 "Corrupted IPMI user data file - invalid user count"); 1208 } 1209 1210 // user index 0 is reserved, starts with 1 1211 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1212 { 1213 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0. 1214 if (userInfo.is_null()) 1215 { 1216 log<level::ERR>("Error in reading IPMI user data file - " 1217 "user info corrupted"); 1218 throw std::runtime_error( 1219 "Corrupted IPMI user data file - invalid user info"); 1220 } 1221 std::string userName = userInfo[jsonUserName].get<std::string>(); 1222 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 1223 userName.c_str(), ipmiMaxUserName); 1224 1225 std::vector<std::string> privilege = 1226 userInfo[jsonPriv].get<std::vector<std::string>>(); 1227 std::vector<bool> ipmiEnabled = 1228 userInfo[jsonIpmiEnabled].get<std::vector<bool>>(); 1229 std::vector<bool> linkAuthEnabled = 1230 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>(); 1231 std::vector<bool> accessCallback = 1232 userInfo[jsonAccCallbk].get<std::vector<bool>>(); 1233 1234 // Payload Enables Processing. 1235 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1236 stdPayload = {}; 1237 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1238 oemPayload = {}; 1239 try 1240 { 1241 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr); 1242 for (auto payloadNum = 0; payloadNum < payloadsPerByte; 1243 payloadNum++) 1244 { 1245 std::ostringstream stdPayloadStream; 1246 std::ostringstream oemPayloadStream; 1247 1248 stdPayloadStream << stdPayloadStr << payloadNum; 1249 oemPayloadStream << oemPayloadStr << payloadNum; 1250 1251 stdPayload[payloadNum] = 1252 jsonPayloadEnabled[stdPayloadStream.str()] 1253 .get<std::array<bool, ipmiMaxChannels>>(); 1254 oemPayload[payloadNum] = 1255 jsonPayloadEnabled[oemPayloadStream.str()] 1256 .get<std::array<bool, ipmiMaxChannels>>(); 1257 1258 if (stdPayload[payloadNum].size() != ipmiMaxChannels || 1259 oemPayload[payloadNum].size() != ipmiMaxChannels) 1260 { 1261 log<level::ERR>("Error in reading IPMI user data file - " 1262 "payload properties corrupted"); 1263 throw std::runtime_error( 1264 "Corrupted IPMI user data file - payload properties"); 1265 } 1266 } 1267 } 1268 catch (Json::out_of_range& e) 1269 { 1270 // Key not found in 'userInfo'; possibly an old JSON file. Use 1271 // default values for all payloads, and SOL payload default is true. 1272 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true); 1273 } 1274 1275 if (privilege.size() != ipmiMaxChannels || 1276 ipmiEnabled.size() != ipmiMaxChannels || 1277 linkAuthEnabled.size() != ipmiMaxChannels || 1278 accessCallback.size() != ipmiMaxChannels) 1279 { 1280 log<level::ERR>("Error in reading IPMI user data file - " 1281 "properties corrupted"); 1282 throw std::runtime_error( 1283 "Corrupted IPMI user data file - properties"); 1284 } 1285 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1286 { 1287 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege = 1288 static_cast<uint8_t>( 1289 convertToIPMIPrivilege(privilege[chIndex])); 1290 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled = 1291 ipmiEnabled[chIndex]; 1292 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled = 1293 linkAuthEnabled[chIndex]; 1294 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback = 1295 accessCallback[chIndex]; 1296 } 1297 updatePayloadAccessInUserInfo(stdPayload, oemPayload, 1298 usersTbl.user[usrIndex]); 1299 usersTbl.user[usrIndex].userEnabled = 1300 userInfo[jsonUserEnabled].get<bool>(); 1301 usersTbl.user[usrIndex].userInSystem = 1302 userInfo[jsonUserInSys].get<bool>(); 1303 usersTbl.user[usrIndex].fixedUserName = 1304 userInfo[jsonFixedUser].get<bool>(); 1305 } 1306 1307 log<level::DEBUG>("User data read from IPMI data file"); 1308 iUsrData.close(); 1309 // Update the timestamp 1310 fileLastUpdatedTime = getUpdatedFileTime(); 1311 return; 1312 } 1313 1314 void UserAccess::writeUserData() 1315 { 1316 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1317 userLock{*userMutex}; 1318 1319 Json jsonUsersTbl = Json::array(); 1320 // user index 0 is reserved, starts with 1 1321 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1322 { 1323 Json jsonUserInfo; 1324 jsonUserInfo[jsonUserName] = std::string( 1325 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 1326 ipmiMaxUserName); 1327 std::vector<std::string> privilege(ipmiMaxChannels); 1328 std::vector<bool> ipmiEnabled(ipmiMaxChannels); 1329 std::vector<bool> linkAuthEnabled(ipmiMaxChannels); 1330 std::vector<bool> accessCallback(ipmiMaxChannels); 1331 1332 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1333 stdPayload; 1334 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> 1335 oemPayload; 1336 1337 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1338 { 1339 privilege[chIndex] = 1340 convertToSystemPrivilege(static_cast<CommandPrivilege>( 1341 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege)); 1342 ipmiEnabled[chIndex] = 1343 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled; 1344 linkAuthEnabled[chIndex] = 1345 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled; 1346 accessCallback[chIndex] = 1347 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback; 1348 } 1349 jsonUserInfo[jsonPriv] = privilege; 1350 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled; 1351 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled; 1352 jsonUserInfo[jsonAccCallbk] = accessCallback; 1353 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled; 1354 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem; 1355 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName; 1356 1357 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload, 1358 oemPayload); 1359 Json jsonPayloadEnabledInfo = 1360 constructJsonPayloadEnables(stdPayload, oemPayload); 1361 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo; 1362 1363 jsonUsersTbl.push_back(jsonUserInfo); 1364 } 1365 1366 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"}; 1367 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC, 1368 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 1369 if (fd < 0) 1370 { 1371 log<level::ERR>("Error in creating temporary IPMI user data file"); 1372 throw std::ios_base::failure( 1373 "Error in creating temporary IPMI user data file"); 1374 } 1375 const auto& writeStr = jsonUsersTbl.dump(); 1376 if (write(fd, writeStr.c_str(), writeStr.size()) != 1377 static_cast<ssize_t>(writeStr.size())) 1378 { 1379 close(fd); 1380 log<level::ERR>("Error in writing temporary IPMI user data file"); 1381 throw std::ios_base::failure( 1382 "Error in writing temporary IPMI user data file"); 1383 } 1384 close(fd); 1385 1386 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0) 1387 { 1388 log<level::ERR>("Error in renaming temporary IPMI user data file"); 1389 throw std::runtime_error("Error in renaming IPMI user data file"); 1390 } 1391 // Update the timestamp 1392 fileLastUpdatedTime = getUpdatedFileTime(); 1393 return; 1394 } 1395 1396 bool UserAccess::addUserEntry(const std::string& userName, 1397 const std::string& sysPriv, const bool& enabled) 1398 { 1399 UsersTbl* userData = getUsersTblPtr(); 1400 size_t freeIndex = 0xFF; 1401 // user index 0 is reserved, starts with 1 1402 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1403 { 1404 std::string curName( 1405 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 1406 ipmiMaxUserName); 1407 if (userName == curName) 1408 { 1409 log<level::DEBUG>("User name exists", 1410 entry("USER_NAME=%s", userName.c_str())); 1411 return false; // user name exists. 1412 } 1413 1414 if ((!userData->user[usrIndex].userInSystem) && 1415 (userData->user[usrIndex].userName[0] == '\0') && 1416 (freeIndex == 0xFF)) 1417 { 1418 freeIndex = usrIndex; 1419 } 1420 } 1421 if (freeIndex == 0xFF) 1422 { 1423 log<level::ERR>("No empty slots found"); 1424 return false; 1425 } 1426 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName), 1427 userName.c_str(), ipmiMaxUserName); 1428 uint8_t priv = 1429 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) & 1430 privMask; 1431 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1432 { 1433 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv; 1434 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true; 1435 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled = 1436 true; 1437 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true; 1438 } 1439 userData->user[freeIndex].userInSystem = true; 1440 userData->user[freeIndex].userEnabled = enabled; 1441 1442 return true; 1443 } 1444 1445 void UserAccess::deleteUserIndex(const size_t& usrIdx) 1446 { 1447 UsersTbl* userData = getUsersTblPtr(); 1448 1449 std::string userName( 1450 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1451 ipmiMaxUserName); 1452 ipmiClearUserEntryPassword(userName); 1453 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName), 1454 static_cast<uint8_t*>(userData->user[usrIdx].userName) + 1455 sizeof(userData->user[usrIdx].userName), 1456 0); 1457 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1458 { 1459 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess; 1460 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false; 1461 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false; 1462 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false; 1463 } 1464 userData->user[usrIdx].userInSystem = false; 1465 userData->user[usrIdx].userEnabled = false; 1466 return; 1467 } 1468 1469 void UserAccess::checkAndReloadUserData() 1470 { 1471 std::time_t updateTime = getUpdatedFileTime(); 1472 if (updateTime != fileLastUpdatedTime || updateTime == -EIO) 1473 { 1474 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1475 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1476 readUserData(); 1477 } 1478 return; 1479 } 1480 1481 UsersTbl* UserAccess::getUsersTblPtr() 1482 { 1483 // reload data before using it. 1484 checkAndReloadUserData(); 1485 return &usersTbl; 1486 } 1487 1488 void UserAccess::getSystemPrivAndGroups() 1489 { 1490 std::map<std::string, PrivAndGroupType> properties; 1491 try 1492 { 1493 auto method = bus.new_method_call( 1494 getUserServiceName().c_str(), userMgrObjBasePath, 1495 dBusPropertiesInterface, getAllPropertiesMethod); 1496 method.append(userMgrInterface); 1497 1498 auto reply = bus.call(method); 1499 reply.read(properties); 1500 } 1501 catch (const sdbusplus::exception::SdBusError& e) 1502 { 1503 log<level::DEBUG>("Failed to excute method", 1504 entry("METHOD=%s", getAllPropertiesMethod), 1505 entry("PATH=%s", userMgrObjBasePath)); 1506 return; 1507 } 1508 for (const auto& t : properties) 1509 { 1510 auto key = t.first; 1511 if (key == allPrivProperty) 1512 { 1513 availablePrivileges = std::get<std::vector<std::string>>(t.second); 1514 } 1515 else if (key == allGrpProperty) 1516 { 1517 availableGroups = std::get<std::vector<std::string>>(t.second); 1518 } 1519 } 1520 // TODO: Implement Supported Privilege & Groups verification logic 1521 return; 1522 } 1523 1524 std::time_t UserAccess::getUpdatedFileTime() 1525 { 1526 struct stat fileStat; 1527 if (stat(ipmiUserDataFile, &fileStat) != 0) 1528 { 1529 log<level::DEBUG>("Error in getting last updated time stamp"); 1530 return -EIO; 1531 } 1532 return fileStat.st_mtime; 1533 } 1534 1535 void UserAccess::getUserProperties(const DbusUserObjProperties& properties, 1536 std::vector<std::string>& usrGrps, 1537 std::string& usrPriv, bool& usrEnabled) 1538 { 1539 for (const auto& t : properties) 1540 { 1541 std::string key = t.first; 1542 if (key == userPrivProperty) 1543 { 1544 usrPriv = std::get<std::string>(t.second); 1545 } 1546 else if (key == userGrpProperty) 1547 { 1548 usrGrps = std::get<std::vector<std::string>>(t.second); 1549 } 1550 else if (key == userEnabledProperty) 1551 { 1552 usrEnabled = std::get<bool>(t.second); 1553 } 1554 } 1555 return; 1556 } 1557 1558 int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs, 1559 std::vector<std::string>& usrGrps, 1560 std::string& usrPriv, bool& usrEnabled) 1561 { 1562 auto usrObj = userObjs.find(usersInterface); 1563 if (usrObj != userObjs.end()) 1564 { 1565 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled); 1566 return 0; 1567 } 1568 return -EIO; 1569 } 1570 1571 void UserAccess::cacheUserDataFile() 1572 { 1573 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1574 userLock{*userMutex}; 1575 try 1576 { 1577 readUserData(); 1578 } 1579 catch (const std::ios_base::failure& e) 1580 { // File is empty, create it for the first time 1581 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1582 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1583 // user index 0 is reserved, starts with 1 1584 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex) 1585 { 1586 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1587 { 1588 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege = 1589 privNoAccess; 1590 usersTbl.user[userIndex] 1591 .payloadAccess[chIndex] 1592 .stdPayloadEnables1[static_cast<uint8_t>( 1593 ipmi::PayloadType::SOL)] = true; 1594 } 1595 } 1596 writeUserData(); 1597 } 1598 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile); 1599 // Register it for single object and single process either netipimd / 1600 // host-ipmid 1601 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock()) 1602 { 1603 log<level::DEBUG>("Registering signal handler"); 1604 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>( 1605 bus, 1606 sdbusplus::bus::match::rules::type::signal() + 1607 sdbusplus::bus::match::rules::interface(dBusObjManager) + 1608 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 1609 [&](sdbusplus::message::message& msg) { 1610 userUpdatedSignalHandler(*this, msg); 1611 }); 1612 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>( 1613 bus, 1614 sdbusplus::bus::match::rules::type::signal() + 1615 sdbusplus::bus::match::rules::interface(userMgrInterface) + 1616 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 1617 [&](sdbusplus::message::message& msg) { 1618 userUpdatedSignalHandler(*this, msg); 1619 }); 1620 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>( 1621 bus, 1622 sdbusplus::bus::match::rules::type::signal() + 1623 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) + 1624 sdbusplus::bus::match::rules::interface( 1625 dBusPropertiesInterface) + 1626 sdbusplus::bus::match::rules::member(propertiesChangedSignal) + 1627 sdbusplus::bus::match::rules::argN(0, usersInterface), 1628 [&](sdbusplus::message::message& msg) { 1629 userUpdatedSignalHandler(*this, msg); 1630 }); 1631 signalHndlrObject = true; 1632 } 1633 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs; 1634 try 1635 { 1636 auto method = bus.new_method_call(getUserServiceName().c_str(), 1637 userMgrObjBasePath, dBusObjManager, 1638 getManagedObjectsMethod); 1639 auto reply = bus.call(method); 1640 reply.read(managedObjs); 1641 } 1642 catch (const sdbusplus::exception::SdBusError& e) 1643 { 1644 log<level::DEBUG>("Failed to excute method", 1645 entry("METHOD=%s", getSubTreeMethod), 1646 entry("PATH=%s", userMgrObjBasePath)); 1647 return; 1648 } 1649 bool updateRequired = false; 1650 UsersTbl* userData = &usersTbl; 1651 // user index 0 is reserved, starts with 1 1652 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx) 1653 { 1654 if ((userData->user[usrIdx].userInSystem) && 1655 (userData->user[usrIdx].userName[0] != '\0')) 1656 { 1657 std::vector<std::string> usrGrps; 1658 std::string usrPriv; 1659 1660 std::string userName( 1661 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1662 ipmiMaxUserName); 1663 std::string usersPath = 1664 std::string(userObjBasePath) + "/" + userName; 1665 1666 auto usrObj = managedObjs.find(usersPath); 1667 if (usrObj != managedObjs.end()) 1668 { 1669 bool usrEnabled = false; 1670 1671 // User exist. Lets check and update other fileds 1672 getUserObjProperties(usrObj->second, usrGrps, usrPriv, 1673 usrEnabled); 1674 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) == 1675 usrGrps.end()) 1676 { 1677 updateRequired = true; 1678 // Group "ipmi" is removed so lets remove user in IPMI 1679 deleteUserIndex(usrIdx); 1680 } 1681 else 1682 { 1683 // Group "ipmi" is present so lets update other properties 1684 // in IPMI 1685 uint8_t priv = 1686 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask; 1687 // Update all channels priv, only if it is not equivalent to 1688 // getUsrMgmtSyncIndex() 1689 if (userData->user[usrIdx] 1690 .userPrivAccess[getUsrMgmtSyncIndex()] 1691 .privilege != priv) 1692 { 1693 updateRequired = true; 1694 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 1695 ++chIndex) 1696 { 1697 userData->user[usrIdx] 1698 .userPrivAccess[chIndex] 1699 .privilege = priv; 1700 } 1701 } 1702 if (userData->user[usrIdx].userEnabled != usrEnabled) 1703 { 1704 updateRequired = true; 1705 userData->user[usrIdx].userEnabled = usrEnabled; 1706 } 1707 } 1708 1709 // We are done with this obj. lets delete from MAP 1710 managedObjs.erase(usrObj); 1711 } 1712 else 1713 { 1714 updateRequired = true; 1715 deleteUserIndex(usrIdx); 1716 } 1717 } 1718 } 1719 1720 // Walk through remnaining managedObj users list 1721 // Add them to ipmi data base 1722 for (const auto& usrObj : managedObjs) 1723 { 1724 std::vector<std::string> usrGrps; 1725 std::string usrPriv, userName; 1726 bool usrEnabled = false; 1727 std::string usrObjPath = std::string(usrObj.first); 1728 if (getUserNameFromPath(usrObj.first.str, userName) != 0) 1729 { 1730 log<level::ERR>("Error in user object path"); 1731 continue; 1732 } 1733 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled); 1734 // Add 'ipmi' group users 1735 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) != 1736 usrGrps.end()) 1737 { 1738 updateRequired = true; 1739 // CREATE NEW USER 1740 if (true != addUserEntry(userName, usrPriv, usrEnabled)) 1741 { 1742 break; 1743 } 1744 } 1745 } 1746 1747 if (updateRequired) 1748 { 1749 // All userData slots update done. Lets write the data 1750 writeUserData(); 1751 } 1752 1753 return; 1754 } 1755 } // namespace ipmi 1756