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