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