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