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