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