xref: /openbmc/phosphor-host-ipmid/user_channel/user_mgmt.cpp (revision 2b42d7ee5a6f119fae969200a9ee8597b2b67da7)
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::SdBusError& 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::SdBusError& 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::SdBusError& 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::SdBusError& 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_AUTH_ERR;
628     }
629     size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1;
630     char* pass = reinterpret_cast<char*>(malloc(passSize));
631     std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize);
632 
633     *resp = reinterpret_cast<pam_response*>(
634         calloc(numMsg, sizeof(struct pam_response)));
635 
636     for (int i = 0; i < numMsg; ++i)
637     {
638         if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
639         {
640             continue;
641         }
642         resp[i]->resp = pass;
643     }
644     return PAM_SUCCESS;
645 }
646 
647 /** @brief Updating the PAM password
648  *
649  *  @param[in] username - username in string
650  *
651  *  @param[in] password  - new password in string
652  *
653  *  @return status
654  */
655 
656 int pamUpdatePasswd(const char* username, const char* password)
657 {
658     const struct pam_conv localConversation = {pamFunctionConversation,
659                                                const_cast<char*>(password)};
660     pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
661 
662     int retval =
663         pam_start("passwd", username, &localConversation, &localAuthHandle);
664 
665     if (retval != PAM_SUCCESS)
666     {
667         return retval;
668     }
669 
670     retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
671     if (retval != PAM_SUCCESS)
672     {
673         pam_end(localAuthHandle, retval);
674         return retval;
675     }
676 
677     return pam_end(localAuthHandle, PAM_SUCCESS);
678 }
679 
680 bool pamUserCheckAuthenticate(std::string_view username,
681                               std::string_view password)
682 {
683     const struct pam_conv localConversation = {
684         pamFunctionConversation, const_cast<char*>(password.data())};
685 
686     pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
687 
688     if (pam_start("dropbear", username.data(), &localConversation,
689                   &localAuthHandle) != PAM_SUCCESS)
690     {
691         log<level::ERR>("User Authentication Failure");
692         return false;
693     }
694 
695     int retval = pam_authenticate(localAuthHandle,
696                                   PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
697 
698     if (retval != PAM_SUCCESS)
699     {
700         log<level::DEBUG>("pam_authenticate returned failure",
701                           entry("ERROR=%d", retval));
702 
703         pam_end(localAuthHandle, retval);
704         return false;
705     }
706 
707     if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
708         PAM_SUCCESS)
709     {
710         pam_end(localAuthHandle, PAM_SUCCESS);
711         return false;
712     }
713 
714     if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
715     {
716         return false;
717     }
718     return true;
719 }
720 
721 Cc UserAccess::setSpecialUserPassword(const std::string& userName,
722                                       const std::string& userPassword)
723 {
724     if (pamUpdatePasswd(userName.c_str(), userPassword.c_str()) != PAM_SUCCESS)
725     {
726         log<level::DEBUG>("Failed to update password");
727         return ccUnspecifiedError;
728     }
729     return ccSuccess;
730 }
731 
732 Cc UserAccess::setUserPassword(const uint8_t userId, const char* userPassword)
733 {
734     std::string userName;
735     if (ipmiUserGetUserName(userId, userName) != ccSuccess)
736     {
737         log<level::DEBUG>("User Name not found",
738                           entry("USER-ID=%d", (uint8_t)userId));
739         return ccParmOutOfRange;
740     }
741 
742     ipmi::SecureString passwd;
743     passwd.assign(reinterpret_cast<const char*>(userPassword), 0,
744                   maxIpmi20PasswordSize);
745     int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str());
746 
747     switch (retval)
748     {
749         case PAM_SUCCESS:
750         {
751             return ccSuccess;
752         }
753         case PAM_AUTHTOK_ERR:
754         {
755             log<level::DEBUG>("Bad authentication token");
756             return ccInvalidFieldRequest;
757         }
758         default:
759         {
760             log<level::DEBUG>("Failed to update password",
761                               entry("USER-ID=%d", (uint8_t)userId));
762             return ccUnspecifiedError;
763         }
764     }
765 }
766 
767 Cc UserAccess::setUserEnabledState(const uint8_t userId,
768                                    const bool& enabledState)
769 {
770     if (!isValidUserId(userId))
771     {
772         return ccParmOutOfRange;
773     }
774     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
775         userLock{*userMutex};
776     UserInfo* userInfo = getUserInfo(userId);
777     std::string userName;
778     userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
779                     ipmiMaxUserName);
780     if (userName.empty())
781     {
782         log<level::DEBUG>("User name not set / invalid");
783         return ccUnspecifiedError;
784     }
785     if (userInfo->userEnabled != enabledState)
786     {
787         std::string userPath = std::string(userObjBasePath) + "/" + userName;
788         setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
789                         userEnabledProperty, enabledState);
790         userInfo->userEnabled = enabledState;
791         try
792         {
793             writeUserData();
794         }
795         catch (const std::exception& e)
796         {
797             log<level::DEBUG>("Write user data failed");
798             return ccUnspecifiedError;
799         }
800     }
801     return ccSuccess;
802 }
803 
804 Cc UserAccess::setUserPayloadAccess(const uint8_t chNum,
805                                     const uint8_t operation,
806                                     const uint8_t userId,
807                                     const PayloadAccess& payloadAccess)
808 {
809     constexpr uint8_t enable = 0x0;
810     constexpr uint8_t disable = 0x1;
811 
812     if (!isValidChannel(chNum))
813     {
814         return ccInvalidFieldRequest;
815     }
816     if (!isValidUserId(userId))
817     {
818         return ccParmOutOfRange;
819     }
820     if (operation != enable && operation != disable)
821     {
822         return ccInvalidFieldRequest;
823     }
824     // Check operation & payloadAccess if required.
825     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
826         userLock{*userMutex};
827     UserInfo* userInfo = getUserInfo(userId);
828 
829     if (operation == enable)
830     {
831         userInfo->payloadAccess[chNum].stdPayloadEnables1 |=
832             payloadAccess.stdPayloadEnables1;
833 
834         userInfo->payloadAccess[chNum].oemPayloadEnables1 |=
835             payloadAccess.oemPayloadEnables1;
836     }
837     else
838     {
839         userInfo->payloadAccess[chNum].stdPayloadEnables1 &=
840             ~(payloadAccess.stdPayloadEnables1);
841 
842         userInfo->payloadAccess[chNum].oemPayloadEnables1 &=
843             ~(payloadAccess.oemPayloadEnables1);
844     }
845 
846     try
847     {
848         writeUserData();
849     }
850     catch (const std::exception& e)
851     {
852         log<level::ERR>("Write user data failed");
853         return ccUnspecifiedError;
854     }
855     return ccSuccess;
856 }
857 
858 Cc UserAccess::setUserPrivilegeAccess(const uint8_t userId, const uint8_t chNum,
859                                       const UserPrivAccess& privAccess,
860                                       const bool& otherPrivUpdates)
861 {
862     if (!isValidChannel(chNum))
863     {
864         return ccInvalidFieldRequest;
865     }
866     if (!isValidUserId(userId))
867     {
868         return ccParmOutOfRange;
869     }
870     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
871         userLock{*userMutex};
872     UserInfo* userInfo = getUserInfo(userId);
873     std::string userName;
874     userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
875                     ipmiMaxUserName);
876     if (userName.empty())
877     {
878         log<level::DEBUG>("User name not set / invalid");
879         return ccUnspecifiedError;
880     }
881     std::string priv = convertToSystemPrivilege(
882         static_cast<CommandPrivilege>(privAccess.privilege));
883     uint8_t syncIndex = getUsrMgmtSyncIndex();
884     if (chNum == syncIndex &&
885         privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
886     {
887         std::string userPath = std::string(userObjBasePath) + "/" + userName;
888         setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
889                         userPrivProperty, priv);
890     }
891     userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
892 
893     if (otherPrivUpdates)
894     {
895         userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
896         userInfo->userPrivAccess[chNum].linkAuthEnabled =
897             privAccess.linkAuthEnabled;
898         userInfo->userPrivAccess[chNum].accessCallback =
899             privAccess.accessCallback;
900     }
901     try
902     {
903         writeUserData();
904     }
905     catch (const std::exception& e)
906     {
907         log<level::DEBUG>("Write user data failed");
908         return ccUnspecifiedError;
909     }
910     return ccSuccess;
911 }
912 
913 uint8_t UserAccess::getUserId(const std::string& userName)
914 {
915     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
916         userLock{*userMutex};
917     checkAndReloadUserData();
918     // user index 0 is reserved, starts with 1
919     size_t usrIndex = 1;
920     for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
921     {
922         std::string curName(
923             reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
924             ipmiMaxUserName);
925         if (userName == curName)
926         {
927             break; // found the entry
928         }
929     }
930     if (usrIndex > ipmiMaxUsers)
931     {
932         log<level::DEBUG>("User not found",
933                           entry("USER_NAME=%s", userName.c_str()));
934         return invalidUserId;
935     }
936 
937     return usrIndex;
938 }
939 
940 Cc UserAccess::getUserName(const uint8_t userId, std::string& userName)
941 {
942     if (!isValidUserId(userId))
943     {
944         return ccParmOutOfRange;
945     }
946     UserInfo* userInfo = getUserInfo(userId);
947     userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
948                     ipmiMaxUserName);
949     return ccSuccess;
950 }
951 
952 bool UserAccess::isIpmiInAvailableGroupList()
953 {
954     if (std::find(availableGroups.begin(), availableGroups.end(),
955                   ipmiGrpName) != availableGroups.end())
956     {
957         return true;
958     }
959     if (availableGroups.empty())
960     {
961         // available groups shouldn't be empty, re-query
962         getSystemPrivAndGroups();
963         if (std::find(availableGroups.begin(), availableGroups.end(),
964                       ipmiGrpName) != availableGroups.end())
965         {
966             return true;
967         }
968     }
969     return false;
970 }
971 
972 Cc UserAccess::setUserName(const uint8_t userId, const std::string& userName)
973 {
974     if (!isValidUserId(userId))
975     {
976         return ccParmOutOfRange;
977     }
978 
979     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
980         userLock{*userMutex};
981     std::string oldUser;
982     getUserName(userId, oldUser);
983 
984     if (oldUser == userName)
985     {
986         // requesting to set the same user name, return success.
987         return ccSuccess;
988     }
989 
990     bool validUser = isValidUserName(userName);
991     UserInfo* userInfo = getUserInfo(userId);
992     if (userName.empty() && !oldUser.empty())
993     {
994         // Delete existing user
995         std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
996         try
997         {
998             auto method = bus.new_method_call(
999                 getUserServiceName().c_str(), userPath.c_str(),
1000                 deleteUserInterface, deleteUserMethod);
1001             auto reply = bus.call(method);
1002         }
1003         catch (const sdbusplus::exception::SdBusError& e)
1004         {
1005             log<level::DEBUG>("Failed to excute method",
1006                               entry("METHOD=%s", deleteUserMethod),
1007                               entry("PATH=%s", userPath.c_str()));
1008             return ccUnspecifiedError;
1009         }
1010         deleteUserIndex(userId);
1011     }
1012     else if (oldUser.empty() && !userName.empty() && validUser)
1013     {
1014         try
1015         {
1016             if (!isIpmiInAvailableGroupList())
1017             {
1018                 return ccUnspecifiedError;
1019             }
1020             // Create new user
1021             auto method = bus.new_method_call(
1022                 getUserServiceName().c_str(), userMgrObjBasePath,
1023                 userMgrInterface, createUserMethod);
1024             method.append(userName.c_str(), availableGroups, "", false);
1025             auto reply = bus.call(method);
1026         }
1027         catch (const sdbusplus::exception::SdBusError& e)
1028         {
1029             log<level::DEBUG>("Failed to excute method",
1030                               entry("METHOD=%s", createUserMethod),
1031                               entry("PATH=%s", userMgrObjBasePath));
1032             return ccUnspecifiedError;
1033         }
1034 
1035         std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1036         std::memcpy(userInfo->userName,
1037                     static_cast<const void*>(userName.data()), userName.size());
1038         userInfo->userInSystem = true;
1039     }
1040     else if (oldUser != userName && validUser)
1041     {
1042         try
1043         {
1044             // User rename
1045             auto method = bus.new_method_call(
1046                 getUserServiceName().c_str(), userMgrObjBasePath,
1047                 userMgrInterface, renameUserMethod);
1048             method.append(oldUser.c_str(), userName.c_str());
1049             auto reply = bus.call(method);
1050         }
1051         catch (const sdbusplus::exception::SdBusError& e)
1052         {
1053             log<level::DEBUG>("Failed to excute method",
1054                               entry("METHOD=%s", renameUserMethod),
1055                               entry("PATH=%s", userMgrObjBasePath));
1056             return ccUnspecifiedError;
1057         }
1058         std::fill(static_cast<uint8_t*>(userInfo->userName),
1059                   static_cast<uint8_t*>(userInfo->userName) +
1060                       sizeof(userInfo->userName),
1061                   0);
1062 
1063         std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1064         std::memcpy(userInfo->userName,
1065                     static_cast<const void*>(userName.data()), userName.size());
1066 
1067         ipmiRenameUserEntryPassword(oldUser, userName);
1068         userInfo->userInSystem = true;
1069     }
1070     else if (!validUser)
1071     {
1072         return ccInvalidFieldRequest;
1073     }
1074     try
1075     {
1076         writeUserData();
1077     }
1078     catch (const std::exception& e)
1079     {
1080         log<level::DEBUG>("Write user data failed");
1081         return ccUnspecifiedError;
1082     }
1083     return ccSuccess;
1084 }
1085 
1086 static constexpr const char* jsonUserName = "user_name";
1087 static constexpr const char* jsonPriv = "privilege";
1088 static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
1089 static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
1090 static constexpr const char* jsonAccCallbk = "access_callback";
1091 static constexpr const char* jsonUserEnabled = "user_enabled";
1092 static constexpr const char* jsonUserInSys = "user_in_system";
1093 static constexpr const char* jsonFixedUser = "fixed_user_name";
1094 static constexpr const char* payloadEnabledStr = "payload_enabled";
1095 static constexpr const char* stdPayloadStr = "std_payload";
1096 static constexpr const char* oemPayloadStr = "OEM_payload";
1097 
1098 /** @brief to construct a JSON object from the given payload access details.
1099  *
1100  *  @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input)
1101  *  @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input)
1102  *
1103  *  @details Sample output JSON object format :
1104  *  "payload_enabled":{
1105  *  "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1106  *  "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1107  *  "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1108  *  "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1109  *  "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1110  *  "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1111  *  "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1112  *  "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1113  *  "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1114  *  "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1115  *  "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1116  *  "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1117  *  "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1118  *  "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1119  *  "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1120  *  "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1121  *  }
1122  */
1123 static const Json constructJsonPayloadEnables(
1124     const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1125         stdPayload,
1126     const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1127         oemPayload)
1128 {
1129     Json jsonPayloadEnabled;
1130 
1131     for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1132     {
1133         std::ostringstream stdPayloadStream;
1134         std::ostringstream oemPayloadStream;
1135 
1136         stdPayloadStream << stdPayloadStr << payloadNum;
1137         oemPayloadStream << oemPayloadStr << payloadNum;
1138 
1139         jsonPayloadEnabled.push_back(Json::object_t::value_type(
1140             stdPayloadStream.str(), stdPayload[payloadNum]));
1141 
1142         jsonPayloadEnabled.push_back(Json::object_t::value_type(
1143             oemPayloadStream.str(), oemPayload[payloadNum]));
1144     }
1145     return jsonPayloadEnabled;
1146 }
1147 
1148 void UserAccess::readPayloadAccessFromUserInfo(
1149     const UserInfo& userInfo,
1150     std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload,
1151     std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload)
1152 {
1153     for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1154     {
1155         for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1156         {
1157             stdPayload[payloadNum][chIndex] =
1158                 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum];
1159 
1160             oemPayload[payloadNum][chIndex] =
1161                 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum];
1162         }
1163     }
1164 }
1165 
1166 void UserAccess::updatePayloadAccessInUserInfo(
1167     const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1168         stdPayload,
1169     const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1170         oemPayload,
1171     UserInfo& userInfo)
1172 {
1173     for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1174     {
1175         // Ensure that reserved/unsupported payloads are marked to zero.
1176         userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset();
1177         userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset();
1178         userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset();
1179         userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset();
1180         // Update SOL status as it is the only supported payload currently.
1181         userInfo.payloadAccess[chIndex]
1182             .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] =
1183             stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex];
1184     }
1185 }
1186 
1187 void UserAccess::readUserData()
1188 {
1189     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1190         userLock{*userMutex};
1191 
1192     std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
1193     if (!iUsrData.good())
1194     {
1195         log<level::ERR>("Error in reading IPMI user data file");
1196         throw std::ios_base::failure("Error opening IPMI user data file");
1197     }
1198 
1199     Json jsonUsersTbl = Json::array();
1200     jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
1201 
1202     if (jsonUsersTbl.size() != ipmiMaxUsers)
1203     {
1204         log<level::ERR>(
1205             "Error in reading IPMI user data file - User count issues");
1206         throw std::runtime_error(
1207             "Corrupted IPMI user data file - invalid user count");
1208     }
1209 
1210     // user index 0 is reserved, starts with 1
1211     for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1212     {
1213         Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
1214         if (userInfo.is_null())
1215         {
1216             log<level::ERR>("Error in reading IPMI user data file - "
1217                             "user info corrupted");
1218             throw std::runtime_error(
1219                 "Corrupted IPMI user data file - invalid user info");
1220         }
1221         std::string userName = userInfo[jsonUserName].get<std::string>();
1222         std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
1223                      userName.c_str(), ipmiMaxUserName);
1224 
1225         std::vector<std::string> privilege =
1226             userInfo[jsonPriv].get<std::vector<std::string>>();
1227         std::vector<bool> ipmiEnabled =
1228             userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
1229         std::vector<bool> linkAuthEnabled =
1230             userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
1231         std::vector<bool> accessCallback =
1232             userInfo[jsonAccCallbk].get<std::vector<bool>>();
1233 
1234         // Payload Enables Processing.
1235         std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1236             stdPayload = {};
1237         std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1238             oemPayload = {};
1239         try
1240         {
1241             const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr);
1242             for (auto payloadNum = 0; payloadNum < payloadsPerByte;
1243                  payloadNum++)
1244             {
1245                 std::ostringstream stdPayloadStream;
1246                 std::ostringstream oemPayloadStream;
1247 
1248                 stdPayloadStream << stdPayloadStr << payloadNum;
1249                 oemPayloadStream << oemPayloadStr << payloadNum;
1250 
1251                 stdPayload[payloadNum] =
1252                     jsonPayloadEnabled[stdPayloadStream.str()]
1253                         .get<std::array<bool, ipmiMaxChannels>>();
1254                 oemPayload[payloadNum] =
1255                     jsonPayloadEnabled[oemPayloadStream.str()]
1256                         .get<std::array<bool, ipmiMaxChannels>>();
1257 
1258                 if (stdPayload[payloadNum].size() != ipmiMaxChannels ||
1259                     oemPayload[payloadNum].size() != ipmiMaxChannels)
1260                 {
1261                     log<level::ERR>("Error in reading IPMI user data file - "
1262                                     "payload properties corrupted");
1263                     throw std::runtime_error(
1264                         "Corrupted IPMI user data file - payload properties");
1265                 }
1266             }
1267         }
1268         catch (Json::out_of_range& e)
1269         {
1270             // Key not found in 'userInfo'; possibly an old JSON file. Use
1271             // default values for all payloads, and SOL payload default is true.
1272             stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true);
1273         }
1274 
1275         if (privilege.size() != ipmiMaxChannels ||
1276             ipmiEnabled.size() != ipmiMaxChannels ||
1277             linkAuthEnabled.size() != ipmiMaxChannels ||
1278             accessCallback.size() != ipmiMaxChannels)
1279         {
1280             log<level::ERR>("Error in reading IPMI user data file - "
1281                             "properties corrupted");
1282             throw std::runtime_error(
1283                 "Corrupted IPMI user data file - properties");
1284         }
1285         for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1286         {
1287             usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
1288                 static_cast<uint8_t>(
1289                     convertToIPMIPrivilege(privilege[chIndex]));
1290             usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
1291                 ipmiEnabled[chIndex];
1292             usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
1293                 linkAuthEnabled[chIndex];
1294             usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
1295                 accessCallback[chIndex];
1296         }
1297         updatePayloadAccessInUserInfo(stdPayload, oemPayload,
1298                                       usersTbl.user[usrIndex]);
1299         usersTbl.user[usrIndex].userEnabled =
1300             userInfo[jsonUserEnabled].get<bool>();
1301         usersTbl.user[usrIndex].userInSystem =
1302             userInfo[jsonUserInSys].get<bool>();
1303         usersTbl.user[usrIndex].fixedUserName =
1304             userInfo[jsonFixedUser].get<bool>();
1305     }
1306 
1307     log<level::DEBUG>("User data read from IPMI data file");
1308     iUsrData.close();
1309     // Update the timestamp
1310     fileLastUpdatedTime = getUpdatedFileTime();
1311     return;
1312 }
1313 
1314 void UserAccess::writeUserData()
1315 {
1316     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1317         userLock{*userMutex};
1318 
1319     Json jsonUsersTbl = Json::array();
1320     // user index 0 is reserved, starts with 1
1321     for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1322     {
1323         Json jsonUserInfo;
1324         jsonUserInfo[jsonUserName] = std::string(
1325             reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
1326             ipmiMaxUserName);
1327         std::vector<std::string> privilege(ipmiMaxChannels);
1328         std::vector<bool> ipmiEnabled(ipmiMaxChannels);
1329         std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
1330         std::vector<bool> accessCallback(ipmiMaxChannels);
1331 
1332         std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1333             stdPayload;
1334         std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1335             oemPayload;
1336 
1337         for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1338         {
1339             privilege[chIndex] =
1340                 convertToSystemPrivilege(static_cast<CommandPrivilege>(
1341                     usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
1342             ipmiEnabled[chIndex] =
1343                 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
1344             linkAuthEnabled[chIndex] =
1345                 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
1346             accessCallback[chIndex] =
1347                 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
1348         }
1349         jsonUserInfo[jsonPriv] = privilege;
1350         jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
1351         jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
1352         jsonUserInfo[jsonAccCallbk] = accessCallback;
1353         jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1354         jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1355         jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
1356 
1357         readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload,
1358                                       oemPayload);
1359         Json jsonPayloadEnabledInfo =
1360             constructJsonPayloadEnables(stdPayload, oemPayload);
1361         jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo;
1362 
1363         jsonUsersTbl.push_back(jsonUserInfo);
1364     }
1365 
1366     static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
1367     int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
1368                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1369     if (fd < 0)
1370     {
1371         log<level::ERR>("Error in creating temporary IPMI user data file");
1372         throw std::ios_base::failure(
1373             "Error in creating temporary IPMI user data file");
1374     }
1375     const auto& writeStr = jsonUsersTbl.dump();
1376     if (write(fd, writeStr.c_str(), writeStr.size()) !=
1377         static_cast<ssize_t>(writeStr.size()))
1378     {
1379         close(fd);
1380         log<level::ERR>("Error in writing temporary IPMI user data file");
1381         throw std::ios_base::failure(
1382             "Error in writing temporary IPMI user data file");
1383     }
1384     close(fd);
1385 
1386     if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1387     {
1388         log<level::ERR>("Error in renaming temporary IPMI user data file");
1389         throw std::runtime_error("Error in renaming IPMI user data file");
1390     }
1391     // Update the timestamp
1392     fileLastUpdatedTime = getUpdatedFileTime();
1393     return;
1394 }
1395 
1396 bool UserAccess::addUserEntry(const std::string& userName,
1397                               const std::string& sysPriv, const bool& enabled)
1398 {
1399     UsersTbl* userData = getUsersTblPtr();
1400     size_t freeIndex = 0xFF;
1401     // user index 0 is reserved, starts with 1
1402     for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1403     {
1404         std::string curName(
1405             reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1406             ipmiMaxUserName);
1407         if (userName == curName)
1408         {
1409             log<level::DEBUG>("User name exists",
1410                               entry("USER_NAME=%s", userName.c_str()));
1411             return false; // user name exists.
1412         }
1413 
1414         if ((!userData->user[usrIndex].userInSystem) &&
1415             (userData->user[usrIndex].userName[0] == '\0') &&
1416             (freeIndex == 0xFF))
1417         {
1418             freeIndex = usrIndex;
1419         }
1420     }
1421     if (freeIndex == 0xFF)
1422     {
1423         log<level::ERR>("No empty slots found");
1424         return false;
1425     }
1426     std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1427                  userName.c_str(), ipmiMaxUserName);
1428     uint8_t priv =
1429         static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1430         privMask;
1431     for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1432     {
1433         userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1434         userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1435         userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1436             true;
1437         userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1438     }
1439     userData->user[freeIndex].userInSystem = true;
1440     userData->user[freeIndex].userEnabled = enabled;
1441 
1442     return true;
1443 }
1444 
1445 void UserAccess::deleteUserIndex(const size_t& usrIdx)
1446 {
1447     UsersTbl* userData = getUsersTblPtr();
1448 
1449     std::string userName(
1450         reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1451         ipmiMaxUserName);
1452     ipmiClearUserEntryPassword(userName);
1453     std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1454               static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1455                   sizeof(userData->user[usrIdx].userName),
1456               0);
1457     for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1458     {
1459         userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1460         userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1461         userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1462         userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1463     }
1464     userData->user[usrIdx].userInSystem = false;
1465     userData->user[usrIdx].userEnabled = false;
1466     return;
1467 }
1468 
1469 void UserAccess::checkAndReloadUserData()
1470 {
1471     std::time_t updateTime = getUpdatedFileTime();
1472     if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1473     {
1474         std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1475                   reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1476         readUserData();
1477     }
1478     return;
1479 }
1480 
1481 UsersTbl* UserAccess::getUsersTblPtr()
1482 {
1483     // reload data before using it.
1484     checkAndReloadUserData();
1485     return &usersTbl;
1486 }
1487 
1488 void UserAccess::getSystemPrivAndGroups()
1489 {
1490     std::map<std::string, PrivAndGroupType> properties;
1491     try
1492     {
1493         auto method = bus.new_method_call(
1494             getUserServiceName().c_str(), userMgrObjBasePath,
1495             dBusPropertiesInterface, getAllPropertiesMethod);
1496         method.append(userMgrInterface);
1497 
1498         auto reply = bus.call(method);
1499         reply.read(properties);
1500     }
1501     catch (const sdbusplus::exception::SdBusError& e)
1502     {
1503         log<level::DEBUG>("Failed to excute method",
1504                           entry("METHOD=%s", getAllPropertiesMethod),
1505                           entry("PATH=%s", userMgrObjBasePath));
1506         return;
1507     }
1508     for (const auto& t : properties)
1509     {
1510         auto key = t.first;
1511         if (key == allPrivProperty)
1512         {
1513             availablePrivileges = std::get<std::vector<std::string>>(t.second);
1514         }
1515         else if (key == allGrpProperty)
1516         {
1517             availableGroups = std::get<std::vector<std::string>>(t.second);
1518         }
1519     }
1520     // TODO: Implement Supported Privilege & Groups verification logic
1521     return;
1522 }
1523 
1524 std::time_t UserAccess::getUpdatedFileTime()
1525 {
1526     struct stat fileStat;
1527     if (stat(ipmiUserDataFile, &fileStat) != 0)
1528     {
1529         log<level::DEBUG>("Error in getting last updated time stamp");
1530         return -EIO;
1531     }
1532     return fileStat.st_mtime;
1533 }
1534 
1535 void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1536                                    std::vector<std::string>& usrGrps,
1537                                    std::string& usrPriv, bool& usrEnabled)
1538 {
1539     for (const auto& t : properties)
1540     {
1541         std::string key = t.first;
1542         if (key == userPrivProperty)
1543         {
1544             usrPriv = std::get<std::string>(t.second);
1545         }
1546         else if (key == userGrpProperty)
1547         {
1548             usrGrps = std::get<std::vector<std::string>>(t.second);
1549         }
1550         else if (key == userEnabledProperty)
1551         {
1552             usrEnabled = std::get<bool>(t.second);
1553         }
1554     }
1555     return;
1556 }
1557 
1558 int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1559                                      std::vector<std::string>& usrGrps,
1560                                      std::string& usrPriv, bool& usrEnabled)
1561 {
1562     auto usrObj = userObjs.find(usersInterface);
1563     if (usrObj != userObjs.end())
1564     {
1565         getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1566         return 0;
1567     }
1568     return -EIO;
1569 }
1570 
1571 void UserAccess::cacheUserDataFile()
1572 {
1573     boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1574         userLock{*userMutex};
1575     try
1576     {
1577         readUserData();
1578     }
1579     catch (const std::ios_base::failure& e)
1580     { // File is empty, create it for the first time
1581         std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1582                   reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1583         // user index 0 is reserved, starts with 1
1584         for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1585         {
1586             for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1587             {
1588                 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1589                     privNoAccess;
1590                 usersTbl.user[userIndex]
1591                     .payloadAccess[chIndex]
1592                     .stdPayloadEnables1[static_cast<uint8_t>(
1593                         ipmi::PayloadType::SOL)] = true;
1594             }
1595         }
1596         writeUserData();
1597     }
1598     sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
1599     // Register it for single object and single process either netipimd /
1600     // host-ipmid
1601     if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
1602     {
1603         log<level::DEBUG>("Registering signal handler");
1604         userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
1605             bus,
1606             sdbusplus::bus::match::rules::type::signal() +
1607                 sdbusplus::bus::match::rules::interface(dBusObjManager) +
1608                 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1609             [&](sdbusplus::message::message& msg) {
1610                 userUpdatedSignalHandler(*this, msg);
1611             });
1612         userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
1613             bus,
1614             sdbusplus::bus::match::rules::type::signal() +
1615                 sdbusplus::bus::match::rules::interface(userMgrInterface) +
1616                 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1617             [&](sdbusplus::message::message& msg) {
1618                 userUpdatedSignalHandler(*this, msg);
1619             });
1620         userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
1621             bus,
1622             sdbusplus::bus::match::rules::type::signal() +
1623                 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
1624                 sdbusplus::bus::match::rules::interface(
1625                     dBusPropertiesInterface) +
1626                 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
1627                 sdbusplus::bus::match::rules::argN(0, usersInterface),
1628             [&](sdbusplus::message::message& msg) {
1629                 userUpdatedSignalHandler(*this, msg);
1630             });
1631         signalHndlrObject = true;
1632     }
1633     std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1634     try
1635     {
1636         auto method = bus.new_method_call(getUserServiceName().c_str(),
1637                                           userMgrObjBasePath, dBusObjManager,
1638                                           getManagedObjectsMethod);
1639         auto reply = bus.call(method);
1640         reply.read(managedObjs);
1641     }
1642     catch (const sdbusplus::exception::SdBusError& e)
1643     {
1644         log<level::DEBUG>("Failed to excute method",
1645                           entry("METHOD=%s", getSubTreeMethod),
1646                           entry("PATH=%s", userMgrObjBasePath));
1647         return;
1648     }
1649     bool updateRequired = false;
1650     UsersTbl* userData = &usersTbl;
1651     // user index 0 is reserved, starts with 1
1652     for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1653     {
1654         if ((userData->user[usrIdx].userInSystem) &&
1655             (userData->user[usrIdx].userName[0] != '\0'))
1656         {
1657             std::vector<std::string> usrGrps;
1658             std::string usrPriv;
1659 
1660             std::string userName(
1661                 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1662                 ipmiMaxUserName);
1663             std::string usersPath =
1664                 std::string(userObjBasePath) + "/" + userName;
1665 
1666             auto usrObj = managedObjs.find(usersPath);
1667             if (usrObj != managedObjs.end())
1668             {
1669                 bool usrEnabled = false;
1670 
1671                 // User exist. Lets check and update other fileds
1672                 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1673                                      usrEnabled);
1674                 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1675                     usrGrps.end())
1676                 {
1677                     updateRequired = true;
1678                     // Group "ipmi" is removed so lets remove user in IPMI
1679                     deleteUserIndex(usrIdx);
1680                 }
1681                 else
1682                 {
1683                     // Group "ipmi" is present so lets update other properties
1684                     // in IPMI
1685                     uint8_t priv =
1686                         UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1687                     // Update all channels priv, only if it is not equivalent to
1688                     // getUsrMgmtSyncIndex()
1689                     if (userData->user[usrIdx]
1690                             .userPrivAccess[getUsrMgmtSyncIndex()]
1691                             .privilege != priv)
1692                     {
1693                         updateRequired = true;
1694                         for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1695                              ++chIndex)
1696                         {
1697                             userData->user[usrIdx]
1698                                 .userPrivAccess[chIndex]
1699                                 .privilege = priv;
1700                         }
1701                     }
1702                     if (userData->user[usrIdx].userEnabled != usrEnabled)
1703                     {
1704                         updateRequired = true;
1705                         userData->user[usrIdx].userEnabled = usrEnabled;
1706                     }
1707                 }
1708 
1709                 // We are done with this obj. lets delete from MAP
1710                 managedObjs.erase(usrObj);
1711             }
1712             else
1713             {
1714                 updateRequired = true;
1715                 deleteUserIndex(usrIdx);
1716             }
1717         }
1718     }
1719 
1720     // Walk through remnaining managedObj users list
1721     // Add them to ipmi data base
1722     for (const auto& usrObj : managedObjs)
1723     {
1724         std::vector<std::string> usrGrps;
1725         std::string usrPriv, userName;
1726         bool usrEnabled = false;
1727         std::string usrObjPath = std::string(usrObj.first);
1728         if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1729         {
1730             log<level::ERR>("Error in user object path");
1731             continue;
1732         }
1733         getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1734         // Add 'ipmi' group users
1735         if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1736             usrGrps.end())
1737         {
1738             updateRequired = true;
1739             // CREATE NEW USER
1740             if (true != addUserEntry(userName, usrPriv, usrEnabled))
1741             {
1742                 break;
1743             }
1744         }
1745     }
1746 
1747     if (updateRequired)
1748     {
1749         // All userData slots update done. Lets write the data
1750         writeUserData();
1751     }
1752 
1753     return;
1754 }
1755 } // namespace ipmi
1756