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