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