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