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