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