blob: e90bff690668b502a502ade1d4aed70792a9d7a8 [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"
19
20#include <sys/stat.h>
21#include <unistd.h>
22
23#include <boost/interprocess/sync/named_recursive_mutex.hpp>
24#include <boost/interprocess/sync/scoped_lock.hpp>
25#include <cerrno>
26#include <fstream>
27#include <host-ipmid/ipmid-host-cmd.hpp>
28#include <nlohmann/json.hpp>
29#include <phosphor-logging/elog-errors.hpp>
30#include <phosphor-logging/log.hpp>
31#include <regex>
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
37namespace ipmi
38{
39
40// TODO: Move D-Bus & Object Manager related stuff, to common files
41// D-Bus property related
42static constexpr const char* dBusPropertiesInterface =
43 "org.freedesktop.DBus.Properties";
44static constexpr const char* getAllPropertiesMethod = "GetAll";
45static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
46static constexpr const char* setPropertiesMethod = "Set";
47
48// Object Manager related
49static constexpr const char* dBusObjManager =
50 "org.freedesktop.DBus.ObjectManager";
51static constexpr const char* getManagedObjectsMethod = "GetManagedObjects";
52// Object Manager signals
53static constexpr const char* intfAddedSignal = "InterfacesAdded";
54static constexpr const char* intfRemovedSignal = "InterfacesRemoved";
55
56// Object Mapper related
57static constexpr const char* objMapperService =
58 "xyz.openbmc_project.ObjectMapper";
59static constexpr const char* objMapperPath =
60 "/xyz/openbmc_project/object_mapper";
61static constexpr const char* objMapperInterface =
62 "xyz.openbmc_project.ObjectMapper";
63static constexpr const char* getSubTreeMethod = "GetSubTree";
64static constexpr const char* getObjectMethod = "GetObject";
65
66static constexpr const char* ipmiUserMutex = "ipmi_usr_mutex";
67static constexpr const char* ipmiMutexCleanupLockFile =
68 "/var/lib/ipmi/ipmi_usr_mutex_cleanup";
69static constexpr const char* ipmiUserDataFile = "/var/lib/ipmi/ipmi_user.json";
70static constexpr const char* ipmiGrpName = "ipmi";
71static constexpr size_t privNoAccess = 0xF;
72static constexpr size_t privMask = 0xF;
73
74// User manager related
75static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user";
76static constexpr const char* userObjBasePath = "/xyz/openbmc_project/user";
77static constexpr const char* userMgrInterface =
78 "xyz.openbmc_project.User.Manager";
79static constexpr const char* usersInterface =
80 "xyz.openbmc_project.User.Attributes";
81static constexpr const char* deleteUserInterface =
82 "xyz.openbmc_project.Object.Delete";
83
84static constexpr const char* createUserMethod = "CreateUser";
85static constexpr const char* deleteUserMethod = "Delete";
86static constexpr const char* renameUserMethod = "RenameUser";
87// User manager signal memebers
88static constexpr const char* userRenamedSignal = "UserRenamed";
89// Mgr interface properties
90static constexpr const char* allPrivProperty = "AllPrivileges";
91static constexpr const char* allGrpProperty = "AllGroups";
92// User interface properties
93static constexpr const char* userPrivProperty = "UserPrivilege";
94static constexpr const char* userGrpProperty = "UserGroups";
95static constexpr const char* userEnabledProperty = "UserEnabled";
96
97static std::array<std::string, (PRIVILEGE_OEM + 1)> ipmiPrivIndex = {
98 "priv-reserved", // PRIVILEGE_RESERVED - 0
99 "priv-callback", // PRIVILEGE_CALLBACK - 1
100 "priv-user", // PRIVILEGE_USER - 2
101 "priv-operator", // PRIVILEGE_OPERATOR - 3
102 "priv-admin", // PRIVILEGE_ADMIN - 4
103 "priv-custom" // PRIVILEGE_OEM - 5
104};
105
106using namespace phosphor::logging;
107using Json = nlohmann::json;
108
109using PrivAndGroupType =
110 sdbusplus::message::variant<std::string, std::vector<std::string>>;
111
112using NoResource =
113 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource;
114
115using InternalFailure =
116 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
117
118std::unique_ptr<sdbusplus::bus::match_t> userUpdatedSignal(nullptr);
119std::unique_ptr<sdbusplus::bus::match_t> userMgrRenamedSignal(nullptr);
120std::unique_ptr<sdbusplus::bus::match_t> userPropertiesSignal(nullptr);
121
122// TODO: Below code can be removed once it is moved to common layer libmiscutil
123std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf,
124 const std::string& path)
125{
126 auto mapperCall = bus.new_method_call(objMapperService, objMapperPath,
127 objMapperInterface, getObjectMethod);
128
129 mapperCall.append(path);
130 mapperCall.append(std::vector<std::string>({intf}));
131
132 auto mapperResponseMsg = bus.call(mapperCall);
133
134 std::map<std::string, std::vector<std::string>> mapperResponse;
135 mapperResponseMsg.read(mapperResponse);
136
137 if (mapperResponse.begin() == mapperResponse.end())
138 {
139 throw sdbusplus::exception::SdBusError(
140 -EIO, "ERROR in reading the mapper response");
141 }
142
143 return mapperResponse.begin()->first;
144}
145
146void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service,
147 const std::string& objPath, const std::string& interface,
148 const std::string& property,
149 const DbusUserPropVariant& value)
150{
151 try
152 {
153 auto method =
154 bus.new_method_call(service.c_str(), objPath.c_str(),
155 dBusPropertiesInterface, setPropertiesMethod);
156 method.append(interface, property, value);
157 bus.call(method);
158 }
159 catch (const sdbusplus::exception::SdBusError& e)
160 {
161 log<level::ERR>("Failed to set property",
162 entry("PROPERTY=%s", property.c_str()),
163 entry("PATH=%s", objPath.c_str()),
164 entry("INTERFACE=%s", interface.c_str()));
165 throw;
166 }
167}
168
169static std::string getUserServiceName()
170{
171 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
172 static std::string userMgmtService;
173 if (userMgmtService.empty())
174 {
175 try
176 {
177 userMgmtService =
178 ipmi::getUserService(bus, userMgrInterface, userMgrObjBasePath);
179 }
180 catch (const sdbusplus::exception::SdBusError& e)
181 {
182 userMgmtService.clear();
183 }
184 }
185 return userMgmtService;
186}
187
188UserAccess& getUserAccessObject()
189{
190 static UserAccess userAccess;
191 return userAccess;
192}
193
194int getUserNameFromPath(const std::string& path, std::string& userName)
195{
196 static size_t pos = strlen(userObjBasePath) + 1;
197 if (path.find(userObjBasePath) == std::string::npos)
198 {
199 return -EINVAL;
200 }
201 userName.assign(path, pos, path.size());
202 return 0;
203}
204
205void userUpdateHelper(UserAccess& usrAccess, const UserUpdateEvent& userEvent,
206 const std::string& userName, const std::string& priv,
207 const bool& enabled, const std::string& newUserName)
208{
209 UsersTbl* userData = usrAccess.getUsersTblPtr();
210 if (userEvent == UserUpdateEvent::userCreated)
211 {
212 if (usrAccess.addUserEntry(userName, priv, enabled) == false)
213 {
214 return;
215 }
216 }
217 else
218 {
219 // user index 0 is reserved, starts with 1
220 size_t usrIndex = 1;
221 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
222 {
223 std::string curName(
224 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
225 ipmiMaxUserName);
226 if (userName == curName)
227 {
228 break; // found the entry
229 }
230 }
231 if (usrIndex > ipmiMaxUsers)
232 {
233 log<level::DEBUG>("User not found for signal",
234 entry("USER_NAME=%s", userName.c_str()),
235 entry("USER_EVENT=%d", userEvent));
236 return;
237 }
238 switch (userEvent)
239 {
240 case UserUpdateEvent::userDeleted:
241 {
242 usrAccess.deleteUserIndex(usrIndex);
243 break;
244 }
245 case UserUpdateEvent::userPrivUpdated:
246 {
247 uint8_t userPriv =
248 static_cast<uint8_t>(
249 UserAccess::convertToIPMIPrivilege(priv)) &
250 privMask;
251 // Update all channels privileges, only if it is not equivalent
252 // to getUsrMgmtSyncIndex()
253 if (userData->user[usrIndex]
254 .userPrivAccess[UserAccess::getUsrMgmtSyncIndex()]
255 .privilege != userPriv)
256 {
257 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
258 ++chIndex)
259 {
260 userData->user[usrIndex]
261 .userPrivAccess[chIndex]
262 .privilege = userPriv;
263 }
264 }
265 break;
266 }
267 case UserUpdateEvent::userRenamed:
268 {
269 std::fill(
270 static_cast<uint8_t*>(userData->user[usrIndex].userName),
271 static_cast<uint8_t*>(userData->user[usrIndex].userName) +
272 sizeof(userData->user[usrIndex].userName),
273 0);
274 std::strncpy(
275 reinterpret_cast<char*>(userData->user[usrIndex].userName),
276 newUserName.c_str(), ipmiMaxUserName);
277 ipmiRenameUserEntryPassword(userName, newUserName);
278 break;
279 }
280 case UserUpdateEvent::userStateUpdated:
281 {
282 userData->user[usrIndex].userEnabled = enabled;
283 break;
284 }
285 default:
286 {
287 log<level::ERR>("Unhandled user event",
288 entry("USER_EVENT=%d", userEvent));
289 return;
290 }
291 }
292 }
293 usrAccess.writeUserData();
294 log<level::DEBUG>("User event handled successfully",
295 entry("USER_NAME=%s", userName.c_str()),
296 entry("USER_EVENT=%d", userEvent));
297
298 return;
299}
300
301void userUpdatedSignalHandler(UserAccess& usrAccess,
302 sdbusplus::message::message& msg)
303{
304 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
305 std::string signal = msg.get_member();
306 std::string userName, update, priv, newUserName;
307 std::vector<std::string> groups;
308 bool enabled = false;
309 UserUpdateEvent userEvent = UserUpdateEvent::reservedEvent;
310 if (signal == intfAddedSignal)
311 {
312 DbusUserObjPath objPath;
313 DbusUserObjValue objValue;
314 msg.read(objPath, objValue);
315 getUserNameFromPath(objPath.str, userName);
316 if (usrAccess.getUserObjProperties(objValue, groups, priv, enabled) !=
317 0)
318 {
319 return;
320 }
321 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
322 groups.end())
323 {
324 return;
325 }
326 userEvent = UserUpdateEvent::userCreated;
327 }
328 else if (signal == intfRemovedSignal)
329 {
330 DbusUserObjPath objPath;
331 std::vector<std::string> interfaces;
332 msg.read(objPath, interfaces);
333 getUserNameFromPath(objPath.str, userName);
334 userEvent = UserUpdateEvent::userDeleted;
335 }
336 else if (signal == userRenamedSignal)
337 {
338 msg.read(userName, newUserName);
339 userEvent = UserUpdateEvent::userRenamed;
340 }
341 else if (signal == propertiesChangedSignal)
342 {
343 getUserNameFromPath(msg.get_path(), userName);
344 }
345 else
346 {
347 log<level::ERR>("Unknown user update signal",
348 entry("SIGNAL=%s", signal.c_str()));
349 return;
350 }
351
352 if (signal.empty() || userName.empty() ||
353 (signal == userRenamedSignal && newUserName.empty()))
354 {
355 log<level::ERR>("Invalid inputs received");
356 return;
357 }
358
359 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
360 userLock{*(usrAccess.userMutex)};
361 usrAccess.checkAndReloadUserData();
362
363 if (signal == propertiesChangedSignal)
364 {
365 std::string intfName;
366 DbusUserObjProperties chProperties;
367 msg.read(intfName, chProperties); // skip reading 3rd argument.
368 for (const auto& prop : chProperties)
369 {
370 userEvent = UserUpdateEvent::reservedEvent;
371 std::string member = prop.first;
372 if (member == userPrivProperty)
373 {
374 priv = prop.second.get<std::string>();
375 userEvent = UserUpdateEvent::userPrivUpdated;
376 }
377 else if (member == userGrpProperty)
378 {
379 groups = prop.second.get<std::vector<std::string>>();
380 userEvent = UserUpdateEvent::userGrpUpdated;
381 }
382 else if (member == userEnabledProperty)
383 {
384 enabled = prop.second.get<bool>();
385 userEvent = UserUpdateEvent::userStateUpdated;
386 }
387 // Process based on event type.
388 if (userEvent == UserUpdateEvent::userGrpUpdated)
389 {
390 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
391 groups.end())
392 {
393 // remove user from ipmi user list.
394 userUpdateHelper(usrAccess, UserUpdateEvent::userDeleted,
395 userName, priv, enabled, newUserName);
396 }
397 else
398 {
399 DbusUserObjProperties properties;
400 try
401 {
402 auto method = bus.new_method_call(
403 getUserServiceName().c_str(), msg.get_path(),
404 dBusPropertiesInterface, getAllPropertiesMethod);
405 method.append(usersInterface);
406 auto reply = bus.call(method);
407 reply.read(properties);
408 }
409 catch (const sdbusplus::exception::SdBusError& e)
410 {
411 log<level::DEBUG>(
412 "Failed to excute method",
413 entry("METHOD=%s", getAllPropertiesMethod),
414 entry("PATH=%s", msg.get_path()));
415 return;
416 }
417 usrAccess.getUserProperties(properties, groups, priv,
418 enabled);
419 // add user to ipmi user list.
420 userUpdateHelper(usrAccess, UserUpdateEvent::userCreated,
421 userName, priv, enabled, newUserName);
422 }
423 }
424 else if (userEvent != UserUpdateEvent::reservedEvent)
425 {
426 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
427 newUserName);
428 }
429 }
430 }
431 else if (userEvent != UserUpdateEvent::reservedEvent)
432 {
433 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
434 newUserName);
435 }
436 return;
437}
438
439UserAccess::~UserAccess()
440{
441 if (signalHndlrObject)
442 {
443 userUpdatedSignal.reset();
444 userMgrRenamedSignal.reset();
445 userPropertiesSignal.reset();
446 sigHndlrLock.unlock();
447 }
448}
449
450UserAccess::UserAccess() : bus(ipmid_get_sd_bus_connection())
451{
452 std::ofstream mutexCleanUpFile;
453 mutexCleanUpFile.open(ipmiMutexCleanupLockFile,
454 std::ofstream::out | std::ofstream::app);
455 if (!mutexCleanUpFile.good())
456 {
457 log<level::DEBUG>("Unable to open mutex cleanup file");
458 return;
459 }
460 mutexCleanUpFile.close();
461 mutexCleanupLock = boost::interprocess::file_lock(ipmiMutexCleanupLockFile);
462 if (mutexCleanupLock.try_lock())
463 {
464 boost::interprocess::named_recursive_mutex::remove(ipmiUserMutex);
465 }
466 mutexCleanupLock.lock_sharable();
467 userMutex = std::make_unique<boost::interprocess::named_recursive_mutex>(
468 boost::interprocess::open_or_create, ipmiUserMutex);
469
470 initUserDataFile();
471 getSystemPrivAndGroups();
472 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
473 // Register it for single object and single process either netipimd /
474 // host-ipmid
475 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
476 {
477 log<level::DEBUG>("Registering signal handler");
478 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
479 bus,
480 sdbusplus::bus::match::rules::type::signal() +
481 sdbusplus::bus::match::rules::interface(dBusObjManager) +
482 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
483 [&](sdbusplus::message::message& msg) {
484 userUpdatedSignalHandler(*this, msg);
485 });
486 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
487 bus,
488 sdbusplus::bus::match::rules::type::signal() +
489 sdbusplus::bus::match::rules::interface(userMgrInterface) +
490 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
491 [&](sdbusplus::message::message& msg) {
492 userUpdatedSignalHandler(*this, msg);
493 });
494 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
495 bus,
496 sdbusplus::bus::match::rules::type::signal() +
497 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
498 sdbusplus::bus::match::rules::interface(
499 dBusPropertiesInterface) +
500 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
501 sdbusplus::bus::match::rules::argN(0, usersInterface),
502 [&](sdbusplus::message::message& msg) {
503 userUpdatedSignalHandler(*this, msg);
504 });
505 signalHndlrObject = true;
506 }
507}
508
509UserInfo* UserAccess::getUserInfo(const uint8_t& userId)
510{
511 checkAndReloadUserData();
512 return &usersTbl.user[userId];
513}
514
515void UserAccess::setUserInfo(const uint8_t& userId, UserInfo* userInfo)
516{
517 checkAndReloadUserData();
518 std::copy(reinterpret_cast<uint8_t*>(userInfo),
519 reinterpret_cast<uint8_t*>(userInfo) + sizeof(*userInfo),
520 reinterpret_cast<uint8_t*>(&usersTbl.user[userId]));
521 writeUserData();
522}
523
524bool UserAccess::isValidChannel(const uint8_t& chNum)
525{
526 return (chNum < ipmiMaxChannels);
527}
528
529bool UserAccess::isValidUserId(const uint8_t& userId)
530{
531 return ((userId <= ipmiMaxUsers) && (userId != reservedUserId));
532}
533
534bool UserAccess::isValidPrivilege(const uint8_t& priv)
535{
536 return ((priv >= PRIVILEGE_CALLBACK && priv <= PRIVILEGE_OEM) ||
537 priv == privNoAccess);
538}
539
540uint8_t UserAccess::getUsrMgmtSyncIndex()
541{
542 // TODO: Need to get LAN1 channel number dynamically,
543 // which has to be in sync with system user privilege
544 // level(Phosphor-user-manager). Note: For time being chanLan1 is marked as
545 // sync index to the user-manager privilege..
546 return static_cast<uint8_t>(EChannelID::chanLan1);
547}
548
549CommandPrivilege UserAccess::convertToIPMIPrivilege(const std::string& value)
550{
551 auto iter = std::find(ipmiPrivIndex.begin(), ipmiPrivIndex.end(), value);
552 if (iter == ipmiPrivIndex.end())
553 {
554 if (value == "")
555 {
556 return static_cast<CommandPrivilege>(privNoAccess);
557 }
558 log<level::ERR>("Error in converting to IPMI privilege",
559 entry("PRIV=%s", value.c_str()));
560 throw std::out_of_range("Out of range - convertToIPMIPrivilege");
561 }
562 else
563 {
564 return static_cast<CommandPrivilege>(
565 std::distance(ipmiPrivIndex.begin(), iter));
566 }
567}
568
569std::string UserAccess::convertToSystemPrivilege(const CommandPrivilege& value)
570{
571 if (value == static_cast<CommandPrivilege>(privNoAccess))
572 {
573 return "";
574 }
575 try
576 {
577 return ipmiPrivIndex.at(value);
578 }
579 catch (const std::out_of_range& e)
580 {
581 log<level::ERR>("Error in converting to system privilege",
582 entry("PRIV=%d", static_cast<uint8_t>(value)));
583 throw std::out_of_range("Out of range - convertToSystemPrivilege");
584 }
585}
586
587bool UserAccess::isValidUserName(const char* userNameInChar)
588{
589 if (!userNameInChar)
590 {
591 log<level::ERR>("null ptr");
592 return false;
593 }
594 std::string userName(userNameInChar, 0, ipmiMaxUserName);
595 if (!std::regex_match(userName.c_str(),
596 std::regex("[a-zA-z_][a-zA-Z_0-9]*")))
597 {
598 log<level::ERR>("Unsupported characters in user name");
599 return false;
600 }
601 if (userName == "root")
602 {
603 log<level::ERR>("Invalid user name - root");
604 return false;
605 }
606 std::map<DbusUserObjPath, DbusUserObjValue> properties;
607 try
608 {
609 auto method = bus.new_method_call(getUserServiceName().c_str(),
610 userMgrObjBasePath, dBusObjManager,
611 getManagedObjectsMethod);
612 auto reply = bus.call(method);
613 reply.read(properties);
614 }
615 catch (const sdbusplus::exception::SdBusError& e)
616 {
617 log<level::ERR>("Failed to excute method",
618 entry("METHOD=%s", getSubTreeMethod),
619 entry("PATH=%s", userMgrObjBasePath));
620 return false;
621 }
622
623 std::string usersPath = std::string(userObjBasePath) + "/" + userName;
624 if (properties.find(usersPath) != properties.end())
625 {
626 log<level::DEBUG>("User name already exists",
627 entry("USER_NAME=%s", userName.c_str()));
628 return false;
629 }
630
631 return true;
632}
633
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530634ipmi_ret_t UserAccess::setUserEnabledState(const uint8_t& userId,
635 const bool& enabledState)
636{
637 if (!isValidUserId(userId))
638 {
639 return IPMI_CC_PARM_OUT_OF_RANGE;
640 }
641 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
642 userLock{*userMutex};
643 UserInfo* userInfo = getUserInfo(userId);
644 std::string userName;
645 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
646 ipmiMaxUserName);
647 if (userName.empty())
648 {
649 log<level::DEBUG>("User name not set / invalid");
650 return IPMI_CC_UNSPECIFIED_ERROR;
651 }
652 if (userInfo->userEnabled != enabledState)
653 {
654 std::string userPath = std::string(userObjBasePath) + "/" + userName;
655 setDbusProperty(bus, getUserServiceName().c_str(), userPath.c_str(),
656 usersInterface, userEnabledProperty, enabledState);
657 }
658 return IPMI_CC_OK;
659}
660
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530661ipmi_ret_t UserAccess::setUserPrivilegeAccess(const uint8_t& userId,
662 const uint8_t& chNum,
663 const UserPrivAccess& privAccess,
664 const bool& otherPrivUpdates)
665{
666 if (!isValidChannel(chNum))
667 {
668 return IPMI_CC_INVALID_FIELD_REQUEST;
669 }
670 if (!isValidUserId(userId))
671 {
672 return IPMI_CC_PARM_OUT_OF_RANGE;
673 }
674 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
675 userLock{*userMutex};
676 UserInfo* userInfo = getUserInfo(userId);
677 std::string userName;
678 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
679 ipmiMaxUserName);
680 if (userName.empty())
681 {
682 log<level::DEBUG>("User name not set / invalid");
683 return IPMI_CC_UNSPECIFIED_ERROR;
684 }
685 std::string priv = convertToSystemPrivilege(
686 static_cast<CommandPrivilege>(privAccess.privilege));
687 if (priv.empty())
688 {
689 return IPMI_CC_PARM_OUT_OF_RANGE;
690 }
691 uint8_t syncIndex = getUsrMgmtSyncIndex();
692 if (chNum == syncIndex &&
693 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
694 {
695 std::string userPath = std::string(userObjBasePath) + "/" + userName;
696 setDbusProperty(bus, getUserServiceName().c_str(), userPath.c_str(),
697 usersInterface, userPrivProperty, priv);
698 }
699 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
700
701 if (otherPrivUpdates)
702 {
703 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
704 userInfo->userPrivAccess[chNum].linkAuthEnabled =
705 privAccess.linkAuthEnabled;
706 userInfo->userPrivAccess[chNum].accessCallback =
707 privAccess.accessCallback;
708 }
709 try
710 {
711 writeUserData();
712 }
713 catch (const std::exception& e)
714 {
715 log<level::DEBUG>("Write user data failed");
716 return IPMI_CC_UNSPECIFIED_ERROR;
717 }
718 return IPMI_CC_OK;
719}
720
721uint8_t UserAccess::getUserId(const std::string& userName)
722{
723 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
724 userLock{*userMutex};
725 checkAndReloadUserData();
726 // user index 0 is reserved, starts with 1
727 size_t usrIndex = 1;
728 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
729 {
730 std::string curName(
731 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
732 ipmiMaxUserName);
733 if (userName == curName)
734 {
735 break; // found the entry
736 }
737 }
738 if (usrIndex > ipmiMaxUsers)
739 {
740 log<level::DEBUG>("User not found",
741 entry("USER_NAME=%s", userName.c_str()));
742 return invalidUserId;
743 }
744
745 return usrIndex;
746}
747
748ipmi_ret_t UserAccess::getUserName(const uint8_t& userId, std::string& userName)
749{
750 if (!isValidUserId(userId))
751 {
752 return IPMI_CC_PARM_OUT_OF_RANGE;
753 }
754 UserInfo* userInfo = getUserInfo(userId);
755 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
756 ipmiMaxUserName);
757 return IPMI_CC_OK;
758}
759
760ipmi_ret_t UserAccess::setUserName(const uint8_t& userId,
761 const char* userNameInChar)
762{
763 if (!isValidUserId(userId))
764 {
765 return IPMI_CC_PARM_OUT_OF_RANGE;
766 }
767
768 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
769 userLock{*userMutex};
770 bool validUser = isValidUserName(userNameInChar);
771 std::string oldUser;
772 getUserName(userId, oldUser);
773 UserInfo* userInfo = getUserInfo(userId);
774
775 std::string newUser(userNameInChar, 0, ipmiMaxUserName);
776 if (newUser.empty() && !oldUser.empty())
777 {
778 // Delete existing user
779 std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
780 try
781 {
782 auto method = bus.new_method_call(
783 getUserServiceName().c_str(), userPath.c_str(),
784 deleteUserInterface, deleteUserMethod);
785 auto reply = bus.call(method);
786 }
787 catch (const sdbusplus::exception::SdBusError& e)
788 {
789 log<level::DEBUG>("Failed to excute method",
790 entry("METHOD=%s", deleteUserMethod),
791 entry("PATH=%s", userPath.c_str()));
792 return IPMI_CC_UNSPECIFIED_ERROR;
793 }
794 std::fill(userInfo->userName,
795 userInfo->userName + sizeof(userInfo->userName), 0);
796 ipmiClearUserEntryPassword(oldUser);
797 userInfo->userInSystem = false;
798 }
799 else if (oldUser.empty() && !newUser.empty() && validUser)
800 {
801 try
802 {
803 // Create new user
804 auto method = bus.new_method_call(
805 getUserServiceName().c_str(), userMgrObjBasePath,
806 userMgrInterface, createUserMethod);
807 // TODO: Fetch proper privilege & enable state once set User access
808 // is implemented if LAN Channel specified, then create user for all
809 // groups follow channel privilege for user creation.
810 method.append(newUser.c_str(), availableGroups, "priv-admin", true);
811 auto reply = bus.call(method);
812 }
813 catch (const sdbusplus::exception::SdBusError& e)
814 {
815 log<level::DEBUG>("Failed to excute method",
816 entry("METHOD=%s", createUserMethod),
817 entry("PATH=%s", userMgrObjBasePath));
818 return IPMI_CC_UNSPECIFIED_ERROR;
819 }
820 std::strncpy(reinterpret_cast<char*>(userInfo->userName),
821 userNameInChar, ipmiMaxUserName);
822 userInfo->userInSystem = true;
823 }
824 else if (oldUser != newUser && validUser)
825 {
826 try
827 {
828 // User rename
829 auto method = bus.new_method_call(
830 getUserServiceName().c_str(), userMgrObjBasePath,
831 userMgrInterface, renameUserMethod);
832 method.append(oldUser.c_str(), newUser.c_str());
833 auto reply = bus.call(method);
834 }
835 catch (const sdbusplus::exception::SdBusError& e)
836 {
837 log<level::DEBUG>("Failed to excute method",
838 entry("METHOD=%s", renameUserMethod),
839 entry("PATH=%s", userMgrObjBasePath));
840 return IPMI_CC_UNSPECIFIED_ERROR;
841 }
842 std::fill(static_cast<uint8_t*>(userInfo->userName),
843 static_cast<uint8_t*>(userInfo->userName) +
844 sizeof(userInfo->userName),
845 0);
846 std::strncpy(reinterpret_cast<char*>(userInfo->userName),
847 userNameInChar, ipmiMaxUserName);
848 ipmiRenameUserEntryPassword(oldUser, newUser);
849 userInfo->userInSystem = true;
850 }
851 else if (!validUser)
852 {
853 return IPMI_CC_INVALID_FIELD_REQUEST;
854 }
855 try
856 {
857 writeUserData();
858 }
859 catch (const std::exception& e)
860 {
861 log<level::DEBUG>("Write user data failed");
862 return IPMI_CC_UNSPECIFIED_ERROR;
863 }
864 return IPMI_CC_OK;
865}
866
867static constexpr const char* jsonUserName = "user_name";
868static constexpr const char* jsonPriv = "privilege";
869static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
870static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
871static constexpr const char* jsonAccCallbk = "access_callback";
872static constexpr const char* jsonUserEnabled = "user_enabled";
873static constexpr const char* jsonUserInSys = "user_in_system";
874static constexpr const char* jsonFixedUser = "fixed_user_name";
875
876void UserAccess::readUserData()
877{
878 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
879 userLock{*userMutex};
880
881 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
882 if (!iUsrData.good())
883 {
884 log<level::ERR>("Error in reading IPMI user data file");
885 throw std::ios_base::failure("Error opening IPMI user data file");
886 }
887
888 Json jsonUsersTbl = Json::array();
889 jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
890
891 if (jsonUsersTbl.size() != ipmiMaxUsers)
892 {
893 log<level::ERR>(
894 "Error in reading IPMI user data file - User count issues");
895 throw std::runtime_error(
896 "Corrupted IPMI user data file - invalid user count");
897 }
898 // user index 0 is reserved, starts with 1
899 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
900 {
901 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
902 if (userInfo.is_null())
903 {
904 log<level::ERR>("Error in reading IPMI user data file - "
905 "user info corrupted");
906 throw std::runtime_error(
907 "Corrupted IPMI user data file - invalid user info");
908 }
909 std::string userName = userInfo[jsonUserName].get<std::string>();
910 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
911 userName.c_str(), ipmiMaxUserName);
912
913 std::vector<std::string> privilege =
914 userInfo[jsonPriv].get<std::vector<std::string>>();
915 std::vector<bool> ipmiEnabled =
916 userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
917 std::vector<bool> linkAuthEnabled =
918 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
919 std::vector<bool> accessCallback =
920 userInfo[jsonAccCallbk].get<std::vector<bool>>();
921 if (privilege.size() != ipmiMaxChannels ||
922 ipmiEnabled.size() != ipmiMaxChannels ||
923 linkAuthEnabled.size() != ipmiMaxChannels ||
924 accessCallback.size() != ipmiMaxChannels)
925 {
926 log<level::ERR>("Error in reading IPMI user data file - "
927 "properties corrupted");
928 throw std::runtime_error(
929 "Corrupted IPMI user data file - properties");
930 }
931 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
932 {
933 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
934 static_cast<uint8_t>(
935 convertToIPMIPrivilege(privilege[chIndex]));
936 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
937 ipmiEnabled[chIndex];
938 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
939 linkAuthEnabled[chIndex];
940 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
941 accessCallback[chIndex];
942 }
943 usersTbl.user[usrIndex].userEnabled =
944 userInfo[jsonUserEnabled].get<bool>();
945 usersTbl.user[usrIndex].userInSystem =
946 userInfo[jsonUserInSys].get<bool>();
947 usersTbl.user[usrIndex].fixedUserName =
948 userInfo[jsonFixedUser].get<bool>();
949 }
950
951 log<level::DEBUG>("User data read from IPMI data file");
952 iUsrData.close();
953 // Update the timestamp
954 fileLastUpdatedTime = getUpdatedFileTime();
955 return;
956}
957
958void UserAccess::writeUserData()
959{
960 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
961 userLock{*userMutex};
962
963 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
964 std::ofstream oUsrData(tmpFile, std::ios::out | std::ios::binary);
965 if (!oUsrData.good())
966 {
967 log<level::ERR>("Error in creating temporary IPMI user data file");
968 throw std::ios_base::failure(
969 "Error in creating temporary IPMI user data file");
970 }
971
972 Json jsonUsersTbl = Json::array();
973 // user index 0 is reserved, starts with 1
974 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
975 {
976 Json jsonUserInfo;
977 jsonUserInfo[jsonUserName] = std::string(
978 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
979 ipmiMaxUserName);
980 std::vector<std::string> privilege(ipmiMaxChannels);
981 std::vector<bool> ipmiEnabled(ipmiMaxChannels);
982 std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
983 std::vector<bool> accessCallback(ipmiMaxChannels);
984 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
985 {
986 privilege[chIndex] =
987 convertToSystemPrivilege(static_cast<CommandPrivilege>(
988 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
989 ipmiEnabled[chIndex] =
990 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
991 linkAuthEnabled[chIndex] =
992 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
993 accessCallback[chIndex] =
994 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
995 }
996 jsonUserInfo[jsonPriv] = privilege;
997 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
998 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
999 jsonUserInfo[jsonAccCallbk] = accessCallback;
1000 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1001 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1002 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
1003 jsonUsersTbl.push_back(jsonUserInfo);
1004 }
1005
1006 oUsrData << jsonUsersTbl;
1007 oUsrData.flush();
1008 oUsrData.close();
1009
1010 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1011 {
1012 log<level::ERR>("Error in renaming temporary IPMI user data file");
1013 throw std::runtime_error("Error in renaming IPMI user data file");
1014 }
1015 // Update the timestamp
1016 fileLastUpdatedTime = getUpdatedFileTime();
1017 return;
1018}
1019
1020bool UserAccess::addUserEntry(const std::string& userName,
1021 const std::string& sysPriv, const bool& enabled)
1022{
1023 UsersTbl* userData = getUsersTblPtr();
1024 size_t freeIndex = 0xFF;
1025 // user index 0 is reserved, starts with 1
1026 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1027 {
1028 std::string curName(
1029 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1030 ipmiMaxUserName);
1031 if (userName == curName)
1032 {
1033 log<level::DEBUG>("User name exists",
1034 entry("USER_NAME=%s", userName.c_str()));
1035 return false; // user name exists.
1036 }
1037
1038 if ((!userData->user[usrIndex].userInSystem) &&
1039 (userData->user[usrIndex].userName[0] == '\0') &&
1040 (freeIndex == 0xFF))
1041 {
1042 freeIndex = usrIndex;
1043 }
1044 }
1045 if (freeIndex == 0xFF)
1046 {
1047 log<level::ERR>("No empty slots found");
1048 return false;
1049 }
1050 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1051 userName.c_str(), ipmiMaxUserName);
1052 uint8_t priv =
1053 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1054 privMask;
1055 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1056 {
1057 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1058 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1059 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1060 true;
1061 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1062 }
1063 userData->user[freeIndex].userInSystem = true;
1064 userData->user[freeIndex].userEnabled = enabled;
1065
1066 return true;
1067}
1068
1069void UserAccess::deleteUserIndex(const size_t& usrIdx)
1070{
1071 UsersTbl* userData = getUsersTblPtr();
1072
1073 std::string userName(
1074 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1075 ipmiMaxUserName);
1076 ipmiClearUserEntryPassword(userName);
1077 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1078 static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1079 sizeof(userData->user[usrIdx].userName),
1080 0);
1081 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1082 {
1083 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1084 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1085 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1086 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1087 }
1088 userData->user[usrIdx].userInSystem = false;
1089 userData->user[usrIdx].userEnabled = false;
1090 return;
1091}
1092
1093void UserAccess::checkAndReloadUserData()
1094{
1095 std::time_t updateTime = getUpdatedFileTime();
1096 if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1097 {
1098 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1099 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1100 readUserData();
1101 }
1102 return;
1103}
1104
1105UsersTbl* UserAccess::getUsersTblPtr()
1106{
1107 // reload data before using it.
1108 checkAndReloadUserData();
1109 return &usersTbl;
1110}
1111
1112void UserAccess::getSystemPrivAndGroups()
1113{
1114 std::map<std::string, PrivAndGroupType> properties;
1115 try
1116 {
1117 auto method = bus.new_method_call(
1118 getUserServiceName().c_str(), userMgrObjBasePath,
1119 dBusPropertiesInterface, getAllPropertiesMethod);
1120 method.append(userMgrInterface);
1121
1122 auto reply = bus.call(method);
1123 reply.read(properties);
1124 }
1125 catch (const sdbusplus::exception::SdBusError& e)
1126 {
1127 log<level::DEBUG>("Failed to excute method",
1128 entry("METHOD=%s", getAllPropertiesMethod),
1129 entry("PATH=%s", userMgrObjBasePath));
1130 return;
1131 }
1132 for (const auto& t : properties)
1133 {
1134 auto key = t.first;
1135 if (key == allPrivProperty)
1136 {
1137 availablePrivileges = t.second.get<std::vector<std::string>>();
1138 }
1139 else if (key == allGrpProperty)
1140 {
1141 availableGroups = t.second.get<std::vector<std::string>>();
1142 }
1143 }
1144 // TODO: Implement Supported Privilege & Groups verification logic
1145 return;
1146}
1147
1148std::time_t UserAccess::getUpdatedFileTime()
1149{
1150 struct stat fileStat;
1151 if (stat(ipmiUserDataFile, &fileStat) != 0)
1152 {
1153 log<level::DEBUG>("Error in getting last updated time stamp");
1154 return -EIO;
1155 }
1156 return fileStat.st_mtime;
1157}
1158
1159void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1160 std::vector<std::string>& usrGrps,
1161 std::string& usrPriv, bool& usrEnabled)
1162{
1163 for (const auto& t : properties)
1164 {
1165 std::string key = t.first;
1166 if (key == userPrivProperty)
1167 {
1168 usrPriv = t.second.get<std::string>();
1169 }
1170 else if (key == userGrpProperty)
1171 {
1172 usrGrps = t.second.get<std::vector<std::string>>();
1173 }
1174 else if (key == userEnabledProperty)
1175 {
1176 usrEnabled = t.second.get<bool>();
1177 }
1178 }
1179 return;
1180}
1181
1182int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1183 std::vector<std::string>& usrGrps,
1184 std::string& usrPriv, bool& usrEnabled)
1185{
1186 auto usrObj = userObjs.find(usersInterface);
1187 if (usrObj != userObjs.end())
1188 {
1189 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1190 return 0;
1191 }
1192 return -EIO;
1193}
1194
1195void UserAccess::initUserDataFile()
1196{
1197 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1198 userLock{*userMutex};
1199 try
1200 {
1201 readUserData();
1202 }
1203 catch (const std::ios_base::failure& e)
1204 { // File is empty, create it for the first time
1205 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1206 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1207 // user index 0 is reserved, starts with 1
1208 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1209 {
1210 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1211 {
1212 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1213 privNoAccess;
1214 }
1215 }
1216 writeUserData();
1217 }
1218 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1219 try
1220 {
1221 auto method = bus.new_method_call(getUserServiceName().c_str(),
1222 userMgrObjBasePath, dBusObjManager,
1223 getManagedObjectsMethod);
1224 auto reply = bus.call(method);
1225 reply.read(managedObjs);
1226 }
1227 catch (const sdbusplus::exception::SdBusError& e)
1228 {
1229 log<level::DEBUG>("Failed to excute method",
1230 entry("METHOD=%s", getSubTreeMethod),
1231 entry("PATH=%s", userMgrObjBasePath));
1232 return;
1233 }
1234
1235 UsersTbl* userData = &usersTbl;
1236 // user index 0 is reserved, starts with 1
1237 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1238 {
1239 if ((userData->user[usrIdx].userInSystem) &&
1240 (userData->user[usrIdx].userName[0] != '\0'))
1241 {
1242 std::vector<std::string> usrGrps;
1243 std::string usrPriv;
1244 bool usrEnabled;
1245
1246 std::string userName(
1247 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1248 ipmiMaxUserName);
1249 std::string usersPath =
1250 std::string(userObjBasePath) + "/" + userName;
1251
1252 auto usrObj = managedObjs.find(usersPath);
1253 if (usrObj != managedObjs.end())
1254 {
1255 // User exist. Lets check and update other fileds
1256 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1257 usrEnabled);
1258 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1259 usrGrps.end())
1260 {
1261 // Group "ipmi" is removed so lets remove user in IPMI
1262 deleteUserIndex(usrIdx);
1263 }
1264 else
1265 {
1266 // Group "ipmi" is present so lets update other properties
1267 // in IPMI
1268 uint8_t priv =
1269 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1270 // Update all channels priv, only if it is not equivalent to
1271 // getUsrMgmtSyncIndex()
1272 if (userData->user[usrIdx]
1273 .userPrivAccess[getUsrMgmtSyncIndex()]
1274 .privilege != priv)
1275 {
1276 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1277 ++chIndex)
1278 {
1279 userData->user[usrIdx]
1280 .userPrivAccess[chIndex]
1281 .privilege = priv;
1282 }
1283 }
1284 if (userData->user[usrIdx].userEnabled != usrEnabled)
1285 {
1286 userData->user[usrIdx].userEnabled = usrEnabled;
1287 }
1288 }
1289
1290 // We are done with this obj. lets delete from MAP
1291 managedObjs.erase(usrObj);
1292 }
1293 else
1294 {
1295 deleteUserIndex(usrIdx);
1296 }
1297 }
1298 }
1299
1300 // Walk through remnaining managedObj users list
1301 // Add them to ipmi data base
1302 for (const auto& usrObj : managedObjs)
1303 {
1304 std::vector<std::string> usrGrps;
1305 std::string usrPriv, userName;
1306 bool usrEnabled;
1307 std::string usrObjPath = std::string(usrObj.first);
1308 if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1309 {
1310 log<level::ERR>("Error in user object path");
1311 continue;
1312 }
1313 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1314 // Add 'ipmi' group users
1315 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1316 usrGrps.end())
1317 {
1318 // CREATE NEW USER
1319 if (true != addUserEntry(userName, usrPriv, usrEnabled))
1320 {
1321 break;
1322 }
1323 }
1324 }
1325
1326 // All userData slots update done. Lets write the data
1327 writeUserData();
1328
1329 return;
1330}
1331} // namespace ipmi