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