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