blob: 6b31eb92117d9c779df8d5811c841a6b78d12bb6 [file] [log] [blame]
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include "user_mgmt.hpp"
17
18#include "apphandler.hpp"
Saravanan Palanisamy77381f12019-05-15 22:33:17 +000019#include "channel_layer.hpp"
Johnathan Manteyfd61fc32021-04-08 11:05:38 -070020#include "channel_mgmt.hpp"
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053021
Suryakanth Sekar90b00c72019-01-16 10:37:57 +053022#include <security/pam_appl.h>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053023#include <sys/stat.h>
24#include <unistd.h>
25
26#include <boost/interprocess/sync/named_recursive_mutex.hpp>
27#include <boost/interprocess/sync/scoped_lock.hpp>
28#include <cerrno>
29#include <fstream>
Snehalatha Venkatesh745164c2021-06-25 10:02:25 +000030#include <ipmid/types.hpp>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053031#include <nlohmann/json.hpp>
32#include <phosphor-logging/elog-errors.hpp>
33#include <phosphor-logging/log.hpp>
34#include <regex>
35#include <sdbusplus/bus/match.hpp>
36#include <sdbusplus/server/object.hpp>
Vernon Mauery16b86932019-05-01 08:36:11 -070037#include <variant>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053038#include <xyz/openbmc_project/Common/error.hpp>
39#include <xyz/openbmc_project/User/Common/error.hpp>
40
41namespace ipmi
42{
43
44// TODO: Move D-Bus & Object Manager related stuff, to common files
45// D-Bus property related
46static constexpr const char* dBusPropertiesInterface =
47 "org.freedesktop.DBus.Properties";
48static constexpr const char* getAllPropertiesMethod = "GetAll";
49static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
50static constexpr const char* setPropertiesMethod = "Set";
51
52// Object Manager related
53static constexpr const char* dBusObjManager =
54 "org.freedesktop.DBus.ObjectManager";
55static constexpr const char* getManagedObjectsMethod = "GetManagedObjects";
56// Object Manager signals
57static constexpr const char* intfAddedSignal = "InterfacesAdded";
58static constexpr const char* intfRemovedSignal = "InterfacesRemoved";
59
60// Object Mapper related
61static constexpr const char* objMapperService =
62 "xyz.openbmc_project.ObjectMapper";
63static constexpr const char* objMapperPath =
64 "/xyz/openbmc_project/object_mapper";
65static constexpr const char* objMapperInterface =
66 "xyz.openbmc_project.ObjectMapper";
67static constexpr const char* getSubTreeMethod = "GetSubTree";
68static constexpr const char* getObjectMethod = "GetObject";
69
70static constexpr const char* ipmiUserMutex = "ipmi_usr_mutex";
71static constexpr const char* ipmiMutexCleanupLockFile =
72 "/var/lib/ipmi/ipmi_usr_mutex_cleanup";
73static constexpr const char* ipmiUserDataFile = "/var/lib/ipmi/ipmi_user.json";
74static constexpr const char* ipmiGrpName = "ipmi";
75static constexpr size_t privNoAccess = 0xF;
76static constexpr size_t privMask = 0xF;
77
78// User manager related
79static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user";
80static constexpr const char* userObjBasePath = "/xyz/openbmc_project/user";
81static constexpr const char* userMgrInterface =
82 "xyz.openbmc_project.User.Manager";
83static constexpr const char* usersInterface =
84 "xyz.openbmc_project.User.Attributes";
85static constexpr const char* deleteUserInterface =
86 "xyz.openbmc_project.Object.Delete";
87
88static constexpr const char* createUserMethod = "CreateUser";
89static constexpr const char* deleteUserMethod = "Delete";
90static constexpr const char* renameUserMethod = "RenameUser";
91// User manager signal memebers
92static constexpr const char* userRenamedSignal = "UserRenamed";
93// Mgr interface properties
94static constexpr const char* allPrivProperty = "AllPrivileges";
95static constexpr const char* allGrpProperty = "AllGroups";
96// User interface properties
97static constexpr const char* userPrivProperty = "UserPrivilege";
98static constexpr const char* userGrpProperty = "UserGroups";
99static constexpr const char* userEnabledProperty = "UserEnabled";
100
101static std::array<std::string, (PRIVILEGE_OEM + 1)> ipmiPrivIndex = {
102 "priv-reserved", // PRIVILEGE_RESERVED - 0
103 "priv-callback", // PRIVILEGE_CALLBACK - 1
104 "priv-user", // PRIVILEGE_USER - 2
105 "priv-operator", // PRIVILEGE_OPERATOR - 3
106 "priv-admin", // PRIVILEGE_ADMIN - 4
107 "priv-custom" // PRIVILEGE_OEM - 5
108};
109
110using namespace phosphor::logging;
111using Json = nlohmann::json;
112
Vernon Mauery16b86932019-05-01 08:36:11 -0700113using PrivAndGroupType = std::variant<std::string, std::vector<std::string>>;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530114
115using NoResource =
116 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource;
117
118using InternalFailure =
119 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
120
Lei YU4b0ddb62019-01-25 16:43:50 +0800121std::unique_ptr<sdbusplus::bus::match_t> userUpdatedSignal
122 __attribute__((init_priority(101)));
123std::unique_ptr<sdbusplus::bus::match_t> userMgrRenamedSignal
124 __attribute__((init_priority(101)));
125std::unique_ptr<sdbusplus::bus::match_t> userPropertiesSignal
126 __attribute__((init_priority(101)));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530127
128// TODO: Below code can be removed once it is moved to common layer libmiscutil
129std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf,
130 const std::string& path)
131{
132 auto mapperCall = bus.new_method_call(objMapperService, objMapperPath,
133 objMapperInterface, getObjectMethod);
134
135 mapperCall.append(path);
136 mapperCall.append(std::vector<std::string>({intf}));
137
138 auto mapperResponseMsg = bus.call(mapperCall);
139
140 std::map<std::string, std::vector<std::string>> mapperResponse;
141 mapperResponseMsg.read(mapperResponse);
142
143 if (mapperResponse.begin() == mapperResponse.end())
144 {
145 throw sdbusplus::exception::SdBusError(
146 -EIO, "ERROR in reading the mapper response");
147 }
148
149 return mapperResponse.begin()->first;
150}
151
152void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service,
153 const std::string& objPath, const std::string& interface,
154 const std::string& property,
155 const DbusUserPropVariant& value)
156{
157 try
158 {
159 auto method =
160 bus.new_method_call(service.c_str(), objPath.c_str(),
161 dBusPropertiesInterface, setPropertiesMethod);
162 method.append(interface, property, value);
163 bus.call(method);
164 }
165 catch (const sdbusplus::exception::SdBusError& e)
166 {
167 log<level::ERR>("Failed to set property",
168 entry("PROPERTY=%s", property.c_str()),
169 entry("PATH=%s", objPath.c_str()),
170 entry("INTERFACE=%s", interface.c_str()));
171 throw;
172 }
173}
174
175static std::string getUserServiceName()
176{
177 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
178 static std::string userMgmtService;
179 if (userMgmtService.empty())
180 {
181 try
182 {
183 userMgmtService =
184 ipmi::getUserService(bus, userMgrInterface, userMgrObjBasePath);
185 }
186 catch (const sdbusplus::exception::SdBusError& e)
187 {
188 userMgmtService.clear();
189 }
190 }
191 return userMgmtService;
192}
193
194UserAccess& getUserAccessObject()
195{
196 static UserAccess userAccess;
197 return userAccess;
198}
199
200int getUserNameFromPath(const std::string& path, std::string& userName)
201{
Richard Marian Thomaiyare3d144f2020-01-09 11:55:06 +0530202 constexpr size_t length = strlen(userObjBasePath);
203 if (((length + 1) >= path.size()) ||
204 path.compare(0, length, userObjBasePath))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530205 {
206 return -EINVAL;
207 }
Richard Marian Thomaiyare3d144f2020-01-09 11:55:06 +0530208 userName.assign(path, length + 1, path.size());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530209 return 0;
210}
211
212void userUpdateHelper(UserAccess& usrAccess, const UserUpdateEvent& userEvent,
213 const std::string& userName, const std::string& priv,
214 const bool& enabled, const std::string& newUserName)
215{
216 UsersTbl* userData = usrAccess.getUsersTblPtr();
217 if (userEvent == UserUpdateEvent::userCreated)
218 {
219 if (usrAccess.addUserEntry(userName, priv, enabled) == false)
220 {
221 return;
222 }
223 }
224 else
225 {
226 // user index 0 is reserved, starts with 1
227 size_t usrIndex = 1;
228 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
229 {
230 std::string curName(
231 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
232 ipmiMaxUserName);
233 if (userName == curName)
234 {
235 break; // found the entry
236 }
237 }
238 if (usrIndex > ipmiMaxUsers)
239 {
240 log<level::DEBUG>("User not found for signal",
241 entry("USER_NAME=%s", userName.c_str()),
242 entry("USER_EVENT=%d", userEvent));
243 return;
244 }
245 switch (userEvent)
246 {
247 case UserUpdateEvent::userDeleted:
248 {
249 usrAccess.deleteUserIndex(usrIndex);
250 break;
251 }
252 case UserUpdateEvent::userPrivUpdated:
253 {
254 uint8_t userPriv =
255 static_cast<uint8_t>(
256 UserAccess::convertToIPMIPrivilege(priv)) &
257 privMask;
258 // Update all channels privileges, only if it is not equivalent
259 // to getUsrMgmtSyncIndex()
260 if (userData->user[usrIndex]
261 .userPrivAccess[UserAccess::getUsrMgmtSyncIndex()]
262 .privilege != userPriv)
263 {
264 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
265 ++chIndex)
266 {
267 userData->user[usrIndex]
268 .userPrivAccess[chIndex]
269 .privilege = userPriv;
270 }
271 }
272 break;
273 }
274 case UserUpdateEvent::userRenamed:
275 {
276 std::fill(
277 static_cast<uint8_t*>(userData->user[usrIndex].userName),
278 static_cast<uint8_t*>(userData->user[usrIndex].userName) +
279 sizeof(userData->user[usrIndex].userName),
280 0);
281 std::strncpy(
282 reinterpret_cast<char*>(userData->user[usrIndex].userName),
283 newUserName.c_str(), ipmiMaxUserName);
284 ipmiRenameUserEntryPassword(userName, newUserName);
285 break;
286 }
287 case UserUpdateEvent::userStateUpdated:
288 {
289 userData->user[usrIndex].userEnabled = enabled;
290 break;
291 }
292 default:
293 {
294 log<level::ERR>("Unhandled user event",
295 entry("USER_EVENT=%d", userEvent));
296 return;
297 }
298 }
299 }
300 usrAccess.writeUserData();
301 log<level::DEBUG>("User event handled successfully",
302 entry("USER_NAME=%s", userName.c_str()),
303 entry("USER_EVENT=%d", userEvent));
304
305 return;
306}
307
308void userUpdatedSignalHandler(UserAccess& usrAccess,
309 sdbusplus::message::message& msg)
310{
311 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
312 std::string signal = msg.get_member();
Patrick Venture3a697ad2019-08-19 11:12:05 -0700313 std::string userName, priv, newUserName;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530314 std::vector<std::string> groups;
315 bool enabled = false;
316 UserUpdateEvent userEvent = UserUpdateEvent::reservedEvent;
317 if (signal == intfAddedSignal)
318 {
319 DbusUserObjPath objPath;
320 DbusUserObjValue objValue;
321 msg.read(objPath, objValue);
322 getUserNameFromPath(objPath.str, userName);
323 if (usrAccess.getUserObjProperties(objValue, groups, priv, enabled) !=
324 0)
325 {
326 return;
327 }
328 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
329 groups.end())
330 {
331 return;
332 }
333 userEvent = UserUpdateEvent::userCreated;
334 }
335 else if (signal == intfRemovedSignal)
336 {
337 DbusUserObjPath objPath;
338 std::vector<std::string> interfaces;
339 msg.read(objPath, interfaces);
340 getUserNameFromPath(objPath.str, userName);
341 userEvent = UserUpdateEvent::userDeleted;
342 }
343 else if (signal == userRenamedSignal)
344 {
345 msg.read(userName, newUserName);
346 userEvent = UserUpdateEvent::userRenamed;
347 }
348 else if (signal == propertiesChangedSignal)
349 {
350 getUserNameFromPath(msg.get_path(), userName);
351 }
352 else
353 {
354 log<level::ERR>("Unknown user update signal",
355 entry("SIGNAL=%s", signal.c_str()));
356 return;
357 }
358
359 if (signal.empty() || userName.empty() ||
360 (signal == userRenamedSignal && newUserName.empty()))
361 {
362 log<level::ERR>("Invalid inputs received");
363 return;
364 }
365
366 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
367 userLock{*(usrAccess.userMutex)};
368 usrAccess.checkAndReloadUserData();
369
370 if (signal == propertiesChangedSignal)
371 {
372 std::string intfName;
373 DbusUserObjProperties chProperties;
374 msg.read(intfName, chProperties); // skip reading 3rd argument.
375 for (const auto& prop : chProperties)
376 {
377 userEvent = UserUpdateEvent::reservedEvent;
378 std::string member = prop.first;
379 if (member == userPrivProperty)
380 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700381 priv = std::get<std::string>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530382 userEvent = UserUpdateEvent::userPrivUpdated;
383 }
384 else if (member == userGrpProperty)
385 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700386 groups = std::get<std::vector<std::string>>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530387 userEvent = UserUpdateEvent::userGrpUpdated;
388 }
389 else if (member == userEnabledProperty)
390 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700391 enabled = std::get<bool>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530392 userEvent = UserUpdateEvent::userStateUpdated;
393 }
394 // Process based on event type.
395 if (userEvent == UserUpdateEvent::userGrpUpdated)
396 {
397 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
398 groups.end())
399 {
400 // remove user from ipmi user list.
401 userUpdateHelper(usrAccess, UserUpdateEvent::userDeleted,
402 userName, priv, enabled, newUserName);
403 }
404 else
405 {
406 DbusUserObjProperties properties;
407 try
408 {
409 auto method = bus.new_method_call(
410 getUserServiceName().c_str(), msg.get_path(),
411 dBusPropertiesInterface, getAllPropertiesMethod);
412 method.append(usersInterface);
413 auto reply = bus.call(method);
414 reply.read(properties);
415 }
416 catch (const sdbusplus::exception::SdBusError& e)
417 {
418 log<level::DEBUG>(
419 "Failed to excute method",
420 entry("METHOD=%s", getAllPropertiesMethod),
421 entry("PATH=%s", msg.get_path()));
422 return;
423 }
424 usrAccess.getUserProperties(properties, groups, priv,
425 enabled);
426 // add user to ipmi user list.
427 userUpdateHelper(usrAccess, UserUpdateEvent::userCreated,
428 userName, priv, enabled, newUserName);
429 }
430 }
431 else if (userEvent != UserUpdateEvent::reservedEvent)
432 {
433 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
434 newUserName);
435 }
436 }
437 }
438 else if (userEvent != UserUpdateEvent::reservedEvent)
439 {
440 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
441 newUserName);
442 }
443 return;
444}
445
446UserAccess::~UserAccess()
447{
448 if (signalHndlrObject)
449 {
450 userUpdatedSignal.reset();
451 userMgrRenamedSignal.reset();
452 userPropertiesSignal.reset();
453 sigHndlrLock.unlock();
454 }
455}
456
457UserAccess::UserAccess() : bus(ipmid_get_sd_bus_connection())
458{
459 std::ofstream mutexCleanUpFile;
460 mutexCleanUpFile.open(ipmiMutexCleanupLockFile,
461 std::ofstream::out | std::ofstream::app);
462 if (!mutexCleanUpFile.good())
463 {
464 log<level::DEBUG>("Unable to open mutex cleanup file");
465 return;
466 }
467 mutexCleanUpFile.close();
468 mutexCleanupLock = boost::interprocess::file_lock(ipmiMutexCleanupLockFile);
469 if (mutexCleanupLock.try_lock())
470 {
471 boost::interprocess::named_recursive_mutex::remove(ipmiUserMutex);
472 }
473 mutexCleanupLock.lock_sharable();
474 userMutex = std::make_unique<boost::interprocess::named_recursive_mutex>(
475 boost::interprocess::open_or_create, ipmiUserMutex);
476
arun-pmbbe728c2020-01-10 15:18:04 +0530477 cacheUserDataFile();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530478 getSystemPrivAndGroups();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530479}
480
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530481UserInfo* UserAccess::getUserInfo(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530482{
483 checkAndReloadUserData();
484 return &usersTbl.user[userId];
485}
486
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530487void UserAccess::setUserInfo(const uint8_t userId, UserInfo* userInfo)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530488{
489 checkAndReloadUserData();
490 std::copy(reinterpret_cast<uint8_t*>(userInfo),
491 reinterpret_cast<uint8_t*>(userInfo) + sizeof(*userInfo),
492 reinterpret_cast<uint8_t*>(&usersTbl.user[userId]));
493 writeUserData();
494}
495
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530496bool UserAccess::isValidChannel(const uint8_t chNum)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530497{
498 return (chNum < ipmiMaxChannels);
499}
500
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530501bool UserAccess::isValidUserId(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530502{
503 return ((userId <= ipmiMaxUsers) && (userId != reservedUserId));
504}
505
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530506bool UserAccess::isValidPrivilege(const uint8_t priv)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530507{
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000508 // Callback privilege is deprecated in OpenBMC
509 return (isValidPrivLimit(priv) || priv == privNoAccess);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530510}
511
512uint8_t UserAccess::getUsrMgmtSyncIndex()
513{
Johnathan Manteyfd61fc32021-04-08 11:05:38 -0700514 // Identify the IPMI channel used to assign system user privilege levels
515 // in phosphor-user-manager. The default value is IPMI Channel 1. To
516 // assign a different channel add:
517 // "is_management_nic" : true
518 // into the channel_config.json file describing the assignment of the IPMI
519 // channels. It is only necessary to add the string above to ONE record in
520 // the channel_config.json file. All other records will be automatically
521 // assigned a "false" value.
522 return getChannelConfigObject().getManagementNICID();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530523}
524
525CommandPrivilege UserAccess::convertToIPMIPrivilege(const std::string& value)
526{
527 auto iter = std::find(ipmiPrivIndex.begin(), ipmiPrivIndex.end(), value);
528 if (iter == ipmiPrivIndex.end())
529 {
530 if (value == "")
531 {
532 return static_cast<CommandPrivilege>(privNoAccess);
533 }
534 log<level::ERR>("Error in converting to IPMI privilege",
535 entry("PRIV=%s", value.c_str()));
536 throw std::out_of_range("Out of range - convertToIPMIPrivilege");
537 }
538 else
539 {
540 return static_cast<CommandPrivilege>(
541 std::distance(ipmiPrivIndex.begin(), iter));
542 }
543}
544
545std::string UserAccess::convertToSystemPrivilege(const CommandPrivilege& value)
546{
547 if (value == static_cast<CommandPrivilege>(privNoAccess))
548 {
549 return "";
550 }
551 try
552 {
553 return ipmiPrivIndex.at(value);
554 }
555 catch (const std::out_of_range& e)
556 {
557 log<level::ERR>("Error in converting to system privilege",
558 entry("PRIV=%d", static_cast<uint8_t>(value)));
559 throw std::out_of_range("Out of range - convertToSystemPrivilege");
560 }
561}
562
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000563bool UserAccess::isValidUserName(const std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530564{
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000565 if (userName.empty())
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530566 {
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000567 log<level::ERR>("userName is empty");
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530568 return false;
569 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530570 if (!std::regex_match(userName.c_str(),
571 std::regex("[a-zA-z_][a-zA-Z_0-9]*")))
572 {
573 log<level::ERR>("Unsupported characters in user name");
574 return false;
575 }
576 if (userName == "root")
577 {
578 log<level::ERR>("Invalid user name - root");
579 return false;
580 }
581 std::map<DbusUserObjPath, DbusUserObjValue> properties;
582 try
583 {
584 auto method = bus.new_method_call(getUserServiceName().c_str(),
585 userMgrObjBasePath, dBusObjManager,
586 getManagedObjectsMethod);
587 auto reply = bus.call(method);
588 reply.read(properties);
589 }
590 catch (const sdbusplus::exception::SdBusError& e)
591 {
592 log<level::ERR>("Failed to excute method",
593 entry("METHOD=%s", getSubTreeMethod),
594 entry("PATH=%s", userMgrObjBasePath));
595 return false;
596 }
597
598 std::string usersPath = std::string(userObjBasePath) + "/" + userName;
599 if (properties.find(usersPath) != properties.end())
600 {
601 log<level::DEBUG>("User name already exists",
602 entry("USER_NAME=%s", userName.c_str()));
603 return false;
604 }
605
606 return true;
607}
608
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530609/** @brief Information exchanged by pam module and application.
610 *
611 * @param[in] numMsg - length of the array of pointers,msg.
612 *
613 * @param[in] msg - pointer to an array of pointers to pam_message structure
614 *
615 * @param[out] resp - struct pam response array
616 *
617 * @param[in] appdataPtr - member of pam_conv structure
618 *
619 * @return the response in pam response structure.
620 */
621
622static int pamFunctionConversation(int numMsg, const struct pam_message** msg,
623 struct pam_response** resp, void* appdataPtr)
624{
625 if (appdataPtr == nullptr)
626 {
627 return PAM_AUTH_ERR;
628 }
629 size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1;
630 char* pass = reinterpret_cast<char*>(malloc(passSize));
631 std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize);
632
633 *resp = reinterpret_cast<pam_response*>(
634 calloc(numMsg, sizeof(struct pam_response)));
635
636 for (int i = 0; i < numMsg; ++i)
637 {
638 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
639 {
640 continue;
641 }
642 resp[i]->resp = pass;
643 }
644 return PAM_SUCCESS;
645}
646
647/** @brief Updating the PAM password
648 *
649 * @param[in] username - username in string
650 *
651 * @param[in] password - new password in string
652 *
653 * @return status
654 */
655
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000656int pamUpdatePasswd(const char* username, const char* password)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530657{
658 const struct pam_conv localConversation = {pamFunctionConversation,
659 const_cast<char*>(password)};
660 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
661
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000662 int retval =
663 pam_start("passwd", username, &localConversation, &localAuthHandle);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530664
665 if (retval != PAM_SUCCESS)
666 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000667 return retval;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530668 }
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000669
670 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
671 if (retval != PAM_SUCCESS)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530672 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000673 pam_end(localAuthHandle, retval);
674 return retval;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530675 }
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000676
677 return pam_end(localAuthHandle, PAM_SUCCESS);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530678}
679
Ayushi Smriti02650d52019-05-15 11:59:09 +0000680bool pamUserCheckAuthenticate(std::string_view username,
681 std::string_view password)
682{
683 const struct pam_conv localConversation = {
684 pamFunctionConversation, const_cast<char*>(password.data())};
685
686 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
687
688 if (pam_start("dropbear", username.data(), &localConversation,
689 &localAuthHandle) != PAM_SUCCESS)
690 {
691 log<level::ERR>("User Authentication Failure");
692 return false;
693 }
694
695 int retval = pam_authenticate(localAuthHandle,
696 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
697
698 if (retval != PAM_SUCCESS)
699 {
700 log<level::DEBUG>("pam_authenticate returned failure",
701 entry("ERROR=%d", retval));
702
703 pam_end(localAuthHandle, retval);
704 return false;
705 }
706
707 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
708 PAM_SUCCESS)
709 {
710 pam_end(localAuthHandle, PAM_SUCCESS);
711 return false;
712 }
713
714 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
715 {
716 return false;
717 }
718 return true;
719}
720
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000721Cc UserAccess::setSpecialUserPassword(const std::string& userName,
722 const std::string& userPassword)
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530723{
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000724 if (pamUpdatePasswd(userName.c_str(), userPassword.c_str()) != PAM_SUCCESS)
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530725 {
726 log<level::DEBUG>("Failed to update password");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000727 return ccUnspecifiedError;
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530728 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000729 return ccSuccess;
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530730}
731
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000732Cc UserAccess::setUserPassword(const uint8_t userId, const char* userPassword)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530733{
734 std::string userName;
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000735 if (ipmiUserGetUserName(userId, userName) != ccSuccess)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530736 {
737 log<level::DEBUG>("User Name not found",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530738 entry("USER-ID=%d", (uint8_t)userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000739 return ccParmOutOfRange;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530740 }
Snehalatha Venkatesh61024d72021-04-08 16:24:39 +0000741
742 ipmi::SecureString passwd;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530743 passwd.assign(reinterpret_cast<const char*>(userPassword), 0,
744 maxIpmi20PasswordSize);
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000745 int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str());
746
747 switch (retval)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530748 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000749 case PAM_SUCCESS:
750 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000751 return ccSuccess;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000752 }
753 case PAM_AUTHTOK_ERR:
754 {
755 log<level::DEBUG>("Bad authentication token");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000756 return ccInvalidFieldRequest;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000757 }
758 default:
759 {
760 log<level::DEBUG>("Failed to update password",
761 entry("USER-ID=%d", (uint8_t)userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000762 return ccUnspecifiedError;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000763 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530764 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530765}
766
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000767Cc UserAccess::setUserEnabledState(const uint8_t userId,
768 const bool& enabledState)
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530769{
770 if (!isValidUserId(userId))
771 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000772 return ccParmOutOfRange;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530773 }
774 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
775 userLock{*userMutex};
776 UserInfo* userInfo = getUserInfo(userId);
777 std::string userName;
778 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
779 ipmiMaxUserName);
780 if (userName.empty())
781 {
782 log<level::DEBUG>("User name not set / invalid");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000783 return ccUnspecifiedError;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530784 }
785 if (userInfo->userEnabled != enabledState)
786 {
787 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800788 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
789 userEnabledProperty, enabledState);
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530790 userInfo->userEnabled = enabledState;
791 try
792 {
793 writeUserData();
794 }
795 catch (const std::exception& e)
796 {
797 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000798 return ccUnspecifiedError;
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530799 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530800 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000801 return ccSuccess;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530802}
803
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000804Cc UserAccess::setUserPayloadAccess(const uint8_t chNum,
805 const uint8_t operation,
806 const uint8_t userId,
807 const PayloadAccess& payloadAccess)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000808{
809 constexpr uint8_t enable = 0x0;
810 constexpr uint8_t disable = 0x1;
811
812 if (!isValidChannel(chNum))
813 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000814 return ccInvalidFieldRequest;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000815 }
816 if (!isValidUserId(userId))
817 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000818 return ccParmOutOfRange;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000819 }
820 if (operation != enable && operation != disable)
821 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000822 return ccInvalidFieldRequest;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000823 }
824 // Check operation & payloadAccess if required.
825 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
826 userLock{*userMutex};
827 UserInfo* userInfo = getUserInfo(userId);
828
829 if (operation == enable)
830 {
831 userInfo->payloadAccess[chNum].stdPayloadEnables1 |=
832 payloadAccess.stdPayloadEnables1;
833
834 userInfo->payloadAccess[chNum].oemPayloadEnables1 |=
835 payloadAccess.oemPayloadEnables1;
836 }
837 else
838 {
839 userInfo->payloadAccess[chNum].stdPayloadEnables1 &=
840 ~(payloadAccess.stdPayloadEnables1);
841
842 userInfo->payloadAccess[chNum].oemPayloadEnables1 &=
843 ~(payloadAccess.oemPayloadEnables1);
844 }
845
846 try
847 {
848 writeUserData();
849 }
850 catch (const std::exception& e)
851 {
852 log<level::ERR>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000853 return ccUnspecifiedError;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000854 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000855 return ccSuccess;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000856}
857
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000858Cc UserAccess::setUserPrivilegeAccess(const uint8_t userId, const uint8_t chNum,
859 const UserPrivAccess& privAccess,
860 const bool& otherPrivUpdates)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530861{
862 if (!isValidChannel(chNum))
863 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000864 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530865 }
866 if (!isValidUserId(userId))
867 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000868 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530869 }
870 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
871 userLock{*userMutex};
872 UserInfo* userInfo = getUserInfo(userId);
873 std::string userName;
874 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
875 ipmiMaxUserName);
876 if (userName.empty())
877 {
878 log<level::DEBUG>("User name not set / invalid");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000879 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530880 }
881 std::string priv = convertToSystemPrivilege(
882 static_cast<CommandPrivilege>(privAccess.privilege));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530883 uint8_t syncIndex = getUsrMgmtSyncIndex();
884 if (chNum == syncIndex &&
885 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
886 {
887 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800888 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
889 userPrivProperty, priv);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530890 }
891 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
892
893 if (otherPrivUpdates)
894 {
895 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
896 userInfo->userPrivAccess[chNum].linkAuthEnabled =
897 privAccess.linkAuthEnabled;
898 userInfo->userPrivAccess[chNum].accessCallback =
899 privAccess.accessCallback;
900 }
901 try
902 {
903 writeUserData();
904 }
905 catch (const std::exception& e)
906 {
907 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000908 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530909 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000910 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530911}
912
913uint8_t UserAccess::getUserId(const std::string& userName)
914{
915 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
916 userLock{*userMutex};
917 checkAndReloadUserData();
918 // user index 0 is reserved, starts with 1
919 size_t usrIndex = 1;
920 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
921 {
922 std::string curName(
923 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
924 ipmiMaxUserName);
925 if (userName == curName)
926 {
927 break; // found the entry
928 }
929 }
930 if (usrIndex > ipmiMaxUsers)
931 {
932 log<level::DEBUG>("User not found",
933 entry("USER_NAME=%s", userName.c_str()));
934 return invalidUserId;
935 }
936
937 return usrIndex;
938}
939
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000940Cc UserAccess::getUserName(const uint8_t userId, std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530941{
942 if (!isValidUserId(userId))
943 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000944 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530945 }
946 UserInfo* userInfo = getUserInfo(userId);
947 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
948 ipmiMaxUserName);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000949 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530950}
951
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +0530952bool UserAccess::isIpmiInAvailableGroupList()
953{
954 if (std::find(availableGroups.begin(), availableGroups.end(),
955 ipmiGrpName) != availableGroups.end())
956 {
957 return true;
958 }
959 if (availableGroups.empty())
960 {
961 // available groups shouldn't be empty, re-query
962 getSystemPrivAndGroups();
963 if (std::find(availableGroups.begin(), availableGroups.end(),
964 ipmiGrpName) != availableGroups.end())
965 {
966 return true;
967 }
968 }
969 return false;
970}
971
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000972Cc UserAccess::setUserName(const uint8_t userId, const std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530973{
974 if (!isValidUserId(userId))
975 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000976 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530977 }
978
979 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
980 userLock{*userMutex};
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530981 std::string oldUser;
982 getUserName(userId, oldUser);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530983
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000984 if (oldUser == userName)
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530985 {
986 // requesting to set the same user name, return success.
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000987 return ccSuccess;
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530988 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000989
990 bool validUser = isValidUserName(userName);
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530991 UserInfo* userInfo = getUserInfo(userId);
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000992 if (userName.empty() && !oldUser.empty())
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530993 {
994 // Delete existing user
995 std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
996 try
997 {
998 auto method = bus.new_method_call(
999 getUserServiceName().c_str(), userPath.c_str(),
1000 deleteUserInterface, deleteUserMethod);
1001 auto reply = bus.call(method);
1002 }
1003 catch (const sdbusplus::exception::SdBusError& e)
1004 {
1005 log<level::DEBUG>("Failed to excute method",
1006 entry("METHOD=%s", deleteUserMethod),
1007 entry("PATH=%s", userPath.c_str()));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001008 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301009 }
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +05301010 deleteUserIndex(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301011 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001012 else if (oldUser.empty() && !userName.empty() && validUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301013 {
1014 try
1015 {
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +05301016 if (!isIpmiInAvailableGroupList())
1017 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001018 return ccUnspecifiedError;
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +05301019 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301020 // Create new user
1021 auto method = bus.new_method_call(
1022 getUserServiceName().c_str(), userMgrObjBasePath,
1023 userMgrInterface, createUserMethod);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001024 method.append(userName.c_str(), availableGroups, "", false);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301025 auto reply = bus.call(method);
1026 }
1027 catch (const sdbusplus::exception::SdBusError& e)
1028 {
1029 log<level::DEBUG>("Failed to excute method",
1030 entry("METHOD=%s", createUserMethod),
1031 entry("PATH=%s", userMgrObjBasePath));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001032 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301033 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001034
1035 std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1036 std::memcpy(userInfo->userName,
1037 static_cast<const void*>(userName.data()), userName.size());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301038 userInfo->userInSystem = true;
1039 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001040 else if (oldUser != userName && validUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301041 {
1042 try
1043 {
1044 // User rename
1045 auto method = bus.new_method_call(
1046 getUserServiceName().c_str(), userMgrObjBasePath,
1047 userMgrInterface, renameUserMethod);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001048 method.append(oldUser.c_str(), userName.c_str());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301049 auto reply = bus.call(method);
1050 }
1051 catch (const sdbusplus::exception::SdBusError& e)
1052 {
1053 log<level::DEBUG>("Failed to excute method",
1054 entry("METHOD=%s", renameUserMethod),
1055 entry("PATH=%s", userMgrObjBasePath));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001056 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301057 }
1058 std::fill(static_cast<uint8_t*>(userInfo->userName),
1059 static_cast<uint8_t*>(userInfo->userName) +
1060 sizeof(userInfo->userName),
1061 0);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001062
1063 std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1064 std::memcpy(userInfo->userName,
1065 static_cast<const void*>(userName.data()), userName.size());
1066
1067 ipmiRenameUserEntryPassword(oldUser, userName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301068 userInfo->userInSystem = true;
1069 }
1070 else if (!validUser)
1071 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001072 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301073 }
1074 try
1075 {
1076 writeUserData();
1077 }
1078 catch (const std::exception& e)
1079 {
1080 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001081 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301082 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001083 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301084}
1085
1086static constexpr const char* jsonUserName = "user_name";
1087static constexpr const char* jsonPriv = "privilege";
1088static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
1089static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
1090static constexpr const char* jsonAccCallbk = "access_callback";
1091static constexpr const char* jsonUserEnabled = "user_enabled";
1092static constexpr const char* jsonUserInSys = "user_in_system";
1093static constexpr const char* jsonFixedUser = "fixed_user_name";
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001094static constexpr const char* payloadEnabledStr = "payload_enabled";
1095static constexpr const char* stdPayloadStr = "std_payload";
1096static constexpr const char* oemPayloadStr = "OEM_payload";
1097
1098/** @brief to construct a JSON object from the given payload access details.
1099 *
1100 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input)
1101 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input)
1102 *
1103 * @details Sample output JSON object format :
1104 * "payload_enabled":{
1105 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1106 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1107 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1108 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1109 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1110 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1111 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1112 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1113 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1114 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1115 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1116 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1117 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1118 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1119 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1120 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1121 * }
1122 */
1123static const Json constructJsonPayloadEnables(
1124 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1125 stdPayload,
1126 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1127 oemPayload)
1128{
1129 Json jsonPayloadEnabled;
1130
1131 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1132 {
1133 std::ostringstream stdPayloadStream;
1134 std::ostringstream oemPayloadStream;
1135
1136 stdPayloadStream << stdPayloadStr << payloadNum;
1137 oemPayloadStream << oemPayloadStr << payloadNum;
1138
1139 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1140 stdPayloadStream.str(), stdPayload[payloadNum]));
1141
1142 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1143 oemPayloadStream.str(), oemPayload[payloadNum]));
1144 }
1145 return jsonPayloadEnabled;
1146}
1147
1148void UserAccess::readPayloadAccessFromUserInfo(
1149 const UserInfo& userInfo,
1150 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload,
1151 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload)
1152{
1153 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1154 {
1155 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1156 {
1157 stdPayload[payloadNum][chIndex] =
1158 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum];
1159
1160 oemPayload[payloadNum][chIndex] =
1161 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum];
1162 }
1163 }
1164}
1165
1166void UserAccess::updatePayloadAccessInUserInfo(
1167 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1168 stdPayload,
1169 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1170 oemPayload,
1171 UserInfo& userInfo)
1172{
1173 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1174 {
1175 // Ensure that reserved/unsupported payloads are marked to zero.
1176 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset();
1177 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset();
1178 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset();
1179 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset();
1180 // Update SOL status as it is the only supported payload currently.
1181 userInfo.payloadAccess[chIndex]
1182 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] =
1183 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex];
1184 }
1185}
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301186
1187void UserAccess::readUserData()
1188{
1189 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1190 userLock{*userMutex};
1191
1192 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
1193 if (!iUsrData.good())
1194 {
1195 log<level::ERR>("Error in reading IPMI user data file");
1196 throw std::ios_base::failure("Error opening IPMI user data file");
1197 }
1198
1199 Json jsonUsersTbl = Json::array();
1200 jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
1201
1202 if (jsonUsersTbl.size() != ipmiMaxUsers)
1203 {
1204 log<level::ERR>(
1205 "Error in reading IPMI user data file - User count issues");
1206 throw std::runtime_error(
1207 "Corrupted IPMI user data file - invalid user count");
1208 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001209
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301210 // user index 0 is reserved, starts with 1
1211 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1212 {
1213 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
1214 if (userInfo.is_null())
1215 {
1216 log<level::ERR>("Error in reading IPMI user data file - "
1217 "user info corrupted");
1218 throw std::runtime_error(
1219 "Corrupted IPMI user data file - invalid user info");
1220 }
1221 std::string userName = userInfo[jsonUserName].get<std::string>();
1222 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
1223 userName.c_str(), ipmiMaxUserName);
1224
1225 std::vector<std::string> privilege =
1226 userInfo[jsonPriv].get<std::vector<std::string>>();
1227 std::vector<bool> ipmiEnabled =
1228 userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
1229 std::vector<bool> linkAuthEnabled =
1230 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
1231 std::vector<bool> accessCallback =
1232 userInfo[jsonAccCallbk].get<std::vector<bool>>();
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001233
1234 // Payload Enables Processing.
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001235 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1236 stdPayload = {};
1237 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1238 oemPayload = {};
1239 try
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001240 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001241 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr);
1242 for (auto payloadNum = 0; payloadNum < payloadsPerByte;
1243 payloadNum++)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001244 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001245 std::ostringstream stdPayloadStream;
1246 std::ostringstream oemPayloadStream;
1247
1248 stdPayloadStream << stdPayloadStr << payloadNum;
1249 oemPayloadStream << oemPayloadStr << payloadNum;
1250
1251 stdPayload[payloadNum] =
1252 jsonPayloadEnabled[stdPayloadStream.str()]
1253 .get<std::array<bool, ipmiMaxChannels>>();
1254 oemPayload[payloadNum] =
1255 jsonPayloadEnabled[oemPayloadStream.str()]
1256 .get<std::array<bool, ipmiMaxChannels>>();
1257
1258 if (stdPayload[payloadNum].size() != ipmiMaxChannels ||
1259 oemPayload[payloadNum].size() != ipmiMaxChannels)
1260 {
1261 log<level::ERR>("Error in reading IPMI user data file - "
1262 "payload properties corrupted");
1263 throw std::runtime_error(
1264 "Corrupted IPMI user data file - payload properties");
1265 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001266 }
1267 }
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001268 catch (Json::out_of_range& e)
1269 {
1270 // Key not found in 'userInfo'; possibly an old JSON file. Use
1271 // default values for all payloads, and SOL payload default is true.
1272 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true);
1273 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001274
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301275 if (privilege.size() != ipmiMaxChannels ||
1276 ipmiEnabled.size() != ipmiMaxChannels ||
1277 linkAuthEnabled.size() != ipmiMaxChannels ||
1278 accessCallback.size() != ipmiMaxChannels)
1279 {
1280 log<level::ERR>("Error in reading IPMI user data file - "
1281 "properties corrupted");
1282 throw std::runtime_error(
1283 "Corrupted IPMI user data file - properties");
1284 }
1285 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1286 {
1287 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
1288 static_cast<uint8_t>(
1289 convertToIPMIPrivilege(privilege[chIndex]));
1290 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
1291 ipmiEnabled[chIndex];
1292 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
1293 linkAuthEnabled[chIndex];
1294 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
1295 accessCallback[chIndex];
1296 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001297 updatePayloadAccessInUserInfo(stdPayload, oemPayload,
1298 usersTbl.user[usrIndex]);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301299 usersTbl.user[usrIndex].userEnabled =
1300 userInfo[jsonUserEnabled].get<bool>();
1301 usersTbl.user[usrIndex].userInSystem =
1302 userInfo[jsonUserInSys].get<bool>();
1303 usersTbl.user[usrIndex].fixedUserName =
1304 userInfo[jsonFixedUser].get<bool>();
1305 }
1306
1307 log<level::DEBUG>("User data read from IPMI data file");
1308 iUsrData.close();
1309 // Update the timestamp
1310 fileLastUpdatedTime = getUpdatedFileTime();
1311 return;
1312}
1313
1314void UserAccess::writeUserData()
1315{
1316 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1317 userLock{*userMutex};
1318
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301319 Json jsonUsersTbl = Json::array();
1320 // user index 0 is reserved, starts with 1
1321 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1322 {
1323 Json jsonUserInfo;
1324 jsonUserInfo[jsonUserName] = std::string(
1325 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
1326 ipmiMaxUserName);
1327 std::vector<std::string> privilege(ipmiMaxChannels);
1328 std::vector<bool> ipmiEnabled(ipmiMaxChannels);
1329 std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
1330 std::vector<bool> accessCallback(ipmiMaxChannels);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001331
1332 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1333 stdPayload;
1334 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1335 oemPayload;
1336
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301337 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1338 {
1339 privilege[chIndex] =
1340 convertToSystemPrivilege(static_cast<CommandPrivilege>(
1341 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
1342 ipmiEnabled[chIndex] =
1343 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
1344 linkAuthEnabled[chIndex] =
1345 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
1346 accessCallback[chIndex] =
1347 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
1348 }
1349 jsonUserInfo[jsonPriv] = privilege;
1350 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
1351 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
1352 jsonUserInfo[jsonAccCallbk] = accessCallback;
1353 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1354 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1355 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001356
1357 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload,
1358 oemPayload);
1359 Json jsonPayloadEnabledInfo =
1360 constructJsonPayloadEnables(stdPayload, oemPayload);
1361 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo;
1362
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301363 jsonUsersTbl.push_back(jsonUserInfo);
1364 }
1365
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +05301366 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
1367 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
1368 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1369 if (fd < 0)
1370 {
1371 log<level::ERR>("Error in creating temporary IPMI user data file");
1372 throw std::ios_base::failure(
1373 "Error in creating temporary IPMI user data file");
1374 }
1375 const auto& writeStr = jsonUsersTbl.dump();
1376 if (write(fd, writeStr.c_str(), writeStr.size()) !=
1377 static_cast<ssize_t>(writeStr.size()))
1378 {
1379 close(fd);
1380 log<level::ERR>("Error in writing temporary IPMI user data file");
1381 throw std::ios_base::failure(
1382 "Error in writing temporary IPMI user data file");
1383 }
1384 close(fd);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301385
1386 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1387 {
1388 log<level::ERR>("Error in renaming temporary IPMI user data file");
1389 throw std::runtime_error("Error in renaming IPMI user data file");
1390 }
1391 // Update the timestamp
1392 fileLastUpdatedTime = getUpdatedFileTime();
1393 return;
1394}
1395
1396bool UserAccess::addUserEntry(const std::string& userName,
1397 const std::string& sysPriv, const bool& enabled)
1398{
1399 UsersTbl* userData = getUsersTblPtr();
1400 size_t freeIndex = 0xFF;
1401 // user index 0 is reserved, starts with 1
1402 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1403 {
1404 std::string curName(
1405 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1406 ipmiMaxUserName);
1407 if (userName == curName)
1408 {
1409 log<level::DEBUG>("User name exists",
1410 entry("USER_NAME=%s", userName.c_str()));
1411 return false; // user name exists.
1412 }
1413
1414 if ((!userData->user[usrIndex].userInSystem) &&
1415 (userData->user[usrIndex].userName[0] == '\0') &&
1416 (freeIndex == 0xFF))
1417 {
1418 freeIndex = usrIndex;
1419 }
1420 }
1421 if (freeIndex == 0xFF)
1422 {
1423 log<level::ERR>("No empty slots found");
1424 return false;
1425 }
1426 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1427 userName.c_str(), ipmiMaxUserName);
1428 uint8_t priv =
1429 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1430 privMask;
1431 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1432 {
1433 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1434 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1435 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1436 true;
1437 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1438 }
1439 userData->user[freeIndex].userInSystem = true;
1440 userData->user[freeIndex].userEnabled = enabled;
1441
1442 return true;
1443}
1444
1445void UserAccess::deleteUserIndex(const size_t& usrIdx)
1446{
1447 UsersTbl* userData = getUsersTblPtr();
1448
1449 std::string userName(
1450 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1451 ipmiMaxUserName);
1452 ipmiClearUserEntryPassword(userName);
1453 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1454 static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1455 sizeof(userData->user[usrIdx].userName),
1456 0);
1457 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1458 {
1459 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1460 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1461 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1462 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1463 }
1464 userData->user[usrIdx].userInSystem = false;
1465 userData->user[usrIdx].userEnabled = false;
1466 return;
1467}
1468
1469void UserAccess::checkAndReloadUserData()
1470{
1471 std::time_t updateTime = getUpdatedFileTime();
1472 if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1473 {
1474 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1475 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1476 readUserData();
1477 }
1478 return;
1479}
1480
1481UsersTbl* UserAccess::getUsersTblPtr()
1482{
1483 // reload data before using it.
1484 checkAndReloadUserData();
1485 return &usersTbl;
1486}
1487
1488void UserAccess::getSystemPrivAndGroups()
1489{
1490 std::map<std::string, PrivAndGroupType> properties;
1491 try
1492 {
1493 auto method = bus.new_method_call(
1494 getUserServiceName().c_str(), userMgrObjBasePath,
1495 dBusPropertiesInterface, getAllPropertiesMethod);
1496 method.append(userMgrInterface);
1497
1498 auto reply = bus.call(method);
1499 reply.read(properties);
1500 }
1501 catch (const sdbusplus::exception::SdBusError& e)
1502 {
1503 log<level::DEBUG>("Failed to excute method",
1504 entry("METHOD=%s", getAllPropertiesMethod),
1505 entry("PATH=%s", userMgrObjBasePath));
1506 return;
1507 }
1508 for (const auto& t : properties)
1509 {
1510 auto key = t.first;
1511 if (key == allPrivProperty)
1512 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001513 availablePrivileges = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301514 }
1515 else if (key == allGrpProperty)
1516 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001517 availableGroups = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301518 }
1519 }
1520 // TODO: Implement Supported Privilege & Groups verification logic
1521 return;
1522}
1523
1524std::time_t UserAccess::getUpdatedFileTime()
1525{
1526 struct stat fileStat;
1527 if (stat(ipmiUserDataFile, &fileStat) != 0)
1528 {
1529 log<level::DEBUG>("Error in getting last updated time stamp");
1530 return -EIO;
1531 }
1532 return fileStat.st_mtime;
1533}
1534
1535void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1536 std::vector<std::string>& usrGrps,
1537 std::string& usrPriv, bool& usrEnabled)
1538{
1539 for (const auto& t : properties)
1540 {
1541 std::string key = t.first;
1542 if (key == userPrivProperty)
1543 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001544 usrPriv = std::get<std::string>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301545 }
1546 else if (key == userGrpProperty)
1547 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001548 usrGrps = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301549 }
1550 else if (key == userEnabledProperty)
1551 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001552 usrEnabled = std::get<bool>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301553 }
1554 }
1555 return;
1556}
1557
1558int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1559 std::vector<std::string>& usrGrps,
1560 std::string& usrPriv, bool& usrEnabled)
1561{
1562 auto usrObj = userObjs.find(usersInterface);
1563 if (usrObj != userObjs.end())
1564 {
1565 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1566 return 0;
1567 }
1568 return -EIO;
1569}
1570
arun-pmbbe728c2020-01-10 15:18:04 +05301571void UserAccess::cacheUserDataFile()
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301572{
1573 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1574 userLock{*userMutex};
1575 try
1576 {
1577 readUserData();
1578 }
1579 catch (const std::ios_base::failure& e)
1580 { // File is empty, create it for the first time
1581 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1582 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1583 // user index 0 is reserved, starts with 1
1584 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1585 {
1586 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1587 {
1588 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1589 privNoAccess;
Saravanan Palanisamy92d81192019-08-07 18:00:04 +00001590 usersTbl.user[userIndex]
1591 .payloadAccess[chIndex]
1592 .stdPayloadEnables1[static_cast<uint8_t>(
1593 ipmi::PayloadType::SOL)] = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301594 }
1595 }
1596 writeUserData();
1597 }
arun-pmbbe728c2020-01-10 15:18:04 +05301598 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
1599 // Register it for single object and single process either netipimd /
1600 // host-ipmid
1601 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
1602 {
1603 log<level::DEBUG>("Registering signal handler");
1604 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
1605 bus,
1606 sdbusplus::bus::match::rules::type::signal() +
1607 sdbusplus::bus::match::rules::interface(dBusObjManager) +
1608 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1609 [&](sdbusplus::message::message& msg) {
1610 userUpdatedSignalHandler(*this, msg);
1611 });
1612 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
1613 bus,
1614 sdbusplus::bus::match::rules::type::signal() +
1615 sdbusplus::bus::match::rules::interface(userMgrInterface) +
1616 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1617 [&](sdbusplus::message::message& msg) {
1618 userUpdatedSignalHandler(*this, msg);
1619 });
1620 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
1621 bus,
1622 sdbusplus::bus::match::rules::type::signal() +
1623 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
1624 sdbusplus::bus::match::rules::interface(
1625 dBusPropertiesInterface) +
1626 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
1627 sdbusplus::bus::match::rules::argN(0, usersInterface),
1628 [&](sdbusplus::message::message& msg) {
1629 userUpdatedSignalHandler(*this, msg);
1630 });
1631 signalHndlrObject = true;
1632 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301633 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1634 try
1635 {
1636 auto method = bus.new_method_call(getUserServiceName().c_str(),
1637 userMgrObjBasePath, dBusObjManager,
1638 getManagedObjectsMethod);
1639 auto reply = bus.call(method);
1640 reply.read(managedObjs);
1641 }
1642 catch (const sdbusplus::exception::SdBusError& e)
1643 {
1644 log<level::DEBUG>("Failed to excute method",
1645 entry("METHOD=%s", getSubTreeMethod),
1646 entry("PATH=%s", userMgrObjBasePath));
1647 return;
1648 }
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301649 bool updateRequired = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301650 UsersTbl* userData = &usersTbl;
1651 // user index 0 is reserved, starts with 1
1652 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1653 {
1654 if ((userData->user[usrIdx].userInSystem) &&
1655 (userData->user[usrIdx].userName[0] != '\0'))
1656 {
1657 std::vector<std::string> usrGrps;
1658 std::string usrPriv;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301659
1660 std::string userName(
1661 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1662 ipmiMaxUserName);
1663 std::string usersPath =
1664 std::string(userObjBasePath) + "/" + userName;
1665
1666 auto usrObj = managedObjs.find(usersPath);
1667 if (usrObj != managedObjs.end())
1668 {
Chen,Yugang0e862fa2019-09-06 11:03:05 +08001669 bool usrEnabled = false;
Patrick Venture3a697ad2019-08-19 11:12:05 -07001670
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301671 // User exist. Lets check and update other fileds
1672 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1673 usrEnabled);
1674 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1675 usrGrps.end())
1676 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301677 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301678 // Group "ipmi" is removed so lets remove user in IPMI
1679 deleteUserIndex(usrIdx);
1680 }
1681 else
1682 {
1683 // Group "ipmi" is present so lets update other properties
1684 // in IPMI
1685 uint8_t priv =
1686 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1687 // Update all channels priv, only if it is not equivalent to
1688 // getUsrMgmtSyncIndex()
1689 if (userData->user[usrIdx]
1690 .userPrivAccess[getUsrMgmtSyncIndex()]
1691 .privilege != priv)
1692 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301693 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301694 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1695 ++chIndex)
1696 {
1697 userData->user[usrIdx]
1698 .userPrivAccess[chIndex]
1699 .privilege = priv;
1700 }
1701 }
1702 if (userData->user[usrIdx].userEnabled != usrEnabled)
1703 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301704 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301705 userData->user[usrIdx].userEnabled = usrEnabled;
1706 }
1707 }
1708
1709 // We are done with this obj. lets delete from MAP
1710 managedObjs.erase(usrObj);
1711 }
1712 else
1713 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301714 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301715 deleteUserIndex(usrIdx);
1716 }
1717 }
1718 }
1719
1720 // Walk through remnaining managedObj users list
1721 // Add them to ipmi data base
1722 for (const auto& usrObj : managedObjs)
1723 {
1724 std::vector<std::string> usrGrps;
1725 std::string usrPriv, userName;
Chen,Yugang0e862fa2019-09-06 11:03:05 +08001726 bool usrEnabled = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301727 std::string usrObjPath = std::string(usrObj.first);
1728 if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1729 {
1730 log<level::ERR>("Error in user object path");
1731 continue;
1732 }
1733 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1734 // Add 'ipmi' group users
1735 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1736 usrGrps.end())
1737 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301738 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301739 // CREATE NEW USER
1740 if (true != addUserEntry(userName, usrPriv, usrEnabled))
1741 {
1742 break;
1743 }
1744 }
1745 }
1746
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301747 if (updateRequired)
1748 {
1749 // All userData slots update done. Lets write the data
1750 writeUserData();
1751 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301752
1753 return;
1754}
1755} // namespace ipmi