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