blob: 182d17d12d52b265bfcad052b9c1c673846598db [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 {
P Dheeraj Srujan Kumar2aeb1c12021-07-20 04:26:13 +0530627 return PAM_CONV_ERR;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530628 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530629
P Dheeraj Srujan Kumar2aeb1c12021-07-20 04:26:13 +0530630 if (numMsg <= 0 || numMsg >= PAM_MAX_NUM_MSG)
631 {
632 return PAM_CONV_ERR;
633 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530634
635 for (int i = 0; i < numMsg; ++i)
636 {
P Dheeraj Srujan Kumar2aeb1c12021-07-20 04:26:13 +0530637 /* Ignore all PAM messages except prompting for hidden input */
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530638 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
639 {
640 continue;
641 }
P Dheeraj Srujan Kumar2aeb1c12021-07-20 04:26:13 +0530642
643 /* Assume PAM is only prompting for the password as hidden input */
644 /* Allocate memory only when PAM_PROMPT_ECHO_OFF is encounterred */
645
646 char* appPass = reinterpret_cast<char*>(appdataPtr);
647 size_t appPassSize = std::strlen(appPass);
648
649 if (appPassSize >= PAM_MAX_RESP_SIZE)
650 {
651 return PAM_CONV_ERR;
652 }
653
654 char* pass = reinterpret_cast<char*>(malloc(appPassSize + 1));
655 if (pass == nullptr)
656 {
657 return PAM_BUF_ERR;
658 }
659
660 void* ptr =
661 calloc(static_cast<size_t>(numMsg), sizeof(struct pam_response));
662 if (ptr == nullptr)
663 {
664 free(pass);
665 return PAM_BUF_ERR;
666 }
667
668 std::strncpy(pass, appPass, appPassSize + 1);
669
670 *resp = reinterpret_cast<pam_response*>(ptr);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530671 resp[i]->resp = pass;
P Dheeraj Srujan Kumar2aeb1c12021-07-20 04:26:13 +0530672
673 return PAM_SUCCESS;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530674 }
P Dheeraj Srujan Kumar2aeb1c12021-07-20 04:26:13 +0530675
676 return PAM_CONV_ERR;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530677}
678
679/** @brief Updating the PAM password
680 *
681 * @param[in] username - username in string
682 *
683 * @param[in] password - new password in string
684 *
685 * @return status
686 */
687
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000688int pamUpdatePasswd(const char* username, const char* password)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530689{
690 const struct pam_conv localConversation = {pamFunctionConversation,
691 const_cast<char*>(password)};
692 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
693
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000694 int retval =
695 pam_start("passwd", username, &localConversation, &localAuthHandle);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530696
697 if (retval != PAM_SUCCESS)
698 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000699 return retval;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530700 }
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000701
702 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
703 if (retval != PAM_SUCCESS)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530704 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000705 pam_end(localAuthHandle, retval);
706 return retval;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530707 }
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000708
709 return pam_end(localAuthHandle, PAM_SUCCESS);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530710}
711
Ayushi Smriti02650d52019-05-15 11:59:09 +0000712bool pamUserCheckAuthenticate(std::string_view username,
713 std::string_view password)
714{
715 const struct pam_conv localConversation = {
716 pamFunctionConversation, const_cast<char*>(password.data())};
717
718 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
719
720 if (pam_start("dropbear", username.data(), &localConversation,
721 &localAuthHandle) != PAM_SUCCESS)
722 {
723 log<level::ERR>("User Authentication Failure");
724 return false;
725 }
726
727 int retval = pam_authenticate(localAuthHandle,
728 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
729
730 if (retval != PAM_SUCCESS)
731 {
732 log<level::DEBUG>("pam_authenticate returned failure",
733 entry("ERROR=%d", retval));
734
735 pam_end(localAuthHandle, retval);
736 return false;
737 }
738
739 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
740 PAM_SUCCESS)
741 {
742 pam_end(localAuthHandle, PAM_SUCCESS);
743 return false;
744 }
745
746 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
747 {
748 return false;
749 }
750 return true;
751}
752
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000753Cc UserAccess::setSpecialUserPassword(const std::string& userName,
754 const std::string& userPassword)
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530755{
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000756 if (pamUpdatePasswd(userName.c_str(), userPassword.c_str()) != PAM_SUCCESS)
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530757 {
758 log<level::DEBUG>("Failed to update password");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000759 return ccUnspecifiedError;
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530760 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000761 return ccSuccess;
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530762}
763
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000764Cc UserAccess::setUserPassword(const uint8_t userId, const char* userPassword)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530765{
766 std::string userName;
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000767 if (ipmiUserGetUserName(userId, userName) != ccSuccess)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530768 {
769 log<level::DEBUG>("User Name not found",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530770 entry("USER-ID=%d", (uint8_t)userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000771 return ccParmOutOfRange;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530772 }
Snehalatha Venkatesh61024d72021-04-08 16:24:39 +0000773
774 ipmi::SecureString passwd;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530775 passwd.assign(reinterpret_cast<const char*>(userPassword), 0,
776 maxIpmi20PasswordSize);
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000777 int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str());
778
779 switch (retval)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530780 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000781 case PAM_SUCCESS:
782 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000783 return ccSuccess;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000784 }
785 case PAM_AUTHTOK_ERR:
786 {
787 log<level::DEBUG>("Bad authentication token");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000788 return ccInvalidFieldRequest;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000789 }
790 default:
791 {
792 log<level::DEBUG>("Failed to update password",
793 entry("USER-ID=%d", (uint8_t)userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000794 return ccUnspecifiedError;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000795 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530796 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530797}
798
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000799Cc UserAccess::setUserEnabledState(const uint8_t userId,
800 const bool& enabledState)
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530801{
802 if (!isValidUserId(userId))
803 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000804 return ccParmOutOfRange;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530805 }
806 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
807 userLock{*userMutex};
808 UserInfo* userInfo = getUserInfo(userId);
809 std::string userName;
810 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
811 ipmiMaxUserName);
812 if (userName.empty())
813 {
814 log<level::DEBUG>("User name not set / invalid");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000815 return ccUnspecifiedError;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530816 }
817 if (userInfo->userEnabled != enabledState)
818 {
819 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800820 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
821 userEnabledProperty, enabledState);
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530822 userInfo->userEnabled = enabledState;
823 try
824 {
825 writeUserData();
826 }
827 catch (const std::exception& e)
828 {
829 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000830 return ccUnspecifiedError;
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530831 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530832 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000833 return ccSuccess;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530834}
835
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000836Cc UserAccess::setUserPayloadAccess(const uint8_t chNum,
837 const uint8_t operation,
838 const uint8_t userId,
839 const PayloadAccess& payloadAccess)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000840{
841 constexpr uint8_t enable = 0x0;
842 constexpr uint8_t disable = 0x1;
843
844 if (!isValidChannel(chNum))
845 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000846 return ccInvalidFieldRequest;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000847 }
848 if (!isValidUserId(userId))
849 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000850 return ccParmOutOfRange;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000851 }
852 if (operation != enable && operation != disable)
853 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000854 return ccInvalidFieldRequest;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000855 }
856 // Check operation & payloadAccess if required.
857 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
858 userLock{*userMutex};
859 UserInfo* userInfo = getUserInfo(userId);
860
861 if (operation == enable)
862 {
863 userInfo->payloadAccess[chNum].stdPayloadEnables1 |=
864 payloadAccess.stdPayloadEnables1;
865
866 userInfo->payloadAccess[chNum].oemPayloadEnables1 |=
867 payloadAccess.oemPayloadEnables1;
868 }
869 else
870 {
871 userInfo->payloadAccess[chNum].stdPayloadEnables1 &=
872 ~(payloadAccess.stdPayloadEnables1);
873
874 userInfo->payloadAccess[chNum].oemPayloadEnables1 &=
875 ~(payloadAccess.oemPayloadEnables1);
876 }
877
878 try
879 {
880 writeUserData();
881 }
882 catch (const std::exception& e)
883 {
884 log<level::ERR>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000885 return ccUnspecifiedError;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000886 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000887 return ccSuccess;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000888}
889
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000890Cc UserAccess::setUserPrivilegeAccess(const uint8_t userId, const uint8_t chNum,
891 const UserPrivAccess& privAccess,
892 const bool& otherPrivUpdates)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530893{
894 if (!isValidChannel(chNum))
895 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000896 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530897 }
898 if (!isValidUserId(userId))
899 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000900 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530901 }
902 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
903 userLock{*userMutex};
904 UserInfo* userInfo = getUserInfo(userId);
905 std::string userName;
906 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
907 ipmiMaxUserName);
908 if (userName.empty())
909 {
910 log<level::DEBUG>("User name not set / invalid");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000911 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530912 }
913 std::string priv = convertToSystemPrivilege(
914 static_cast<CommandPrivilege>(privAccess.privilege));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530915 uint8_t syncIndex = getUsrMgmtSyncIndex();
916 if (chNum == syncIndex &&
917 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
918 {
919 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800920 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
921 userPrivProperty, priv);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530922 }
923 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
924
925 if (otherPrivUpdates)
926 {
927 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
928 userInfo->userPrivAccess[chNum].linkAuthEnabled =
929 privAccess.linkAuthEnabled;
930 userInfo->userPrivAccess[chNum].accessCallback =
931 privAccess.accessCallback;
932 }
933 try
934 {
935 writeUserData();
936 }
937 catch (const std::exception& e)
938 {
939 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000940 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530941 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000942 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530943}
944
945uint8_t UserAccess::getUserId(const std::string& userName)
946{
947 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
948 userLock{*userMutex};
949 checkAndReloadUserData();
950 // user index 0 is reserved, starts with 1
951 size_t usrIndex = 1;
952 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
953 {
954 std::string curName(
955 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
956 ipmiMaxUserName);
957 if (userName == curName)
958 {
959 break; // found the entry
960 }
961 }
962 if (usrIndex > ipmiMaxUsers)
963 {
964 log<level::DEBUG>("User not found",
965 entry("USER_NAME=%s", userName.c_str()));
966 return invalidUserId;
967 }
968
969 return usrIndex;
970}
971
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000972Cc UserAccess::getUserName(const uint8_t userId, 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 UserInfo* userInfo = getUserInfo(userId);
979 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
980 ipmiMaxUserName);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000981 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530982}
983
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +0530984bool UserAccess::isIpmiInAvailableGroupList()
985{
986 if (std::find(availableGroups.begin(), availableGroups.end(),
987 ipmiGrpName) != availableGroups.end())
988 {
989 return true;
990 }
991 if (availableGroups.empty())
992 {
993 // available groups shouldn't be empty, re-query
994 getSystemPrivAndGroups();
995 if (std::find(availableGroups.begin(), availableGroups.end(),
996 ipmiGrpName) != availableGroups.end())
997 {
998 return true;
999 }
1000 }
1001 return false;
1002}
1003
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001004Cc UserAccess::setUserName(const uint8_t userId, const std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301005{
1006 if (!isValidUserId(userId))
1007 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001008 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301009 }
1010
1011 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1012 userLock{*userMutex};
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301013 std::string oldUser;
1014 getUserName(userId, oldUser);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301015
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001016 if (oldUser == userName)
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +05301017 {
1018 // requesting to set the same user name, return success.
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001019 return ccSuccess;
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +05301020 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001021
1022 bool validUser = isValidUserName(userName);
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +05301023 UserInfo* userInfo = getUserInfo(userId);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001024 if (userName.empty() && !oldUser.empty())
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301025 {
1026 // Delete existing user
1027 std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
1028 try
1029 {
1030 auto method = bus.new_method_call(
1031 getUserServiceName().c_str(), userPath.c_str(),
1032 deleteUserInterface, deleteUserMethod);
1033 auto reply = bus.call(method);
1034 }
1035 catch (const sdbusplus::exception::SdBusError& e)
1036 {
1037 log<level::DEBUG>("Failed to excute method",
1038 entry("METHOD=%s", deleteUserMethod),
1039 entry("PATH=%s", userPath.c_str()));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001040 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301041 }
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +05301042 deleteUserIndex(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301043 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001044 else if (oldUser.empty() && !userName.empty() && validUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301045 {
1046 try
1047 {
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +05301048 if (!isIpmiInAvailableGroupList())
1049 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001050 return ccUnspecifiedError;
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +05301051 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301052 // Create new user
1053 auto method = bus.new_method_call(
1054 getUserServiceName().c_str(), userMgrObjBasePath,
1055 userMgrInterface, createUserMethod);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001056 method.append(userName.c_str(), availableGroups, "", false);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301057 auto reply = bus.call(method);
1058 }
1059 catch (const sdbusplus::exception::SdBusError& e)
1060 {
1061 log<level::DEBUG>("Failed to excute method",
1062 entry("METHOD=%s", createUserMethod),
1063 entry("PATH=%s", userMgrObjBasePath));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001064 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301065 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001066
1067 std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1068 std::memcpy(userInfo->userName,
1069 static_cast<const void*>(userName.data()), userName.size());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301070 userInfo->userInSystem = true;
1071 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001072 else if (oldUser != userName && validUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301073 {
1074 try
1075 {
1076 // User rename
1077 auto method = bus.new_method_call(
1078 getUserServiceName().c_str(), userMgrObjBasePath,
1079 userMgrInterface, renameUserMethod);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001080 method.append(oldUser.c_str(), userName.c_str());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301081 auto reply = bus.call(method);
1082 }
1083 catch (const sdbusplus::exception::SdBusError& e)
1084 {
1085 log<level::DEBUG>("Failed to excute method",
1086 entry("METHOD=%s", renameUserMethod),
1087 entry("PATH=%s", userMgrObjBasePath));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001088 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301089 }
1090 std::fill(static_cast<uint8_t*>(userInfo->userName),
1091 static_cast<uint8_t*>(userInfo->userName) +
1092 sizeof(userInfo->userName),
1093 0);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001094
1095 std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1096 std::memcpy(userInfo->userName,
1097 static_cast<const void*>(userName.data()), userName.size());
1098
1099 ipmiRenameUserEntryPassword(oldUser, userName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301100 userInfo->userInSystem = true;
1101 }
1102 else if (!validUser)
1103 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001104 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301105 }
1106 try
1107 {
1108 writeUserData();
1109 }
1110 catch (const std::exception& e)
1111 {
1112 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001113 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301114 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001115 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301116}
1117
1118static constexpr const char* jsonUserName = "user_name";
1119static constexpr const char* jsonPriv = "privilege";
1120static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
1121static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
1122static constexpr const char* jsonAccCallbk = "access_callback";
1123static constexpr const char* jsonUserEnabled = "user_enabled";
1124static constexpr const char* jsonUserInSys = "user_in_system";
1125static constexpr const char* jsonFixedUser = "fixed_user_name";
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001126static constexpr const char* payloadEnabledStr = "payload_enabled";
1127static constexpr const char* stdPayloadStr = "std_payload";
1128static constexpr const char* oemPayloadStr = "OEM_payload";
1129
1130/** @brief to construct a JSON object from the given payload access details.
1131 *
1132 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input)
1133 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input)
1134 *
1135 * @details Sample output JSON object format :
1136 * "payload_enabled":{
1137 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1138 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1139 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1140 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1141 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1142 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1143 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1144 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1145 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1146 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1147 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1148 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1149 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1150 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1151 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1152 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1153 * }
1154 */
1155static const Json constructJsonPayloadEnables(
1156 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1157 stdPayload,
1158 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1159 oemPayload)
1160{
1161 Json jsonPayloadEnabled;
1162
1163 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1164 {
1165 std::ostringstream stdPayloadStream;
1166 std::ostringstream oemPayloadStream;
1167
1168 stdPayloadStream << stdPayloadStr << payloadNum;
1169 oemPayloadStream << oemPayloadStr << payloadNum;
1170
1171 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1172 stdPayloadStream.str(), stdPayload[payloadNum]));
1173
1174 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1175 oemPayloadStream.str(), oemPayload[payloadNum]));
1176 }
1177 return jsonPayloadEnabled;
1178}
1179
1180void UserAccess::readPayloadAccessFromUserInfo(
1181 const UserInfo& userInfo,
1182 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload,
1183 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload)
1184{
1185 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1186 {
1187 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1188 {
1189 stdPayload[payloadNum][chIndex] =
1190 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum];
1191
1192 oemPayload[payloadNum][chIndex] =
1193 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum];
1194 }
1195 }
1196}
1197
1198void UserAccess::updatePayloadAccessInUserInfo(
1199 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1200 stdPayload,
1201 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1202 oemPayload,
1203 UserInfo& userInfo)
1204{
1205 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1206 {
1207 // Ensure that reserved/unsupported payloads are marked to zero.
1208 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset();
1209 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset();
1210 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset();
1211 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset();
1212 // Update SOL status as it is the only supported payload currently.
1213 userInfo.payloadAccess[chIndex]
1214 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] =
1215 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex];
1216 }
1217}
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301218
1219void UserAccess::readUserData()
1220{
1221 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1222 userLock{*userMutex};
1223
1224 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
1225 if (!iUsrData.good())
1226 {
1227 log<level::ERR>("Error in reading IPMI user data file");
1228 throw std::ios_base::failure("Error opening IPMI user data file");
1229 }
1230
1231 Json jsonUsersTbl = Json::array();
1232 jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
1233
1234 if (jsonUsersTbl.size() != ipmiMaxUsers)
1235 {
1236 log<level::ERR>(
1237 "Error in reading IPMI user data file - User count issues");
1238 throw std::runtime_error(
1239 "Corrupted IPMI user data file - invalid user count");
1240 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001241
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301242 // user index 0 is reserved, starts with 1
1243 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1244 {
1245 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
1246 if (userInfo.is_null())
1247 {
1248 log<level::ERR>("Error in reading IPMI user data file - "
1249 "user info corrupted");
1250 throw std::runtime_error(
1251 "Corrupted IPMI user data file - invalid user info");
1252 }
1253 std::string userName = userInfo[jsonUserName].get<std::string>();
1254 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
1255 userName.c_str(), ipmiMaxUserName);
1256
1257 std::vector<std::string> privilege =
1258 userInfo[jsonPriv].get<std::vector<std::string>>();
1259 std::vector<bool> ipmiEnabled =
1260 userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
1261 std::vector<bool> linkAuthEnabled =
1262 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
1263 std::vector<bool> accessCallback =
1264 userInfo[jsonAccCallbk].get<std::vector<bool>>();
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001265
1266 // Payload Enables Processing.
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001267 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1268 stdPayload = {};
1269 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1270 oemPayload = {};
1271 try
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001272 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001273 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr);
1274 for (auto payloadNum = 0; payloadNum < payloadsPerByte;
1275 payloadNum++)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001276 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001277 std::ostringstream stdPayloadStream;
1278 std::ostringstream oemPayloadStream;
1279
1280 stdPayloadStream << stdPayloadStr << payloadNum;
1281 oemPayloadStream << oemPayloadStr << payloadNum;
1282
1283 stdPayload[payloadNum] =
1284 jsonPayloadEnabled[stdPayloadStream.str()]
1285 .get<std::array<bool, ipmiMaxChannels>>();
1286 oemPayload[payloadNum] =
1287 jsonPayloadEnabled[oemPayloadStream.str()]
1288 .get<std::array<bool, ipmiMaxChannels>>();
1289
1290 if (stdPayload[payloadNum].size() != ipmiMaxChannels ||
1291 oemPayload[payloadNum].size() != ipmiMaxChannels)
1292 {
1293 log<level::ERR>("Error in reading IPMI user data file - "
1294 "payload properties corrupted");
1295 throw std::runtime_error(
1296 "Corrupted IPMI user data file - payload properties");
1297 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001298 }
1299 }
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001300 catch (Json::out_of_range& e)
1301 {
1302 // Key not found in 'userInfo'; possibly an old JSON file. Use
1303 // default values for all payloads, and SOL payload default is true.
1304 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true);
1305 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001306
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301307 if (privilege.size() != ipmiMaxChannels ||
1308 ipmiEnabled.size() != ipmiMaxChannels ||
1309 linkAuthEnabled.size() != ipmiMaxChannels ||
1310 accessCallback.size() != ipmiMaxChannels)
1311 {
1312 log<level::ERR>("Error in reading IPMI user data file - "
1313 "properties corrupted");
1314 throw std::runtime_error(
1315 "Corrupted IPMI user data file - properties");
1316 }
1317 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1318 {
1319 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
1320 static_cast<uint8_t>(
1321 convertToIPMIPrivilege(privilege[chIndex]));
1322 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
1323 ipmiEnabled[chIndex];
1324 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
1325 linkAuthEnabled[chIndex];
1326 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
1327 accessCallback[chIndex];
1328 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001329 updatePayloadAccessInUserInfo(stdPayload, oemPayload,
1330 usersTbl.user[usrIndex]);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301331 usersTbl.user[usrIndex].userEnabled =
1332 userInfo[jsonUserEnabled].get<bool>();
1333 usersTbl.user[usrIndex].userInSystem =
1334 userInfo[jsonUserInSys].get<bool>();
1335 usersTbl.user[usrIndex].fixedUserName =
1336 userInfo[jsonFixedUser].get<bool>();
1337 }
1338
1339 log<level::DEBUG>("User data read from IPMI data file");
1340 iUsrData.close();
1341 // Update the timestamp
1342 fileLastUpdatedTime = getUpdatedFileTime();
1343 return;
1344}
1345
1346void UserAccess::writeUserData()
1347{
1348 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1349 userLock{*userMutex};
1350
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301351 Json jsonUsersTbl = Json::array();
1352 // user index 0 is reserved, starts with 1
1353 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1354 {
1355 Json jsonUserInfo;
1356 jsonUserInfo[jsonUserName] = std::string(
1357 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
1358 ipmiMaxUserName);
1359 std::vector<std::string> privilege(ipmiMaxChannels);
1360 std::vector<bool> ipmiEnabled(ipmiMaxChannels);
1361 std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
1362 std::vector<bool> accessCallback(ipmiMaxChannels);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001363
1364 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1365 stdPayload;
1366 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1367 oemPayload;
1368
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301369 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1370 {
1371 privilege[chIndex] =
1372 convertToSystemPrivilege(static_cast<CommandPrivilege>(
1373 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
1374 ipmiEnabled[chIndex] =
1375 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
1376 linkAuthEnabled[chIndex] =
1377 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
1378 accessCallback[chIndex] =
1379 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
1380 }
1381 jsonUserInfo[jsonPriv] = privilege;
1382 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
1383 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
1384 jsonUserInfo[jsonAccCallbk] = accessCallback;
1385 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1386 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1387 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001388
1389 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload,
1390 oemPayload);
1391 Json jsonPayloadEnabledInfo =
1392 constructJsonPayloadEnables(stdPayload, oemPayload);
1393 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo;
1394
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301395 jsonUsersTbl.push_back(jsonUserInfo);
1396 }
1397
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +05301398 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
1399 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
1400 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1401 if (fd < 0)
1402 {
1403 log<level::ERR>("Error in creating temporary IPMI user data file");
1404 throw std::ios_base::failure(
1405 "Error in creating temporary IPMI user data file");
1406 }
1407 const auto& writeStr = jsonUsersTbl.dump();
1408 if (write(fd, writeStr.c_str(), writeStr.size()) !=
1409 static_cast<ssize_t>(writeStr.size()))
1410 {
1411 close(fd);
1412 log<level::ERR>("Error in writing temporary IPMI user data file");
1413 throw std::ios_base::failure(
1414 "Error in writing temporary IPMI user data file");
1415 }
1416 close(fd);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301417
1418 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1419 {
1420 log<level::ERR>("Error in renaming temporary IPMI user data file");
1421 throw std::runtime_error("Error in renaming IPMI user data file");
1422 }
1423 // Update the timestamp
1424 fileLastUpdatedTime = getUpdatedFileTime();
1425 return;
1426}
1427
1428bool UserAccess::addUserEntry(const std::string& userName,
1429 const std::string& sysPriv, const bool& enabled)
1430{
1431 UsersTbl* userData = getUsersTblPtr();
1432 size_t freeIndex = 0xFF;
1433 // user index 0 is reserved, starts with 1
1434 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1435 {
1436 std::string curName(
1437 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1438 ipmiMaxUserName);
1439 if (userName == curName)
1440 {
1441 log<level::DEBUG>("User name exists",
1442 entry("USER_NAME=%s", userName.c_str()));
1443 return false; // user name exists.
1444 }
1445
1446 if ((!userData->user[usrIndex].userInSystem) &&
1447 (userData->user[usrIndex].userName[0] == '\0') &&
1448 (freeIndex == 0xFF))
1449 {
1450 freeIndex = usrIndex;
1451 }
1452 }
1453 if (freeIndex == 0xFF)
1454 {
1455 log<level::ERR>("No empty slots found");
1456 return false;
1457 }
1458 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1459 userName.c_str(), ipmiMaxUserName);
1460 uint8_t priv =
1461 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1462 privMask;
1463 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1464 {
1465 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1466 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1467 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1468 true;
1469 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1470 }
1471 userData->user[freeIndex].userInSystem = true;
1472 userData->user[freeIndex].userEnabled = enabled;
1473
1474 return true;
1475}
1476
1477void UserAccess::deleteUserIndex(const size_t& usrIdx)
1478{
1479 UsersTbl* userData = getUsersTblPtr();
1480
1481 std::string userName(
1482 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1483 ipmiMaxUserName);
1484 ipmiClearUserEntryPassword(userName);
1485 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1486 static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1487 sizeof(userData->user[usrIdx].userName),
1488 0);
1489 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1490 {
1491 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1492 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1493 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1494 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1495 }
1496 userData->user[usrIdx].userInSystem = false;
1497 userData->user[usrIdx].userEnabled = false;
1498 return;
1499}
1500
1501void UserAccess::checkAndReloadUserData()
1502{
1503 std::time_t updateTime = getUpdatedFileTime();
1504 if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1505 {
1506 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1507 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1508 readUserData();
1509 }
1510 return;
1511}
1512
1513UsersTbl* UserAccess::getUsersTblPtr()
1514{
1515 // reload data before using it.
1516 checkAndReloadUserData();
1517 return &usersTbl;
1518}
1519
1520void UserAccess::getSystemPrivAndGroups()
1521{
1522 std::map<std::string, PrivAndGroupType> properties;
1523 try
1524 {
1525 auto method = bus.new_method_call(
1526 getUserServiceName().c_str(), userMgrObjBasePath,
1527 dBusPropertiesInterface, getAllPropertiesMethod);
1528 method.append(userMgrInterface);
1529
1530 auto reply = bus.call(method);
1531 reply.read(properties);
1532 }
1533 catch (const sdbusplus::exception::SdBusError& e)
1534 {
1535 log<level::DEBUG>("Failed to excute method",
1536 entry("METHOD=%s", getAllPropertiesMethod),
1537 entry("PATH=%s", userMgrObjBasePath));
1538 return;
1539 }
1540 for (const auto& t : properties)
1541 {
1542 auto key = t.first;
1543 if (key == allPrivProperty)
1544 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001545 availablePrivileges = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301546 }
1547 else if (key == allGrpProperty)
1548 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001549 availableGroups = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301550 }
1551 }
1552 // TODO: Implement Supported Privilege & Groups verification logic
1553 return;
1554}
1555
1556std::time_t UserAccess::getUpdatedFileTime()
1557{
1558 struct stat fileStat;
1559 if (stat(ipmiUserDataFile, &fileStat) != 0)
1560 {
1561 log<level::DEBUG>("Error in getting last updated time stamp");
1562 return -EIO;
1563 }
1564 return fileStat.st_mtime;
1565}
1566
1567void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1568 std::vector<std::string>& usrGrps,
1569 std::string& usrPriv, bool& usrEnabled)
1570{
1571 for (const auto& t : properties)
1572 {
1573 std::string key = t.first;
1574 if (key == userPrivProperty)
1575 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001576 usrPriv = std::get<std::string>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301577 }
1578 else if (key == userGrpProperty)
1579 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001580 usrGrps = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301581 }
1582 else if (key == userEnabledProperty)
1583 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001584 usrEnabled = std::get<bool>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301585 }
1586 }
1587 return;
1588}
1589
1590int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1591 std::vector<std::string>& usrGrps,
1592 std::string& usrPriv, bool& usrEnabled)
1593{
1594 auto usrObj = userObjs.find(usersInterface);
1595 if (usrObj != userObjs.end())
1596 {
1597 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1598 return 0;
1599 }
1600 return -EIO;
1601}
1602
arun-pmbbe728c2020-01-10 15:18:04 +05301603void UserAccess::cacheUserDataFile()
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301604{
1605 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1606 userLock{*userMutex};
1607 try
1608 {
1609 readUserData();
1610 }
1611 catch (const std::ios_base::failure& e)
1612 { // File is empty, create it for the first time
1613 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1614 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1615 // user index 0 is reserved, starts with 1
1616 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1617 {
1618 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1619 {
1620 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1621 privNoAccess;
Saravanan Palanisamy92d81192019-08-07 18:00:04 +00001622 usersTbl.user[userIndex]
1623 .payloadAccess[chIndex]
1624 .stdPayloadEnables1[static_cast<uint8_t>(
1625 ipmi::PayloadType::SOL)] = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301626 }
1627 }
1628 writeUserData();
1629 }
arun-pmbbe728c2020-01-10 15:18:04 +05301630 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
1631 // Register it for single object and single process either netipimd /
1632 // host-ipmid
1633 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
1634 {
1635 log<level::DEBUG>("Registering signal handler");
1636 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
1637 bus,
1638 sdbusplus::bus::match::rules::type::signal() +
1639 sdbusplus::bus::match::rules::interface(dBusObjManager) +
1640 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1641 [&](sdbusplus::message::message& msg) {
1642 userUpdatedSignalHandler(*this, msg);
1643 });
1644 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
1645 bus,
1646 sdbusplus::bus::match::rules::type::signal() +
1647 sdbusplus::bus::match::rules::interface(userMgrInterface) +
1648 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1649 [&](sdbusplus::message::message& msg) {
1650 userUpdatedSignalHandler(*this, msg);
1651 });
1652 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
1653 bus,
1654 sdbusplus::bus::match::rules::type::signal() +
1655 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
1656 sdbusplus::bus::match::rules::interface(
1657 dBusPropertiesInterface) +
1658 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
1659 sdbusplus::bus::match::rules::argN(0, usersInterface),
1660 [&](sdbusplus::message::message& msg) {
1661 userUpdatedSignalHandler(*this, msg);
1662 });
1663 signalHndlrObject = true;
1664 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301665 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1666 try
1667 {
1668 auto method = bus.new_method_call(getUserServiceName().c_str(),
1669 userMgrObjBasePath, dBusObjManager,
1670 getManagedObjectsMethod);
1671 auto reply = bus.call(method);
1672 reply.read(managedObjs);
1673 }
1674 catch (const sdbusplus::exception::SdBusError& e)
1675 {
1676 log<level::DEBUG>("Failed to excute method",
1677 entry("METHOD=%s", getSubTreeMethod),
1678 entry("PATH=%s", userMgrObjBasePath));
1679 return;
1680 }
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301681 bool updateRequired = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301682 UsersTbl* userData = &usersTbl;
1683 // user index 0 is reserved, starts with 1
1684 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1685 {
1686 if ((userData->user[usrIdx].userInSystem) &&
1687 (userData->user[usrIdx].userName[0] != '\0'))
1688 {
1689 std::vector<std::string> usrGrps;
1690 std::string usrPriv;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301691
1692 std::string userName(
1693 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1694 ipmiMaxUserName);
1695 std::string usersPath =
1696 std::string(userObjBasePath) + "/" + userName;
1697
1698 auto usrObj = managedObjs.find(usersPath);
1699 if (usrObj != managedObjs.end())
1700 {
Chen,Yugang0e862fa2019-09-06 11:03:05 +08001701 bool usrEnabled = false;
Patrick Venture3a697ad2019-08-19 11:12:05 -07001702
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301703 // User exist. Lets check and update other fileds
1704 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1705 usrEnabled);
1706 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1707 usrGrps.end())
1708 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301709 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301710 // Group "ipmi" is removed so lets remove user in IPMI
1711 deleteUserIndex(usrIdx);
1712 }
1713 else
1714 {
1715 // Group "ipmi" is present so lets update other properties
1716 // in IPMI
1717 uint8_t priv =
1718 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1719 // Update all channels priv, only if it is not equivalent to
1720 // getUsrMgmtSyncIndex()
1721 if (userData->user[usrIdx]
1722 .userPrivAccess[getUsrMgmtSyncIndex()]
1723 .privilege != priv)
1724 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301725 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301726 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1727 ++chIndex)
1728 {
1729 userData->user[usrIdx]
1730 .userPrivAccess[chIndex]
1731 .privilege = priv;
1732 }
1733 }
1734 if (userData->user[usrIdx].userEnabled != usrEnabled)
1735 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301736 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301737 userData->user[usrIdx].userEnabled = usrEnabled;
1738 }
1739 }
1740
1741 // We are done with this obj. lets delete from MAP
1742 managedObjs.erase(usrObj);
1743 }
1744 else
1745 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301746 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301747 deleteUserIndex(usrIdx);
1748 }
1749 }
1750 }
1751
1752 // Walk through remnaining managedObj users list
1753 // Add them to ipmi data base
1754 for (const auto& usrObj : managedObjs)
1755 {
1756 std::vector<std::string> usrGrps;
1757 std::string usrPriv, userName;
Chen,Yugang0e862fa2019-09-06 11:03:05 +08001758 bool usrEnabled = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301759 std::string usrObjPath = std::string(usrObj.first);
1760 if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1761 {
1762 log<level::ERR>("Error in user object path");
1763 continue;
1764 }
1765 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1766 // Add 'ipmi' group users
1767 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1768 usrGrps.end())
1769 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301770 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301771 // CREATE NEW USER
1772 if (true != addUserEntry(userName, usrPriv, usrEnabled))
1773 {
1774 break;
1775 }
1776 }
1777 }
1778
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301779 if (updateRequired)
1780 {
1781 // All userData slots update done. Lets write the data
1782 writeUserData();
1783 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301784
1785 return;
1786}
1787} // namespace ipmi