blob: 036f73d6ebd0bc1a79c6562927c0b1d9fdf8506c [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>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053030#include <nlohmann/json.hpp>
31#include <phosphor-logging/elog-errors.hpp>
32#include <phosphor-logging/log.hpp>
33#include <regex>
34#include <sdbusplus/bus/match.hpp>
35#include <sdbusplus/server/object.hpp>
Vernon Mauery16b86932019-05-01 08:36:11 -070036#include <variant>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053037#include <xyz/openbmc_project/Common/error.hpp>
38#include <xyz/openbmc_project/User/Common/error.hpp>
39
40namespace ipmi
41{
42
43// TODO: Move D-Bus & Object Manager related stuff, to common files
44// D-Bus property related
45static constexpr const char* dBusPropertiesInterface =
46 "org.freedesktop.DBus.Properties";
47static constexpr const char* getAllPropertiesMethod = "GetAll";
48static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
49static constexpr const char* setPropertiesMethod = "Set";
50
51// Object Manager related
52static constexpr const char* dBusObjManager =
53 "org.freedesktop.DBus.ObjectManager";
54static constexpr const char* getManagedObjectsMethod = "GetManagedObjects";
55// Object Manager signals
56static constexpr const char* intfAddedSignal = "InterfacesAdded";
57static constexpr const char* intfRemovedSignal = "InterfacesRemoved";
58
59// Object Mapper related
60static constexpr const char* objMapperService =
61 "xyz.openbmc_project.ObjectMapper";
62static constexpr const char* objMapperPath =
63 "/xyz/openbmc_project/object_mapper";
64static constexpr const char* objMapperInterface =
65 "xyz.openbmc_project.ObjectMapper";
66static constexpr const char* getSubTreeMethod = "GetSubTree";
67static constexpr const char* getObjectMethod = "GetObject";
68
69static constexpr const char* ipmiUserMutex = "ipmi_usr_mutex";
70static constexpr const char* ipmiMutexCleanupLockFile =
71 "/var/lib/ipmi/ipmi_usr_mutex_cleanup";
72static constexpr const char* ipmiUserDataFile = "/var/lib/ipmi/ipmi_user.json";
73static constexpr const char* ipmiGrpName = "ipmi";
74static constexpr size_t privNoAccess = 0xF;
75static constexpr size_t privMask = 0xF;
76
77// User manager related
78static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user";
79static constexpr const char* userObjBasePath = "/xyz/openbmc_project/user";
80static constexpr const char* userMgrInterface =
81 "xyz.openbmc_project.User.Manager";
82static constexpr const char* usersInterface =
83 "xyz.openbmc_project.User.Attributes";
84static constexpr const char* deleteUserInterface =
85 "xyz.openbmc_project.Object.Delete";
86
87static constexpr const char* createUserMethod = "CreateUser";
88static constexpr const char* deleteUserMethod = "Delete";
89static constexpr const char* renameUserMethod = "RenameUser";
90// User manager signal memebers
91static constexpr const char* userRenamedSignal = "UserRenamed";
92// Mgr interface properties
93static constexpr const char* allPrivProperty = "AllPrivileges";
94static constexpr const char* allGrpProperty = "AllGroups";
95// User interface properties
96static constexpr const char* userPrivProperty = "UserPrivilege";
97static constexpr const char* userGrpProperty = "UserGroups";
98static constexpr const char* userEnabledProperty = "UserEnabled";
99
100static std::array<std::string, (PRIVILEGE_OEM + 1)> ipmiPrivIndex = {
101 "priv-reserved", // PRIVILEGE_RESERVED - 0
102 "priv-callback", // PRIVILEGE_CALLBACK - 1
103 "priv-user", // PRIVILEGE_USER - 2
104 "priv-operator", // PRIVILEGE_OPERATOR - 3
105 "priv-admin", // PRIVILEGE_ADMIN - 4
106 "priv-custom" // PRIVILEGE_OEM - 5
107};
108
109using namespace phosphor::logging;
110using Json = nlohmann::json;
111
Vernon Mauery16b86932019-05-01 08:36:11 -0700112using PrivAndGroupType = std::variant<std::string, std::vector<std::string>>;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530113
114using NoResource =
115 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource;
116
117using InternalFailure =
118 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
119
Lei YU4b0ddb62019-01-25 16:43:50 +0800120std::unique_ptr<sdbusplus::bus::match_t> userUpdatedSignal
121 __attribute__((init_priority(101)));
122std::unique_ptr<sdbusplus::bus::match_t> userMgrRenamedSignal
123 __attribute__((init_priority(101)));
124std::unique_ptr<sdbusplus::bus::match_t> userPropertiesSignal
125 __attribute__((init_priority(101)));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530126
127// TODO: Below code can be removed once it is moved to common layer libmiscutil
128std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf,
129 const std::string& path)
130{
131 auto mapperCall = bus.new_method_call(objMapperService, objMapperPath,
132 objMapperInterface, getObjectMethod);
133
134 mapperCall.append(path);
135 mapperCall.append(std::vector<std::string>({intf}));
136
137 auto mapperResponseMsg = bus.call(mapperCall);
138
139 std::map<std::string, std::vector<std::string>> mapperResponse;
140 mapperResponseMsg.read(mapperResponse);
141
142 if (mapperResponse.begin() == mapperResponse.end())
143 {
144 throw sdbusplus::exception::SdBusError(
145 -EIO, "ERROR in reading the mapper response");
146 }
147
148 return mapperResponse.begin()->first;
149}
150
151void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service,
152 const std::string& objPath, const std::string& interface,
153 const std::string& property,
154 const DbusUserPropVariant& value)
155{
156 try
157 {
158 auto method =
159 bus.new_method_call(service.c_str(), objPath.c_str(),
160 dBusPropertiesInterface, setPropertiesMethod);
161 method.append(interface, property, value);
162 bus.call(method);
163 }
164 catch (const sdbusplus::exception::SdBusError& e)
165 {
166 log<level::ERR>("Failed to set property",
167 entry("PROPERTY=%s", property.c_str()),
168 entry("PATH=%s", objPath.c_str()),
169 entry("INTERFACE=%s", interface.c_str()));
170 throw;
171 }
172}
173
174static std::string getUserServiceName()
175{
176 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
177 static std::string userMgmtService;
178 if (userMgmtService.empty())
179 {
180 try
181 {
182 userMgmtService =
183 ipmi::getUserService(bus, userMgrInterface, userMgrObjBasePath);
184 }
185 catch (const sdbusplus::exception::SdBusError& e)
186 {
187 userMgmtService.clear();
188 }
189 }
190 return userMgmtService;
191}
192
193UserAccess& getUserAccessObject()
194{
195 static UserAccess userAccess;
196 return userAccess;
197}
198
199int getUserNameFromPath(const std::string& path, std::string& userName)
200{
Richard Marian Thomaiyare3d144f2020-01-09 11:55:06 +0530201 constexpr size_t length = strlen(userObjBasePath);
202 if (((length + 1) >= path.size()) ||
203 path.compare(0, length, userObjBasePath))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530204 {
205 return -EINVAL;
206 }
Richard Marian Thomaiyare3d144f2020-01-09 11:55:06 +0530207 userName.assign(path, length + 1, path.size());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530208 return 0;
209}
210
211void userUpdateHelper(UserAccess& usrAccess, const UserUpdateEvent& userEvent,
212 const std::string& userName, const std::string& priv,
213 const bool& enabled, const std::string& newUserName)
214{
215 UsersTbl* userData = usrAccess.getUsersTblPtr();
216 if (userEvent == UserUpdateEvent::userCreated)
217 {
218 if (usrAccess.addUserEntry(userName, priv, enabled) == false)
219 {
220 return;
221 }
222 }
223 else
224 {
225 // user index 0 is reserved, starts with 1
226 size_t usrIndex = 1;
227 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
228 {
229 std::string curName(
230 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
231 ipmiMaxUserName);
232 if (userName == curName)
233 {
234 break; // found the entry
235 }
236 }
237 if (usrIndex > ipmiMaxUsers)
238 {
239 log<level::DEBUG>("User not found for signal",
240 entry("USER_NAME=%s", userName.c_str()),
241 entry("USER_EVENT=%d", userEvent));
242 return;
243 }
244 switch (userEvent)
245 {
246 case UserUpdateEvent::userDeleted:
247 {
248 usrAccess.deleteUserIndex(usrIndex);
249 break;
250 }
251 case UserUpdateEvent::userPrivUpdated:
252 {
253 uint8_t userPriv =
254 static_cast<uint8_t>(
255 UserAccess::convertToIPMIPrivilege(priv)) &
256 privMask;
257 // Update all channels privileges, only if it is not equivalent
258 // to getUsrMgmtSyncIndex()
259 if (userData->user[usrIndex]
260 .userPrivAccess[UserAccess::getUsrMgmtSyncIndex()]
261 .privilege != userPriv)
262 {
263 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
264 ++chIndex)
265 {
266 userData->user[usrIndex]
267 .userPrivAccess[chIndex]
268 .privilege = userPriv;
269 }
270 }
271 break;
272 }
273 case UserUpdateEvent::userRenamed:
274 {
275 std::fill(
276 static_cast<uint8_t*>(userData->user[usrIndex].userName),
277 static_cast<uint8_t*>(userData->user[usrIndex].userName) +
278 sizeof(userData->user[usrIndex].userName),
279 0);
280 std::strncpy(
281 reinterpret_cast<char*>(userData->user[usrIndex].userName),
282 newUserName.c_str(), ipmiMaxUserName);
283 ipmiRenameUserEntryPassword(userName, newUserName);
284 break;
285 }
286 case UserUpdateEvent::userStateUpdated:
287 {
288 userData->user[usrIndex].userEnabled = enabled;
289 break;
290 }
291 default:
292 {
293 log<level::ERR>("Unhandled user event",
294 entry("USER_EVENT=%d", userEvent));
295 return;
296 }
297 }
298 }
299 usrAccess.writeUserData();
300 log<level::DEBUG>("User event handled successfully",
301 entry("USER_NAME=%s", userName.c_str()),
302 entry("USER_EVENT=%d", userEvent));
303
304 return;
305}
306
307void userUpdatedSignalHandler(UserAccess& usrAccess,
308 sdbusplus::message::message& msg)
309{
310 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
311 std::string signal = msg.get_member();
Patrick Venture3a697ad2019-08-19 11:12:05 -0700312 std::string userName, priv, newUserName;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530313 std::vector<std::string> groups;
314 bool enabled = false;
315 UserUpdateEvent userEvent = UserUpdateEvent::reservedEvent;
316 if (signal == intfAddedSignal)
317 {
318 DbusUserObjPath objPath;
319 DbusUserObjValue objValue;
320 msg.read(objPath, objValue);
321 getUserNameFromPath(objPath.str, userName);
322 if (usrAccess.getUserObjProperties(objValue, groups, priv, enabled) !=
323 0)
324 {
325 return;
326 }
327 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
328 groups.end())
329 {
330 return;
331 }
332 userEvent = UserUpdateEvent::userCreated;
333 }
334 else if (signal == intfRemovedSignal)
335 {
336 DbusUserObjPath objPath;
337 std::vector<std::string> interfaces;
338 msg.read(objPath, interfaces);
339 getUserNameFromPath(objPath.str, userName);
340 userEvent = UserUpdateEvent::userDeleted;
341 }
342 else if (signal == userRenamedSignal)
343 {
344 msg.read(userName, newUserName);
345 userEvent = UserUpdateEvent::userRenamed;
346 }
347 else if (signal == propertiesChangedSignal)
348 {
349 getUserNameFromPath(msg.get_path(), userName);
350 }
351 else
352 {
353 log<level::ERR>("Unknown user update signal",
354 entry("SIGNAL=%s", signal.c_str()));
355 return;
356 }
357
358 if (signal.empty() || userName.empty() ||
359 (signal == userRenamedSignal && newUserName.empty()))
360 {
361 log<level::ERR>("Invalid inputs received");
362 return;
363 }
364
365 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
366 userLock{*(usrAccess.userMutex)};
367 usrAccess.checkAndReloadUserData();
368
369 if (signal == propertiesChangedSignal)
370 {
371 std::string intfName;
372 DbusUserObjProperties chProperties;
373 msg.read(intfName, chProperties); // skip reading 3rd argument.
374 for (const auto& prop : chProperties)
375 {
376 userEvent = UserUpdateEvent::reservedEvent;
377 std::string member = prop.first;
378 if (member == userPrivProperty)
379 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700380 priv = std::get<std::string>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530381 userEvent = UserUpdateEvent::userPrivUpdated;
382 }
383 else if (member == userGrpProperty)
384 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700385 groups = std::get<std::vector<std::string>>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530386 userEvent = UserUpdateEvent::userGrpUpdated;
387 }
388 else if (member == userEnabledProperty)
389 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700390 enabled = std::get<bool>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530391 userEvent = UserUpdateEvent::userStateUpdated;
392 }
393 // Process based on event type.
394 if (userEvent == UserUpdateEvent::userGrpUpdated)
395 {
396 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
397 groups.end())
398 {
399 // remove user from ipmi user list.
400 userUpdateHelper(usrAccess, UserUpdateEvent::userDeleted,
401 userName, priv, enabled, newUserName);
402 }
403 else
404 {
405 DbusUserObjProperties properties;
406 try
407 {
408 auto method = bus.new_method_call(
409 getUserServiceName().c_str(), msg.get_path(),
410 dBusPropertiesInterface, getAllPropertiesMethod);
411 method.append(usersInterface);
412 auto reply = bus.call(method);
413 reply.read(properties);
414 }
415 catch (const sdbusplus::exception::SdBusError& e)
416 {
417 log<level::DEBUG>(
418 "Failed to excute method",
419 entry("METHOD=%s", getAllPropertiesMethod),
420 entry("PATH=%s", msg.get_path()));
421 return;
422 }
423 usrAccess.getUserProperties(properties, groups, priv,
424 enabled);
425 // add user to ipmi user list.
426 userUpdateHelper(usrAccess, UserUpdateEvent::userCreated,
427 userName, priv, enabled, newUserName);
428 }
429 }
430 else if (userEvent != UserUpdateEvent::reservedEvent)
431 {
432 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
433 newUserName);
434 }
435 }
436 }
437 else if (userEvent != UserUpdateEvent::reservedEvent)
438 {
439 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
440 newUserName);
441 }
442 return;
443}
444
445UserAccess::~UserAccess()
446{
447 if (signalHndlrObject)
448 {
449 userUpdatedSignal.reset();
450 userMgrRenamedSignal.reset();
451 userPropertiesSignal.reset();
452 sigHndlrLock.unlock();
453 }
454}
455
456UserAccess::UserAccess() : bus(ipmid_get_sd_bus_connection())
457{
458 std::ofstream mutexCleanUpFile;
459 mutexCleanUpFile.open(ipmiMutexCleanupLockFile,
460 std::ofstream::out | std::ofstream::app);
461 if (!mutexCleanUpFile.good())
462 {
463 log<level::DEBUG>("Unable to open mutex cleanup file");
464 return;
465 }
466 mutexCleanUpFile.close();
467 mutexCleanupLock = boost::interprocess::file_lock(ipmiMutexCleanupLockFile);
468 if (mutexCleanupLock.try_lock())
469 {
470 boost::interprocess::named_recursive_mutex::remove(ipmiUserMutex);
471 }
472 mutexCleanupLock.lock_sharable();
473 userMutex = std::make_unique<boost::interprocess::named_recursive_mutex>(
474 boost::interprocess::open_or_create, ipmiUserMutex);
475
arun-pmbbe728c2020-01-10 15:18:04 +0530476 cacheUserDataFile();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530477 getSystemPrivAndGroups();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530478}
479
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530480UserInfo* UserAccess::getUserInfo(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530481{
482 checkAndReloadUserData();
483 return &usersTbl.user[userId];
484}
485
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530486void UserAccess::setUserInfo(const uint8_t userId, UserInfo* userInfo)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530487{
488 checkAndReloadUserData();
489 std::copy(reinterpret_cast<uint8_t*>(userInfo),
490 reinterpret_cast<uint8_t*>(userInfo) + sizeof(*userInfo),
491 reinterpret_cast<uint8_t*>(&usersTbl.user[userId]));
492 writeUserData();
493}
494
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530495bool UserAccess::isValidChannel(const uint8_t chNum)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530496{
497 return (chNum < ipmiMaxChannels);
498}
499
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530500bool UserAccess::isValidUserId(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530501{
502 return ((userId <= ipmiMaxUsers) && (userId != reservedUserId));
503}
504
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530505bool UserAccess::isValidPrivilege(const uint8_t priv)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530506{
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000507 // Callback privilege is deprecated in OpenBMC
508 return (isValidPrivLimit(priv) || priv == privNoAccess);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530509}
510
511uint8_t UserAccess::getUsrMgmtSyncIndex()
512{
Johnathan Manteyfd61fc32021-04-08 11:05:38 -0700513 // Identify the IPMI channel used to assign system user privilege levels
514 // in phosphor-user-manager. The default value is IPMI Channel 1. To
515 // assign a different channel add:
516 // "is_management_nic" : true
517 // into the channel_config.json file describing the assignment of the IPMI
518 // channels. It is only necessary to add the string above to ONE record in
519 // the channel_config.json file. All other records will be automatically
520 // assigned a "false" value.
521 return getChannelConfigObject().getManagementNICID();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530522}
523
524CommandPrivilege UserAccess::convertToIPMIPrivilege(const std::string& value)
525{
526 auto iter = std::find(ipmiPrivIndex.begin(), ipmiPrivIndex.end(), value);
527 if (iter == ipmiPrivIndex.end())
528 {
529 if (value == "")
530 {
531 return static_cast<CommandPrivilege>(privNoAccess);
532 }
533 log<level::ERR>("Error in converting to IPMI privilege",
534 entry("PRIV=%s", value.c_str()));
535 throw std::out_of_range("Out of range - convertToIPMIPrivilege");
536 }
537 else
538 {
539 return static_cast<CommandPrivilege>(
540 std::distance(ipmiPrivIndex.begin(), iter));
541 }
542}
543
544std::string UserAccess::convertToSystemPrivilege(const CommandPrivilege& value)
545{
546 if (value == static_cast<CommandPrivilege>(privNoAccess))
547 {
548 return "";
549 }
550 try
551 {
552 return ipmiPrivIndex.at(value);
553 }
554 catch (const std::out_of_range& e)
555 {
556 log<level::ERR>("Error in converting to system privilege",
557 entry("PRIV=%d", static_cast<uint8_t>(value)));
558 throw std::out_of_range("Out of range - convertToSystemPrivilege");
559 }
560}
561
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000562bool UserAccess::isValidUserName(const std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530563{
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000564 if (userName.empty())
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530565 {
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000566 log<level::ERR>("userName is empty");
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530567 return false;
568 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530569 if (!std::regex_match(userName.c_str(),
570 std::regex("[a-zA-z_][a-zA-Z_0-9]*")))
571 {
572 log<level::ERR>("Unsupported characters in user name");
573 return false;
574 }
575 if (userName == "root")
576 {
577 log<level::ERR>("Invalid user name - root");
578 return false;
579 }
580 std::map<DbusUserObjPath, DbusUserObjValue> properties;
581 try
582 {
583 auto method = bus.new_method_call(getUserServiceName().c_str(),
584 userMgrObjBasePath, dBusObjManager,
585 getManagedObjectsMethod);
586 auto reply = bus.call(method);
587 reply.read(properties);
588 }
589 catch (const sdbusplus::exception::SdBusError& e)
590 {
591 log<level::ERR>("Failed to excute method",
592 entry("METHOD=%s", getSubTreeMethod),
593 entry("PATH=%s", userMgrObjBasePath));
594 return false;
595 }
596
597 std::string usersPath = std::string(userObjBasePath) + "/" + userName;
598 if (properties.find(usersPath) != properties.end())
599 {
600 log<level::DEBUG>("User name already exists",
601 entry("USER_NAME=%s", userName.c_str()));
602 return false;
603 }
604
605 return true;
606}
607
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530608/** @brief Information exchanged by pam module and application.
609 *
610 * @param[in] numMsg - length of the array of pointers,msg.
611 *
612 * @param[in] msg - pointer to an array of pointers to pam_message structure
613 *
614 * @param[out] resp - struct pam response array
615 *
616 * @param[in] appdataPtr - member of pam_conv structure
617 *
618 * @return the response in pam response structure.
619 */
620
621static int pamFunctionConversation(int numMsg, const struct pam_message** msg,
622 struct pam_response** resp, void* appdataPtr)
623{
624 if (appdataPtr == nullptr)
625 {
626 return PAM_AUTH_ERR;
627 }
628 size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1;
629 char* pass = reinterpret_cast<char*>(malloc(passSize));
630 std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize);
631
632 *resp = reinterpret_cast<pam_response*>(
633 calloc(numMsg, sizeof(struct pam_response)));
634
635 for (int i = 0; i < numMsg; ++i)
636 {
637 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
638 {
639 continue;
640 }
641 resp[i]->resp = pass;
642 }
643 return PAM_SUCCESS;
644}
645
646/** @brief Updating the PAM password
647 *
648 * @param[in] username - username in string
649 *
650 * @param[in] password - new password in string
651 *
652 * @return status
653 */
654
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000655int pamUpdatePasswd(const char* username, const char* password)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530656{
657 const struct pam_conv localConversation = {pamFunctionConversation,
658 const_cast<char*>(password)};
659 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
660
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000661 int retval =
662 pam_start("passwd", username, &localConversation, &localAuthHandle);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530663
664 if (retval != PAM_SUCCESS)
665 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000666 return retval;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530667 }
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000668
669 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
670 if (retval != PAM_SUCCESS)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530671 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000672 pam_end(localAuthHandle, retval);
673 return retval;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530674 }
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000675
676 return pam_end(localAuthHandle, PAM_SUCCESS);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530677}
678
Ayushi Smriti02650d52019-05-15 11:59:09 +0000679bool pamUserCheckAuthenticate(std::string_view username,
680 std::string_view password)
681{
682 const struct pam_conv localConversation = {
683 pamFunctionConversation, const_cast<char*>(password.data())};
684
685 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
686
687 if (pam_start("dropbear", username.data(), &localConversation,
688 &localAuthHandle) != PAM_SUCCESS)
689 {
690 log<level::ERR>("User Authentication Failure");
691 return false;
692 }
693
694 int retval = pam_authenticate(localAuthHandle,
695 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
696
697 if (retval != PAM_SUCCESS)
698 {
699 log<level::DEBUG>("pam_authenticate returned failure",
700 entry("ERROR=%d", retval));
701
702 pam_end(localAuthHandle, retval);
703 return false;
704 }
705
706 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
707 PAM_SUCCESS)
708 {
709 pam_end(localAuthHandle, PAM_SUCCESS);
710 return false;
711 }
712
713 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
714 {
715 return false;
716 }
717 return true;
718}
719
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000720Cc UserAccess::setSpecialUserPassword(const std::string& userName,
721 const std::string& userPassword)
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530722{
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000723 if (pamUpdatePasswd(userName.c_str(), userPassword.c_str()) != PAM_SUCCESS)
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530724 {
725 log<level::DEBUG>("Failed to update password");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000726 return ccUnspecifiedError;
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530727 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000728 return ccSuccess;
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530729}
730
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000731Cc UserAccess::setUserPassword(const uint8_t userId, const char* userPassword)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530732{
733 std::string userName;
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000734 if (ipmiUserGetUserName(userId, userName) != ccSuccess)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530735 {
736 log<level::DEBUG>("User Name not found",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530737 entry("USER-ID=%d", (uint8_t)userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000738 return ccParmOutOfRange;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530739 }
Snehalatha Venkatesh61024d72021-04-08 16:24:39 +0000740
741 ipmi::SecureString passwd;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530742 passwd.assign(reinterpret_cast<const char*>(userPassword), 0,
743 maxIpmi20PasswordSize);
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000744 int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str());
745
746 switch (retval)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530747 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000748 case PAM_SUCCESS:
749 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000750 return ccSuccess;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000751 }
752 case PAM_AUTHTOK_ERR:
753 {
754 log<level::DEBUG>("Bad authentication token");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000755 return ccInvalidFieldRequest;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000756 }
757 default:
758 {
759 log<level::DEBUG>("Failed to update password",
760 entry("USER-ID=%d", (uint8_t)userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000761 return ccUnspecifiedError;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000762 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530763 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530764}
765
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000766Cc UserAccess::setUserEnabledState(const uint8_t userId,
767 const bool& enabledState)
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530768{
769 if (!isValidUserId(userId))
770 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000771 return ccParmOutOfRange;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530772 }
773 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
774 userLock{*userMutex};
775 UserInfo* userInfo = getUserInfo(userId);
776 std::string userName;
777 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
778 ipmiMaxUserName);
779 if (userName.empty())
780 {
781 log<level::DEBUG>("User name not set / invalid");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000782 return ccUnspecifiedError;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530783 }
784 if (userInfo->userEnabled != enabledState)
785 {
786 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800787 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
788 userEnabledProperty, enabledState);
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530789 userInfo->userEnabled = enabledState;
790 try
791 {
792 writeUserData();
793 }
794 catch (const std::exception& e)
795 {
796 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000797 return ccUnspecifiedError;
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530798 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530799 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000800 return ccSuccess;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530801}
802
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000803Cc UserAccess::setUserPayloadAccess(const uint8_t chNum,
804 const uint8_t operation,
805 const uint8_t userId,
806 const PayloadAccess& payloadAccess)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000807{
808 constexpr uint8_t enable = 0x0;
809 constexpr uint8_t disable = 0x1;
810
811 if (!isValidChannel(chNum))
812 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000813 return ccInvalidFieldRequest;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000814 }
815 if (!isValidUserId(userId))
816 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000817 return ccParmOutOfRange;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000818 }
819 if (operation != enable && operation != disable)
820 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000821 return ccInvalidFieldRequest;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000822 }
823 // Check operation & payloadAccess if required.
824 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
825 userLock{*userMutex};
826 UserInfo* userInfo = getUserInfo(userId);
827
828 if (operation == enable)
829 {
830 userInfo->payloadAccess[chNum].stdPayloadEnables1 |=
831 payloadAccess.stdPayloadEnables1;
832
833 userInfo->payloadAccess[chNum].oemPayloadEnables1 |=
834 payloadAccess.oemPayloadEnables1;
835 }
836 else
837 {
838 userInfo->payloadAccess[chNum].stdPayloadEnables1 &=
839 ~(payloadAccess.stdPayloadEnables1);
840
841 userInfo->payloadAccess[chNum].oemPayloadEnables1 &=
842 ~(payloadAccess.oemPayloadEnables1);
843 }
844
845 try
846 {
847 writeUserData();
848 }
849 catch (const std::exception& e)
850 {
851 log<level::ERR>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000852 return ccUnspecifiedError;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000853 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000854 return ccSuccess;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000855}
856
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000857Cc UserAccess::setUserPrivilegeAccess(const uint8_t userId, const uint8_t chNum,
858 const UserPrivAccess& privAccess,
859 const bool& otherPrivUpdates)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530860{
861 if (!isValidChannel(chNum))
862 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000863 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530864 }
865 if (!isValidUserId(userId))
866 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000867 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530868 }
869 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
870 userLock{*userMutex};
871 UserInfo* userInfo = getUserInfo(userId);
872 std::string userName;
873 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
874 ipmiMaxUserName);
875 if (userName.empty())
876 {
877 log<level::DEBUG>("User name not set / invalid");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000878 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530879 }
880 std::string priv = convertToSystemPrivilege(
881 static_cast<CommandPrivilege>(privAccess.privilege));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530882 uint8_t syncIndex = getUsrMgmtSyncIndex();
883 if (chNum == syncIndex &&
884 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
885 {
886 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800887 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
888 userPrivProperty, priv);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530889 }
890 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
891
892 if (otherPrivUpdates)
893 {
894 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
895 userInfo->userPrivAccess[chNum].linkAuthEnabled =
896 privAccess.linkAuthEnabled;
897 userInfo->userPrivAccess[chNum].accessCallback =
898 privAccess.accessCallback;
899 }
900 try
901 {
902 writeUserData();
903 }
904 catch (const std::exception& e)
905 {
906 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000907 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530908 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000909 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530910}
911
912uint8_t UserAccess::getUserId(const std::string& userName)
913{
914 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
915 userLock{*userMutex};
916 checkAndReloadUserData();
917 // user index 0 is reserved, starts with 1
918 size_t usrIndex = 1;
919 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
920 {
921 std::string curName(
922 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
923 ipmiMaxUserName);
924 if (userName == curName)
925 {
926 break; // found the entry
927 }
928 }
929 if (usrIndex > ipmiMaxUsers)
930 {
931 log<level::DEBUG>("User not found",
932 entry("USER_NAME=%s", userName.c_str()));
933 return invalidUserId;
934 }
935
936 return usrIndex;
937}
938
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000939Cc UserAccess::getUserName(const uint8_t userId, std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530940{
941 if (!isValidUserId(userId))
942 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000943 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530944 }
945 UserInfo* userInfo = getUserInfo(userId);
946 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
947 ipmiMaxUserName);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000948 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530949}
950
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +0530951bool UserAccess::isIpmiInAvailableGroupList()
952{
953 if (std::find(availableGroups.begin(), availableGroups.end(),
954 ipmiGrpName) != availableGroups.end())
955 {
956 return true;
957 }
958 if (availableGroups.empty())
959 {
960 // available groups shouldn't be empty, re-query
961 getSystemPrivAndGroups();
962 if (std::find(availableGroups.begin(), availableGroups.end(),
963 ipmiGrpName) != availableGroups.end())
964 {
965 return true;
966 }
967 }
968 return false;
969}
970
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000971Cc UserAccess::setUserName(const uint8_t userId, const std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530972{
973 if (!isValidUserId(userId))
974 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000975 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530976 }
977
978 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
979 userLock{*userMutex};
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530980 std::string oldUser;
981 getUserName(userId, oldUser);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530982
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000983 if (oldUser == userName)
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530984 {
985 // requesting to set the same user name, return success.
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000986 return ccSuccess;
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530987 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000988
989 bool validUser = isValidUserName(userName);
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530990 UserInfo* userInfo = getUserInfo(userId);
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000991 if (userName.empty() && !oldUser.empty())
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530992 {
993 // Delete existing user
994 std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
995 try
996 {
997 auto method = bus.new_method_call(
998 getUserServiceName().c_str(), userPath.c_str(),
999 deleteUserInterface, deleteUserMethod);
1000 auto reply = bus.call(method);
1001 }
1002 catch (const sdbusplus::exception::SdBusError& e)
1003 {
1004 log<level::DEBUG>("Failed to excute method",
1005 entry("METHOD=%s", deleteUserMethod),
1006 entry("PATH=%s", userPath.c_str()));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001007 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301008 }
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +05301009 deleteUserIndex(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301010 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001011 else if (oldUser.empty() && !userName.empty() && validUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301012 {
1013 try
1014 {
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +05301015 if (!isIpmiInAvailableGroupList())
1016 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001017 return ccUnspecifiedError;
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +05301018 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301019 // Create new user
1020 auto method = bus.new_method_call(
1021 getUserServiceName().c_str(), userMgrObjBasePath,
1022 userMgrInterface, createUserMethod);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001023 method.append(userName.c_str(), availableGroups, "", false);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301024 auto reply = bus.call(method);
1025 }
1026 catch (const sdbusplus::exception::SdBusError& e)
1027 {
1028 log<level::DEBUG>("Failed to excute method",
1029 entry("METHOD=%s", createUserMethod),
1030 entry("PATH=%s", userMgrObjBasePath));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001031 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301032 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001033
1034 std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1035 std::memcpy(userInfo->userName,
1036 static_cast<const void*>(userName.data()), userName.size());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301037 userInfo->userInSystem = true;
1038 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001039 else if (oldUser != userName && validUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301040 {
1041 try
1042 {
1043 // User rename
1044 auto method = bus.new_method_call(
1045 getUserServiceName().c_str(), userMgrObjBasePath,
1046 userMgrInterface, renameUserMethod);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001047 method.append(oldUser.c_str(), userName.c_str());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301048 auto reply = bus.call(method);
1049 }
1050 catch (const sdbusplus::exception::SdBusError& e)
1051 {
1052 log<level::DEBUG>("Failed to excute method",
1053 entry("METHOD=%s", renameUserMethod),
1054 entry("PATH=%s", userMgrObjBasePath));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001055 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301056 }
1057 std::fill(static_cast<uint8_t*>(userInfo->userName),
1058 static_cast<uint8_t*>(userInfo->userName) +
1059 sizeof(userInfo->userName),
1060 0);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001061
1062 std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1063 std::memcpy(userInfo->userName,
1064 static_cast<const void*>(userName.data()), userName.size());
1065
1066 ipmiRenameUserEntryPassword(oldUser, userName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301067 userInfo->userInSystem = true;
1068 }
1069 else if (!validUser)
1070 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001071 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301072 }
1073 try
1074 {
1075 writeUserData();
1076 }
1077 catch (const std::exception& e)
1078 {
1079 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001080 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301081 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001082 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301083}
1084
1085static constexpr const char* jsonUserName = "user_name";
1086static constexpr const char* jsonPriv = "privilege";
1087static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
1088static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
1089static constexpr const char* jsonAccCallbk = "access_callback";
1090static constexpr const char* jsonUserEnabled = "user_enabled";
1091static constexpr const char* jsonUserInSys = "user_in_system";
1092static constexpr const char* jsonFixedUser = "fixed_user_name";
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001093static constexpr const char* payloadEnabledStr = "payload_enabled";
1094static constexpr const char* stdPayloadStr = "std_payload";
1095static constexpr const char* oemPayloadStr = "OEM_payload";
1096
1097/** @brief to construct a JSON object from the given payload access details.
1098 *
1099 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input)
1100 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input)
1101 *
1102 * @details Sample output JSON object format :
1103 * "payload_enabled":{
1104 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1105 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1106 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1107 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1108 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1109 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1110 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1111 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1112 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1113 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1114 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1115 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1116 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1117 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1118 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1119 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1120 * }
1121 */
1122static const Json constructJsonPayloadEnables(
1123 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1124 stdPayload,
1125 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1126 oemPayload)
1127{
1128 Json jsonPayloadEnabled;
1129
1130 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1131 {
1132 std::ostringstream stdPayloadStream;
1133 std::ostringstream oemPayloadStream;
1134
1135 stdPayloadStream << stdPayloadStr << payloadNum;
1136 oemPayloadStream << oemPayloadStr << payloadNum;
1137
1138 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1139 stdPayloadStream.str(), stdPayload[payloadNum]));
1140
1141 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1142 oemPayloadStream.str(), oemPayload[payloadNum]));
1143 }
1144 return jsonPayloadEnabled;
1145}
1146
1147void UserAccess::readPayloadAccessFromUserInfo(
1148 const UserInfo& userInfo,
1149 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload,
1150 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload)
1151{
1152 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1153 {
1154 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1155 {
1156 stdPayload[payloadNum][chIndex] =
1157 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum];
1158
1159 oemPayload[payloadNum][chIndex] =
1160 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum];
1161 }
1162 }
1163}
1164
1165void UserAccess::updatePayloadAccessInUserInfo(
1166 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1167 stdPayload,
1168 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1169 oemPayload,
1170 UserInfo& userInfo)
1171{
1172 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1173 {
1174 // Ensure that reserved/unsupported payloads are marked to zero.
1175 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset();
1176 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset();
1177 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset();
1178 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset();
1179 // Update SOL status as it is the only supported payload currently.
1180 userInfo.payloadAccess[chIndex]
1181 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] =
1182 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex];
1183 }
1184}
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301185
1186void UserAccess::readUserData()
1187{
1188 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1189 userLock{*userMutex};
1190
1191 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
1192 if (!iUsrData.good())
1193 {
1194 log<level::ERR>("Error in reading IPMI user data file");
1195 throw std::ios_base::failure("Error opening IPMI user data file");
1196 }
1197
1198 Json jsonUsersTbl = Json::array();
1199 jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
1200
1201 if (jsonUsersTbl.size() != ipmiMaxUsers)
1202 {
1203 log<level::ERR>(
1204 "Error in reading IPMI user data file - User count issues");
1205 throw std::runtime_error(
1206 "Corrupted IPMI user data file - invalid user count");
1207 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001208
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301209 // user index 0 is reserved, starts with 1
1210 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1211 {
1212 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
1213 if (userInfo.is_null())
1214 {
1215 log<level::ERR>("Error in reading IPMI user data file - "
1216 "user info corrupted");
1217 throw std::runtime_error(
1218 "Corrupted IPMI user data file - invalid user info");
1219 }
1220 std::string userName = userInfo[jsonUserName].get<std::string>();
1221 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
1222 userName.c_str(), ipmiMaxUserName);
1223
1224 std::vector<std::string> privilege =
1225 userInfo[jsonPriv].get<std::vector<std::string>>();
1226 std::vector<bool> ipmiEnabled =
1227 userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
1228 std::vector<bool> linkAuthEnabled =
1229 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
1230 std::vector<bool> accessCallback =
1231 userInfo[jsonAccCallbk].get<std::vector<bool>>();
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001232
1233 // Payload Enables Processing.
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001234 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1235 stdPayload = {};
1236 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1237 oemPayload = {};
1238 try
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001239 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001240 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr);
1241 for (auto payloadNum = 0; payloadNum < payloadsPerByte;
1242 payloadNum++)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001243 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001244 std::ostringstream stdPayloadStream;
1245 std::ostringstream oemPayloadStream;
1246
1247 stdPayloadStream << stdPayloadStr << payloadNum;
1248 oemPayloadStream << oemPayloadStr << payloadNum;
1249
1250 stdPayload[payloadNum] =
1251 jsonPayloadEnabled[stdPayloadStream.str()]
1252 .get<std::array<bool, ipmiMaxChannels>>();
1253 oemPayload[payloadNum] =
1254 jsonPayloadEnabled[oemPayloadStream.str()]
1255 .get<std::array<bool, ipmiMaxChannels>>();
1256
1257 if (stdPayload[payloadNum].size() != ipmiMaxChannels ||
1258 oemPayload[payloadNum].size() != ipmiMaxChannels)
1259 {
1260 log<level::ERR>("Error in reading IPMI user data file - "
1261 "payload properties corrupted");
1262 throw std::runtime_error(
1263 "Corrupted IPMI user data file - payload properties");
1264 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001265 }
1266 }
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001267 catch (Json::out_of_range& e)
1268 {
1269 // Key not found in 'userInfo'; possibly an old JSON file. Use
1270 // default values for all payloads, and SOL payload default is true.
1271 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true);
1272 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001273
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301274 if (privilege.size() != ipmiMaxChannels ||
1275 ipmiEnabled.size() != ipmiMaxChannels ||
1276 linkAuthEnabled.size() != ipmiMaxChannels ||
1277 accessCallback.size() != ipmiMaxChannels)
1278 {
1279 log<level::ERR>("Error in reading IPMI user data file - "
1280 "properties corrupted");
1281 throw std::runtime_error(
1282 "Corrupted IPMI user data file - properties");
1283 }
1284 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1285 {
1286 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
1287 static_cast<uint8_t>(
1288 convertToIPMIPrivilege(privilege[chIndex]));
1289 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
1290 ipmiEnabled[chIndex];
1291 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
1292 linkAuthEnabled[chIndex];
1293 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
1294 accessCallback[chIndex];
1295 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001296 updatePayloadAccessInUserInfo(stdPayload, oemPayload,
1297 usersTbl.user[usrIndex]);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301298 usersTbl.user[usrIndex].userEnabled =
1299 userInfo[jsonUserEnabled].get<bool>();
1300 usersTbl.user[usrIndex].userInSystem =
1301 userInfo[jsonUserInSys].get<bool>();
1302 usersTbl.user[usrIndex].fixedUserName =
1303 userInfo[jsonFixedUser].get<bool>();
1304 }
1305
1306 log<level::DEBUG>("User data read from IPMI data file");
1307 iUsrData.close();
1308 // Update the timestamp
1309 fileLastUpdatedTime = getUpdatedFileTime();
1310 return;
1311}
1312
1313void UserAccess::writeUserData()
1314{
1315 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1316 userLock{*userMutex};
1317
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301318 Json jsonUsersTbl = Json::array();
1319 // user index 0 is reserved, starts with 1
1320 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1321 {
1322 Json jsonUserInfo;
1323 jsonUserInfo[jsonUserName] = std::string(
1324 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
1325 ipmiMaxUserName);
1326 std::vector<std::string> privilege(ipmiMaxChannels);
1327 std::vector<bool> ipmiEnabled(ipmiMaxChannels);
1328 std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
1329 std::vector<bool> accessCallback(ipmiMaxChannels);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001330
1331 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1332 stdPayload;
1333 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1334 oemPayload;
1335
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301336 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1337 {
1338 privilege[chIndex] =
1339 convertToSystemPrivilege(static_cast<CommandPrivilege>(
1340 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
1341 ipmiEnabled[chIndex] =
1342 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
1343 linkAuthEnabled[chIndex] =
1344 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
1345 accessCallback[chIndex] =
1346 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
1347 }
1348 jsonUserInfo[jsonPriv] = privilege;
1349 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
1350 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
1351 jsonUserInfo[jsonAccCallbk] = accessCallback;
1352 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1353 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1354 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001355
1356 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload,
1357 oemPayload);
1358 Json jsonPayloadEnabledInfo =
1359 constructJsonPayloadEnables(stdPayload, oemPayload);
1360 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo;
1361
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301362 jsonUsersTbl.push_back(jsonUserInfo);
1363 }
1364
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +05301365 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
1366 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
1367 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1368 if (fd < 0)
1369 {
1370 log<level::ERR>("Error in creating temporary IPMI user data file");
1371 throw std::ios_base::failure(
1372 "Error in creating temporary IPMI user data file");
1373 }
1374 const auto& writeStr = jsonUsersTbl.dump();
1375 if (write(fd, writeStr.c_str(), writeStr.size()) !=
1376 static_cast<ssize_t>(writeStr.size()))
1377 {
1378 close(fd);
1379 log<level::ERR>("Error in writing temporary IPMI user data file");
1380 throw std::ios_base::failure(
1381 "Error in writing temporary IPMI user data file");
1382 }
1383 close(fd);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301384
1385 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1386 {
1387 log<level::ERR>("Error in renaming temporary IPMI user data file");
1388 throw std::runtime_error("Error in renaming IPMI user data file");
1389 }
1390 // Update the timestamp
1391 fileLastUpdatedTime = getUpdatedFileTime();
1392 return;
1393}
1394
1395bool UserAccess::addUserEntry(const std::string& userName,
1396 const std::string& sysPriv, const bool& enabled)
1397{
1398 UsersTbl* userData = getUsersTblPtr();
1399 size_t freeIndex = 0xFF;
1400 // user index 0 is reserved, starts with 1
1401 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1402 {
1403 std::string curName(
1404 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1405 ipmiMaxUserName);
1406 if (userName == curName)
1407 {
1408 log<level::DEBUG>("User name exists",
1409 entry("USER_NAME=%s", userName.c_str()));
1410 return false; // user name exists.
1411 }
1412
1413 if ((!userData->user[usrIndex].userInSystem) &&
1414 (userData->user[usrIndex].userName[0] == '\0') &&
1415 (freeIndex == 0xFF))
1416 {
1417 freeIndex = usrIndex;
1418 }
1419 }
1420 if (freeIndex == 0xFF)
1421 {
1422 log<level::ERR>("No empty slots found");
1423 return false;
1424 }
1425 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1426 userName.c_str(), ipmiMaxUserName);
1427 uint8_t priv =
1428 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1429 privMask;
1430 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1431 {
1432 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1433 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1434 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1435 true;
1436 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1437 }
1438 userData->user[freeIndex].userInSystem = true;
1439 userData->user[freeIndex].userEnabled = enabled;
1440
1441 return true;
1442}
1443
1444void UserAccess::deleteUserIndex(const size_t& usrIdx)
1445{
1446 UsersTbl* userData = getUsersTblPtr();
1447
1448 std::string userName(
1449 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1450 ipmiMaxUserName);
1451 ipmiClearUserEntryPassword(userName);
1452 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1453 static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1454 sizeof(userData->user[usrIdx].userName),
1455 0);
1456 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1457 {
1458 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1459 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1460 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1461 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1462 }
1463 userData->user[usrIdx].userInSystem = false;
1464 userData->user[usrIdx].userEnabled = false;
1465 return;
1466}
1467
1468void UserAccess::checkAndReloadUserData()
1469{
1470 std::time_t updateTime = getUpdatedFileTime();
1471 if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1472 {
1473 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1474 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1475 readUserData();
1476 }
1477 return;
1478}
1479
1480UsersTbl* UserAccess::getUsersTblPtr()
1481{
1482 // reload data before using it.
1483 checkAndReloadUserData();
1484 return &usersTbl;
1485}
1486
1487void UserAccess::getSystemPrivAndGroups()
1488{
1489 std::map<std::string, PrivAndGroupType> properties;
1490 try
1491 {
1492 auto method = bus.new_method_call(
1493 getUserServiceName().c_str(), userMgrObjBasePath,
1494 dBusPropertiesInterface, getAllPropertiesMethod);
1495 method.append(userMgrInterface);
1496
1497 auto reply = bus.call(method);
1498 reply.read(properties);
1499 }
1500 catch (const sdbusplus::exception::SdBusError& e)
1501 {
1502 log<level::DEBUG>("Failed to excute method",
1503 entry("METHOD=%s", getAllPropertiesMethod),
1504 entry("PATH=%s", userMgrObjBasePath));
1505 return;
1506 }
1507 for (const auto& t : properties)
1508 {
1509 auto key = t.first;
1510 if (key == allPrivProperty)
1511 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001512 availablePrivileges = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301513 }
1514 else if (key == allGrpProperty)
1515 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001516 availableGroups = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301517 }
1518 }
1519 // TODO: Implement Supported Privilege & Groups verification logic
1520 return;
1521}
1522
1523std::time_t UserAccess::getUpdatedFileTime()
1524{
1525 struct stat fileStat;
1526 if (stat(ipmiUserDataFile, &fileStat) != 0)
1527 {
1528 log<level::DEBUG>("Error in getting last updated time stamp");
1529 return -EIO;
1530 }
1531 return fileStat.st_mtime;
1532}
1533
1534void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1535 std::vector<std::string>& usrGrps,
1536 std::string& usrPriv, bool& usrEnabled)
1537{
1538 for (const auto& t : properties)
1539 {
1540 std::string key = t.first;
1541 if (key == userPrivProperty)
1542 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001543 usrPriv = std::get<std::string>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301544 }
1545 else if (key == userGrpProperty)
1546 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001547 usrGrps = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301548 }
1549 else if (key == userEnabledProperty)
1550 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001551 usrEnabled = std::get<bool>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301552 }
1553 }
1554 return;
1555}
1556
1557int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1558 std::vector<std::string>& usrGrps,
1559 std::string& usrPriv, bool& usrEnabled)
1560{
1561 auto usrObj = userObjs.find(usersInterface);
1562 if (usrObj != userObjs.end())
1563 {
1564 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1565 return 0;
1566 }
1567 return -EIO;
1568}
1569
arun-pmbbe728c2020-01-10 15:18:04 +05301570void UserAccess::cacheUserDataFile()
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301571{
1572 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1573 userLock{*userMutex};
1574 try
1575 {
1576 readUserData();
1577 }
1578 catch (const std::ios_base::failure& e)
1579 { // File is empty, create it for the first time
1580 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1581 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1582 // user index 0 is reserved, starts with 1
1583 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1584 {
1585 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1586 {
1587 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1588 privNoAccess;
Saravanan Palanisamy92d81192019-08-07 18:00:04 +00001589 usersTbl.user[userIndex]
1590 .payloadAccess[chIndex]
1591 .stdPayloadEnables1[static_cast<uint8_t>(
1592 ipmi::PayloadType::SOL)] = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301593 }
1594 }
1595 writeUserData();
1596 }
arun-pmbbe728c2020-01-10 15:18:04 +05301597 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
1598 // Register it for single object and single process either netipimd /
1599 // host-ipmid
1600 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
1601 {
1602 log<level::DEBUG>("Registering signal handler");
1603 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
1604 bus,
1605 sdbusplus::bus::match::rules::type::signal() +
1606 sdbusplus::bus::match::rules::interface(dBusObjManager) +
1607 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1608 [&](sdbusplus::message::message& msg) {
1609 userUpdatedSignalHandler(*this, msg);
1610 });
1611 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
1612 bus,
1613 sdbusplus::bus::match::rules::type::signal() +
1614 sdbusplus::bus::match::rules::interface(userMgrInterface) +
1615 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1616 [&](sdbusplus::message::message& msg) {
1617 userUpdatedSignalHandler(*this, msg);
1618 });
1619 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
1620 bus,
1621 sdbusplus::bus::match::rules::type::signal() +
1622 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
1623 sdbusplus::bus::match::rules::interface(
1624 dBusPropertiesInterface) +
1625 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
1626 sdbusplus::bus::match::rules::argN(0, usersInterface),
1627 [&](sdbusplus::message::message& msg) {
1628 userUpdatedSignalHandler(*this, msg);
1629 });
1630 signalHndlrObject = true;
1631 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301632 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1633 try
1634 {
1635 auto method = bus.new_method_call(getUserServiceName().c_str(),
1636 userMgrObjBasePath, dBusObjManager,
1637 getManagedObjectsMethod);
1638 auto reply = bus.call(method);
1639 reply.read(managedObjs);
1640 }
1641 catch (const sdbusplus::exception::SdBusError& e)
1642 {
1643 log<level::DEBUG>("Failed to excute method",
1644 entry("METHOD=%s", getSubTreeMethod),
1645 entry("PATH=%s", userMgrObjBasePath));
1646 return;
1647 }
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301648 bool updateRequired = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301649 UsersTbl* userData = &usersTbl;
1650 // user index 0 is reserved, starts with 1
1651 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1652 {
1653 if ((userData->user[usrIdx].userInSystem) &&
1654 (userData->user[usrIdx].userName[0] != '\0'))
1655 {
1656 std::vector<std::string> usrGrps;
1657 std::string usrPriv;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301658
1659 std::string userName(
1660 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1661 ipmiMaxUserName);
1662 std::string usersPath =
1663 std::string(userObjBasePath) + "/" + userName;
1664
1665 auto usrObj = managedObjs.find(usersPath);
1666 if (usrObj != managedObjs.end())
1667 {
Chen,Yugang0e862fa2019-09-06 11:03:05 +08001668 bool usrEnabled = false;
Patrick Venture3a697ad2019-08-19 11:12:05 -07001669
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301670 // User exist. Lets check and update other fileds
1671 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1672 usrEnabled);
1673 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1674 usrGrps.end())
1675 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301676 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301677 // Group "ipmi" is removed so lets remove user in IPMI
1678 deleteUserIndex(usrIdx);
1679 }
1680 else
1681 {
1682 // Group "ipmi" is present so lets update other properties
1683 // in IPMI
1684 uint8_t priv =
1685 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1686 // Update all channels priv, only if it is not equivalent to
1687 // getUsrMgmtSyncIndex()
1688 if (userData->user[usrIdx]
1689 .userPrivAccess[getUsrMgmtSyncIndex()]
1690 .privilege != priv)
1691 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301692 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301693 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1694 ++chIndex)
1695 {
1696 userData->user[usrIdx]
1697 .userPrivAccess[chIndex]
1698 .privilege = priv;
1699 }
1700 }
1701 if (userData->user[usrIdx].userEnabled != usrEnabled)
1702 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301703 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301704 userData->user[usrIdx].userEnabled = usrEnabled;
1705 }
1706 }
1707
1708 // We are done with this obj. lets delete from MAP
1709 managedObjs.erase(usrObj);
1710 }
1711 else
1712 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301713 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301714 deleteUserIndex(usrIdx);
1715 }
1716 }
1717 }
1718
1719 // Walk through remnaining managedObj users list
1720 // Add them to ipmi data base
1721 for (const auto& usrObj : managedObjs)
1722 {
1723 std::vector<std::string> usrGrps;
1724 std::string usrPriv, userName;
Chen,Yugang0e862fa2019-09-06 11:03:05 +08001725 bool usrEnabled = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301726 std::string usrObjPath = std::string(usrObj.first);
1727 if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1728 {
1729 log<level::ERR>("Error in user object path");
1730 continue;
1731 }
1732 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1733 // Add 'ipmi' group users
1734 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1735 usrGrps.end())
1736 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301737 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301738 // CREATE NEW USER
1739 if (true != addUserEntry(userName, usrPriv, usrEnabled))
1740 {
1741 break;
1742 }
1743 }
1744 }
1745
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301746 if (updateRequired)
1747 {
1748 // All userData slots update done. Lets write the data
1749 writeUserData();
1750 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301751
1752 return;
1753}
1754} // namespace ipmi