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