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