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