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 <xyz/openbmc_project/Common/error.hpp> 35 #include <xyz/openbmc_project/User/Common/error.hpp> 36 37 namespace ipmi 38 { 39 40 // TODO: Move D-Bus & Object Manager related stuff, to common files 41 // D-Bus property related 42 static constexpr const char* dBusPropertiesInterface = 43 "org.freedesktop.DBus.Properties"; 44 static constexpr const char* getAllPropertiesMethod = "GetAll"; 45 static constexpr const char* propertiesChangedSignal = "PropertiesChanged"; 46 static constexpr const char* setPropertiesMethod = "Set"; 47 48 // Object Manager related 49 static constexpr const char* dBusObjManager = 50 "org.freedesktop.DBus.ObjectManager"; 51 static constexpr const char* getManagedObjectsMethod = "GetManagedObjects"; 52 // Object Manager signals 53 static constexpr const char* intfAddedSignal = "InterfacesAdded"; 54 static constexpr const char* intfRemovedSignal = "InterfacesRemoved"; 55 56 // Object Mapper related 57 static constexpr const char* objMapperService = 58 "xyz.openbmc_project.ObjectMapper"; 59 static constexpr const char* objMapperPath = 60 "/xyz/openbmc_project/object_mapper"; 61 static constexpr const char* objMapperInterface = 62 "xyz.openbmc_project.ObjectMapper"; 63 static constexpr const char* getSubTreeMethod = "GetSubTree"; 64 static constexpr const char* getObjectMethod = "GetObject"; 65 66 static constexpr const char* ipmiUserMutex = "ipmi_usr_mutex"; 67 static constexpr const char* ipmiMutexCleanupLockFile = 68 "/var/lib/ipmi/ipmi_usr_mutex_cleanup"; 69 static constexpr const char* ipmiUserDataFile = "/var/lib/ipmi/ipmi_user.json"; 70 static constexpr const char* ipmiGrpName = "ipmi"; 71 static constexpr size_t privNoAccess = 0xF; 72 static constexpr size_t privMask = 0xF; 73 74 // User manager related 75 static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user"; 76 static constexpr const char* userObjBasePath = "/xyz/openbmc_project/user"; 77 static constexpr const char* userMgrInterface = 78 "xyz.openbmc_project.User.Manager"; 79 static constexpr const char* usersInterface = 80 "xyz.openbmc_project.User.Attributes"; 81 static constexpr const char* deleteUserInterface = 82 "xyz.openbmc_project.Object.Delete"; 83 84 static constexpr const char* createUserMethod = "CreateUser"; 85 static constexpr const char* deleteUserMethod = "Delete"; 86 static constexpr const char* renameUserMethod = "RenameUser"; 87 // User manager signal memebers 88 static constexpr const char* userRenamedSignal = "UserRenamed"; 89 // Mgr interface properties 90 static constexpr const char* allPrivProperty = "AllPrivileges"; 91 static constexpr const char* allGrpProperty = "AllGroups"; 92 // User interface properties 93 static constexpr const char* userPrivProperty = "UserPrivilege"; 94 static constexpr const char* userGrpProperty = "UserGroups"; 95 static constexpr const char* userEnabledProperty = "UserEnabled"; 96 97 static std::array<std::string, (PRIVILEGE_OEM + 1)> ipmiPrivIndex = { 98 "priv-reserved", // PRIVILEGE_RESERVED - 0 99 "priv-callback", // PRIVILEGE_CALLBACK - 1 100 "priv-user", // PRIVILEGE_USER - 2 101 "priv-operator", // PRIVILEGE_OPERATOR - 3 102 "priv-admin", // PRIVILEGE_ADMIN - 4 103 "priv-custom" // PRIVILEGE_OEM - 5 104 }; 105 106 using namespace phosphor::logging; 107 using Json = nlohmann::json; 108 109 using PrivAndGroupType = 110 sdbusplus::message::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 ipmi_ret_t UserAccess::setSpecialUserPassword(const std::string& userName, 719 const std::string& userPassword) 720 { 721 if (!pamUpdatePasswd(userName.c_str(), userPassword.c_str())) 722 { 723 log<level::DEBUG>("Failed to update password"); 724 return IPMI_CC_UNSPECIFIED_ERROR; 725 } 726 return IPMI_CC_OK; 727 } 728 729 ipmi_ret_t UserAccess::setUserPassword(const uint8_t userId, 730 const char* userPassword) 731 { 732 std::string userName; 733 if (ipmiUserGetUserName(userId, userName) != IPMI_CC_OK) 734 { 735 log<level::DEBUG>("User Name not found", 736 entry("USER-ID:%d", (uint8_t)userId)); 737 return IPMI_CC_PARM_OUT_OF_RANGE; 738 } 739 std::string passwd; 740 passwd.assign(reinterpret_cast<const char*>(userPassword), 0, 741 maxIpmi20PasswordSize); 742 if (!std::regex_match(passwd.c_str(), 743 std::regex("[a-zA-z_0-9][a-zA-Z_0-9,?:`!\"]*"))) 744 { 745 log<level::DEBUG>("Invalid password fields", 746 entry("USER-ID:%d", (uint8_t)userId)); 747 return IPMI_CC_INVALID_FIELD_REQUEST; 748 } 749 if (!pamUpdatePasswd(userName.c_str(), passwd.c_str())) 750 { 751 log<level::DEBUG>("Failed to update password", 752 entry("USER-ID:%d", (uint8_t)userId)); 753 return IPMI_CC_UNSPECIFIED_ERROR; 754 } 755 return IPMI_CC_OK; 756 } 757 758 ipmi_ret_t UserAccess::setUserEnabledState(const uint8_t userId, 759 const bool& enabledState) 760 { 761 if (!isValidUserId(userId)) 762 { 763 return IPMI_CC_PARM_OUT_OF_RANGE; 764 } 765 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 766 userLock{*userMutex}; 767 UserInfo* userInfo = getUserInfo(userId); 768 std::string userName; 769 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 770 ipmiMaxUserName); 771 if (userName.empty()) 772 { 773 log<level::DEBUG>("User name not set / invalid"); 774 return IPMI_CC_UNSPECIFIED_ERROR; 775 } 776 if (userInfo->userEnabled != enabledState) 777 { 778 std::string userPath = std::string(userObjBasePath) + "/" + userName; 779 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface, 780 userEnabledProperty, enabledState); 781 userInfo->userEnabled = enabledState; 782 try 783 { 784 writeUserData(); 785 } 786 catch (const std::exception& e) 787 { 788 log<level::DEBUG>("Write user data failed"); 789 return IPMI_CC_UNSPECIFIED_ERROR; 790 } 791 } 792 return IPMI_CC_OK; 793 } 794 795 ipmi_ret_t UserAccess::setUserPrivilegeAccess(const uint8_t userId, 796 const uint8_t chNum, 797 const UserPrivAccess& privAccess, 798 const bool& otherPrivUpdates) 799 { 800 if (!isValidChannel(chNum)) 801 { 802 return IPMI_CC_INVALID_FIELD_REQUEST; 803 } 804 if (!isValidUserId(userId)) 805 { 806 return IPMI_CC_PARM_OUT_OF_RANGE; 807 } 808 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 809 userLock{*userMutex}; 810 UserInfo* userInfo = getUserInfo(userId); 811 std::string userName; 812 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 813 ipmiMaxUserName); 814 if (userName.empty()) 815 { 816 log<level::DEBUG>("User name not set / invalid"); 817 return IPMI_CC_UNSPECIFIED_ERROR; 818 } 819 std::string priv = convertToSystemPrivilege( 820 static_cast<CommandPrivilege>(privAccess.privilege)); 821 uint8_t syncIndex = getUsrMgmtSyncIndex(); 822 if (chNum == syncIndex && 823 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege) 824 { 825 std::string userPath = std::string(userObjBasePath) + "/" + userName; 826 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface, 827 userPrivProperty, priv); 828 } 829 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege; 830 831 if (otherPrivUpdates) 832 { 833 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled; 834 userInfo->userPrivAccess[chNum].linkAuthEnabled = 835 privAccess.linkAuthEnabled; 836 userInfo->userPrivAccess[chNum].accessCallback = 837 privAccess.accessCallback; 838 } 839 try 840 { 841 writeUserData(); 842 } 843 catch (const std::exception& e) 844 { 845 log<level::DEBUG>("Write user data failed"); 846 return IPMI_CC_UNSPECIFIED_ERROR; 847 } 848 return IPMI_CC_OK; 849 } 850 851 uint8_t UserAccess::getUserId(const std::string& userName) 852 { 853 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 854 userLock{*userMutex}; 855 checkAndReloadUserData(); 856 // user index 0 is reserved, starts with 1 857 size_t usrIndex = 1; 858 for (; usrIndex <= ipmiMaxUsers; ++usrIndex) 859 { 860 std::string curName( 861 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 862 ipmiMaxUserName); 863 if (userName == curName) 864 { 865 break; // found the entry 866 } 867 } 868 if (usrIndex > ipmiMaxUsers) 869 { 870 log<level::DEBUG>("User not found", 871 entry("USER_NAME=%s", userName.c_str())); 872 return invalidUserId; 873 } 874 875 return usrIndex; 876 } 877 878 ipmi_ret_t UserAccess::getUserName(const uint8_t userId, std::string& userName) 879 { 880 if (!isValidUserId(userId)) 881 { 882 return IPMI_CC_PARM_OUT_OF_RANGE; 883 } 884 UserInfo* userInfo = getUserInfo(userId); 885 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 886 ipmiMaxUserName); 887 return IPMI_CC_OK; 888 } 889 890 ipmi_ret_t UserAccess::setUserName(const uint8_t userId, 891 const char* userNameInChar) 892 { 893 if (!isValidUserId(userId)) 894 { 895 return IPMI_CC_PARM_OUT_OF_RANGE; 896 } 897 898 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 899 userLock{*userMutex}; 900 std::string oldUser; 901 getUserName(userId, oldUser); 902 903 std::string newUser(userNameInChar, 0, ipmiMaxUserName); 904 if (oldUser == newUser) 905 { 906 // requesting to set the same user name, return success. 907 return IPMI_CC_OK; 908 } 909 bool validUser = isValidUserName(userNameInChar); 910 UserInfo* userInfo = getUserInfo(userId); 911 if (newUser.empty() && !oldUser.empty()) 912 { 913 // Delete existing user 914 std::string userPath = std::string(userObjBasePath) + "/" + oldUser; 915 try 916 { 917 auto method = bus.new_method_call( 918 getUserServiceName().c_str(), userPath.c_str(), 919 deleteUserInterface, deleteUserMethod); 920 auto reply = bus.call(method); 921 } 922 catch (const sdbusplus::exception::SdBusError& e) 923 { 924 log<level::DEBUG>("Failed to excute method", 925 entry("METHOD=%s", deleteUserMethod), 926 entry("PATH=%s", userPath.c_str())); 927 return IPMI_CC_UNSPECIFIED_ERROR; 928 } 929 deleteUserIndex(userId); 930 } 931 else if (oldUser.empty() && !newUser.empty() && validUser) 932 { 933 try 934 { 935 // Create new user 936 auto method = bus.new_method_call( 937 getUserServiceName().c_str(), userMgrObjBasePath, 938 userMgrInterface, createUserMethod); 939 method.append(newUser.c_str(), availableGroups, "", false); 940 auto reply = bus.call(method); 941 } 942 catch (const sdbusplus::exception::SdBusError& e) 943 { 944 log<level::DEBUG>("Failed to excute method", 945 entry("METHOD=%s", createUserMethod), 946 entry("PATH=%s", userMgrObjBasePath)); 947 return IPMI_CC_UNSPECIFIED_ERROR; 948 } 949 std::memcpy(userInfo->userName, userNameInChar, ipmiMaxUserName); 950 userInfo->userInSystem = true; 951 } 952 else if (oldUser != newUser && validUser) 953 { 954 try 955 { 956 // User rename 957 auto method = bus.new_method_call( 958 getUserServiceName().c_str(), userMgrObjBasePath, 959 userMgrInterface, renameUserMethod); 960 method.append(oldUser.c_str(), newUser.c_str()); 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", renameUserMethod), 967 entry("PATH=%s", userMgrObjBasePath)); 968 return IPMI_CC_UNSPECIFIED_ERROR; 969 } 970 std::fill(static_cast<uint8_t*>(userInfo->userName), 971 static_cast<uint8_t*>(userInfo->userName) + 972 sizeof(userInfo->userName), 973 0); 974 std::memcpy(userInfo->userName, userNameInChar, ipmiMaxUserName); 975 ipmiRenameUserEntryPassword(oldUser, newUser); 976 userInfo->userInSystem = true; 977 } 978 else if (!validUser) 979 { 980 return IPMI_CC_INVALID_FIELD_REQUEST; 981 } 982 try 983 { 984 writeUserData(); 985 } 986 catch (const std::exception& e) 987 { 988 log<level::DEBUG>("Write user data failed"); 989 return IPMI_CC_UNSPECIFIED_ERROR; 990 } 991 return IPMI_CC_OK; 992 } 993 994 static constexpr const char* jsonUserName = "user_name"; 995 static constexpr const char* jsonPriv = "privilege"; 996 static constexpr const char* jsonIpmiEnabled = "ipmi_enabled"; 997 static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled"; 998 static constexpr const char* jsonAccCallbk = "access_callback"; 999 static constexpr const char* jsonUserEnabled = "user_enabled"; 1000 static constexpr const char* jsonUserInSys = "user_in_system"; 1001 static constexpr const char* jsonFixedUser = "fixed_user_name"; 1002 1003 void UserAccess::readUserData() 1004 { 1005 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1006 userLock{*userMutex}; 1007 1008 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary); 1009 if (!iUsrData.good()) 1010 { 1011 log<level::ERR>("Error in reading IPMI user data file"); 1012 throw std::ios_base::failure("Error opening IPMI user data file"); 1013 } 1014 1015 Json jsonUsersTbl = Json::array(); 1016 jsonUsersTbl = Json::parse(iUsrData, nullptr, false); 1017 1018 if (jsonUsersTbl.size() != ipmiMaxUsers) 1019 { 1020 log<level::ERR>( 1021 "Error in reading IPMI user data file - User count issues"); 1022 throw std::runtime_error( 1023 "Corrupted IPMI user data file - invalid user count"); 1024 } 1025 // user index 0 is reserved, starts with 1 1026 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1027 { 1028 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0. 1029 if (userInfo.is_null()) 1030 { 1031 log<level::ERR>("Error in reading IPMI user data file - " 1032 "user info corrupted"); 1033 throw std::runtime_error( 1034 "Corrupted IPMI user data file - invalid user info"); 1035 } 1036 std::string userName = userInfo[jsonUserName].get<std::string>(); 1037 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 1038 userName.c_str(), ipmiMaxUserName); 1039 1040 std::vector<std::string> privilege = 1041 userInfo[jsonPriv].get<std::vector<std::string>>(); 1042 std::vector<bool> ipmiEnabled = 1043 userInfo[jsonIpmiEnabled].get<std::vector<bool>>(); 1044 std::vector<bool> linkAuthEnabled = 1045 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>(); 1046 std::vector<bool> accessCallback = 1047 userInfo[jsonAccCallbk].get<std::vector<bool>>(); 1048 if (privilege.size() != ipmiMaxChannels || 1049 ipmiEnabled.size() != ipmiMaxChannels || 1050 linkAuthEnabled.size() != ipmiMaxChannels || 1051 accessCallback.size() != ipmiMaxChannels) 1052 { 1053 log<level::ERR>("Error in reading IPMI user data file - " 1054 "properties corrupted"); 1055 throw std::runtime_error( 1056 "Corrupted IPMI user data file - properties"); 1057 } 1058 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1059 { 1060 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege = 1061 static_cast<uint8_t>( 1062 convertToIPMIPrivilege(privilege[chIndex])); 1063 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled = 1064 ipmiEnabled[chIndex]; 1065 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled = 1066 linkAuthEnabled[chIndex]; 1067 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback = 1068 accessCallback[chIndex]; 1069 } 1070 usersTbl.user[usrIndex].userEnabled = 1071 userInfo[jsonUserEnabled].get<bool>(); 1072 usersTbl.user[usrIndex].userInSystem = 1073 userInfo[jsonUserInSys].get<bool>(); 1074 usersTbl.user[usrIndex].fixedUserName = 1075 userInfo[jsonFixedUser].get<bool>(); 1076 } 1077 1078 log<level::DEBUG>("User data read from IPMI data file"); 1079 iUsrData.close(); 1080 // Update the timestamp 1081 fileLastUpdatedTime = getUpdatedFileTime(); 1082 return; 1083 } 1084 1085 void UserAccess::writeUserData() 1086 { 1087 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1088 userLock{*userMutex}; 1089 1090 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"}; 1091 std::ofstream oUsrData(tmpFile, std::ios::out | std::ios::binary); 1092 if (!oUsrData.good()) 1093 { 1094 log<level::ERR>("Error in creating temporary IPMI user data file"); 1095 throw std::ios_base::failure( 1096 "Error in creating temporary IPMI user data file"); 1097 } 1098 1099 Json jsonUsersTbl = Json::array(); 1100 // user index 0 is reserved, starts with 1 1101 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1102 { 1103 Json jsonUserInfo; 1104 jsonUserInfo[jsonUserName] = std::string( 1105 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 1106 ipmiMaxUserName); 1107 std::vector<std::string> privilege(ipmiMaxChannels); 1108 std::vector<bool> ipmiEnabled(ipmiMaxChannels); 1109 std::vector<bool> linkAuthEnabled(ipmiMaxChannels); 1110 std::vector<bool> accessCallback(ipmiMaxChannels); 1111 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1112 { 1113 privilege[chIndex] = 1114 convertToSystemPrivilege(static_cast<CommandPrivilege>( 1115 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege)); 1116 ipmiEnabled[chIndex] = 1117 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled; 1118 linkAuthEnabled[chIndex] = 1119 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled; 1120 accessCallback[chIndex] = 1121 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback; 1122 } 1123 jsonUserInfo[jsonPriv] = privilege; 1124 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled; 1125 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled; 1126 jsonUserInfo[jsonAccCallbk] = accessCallback; 1127 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled; 1128 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem; 1129 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName; 1130 jsonUsersTbl.push_back(jsonUserInfo); 1131 } 1132 1133 oUsrData << jsonUsersTbl; 1134 oUsrData.flush(); 1135 oUsrData.close(); 1136 1137 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0) 1138 { 1139 log<level::ERR>("Error in renaming temporary IPMI user data file"); 1140 throw std::runtime_error("Error in renaming IPMI user data file"); 1141 } 1142 // Update the timestamp 1143 fileLastUpdatedTime = getUpdatedFileTime(); 1144 return; 1145 } 1146 1147 bool UserAccess::addUserEntry(const std::string& userName, 1148 const std::string& sysPriv, const bool& enabled) 1149 { 1150 UsersTbl* userData = getUsersTblPtr(); 1151 size_t freeIndex = 0xFF; 1152 // user index 0 is reserved, starts with 1 1153 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1154 { 1155 std::string curName( 1156 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 1157 ipmiMaxUserName); 1158 if (userName == curName) 1159 { 1160 log<level::DEBUG>("User name exists", 1161 entry("USER_NAME=%s", userName.c_str())); 1162 return false; // user name exists. 1163 } 1164 1165 if ((!userData->user[usrIndex].userInSystem) && 1166 (userData->user[usrIndex].userName[0] == '\0') && 1167 (freeIndex == 0xFF)) 1168 { 1169 freeIndex = usrIndex; 1170 } 1171 } 1172 if (freeIndex == 0xFF) 1173 { 1174 log<level::ERR>("No empty slots found"); 1175 return false; 1176 } 1177 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName), 1178 userName.c_str(), ipmiMaxUserName); 1179 uint8_t priv = 1180 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) & 1181 privMask; 1182 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1183 { 1184 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv; 1185 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true; 1186 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled = 1187 true; 1188 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true; 1189 } 1190 userData->user[freeIndex].userInSystem = true; 1191 userData->user[freeIndex].userEnabled = enabled; 1192 1193 return true; 1194 } 1195 1196 void UserAccess::deleteUserIndex(const size_t& usrIdx) 1197 { 1198 UsersTbl* userData = getUsersTblPtr(); 1199 1200 std::string userName( 1201 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1202 ipmiMaxUserName); 1203 ipmiClearUserEntryPassword(userName); 1204 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName), 1205 static_cast<uint8_t*>(userData->user[usrIdx].userName) + 1206 sizeof(userData->user[usrIdx].userName), 1207 0); 1208 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1209 { 1210 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess; 1211 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false; 1212 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false; 1213 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false; 1214 } 1215 userData->user[usrIdx].userInSystem = false; 1216 userData->user[usrIdx].userEnabled = false; 1217 return; 1218 } 1219 1220 void UserAccess::checkAndReloadUserData() 1221 { 1222 std::time_t updateTime = getUpdatedFileTime(); 1223 if (updateTime != fileLastUpdatedTime || updateTime == -EIO) 1224 { 1225 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1226 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1227 readUserData(); 1228 } 1229 return; 1230 } 1231 1232 UsersTbl* UserAccess::getUsersTblPtr() 1233 { 1234 // reload data before using it. 1235 checkAndReloadUserData(); 1236 return &usersTbl; 1237 } 1238 1239 void UserAccess::getSystemPrivAndGroups() 1240 { 1241 std::map<std::string, PrivAndGroupType> properties; 1242 try 1243 { 1244 auto method = bus.new_method_call( 1245 getUserServiceName().c_str(), userMgrObjBasePath, 1246 dBusPropertiesInterface, getAllPropertiesMethod); 1247 method.append(userMgrInterface); 1248 1249 auto reply = bus.call(method); 1250 reply.read(properties); 1251 } 1252 catch (const sdbusplus::exception::SdBusError& e) 1253 { 1254 log<level::DEBUG>("Failed to excute method", 1255 entry("METHOD=%s", getAllPropertiesMethod), 1256 entry("PATH=%s", userMgrObjBasePath)); 1257 return; 1258 } 1259 for (const auto& t : properties) 1260 { 1261 auto key = t.first; 1262 if (key == allPrivProperty) 1263 { 1264 availablePrivileges = std::get<std::vector<std::string>>(t.second); 1265 } 1266 else if (key == allGrpProperty) 1267 { 1268 availableGroups = std::get<std::vector<std::string>>(t.second); 1269 } 1270 } 1271 // TODO: Implement Supported Privilege & Groups verification logic 1272 return; 1273 } 1274 1275 std::time_t UserAccess::getUpdatedFileTime() 1276 { 1277 struct stat fileStat; 1278 if (stat(ipmiUserDataFile, &fileStat) != 0) 1279 { 1280 log<level::DEBUG>("Error in getting last updated time stamp"); 1281 return -EIO; 1282 } 1283 return fileStat.st_mtime; 1284 } 1285 1286 void UserAccess::getUserProperties(const DbusUserObjProperties& properties, 1287 std::vector<std::string>& usrGrps, 1288 std::string& usrPriv, bool& usrEnabled) 1289 { 1290 for (const auto& t : properties) 1291 { 1292 std::string key = t.first; 1293 if (key == userPrivProperty) 1294 { 1295 usrPriv = std::get<std::string>(t.second); 1296 } 1297 else if (key == userGrpProperty) 1298 { 1299 usrGrps = std::get<std::vector<std::string>>(t.second); 1300 } 1301 else if (key == userEnabledProperty) 1302 { 1303 usrEnabled = std::get<bool>(t.second); 1304 } 1305 } 1306 return; 1307 } 1308 1309 int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs, 1310 std::vector<std::string>& usrGrps, 1311 std::string& usrPriv, bool& usrEnabled) 1312 { 1313 auto usrObj = userObjs.find(usersInterface); 1314 if (usrObj != userObjs.end()) 1315 { 1316 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled); 1317 return 0; 1318 } 1319 return -EIO; 1320 } 1321 1322 void UserAccess::initUserDataFile() 1323 { 1324 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1325 userLock{*userMutex}; 1326 try 1327 { 1328 readUserData(); 1329 } 1330 catch (const std::ios_base::failure& e) 1331 { // File is empty, create it for the first time 1332 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1333 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1334 // user index 0 is reserved, starts with 1 1335 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex) 1336 { 1337 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1338 { 1339 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege = 1340 privNoAccess; 1341 } 1342 } 1343 writeUserData(); 1344 } 1345 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs; 1346 try 1347 { 1348 auto method = bus.new_method_call(getUserServiceName().c_str(), 1349 userMgrObjBasePath, dBusObjManager, 1350 getManagedObjectsMethod); 1351 auto reply = bus.call(method); 1352 reply.read(managedObjs); 1353 } 1354 catch (const sdbusplus::exception::SdBusError& e) 1355 { 1356 log<level::DEBUG>("Failed to excute method", 1357 entry("METHOD=%s", getSubTreeMethod), 1358 entry("PATH=%s", userMgrObjBasePath)); 1359 return; 1360 } 1361 1362 UsersTbl* userData = &usersTbl; 1363 // user index 0 is reserved, starts with 1 1364 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx) 1365 { 1366 if ((userData->user[usrIdx].userInSystem) && 1367 (userData->user[usrIdx].userName[0] != '\0')) 1368 { 1369 std::vector<std::string> usrGrps; 1370 std::string usrPriv; 1371 bool usrEnabled; 1372 1373 std::string userName( 1374 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1375 ipmiMaxUserName); 1376 std::string usersPath = 1377 std::string(userObjBasePath) + "/" + userName; 1378 1379 auto usrObj = managedObjs.find(usersPath); 1380 if (usrObj != managedObjs.end()) 1381 { 1382 // User exist. Lets check and update other fileds 1383 getUserObjProperties(usrObj->second, usrGrps, usrPriv, 1384 usrEnabled); 1385 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) == 1386 usrGrps.end()) 1387 { 1388 // Group "ipmi" is removed so lets remove user in IPMI 1389 deleteUserIndex(usrIdx); 1390 } 1391 else 1392 { 1393 // Group "ipmi" is present so lets update other properties 1394 // in IPMI 1395 uint8_t priv = 1396 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask; 1397 // Update all channels priv, only if it is not equivalent to 1398 // getUsrMgmtSyncIndex() 1399 if (userData->user[usrIdx] 1400 .userPrivAccess[getUsrMgmtSyncIndex()] 1401 .privilege != priv) 1402 { 1403 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 1404 ++chIndex) 1405 { 1406 userData->user[usrIdx] 1407 .userPrivAccess[chIndex] 1408 .privilege = priv; 1409 } 1410 } 1411 if (userData->user[usrIdx].userEnabled != usrEnabled) 1412 { 1413 userData->user[usrIdx].userEnabled = usrEnabled; 1414 } 1415 } 1416 1417 // We are done with this obj. lets delete from MAP 1418 managedObjs.erase(usrObj); 1419 } 1420 else 1421 { 1422 deleteUserIndex(usrIdx); 1423 } 1424 } 1425 } 1426 1427 // Walk through remnaining managedObj users list 1428 // Add them to ipmi data base 1429 for (const auto& usrObj : managedObjs) 1430 { 1431 std::vector<std::string> usrGrps; 1432 std::string usrPriv, userName; 1433 bool usrEnabled; 1434 std::string usrObjPath = std::string(usrObj.first); 1435 if (getUserNameFromPath(usrObj.first.str, userName) != 0) 1436 { 1437 log<level::ERR>("Error in user object path"); 1438 continue; 1439 } 1440 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled); 1441 // Add 'ipmi' group users 1442 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) != 1443 usrGrps.end()) 1444 { 1445 // CREATE NEW USER 1446 if (true != addUserEntry(userName, usrPriv, usrEnabled)) 1447 { 1448 break; 1449 } 1450 } 1451 } 1452 1453 // All userData slots update done. Lets write the data 1454 writeUserData(); 1455 1456 return; 1457 } 1458 } // namespace ipmi 1459