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