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