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