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