blob: 86f51da1b2305819346f0c8caeb921fddba7c52b [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
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();
310 std::string userName, update, priv, newUserName;
311 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 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800378 priv = variant_ns::get<std::string>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530379 userEvent = UserUpdateEvent::userPrivUpdated;
380 }
381 else if (member == userGrpProperty)
382 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800383 groups = variant_ns::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 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800388 enabled = variant_ns::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
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530638ipmi_ret_t UserAccess::setUserEnabledState(const uint8_t userId,
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530639 const bool& enabledState)
640{
641 if (!isValidUserId(userId))
642 {
643 return IPMI_CC_PARM_OUT_OF_RANGE;
644 }
645 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
646 userLock{*userMutex};
647 UserInfo* userInfo = getUserInfo(userId);
648 std::string userName;
649 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
650 ipmiMaxUserName);
651 if (userName.empty())
652 {
653 log<level::DEBUG>("User name not set / invalid");
654 return IPMI_CC_UNSPECIFIED_ERROR;
655 }
656 if (userInfo->userEnabled != enabledState)
657 {
658 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800659 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
660 userEnabledProperty, enabledState);
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530661 userInfo->userEnabled = enabledState;
662 try
663 {
664 writeUserData();
665 }
666 catch (const std::exception& e)
667 {
668 log<level::DEBUG>("Write user data failed");
669 return IPMI_CC_UNSPECIFIED_ERROR;
670 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530671 }
672 return IPMI_CC_OK;
673}
674
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530675ipmi_ret_t UserAccess::setUserPrivilegeAccess(const uint8_t userId,
676 const uint8_t chNum,
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530677 const UserPrivAccess& privAccess,
678 const bool& otherPrivUpdates)
679{
680 if (!isValidChannel(chNum))
681 {
682 return IPMI_CC_INVALID_FIELD_REQUEST;
683 }
684 if (!isValidUserId(userId))
685 {
686 return IPMI_CC_PARM_OUT_OF_RANGE;
687 }
688 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
689 userLock{*userMutex};
690 UserInfo* userInfo = getUserInfo(userId);
691 std::string userName;
692 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
693 ipmiMaxUserName);
694 if (userName.empty())
695 {
696 log<level::DEBUG>("User name not set / invalid");
697 return IPMI_CC_UNSPECIFIED_ERROR;
698 }
699 std::string priv = convertToSystemPrivilege(
700 static_cast<CommandPrivilege>(privAccess.privilege));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530701 uint8_t syncIndex = getUsrMgmtSyncIndex();
702 if (chNum == syncIndex &&
703 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
704 {
705 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800706 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
707 userPrivProperty, priv);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530708 }
709 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
710
711 if (otherPrivUpdates)
712 {
713 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
714 userInfo->userPrivAccess[chNum].linkAuthEnabled =
715 privAccess.linkAuthEnabled;
716 userInfo->userPrivAccess[chNum].accessCallback =
717 privAccess.accessCallback;
718 }
719 try
720 {
721 writeUserData();
722 }
723 catch (const std::exception& e)
724 {
725 log<level::DEBUG>("Write user data failed");
726 return IPMI_CC_UNSPECIFIED_ERROR;
727 }
728 return IPMI_CC_OK;
729}
730
731uint8_t UserAccess::getUserId(const std::string& userName)
732{
733 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
734 userLock{*userMutex};
735 checkAndReloadUserData();
736 // user index 0 is reserved, starts with 1
737 size_t usrIndex = 1;
738 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
739 {
740 std::string curName(
741 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
742 ipmiMaxUserName);
743 if (userName == curName)
744 {
745 break; // found the entry
746 }
747 }
748 if (usrIndex > ipmiMaxUsers)
749 {
750 log<level::DEBUG>("User not found",
751 entry("USER_NAME=%s", userName.c_str()));
752 return invalidUserId;
753 }
754
755 return usrIndex;
756}
757
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530758ipmi_ret_t UserAccess::getUserName(const uint8_t userId, std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530759{
760 if (!isValidUserId(userId))
761 {
762 return IPMI_CC_PARM_OUT_OF_RANGE;
763 }
764 UserInfo* userInfo = getUserInfo(userId);
765 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
766 ipmiMaxUserName);
767 return IPMI_CC_OK;
768}
769
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530770ipmi_ret_t UserAccess::setUserName(const uint8_t userId,
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530771 const char* userNameInChar)
772{
773 if (!isValidUserId(userId))
774 {
775 return IPMI_CC_PARM_OUT_OF_RANGE;
776 }
777
778 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
779 userLock{*userMutex};
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530780 std::string oldUser;
781 getUserName(userId, oldUser);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530782
783 std::string newUser(userNameInChar, 0, ipmiMaxUserName);
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530784 if (oldUser == newUser)
785 {
786 // requesting to set the same user name, return success.
787 return IPMI_CC_OK;
788 }
789 bool validUser = isValidUserName(userNameInChar);
790 UserInfo* userInfo = getUserInfo(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530791 if (newUser.empty() && !oldUser.empty())
792 {
793 // Delete existing user
794 std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
795 try
796 {
797 auto method = bus.new_method_call(
798 getUserServiceName().c_str(), userPath.c_str(),
799 deleteUserInterface, deleteUserMethod);
800 auto reply = bus.call(method);
801 }
802 catch (const sdbusplus::exception::SdBusError& e)
803 {
804 log<level::DEBUG>("Failed to excute method",
805 entry("METHOD=%s", deleteUserMethod),
806 entry("PATH=%s", userPath.c_str()));
807 return IPMI_CC_UNSPECIFIED_ERROR;
808 }
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +0530809 deleteUserIndex(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530810 }
811 else if (oldUser.empty() && !newUser.empty() && validUser)
812 {
813 try
814 {
815 // Create new user
816 auto method = bus.new_method_call(
817 getUserServiceName().c_str(), userMgrObjBasePath,
818 userMgrInterface, createUserMethod);
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +0530819 method.append(newUser.c_str(), availableGroups, "", false);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530820 auto reply = bus.call(method);
821 }
822 catch (const sdbusplus::exception::SdBusError& e)
823 {
824 log<level::DEBUG>("Failed to excute method",
825 entry("METHOD=%s", createUserMethod),
826 entry("PATH=%s", userMgrObjBasePath));
827 return IPMI_CC_UNSPECIFIED_ERROR;
828 }
Brad Bishop77ff3fe2018-11-21 15:24:44 -0500829 std::memcpy(userInfo->userName, userNameInChar, ipmiMaxUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530830 userInfo->userInSystem = true;
831 }
832 else if (oldUser != newUser && validUser)
833 {
834 try
835 {
836 // User rename
837 auto method = bus.new_method_call(
838 getUserServiceName().c_str(), userMgrObjBasePath,
839 userMgrInterface, renameUserMethod);
840 method.append(oldUser.c_str(), newUser.c_str());
841 auto reply = bus.call(method);
842 }
843 catch (const sdbusplus::exception::SdBusError& e)
844 {
845 log<level::DEBUG>("Failed to excute method",
846 entry("METHOD=%s", renameUserMethod),
847 entry("PATH=%s", userMgrObjBasePath));
848 return IPMI_CC_UNSPECIFIED_ERROR;
849 }
850 std::fill(static_cast<uint8_t*>(userInfo->userName),
851 static_cast<uint8_t*>(userInfo->userName) +
852 sizeof(userInfo->userName),
853 0);
Brad Bishop77ff3fe2018-11-21 15:24:44 -0500854 std::memcpy(userInfo->userName, userNameInChar, ipmiMaxUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530855 ipmiRenameUserEntryPassword(oldUser, newUser);
856 userInfo->userInSystem = true;
857 }
858 else if (!validUser)
859 {
860 return IPMI_CC_INVALID_FIELD_REQUEST;
861 }
862 try
863 {
864 writeUserData();
865 }
866 catch (const std::exception& e)
867 {
868 log<level::DEBUG>("Write user data failed");
869 return IPMI_CC_UNSPECIFIED_ERROR;
870 }
871 return IPMI_CC_OK;
872}
873
874static constexpr const char* jsonUserName = "user_name";
875static constexpr const char* jsonPriv = "privilege";
876static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
877static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
878static constexpr const char* jsonAccCallbk = "access_callback";
879static constexpr const char* jsonUserEnabled = "user_enabled";
880static constexpr const char* jsonUserInSys = "user_in_system";
881static constexpr const char* jsonFixedUser = "fixed_user_name";
882
883void UserAccess::readUserData()
884{
885 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
886 userLock{*userMutex};
887
888 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
889 if (!iUsrData.good())
890 {
891 log<level::ERR>("Error in reading IPMI user data file");
892 throw std::ios_base::failure("Error opening IPMI user data file");
893 }
894
895 Json jsonUsersTbl = Json::array();
896 jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
897
898 if (jsonUsersTbl.size() != ipmiMaxUsers)
899 {
900 log<level::ERR>(
901 "Error in reading IPMI user data file - User count issues");
902 throw std::runtime_error(
903 "Corrupted IPMI user data file - invalid user count");
904 }
905 // user index 0 is reserved, starts with 1
906 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
907 {
908 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
909 if (userInfo.is_null())
910 {
911 log<level::ERR>("Error in reading IPMI user data file - "
912 "user info corrupted");
913 throw std::runtime_error(
914 "Corrupted IPMI user data file - invalid user info");
915 }
916 std::string userName = userInfo[jsonUserName].get<std::string>();
917 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
918 userName.c_str(), ipmiMaxUserName);
919
920 std::vector<std::string> privilege =
921 userInfo[jsonPriv].get<std::vector<std::string>>();
922 std::vector<bool> ipmiEnabled =
923 userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
924 std::vector<bool> linkAuthEnabled =
925 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
926 std::vector<bool> accessCallback =
927 userInfo[jsonAccCallbk].get<std::vector<bool>>();
928 if (privilege.size() != ipmiMaxChannels ||
929 ipmiEnabled.size() != ipmiMaxChannels ||
930 linkAuthEnabled.size() != ipmiMaxChannels ||
931 accessCallback.size() != ipmiMaxChannels)
932 {
933 log<level::ERR>("Error in reading IPMI user data file - "
934 "properties corrupted");
935 throw std::runtime_error(
936 "Corrupted IPMI user data file - properties");
937 }
938 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
939 {
940 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
941 static_cast<uint8_t>(
942 convertToIPMIPrivilege(privilege[chIndex]));
943 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
944 ipmiEnabled[chIndex];
945 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
946 linkAuthEnabled[chIndex];
947 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
948 accessCallback[chIndex];
949 }
950 usersTbl.user[usrIndex].userEnabled =
951 userInfo[jsonUserEnabled].get<bool>();
952 usersTbl.user[usrIndex].userInSystem =
953 userInfo[jsonUserInSys].get<bool>();
954 usersTbl.user[usrIndex].fixedUserName =
955 userInfo[jsonFixedUser].get<bool>();
956 }
957
958 log<level::DEBUG>("User data read from IPMI data file");
959 iUsrData.close();
960 // Update the timestamp
961 fileLastUpdatedTime = getUpdatedFileTime();
962 return;
963}
964
965void UserAccess::writeUserData()
966{
967 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
968 userLock{*userMutex};
969
970 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
971 std::ofstream oUsrData(tmpFile, std::ios::out | std::ios::binary);
972 if (!oUsrData.good())
973 {
974 log<level::ERR>("Error in creating temporary IPMI user data file");
975 throw std::ios_base::failure(
976 "Error in creating temporary IPMI user data file");
977 }
978
979 Json jsonUsersTbl = Json::array();
980 // user index 0 is reserved, starts with 1
981 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
982 {
983 Json jsonUserInfo;
984 jsonUserInfo[jsonUserName] = std::string(
985 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
986 ipmiMaxUserName);
987 std::vector<std::string> privilege(ipmiMaxChannels);
988 std::vector<bool> ipmiEnabled(ipmiMaxChannels);
989 std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
990 std::vector<bool> accessCallback(ipmiMaxChannels);
991 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
992 {
993 privilege[chIndex] =
994 convertToSystemPrivilege(static_cast<CommandPrivilege>(
995 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
996 ipmiEnabled[chIndex] =
997 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
998 linkAuthEnabled[chIndex] =
999 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
1000 accessCallback[chIndex] =
1001 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
1002 }
1003 jsonUserInfo[jsonPriv] = privilege;
1004 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
1005 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
1006 jsonUserInfo[jsonAccCallbk] = accessCallback;
1007 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1008 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1009 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
1010 jsonUsersTbl.push_back(jsonUserInfo);
1011 }
1012
1013 oUsrData << jsonUsersTbl;
1014 oUsrData.flush();
1015 oUsrData.close();
1016
1017 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1018 {
1019 log<level::ERR>("Error in renaming temporary IPMI user data file");
1020 throw std::runtime_error("Error in renaming IPMI user data file");
1021 }
1022 // Update the timestamp
1023 fileLastUpdatedTime = getUpdatedFileTime();
1024 return;
1025}
1026
1027bool UserAccess::addUserEntry(const std::string& userName,
1028 const std::string& sysPriv, const bool& enabled)
1029{
1030 UsersTbl* userData = getUsersTblPtr();
1031 size_t freeIndex = 0xFF;
1032 // user index 0 is reserved, starts with 1
1033 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1034 {
1035 std::string curName(
1036 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1037 ipmiMaxUserName);
1038 if (userName == curName)
1039 {
1040 log<level::DEBUG>("User name exists",
1041 entry("USER_NAME=%s", userName.c_str()));
1042 return false; // user name exists.
1043 }
1044
1045 if ((!userData->user[usrIndex].userInSystem) &&
1046 (userData->user[usrIndex].userName[0] == '\0') &&
1047 (freeIndex == 0xFF))
1048 {
1049 freeIndex = usrIndex;
1050 }
1051 }
1052 if (freeIndex == 0xFF)
1053 {
1054 log<level::ERR>("No empty slots found");
1055 return false;
1056 }
1057 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1058 userName.c_str(), ipmiMaxUserName);
1059 uint8_t priv =
1060 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1061 privMask;
1062 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1063 {
1064 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1065 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1066 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1067 true;
1068 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1069 }
1070 userData->user[freeIndex].userInSystem = true;
1071 userData->user[freeIndex].userEnabled = enabled;
1072
1073 return true;
1074}
1075
1076void UserAccess::deleteUserIndex(const size_t& usrIdx)
1077{
1078 UsersTbl* userData = getUsersTblPtr();
1079
1080 std::string userName(
1081 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1082 ipmiMaxUserName);
1083 ipmiClearUserEntryPassword(userName);
1084 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1085 static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1086 sizeof(userData->user[usrIdx].userName),
1087 0);
1088 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1089 {
1090 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1091 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1092 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1093 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1094 }
1095 userData->user[usrIdx].userInSystem = false;
1096 userData->user[usrIdx].userEnabled = false;
1097 return;
1098}
1099
1100void UserAccess::checkAndReloadUserData()
1101{
1102 std::time_t updateTime = getUpdatedFileTime();
1103 if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1104 {
1105 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1106 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1107 readUserData();
1108 }
1109 return;
1110}
1111
1112UsersTbl* UserAccess::getUsersTblPtr()
1113{
1114 // reload data before using it.
1115 checkAndReloadUserData();
1116 return &usersTbl;
1117}
1118
1119void UserAccess::getSystemPrivAndGroups()
1120{
1121 std::map<std::string, PrivAndGroupType> properties;
1122 try
1123 {
1124 auto method = bus.new_method_call(
1125 getUserServiceName().c_str(), userMgrObjBasePath,
1126 dBusPropertiesInterface, getAllPropertiesMethod);
1127 method.append(userMgrInterface);
1128
1129 auto reply = bus.call(method);
1130 reply.read(properties);
1131 }
1132 catch (const sdbusplus::exception::SdBusError& e)
1133 {
1134 log<level::DEBUG>("Failed to excute method",
1135 entry("METHOD=%s", getAllPropertiesMethod),
1136 entry("PATH=%s", userMgrObjBasePath));
1137 return;
1138 }
1139 for (const auto& t : properties)
1140 {
1141 auto key = t.first;
1142 if (key == allPrivProperty)
1143 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001144 availablePrivileges =
1145 variant_ns::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301146 }
1147 else if (key == allGrpProperty)
1148 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001149 availableGroups =
1150 variant_ns::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301151 }
1152 }
1153 // TODO: Implement Supported Privilege & Groups verification logic
1154 return;
1155}
1156
1157std::time_t UserAccess::getUpdatedFileTime()
1158{
1159 struct stat fileStat;
1160 if (stat(ipmiUserDataFile, &fileStat) != 0)
1161 {
1162 log<level::DEBUG>("Error in getting last updated time stamp");
1163 return -EIO;
1164 }
1165 return fileStat.st_mtime;
1166}
1167
1168void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1169 std::vector<std::string>& usrGrps,
1170 std::string& usrPriv, bool& usrEnabled)
1171{
1172 for (const auto& t : properties)
1173 {
1174 std::string key = t.first;
1175 if (key == userPrivProperty)
1176 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001177 usrPriv = variant_ns::get<std::string>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301178 }
1179 else if (key == userGrpProperty)
1180 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001181 usrGrps = variant_ns::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301182 }
1183 else if (key == userEnabledProperty)
1184 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001185 usrEnabled = variant_ns::get<bool>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301186 }
1187 }
1188 return;
1189}
1190
1191int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1192 std::vector<std::string>& usrGrps,
1193 std::string& usrPriv, bool& usrEnabled)
1194{
1195 auto usrObj = userObjs.find(usersInterface);
1196 if (usrObj != userObjs.end())
1197 {
1198 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1199 return 0;
1200 }
1201 return -EIO;
1202}
1203
1204void UserAccess::initUserDataFile()
1205{
1206 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1207 userLock{*userMutex};
1208 try
1209 {
1210 readUserData();
1211 }
1212 catch (const std::ios_base::failure& e)
1213 { // File is empty, create it for the first time
1214 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1215 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1216 // user index 0 is reserved, starts with 1
1217 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1218 {
1219 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1220 {
1221 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1222 privNoAccess;
1223 }
1224 }
1225 writeUserData();
1226 }
1227 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1228 try
1229 {
1230 auto method = bus.new_method_call(getUserServiceName().c_str(),
1231 userMgrObjBasePath, dBusObjManager,
1232 getManagedObjectsMethod);
1233 auto reply = bus.call(method);
1234 reply.read(managedObjs);
1235 }
1236 catch (const sdbusplus::exception::SdBusError& e)
1237 {
1238 log<level::DEBUG>("Failed to excute method",
1239 entry("METHOD=%s", getSubTreeMethod),
1240 entry("PATH=%s", userMgrObjBasePath));
1241 return;
1242 }
1243
1244 UsersTbl* userData = &usersTbl;
1245 // user index 0 is reserved, starts with 1
1246 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1247 {
1248 if ((userData->user[usrIdx].userInSystem) &&
1249 (userData->user[usrIdx].userName[0] != '\0'))
1250 {
1251 std::vector<std::string> usrGrps;
1252 std::string usrPriv;
1253 bool usrEnabled;
1254
1255 std::string userName(
1256 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1257 ipmiMaxUserName);
1258 std::string usersPath =
1259 std::string(userObjBasePath) + "/" + userName;
1260
1261 auto usrObj = managedObjs.find(usersPath);
1262 if (usrObj != managedObjs.end())
1263 {
1264 // User exist. Lets check and update other fileds
1265 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1266 usrEnabled);
1267 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1268 usrGrps.end())
1269 {
1270 // Group "ipmi" is removed so lets remove user in IPMI
1271 deleteUserIndex(usrIdx);
1272 }
1273 else
1274 {
1275 // Group "ipmi" is present so lets update other properties
1276 // in IPMI
1277 uint8_t priv =
1278 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1279 // Update all channels priv, only if it is not equivalent to
1280 // getUsrMgmtSyncIndex()
1281 if (userData->user[usrIdx]
1282 .userPrivAccess[getUsrMgmtSyncIndex()]
1283 .privilege != priv)
1284 {
1285 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1286 ++chIndex)
1287 {
1288 userData->user[usrIdx]
1289 .userPrivAccess[chIndex]
1290 .privilege = priv;
1291 }
1292 }
1293 if (userData->user[usrIdx].userEnabled != usrEnabled)
1294 {
1295 userData->user[usrIdx].userEnabled = usrEnabled;
1296 }
1297 }
1298
1299 // We are done with this obj. lets delete from MAP
1300 managedObjs.erase(usrObj);
1301 }
1302 else
1303 {
1304 deleteUserIndex(usrIdx);
1305 }
1306 }
1307 }
1308
1309 // Walk through remnaining managedObj users list
1310 // Add them to ipmi data base
1311 for (const auto& usrObj : managedObjs)
1312 {
1313 std::vector<std::string> usrGrps;
1314 std::string usrPriv, userName;
1315 bool usrEnabled;
1316 std::string usrObjPath = std::string(usrObj.first);
1317 if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1318 {
1319 log<level::ERR>("Error in user object path");
1320 continue;
1321 }
1322 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1323 // Add 'ipmi' group users
1324 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1325 usrGrps.end())
1326 {
1327 // CREATE NEW USER
1328 if (true != addUserEntry(userName, usrPriv, usrEnabled))
1329 {
1330 break;
1331 }
1332 }
1333 }
1334
1335 // All userData slots update done. Lets write the data
1336 writeUserData();
1337
1338 return;
1339}
1340} // namespace ipmi