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 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 Json jsonUsersTbl = Json::array(); 1091 // user index 0 is reserved, starts with 1 1092 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1093 { 1094 Json jsonUserInfo; 1095 jsonUserInfo[jsonUserName] = std::string( 1096 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 1097 ipmiMaxUserName); 1098 std::vector<std::string> privilege(ipmiMaxChannels); 1099 std::vector<bool> ipmiEnabled(ipmiMaxChannels); 1100 std::vector<bool> linkAuthEnabled(ipmiMaxChannels); 1101 std::vector<bool> accessCallback(ipmiMaxChannels); 1102 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 1103 { 1104 privilege[chIndex] = 1105 convertToSystemPrivilege(static_cast<CommandPrivilege>( 1106 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege)); 1107 ipmiEnabled[chIndex] = 1108 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled; 1109 linkAuthEnabled[chIndex] = 1110 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled; 1111 accessCallback[chIndex] = 1112 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback; 1113 } 1114 jsonUserInfo[jsonPriv] = privilege; 1115 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled; 1116 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled; 1117 jsonUserInfo[jsonAccCallbk] = accessCallback; 1118 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled; 1119 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem; 1120 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName; 1121 jsonUsersTbl.push_back(jsonUserInfo); 1122 } 1123 1124 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"}; 1125 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC, 1126 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 1127 if (fd < 0) 1128 { 1129 log<level::ERR>("Error in creating temporary IPMI user data file"); 1130 throw std::ios_base::failure( 1131 "Error in creating temporary IPMI user data file"); 1132 } 1133 const auto& writeStr = jsonUsersTbl.dump(); 1134 if (write(fd, writeStr.c_str(), writeStr.size()) != 1135 static_cast<ssize_t>(writeStr.size())) 1136 { 1137 close(fd); 1138 log<level::ERR>("Error in writing temporary IPMI user data file"); 1139 throw std::ios_base::failure( 1140 "Error in writing temporary IPMI user data file"); 1141 } 1142 close(fd); 1143 1144 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0) 1145 { 1146 log<level::ERR>("Error in renaming temporary IPMI user data file"); 1147 throw std::runtime_error("Error in renaming IPMI user data file"); 1148 } 1149 // Update the timestamp 1150 fileLastUpdatedTime = getUpdatedFileTime(); 1151 return; 1152 } 1153 1154 bool UserAccess::addUserEntry(const std::string& userName, 1155 const std::string& sysPriv, const bool& enabled) 1156 { 1157 UsersTbl* userData = getUsersTblPtr(); 1158 size_t freeIndex = 0xFF; 1159 // user index 0 is reserved, starts with 1 1160 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1161 { 1162 std::string curName( 1163 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 1164 ipmiMaxUserName); 1165 if (userName == curName) 1166 { 1167 log<level::DEBUG>("User name exists", 1168 entry("USER_NAME=%s", userName.c_str())); 1169 return false; // user name exists. 1170 } 1171 1172 if ((!userData->user[usrIndex].userInSystem) && 1173 (userData->user[usrIndex].userName[0] == '\0') && 1174 (freeIndex == 0xFF)) 1175 { 1176 freeIndex = usrIndex; 1177 } 1178 } 1179 if (freeIndex == 0xFF) 1180 { 1181 log<level::ERR>("No empty slots found"); 1182 return false; 1183 } 1184 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName), 1185 userName.c_str(), ipmiMaxUserName); 1186 uint8_t priv = 1187 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) & 1188 privMask; 1189 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1190 { 1191 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv; 1192 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true; 1193 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled = 1194 true; 1195 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true; 1196 } 1197 userData->user[freeIndex].userInSystem = true; 1198 userData->user[freeIndex].userEnabled = enabled; 1199 1200 return true; 1201 } 1202 1203 void UserAccess::deleteUserIndex(const size_t& usrIdx) 1204 { 1205 UsersTbl* userData = getUsersTblPtr(); 1206 1207 std::string userName( 1208 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1209 ipmiMaxUserName); 1210 ipmiClearUserEntryPassword(userName); 1211 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName), 1212 static_cast<uint8_t*>(userData->user[usrIdx].userName) + 1213 sizeof(userData->user[usrIdx].userName), 1214 0); 1215 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1216 { 1217 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess; 1218 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false; 1219 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false; 1220 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false; 1221 } 1222 userData->user[usrIdx].userInSystem = false; 1223 userData->user[usrIdx].userEnabled = false; 1224 return; 1225 } 1226 1227 void UserAccess::checkAndReloadUserData() 1228 { 1229 std::time_t updateTime = getUpdatedFileTime(); 1230 if (updateTime != fileLastUpdatedTime || updateTime == -EIO) 1231 { 1232 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1233 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1234 readUserData(); 1235 } 1236 return; 1237 } 1238 1239 UsersTbl* UserAccess::getUsersTblPtr() 1240 { 1241 // reload data before using it. 1242 checkAndReloadUserData(); 1243 return &usersTbl; 1244 } 1245 1246 void UserAccess::getSystemPrivAndGroups() 1247 { 1248 std::map<std::string, PrivAndGroupType> properties; 1249 try 1250 { 1251 auto method = bus.new_method_call( 1252 getUserServiceName().c_str(), userMgrObjBasePath, 1253 dBusPropertiesInterface, getAllPropertiesMethod); 1254 method.append(userMgrInterface); 1255 1256 auto reply = bus.call(method); 1257 reply.read(properties); 1258 } 1259 catch (const sdbusplus::exception::SdBusError& e) 1260 { 1261 log<level::DEBUG>("Failed to excute method", 1262 entry("METHOD=%s", getAllPropertiesMethod), 1263 entry("PATH=%s", userMgrObjBasePath)); 1264 return; 1265 } 1266 for (const auto& t : properties) 1267 { 1268 auto key = t.first; 1269 if (key == allPrivProperty) 1270 { 1271 availablePrivileges = std::get<std::vector<std::string>>(t.second); 1272 } 1273 else if (key == allGrpProperty) 1274 { 1275 availableGroups = std::get<std::vector<std::string>>(t.second); 1276 } 1277 } 1278 // TODO: Implement Supported Privilege & Groups verification logic 1279 return; 1280 } 1281 1282 std::time_t UserAccess::getUpdatedFileTime() 1283 { 1284 struct stat fileStat; 1285 if (stat(ipmiUserDataFile, &fileStat) != 0) 1286 { 1287 log<level::DEBUG>("Error in getting last updated time stamp"); 1288 return -EIO; 1289 } 1290 return fileStat.st_mtime; 1291 } 1292 1293 void UserAccess::getUserProperties(const DbusUserObjProperties& properties, 1294 std::vector<std::string>& usrGrps, 1295 std::string& usrPriv, bool& usrEnabled) 1296 { 1297 for (const auto& t : properties) 1298 { 1299 std::string key = t.first; 1300 if (key == userPrivProperty) 1301 { 1302 usrPriv = std::get<std::string>(t.second); 1303 } 1304 else if (key == userGrpProperty) 1305 { 1306 usrGrps = std::get<std::vector<std::string>>(t.second); 1307 } 1308 else if (key == userEnabledProperty) 1309 { 1310 usrEnabled = std::get<bool>(t.second); 1311 } 1312 } 1313 return; 1314 } 1315 1316 int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs, 1317 std::vector<std::string>& usrGrps, 1318 std::string& usrPriv, bool& usrEnabled) 1319 { 1320 auto usrObj = userObjs.find(usersInterface); 1321 if (usrObj != userObjs.end()) 1322 { 1323 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled); 1324 return 0; 1325 } 1326 return -EIO; 1327 } 1328 1329 void UserAccess::initUserDataFile() 1330 { 1331 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1332 userLock{*userMutex}; 1333 try 1334 { 1335 readUserData(); 1336 } 1337 catch (const std::ios_base::failure& e) 1338 { // File is empty, create it for the first time 1339 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1340 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1341 // user index 0 is reserved, starts with 1 1342 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex) 1343 { 1344 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1345 { 1346 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege = 1347 privNoAccess; 1348 } 1349 } 1350 writeUserData(); 1351 } 1352 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs; 1353 try 1354 { 1355 auto method = bus.new_method_call(getUserServiceName().c_str(), 1356 userMgrObjBasePath, dBusObjManager, 1357 getManagedObjectsMethod); 1358 auto reply = bus.call(method); 1359 reply.read(managedObjs); 1360 } 1361 catch (const sdbusplus::exception::SdBusError& e) 1362 { 1363 log<level::DEBUG>("Failed to excute method", 1364 entry("METHOD=%s", getSubTreeMethod), 1365 entry("PATH=%s", userMgrObjBasePath)); 1366 return; 1367 } 1368 1369 UsersTbl* userData = &usersTbl; 1370 // user index 0 is reserved, starts with 1 1371 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx) 1372 { 1373 if ((userData->user[usrIdx].userInSystem) && 1374 (userData->user[usrIdx].userName[0] != '\0')) 1375 { 1376 std::vector<std::string> usrGrps; 1377 std::string usrPriv; 1378 bool usrEnabled; 1379 1380 std::string userName( 1381 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1382 ipmiMaxUserName); 1383 std::string usersPath = 1384 std::string(userObjBasePath) + "/" + userName; 1385 1386 auto usrObj = managedObjs.find(usersPath); 1387 if (usrObj != managedObjs.end()) 1388 { 1389 // User exist. Lets check and update other fileds 1390 getUserObjProperties(usrObj->second, usrGrps, usrPriv, 1391 usrEnabled); 1392 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) == 1393 usrGrps.end()) 1394 { 1395 // Group "ipmi" is removed so lets remove user in IPMI 1396 deleteUserIndex(usrIdx); 1397 } 1398 else 1399 { 1400 // Group "ipmi" is present so lets update other properties 1401 // in IPMI 1402 uint8_t priv = 1403 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask; 1404 // Update all channels priv, only if it is not equivalent to 1405 // getUsrMgmtSyncIndex() 1406 if (userData->user[usrIdx] 1407 .userPrivAccess[getUsrMgmtSyncIndex()] 1408 .privilege != priv) 1409 { 1410 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 1411 ++chIndex) 1412 { 1413 userData->user[usrIdx] 1414 .userPrivAccess[chIndex] 1415 .privilege = priv; 1416 } 1417 } 1418 if (userData->user[usrIdx].userEnabled != usrEnabled) 1419 { 1420 userData->user[usrIdx].userEnabled = usrEnabled; 1421 } 1422 } 1423 1424 // We are done with this obj. lets delete from MAP 1425 managedObjs.erase(usrObj); 1426 } 1427 else 1428 { 1429 deleteUserIndex(usrIdx); 1430 } 1431 } 1432 } 1433 1434 // Walk through remnaining managedObj users list 1435 // Add them to ipmi data base 1436 for (const auto& usrObj : managedObjs) 1437 { 1438 std::vector<std::string> usrGrps; 1439 std::string usrPriv, userName; 1440 bool usrEnabled; 1441 std::string usrObjPath = std::string(usrObj.first); 1442 if (getUserNameFromPath(usrObj.first.str, userName) != 0) 1443 { 1444 log<level::ERR>("Error in user object path"); 1445 continue; 1446 } 1447 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled); 1448 // Add 'ipmi' group users 1449 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) != 1450 usrGrps.end()) 1451 { 1452 // CREATE NEW USER 1453 if (true != addUserEntry(userName, usrPriv, usrEnabled)) 1454 { 1455 break; 1456 } 1457 } 1458 } 1459 1460 // All userData slots update done. Lets write the data 1461 writeUserData(); 1462 1463 return; 1464 } 1465 } // namespace ipmi 1466