blob: f0cd7ada53e7ec61a55a2131941d8f0963d186f5 [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
Suryakanth Sekar90b00c72019-01-16 10:37:57 +053020#include <security/pam_appl.h>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053021#include <sys/stat.h>
22#include <unistd.h>
23
24#include <boost/interprocess/sync/named_recursive_mutex.hpp>
25#include <boost/interprocess/sync/scoped_lock.hpp>
26#include <cerrno>
27#include <fstream>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053028#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
Lei YU4b0ddb62019-01-25 16:43:50 +0800120std::unique_ptr<sdbusplus::bus::match_t> userUpdatedSignal
121 __attribute__((init_priority(101)));
122std::unique_ptr<sdbusplus::bus::match_t> userMgrRenamedSignal
123 __attribute__((init_priority(101)));
124std::unique_ptr<sdbusplus::bus::match_t> userPropertiesSignal
125 __attribute__((init_priority(101)));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530126
127// TODO: Below code can be removed once it is moved to common layer libmiscutil
128std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf,
129 const std::string& path)
130{
131 auto mapperCall = bus.new_method_call(objMapperService, objMapperPath,
132 objMapperInterface, getObjectMethod);
133
134 mapperCall.append(path);
135 mapperCall.append(std::vector<std::string>({intf}));
136
137 auto mapperResponseMsg = bus.call(mapperCall);
138
139 std::map<std::string, std::vector<std::string>> mapperResponse;
140 mapperResponseMsg.read(mapperResponse);
141
142 if (mapperResponse.begin() == mapperResponse.end())
143 {
144 throw sdbusplus::exception::SdBusError(
145 -EIO, "ERROR in reading the mapper response");
146 }
147
148 return mapperResponse.begin()->first;
149}
150
151void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service,
152 const std::string& objPath, const std::string& interface,
153 const std::string& property,
154 const DbusUserPropVariant& value)
155{
156 try
157 {
158 auto method =
159 bus.new_method_call(service.c_str(), objPath.c_str(),
160 dBusPropertiesInterface, setPropertiesMethod);
161 method.append(interface, property, value);
162 bus.call(method);
163 }
164 catch (const sdbusplus::exception::SdBusError& e)
165 {
166 log<level::ERR>("Failed to set property",
167 entry("PROPERTY=%s", property.c_str()),
168 entry("PATH=%s", objPath.c_str()),
169 entry("INTERFACE=%s", interface.c_str()));
170 throw;
171 }
172}
173
174static std::string getUserServiceName()
175{
176 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
177 static std::string userMgmtService;
178 if (userMgmtService.empty())
179 {
180 try
181 {
182 userMgmtService =
183 ipmi::getUserService(bus, userMgrInterface, userMgrObjBasePath);
184 }
185 catch (const sdbusplus::exception::SdBusError& e)
186 {
187 userMgmtService.clear();
188 }
189 }
190 return userMgmtService;
191}
192
193UserAccess& getUserAccessObject()
194{
195 static UserAccess userAccess;
196 return userAccess;
197}
198
199int getUserNameFromPath(const std::string& path, std::string& userName)
200{
201 static size_t pos = strlen(userObjBasePath) + 1;
202 if (path.find(userObjBasePath) == std::string::npos)
203 {
204 return -EINVAL;
205 }
206 userName.assign(path, pos, path.size());
207 return 0;
208}
209
210void userUpdateHelper(UserAccess& usrAccess, const UserUpdateEvent& userEvent,
211 const std::string& userName, const std::string& priv,
212 const bool& enabled, const std::string& newUserName)
213{
214 UsersTbl* userData = usrAccess.getUsersTblPtr();
215 if (userEvent == UserUpdateEvent::userCreated)
216 {
217 if (usrAccess.addUserEntry(userName, priv, enabled) == false)
218 {
219 return;
220 }
221 }
222 else
223 {
224 // user index 0 is reserved, starts with 1
225 size_t usrIndex = 1;
226 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
227 {
228 std::string curName(
229 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
230 ipmiMaxUserName);
231 if (userName == curName)
232 {
233 break; // found the entry
234 }
235 }
236 if (usrIndex > ipmiMaxUsers)
237 {
238 log<level::DEBUG>("User not found for signal",
239 entry("USER_NAME=%s", userName.c_str()),
240 entry("USER_EVENT=%d", userEvent));
241 return;
242 }
243 switch (userEvent)
244 {
245 case UserUpdateEvent::userDeleted:
246 {
247 usrAccess.deleteUserIndex(usrIndex);
248 break;
249 }
250 case UserUpdateEvent::userPrivUpdated:
251 {
252 uint8_t userPriv =
253 static_cast<uint8_t>(
254 UserAccess::convertToIPMIPrivilege(priv)) &
255 privMask;
256 // Update all channels privileges, only if it is not equivalent
257 // to getUsrMgmtSyncIndex()
258 if (userData->user[usrIndex]
259 .userPrivAccess[UserAccess::getUsrMgmtSyncIndex()]
260 .privilege != userPriv)
261 {
262 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
263 ++chIndex)
264 {
265 userData->user[usrIndex]
266 .userPrivAccess[chIndex]
267 .privilege = userPriv;
268 }
269 }
270 break;
271 }
272 case UserUpdateEvent::userRenamed:
273 {
274 std::fill(
275 static_cast<uint8_t*>(userData->user[usrIndex].userName),
276 static_cast<uint8_t*>(userData->user[usrIndex].userName) +
277 sizeof(userData->user[usrIndex].userName),
278 0);
279 std::strncpy(
280 reinterpret_cast<char*>(userData->user[usrIndex].userName),
281 newUserName.c_str(), ipmiMaxUserName);
282 ipmiRenameUserEntryPassword(userName, newUserName);
283 break;
284 }
285 case UserUpdateEvent::userStateUpdated:
286 {
287 userData->user[usrIndex].userEnabled = enabled;
288 break;
289 }
290 default:
291 {
292 log<level::ERR>("Unhandled user event",
293 entry("USER_EVENT=%d", userEvent));
294 return;
295 }
296 }
297 }
298 usrAccess.writeUserData();
299 log<level::DEBUG>("User event handled successfully",
300 entry("USER_NAME=%s", userName.c_str()),
301 entry("USER_EVENT=%d", userEvent));
302
303 return;
304}
305
306void userUpdatedSignalHandler(UserAccess& usrAccess,
307 sdbusplus::message::message& msg)
308{
309 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
310 std::string signal = msg.get_member();
311 std::string userName, update, priv, newUserName;
312 std::vector<std::string> groups;
313 bool enabled = false;
314 UserUpdateEvent userEvent = UserUpdateEvent::reservedEvent;
315 if (signal == intfAddedSignal)
316 {
317 DbusUserObjPath objPath;
318 DbusUserObjValue objValue;
319 msg.read(objPath, objValue);
320 getUserNameFromPath(objPath.str, userName);
321 if (usrAccess.getUserObjProperties(objValue, groups, priv, enabled) !=
322 0)
323 {
324 return;
325 }
326 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
327 groups.end())
328 {
329 return;
330 }
331 userEvent = UserUpdateEvent::userCreated;
332 }
333 else if (signal == intfRemovedSignal)
334 {
335 DbusUserObjPath objPath;
336 std::vector<std::string> interfaces;
337 msg.read(objPath, interfaces);
338 getUserNameFromPath(objPath.str, userName);
339 userEvent = UserUpdateEvent::userDeleted;
340 }
341 else if (signal == userRenamedSignal)
342 {
343 msg.read(userName, newUserName);
344 userEvent = UserUpdateEvent::userRenamed;
345 }
346 else if (signal == propertiesChangedSignal)
347 {
348 getUserNameFromPath(msg.get_path(), userName);
349 }
350 else
351 {
352 log<level::ERR>("Unknown user update signal",
353 entry("SIGNAL=%s", signal.c_str()));
354 return;
355 }
356
357 if (signal.empty() || userName.empty() ||
358 (signal == userRenamedSignal && newUserName.empty()))
359 {
360 log<level::ERR>("Invalid inputs received");
361 return;
362 }
363
364 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
365 userLock{*(usrAccess.userMutex)};
366 usrAccess.checkAndReloadUserData();
367
368 if (signal == propertiesChangedSignal)
369 {
370 std::string intfName;
371 DbusUserObjProperties chProperties;
372 msg.read(intfName, chProperties); // skip reading 3rd argument.
373 for (const auto& prop : chProperties)
374 {
375 userEvent = UserUpdateEvent::reservedEvent;
376 std::string member = prop.first;
377 if (member == userPrivProperty)
378 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800379 priv = variant_ns::get<std::string>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530380 userEvent = UserUpdateEvent::userPrivUpdated;
381 }
382 else if (member == userGrpProperty)
383 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800384 groups = variant_ns::get<std::vector<std::string>>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530385 userEvent = UserUpdateEvent::userGrpUpdated;
386 }
387 else if (member == userEnabledProperty)
388 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800389 enabled = variant_ns::get<bool>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530390 userEvent = UserUpdateEvent::userStateUpdated;
391 }
392 // Process based on event type.
393 if (userEvent == UserUpdateEvent::userGrpUpdated)
394 {
395 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
396 groups.end())
397 {
398 // remove user from ipmi user list.
399 userUpdateHelper(usrAccess, UserUpdateEvent::userDeleted,
400 userName, priv, enabled, newUserName);
401 }
402 else
403 {
404 DbusUserObjProperties properties;
405 try
406 {
407 auto method = bus.new_method_call(
408 getUserServiceName().c_str(), msg.get_path(),
409 dBusPropertiesInterface, getAllPropertiesMethod);
410 method.append(usersInterface);
411 auto reply = bus.call(method);
412 reply.read(properties);
413 }
414 catch (const sdbusplus::exception::SdBusError& e)
415 {
416 log<level::DEBUG>(
417 "Failed to excute method",
418 entry("METHOD=%s", getAllPropertiesMethod),
419 entry("PATH=%s", msg.get_path()));
420 return;
421 }
422 usrAccess.getUserProperties(properties, groups, priv,
423 enabled);
424 // add user to ipmi user list.
425 userUpdateHelper(usrAccess, UserUpdateEvent::userCreated,
426 userName, priv, enabled, newUserName);
427 }
428 }
429 else if (userEvent != UserUpdateEvent::reservedEvent)
430 {
431 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
432 newUserName);
433 }
434 }
435 }
436 else if (userEvent != UserUpdateEvent::reservedEvent)
437 {
438 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
439 newUserName);
440 }
441 return;
442}
443
444UserAccess::~UserAccess()
445{
446 if (signalHndlrObject)
447 {
448 userUpdatedSignal.reset();
449 userMgrRenamedSignal.reset();
450 userPropertiesSignal.reset();
451 sigHndlrLock.unlock();
452 }
453}
454
455UserAccess::UserAccess() : bus(ipmid_get_sd_bus_connection())
456{
457 std::ofstream mutexCleanUpFile;
458 mutexCleanUpFile.open(ipmiMutexCleanupLockFile,
459 std::ofstream::out | std::ofstream::app);
460 if (!mutexCleanUpFile.good())
461 {
462 log<level::DEBUG>("Unable to open mutex cleanup file");
463 return;
464 }
465 mutexCleanUpFile.close();
466 mutexCleanupLock = boost::interprocess::file_lock(ipmiMutexCleanupLockFile);
467 if (mutexCleanupLock.try_lock())
468 {
469 boost::interprocess::named_recursive_mutex::remove(ipmiUserMutex);
470 }
471 mutexCleanupLock.lock_sharable();
472 userMutex = std::make_unique<boost::interprocess::named_recursive_mutex>(
473 boost::interprocess::open_or_create, ipmiUserMutex);
474
475 initUserDataFile();
476 getSystemPrivAndGroups();
477 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
478 // Register it for single object and single process either netipimd /
479 // host-ipmid
480 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
481 {
482 log<level::DEBUG>("Registering signal handler");
483 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
484 bus,
485 sdbusplus::bus::match::rules::type::signal() +
486 sdbusplus::bus::match::rules::interface(dBusObjManager) +
487 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
488 [&](sdbusplus::message::message& msg) {
489 userUpdatedSignalHandler(*this, msg);
490 });
491 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
492 bus,
493 sdbusplus::bus::match::rules::type::signal() +
494 sdbusplus::bus::match::rules::interface(userMgrInterface) +
495 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
496 [&](sdbusplus::message::message& msg) {
497 userUpdatedSignalHandler(*this, msg);
498 });
499 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
500 bus,
501 sdbusplus::bus::match::rules::type::signal() +
502 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
503 sdbusplus::bus::match::rules::interface(
504 dBusPropertiesInterface) +
505 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
506 sdbusplus::bus::match::rules::argN(0, usersInterface),
507 [&](sdbusplus::message::message& msg) {
508 userUpdatedSignalHandler(*this, msg);
509 });
510 signalHndlrObject = true;
511 }
512}
513
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530514UserInfo* UserAccess::getUserInfo(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530515{
516 checkAndReloadUserData();
517 return &usersTbl.user[userId];
518}
519
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530520void UserAccess::setUserInfo(const uint8_t userId, UserInfo* userInfo)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530521{
522 checkAndReloadUserData();
523 std::copy(reinterpret_cast<uint8_t*>(userInfo),
524 reinterpret_cast<uint8_t*>(userInfo) + sizeof(*userInfo),
525 reinterpret_cast<uint8_t*>(&usersTbl.user[userId]));
526 writeUserData();
527}
528
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530529bool UserAccess::isValidChannel(const uint8_t chNum)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530530{
531 return (chNum < ipmiMaxChannels);
532}
533
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530534bool UserAccess::isValidUserId(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530535{
536 return ((userId <= ipmiMaxUsers) && (userId != reservedUserId));
537}
538
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530539bool UserAccess::isValidPrivilege(const uint8_t priv)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530540{
541 return ((priv >= PRIVILEGE_CALLBACK && priv <= PRIVILEGE_OEM) ||
542 priv == privNoAccess);
543}
544
545uint8_t UserAccess::getUsrMgmtSyncIndex()
546{
547 // TODO: Need to get LAN1 channel number dynamically,
548 // which has to be in sync with system user privilege
549 // level(Phosphor-user-manager). Note: For time being chanLan1 is marked as
550 // sync index to the user-manager privilege..
551 return static_cast<uint8_t>(EChannelID::chanLan1);
552}
553
554CommandPrivilege UserAccess::convertToIPMIPrivilege(const std::string& value)
555{
556 auto iter = std::find(ipmiPrivIndex.begin(), ipmiPrivIndex.end(), value);
557 if (iter == ipmiPrivIndex.end())
558 {
559 if (value == "")
560 {
561 return static_cast<CommandPrivilege>(privNoAccess);
562 }
563 log<level::ERR>("Error in converting to IPMI privilege",
564 entry("PRIV=%s", value.c_str()));
565 throw std::out_of_range("Out of range - convertToIPMIPrivilege");
566 }
567 else
568 {
569 return static_cast<CommandPrivilege>(
570 std::distance(ipmiPrivIndex.begin(), iter));
571 }
572}
573
574std::string UserAccess::convertToSystemPrivilege(const CommandPrivilege& value)
575{
576 if (value == static_cast<CommandPrivilege>(privNoAccess))
577 {
578 return "";
579 }
580 try
581 {
582 return ipmiPrivIndex.at(value);
583 }
584 catch (const std::out_of_range& e)
585 {
586 log<level::ERR>("Error in converting to system privilege",
587 entry("PRIV=%d", static_cast<uint8_t>(value)));
588 throw std::out_of_range("Out of range - convertToSystemPrivilege");
589 }
590}
591
592bool UserAccess::isValidUserName(const char* userNameInChar)
593{
594 if (!userNameInChar)
595 {
596 log<level::ERR>("null ptr");
597 return false;
598 }
599 std::string userName(userNameInChar, 0, ipmiMaxUserName);
600 if (!std::regex_match(userName.c_str(),
601 std::regex("[a-zA-z_][a-zA-Z_0-9]*")))
602 {
603 log<level::ERR>("Unsupported characters in user name");
604 return false;
605 }
606 if (userName == "root")
607 {
608 log<level::ERR>("Invalid user name - root");
609 return false;
610 }
611 std::map<DbusUserObjPath, DbusUserObjValue> properties;
612 try
613 {
614 auto method = bus.new_method_call(getUserServiceName().c_str(),
615 userMgrObjBasePath, dBusObjManager,
616 getManagedObjectsMethod);
617 auto reply = bus.call(method);
618 reply.read(properties);
619 }
620 catch (const sdbusplus::exception::SdBusError& e)
621 {
622 log<level::ERR>("Failed to excute method",
623 entry("METHOD=%s", getSubTreeMethod),
624 entry("PATH=%s", userMgrObjBasePath));
625 return false;
626 }
627
628 std::string usersPath = std::string(userObjBasePath) + "/" + userName;
629 if (properties.find(usersPath) != properties.end())
630 {
631 log<level::DEBUG>("User name already exists",
632 entry("USER_NAME=%s", userName.c_str()));
633 return false;
634 }
635
636 return true;
637}
638
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530639/** @brief Information exchanged by pam module and application.
640 *
641 * @param[in] numMsg - length of the array of pointers,msg.
642 *
643 * @param[in] msg - pointer to an array of pointers to pam_message structure
644 *
645 * @param[out] resp - struct pam response array
646 *
647 * @param[in] appdataPtr - member of pam_conv structure
648 *
649 * @return the response in pam response structure.
650 */
651
652static int pamFunctionConversation(int numMsg, const struct pam_message** msg,
653 struct pam_response** resp, void* appdataPtr)
654{
655 if (appdataPtr == nullptr)
656 {
657 return PAM_AUTH_ERR;
658 }
659 size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1;
660 char* pass = reinterpret_cast<char*>(malloc(passSize));
661 std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize);
662
663 *resp = reinterpret_cast<pam_response*>(
664 calloc(numMsg, sizeof(struct pam_response)));
665
666 for (int i = 0; i < numMsg; ++i)
667 {
668 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
669 {
670 continue;
671 }
672 resp[i]->resp = pass;
673 }
674 return PAM_SUCCESS;
675}
676
677/** @brief Updating the PAM password
678 *
679 * @param[in] username - username in string
680 *
681 * @param[in] password - new password in string
682 *
683 * @return status
684 */
685
686bool pamUpdatePasswd(const char* username, const char* password)
687{
688 const struct pam_conv localConversation = {pamFunctionConversation,
689 const_cast<char*>(password)};
690 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
691
692 if (pam_start("passwd", username, &localConversation, &localAuthHandle) !=
693 PAM_SUCCESS)
694 {
695 return false;
696 }
697 int retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
698
699 if (retval != PAM_SUCCESS)
700 {
701 if (retval == PAM_AUTHTOK_ERR)
702 {
703 log<level::DEBUG>("Authentication Failure");
704 }
705 else
706 {
707 log<level::DEBUG>("pam_chauthtok returned failure",
708 entry("ERROR=%d", retval));
709 }
710 pam_end(localAuthHandle, retval);
711 return false;
712 }
713 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
714 {
715 return false;
716 }
717 return true;
718}
719
720ipmi_ret_t UserAccess::setUserPassword(const uint8_t userId,
721 const char* userPassword)
722{
723 std::string userName;
724 if (ipmiUserGetUserName(userId, userName) != IPMI_CC_OK)
725 {
726 log<level::DEBUG>("User Name not found",
727 entry("USER-ID:%d", (uint8_t)userId));
728 return IPMI_CC_PARM_OUT_OF_RANGE;
729 }
730 std::string passwd;
731 passwd.assign(reinterpret_cast<const char*>(userPassword), 0,
732 maxIpmi20PasswordSize);
733 if (!std::regex_match(passwd.c_str(),
734 std::regex("[a-zA-z_0-9][a-zA-Z_0-9,?:`!\"]*")))
735 {
736 log<level::DEBUG>("Invalid password fields",
737 entry("USER-ID:%d", (uint8_t)userId));
738 return IPMI_CC_INVALID_FIELD_REQUEST;
739 }
740 if (!pamUpdatePasswd(userName.c_str(), passwd.c_str()))
741 {
742 log<level::DEBUG>("Failed to update password",
743 entry("USER-ID:%d", (uint8_t)userId));
744 return IPMI_CC_UNSPECIFIED_ERROR;
745 }
746 return IPMI_CC_OK;
747}
748
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530749ipmi_ret_t UserAccess::setUserEnabledState(const uint8_t userId,
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530750 const bool& enabledState)
751{
752 if (!isValidUserId(userId))
753 {
754 return IPMI_CC_PARM_OUT_OF_RANGE;
755 }
756 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
757 userLock{*userMutex};
758 UserInfo* userInfo = getUserInfo(userId);
759 std::string userName;
760 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
761 ipmiMaxUserName);
762 if (userName.empty())
763 {
764 log<level::DEBUG>("User name not set / invalid");
765 return IPMI_CC_UNSPECIFIED_ERROR;
766 }
767 if (userInfo->userEnabled != enabledState)
768 {
769 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800770 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
771 userEnabledProperty, enabledState);
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530772 userInfo->userEnabled = enabledState;
773 try
774 {
775 writeUserData();
776 }
777 catch (const std::exception& e)
778 {
779 log<level::DEBUG>("Write user data failed");
780 return IPMI_CC_UNSPECIFIED_ERROR;
781 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530782 }
783 return IPMI_CC_OK;
784}
785
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530786ipmi_ret_t UserAccess::setUserPrivilegeAccess(const uint8_t userId,
787 const uint8_t chNum,
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530788 const UserPrivAccess& privAccess,
789 const bool& otherPrivUpdates)
790{
791 if (!isValidChannel(chNum))
792 {
793 return IPMI_CC_INVALID_FIELD_REQUEST;
794 }
795 if (!isValidUserId(userId))
796 {
797 return IPMI_CC_PARM_OUT_OF_RANGE;
798 }
799 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
800 userLock{*userMutex};
801 UserInfo* userInfo = getUserInfo(userId);
802 std::string userName;
803 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
804 ipmiMaxUserName);
805 if (userName.empty())
806 {
807 log<level::DEBUG>("User name not set / invalid");
808 return IPMI_CC_UNSPECIFIED_ERROR;
809 }
810 std::string priv = convertToSystemPrivilege(
811 static_cast<CommandPrivilege>(privAccess.privilege));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530812 uint8_t syncIndex = getUsrMgmtSyncIndex();
813 if (chNum == syncIndex &&
814 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
815 {
816 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800817 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
818 userPrivProperty, priv);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530819 }
820 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
821
822 if (otherPrivUpdates)
823 {
824 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
825 userInfo->userPrivAccess[chNum].linkAuthEnabled =
826 privAccess.linkAuthEnabled;
827 userInfo->userPrivAccess[chNum].accessCallback =
828 privAccess.accessCallback;
829 }
830 try
831 {
832 writeUserData();
833 }
834 catch (const std::exception& e)
835 {
836 log<level::DEBUG>("Write user data failed");
837 return IPMI_CC_UNSPECIFIED_ERROR;
838 }
839 return IPMI_CC_OK;
840}
841
842uint8_t UserAccess::getUserId(const std::string& userName)
843{
844 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
845 userLock{*userMutex};
846 checkAndReloadUserData();
847 // user index 0 is reserved, starts with 1
848 size_t usrIndex = 1;
849 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
850 {
851 std::string curName(
852 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
853 ipmiMaxUserName);
854 if (userName == curName)
855 {
856 break; // found the entry
857 }
858 }
859 if (usrIndex > ipmiMaxUsers)
860 {
861 log<level::DEBUG>("User not found",
862 entry("USER_NAME=%s", userName.c_str()));
863 return invalidUserId;
864 }
865
866 return usrIndex;
867}
868
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530869ipmi_ret_t UserAccess::getUserName(const uint8_t userId, std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530870{
871 if (!isValidUserId(userId))
872 {
873 return IPMI_CC_PARM_OUT_OF_RANGE;
874 }
875 UserInfo* userInfo = getUserInfo(userId);
876 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
877 ipmiMaxUserName);
878 return IPMI_CC_OK;
879}
880
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530881ipmi_ret_t UserAccess::setUserName(const uint8_t userId,
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530882 const char* userNameInChar)
883{
884 if (!isValidUserId(userId))
885 {
886 return IPMI_CC_PARM_OUT_OF_RANGE;
887 }
888
889 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
890 userLock{*userMutex};
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530891 std::string oldUser;
892 getUserName(userId, oldUser);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530893
894 std::string newUser(userNameInChar, 0, ipmiMaxUserName);
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530895 if (oldUser == newUser)
896 {
897 // requesting to set the same user name, return success.
898 return IPMI_CC_OK;
899 }
900 bool validUser = isValidUserName(userNameInChar);
901 UserInfo* userInfo = getUserInfo(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530902 if (newUser.empty() && !oldUser.empty())
903 {
904 // Delete existing user
905 std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
906 try
907 {
908 auto method = bus.new_method_call(
909 getUserServiceName().c_str(), userPath.c_str(),
910 deleteUserInterface, deleteUserMethod);
911 auto reply = bus.call(method);
912 }
913 catch (const sdbusplus::exception::SdBusError& e)
914 {
915 log<level::DEBUG>("Failed to excute method",
916 entry("METHOD=%s", deleteUserMethod),
917 entry("PATH=%s", userPath.c_str()));
918 return IPMI_CC_UNSPECIFIED_ERROR;
919 }
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +0530920 deleteUserIndex(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530921 }
922 else if (oldUser.empty() && !newUser.empty() && validUser)
923 {
924 try
925 {
926 // Create new user
927 auto method = bus.new_method_call(
928 getUserServiceName().c_str(), userMgrObjBasePath,
929 userMgrInterface, createUserMethod);
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +0530930 method.append(newUser.c_str(), availableGroups, "", false);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530931 auto reply = bus.call(method);
932 }
933 catch (const sdbusplus::exception::SdBusError& e)
934 {
935 log<level::DEBUG>("Failed to excute method",
936 entry("METHOD=%s", createUserMethod),
937 entry("PATH=%s", userMgrObjBasePath));
938 return IPMI_CC_UNSPECIFIED_ERROR;
939 }
Brad Bishop77ff3fe2018-11-21 15:24:44 -0500940 std::memcpy(userInfo->userName, userNameInChar, ipmiMaxUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530941 userInfo->userInSystem = true;
942 }
943 else if (oldUser != newUser && validUser)
944 {
945 try
946 {
947 // User rename
948 auto method = bus.new_method_call(
949 getUserServiceName().c_str(), userMgrObjBasePath,
950 userMgrInterface, renameUserMethod);
951 method.append(oldUser.c_str(), newUser.c_str());
952 auto reply = bus.call(method);
953 }
954 catch (const sdbusplus::exception::SdBusError& e)
955 {
956 log<level::DEBUG>("Failed to excute method",
957 entry("METHOD=%s", renameUserMethod),
958 entry("PATH=%s", userMgrObjBasePath));
959 return IPMI_CC_UNSPECIFIED_ERROR;
960 }
961 std::fill(static_cast<uint8_t*>(userInfo->userName),
962 static_cast<uint8_t*>(userInfo->userName) +
963 sizeof(userInfo->userName),
964 0);
Brad Bishop77ff3fe2018-11-21 15:24:44 -0500965 std::memcpy(userInfo->userName, userNameInChar, ipmiMaxUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530966 ipmiRenameUserEntryPassword(oldUser, newUser);
967 userInfo->userInSystem = true;
968 }
969 else if (!validUser)
970 {
971 return IPMI_CC_INVALID_FIELD_REQUEST;
972 }
973 try
974 {
975 writeUserData();
976 }
977 catch (const std::exception& e)
978 {
979 log<level::DEBUG>("Write user data failed");
980 return IPMI_CC_UNSPECIFIED_ERROR;
981 }
982 return IPMI_CC_OK;
983}
984
985static constexpr const char* jsonUserName = "user_name";
986static constexpr const char* jsonPriv = "privilege";
987static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
988static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
989static constexpr const char* jsonAccCallbk = "access_callback";
990static constexpr const char* jsonUserEnabled = "user_enabled";
991static constexpr const char* jsonUserInSys = "user_in_system";
992static constexpr const char* jsonFixedUser = "fixed_user_name";
993
994void UserAccess::readUserData()
995{
996 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
997 userLock{*userMutex};
998
999 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
1000 if (!iUsrData.good())
1001 {
1002 log<level::ERR>("Error in reading IPMI user data file");
1003 throw std::ios_base::failure("Error opening IPMI user data file");
1004 }
1005
1006 Json jsonUsersTbl = Json::array();
1007 jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
1008
1009 if (jsonUsersTbl.size() != ipmiMaxUsers)
1010 {
1011 log<level::ERR>(
1012 "Error in reading IPMI user data file - User count issues");
1013 throw std::runtime_error(
1014 "Corrupted IPMI user data file - invalid user count");
1015 }
1016 // user index 0 is reserved, starts with 1
1017 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1018 {
1019 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
1020 if (userInfo.is_null())
1021 {
1022 log<level::ERR>("Error in reading IPMI user data file - "
1023 "user info corrupted");
1024 throw std::runtime_error(
1025 "Corrupted IPMI user data file - invalid user info");
1026 }
1027 std::string userName = userInfo[jsonUserName].get<std::string>();
1028 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
1029 userName.c_str(), ipmiMaxUserName);
1030
1031 std::vector<std::string> privilege =
1032 userInfo[jsonPriv].get<std::vector<std::string>>();
1033 std::vector<bool> ipmiEnabled =
1034 userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
1035 std::vector<bool> linkAuthEnabled =
1036 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
1037 std::vector<bool> accessCallback =
1038 userInfo[jsonAccCallbk].get<std::vector<bool>>();
1039 if (privilege.size() != ipmiMaxChannels ||
1040 ipmiEnabled.size() != ipmiMaxChannels ||
1041 linkAuthEnabled.size() != ipmiMaxChannels ||
1042 accessCallback.size() != ipmiMaxChannels)
1043 {
1044 log<level::ERR>("Error in reading IPMI user data file - "
1045 "properties corrupted");
1046 throw std::runtime_error(
1047 "Corrupted IPMI user data file - properties");
1048 }
1049 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1050 {
1051 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
1052 static_cast<uint8_t>(
1053 convertToIPMIPrivilege(privilege[chIndex]));
1054 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
1055 ipmiEnabled[chIndex];
1056 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
1057 linkAuthEnabled[chIndex];
1058 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
1059 accessCallback[chIndex];
1060 }
1061 usersTbl.user[usrIndex].userEnabled =
1062 userInfo[jsonUserEnabled].get<bool>();
1063 usersTbl.user[usrIndex].userInSystem =
1064 userInfo[jsonUserInSys].get<bool>();
1065 usersTbl.user[usrIndex].fixedUserName =
1066 userInfo[jsonFixedUser].get<bool>();
1067 }
1068
1069 log<level::DEBUG>("User data read from IPMI data file");
1070 iUsrData.close();
1071 // Update the timestamp
1072 fileLastUpdatedTime = getUpdatedFileTime();
1073 return;
1074}
1075
1076void UserAccess::writeUserData()
1077{
1078 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1079 userLock{*userMutex};
1080
1081 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
1082 std::ofstream oUsrData(tmpFile, std::ios::out | std::ios::binary);
1083 if (!oUsrData.good())
1084 {
1085 log<level::ERR>("Error in creating temporary IPMI user data file");
1086 throw std::ios_base::failure(
1087 "Error in creating temporary IPMI user data file");
1088 }
1089
1090 Json jsonUsersTbl = Json::array();
1091 // user index 0 is reserved, starts with 1
1092 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1093 {
1094 Json jsonUserInfo;
1095 jsonUserInfo[jsonUserName] = std::string(
1096 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
1097 ipmiMaxUserName);
1098 std::vector<std::string> privilege(ipmiMaxChannels);
1099 std::vector<bool> ipmiEnabled(ipmiMaxChannels);
1100 std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
1101 std::vector<bool> accessCallback(ipmiMaxChannels);
1102 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1103 {
1104 privilege[chIndex] =
1105 convertToSystemPrivilege(static_cast<CommandPrivilege>(
1106 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
1107 ipmiEnabled[chIndex] =
1108 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
1109 linkAuthEnabled[chIndex] =
1110 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
1111 accessCallback[chIndex] =
1112 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
1113 }
1114 jsonUserInfo[jsonPriv] = privilege;
1115 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
1116 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
1117 jsonUserInfo[jsonAccCallbk] = accessCallback;
1118 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1119 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1120 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
1121 jsonUsersTbl.push_back(jsonUserInfo);
1122 }
1123
1124 oUsrData << jsonUsersTbl;
1125 oUsrData.flush();
1126 oUsrData.close();
1127
1128 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1129 {
1130 log<level::ERR>("Error in renaming temporary IPMI user data file");
1131 throw std::runtime_error("Error in renaming IPMI user data file");
1132 }
1133 // Update the timestamp
1134 fileLastUpdatedTime = getUpdatedFileTime();
1135 return;
1136}
1137
1138bool UserAccess::addUserEntry(const std::string& userName,
1139 const std::string& sysPriv, const bool& enabled)
1140{
1141 UsersTbl* userData = getUsersTblPtr();
1142 size_t freeIndex = 0xFF;
1143 // user index 0 is reserved, starts with 1
1144 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1145 {
1146 std::string curName(
1147 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1148 ipmiMaxUserName);
1149 if (userName == curName)
1150 {
1151 log<level::DEBUG>("User name exists",
1152 entry("USER_NAME=%s", userName.c_str()));
1153 return false; // user name exists.
1154 }
1155
1156 if ((!userData->user[usrIndex].userInSystem) &&
1157 (userData->user[usrIndex].userName[0] == '\0') &&
1158 (freeIndex == 0xFF))
1159 {
1160 freeIndex = usrIndex;
1161 }
1162 }
1163 if (freeIndex == 0xFF)
1164 {
1165 log<level::ERR>("No empty slots found");
1166 return false;
1167 }
1168 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1169 userName.c_str(), ipmiMaxUserName);
1170 uint8_t priv =
1171 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1172 privMask;
1173 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1174 {
1175 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1176 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1177 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1178 true;
1179 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1180 }
1181 userData->user[freeIndex].userInSystem = true;
1182 userData->user[freeIndex].userEnabled = enabled;
1183
1184 return true;
1185}
1186
1187void UserAccess::deleteUserIndex(const size_t& usrIdx)
1188{
1189 UsersTbl* userData = getUsersTblPtr();
1190
1191 std::string userName(
1192 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1193 ipmiMaxUserName);
1194 ipmiClearUserEntryPassword(userName);
1195 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1196 static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1197 sizeof(userData->user[usrIdx].userName),
1198 0);
1199 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1200 {
1201 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1202 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1203 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1204 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1205 }
1206 userData->user[usrIdx].userInSystem = false;
1207 userData->user[usrIdx].userEnabled = false;
1208 return;
1209}
1210
1211void UserAccess::checkAndReloadUserData()
1212{
1213 std::time_t updateTime = getUpdatedFileTime();
1214 if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1215 {
1216 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1217 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1218 readUserData();
1219 }
1220 return;
1221}
1222
1223UsersTbl* UserAccess::getUsersTblPtr()
1224{
1225 // reload data before using it.
1226 checkAndReloadUserData();
1227 return &usersTbl;
1228}
1229
1230void UserAccess::getSystemPrivAndGroups()
1231{
1232 std::map<std::string, PrivAndGroupType> properties;
1233 try
1234 {
1235 auto method = bus.new_method_call(
1236 getUserServiceName().c_str(), userMgrObjBasePath,
1237 dBusPropertiesInterface, getAllPropertiesMethod);
1238 method.append(userMgrInterface);
1239
1240 auto reply = bus.call(method);
1241 reply.read(properties);
1242 }
1243 catch (const sdbusplus::exception::SdBusError& e)
1244 {
1245 log<level::DEBUG>("Failed to excute method",
1246 entry("METHOD=%s", getAllPropertiesMethod),
1247 entry("PATH=%s", userMgrObjBasePath));
1248 return;
1249 }
1250 for (const auto& t : properties)
1251 {
1252 auto key = t.first;
1253 if (key == allPrivProperty)
1254 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001255 availablePrivileges =
1256 variant_ns::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301257 }
1258 else if (key == allGrpProperty)
1259 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001260 availableGroups =
1261 variant_ns::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301262 }
1263 }
1264 // TODO: Implement Supported Privilege & Groups verification logic
1265 return;
1266}
1267
1268std::time_t UserAccess::getUpdatedFileTime()
1269{
1270 struct stat fileStat;
1271 if (stat(ipmiUserDataFile, &fileStat) != 0)
1272 {
1273 log<level::DEBUG>("Error in getting last updated time stamp");
1274 return -EIO;
1275 }
1276 return fileStat.st_mtime;
1277}
1278
1279void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1280 std::vector<std::string>& usrGrps,
1281 std::string& usrPriv, bool& usrEnabled)
1282{
1283 for (const auto& t : properties)
1284 {
1285 std::string key = t.first;
1286 if (key == userPrivProperty)
1287 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001288 usrPriv = variant_ns::get<std::string>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301289 }
1290 else if (key == userGrpProperty)
1291 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001292 usrGrps = variant_ns::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301293 }
1294 else if (key == userEnabledProperty)
1295 {
William A. Kennington IIIdfad4862018-11-19 17:45:35 -08001296 usrEnabled = variant_ns::get<bool>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301297 }
1298 }
1299 return;
1300}
1301
1302int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1303 std::vector<std::string>& usrGrps,
1304 std::string& usrPriv, bool& usrEnabled)
1305{
1306 auto usrObj = userObjs.find(usersInterface);
1307 if (usrObj != userObjs.end())
1308 {
1309 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1310 return 0;
1311 }
1312 return -EIO;
1313}
1314
1315void UserAccess::initUserDataFile()
1316{
1317 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1318 userLock{*userMutex};
1319 try
1320 {
1321 readUserData();
1322 }
1323 catch (const std::ios_base::failure& e)
1324 { // File is empty, create it for the first time
1325 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1326 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1327 // user index 0 is reserved, starts with 1
1328 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1329 {
1330 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1331 {
1332 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1333 privNoAccess;
1334 }
1335 }
1336 writeUserData();
1337 }
1338 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1339 try
1340 {
1341 auto method = bus.new_method_call(getUserServiceName().c_str(),
1342 userMgrObjBasePath, dBusObjManager,
1343 getManagedObjectsMethod);
1344 auto reply = bus.call(method);
1345 reply.read(managedObjs);
1346 }
1347 catch (const sdbusplus::exception::SdBusError& e)
1348 {
1349 log<level::DEBUG>("Failed to excute method",
1350 entry("METHOD=%s", getSubTreeMethod),
1351 entry("PATH=%s", userMgrObjBasePath));
1352 return;
1353 }
1354
1355 UsersTbl* userData = &usersTbl;
1356 // user index 0 is reserved, starts with 1
1357 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1358 {
1359 if ((userData->user[usrIdx].userInSystem) &&
1360 (userData->user[usrIdx].userName[0] != '\0'))
1361 {
1362 std::vector<std::string> usrGrps;
1363 std::string usrPriv;
1364 bool usrEnabled;
1365
1366 std::string userName(
1367 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1368 ipmiMaxUserName);
1369 std::string usersPath =
1370 std::string(userObjBasePath) + "/" + userName;
1371
1372 auto usrObj = managedObjs.find(usersPath);
1373 if (usrObj != managedObjs.end())
1374 {
1375 // User exist. Lets check and update other fileds
1376 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1377 usrEnabled);
1378 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1379 usrGrps.end())
1380 {
1381 // Group "ipmi" is removed so lets remove user in IPMI
1382 deleteUserIndex(usrIdx);
1383 }
1384 else
1385 {
1386 // Group "ipmi" is present so lets update other properties
1387 // in IPMI
1388 uint8_t priv =
1389 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1390 // Update all channels priv, only if it is not equivalent to
1391 // getUsrMgmtSyncIndex()
1392 if (userData->user[usrIdx]
1393 .userPrivAccess[getUsrMgmtSyncIndex()]
1394 .privilege != priv)
1395 {
1396 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1397 ++chIndex)
1398 {
1399 userData->user[usrIdx]
1400 .userPrivAccess[chIndex]
1401 .privilege = priv;
1402 }
1403 }
1404 if (userData->user[usrIdx].userEnabled != usrEnabled)
1405 {
1406 userData->user[usrIdx].userEnabled = usrEnabled;
1407 }
1408 }
1409
1410 // We are done with this obj. lets delete from MAP
1411 managedObjs.erase(usrObj);
1412 }
1413 else
1414 {
1415 deleteUserIndex(usrIdx);
1416 }
1417 }
1418 }
1419
1420 // Walk through remnaining managedObj users list
1421 // Add them to ipmi data base
1422 for (const auto& usrObj : managedObjs)
1423 {
1424 std::vector<std::string> usrGrps;
1425 std::string usrPriv, userName;
1426 bool usrEnabled;
1427 std::string usrObjPath = std::string(usrObj.first);
1428 if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1429 {
1430 log<level::ERR>("Error in user object path");
1431 continue;
1432 }
1433 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1434 // Add 'ipmi' group users
1435 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1436 usrGrps.end())
1437 {
1438 // CREATE NEW USER
1439 if (true != addUserEntry(userName, usrPriv, usrEnabled))
1440 {
1441 break;
1442 }
1443 }
1444 }
1445
1446 // All userData slots update done. Lets write the data
1447 writeUserData();
1448
1449 return;
1450}
1451} // namespace ipmi