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