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