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