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