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