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