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