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 <sys/stat.h> 21 #include <unistd.h> 22 23 #include <boost/interprocess/sync/named_recursive_mutex.hpp> 24 #include <boost/interprocess/sync/scoped_lock.hpp> 25 #include <cerrno> 26 #include <fstream> 27 #include <host-ipmid/ipmid-host-cmd.hpp> 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(nullptr); 119 std::unique_ptr<sdbusplus::bus::match_t> userMgrRenamedSignal(nullptr); 120 std::unique_ptr<sdbusplus::bus::match_t> userPropertiesSignal(nullptr); 121 122 // TODO: Below code can be removed once it is moved to common layer libmiscutil 123 std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf, 124 const std::string& path) 125 { 126 auto mapperCall = bus.new_method_call(objMapperService, objMapperPath, 127 objMapperInterface, getObjectMethod); 128 129 mapperCall.append(path); 130 mapperCall.append(std::vector<std::string>({intf})); 131 132 auto mapperResponseMsg = bus.call(mapperCall); 133 134 std::map<std::string, std::vector<std::string>> mapperResponse; 135 mapperResponseMsg.read(mapperResponse); 136 137 if (mapperResponse.begin() == mapperResponse.end()) 138 { 139 throw sdbusplus::exception::SdBusError( 140 -EIO, "ERROR in reading the mapper response"); 141 } 142 143 return mapperResponse.begin()->first; 144 } 145 146 void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service, 147 const std::string& objPath, const std::string& interface, 148 const std::string& property, 149 const DbusUserPropVariant& value) 150 { 151 try 152 { 153 auto method = 154 bus.new_method_call(service.c_str(), objPath.c_str(), 155 dBusPropertiesInterface, setPropertiesMethod); 156 method.append(interface, property, value); 157 bus.call(method); 158 } 159 catch (const sdbusplus::exception::SdBusError& e) 160 { 161 log<level::ERR>("Failed to set property", 162 entry("PROPERTY=%s", property.c_str()), 163 entry("PATH=%s", objPath.c_str()), 164 entry("INTERFACE=%s", interface.c_str())); 165 throw; 166 } 167 } 168 169 static std::string getUserServiceName() 170 { 171 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 172 static std::string userMgmtService; 173 if (userMgmtService.empty()) 174 { 175 try 176 { 177 userMgmtService = 178 ipmi::getUserService(bus, userMgrInterface, userMgrObjBasePath); 179 } 180 catch (const sdbusplus::exception::SdBusError& e) 181 { 182 userMgmtService.clear(); 183 } 184 } 185 return userMgmtService; 186 } 187 188 UserAccess& getUserAccessObject() 189 { 190 static UserAccess userAccess; 191 return userAccess; 192 } 193 194 int getUserNameFromPath(const std::string& path, std::string& userName) 195 { 196 static size_t pos = strlen(userObjBasePath) + 1; 197 if (path.find(userObjBasePath) == std::string::npos) 198 { 199 return -EINVAL; 200 } 201 userName.assign(path, pos, path.size()); 202 return 0; 203 } 204 205 void userUpdateHelper(UserAccess& usrAccess, const UserUpdateEvent& userEvent, 206 const std::string& userName, const std::string& priv, 207 const bool& enabled, const std::string& newUserName) 208 { 209 UsersTbl* userData = usrAccess.getUsersTblPtr(); 210 if (userEvent == UserUpdateEvent::userCreated) 211 { 212 if (usrAccess.addUserEntry(userName, priv, enabled) == false) 213 { 214 return; 215 } 216 } 217 else 218 { 219 // user index 0 is reserved, starts with 1 220 size_t usrIndex = 1; 221 for (; usrIndex <= ipmiMaxUsers; ++usrIndex) 222 { 223 std::string curName( 224 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 225 ipmiMaxUserName); 226 if (userName == curName) 227 { 228 break; // found the entry 229 } 230 } 231 if (usrIndex > ipmiMaxUsers) 232 { 233 log<level::DEBUG>("User not found for signal", 234 entry("USER_NAME=%s", userName.c_str()), 235 entry("USER_EVENT=%d", userEvent)); 236 return; 237 } 238 switch (userEvent) 239 { 240 case UserUpdateEvent::userDeleted: 241 { 242 usrAccess.deleteUserIndex(usrIndex); 243 break; 244 } 245 case UserUpdateEvent::userPrivUpdated: 246 { 247 uint8_t userPriv = 248 static_cast<uint8_t>( 249 UserAccess::convertToIPMIPrivilege(priv)) & 250 privMask; 251 // Update all channels privileges, only if it is not equivalent 252 // to getUsrMgmtSyncIndex() 253 if (userData->user[usrIndex] 254 .userPrivAccess[UserAccess::getUsrMgmtSyncIndex()] 255 .privilege != userPriv) 256 { 257 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 258 ++chIndex) 259 { 260 userData->user[usrIndex] 261 .userPrivAccess[chIndex] 262 .privilege = userPriv; 263 } 264 } 265 break; 266 } 267 case UserUpdateEvent::userRenamed: 268 { 269 std::fill( 270 static_cast<uint8_t*>(userData->user[usrIndex].userName), 271 static_cast<uint8_t*>(userData->user[usrIndex].userName) + 272 sizeof(userData->user[usrIndex].userName), 273 0); 274 std::strncpy( 275 reinterpret_cast<char*>(userData->user[usrIndex].userName), 276 newUserName.c_str(), ipmiMaxUserName); 277 ipmiRenameUserEntryPassword(userName, newUserName); 278 break; 279 } 280 case UserUpdateEvent::userStateUpdated: 281 { 282 userData->user[usrIndex].userEnabled = enabled; 283 break; 284 } 285 default: 286 { 287 log<level::ERR>("Unhandled user event", 288 entry("USER_EVENT=%d", userEvent)); 289 return; 290 } 291 } 292 } 293 usrAccess.writeUserData(); 294 log<level::DEBUG>("User event handled successfully", 295 entry("USER_NAME=%s", userName.c_str()), 296 entry("USER_EVENT=%d", userEvent)); 297 298 return; 299 } 300 301 void userUpdatedSignalHandler(UserAccess& usrAccess, 302 sdbusplus::message::message& msg) 303 { 304 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 305 std::string signal = msg.get_member(); 306 std::string userName, update, priv, newUserName; 307 std::vector<std::string> groups; 308 bool enabled = false; 309 UserUpdateEvent userEvent = UserUpdateEvent::reservedEvent; 310 if (signal == intfAddedSignal) 311 { 312 DbusUserObjPath objPath; 313 DbusUserObjValue objValue; 314 msg.read(objPath, objValue); 315 getUserNameFromPath(objPath.str, userName); 316 if (usrAccess.getUserObjProperties(objValue, groups, priv, enabled) != 317 0) 318 { 319 return; 320 } 321 if (std::find(groups.begin(), groups.end(), ipmiGrpName) == 322 groups.end()) 323 { 324 return; 325 } 326 userEvent = UserUpdateEvent::userCreated; 327 } 328 else if (signal == intfRemovedSignal) 329 { 330 DbusUserObjPath objPath; 331 std::vector<std::string> interfaces; 332 msg.read(objPath, interfaces); 333 getUserNameFromPath(objPath.str, userName); 334 userEvent = UserUpdateEvent::userDeleted; 335 } 336 else if (signal == userRenamedSignal) 337 { 338 msg.read(userName, newUserName); 339 userEvent = UserUpdateEvent::userRenamed; 340 } 341 else if (signal == propertiesChangedSignal) 342 { 343 getUserNameFromPath(msg.get_path(), userName); 344 } 345 else 346 { 347 log<level::ERR>("Unknown user update signal", 348 entry("SIGNAL=%s", signal.c_str())); 349 return; 350 } 351 352 if (signal.empty() || userName.empty() || 353 (signal == userRenamedSignal && newUserName.empty())) 354 { 355 log<level::ERR>("Invalid inputs received"); 356 return; 357 } 358 359 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 360 userLock{*(usrAccess.userMutex)}; 361 usrAccess.checkAndReloadUserData(); 362 363 if (signal == propertiesChangedSignal) 364 { 365 std::string intfName; 366 DbusUserObjProperties chProperties; 367 msg.read(intfName, chProperties); // skip reading 3rd argument. 368 for (const auto& prop : chProperties) 369 { 370 userEvent = UserUpdateEvent::reservedEvent; 371 std::string member = prop.first; 372 if (member == userPrivProperty) 373 { 374 priv = prop.second.get<std::string>(); 375 userEvent = UserUpdateEvent::userPrivUpdated; 376 } 377 else if (member == userGrpProperty) 378 { 379 groups = prop.second.get<std::vector<std::string>>(); 380 userEvent = UserUpdateEvent::userGrpUpdated; 381 } 382 else if (member == userEnabledProperty) 383 { 384 enabled = prop.second.get<bool>(); 385 userEvent = UserUpdateEvent::userStateUpdated; 386 } 387 // Process based on event type. 388 if (userEvent == UserUpdateEvent::userGrpUpdated) 389 { 390 if (std::find(groups.begin(), groups.end(), ipmiGrpName) == 391 groups.end()) 392 { 393 // remove user from ipmi user list. 394 userUpdateHelper(usrAccess, UserUpdateEvent::userDeleted, 395 userName, priv, enabled, newUserName); 396 } 397 else 398 { 399 DbusUserObjProperties properties; 400 try 401 { 402 auto method = bus.new_method_call( 403 getUserServiceName().c_str(), msg.get_path(), 404 dBusPropertiesInterface, getAllPropertiesMethod); 405 method.append(usersInterface); 406 auto reply = bus.call(method); 407 reply.read(properties); 408 } 409 catch (const sdbusplus::exception::SdBusError& e) 410 { 411 log<level::DEBUG>( 412 "Failed to excute method", 413 entry("METHOD=%s", getAllPropertiesMethod), 414 entry("PATH=%s", msg.get_path())); 415 return; 416 } 417 usrAccess.getUserProperties(properties, groups, priv, 418 enabled); 419 // add user to ipmi user list. 420 userUpdateHelper(usrAccess, UserUpdateEvent::userCreated, 421 userName, priv, enabled, newUserName); 422 } 423 } 424 else if (userEvent != UserUpdateEvent::reservedEvent) 425 { 426 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled, 427 newUserName); 428 } 429 } 430 } 431 else if (userEvent != UserUpdateEvent::reservedEvent) 432 { 433 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled, 434 newUserName); 435 } 436 return; 437 } 438 439 UserAccess::~UserAccess() 440 { 441 if (signalHndlrObject) 442 { 443 userUpdatedSignal.reset(); 444 userMgrRenamedSignal.reset(); 445 userPropertiesSignal.reset(); 446 sigHndlrLock.unlock(); 447 } 448 } 449 450 UserAccess::UserAccess() : bus(ipmid_get_sd_bus_connection()) 451 { 452 std::ofstream mutexCleanUpFile; 453 mutexCleanUpFile.open(ipmiMutexCleanupLockFile, 454 std::ofstream::out | std::ofstream::app); 455 if (!mutexCleanUpFile.good()) 456 { 457 log<level::DEBUG>("Unable to open mutex cleanup file"); 458 return; 459 } 460 mutexCleanUpFile.close(); 461 mutexCleanupLock = boost::interprocess::file_lock(ipmiMutexCleanupLockFile); 462 if (mutexCleanupLock.try_lock()) 463 { 464 boost::interprocess::named_recursive_mutex::remove(ipmiUserMutex); 465 } 466 mutexCleanupLock.lock_sharable(); 467 userMutex = std::make_unique<boost::interprocess::named_recursive_mutex>( 468 boost::interprocess::open_or_create, ipmiUserMutex); 469 470 initUserDataFile(); 471 getSystemPrivAndGroups(); 472 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile); 473 // Register it for single object and single process either netipimd / 474 // host-ipmid 475 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock()) 476 { 477 log<level::DEBUG>("Registering signal handler"); 478 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>( 479 bus, 480 sdbusplus::bus::match::rules::type::signal() + 481 sdbusplus::bus::match::rules::interface(dBusObjManager) + 482 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 483 [&](sdbusplus::message::message& msg) { 484 userUpdatedSignalHandler(*this, msg); 485 }); 486 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>( 487 bus, 488 sdbusplus::bus::match::rules::type::signal() + 489 sdbusplus::bus::match::rules::interface(userMgrInterface) + 490 sdbusplus::bus::match::rules::path(userMgrObjBasePath), 491 [&](sdbusplus::message::message& msg) { 492 userUpdatedSignalHandler(*this, msg); 493 }); 494 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>( 495 bus, 496 sdbusplus::bus::match::rules::type::signal() + 497 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) + 498 sdbusplus::bus::match::rules::interface( 499 dBusPropertiesInterface) + 500 sdbusplus::bus::match::rules::member(propertiesChangedSignal) + 501 sdbusplus::bus::match::rules::argN(0, usersInterface), 502 [&](sdbusplus::message::message& msg) { 503 userUpdatedSignalHandler(*this, msg); 504 }); 505 signalHndlrObject = true; 506 } 507 } 508 509 UserInfo* UserAccess::getUserInfo(const uint8_t& userId) 510 { 511 checkAndReloadUserData(); 512 return &usersTbl.user[userId]; 513 } 514 515 void UserAccess::setUserInfo(const uint8_t& userId, UserInfo* userInfo) 516 { 517 checkAndReloadUserData(); 518 std::copy(reinterpret_cast<uint8_t*>(userInfo), 519 reinterpret_cast<uint8_t*>(userInfo) + sizeof(*userInfo), 520 reinterpret_cast<uint8_t*>(&usersTbl.user[userId])); 521 writeUserData(); 522 } 523 524 bool UserAccess::isValidChannel(const uint8_t& chNum) 525 { 526 return (chNum < ipmiMaxChannels); 527 } 528 529 bool UserAccess::isValidUserId(const uint8_t& userId) 530 { 531 return ((userId <= ipmiMaxUsers) && (userId != reservedUserId)); 532 } 533 534 bool UserAccess::isValidPrivilege(const uint8_t& priv) 535 { 536 return ((priv >= PRIVILEGE_CALLBACK && priv <= PRIVILEGE_OEM) || 537 priv == privNoAccess); 538 } 539 540 uint8_t UserAccess::getUsrMgmtSyncIndex() 541 { 542 // TODO: Need to get LAN1 channel number dynamically, 543 // which has to be in sync with system user privilege 544 // level(Phosphor-user-manager). Note: For time being chanLan1 is marked as 545 // sync index to the user-manager privilege.. 546 return static_cast<uint8_t>(EChannelID::chanLan1); 547 } 548 549 CommandPrivilege UserAccess::convertToIPMIPrivilege(const std::string& value) 550 { 551 auto iter = std::find(ipmiPrivIndex.begin(), ipmiPrivIndex.end(), value); 552 if (iter == ipmiPrivIndex.end()) 553 { 554 if (value == "") 555 { 556 return static_cast<CommandPrivilege>(privNoAccess); 557 } 558 log<level::ERR>("Error in converting to IPMI privilege", 559 entry("PRIV=%s", value.c_str())); 560 throw std::out_of_range("Out of range - convertToIPMIPrivilege"); 561 } 562 else 563 { 564 return static_cast<CommandPrivilege>( 565 std::distance(ipmiPrivIndex.begin(), iter)); 566 } 567 } 568 569 std::string UserAccess::convertToSystemPrivilege(const CommandPrivilege& value) 570 { 571 if (value == static_cast<CommandPrivilege>(privNoAccess)) 572 { 573 return ""; 574 } 575 try 576 { 577 return ipmiPrivIndex.at(value); 578 } 579 catch (const std::out_of_range& e) 580 { 581 log<level::ERR>("Error in converting to system privilege", 582 entry("PRIV=%d", static_cast<uint8_t>(value))); 583 throw std::out_of_range("Out of range - convertToSystemPrivilege"); 584 } 585 } 586 587 bool UserAccess::isValidUserName(const char* userNameInChar) 588 { 589 if (!userNameInChar) 590 { 591 log<level::ERR>("null ptr"); 592 return false; 593 } 594 std::string userName(userNameInChar, 0, ipmiMaxUserName); 595 if (!std::regex_match(userName.c_str(), 596 std::regex("[a-zA-z_][a-zA-Z_0-9]*"))) 597 { 598 log<level::ERR>("Unsupported characters in user name"); 599 return false; 600 } 601 if (userName == "root") 602 { 603 log<level::ERR>("Invalid user name - root"); 604 return false; 605 } 606 std::map<DbusUserObjPath, DbusUserObjValue> properties; 607 try 608 { 609 auto method = bus.new_method_call(getUserServiceName().c_str(), 610 userMgrObjBasePath, dBusObjManager, 611 getManagedObjectsMethod); 612 auto reply = bus.call(method); 613 reply.read(properties); 614 } 615 catch (const sdbusplus::exception::SdBusError& e) 616 { 617 log<level::ERR>("Failed to excute method", 618 entry("METHOD=%s", getSubTreeMethod), 619 entry("PATH=%s", userMgrObjBasePath)); 620 return false; 621 } 622 623 std::string usersPath = std::string(userObjBasePath) + "/" + userName; 624 if (properties.find(usersPath) != properties.end()) 625 { 626 log<level::DEBUG>("User name already exists", 627 entry("USER_NAME=%s", userName.c_str())); 628 return false; 629 } 630 631 return true; 632 } 633 634 ipmi_ret_t UserAccess::setUserEnabledState(const uint8_t& userId, 635 const bool& enabledState) 636 { 637 if (!isValidUserId(userId)) 638 { 639 return IPMI_CC_PARM_OUT_OF_RANGE; 640 } 641 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 642 userLock{*userMutex}; 643 UserInfo* userInfo = getUserInfo(userId); 644 std::string userName; 645 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 646 ipmiMaxUserName); 647 if (userName.empty()) 648 { 649 log<level::DEBUG>("User name not set / invalid"); 650 return IPMI_CC_UNSPECIFIED_ERROR; 651 } 652 if (userInfo->userEnabled != enabledState) 653 { 654 std::string userPath = std::string(userObjBasePath) + "/" + userName; 655 setDbusProperty(bus, getUserServiceName().c_str(), userPath.c_str(), 656 usersInterface, userEnabledProperty, enabledState); 657 } 658 return IPMI_CC_OK; 659 } 660 661 ipmi_ret_t UserAccess::setUserPrivilegeAccess(const uint8_t& userId, 662 const uint8_t& chNum, 663 const UserPrivAccess& privAccess, 664 const bool& otherPrivUpdates) 665 { 666 if (!isValidChannel(chNum)) 667 { 668 return IPMI_CC_INVALID_FIELD_REQUEST; 669 } 670 if (!isValidUserId(userId)) 671 { 672 return IPMI_CC_PARM_OUT_OF_RANGE; 673 } 674 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 675 userLock{*userMutex}; 676 UserInfo* userInfo = getUserInfo(userId); 677 std::string userName; 678 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 679 ipmiMaxUserName); 680 if (userName.empty()) 681 { 682 log<level::DEBUG>("User name not set / invalid"); 683 return IPMI_CC_UNSPECIFIED_ERROR; 684 } 685 std::string priv = convertToSystemPrivilege( 686 static_cast<CommandPrivilege>(privAccess.privilege)); 687 if (priv.empty()) 688 { 689 return IPMI_CC_PARM_OUT_OF_RANGE; 690 } 691 uint8_t syncIndex = getUsrMgmtSyncIndex(); 692 if (chNum == syncIndex && 693 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege) 694 { 695 std::string userPath = std::string(userObjBasePath) + "/" + userName; 696 setDbusProperty(bus, getUserServiceName().c_str(), userPath.c_str(), 697 usersInterface, userPrivProperty, priv); 698 } 699 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege; 700 701 if (otherPrivUpdates) 702 { 703 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled; 704 userInfo->userPrivAccess[chNum].linkAuthEnabled = 705 privAccess.linkAuthEnabled; 706 userInfo->userPrivAccess[chNum].accessCallback = 707 privAccess.accessCallback; 708 } 709 try 710 { 711 writeUserData(); 712 } 713 catch (const std::exception& e) 714 { 715 log<level::DEBUG>("Write user data failed"); 716 return IPMI_CC_UNSPECIFIED_ERROR; 717 } 718 return IPMI_CC_OK; 719 } 720 721 uint8_t UserAccess::getUserId(const std::string& userName) 722 { 723 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 724 userLock{*userMutex}; 725 checkAndReloadUserData(); 726 // user index 0 is reserved, starts with 1 727 size_t usrIndex = 1; 728 for (; usrIndex <= ipmiMaxUsers; ++usrIndex) 729 { 730 std::string curName( 731 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 732 ipmiMaxUserName); 733 if (userName == curName) 734 { 735 break; // found the entry 736 } 737 } 738 if (usrIndex > ipmiMaxUsers) 739 { 740 log<level::DEBUG>("User not found", 741 entry("USER_NAME=%s", userName.c_str())); 742 return invalidUserId; 743 } 744 745 return usrIndex; 746 } 747 748 ipmi_ret_t UserAccess::getUserName(const uint8_t& userId, std::string& userName) 749 { 750 if (!isValidUserId(userId)) 751 { 752 return IPMI_CC_PARM_OUT_OF_RANGE; 753 } 754 UserInfo* userInfo = getUserInfo(userId); 755 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0, 756 ipmiMaxUserName); 757 return IPMI_CC_OK; 758 } 759 760 ipmi_ret_t UserAccess::setUserName(const uint8_t& userId, 761 const char* userNameInChar) 762 { 763 if (!isValidUserId(userId)) 764 { 765 return IPMI_CC_PARM_OUT_OF_RANGE; 766 } 767 768 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 769 userLock{*userMutex}; 770 bool validUser = isValidUserName(userNameInChar); 771 std::string oldUser; 772 getUserName(userId, oldUser); 773 UserInfo* userInfo = getUserInfo(userId); 774 775 std::string newUser(userNameInChar, 0, ipmiMaxUserName); 776 if (newUser.empty() && !oldUser.empty()) 777 { 778 // Delete existing user 779 std::string userPath = std::string(userObjBasePath) + "/" + oldUser; 780 try 781 { 782 auto method = bus.new_method_call( 783 getUserServiceName().c_str(), userPath.c_str(), 784 deleteUserInterface, deleteUserMethod); 785 auto reply = bus.call(method); 786 } 787 catch (const sdbusplus::exception::SdBusError& e) 788 { 789 log<level::DEBUG>("Failed to excute method", 790 entry("METHOD=%s", deleteUserMethod), 791 entry("PATH=%s", userPath.c_str())); 792 return IPMI_CC_UNSPECIFIED_ERROR; 793 } 794 std::fill(userInfo->userName, 795 userInfo->userName + sizeof(userInfo->userName), 0); 796 ipmiClearUserEntryPassword(oldUser); 797 userInfo->userInSystem = false; 798 } 799 else if (oldUser.empty() && !newUser.empty() && validUser) 800 { 801 try 802 { 803 // Create new user 804 auto method = bus.new_method_call( 805 getUserServiceName().c_str(), userMgrObjBasePath, 806 userMgrInterface, createUserMethod); 807 // TODO: Fetch proper privilege & enable state once set User access 808 // is implemented if LAN Channel specified, then create user for all 809 // groups follow channel privilege for user creation. 810 method.append(newUser.c_str(), availableGroups, "priv-admin", true); 811 auto reply = bus.call(method); 812 } 813 catch (const sdbusplus::exception::SdBusError& e) 814 { 815 log<level::DEBUG>("Failed to excute method", 816 entry("METHOD=%s", createUserMethod), 817 entry("PATH=%s", userMgrObjBasePath)); 818 return IPMI_CC_UNSPECIFIED_ERROR; 819 } 820 std::strncpy(reinterpret_cast<char*>(userInfo->userName), 821 userNameInChar, ipmiMaxUserName); 822 userInfo->userInSystem = true; 823 } 824 else if (oldUser != newUser && validUser) 825 { 826 try 827 { 828 // User rename 829 auto method = bus.new_method_call( 830 getUserServiceName().c_str(), userMgrObjBasePath, 831 userMgrInterface, renameUserMethod); 832 method.append(oldUser.c_str(), newUser.c_str()); 833 auto reply = bus.call(method); 834 } 835 catch (const sdbusplus::exception::SdBusError& e) 836 { 837 log<level::DEBUG>("Failed to excute method", 838 entry("METHOD=%s", renameUserMethod), 839 entry("PATH=%s", userMgrObjBasePath)); 840 return IPMI_CC_UNSPECIFIED_ERROR; 841 } 842 std::fill(static_cast<uint8_t*>(userInfo->userName), 843 static_cast<uint8_t*>(userInfo->userName) + 844 sizeof(userInfo->userName), 845 0); 846 std::strncpy(reinterpret_cast<char*>(userInfo->userName), 847 userNameInChar, ipmiMaxUserName); 848 ipmiRenameUserEntryPassword(oldUser, newUser); 849 userInfo->userInSystem = true; 850 } 851 else if (!validUser) 852 { 853 return IPMI_CC_INVALID_FIELD_REQUEST; 854 } 855 try 856 { 857 writeUserData(); 858 } 859 catch (const std::exception& e) 860 { 861 log<level::DEBUG>("Write user data failed"); 862 return IPMI_CC_UNSPECIFIED_ERROR; 863 } 864 return IPMI_CC_OK; 865 } 866 867 static constexpr const char* jsonUserName = "user_name"; 868 static constexpr const char* jsonPriv = "privilege"; 869 static constexpr const char* jsonIpmiEnabled = "ipmi_enabled"; 870 static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled"; 871 static constexpr const char* jsonAccCallbk = "access_callback"; 872 static constexpr const char* jsonUserEnabled = "user_enabled"; 873 static constexpr const char* jsonUserInSys = "user_in_system"; 874 static constexpr const char* jsonFixedUser = "fixed_user_name"; 875 876 void UserAccess::readUserData() 877 { 878 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 879 userLock{*userMutex}; 880 881 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary); 882 if (!iUsrData.good()) 883 { 884 log<level::ERR>("Error in reading IPMI user data file"); 885 throw std::ios_base::failure("Error opening IPMI user data file"); 886 } 887 888 Json jsonUsersTbl = Json::array(); 889 jsonUsersTbl = Json::parse(iUsrData, nullptr, false); 890 891 if (jsonUsersTbl.size() != ipmiMaxUsers) 892 { 893 log<level::ERR>( 894 "Error in reading IPMI user data file - User count issues"); 895 throw std::runtime_error( 896 "Corrupted IPMI user data file - invalid user count"); 897 } 898 // user index 0 is reserved, starts with 1 899 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 900 { 901 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0. 902 if (userInfo.is_null()) 903 { 904 log<level::ERR>("Error in reading IPMI user data file - " 905 "user info corrupted"); 906 throw std::runtime_error( 907 "Corrupted IPMI user data file - invalid user info"); 908 } 909 std::string userName = userInfo[jsonUserName].get<std::string>(); 910 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 911 userName.c_str(), ipmiMaxUserName); 912 913 std::vector<std::string> privilege = 914 userInfo[jsonPriv].get<std::vector<std::string>>(); 915 std::vector<bool> ipmiEnabled = 916 userInfo[jsonIpmiEnabled].get<std::vector<bool>>(); 917 std::vector<bool> linkAuthEnabled = 918 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>(); 919 std::vector<bool> accessCallback = 920 userInfo[jsonAccCallbk].get<std::vector<bool>>(); 921 if (privilege.size() != ipmiMaxChannels || 922 ipmiEnabled.size() != ipmiMaxChannels || 923 linkAuthEnabled.size() != ipmiMaxChannels || 924 accessCallback.size() != ipmiMaxChannels) 925 { 926 log<level::ERR>("Error in reading IPMI user data file - " 927 "properties corrupted"); 928 throw std::runtime_error( 929 "Corrupted IPMI user data file - properties"); 930 } 931 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 932 { 933 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege = 934 static_cast<uint8_t>( 935 convertToIPMIPrivilege(privilege[chIndex])); 936 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled = 937 ipmiEnabled[chIndex]; 938 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled = 939 linkAuthEnabled[chIndex]; 940 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback = 941 accessCallback[chIndex]; 942 } 943 usersTbl.user[usrIndex].userEnabled = 944 userInfo[jsonUserEnabled].get<bool>(); 945 usersTbl.user[usrIndex].userInSystem = 946 userInfo[jsonUserInSys].get<bool>(); 947 usersTbl.user[usrIndex].fixedUserName = 948 userInfo[jsonFixedUser].get<bool>(); 949 } 950 951 log<level::DEBUG>("User data read from IPMI data file"); 952 iUsrData.close(); 953 // Update the timestamp 954 fileLastUpdatedTime = getUpdatedFileTime(); 955 return; 956 } 957 958 void UserAccess::writeUserData() 959 { 960 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 961 userLock{*userMutex}; 962 963 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"}; 964 std::ofstream oUsrData(tmpFile, std::ios::out | std::ios::binary); 965 if (!oUsrData.good()) 966 { 967 log<level::ERR>("Error in creating temporary IPMI user data file"); 968 throw std::ios_base::failure( 969 "Error in creating temporary IPMI user data file"); 970 } 971 972 Json jsonUsersTbl = Json::array(); 973 // user index 0 is reserved, starts with 1 974 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 975 { 976 Json jsonUserInfo; 977 jsonUserInfo[jsonUserName] = std::string( 978 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0, 979 ipmiMaxUserName); 980 std::vector<std::string> privilege(ipmiMaxChannels); 981 std::vector<bool> ipmiEnabled(ipmiMaxChannels); 982 std::vector<bool> linkAuthEnabled(ipmiMaxChannels); 983 std::vector<bool> accessCallback(ipmiMaxChannels); 984 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++) 985 { 986 privilege[chIndex] = 987 convertToSystemPrivilege(static_cast<CommandPrivilege>( 988 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege)); 989 ipmiEnabled[chIndex] = 990 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled; 991 linkAuthEnabled[chIndex] = 992 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled; 993 accessCallback[chIndex] = 994 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback; 995 } 996 jsonUserInfo[jsonPriv] = privilege; 997 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled; 998 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled; 999 jsonUserInfo[jsonAccCallbk] = accessCallback; 1000 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled; 1001 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem; 1002 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName; 1003 jsonUsersTbl.push_back(jsonUserInfo); 1004 } 1005 1006 oUsrData << jsonUsersTbl; 1007 oUsrData.flush(); 1008 oUsrData.close(); 1009 1010 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0) 1011 { 1012 log<level::ERR>("Error in renaming temporary IPMI user data file"); 1013 throw std::runtime_error("Error in renaming IPMI user data file"); 1014 } 1015 // Update the timestamp 1016 fileLastUpdatedTime = getUpdatedFileTime(); 1017 return; 1018 } 1019 1020 bool UserAccess::addUserEntry(const std::string& userName, 1021 const std::string& sysPriv, const bool& enabled) 1022 { 1023 UsersTbl* userData = getUsersTblPtr(); 1024 size_t freeIndex = 0xFF; 1025 // user index 0 is reserved, starts with 1 1026 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex) 1027 { 1028 std::string curName( 1029 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0, 1030 ipmiMaxUserName); 1031 if (userName == curName) 1032 { 1033 log<level::DEBUG>("User name exists", 1034 entry("USER_NAME=%s", userName.c_str())); 1035 return false; // user name exists. 1036 } 1037 1038 if ((!userData->user[usrIndex].userInSystem) && 1039 (userData->user[usrIndex].userName[0] == '\0') && 1040 (freeIndex == 0xFF)) 1041 { 1042 freeIndex = usrIndex; 1043 } 1044 } 1045 if (freeIndex == 0xFF) 1046 { 1047 log<level::ERR>("No empty slots found"); 1048 return false; 1049 } 1050 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName), 1051 userName.c_str(), ipmiMaxUserName); 1052 uint8_t priv = 1053 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) & 1054 privMask; 1055 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1056 { 1057 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv; 1058 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true; 1059 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled = 1060 true; 1061 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true; 1062 } 1063 userData->user[freeIndex].userInSystem = true; 1064 userData->user[freeIndex].userEnabled = enabled; 1065 1066 return true; 1067 } 1068 1069 void UserAccess::deleteUserIndex(const size_t& usrIdx) 1070 { 1071 UsersTbl* userData = getUsersTblPtr(); 1072 1073 std::string userName( 1074 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1075 ipmiMaxUserName); 1076 ipmiClearUserEntryPassword(userName); 1077 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName), 1078 static_cast<uint8_t*>(userData->user[usrIdx].userName) + 1079 sizeof(userData->user[usrIdx].userName), 1080 0); 1081 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1082 { 1083 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess; 1084 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false; 1085 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false; 1086 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false; 1087 } 1088 userData->user[usrIdx].userInSystem = false; 1089 userData->user[usrIdx].userEnabled = false; 1090 return; 1091 } 1092 1093 void UserAccess::checkAndReloadUserData() 1094 { 1095 std::time_t updateTime = getUpdatedFileTime(); 1096 if (updateTime != fileLastUpdatedTime || updateTime == -EIO) 1097 { 1098 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1099 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1100 readUserData(); 1101 } 1102 return; 1103 } 1104 1105 UsersTbl* UserAccess::getUsersTblPtr() 1106 { 1107 // reload data before using it. 1108 checkAndReloadUserData(); 1109 return &usersTbl; 1110 } 1111 1112 void UserAccess::getSystemPrivAndGroups() 1113 { 1114 std::map<std::string, PrivAndGroupType> properties; 1115 try 1116 { 1117 auto method = bus.new_method_call( 1118 getUserServiceName().c_str(), userMgrObjBasePath, 1119 dBusPropertiesInterface, getAllPropertiesMethod); 1120 method.append(userMgrInterface); 1121 1122 auto reply = bus.call(method); 1123 reply.read(properties); 1124 } 1125 catch (const sdbusplus::exception::SdBusError& e) 1126 { 1127 log<level::DEBUG>("Failed to excute method", 1128 entry("METHOD=%s", getAllPropertiesMethod), 1129 entry("PATH=%s", userMgrObjBasePath)); 1130 return; 1131 } 1132 for (const auto& t : properties) 1133 { 1134 auto key = t.first; 1135 if (key == allPrivProperty) 1136 { 1137 availablePrivileges = t.second.get<std::vector<std::string>>(); 1138 } 1139 else if (key == allGrpProperty) 1140 { 1141 availableGroups = t.second.get<std::vector<std::string>>(); 1142 } 1143 } 1144 // TODO: Implement Supported Privilege & Groups verification logic 1145 return; 1146 } 1147 1148 std::time_t UserAccess::getUpdatedFileTime() 1149 { 1150 struct stat fileStat; 1151 if (stat(ipmiUserDataFile, &fileStat) != 0) 1152 { 1153 log<level::DEBUG>("Error in getting last updated time stamp"); 1154 return -EIO; 1155 } 1156 return fileStat.st_mtime; 1157 } 1158 1159 void UserAccess::getUserProperties(const DbusUserObjProperties& properties, 1160 std::vector<std::string>& usrGrps, 1161 std::string& usrPriv, bool& usrEnabled) 1162 { 1163 for (const auto& t : properties) 1164 { 1165 std::string key = t.first; 1166 if (key == userPrivProperty) 1167 { 1168 usrPriv = t.second.get<std::string>(); 1169 } 1170 else if (key == userGrpProperty) 1171 { 1172 usrGrps = t.second.get<std::vector<std::string>>(); 1173 } 1174 else if (key == userEnabledProperty) 1175 { 1176 usrEnabled = t.second.get<bool>(); 1177 } 1178 } 1179 return; 1180 } 1181 1182 int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs, 1183 std::vector<std::string>& usrGrps, 1184 std::string& usrPriv, bool& usrEnabled) 1185 { 1186 auto usrObj = userObjs.find(usersInterface); 1187 if (usrObj != userObjs.end()) 1188 { 1189 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled); 1190 return 0; 1191 } 1192 return -EIO; 1193 } 1194 1195 void UserAccess::initUserDataFile() 1196 { 1197 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex> 1198 userLock{*userMutex}; 1199 try 1200 { 1201 readUserData(); 1202 } 1203 catch (const std::ios_base::failure& e) 1204 { // File is empty, create it for the first time 1205 std::fill(reinterpret_cast<uint8_t*>(&usersTbl), 1206 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0); 1207 // user index 0 is reserved, starts with 1 1208 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex) 1209 { 1210 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex) 1211 { 1212 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege = 1213 privNoAccess; 1214 } 1215 } 1216 writeUserData(); 1217 } 1218 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs; 1219 try 1220 { 1221 auto method = bus.new_method_call(getUserServiceName().c_str(), 1222 userMgrObjBasePath, dBusObjManager, 1223 getManagedObjectsMethod); 1224 auto reply = bus.call(method); 1225 reply.read(managedObjs); 1226 } 1227 catch (const sdbusplus::exception::SdBusError& e) 1228 { 1229 log<level::DEBUG>("Failed to excute method", 1230 entry("METHOD=%s", getSubTreeMethod), 1231 entry("PATH=%s", userMgrObjBasePath)); 1232 return; 1233 } 1234 1235 UsersTbl* userData = &usersTbl; 1236 // user index 0 is reserved, starts with 1 1237 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx) 1238 { 1239 if ((userData->user[usrIdx].userInSystem) && 1240 (userData->user[usrIdx].userName[0] != '\0')) 1241 { 1242 std::vector<std::string> usrGrps; 1243 std::string usrPriv; 1244 bool usrEnabled; 1245 1246 std::string userName( 1247 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0, 1248 ipmiMaxUserName); 1249 std::string usersPath = 1250 std::string(userObjBasePath) + "/" + userName; 1251 1252 auto usrObj = managedObjs.find(usersPath); 1253 if (usrObj != managedObjs.end()) 1254 { 1255 // User exist. Lets check and update other fileds 1256 getUserObjProperties(usrObj->second, usrGrps, usrPriv, 1257 usrEnabled); 1258 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) == 1259 usrGrps.end()) 1260 { 1261 // Group "ipmi" is removed so lets remove user in IPMI 1262 deleteUserIndex(usrIdx); 1263 } 1264 else 1265 { 1266 // Group "ipmi" is present so lets update other properties 1267 // in IPMI 1268 uint8_t priv = 1269 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask; 1270 // Update all channels priv, only if it is not equivalent to 1271 // getUsrMgmtSyncIndex() 1272 if (userData->user[usrIdx] 1273 .userPrivAccess[getUsrMgmtSyncIndex()] 1274 .privilege != priv) 1275 { 1276 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; 1277 ++chIndex) 1278 { 1279 userData->user[usrIdx] 1280 .userPrivAccess[chIndex] 1281 .privilege = priv; 1282 } 1283 } 1284 if (userData->user[usrIdx].userEnabled != usrEnabled) 1285 { 1286 userData->user[usrIdx].userEnabled = usrEnabled; 1287 } 1288 } 1289 1290 // We are done with this obj. lets delete from MAP 1291 managedObjs.erase(usrObj); 1292 } 1293 else 1294 { 1295 deleteUserIndex(usrIdx); 1296 } 1297 } 1298 } 1299 1300 // Walk through remnaining managedObj users list 1301 // Add them to ipmi data base 1302 for (const auto& usrObj : managedObjs) 1303 { 1304 std::vector<std::string> usrGrps; 1305 std::string usrPriv, userName; 1306 bool usrEnabled; 1307 std::string usrObjPath = std::string(usrObj.first); 1308 if (getUserNameFromPath(usrObj.first.str, userName) != 0) 1309 { 1310 log<level::ERR>("Error in user object path"); 1311 continue; 1312 } 1313 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled); 1314 // Add 'ipmi' group users 1315 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) != 1316 usrGrps.end()) 1317 { 1318 // CREATE NEW USER 1319 if (true != addUserEntry(userName, usrPriv, usrEnabled)) 1320 { 1321 break; 1322 } 1323 } 1324 } 1325 1326 // All userData slots update done. Lets write the data 1327 writeUserData(); 1328 1329 return; 1330 } 1331 } // namespace ipmi 1332