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