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