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