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