blob: bf43f881cf3271fb5300c7f20d76d25fdde3a0e7 [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
474 initUserDataFile();
475 getSystemPrivAndGroups();
476 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
477 // Register it for single object and single process either netipimd /
478 // host-ipmid
479 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
480 {
481 log<level::DEBUG>("Registering signal handler");
482 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
483 bus,
484 sdbusplus::bus::match::rules::type::signal() +
485 sdbusplus::bus::match::rules::interface(dBusObjManager) +
486 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
487 [&](sdbusplus::message::message& msg) {
488 userUpdatedSignalHandler(*this, msg);
489 });
490 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
491 bus,
492 sdbusplus::bus::match::rules::type::signal() +
493 sdbusplus::bus::match::rules::interface(userMgrInterface) +
494 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
495 [&](sdbusplus::message::message& msg) {
496 userUpdatedSignalHandler(*this, msg);
497 });
498 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
499 bus,
500 sdbusplus::bus::match::rules::type::signal() +
501 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
502 sdbusplus::bus::match::rules::interface(
503 dBusPropertiesInterface) +
504 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
505 sdbusplus::bus::match::rules::argN(0, usersInterface),
506 [&](sdbusplus::message::message& msg) {
507 userUpdatedSignalHandler(*this, msg);
508 });
509 signalHndlrObject = true;
510 }
511}
512
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530513UserInfo* UserAccess::getUserInfo(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530514{
515 checkAndReloadUserData();
516 return &usersTbl.user[userId];
517}
518
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530519void UserAccess::setUserInfo(const uint8_t userId, UserInfo* userInfo)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530520{
521 checkAndReloadUserData();
522 std::copy(reinterpret_cast<uint8_t*>(userInfo),
523 reinterpret_cast<uint8_t*>(userInfo) + sizeof(*userInfo),
524 reinterpret_cast<uint8_t*>(&usersTbl.user[userId]));
525 writeUserData();
526}
527
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530528bool UserAccess::isValidChannel(const uint8_t chNum)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530529{
530 return (chNum < ipmiMaxChannels);
531}
532
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530533bool UserAccess::isValidUserId(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530534{
535 return ((userId <= ipmiMaxUsers) && (userId != reservedUserId));
536}
537
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530538bool UserAccess::isValidPrivilege(const uint8_t priv)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530539{
540 return ((priv >= PRIVILEGE_CALLBACK && priv <= PRIVILEGE_OEM) ||
541 priv == privNoAccess);
542}
543
544uint8_t UserAccess::getUsrMgmtSyncIndex()
545{
546 // TODO: Need to get LAN1 channel number dynamically,
547 // which has to be in sync with system user privilege
548 // level(Phosphor-user-manager). Note: For time being chanLan1 is marked as
549 // sync index to the user-manager privilege..
550 return static_cast<uint8_t>(EChannelID::chanLan1);
551}
552
553CommandPrivilege UserAccess::convertToIPMIPrivilege(const std::string& value)
554{
555 auto iter = std::find(ipmiPrivIndex.begin(), ipmiPrivIndex.end(), value);
556 if (iter == ipmiPrivIndex.end())
557 {
558 if (value == "")
559 {
560 return static_cast<CommandPrivilege>(privNoAccess);
561 }
562 log<level::ERR>("Error in converting to IPMI privilege",
563 entry("PRIV=%s", value.c_str()));
564 throw std::out_of_range("Out of range - convertToIPMIPrivilege");
565 }
566 else
567 {
568 return static_cast<CommandPrivilege>(
569 std::distance(ipmiPrivIndex.begin(), iter));
570 }
571}
572
573std::string UserAccess::convertToSystemPrivilege(const CommandPrivilege& value)
574{
575 if (value == static_cast<CommandPrivilege>(privNoAccess))
576 {
577 return "";
578 }
579 try
580 {
581 return ipmiPrivIndex.at(value);
582 }
583 catch (const std::out_of_range& e)
584 {
585 log<level::ERR>("Error in converting to system privilege",
586 entry("PRIV=%d", static_cast<uint8_t>(value)));
587 throw std::out_of_range("Out of range - convertToSystemPrivilege");
588 }
589}
590
591bool UserAccess::isValidUserName(const char* userNameInChar)
592{
593 if (!userNameInChar)
594 {
595 log<level::ERR>("null ptr");
596 return false;
597 }
598 std::string userName(userNameInChar, 0, ipmiMaxUserName);
599 if (!std::regex_match(userName.c_str(),
600 std::regex("[a-zA-z_][a-zA-Z_0-9]*")))
601 {
602 log<level::ERR>("Unsupported characters in user name");
603 return false;
604 }
605 if (userName == "root")
606 {
607 log<level::ERR>("Invalid user name - root");
608 return false;
609 }
610 std::map<DbusUserObjPath, DbusUserObjValue> properties;
611 try
612 {
613 auto method = bus.new_method_call(getUserServiceName().c_str(),
614 userMgrObjBasePath, dBusObjManager,
615 getManagedObjectsMethod);
616 auto reply = bus.call(method);
617 reply.read(properties);
618 }
619 catch (const sdbusplus::exception::SdBusError& e)
620 {
621 log<level::ERR>("Failed to excute method",
622 entry("METHOD=%s", getSubTreeMethod),
623 entry("PATH=%s", userMgrObjBasePath));
624 return false;
625 }
626
627 std::string usersPath = std::string(userObjBasePath) + "/" + userName;
628 if (properties.find(usersPath) != properties.end())
629 {
630 log<level::DEBUG>("User name already exists",
631 entry("USER_NAME=%s", userName.c_str()));
632 return false;
633 }
634
635 return true;
636}
637
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530638/** @brief Information exchanged by pam module and application.
639 *
640 * @param[in] numMsg - length of the array of pointers,msg.
641 *
642 * @param[in] msg - pointer to an array of pointers to pam_message structure
643 *
644 * @param[out] resp - struct pam response array
645 *
646 * @param[in] appdataPtr - member of pam_conv structure
647 *
648 * @return the response in pam response structure.
649 */
650
651static int pamFunctionConversation(int numMsg, const struct pam_message** msg,
652 struct pam_response** resp, void* appdataPtr)
653{
654 if (appdataPtr == nullptr)
655 {
656 return PAM_AUTH_ERR;
657 }
658 size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1;
659 char* pass = reinterpret_cast<char*>(malloc(passSize));
660 std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize);
661
662 *resp = reinterpret_cast<pam_response*>(
663 calloc(numMsg, sizeof(struct pam_response)));
664
665 for (int i = 0; i < numMsg; ++i)
666 {
667 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
668 {
669 continue;
670 }
671 resp[i]->resp = pass;
672 }
673 return PAM_SUCCESS;
674}
675
676/** @brief Updating the PAM password
677 *
678 * @param[in] username - username in string
679 *
680 * @param[in] password - new password in string
681 *
682 * @return status
683 */
684
685bool pamUpdatePasswd(const char* username, const char* password)
686{
687 const struct pam_conv localConversation = {pamFunctionConversation,
688 const_cast<char*>(password)};
689 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
690
691 if (pam_start("passwd", username, &localConversation, &localAuthHandle) !=
692 PAM_SUCCESS)
693 {
694 return false;
695 }
696 int retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
697
698 if (retval != PAM_SUCCESS)
699 {
700 if (retval == PAM_AUTHTOK_ERR)
701 {
702 log<level::DEBUG>("Authentication Failure");
703 }
704 else
705 {
706 log<level::DEBUG>("pam_chauthtok returned failure",
707 entry("ERROR=%d", retval));
708 }
709 pam_end(localAuthHandle, retval);
710 return false;
711 }
712 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
713 {
714 return false;
715 }
716 return true;
717}
718
Ayushi Smriti02650d52019-05-15 11:59:09 +0000719bool pamUserCheckAuthenticate(std::string_view username,
720 std::string_view password)
721{
722 const struct pam_conv localConversation = {
723 pamFunctionConversation, const_cast<char*>(password.data())};
724
725 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
726
727 if (pam_start("dropbear", username.data(), &localConversation,
728 &localAuthHandle) != PAM_SUCCESS)
729 {
730 log<level::ERR>("User Authentication Failure");
731 return false;
732 }
733
734 int retval = pam_authenticate(localAuthHandle,
735 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
736
737 if (retval != PAM_SUCCESS)
738 {
739 log<level::DEBUG>("pam_authenticate returned failure",
740 entry("ERROR=%d", retval));
741
742 pam_end(localAuthHandle, retval);
743 return false;
744 }
745
746 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
747 PAM_SUCCESS)
748 {
749 pam_end(localAuthHandle, PAM_SUCCESS);
750 return false;
751 }
752
753 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
754 {
755 return false;
756 }
757 return true;
758}
759
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530760ipmi_ret_t UserAccess::setSpecialUserPassword(const std::string& userName,
761 const std::string& userPassword)
762{
763 if (!pamUpdatePasswd(userName.c_str(), userPassword.c_str()))
764 {
765 log<level::DEBUG>("Failed to update password");
766 return IPMI_CC_UNSPECIFIED_ERROR;
767 }
768 return IPMI_CC_OK;
769}
770
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530771ipmi_ret_t UserAccess::setUserPassword(const uint8_t userId,
772 const char* userPassword)
773{
774 std::string userName;
775 if (ipmiUserGetUserName(userId, userName) != IPMI_CC_OK)
776 {
777 log<level::DEBUG>("User Name not found",
778 entry("USER-ID:%d", (uint8_t)userId));
779 return IPMI_CC_PARM_OUT_OF_RANGE;
780 }
781 std::string passwd;
782 passwd.assign(reinterpret_cast<const char*>(userPassword), 0,
783 maxIpmi20PasswordSize);
784 if (!std::regex_match(passwd.c_str(),
785 std::regex("[a-zA-z_0-9][a-zA-Z_0-9,?:`!\"]*")))
786 {
787 log<level::DEBUG>("Invalid password fields",
788 entry("USER-ID:%d", (uint8_t)userId));
789 return IPMI_CC_INVALID_FIELD_REQUEST;
790 }
791 if (!pamUpdatePasswd(userName.c_str(), passwd.c_str()))
792 {
793 log<level::DEBUG>("Failed to update password",
794 entry("USER-ID:%d", (uint8_t)userId));
795 return IPMI_CC_UNSPECIFIED_ERROR;
796 }
797 return IPMI_CC_OK;
798}
799
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530800ipmi_ret_t UserAccess::setUserEnabledState(const uint8_t userId,
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530801 const bool& enabledState)
802{
803 if (!isValidUserId(userId))
804 {
805 return IPMI_CC_PARM_OUT_OF_RANGE;
806 }
807 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
808 userLock{*userMutex};
809 UserInfo* userInfo = getUserInfo(userId);
810 std::string userName;
811 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
812 ipmiMaxUserName);
813 if (userName.empty())
814 {
815 log<level::DEBUG>("User name not set / invalid");
816 return IPMI_CC_UNSPECIFIED_ERROR;
817 }
818 if (userInfo->userEnabled != enabledState)
819 {
820 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800821 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
822 userEnabledProperty, enabledState);
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530823 userInfo->userEnabled = enabledState;
824 try
825 {
826 writeUserData();
827 }
828 catch (const std::exception& e)
829 {
830 log<level::DEBUG>("Write user data failed");
831 return IPMI_CC_UNSPECIFIED_ERROR;
832 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530833 }
834 return IPMI_CC_OK;
835}
836
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000837ipmi_ret_t UserAccess::setUserPayloadAccess(const uint8_t chNum,
838 const uint8_t operation,
839 const uint8_t userId,
840 const PayloadAccess& payloadAccess)
841{
842 constexpr uint8_t enable = 0x0;
843 constexpr uint8_t disable = 0x1;
844
845 if (!isValidChannel(chNum))
846 {
847 return IPMI_CC_INVALID_FIELD_REQUEST;
848 }
849 if (!isValidUserId(userId))
850 {
851 return IPMI_CC_PARM_OUT_OF_RANGE;
852 }
853 if (operation != enable && operation != disable)
854 {
855 return IPMI_CC_INVALID_FIELD_REQUEST;
856 }
857 // Check operation & payloadAccess if required.
858 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
859 userLock{*userMutex};
860 UserInfo* userInfo = getUserInfo(userId);
861
862 if (operation == enable)
863 {
864 userInfo->payloadAccess[chNum].stdPayloadEnables1 |=
865 payloadAccess.stdPayloadEnables1;
866
867 userInfo->payloadAccess[chNum].oemPayloadEnables1 |=
868 payloadAccess.oemPayloadEnables1;
869 }
870 else
871 {
872 userInfo->payloadAccess[chNum].stdPayloadEnables1 &=
873 ~(payloadAccess.stdPayloadEnables1);
874
875 userInfo->payloadAccess[chNum].oemPayloadEnables1 &=
876 ~(payloadAccess.oemPayloadEnables1);
877 }
878
879 try
880 {
881 writeUserData();
882 }
883 catch (const std::exception& e)
884 {
885 log<level::ERR>("Write user data failed");
886 return IPMI_CC_UNSPECIFIED_ERROR;
887 }
888 return IPMI_CC_OK;
889}
890
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530891ipmi_ret_t UserAccess::setUserPrivilegeAccess(const uint8_t userId,
892 const uint8_t chNum,
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530893 const UserPrivAccess& privAccess,
894 const bool& otherPrivUpdates)
895{
896 if (!isValidChannel(chNum))
897 {
898 return IPMI_CC_INVALID_FIELD_REQUEST;
899 }
900 if (!isValidUserId(userId))
901 {
902 return IPMI_CC_PARM_OUT_OF_RANGE;
903 }
904 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
905 userLock{*userMutex};
906 UserInfo* userInfo = getUserInfo(userId);
907 std::string userName;
908 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
909 ipmiMaxUserName);
910 if (userName.empty())
911 {
912 log<level::DEBUG>("User name not set / invalid");
913 return IPMI_CC_UNSPECIFIED_ERROR;
914 }
915 std::string priv = convertToSystemPrivilege(
916 static_cast<CommandPrivilege>(privAccess.privilege));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530917 uint8_t syncIndex = getUsrMgmtSyncIndex();
918 if (chNum == syncIndex &&
919 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
920 {
921 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800922 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
923 userPrivProperty, priv);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530924 }
925 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
926
927 if (otherPrivUpdates)
928 {
929 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
930 userInfo->userPrivAccess[chNum].linkAuthEnabled =
931 privAccess.linkAuthEnabled;
932 userInfo->userPrivAccess[chNum].accessCallback =
933 privAccess.accessCallback;
934 }
935 try
936 {
937 writeUserData();
938 }
939 catch (const std::exception& e)
940 {
941 log<level::DEBUG>("Write user data failed");
942 return IPMI_CC_UNSPECIFIED_ERROR;
943 }
944 return IPMI_CC_OK;
945}
946
947uint8_t UserAccess::getUserId(const std::string& userName)
948{
949 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
950 userLock{*userMutex};
951 checkAndReloadUserData();
952 // user index 0 is reserved, starts with 1
953 size_t usrIndex = 1;
954 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
955 {
956 std::string curName(
957 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
958 ipmiMaxUserName);
959 if (userName == curName)
960 {
961 break; // found the entry
962 }
963 }
964 if (usrIndex > ipmiMaxUsers)
965 {
966 log<level::DEBUG>("User not found",
967 entry("USER_NAME=%s", userName.c_str()));
968 return invalidUserId;
969 }
970
971 return usrIndex;
972}
973
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530974ipmi_ret_t UserAccess::getUserName(const uint8_t userId, std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530975{
976 if (!isValidUserId(userId))
977 {
978 return IPMI_CC_PARM_OUT_OF_RANGE;
979 }
980 UserInfo* userInfo = getUserInfo(userId);
981 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
982 ipmiMaxUserName);
983 return IPMI_CC_OK;
984}
985
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530986ipmi_ret_t UserAccess::setUserName(const uint8_t userId,
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530987 const char* userNameInChar)
988{
989 if (!isValidUserId(userId))
990 {
991 return IPMI_CC_PARM_OUT_OF_RANGE;
992 }
993
994 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
995 userLock{*userMutex};
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530996 std::string oldUser;
997 getUserName(userId, oldUser);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530998
999 std::string newUser(userNameInChar, 0, ipmiMaxUserName);
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +05301000 if (oldUser == newUser)
1001 {
1002 // requesting to set the same user name, return success.
1003 return IPMI_CC_OK;
1004 }
1005 bool validUser = isValidUserName(userNameInChar);
1006 UserInfo* userInfo = getUserInfo(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301007 if (newUser.empty() && !oldUser.empty())
1008 {
1009 // Delete existing user
1010 std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
1011 try
1012 {
1013 auto method = bus.new_method_call(
1014 getUserServiceName().c_str(), userPath.c_str(),
1015 deleteUserInterface, deleteUserMethod);
1016 auto reply = bus.call(method);
1017 }
1018 catch (const sdbusplus::exception::SdBusError& e)
1019 {
1020 log<level::DEBUG>("Failed to excute method",
1021 entry("METHOD=%s", deleteUserMethod),
1022 entry("PATH=%s", userPath.c_str()));
1023 return IPMI_CC_UNSPECIFIED_ERROR;
1024 }
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +05301025 deleteUserIndex(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301026 }
1027 else if (oldUser.empty() && !newUser.empty() && validUser)
1028 {
1029 try
1030 {
1031 // Create new user
1032 auto method = bus.new_method_call(
1033 getUserServiceName().c_str(), userMgrObjBasePath,
1034 userMgrInterface, createUserMethod);
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +05301035 method.append(newUser.c_str(), availableGroups, "", false);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301036 auto reply = bus.call(method);
1037 }
1038 catch (const sdbusplus::exception::SdBusError& e)
1039 {
1040 log<level::DEBUG>("Failed to excute method",
1041 entry("METHOD=%s", createUserMethod),
1042 entry("PATH=%s", userMgrObjBasePath));
1043 return IPMI_CC_UNSPECIFIED_ERROR;
1044 }
Brad Bishop77ff3fe2018-11-21 15:24:44 -05001045 std::memcpy(userInfo->userName, userNameInChar, ipmiMaxUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301046 userInfo->userInSystem = true;
1047 }
1048 else if (oldUser != newUser && validUser)
1049 {
1050 try
1051 {
1052 // User rename
1053 auto method = bus.new_method_call(
1054 getUserServiceName().c_str(), userMgrObjBasePath,
1055 userMgrInterface, renameUserMethod);
1056 method.append(oldUser.c_str(), newUser.c_str());
1057 auto reply = bus.call(method);
1058 }
1059 catch (const sdbusplus::exception::SdBusError& e)
1060 {
1061 log<level::DEBUG>("Failed to excute method",
1062 entry("METHOD=%s", renameUserMethod),
1063 entry("PATH=%s", userMgrObjBasePath));
1064 return IPMI_CC_UNSPECIFIED_ERROR;
1065 }
1066 std::fill(static_cast<uint8_t*>(userInfo->userName),
1067 static_cast<uint8_t*>(userInfo->userName) +
1068 sizeof(userInfo->userName),
1069 0);
Brad Bishop77ff3fe2018-11-21 15:24:44 -05001070 std::memcpy(userInfo->userName, userNameInChar, ipmiMaxUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301071 ipmiRenameUserEntryPassword(oldUser, newUser);
1072 userInfo->userInSystem = true;
1073 }
1074 else if (!validUser)
1075 {
1076 return IPMI_CC_INVALID_FIELD_REQUEST;
1077 }
1078 try
1079 {
1080 writeUserData();
1081 }
1082 catch (const std::exception& e)
1083 {
1084 log<level::DEBUG>("Write user data failed");
1085 return IPMI_CC_UNSPECIFIED_ERROR;
1086 }
1087 return IPMI_CC_OK;
1088}
1089
1090static constexpr const char* jsonUserName = "user_name";
1091static constexpr const char* jsonPriv = "privilege";
1092static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
1093static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
1094static constexpr const char* jsonAccCallbk = "access_callback";
1095static constexpr const char* jsonUserEnabled = "user_enabled";
1096static constexpr const char* jsonUserInSys = "user_in_system";
1097static constexpr const char* jsonFixedUser = "fixed_user_name";
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001098static constexpr const char* payloadEnabledStr = "payload_enabled";
1099static constexpr const char* stdPayloadStr = "std_payload";
1100static constexpr const char* oemPayloadStr = "OEM_payload";
1101
1102/** @brief to construct a JSON object from the given payload access details.
1103 *
1104 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input)
1105 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input)
1106 *
1107 * @details Sample output JSON object format :
1108 * "payload_enabled":{
1109 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1110 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1111 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1112 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1113 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1114 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1115 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1116 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1117 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1118 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1119 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1120 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1121 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1122 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1123 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1124 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1125 * }
1126 */
1127static const Json constructJsonPayloadEnables(
1128 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1129 stdPayload,
1130 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1131 oemPayload)
1132{
1133 Json jsonPayloadEnabled;
1134
1135 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1136 {
1137 std::ostringstream stdPayloadStream;
1138 std::ostringstream oemPayloadStream;
1139
1140 stdPayloadStream << stdPayloadStr << payloadNum;
1141 oemPayloadStream << oemPayloadStr << payloadNum;
1142
1143 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1144 stdPayloadStream.str(), stdPayload[payloadNum]));
1145
1146 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1147 oemPayloadStream.str(), oemPayload[payloadNum]));
1148 }
1149 return jsonPayloadEnabled;
1150}
1151
1152void UserAccess::readPayloadAccessFromUserInfo(
1153 const UserInfo& userInfo,
1154 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload,
1155 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload)
1156{
1157 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1158 {
1159 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1160 {
1161 stdPayload[payloadNum][chIndex] =
1162 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum];
1163
1164 oemPayload[payloadNum][chIndex] =
1165 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum];
1166 }
1167 }
1168}
1169
1170void UserAccess::updatePayloadAccessInUserInfo(
1171 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1172 stdPayload,
1173 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1174 oemPayload,
1175 UserInfo& userInfo)
1176{
1177 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1178 {
1179 // Ensure that reserved/unsupported payloads are marked to zero.
1180 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset();
1181 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset();
1182 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset();
1183 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset();
1184 // Update SOL status as it is the only supported payload currently.
1185 userInfo.payloadAccess[chIndex]
1186 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] =
1187 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex];
1188 }
1189}
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301190
1191void UserAccess::readUserData()
1192{
1193 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1194 userLock{*userMutex};
1195
1196 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
1197 if (!iUsrData.good())
1198 {
1199 log<level::ERR>("Error in reading IPMI user data file");
1200 throw std::ios_base::failure("Error opening IPMI user data file");
1201 }
1202
1203 Json jsonUsersTbl = Json::array();
1204 jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
1205
1206 if (jsonUsersTbl.size() != ipmiMaxUsers)
1207 {
1208 log<level::ERR>(
1209 "Error in reading IPMI user data file - User count issues");
1210 throw std::runtime_error(
1211 "Corrupted IPMI user data file - invalid user count");
1212 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001213
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301214 // user index 0 is reserved, starts with 1
1215 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1216 {
1217 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
1218 if (userInfo.is_null())
1219 {
1220 log<level::ERR>("Error in reading IPMI user data file - "
1221 "user info corrupted");
1222 throw std::runtime_error(
1223 "Corrupted IPMI user data file - invalid user info");
1224 }
1225 std::string userName = userInfo[jsonUserName].get<std::string>();
1226 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
1227 userName.c_str(), ipmiMaxUserName);
1228
1229 std::vector<std::string> privilege =
1230 userInfo[jsonPriv].get<std::vector<std::string>>();
1231 std::vector<bool> ipmiEnabled =
1232 userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
1233 std::vector<bool> linkAuthEnabled =
1234 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
1235 std::vector<bool> accessCallback =
1236 userInfo[jsonAccCallbk].get<std::vector<bool>>();
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001237
1238 // Payload Enables Processing.
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001239 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1240 stdPayload = {};
1241 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1242 oemPayload = {};
1243 try
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001244 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001245 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr);
1246 for (auto payloadNum = 0; payloadNum < payloadsPerByte;
1247 payloadNum++)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001248 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001249 std::ostringstream stdPayloadStream;
1250 std::ostringstream oemPayloadStream;
1251
1252 stdPayloadStream << stdPayloadStr << payloadNum;
1253 oemPayloadStream << oemPayloadStr << payloadNum;
1254
1255 stdPayload[payloadNum] =
1256 jsonPayloadEnabled[stdPayloadStream.str()]
1257 .get<std::array<bool, ipmiMaxChannels>>();
1258 oemPayload[payloadNum] =
1259 jsonPayloadEnabled[oemPayloadStream.str()]
1260 .get<std::array<bool, ipmiMaxChannels>>();
1261
1262 if (stdPayload[payloadNum].size() != ipmiMaxChannels ||
1263 oemPayload[payloadNum].size() != ipmiMaxChannels)
1264 {
1265 log<level::ERR>("Error in reading IPMI user data file - "
1266 "payload properties corrupted");
1267 throw std::runtime_error(
1268 "Corrupted IPMI user data file - payload properties");
1269 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001270 }
1271 }
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001272 catch (Json::out_of_range& e)
1273 {
1274 // Key not found in 'userInfo'; possibly an old JSON file. Use
1275 // default values for all payloads, and SOL payload default is true.
1276 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true);
1277 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001278
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301279 if (privilege.size() != ipmiMaxChannels ||
1280 ipmiEnabled.size() != ipmiMaxChannels ||
1281 linkAuthEnabled.size() != ipmiMaxChannels ||
1282 accessCallback.size() != ipmiMaxChannels)
1283 {
1284 log<level::ERR>("Error in reading IPMI user data file - "
1285 "properties corrupted");
1286 throw std::runtime_error(
1287 "Corrupted IPMI user data file - properties");
1288 }
1289 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1290 {
1291 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
1292 static_cast<uint8_t>(
1293 convertToIPMIPrivilege(privilege[chIndex]));
1294 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
1295 ipmiEnabled[chIndex];
1296 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
1297 linkAuthEnabled[chIndex];
1298 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
1299 accessCallback[chIndex];
1300 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001301 updatePayloadAccessInUserInfo(stdPayload, oemPayload,
1302 usersTbl.user[usrIndex]);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301303 usersTbl.user[usrIndex].userEnabled =
1304 userInfo[jsonUserEnabled].get<bool>();
1305 usersTbl.user[usrIndex].userInSystem =
1306 userInfo[jsonUserInSys].get<bool>();
1307 usersTbl.user[usrIndex].fixedUserName =
1308 userInfo[jsonFixedUser].get<bool>();
1309 }
1310
1311 log<level::DEBUG>("User data read from IPMI data file");
1312 iUsrData.close();
1313 // Update the timestamp
1314 fileLastUpdatedTime = getUpdatedFileTime();
1315 return;
1316}
1317
1318void UserAccess::writeUserData()
1319{
1320 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1321 userLock{*userMutex};
1322
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301323 Json jsonUsersTbl = Json::array();
1324 // user index 0 is reserved, starts with 1
1325 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1326 {
1327 Json jsonUserInfo;
1328 jsonUserInfo[jsonUserName] = std::string(
1329 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
1330 ipmiMaxUserName);
1331 std::vector<std::string> privilege(ipmiMaxChannels);
1332 std::vector<bool> ipmiEnabled(ipmiMaxChannels);
1333 std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
1334 std::vector<bool> accessCallback(ipmiMaxChannels);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001335
1336 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1337 stdPayload;
1338 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1339 oemPayload;
1340
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301341 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1342 {
1343 privilege[chIndex] =
1344 convertToSystemPrivilege(static_cast<CommandPrivilege>(
1345 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
1346 ipmiEnabled[chIndex] =
1347 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
1348 linkAuthEnabled[chIndex] =
1349 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
1350 accessCallback[chIndex] =
1351 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
1352 }
1353 jsonUserInfo[jsonPriv] = privilege;
1354 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
1355 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
1356 jsonUserInfo[jsonAccCallbk] = accessCallback;
1357 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1358 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1359 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001360
1361 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload,
1362 oemPayload);
1363 Json jsonPayloadEnabledInfo =
1364 constructJsonPayloadEnables(stdPayload, oemPayload);
1365 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo;
1366
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301367 jsonUsersTbl.push_back(jsonUserInfo);
1368 }
1369
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +05301370 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
1371 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
1372 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1373 if (fd < 0)
1374 {
1375 log<level::ERR>("Error in creating temporary IPMI user data file");
1376 throw std::ios_base::failure(
1377 "Error in creating temporary IPMI user data file");
1378 }
1379 const auto& writeStr = jsonUsersTbl.dump();
1380 if (write(fd, writeStr.c_str(), writeStr.size()) !=
1381 static_cast<ssize_t>(writeStr.size()))
1382 {
1383 close(fd);
1384 log<level::ERR>("Error in writing temporary IPMI user data file");
1385 throw std::ios_base::failure(
1386 "Error in writing temporary IPMI user data file");
1387 }
1388 close(fd);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301389
1390 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1391 {
1392 log<level::ERR>("Error in renaming temporary IPMI user data file");
1393 throw std::runtime_error("Error in renaming IPMI user data file");
1394 }
1395 // Update the timestamp
1396 fileLastUpdatedTime = getUpdatedFileTime();
1397 return;
1398}
1399
1400bool UserAccess::addUserEntry(const std::string& userName,
1401 const std::string& sysPriv, const bool& enabled)
1402{
1403 UsersTbl* userData = getUsersTblPtr();
1404 size_t freeIndex = 0xFF;
1405 // user index 0 is reserved, starts with 1
1406 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1407 {
1408 std::string curName(
1409 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1410 ipmiMaxUserName);
1411 if (userName == curName)
1412 {
1413 log<level::DEBUG>("User name exists",
1414 entry("USER_NAME=%s", userName.c_str()));
1415 return false; // user name exists.
1416 }
1417
1418 if ((!userData->user[usrIndex].userInSystem) &&
1419 (userData->user[usrIndex].userName[0] == '\0') &&
1420 (freeIndex == 0xFF))
1421 {
1422 freeIndex = usrIndex;
1423 }
1424 }
1425 if (freeIndex == 0xFF)
1426 {
1427 log<level::ERR>("No empty slots found");
1428 return false;
1429 }
1430 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1431 userName.c_str(), ipmiMaxUserName);
1432 uint8_t priv =
1433 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1434 privMask;
1435 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1436 {
1437 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1438 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1439 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1440 true;
1441 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1442 }
1443 userData->user[freeIndex].userInSystem = true;
1444 userData->user[freeIndex].userEnabled = enabled;
1445
1446 return true;
1447}
1448
1449void UserAccess::deleteUserIndex(const size_t& usrIdx)
1450{
1451 UsersTbl* userData = getUsersTblPtr();
1452
1453 std::string userName(
1454 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1455 ipmiMaxUserName);
1456 ipmiClearUserEntryPassword(userName);
1457 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1458 static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1459 sizeof(userData->user[usrIdx].userName),
1460 0);
1461 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1462 {
1463 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1464 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1465 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1466 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1467 }
1468 userData->user[usrIdx].userInSystem = false;
1469 userData->user[usrIdx].userEnabled = false;
1470 return;
1471}
1472
1473void UserAccess::checkAndReloadUserData()
1474{
1475 std::time_t updateTime = getUpdatedFileTime();
1476 if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1477 {
1478 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1479 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1480 readUserData();
1481 }
1482 return;
1483}
1484
1485UsersTbl* UserAccess::getUsersTblPtr()
1486{
1487 // reload data before using it.
1488 checkAndReloadUserData();
1489 return &usersTbl;
1490}
1491
1492void UserAccess::getSystemPrivAndGroups()
1493{
1494 std::map<std::string, PrivAndGroupType> properties;
1495 try
1496 {
1497 auto method = bus.new_method_call(
1498 getUserServiceName().c_str(), userMgrObjBasePath,
1499 dBusPropertiesInterface, getAllPropertiesMethod);
1500 method.append(userMgrInterface);
1501
1502 auto reply = bus.call(method);
1503 reply.read(properties);
1504 }
1505 catch (const sdbusplus::exception::SdBusError& e)
1506 {
1507 log<level::DEBUG>("Failed to excute method",
1508 entry("METHOD=%s", getAllPropertiesMethod),
1509 entry("PATH=%s", userMgrObjBasePath));
1510 return;
1511 }
1512 for (const auto& t : properties)
1513 {
1514 auto key = t.first;
1515 if (key == allPrivProperty)
1516 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001517 availablePrivileges = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301518 }
1519 else if (key == allGrpProperty)
1520 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001521 availableGroups = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301522 }
1523 }
1524 // TODO: Implement Supported Privilege & Groups verification logic
1525 return;
1526}
1527
1528std::time_t UserAccess::getUpdatedFileTime()
1529{
1530 struct stat fileStat;
1531 if (stat(ipmiUserDataFile, &fileStat) != 0)
1532 {
1533 log<level::DEBUG>("Error in getting last updated time stamp");
1534 return -EIO;
1535 }
1536 return fileStat.st_mtime;
1537}
1538
1539void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1540 std::vector<std::string>& usrGrps,
1541 std::string& usrPriv, bool& usrEnabled)
1542{
1543 for (const auto& t : properties)
1544 {
1545 std::string key = t.first;
1546 if (key == userPrivProperty)
1547 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001548 usrPriv = std::get<std::string>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301549 }
1550 else if (key == userGrpProperty)
1551 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001552 usrGrps = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301553 }
1554 else if (key == userEnabledProperty)
1555 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001556 usrEnabled = std::get<bool>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301557 }
1558 }
1559 return;
1560}
1561
1562int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1563 std::vector<std::string>& usrGrps,
1564 std::string& usrPriv, bool& usrEnabled)
1565{
1566 auto usrObj = userObjs.find(usersInterface);
1567 if (usrObj != userObjs.end())
1568 {
1569 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1570 return 0;
1571 }
1572 return -EIO;
1573}
1574
1575void UserAccess::initUserDataFile()
1576{
1577 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1578 userLock{*userMutex};
1579 try
1580 {
1581 readUserData();
1582 }
1583 catch (const std::ios_base::failure& e)
1584 { // File is empty, create it for the first time
1585 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1586 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1587 // user index 0 is reserved, starts with 1
1588 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1589 {
1590 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1591 {
1592 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1593 privNoAccess;
Saravanan Palanisamy92d81192019-08-07 18:00:04 +00001594 usersTbl.user[userIndex]
1595 .payloadAccess[chIndex]
1596 .stdPayloadEnables1[static_cast<uint8_t>(
1597 ipmi::PayloadType::SOL)] = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301598 }
1599 }
1600 writeUserData();
1601 }
1602 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1603 try
1604 {
1605 auto method = bus.new_method_call(getUserServiceName().c_str(),
1606 userMgrObjBasePath, dBusObjManager,
1607 getManagedObjectsMethod);
1608 auto reply = bus.call(method);
1609 reply.read(managedObjs);
1610 }
1611 catch (const sdbusplus::exception::SdBusError& e)
1612 {
1613 log<level::DEBUG>("Failed to excute method",
1614 entry("METHOD=%s", getSubTreeMethod),
1615 entry("PATH=%s", userMgrObjBasePath));
1616 return;
1617 }
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301618 bool updateRequired = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301619 UsersTbl* userData = &usersTbl;
1620 // user index 0 is reserved, starts with 1
1621 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1622 {
1623 if ((userData->user[usrIdx].userInSystem) &&
1624 (userData->user[usrIdx].userName[0] != '\0'))
1625 {
1626 std::vector<std::string> usrGrps;
1627 std::string usrPriv;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301628
1629 std::string userName(
1630 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1631 ipmiMaxUserName);
1632 std::string usersPath =
1633 std::string(userObjBasePath) + "/" + userName;
1634
1635 auto usrObj = managedObjs.find(usersPath);
1636 if (usrObj != managedObjs.end())
1637 {
Patrick Venture3a697ad2019-08-19 11:12:05 -07001638 bool usrEnabled;
1639
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301640 // User exist. Lets check and update other fileds
1641 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1642 usrEnabled);
1643 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1644 usrGrps.end())
1645 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301646 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301647 // Group "ipmi" is removed so lets remove user in IPMI
1648 deleteUserIndex(usrIdx);
1649 }
1650 else
1651 {
1652 // Group "ipmi" is present so lets update other properties
1653 // in IPMI
1654 uint8_t priv =
1655 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1656 // Update all channels priv, only if it is not equivalent to
1657 // getUsrMgmtSyncIndex()
1658 if (userData->user[usrIdx]
1659 .userPrivAccess[getUsrMgmtSyncIndex()]
1660 .privilege != priv)
1661 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301662 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301663 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1664 ++chIndex)
1665 {
1666 userData->user[usrIdx]
1667 .userPrivAccess[chIndex]
1668 .privilege = priv;
1669 }
1670 }
1671 if (userData->user[usrIdx].userEnabled != usrEnabled)
1672 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301673 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301674 userData->user[usrIdx].userEnabled = usrEnabled;
1675 }
1676 }
1677
1678 // We are done with this obj. lets delete from MAP
1679 managedObjs.erase(usrObj);
1680 }
1681 else
1682 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301683 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301684 deleteUserIndex(usrIdx);
1685 }
1686 }
1687 }
1688
1689 // Walk through remnaining managedObj users list
1690 // Add them to ipmi data base
1691 for (const auto& usrObj : managedObjs)
1692 {
1693 std::vector<std::string> usrGrps;
1694 std::string usrPriv, userName;
1695 bool usrEnabled;
1696 std::string usrObjPath = std::string(usrObj.first);
1697 if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1698 {
1699 log<level::ERR>("Error in user object path");
1700 continue;
1701 }
1702 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1703 // Add 'ipmi' group users
1704 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1705 usrGrps.end())
1706 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301707 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301708 // CREATE NEW USER
1709 if (true != addUserEntry(userName, usrPriv, usrEnabled))
1710 {
1711 break;
1712 }
1713 }
1714 }
1715
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301716 if (updateRequired)
1717 {
1718 // All userData slots update done. Lets write the data
1719 writeUserData();
1720 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301721
1722 return;
1723}
1724} // namespace ipmi