blob: 04eb2f95ce070adbff1356fb0704a9c8366ee85a [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"
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053020
Suryakanth Sekar90b00c72019-01-16 10:37:57 +053021#include <security/pam_appl.h>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053022#include <sys/stat.h>
23#include <unistd.h>
24
25#include <boost/interprocess/sync/named_recursive_mutex.hpp>
26#include <boost/interprocess/sync/scoped_lock.hpp>
27#include <cerrno>
28#include <fstream>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053029#include <nlohmann/json.hpp>
30#include <phosphor-logging/elog-errors.hpp>
31#include <phosphor-logging/log.hpp>
32#include <regex>
33#include <sdbusplus/bus/match.hpp>
34#include <sdbusplus/server/object.hpp>
Vernon Mauery16b86932019-05-01 08:36:11 -070035#include <variant>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053036#include <xyz/openbmc_project/Common/error.hpp>
37#include <xyz/openbmc_project/User/Common/error.hpp>
38
39namespace ipmi
40{
41
42// TODO: Move D-Bus & Object Manager related stuff, to common files
43// D-Bus property related
44static constexpr const char* dBusPropertiesInterface =
45 "org.freedesktop.DBus.Properties";
46static constexpr const char* getAllPropertiesMethod = "GetAll";
47static constexpr const char* propertiesChangedSignal = "PropertiesChanged";
48static constexpr const char* setPropertiesMethod = "Set";
49
50// Object Manager related
51static constexpr const char* dBusObjManager =
52 "org.freedesktop.DBus.ObjectManager";
53static constexpr const char* getManagedObjectsMethod = "GetManagedObjects";
54// Object Manager signals
55static constexpr const char* intfAddedSignal = "InterfacesAdded";
56static constexpr const char* intfRemovedSignal = "InterfacesRemoved";
57
58// Object Mapper related
59static constexpr const char* objMapperService =
60 "xyz.openbmc_project.ObjectMapper";
61static constexpr const char* objMapperPath =
62 "/xyz/openbmc_project/object_mapper";
63static constexpr const char* objMapperInterface =
64 "xyz.openbmc_project.ObjectMapper";
65static constexpr const char* getSubTreeMethod = "GetSubTree";
66static constexpr const char* getObjectMethod = "GetObject";
67
68static constexpr const char* ipmiUserMutex = "ipmi_usr_mutex";
69static constexpr const char* ipmiMutexCleanupLockFile =
70 "/var/lib/ipmi/ipmi_usr_mutex_cleanup";
71static constexpr const char* ipmiUserDataFile = "/var/lib/ipmi/ipmi_user.json";
72static constexpr const char* ipmiGrpName = "ipmi";
73static constexpr size_t privNoAccess = 0xF;
74static constexpr size_t privMask = 0xF;
75
76// User manager related
77static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user";
78static constexpr const char* userObjBasePath = "/xyz/openbmc_project/user";
79static constexpr const char* userMgrInterface =
80 "xyz.openbmc_project.User.Manager";
81static constexpr const char* usersInterface =
82 "xyz.openbmc_project.User.Attributes";
83static constexpr const char* deleteUserInterface =
84 "xyz.openbmc_project.Object.Delete";
85
86static constexpr const char* createUserMethod = "CreateUser";
87static constexpr const char* deleteUserMethod = "Delete";
88static constexpr const char* renameUserMethod = "RenameUser";
89// User manager signal memebers
90static constexpr const char* userRenamedSignal = "UserRenamed";
91// Mgr interface properties
92static constexpr const char* allPrivProperty = "AllPrivileges";
93static constexpr const char* allGrpProperty = "AllGroups";
94// User interface properties
95static constexpr const char* userPrivProperty = "UserPrivilege";
96static constexpr const char* userGrpProperty = "UserGroups";
97static constexpr const char* userEnabledProperty = "UserEnabled";
98
99static std::array<std::string, (PRIVILEGE_OEM + 1)> ipmiPrivIndex = {
100 "priv-reserved", // PRIVILEGE_RESERVED - 0
101 "priv-callback", // PRIVILEGE_CALLBACK - 1
102 "priv-user", // PRIVILEGE_USER - 2
103 "priv-operator", // PRIVILEGE_OPERATOR - 3
104 "priv-admin", // PRIVILEGE_ADMIN - 4
105 "priv-custom" // PRIVILEGE_OEM - 5
106};
107
108using namespace phosphor::logging;
109using Json = nlohmann::json;
110
Vernon Mauery16b86932019-05-01 08:36:11 -0700111using PrivAndGroupType = std::variant<std::string, std::vector<std::string>>;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530112
113using NoResource =
114 sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource;
115
116using InternalFailure =
117 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
118
Lei YU4b0ddb62019-01-25 16:43:50 +0800119std::unique_ptr<sdbusplus::bus::match_t> userUpdatedSignal
120 __attribute__((init_priority(101)));
121std::unique_ptr<sdbusplus::bus::match_t> userMgrRenamedSignal
122 __attribute__((init_priority(101)));
123std::unique_ptr<sdbusplus::bus::match_t> userPropertiesSignal
124 __attribute__((init_priority(101)));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530125
126// TODO: Below code can be removed once it is moved to common layer libmiscutil
127std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf,
128 const std::string& path)
129{
130 auto mapperCall = bus.new_method_call(objMapperService, objMapperPath,
131 objMapperInterface, getObjectMethod);
132
133 mapperCall.append(path);
134 mapperCall.append(std::vector<std::string>({intf}));
135
136 auto mapperResponseMsg = bus.call(mapperCall);
137
138 std::map<std::string, std::vector<std::string>> mapperResponse;
139 mapperResponseMsg.read(mapperResponse);
140
141 if (mapperResponse.begin() == mapperResponse.end())
142 {
143 throw sdbusplus::exception::SdBusError(
144 -EIO, "ERROR in reading the mapper response");
145 }
146
147 return mapperResponse.begin()->first;
148}
149
150void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service,
151 const std::string& objPath, const std::string& interface,
152 const std::string& property,
153 const DbusUserPropVariant& value)
154{
155 try
156 {
157 auto method =
158 bus.new_method_call(service.c_str(), objPath.c_str(),
159 dBusPropertiesInterface, setPropertiesMethod);
160 method.append(interface, property, value);
161 bus.call(method);
162 }
163 catch (const sdbusplus::exception::SdBusError& e)
164 {
165 log<level::ERR>("Failed to set property",
166 entry("PROPERTY=%s", property.c_str()),
167 entry("PATH=%s", objPath.c_str()),
168 entry("INTERFACE=%s", interface.c_str()));
169 throw;
170 }
171}
172
173static std::string getUserServiceName()
174{
175 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
176 static std::string userMgmtService;
177 if (userMgmtService.empty())
178 {
179 try
180 {
181 userMgmtService =
182 ipmi::getUserService(bus, userMgrInterface, userMgrObjBasePath);
183 }
184 catch (const sdbusplus::exception::SdBusError& e)
185 {
186 userMgmtService.clear();
187 }
188 }
189 return userMgmtService;
190}
191
192UserAccess& getUserAccessObject()
193{
194 static UserAccess userAccess;
195 return userAccess;
196}
197
198int getUserNameFromPath(const std::string& path, std::string& userName)
199{
Richard Marian Thomaiyare3d144f2020-01-09 11:55:06 +0530200 constexpr size_t length = strlen(userObjBasePath);
201 if (((length + 1) >= path.size()) ||
202 path.compare(0, length, userObjBasePath))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530203 {
204 return -EINVAL;
205 }
Richard Marian Thomaiyare3d144f2020-01-09 11:55:06 +0530206 userName.assign(path, length + 1, path.size());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530207 return 0;
208}
209
210void userUpdateHelper(UserAccess& usrAccess, const UserUpdateEvent& userEvent,
211 const std::string& userName, const std::string& priv,
212 const bool& enabled, const std::string& newUserName)
213{
214 UsersTbl* userData = usrAccess.getUsersTblPtr();
215 if (userEvent == UserUpdateEvent::userCreated)
216 {
217 if (usrAccess.addUserEntry(userName, priv, enabled) == false)
218 {
219 return;
220 }
221 }
222 else
223 {
224 // user index 0 is reserved, starts with 1
225 size_t usrIndex = 1;
226 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
227 {
228 std::string curName(
229 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
230 ipmiMaxUserName);
231 if (userName == curName)
232 {
233 break; // found the entry
234 }
235 }
236 if (usrIndex > ipmiMaxUsers)
237 {
238 log<level::DEBUG>("User not found for signal",
239 entry("USER_NAME=%s", userName.c_str()),
240 entry("USER_EVENT=%d", userEvent));
241 return;
242 }
243 switch (userEvent)
244 {
245 case UserUpdateEvent::userDeleted:
246 {
247 usrAccess.deleteUserIndex(usrIndex);
248 break;
249 }
250 case UserUpdateEvent::userPrivUpdated:
251 {
252 uint8_t userPriv =
253 static_cast<uint8_t>(
254 UserAccess::convertToIPMIPrivilege(priv)) &
255 privMask;
256 // Update all channels privileges, only if it is not equivalent
257 // to getUsrMgmtSyncIndex()
258 if (userData->user[usrIndex]
259 .userPrivAccess[UserAccess::getUsrMgmtSyncIndex()]
260 .privilege != userPriv)
261 {
262 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
263 ++chIndex)
264 {
265 userData->user[usrIndex]
266 .userPrivAccess[chIndex]
267 .privilege = userPriv;
268 }
269 }
270 break;
271 }
272 case UserUpdateEvent::userRenamed:
273 {
274 std::fill(
275 static_cast<uint8_t*>(userData->user[usrIndex].userName),
276 static_cast<uint8_t*>(userData->user[usrIndex].userName) +
277 sizeof(userData->user[usrIndex].userName),
278 0);
279 std::strncpy(
280 reinterpret_cast<char*>(userData->user[usrIndex].userName),
281 newUserName.c_str(), ipmiMaxUserName);
282 ipmiRenameUserEntryPassword(userName, newUserName);
283 break;
284 }
285 case UserUpdateEvent::userStateUpdated:
286 {
287 userData->user[usrIndex].userEnabled = enabled;
288 break;
289 }
290 default:
291 {
292 log<level::ERR>("Unhandled user event",
293 entry("USER_EVENT=%d", userEvent));
294 return;
295 }
296 }
297 }
298 usrAccess.writeUserData();
299 log<level::DEBUG>("User event handled successfully",
300 entry("USER_NAME=%s", userName.c_str()),
301 entry("USER_EVENT=%d", userEvent));
302
303 return;
304}
305
306void userUpdatedSignalHandler(UserAccess& usrAccess,
307 sdbusplus::message::message& msg)
308{
309 static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
310 std::string signal = msg.get_member();
Patrick Venture3a697ad2019-08-19 11:12:05 -0700311 std::string userName, priv, newUserName;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530312 std::vector<std::string> groups;
313 bool enabled = false;
314 UserUpdateEvent userEvent = UserUpdateEvent::reservedEvent;
315 if (signal == intfAddedSignal)
316 {
317 DbusUserObjPath objPath;
318 DbusUserObjValue objValue;
319 msg.read(objPath, objValue);
320 getUserNameFromPath(objPath.str, userName);
321 if (usrAccess.getUserObjProperties(objValue, groups, priv, enabled) !=
322 0)
323 {
324 return;
325 }
326 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
327 groups.end())
328 {
329 return;
330 }
331 userEvent = UserUpdateEvent::userCreated;
332 }
333 else if (signal == intfRemovedSignal)
334 {
335 DbusUserObjPath objPath;
336 std::vector<std::string> interfaces;
337 msg.read(objPath, interfaces);
338 getUserNameFromPath(objPath.str, userName);
339 userEvent = UserUpdateEvent::userDeleted;
340 }
341 else if (signal == userRenamedSignal)
342 {
343 msg.read(userName, newUserName);
344 userEvent = UserUpdateEvent::userRenamed;
345 }
346 else if (signal == propertiesChangedSignal)
347 {
348 getUserNameFromPath(msg.get_path(), userName);
349 }
350 else
351 {
352 log<level::ERR>("Unknown user update signal",
353 entry("SIGNAL=%s", signal.c_str()));
354 return;
355 }
356
357 if (signal.empty() || userName.empty() ||
358 (signal == userRenamedSignal && newUserName.empty()))
359 {
360 log<level::ERR>("Invalid inputs received");
361 return;
362 }
363
364 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
365 userLock{*(usrAccess.userMutex)};
366 usrAccess.checkAndReloadUserData();
367
368 if (signal == propertiesChangedSignal)
369 {
370 std::string intfName;
371 DbusUserObjProperties chProperties;
372 msg.read(intfName, chProperties); // skip reading 3rd argument.
373 for (const auto& prop : chProperties)
374 {
375 userEvent = UserUpdateEvent::reservedEvent;
376 std::string member = prop.first;
377 if (member == userPrivProperty)
378 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700379 priv = std::get<std::string>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530380 userEvent = UserUpdateEvent::userPrivUpdated;
381 }
382 else if (member == userGrpProperty)
383 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700384 groups = std::get<std::vector<std::string>>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530385 userEvent = UserUpdateEvent::userGrpUpdated;
386 }
387 else if (member == userEnabledProperty)
388 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700389 enabled = std::get<bool>(prop.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530390 userEvent = UserUpdateEvent::userStateUpdated;
391 }
392 // Process based on event type.
393 if (userEvent == UserUpdateEvent::userGrpUpdated)
394 {
395 if (std::find(groups.begin(), groups.end(), ipmiGrpName) ==
396 groups.end())
397 {
398 // remove user from ipmi user list.
399 userUpdateHelper(usrAccess, UserUpdateEvent::userDeleted,
400 userName, priv, enabled, newUserName);
401 }
402 else
403 {
404 DbusUserObjProperties properties;
405 try
406 {
407 auto method = bus.new_method_call(
408 getUserServiceName().c_str(), msg.get_path(),
409 dBusPropertiesInterface, getAllPropertiesMethod);
410 method.append(usersInterface);
411 auto reply = bus.call(method);
412 reply.read(properties);
413 }
414 catch (const sdbusplus::exception::SdBusError& e)
415 {
416 log<level::DEBUG>(
417 "Failed to excute method",
418 entry("METHOD=%s", getAllPropertiesMethod),
419 entry("PATH=%s", msg.get_path()));
420 return;
421 }
422 usrAccess.getUserProperties(properties, groups, priv,
423 enabled);
424 // add user to ipmi user list.
425 userUpdateHelper(usrAccess, UserUpdateEvent::userCreated,
426 userName, priv, enabled, newUserName);
427 }
428 }
429 else if (userEvent != UserUpdateEvent::reservedEvent)
430 {
431 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
432 newUserName);
433 }
434 }
435 }
436 else if (userEvent != UserUpdateEvent::reservedEvent)
437 {
438 userUpdateHelper(usrAccess, userEvent, userName, priv, enabled,
439 newUserName);
440 }
441 return;
442}
443
444UserAccess::~UserAccess()
445{
446 if (signalHndlrObject)
447 {
448 userUpdatedSignal.reset();
449 userMgrRenamedSignal.reset();
450 userPropertiesSignal.reset();
451 sigHndlrLock.unlock();
452 }
453}
454
455UserAccess::UserAccess() : bus(ipmid_get_sd_bus_connection())
456{
457 std::ofstream mutexCleanUpFile;
458 mutexCleanUpFile.open(ipmiMutexCleanupLockFile,
459 std::ofstream::out | std::ofstream::app);
460 if (!mutexCleanUpFile.good())
461 {
462 log<level::DEBUG>("Unable to open mutex cleanup file");
463 return;
464 }
465 mutexCleanUpFile.close();
466 mutexCleanupLock = boost::interprocess::file_lock(ipmiMutexCleanupLockFile);
467 if (mutexCleanupLock.try_lock())
468 {
469 boost::interprocess::named_recursive_mutex::remove(ipmiUserMutex);
470 }
471 mutexCleanupLock.lock_sharable();
472 userMutex = std::make_unique<boost::interprocess::named_recursive_mutex>(
473 boost::interprocess::open_or_create, ipmiUserMutex);
474
arun-pmbbe728c2020-01-10 15:18:04 +0530475 cacheUserDataFile();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530476 getSystemPrivAndGroups();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530477}
478
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530479UserInfo* UserAccess::getUserInfo(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530480{
481 checkAndReloadUserData();
482 return &usersTbl.user[userId];
483}
484
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530485void UserAccess::setUserInfo(const uint8_t userId, UserInfo* userInfo)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530486{
487 checkAndReloadUserData();
488 std::copy(reinterpret_cast<uint8_t*>(userInfo),
489 reinterpret_cast<uint8_t*>(userInfo) + sizeof(*userInfo),
490 reinterpret_cast<uint8_t*>(&usersTbl.user[userId]));
491 writeUserData();
492}
493
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530494bool UserAccess::isValidChannel(const uint8_t chNum)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530495{
496 return (chNum < ipmiMaxChannels);
497}
498
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530499bool UserAccess::isValidUserId(const uint8_t userId)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530500{
501 return ((userId <= ipmiMaxUsers) && (userId != reservedUserId));
502}
503
Richard Marian Thomaiyara45cb342018-12-03 15:08:59 +0530504bool UserAccess::isValidPrivilege(const uint8_t priv)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530505{
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000506 // Callback privilege is deprecated in OpenBMC
507 return (isValidPrivLimit(priv) || priv == privNoAccess);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530508}
509
510uint8_t UserAccess::getUsrMgmtSyncIndex()
511{
512 // TODO: Need to get LAN1 channel number dynamically,
513 // which has to be in sync with system user privilege
514 // level(Phosphor-user-manager). Note: For time being chanLan1 is marked as
515 // sync index to the user-manager privilege..
516 return static_cast<uint8_t>(EChannelID::chanLan1);
517}
518
519CommandPrivilege UserAccess::convertToIPMIPrivilege(const std::string& value)
520{
521 auto iter = std::find(ipmiPrivIndex.begin(), ipmiPrivIndex.end(), value);
522 if (iter == ipmiPrivIndex.end())
523 {
524 if (value == "")
525 {
526 return static_cast<CommandPrivilege>(privNoAccess);
527 }
528 log<level::ERR>("Error in converting to IPMI privilege",
529 entry("PRIV=%s", value.c_str()));
530 throw std::out_of_range("Out of range - convertToIPMIPrivilege");
531 }
532 else
533 {
534 return static_cast<CommandPrivilege>(
535 std::distance(ipmiPrivIndex.begin(), iter));
536 }
537}
538
539std::string UserAccess::convertToSystemPrivilege(const CommandPrivilege& value)
540{
541 if (value == static_cast<CommandPrivilege>(privNoAccess))
542 {
543 return "";
544 }
545 try
546 {
547 return ipmiPrivIndex.at(value);
548 }
549 catch (const std::out_of_range& e)
550 {
551 log<level::ERR>("Error in converting to system privilege",
552 entry("PRIV=%d", static_cast<uint8_t>(value)));
553 throw std::out_of_range("Out of range - convertToSystemPrivilege");
554 }
555}
556
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000557bool UserAccess::isValidUserName(const std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530558{
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000559 if (userName.empty())
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530560 {
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000561 log<level::ERR>("userName is empty");
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530562 return false;
563 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530564 if (!std::regex_match(userName.c_str(),
565 std::regex("[a-zA-z_][a-zA-Z_0-9]*")))
566 {
567 log<level::ERR>("Unsupported characters in user name");
568 return false;
569 }
570 if (userName == "root")
571 {
572 log<level::ERR>("Invalid user name - root");
573 return false;
574 }
575 std::map<DbusUserObjPath, DbusUserObjValue> properties;
576 try
577 {
578 auto method = bus.new_method_call(getUserServiceName().c_str(),
579 userMgrObjBasePath, dBusObjManager,
580 getManagedObjectsMethod);
581 auto reply = bus.call(method);
582 reply.read(properties);
583 }
584 catch (const sdbusplus::exception::SdBusError& e)
585 {
586 log<level::ERR>("Failed to excute method",
587 entry("METHOD=%s", getSubTreeMethod),
588 entry("PATH=%s", userMgrObjBasePath));
589 return false;
590 }
591
592 std::string usersPath = std::string(userObjBasePath) + "/" + userName;
593 if (properties.find(usersPath) != properties.end())
594 {
595 log<level::DEBUG>("User name already exists",
596 entry("USER_NAME=%s", userName.c_str()));
597 return false;
598 }
599
600 return true;
601}
602
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530603/** @brief Information exchanged by pam module and application.
604 *
605 * @param[in] numMsg - length of the array of pointers,msg.
606 *
607 * @param[in] msg - pointer to an array of pointers to pam_message structure
608 *
609 * @param[out] resp - struct pam response array
610 *
611 * @param[in] appdataPtr - member of pam_conv structure
612 *
613 * @return the response in pam response structure.
614 */
615
616static int pamFunctionConversation(int numMsg, const struct pam_message** msg,
617 struct pam_response** resp, void* appdataPtr)
618{
619 if (appdataPtr == nullptr)
620 {
621 return PAM_AUTH_ERR;
622 }
623 size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1;
624 char* pass = reinterpret_cast<char*>(malloc(passSize));
625 std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize);
626
627 *resp = reinterpret_cast<pam_response*>(
628 calloc(numMsg, sizeof(struct pam_response)));
629
630 for (int i = 0; i < numMsg; ++i)
631 {
632 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
633 {
634 continue;
635 }
636 resp[i]->resp = pass;
637 }
638 return PAM_SUCCESS;
639}
640
641/** @brief Updating the PAM password
642 *
643 * @param[in] username - username in string
644 *
645 * @param[in] password - new password in string
646 *
647 * @return status
648 */
649
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000650int pamUpdatePasswd(const char* username, const char* password)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530651{
652 const struct pam_conv localConversation = {pamFunctionConversation,
653 const_cast<char*>(password)};
654 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
655
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000656 int retval =
657 pam_start("passwd", username, &localConversation, &localAuthHandle);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530658
659 if (retval != PAM_SUCCESS)
660 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000661 return retval;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530662 }
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000663
664 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
665 if (retval != PAM_SUCCESS)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530666 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000667 pam_end(localAuthHandle, retval);
668 return retval;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530669 }
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000670
671 return pam_end(localAuthHandle, PAM_SUCCESS);
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530672}
673
Ayushi Smriti02650d52019-05-15 11:59:09 +0000674bool pamUserCheckAuthenticate(std::string_view username,
675 std::string_view password)
676{
677 const struct pam_conv localConversation = {
678 pamFunctionConversation, const_cast<char*>(password.data())};
679
680 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
681
682 if (pam_start("dropbear", username.data(), &localConversation,
683 &localAuthHandle) != PAM_SUCCESS)
684 {
685 log<level::ERR>("User Authentication Failure");
686 return false;
687 }
688
689 int retval = pam_authenticate(localAuthHandle,
690 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
691
692 if (retval != PAM_SUCCESS)
693 {
694 log<level::DEBUG>("pam_authenticate returned failure",
695 entry("ERROR=%d", retval));
696
697 pam_end(localAuthHandle, retval);
698 return false;
699 }
700
701 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
702 PAM_SUCCESS)
703 {
704 pam_end(localAuthHandle, PAM_SUCCESS);
705 return false;
706 }
707
708 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
709 {
710 return false;
711 }
712 return true;
713}
714
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000715Cc UserAccess::setSpecialUserPassword(const std::string& userName,
716 const std::string& userPassword)
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530717{
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000718 if (pamUpdatePasswd(userName.c_str(), userPassword.c_str()) != PAM_SUCCESS)
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530719 {
720 log<level::DEBUG>("Failed to update password");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000721 return ccUnspecifiedError;
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530722 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000723 return ccSuccess;
Richard Marian Thomaiyar788362c2019-04-14 15:12:47 +0530724}
725
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000726Cc UserAccess::setUserPassword(const uint8_t userId, const char* userPassword)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530727{
728 std::string userName;
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000729 if (ipmiUserGetUserName(userId, userName) != ccSuccess)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530730 {
731 log<level::DEBUG>("User Name not found",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530732 entry("USER-ID=%d", (uint8_t)userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000733 return ccParmOutOfRange;
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530734 }
735 std::string passwd;
736 passwd.assign(reinterpret_cast<const char*>(userPassword), 0,
737 maxIpmi20PasswordSize);
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000738
739 int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str());
Jayaprakash Mutyala70bd0632020-10-23 06:24:55 +0000740 // Clear sensitive data
741 OPENSSL_cleanse(&passwd, passwd.length());
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000742
743 switch (retval)
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530744 {
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000745 case PAM_SUCCESS:
746 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000747 return ccSuccess;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000748 }
749 case PAM_AUTHTOK_ERR:
750 {
751 log<level::DEBUG>("Bad authentication token");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000752 return ccInvalidFieldRequest;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000753 }
754 default:
755 {
756 log<level::DEBUG>("Failed to update password",
757 entry("USER-ID=%d", (uint8_t)userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000758 return ccUnspecifiedError;
jayaprakash Mutyala9fc5fa12019-08-29 15:14:06 +0000759 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530760 }
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530761}
762
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000763Cc UserAccess::setUserEnabledState(const uint8_t userId,
764 const bool& enabledState)
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530765{
766 if (!isValidUserId(userId))
767 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000768 return ccParmOutOfRange;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530769 }
770 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
771 userLock{*userMutex};
772 UserInfo* userInfo = getUserInfo(userId);
773 std::string userName;
774 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
775 ipmiMaxUserName);
776 if (userName.empty())
777 {
778 log<level::DEBUG>("User name not set / invalid");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000779 return ccUnspecifiedError;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530780 }
781 if (userInfo->userEnabled != enabledState)
782 {
783 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800784 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
785 userEnabledProperty, enabledState);
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530786 userInfo->userEnabled = enabledState;
787 try
788 {
789 writeUserData();
790 }
791 catch (const std::exception& e)
792 {
793 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000794 return ccUnspecifiedError;
Richard Marian Thomaiyar2fe92822019-03-02 22:07:03 +0530795 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530796 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000797 return ccSuccess;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530798}
799
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000800Cc UserAccess::setUserPayloadAccess(const uint8_t chNum,
801 const uint8_t operation,
802 const uint8_t userId,
803 const PayloadAccess& payloadAccess)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000804{
805 constexpr uint8_t enable = 0x0;
806 constexpr uint8_t disable = 0x1;
807
808 if (!isValidChannel(chNum))
809 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000810 return ccInvalidFieldRequest;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000811 }
812 if (!isValidUserId(userId))
813 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000814 return ccParmOutOfRange;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000815 }
816 if (operation != enable && operation != disable)
817 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000818 return ccInvalidFieldRequest;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000819 }
820 // Check operation & payloadAccess if required.
821 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
822 userLock{*userMutex};
823 UserInfo* userInfo = getUserInfo(userId);
824
825 if (operation == enable)
826 {
827 userInfo->payloadAccess[chNum].stdPayloadEnables1 |=
828 payloadAccess.stdPayloadEnables1;
829
830 userInfo->payloadAccess[chNum].oemPayloadEnables1 |=
831 payloadAccess.oemPayloadEnables1;
832 }
833 else
834 {
835 userInfo->payloadAccess[chNum].stdPayloadEnables1 &=
836 ~(payloadAccess.stdPayloadEnables1);
837
838 userInfo->payloadAccess[chNum].oemPayloadEnables1 &=
839 ~(payloadAccess.oemPayloadEnables1);
840 }
841
842 try
843 {
844 writeUserData();
845 }
846 catch (const std::exception& e)
847 {
848 log<level::ERR>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000849 return ccUnspecifiedError;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000850 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000851 return ccSuccess;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000852}
853
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000854Cc UserAccess::setUserPrivilegeAccess(const uint8_t userId, const uint8_t chNum,
855 const UserPrivAccess& privAccess,
856 const bool& otherPrivUpdates)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530857{
858 if (!isValidChannel(chNum))
859 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000860 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530861 }
862 if (!isValidUserId(userId))
863 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000864 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530865 }
866 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
867 userLock{*userMutex};
868 UserInfo* userInfo = getUserInfo(userId);
869 std::string userName;
870 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
871 ipmiMaxUserName);
872 if (userName.empty())
873 {
874 log<level::DEBUG>("User name not set / invalid");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000875 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530876 }
877 std::string priv = convertToSystemPrivilege(
878 static_cast<CommandPrivilege>(privAccess.privilege));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530879 uint8_t syncIndex = getUsrMgmtSyncIndex();
880 if (chNum == syncIndex &&
881 privAccess.privilege != userInfo->userPrivAccess[syncIndex].privilege)
882 {
883 std::string userPath = std::string(userObjBasePath) + "/" + userName;
Patrick Venture99d1ba02019-02-21 15:11:24 -0800884 setDbusProperty(bus, getUserServiceName(), userPath, usersInterface,
885 userPrivProperty, priv);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530886 }
887 userInfo->userPrivAccess[chNum].privilege = privAccess.privilege;
888
889 if (otherPrivUpdates)
890 {
891 userInfo->userPrivAccess[chNum].ipmiEnabled = privAccess.ipmiEnabled;
892 userInfo->userPrivAccess[chNum].linkAuthEnabled =
893 privAccess.linkAuthEnabled;
894 userInfo->userPrivAccess[chNum].accessCallback =
895 privAccess.accessCallback;
896 }
897 try
898 {
899 writeUserData();
900 }
901 catch (const std::exception& e)
902 {
903 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000904 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530905 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000906 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530907}
908
909uint8_t UserAccess::getUserId(const std::string& userName)
910{
911 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
912 userLock{*userMutex};
913 checkAndReloadUserData();
914 // user index 0 is reserved, starts with 1
915 size_t usrIndex = 1;
916 for (; usrIndex <= ipmiMaxUsers; ++usrIndex)
917 {
918 std::string curName(
919 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
920 ipmiMaxUserName);
921 if (userName == curName)
922 {
923 break; // found the entry
924 }
925 }
926 if (usrIndex > ipmiMaxUsers)
927 {
928 log<level::DEBUG>("User not found",
929 entry("USER_NAME=%s", userName.c_str()));
930 return invalidUserId;
931 }
932
933 return usrIndex;
934}
935
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000936Cc UserAccess::getUserName(const uint8_t userId, std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530937{
938 if (!isValidUserId(userId))
939 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000940 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530941 }
942 UserInfo* userInfo = getUserInfo(userId);
943 userName.assign(reinterpret_cast<char*>(userInfo->userName), 0,
944 ipmiMaxUserName);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000945 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530946}
947
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +0530948bool UserAccess::isIpmiInAvailableGroupList()
949{
950 if (std::find(availableGroups.begin(), availableGroups.end(),
951 ipmiGrpName) != availableGroups.end())
952 {
953 return true;
954 }
955 if (availableGroups.empty())
956 {
957 // available groups shouldn't be empty, re-query
958 getSystemPrivAndGroups();
959 if (std::find(availableGroups.begin(), availableGroups.end(),
960 ipmiGrpName) != availableGroups.end())
961 {
962 return true;
963 }
964 }
965 return false;
966}
967
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000968Cc UserAccess::setUserName(const uint8_t userId, const std::string& userName)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530969{
970 if (!isValidUserId(userId))
971 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000972 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530973 }
974
975 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
976 userLock{*userMutex};
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530977 std::string oldUser;
978 getUserName(userId, oldUser);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530979
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000980 if (oldUser == userName)
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530981 {
982 // requesting to set the same user name, return success.
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000983 return ccSuccess;
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530984 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000985
986 bool validUser = isValidUserName(userName);
Richard Marian Thomaiyar8550b602018-12-06 13:20:38 +0530987 UserInfo* userInfo = getUserInfo(userId);
jayaprakash Mutyala76363302020-02-14 23:50:38 +0000988 if (userName.empty() && !oldUser.empty())
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530989 {
990 // Delete existing user
991 std::string userPath = std::string(userObjBasePath) + "/" + oldUser;
992 try
993 {
994 auto method = bus.new_method_call(
995 getUserServiceName().c_str(), userPath.c_str(),
996 deleteUserInterface, deleteUserMethod);
997 auto reply = bus.call(method);
998 }
999 catch (const sdbusplus::exception::SdBusError& e)
1000 {
1001 log<level::DEBUG>("Failed to excute method",
1002 entry("METHOD=%s", deleteUserMethod),
1003 entry("PATH=%s", userPath.c_str()));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001004 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301005 }
Richard Marian Thomaiyar02710bb2018-11-28 20:42:25 +05301006 deleteUserIndex(userId);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301007 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001008 else if (oldUser.empty() && !userName.empty() && validUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301009 {
1010 try
1011 {
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +05301012 if (!isIpmiInAvailableGroupList())
1013 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001014 return ccUnspecifiedError;
Richard Marian Thomaiyar489a4ed2020-01-17 11:48:40 +05301015 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301016 // Create new user
1017 auto method = bus.new_method_call(
1018 getUserServiceName().c_str(), userMgrObjBasePath,
1019 userMgrInterface, createUserMethod);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001020 method.append(userName.c_str(), availableGroups, "", false);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301021 auto reply = bus.call(method);
1022 }
1023 catch (const sdbusplus::exception::SdBusError& e)
1024 {
1025 log<level::DEBUG>("Failed to excute method",
1026 entry("METHOD=%s", createUserMethod),
1027 entry("PATH=%s", userMgrObjBasePath));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001028 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301029 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001030
1031 std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1032 std::memcpy(userInfo->userName,
1033 static_cast<const void*>(userName.data()), userName.size());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301034 userInfo->userInSystem = true;
1035 }
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001036 else if (oldUser != userName && validUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301037 {
1038 try
1039 {
1040 // User rename
1041 auto method = bus.new_method_call(
1042 getUserServiceName().c_str(), userMgrObjBasePath,
1043 userMgrInterface, renameUserMethod);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001044 method.append(oldUser.c_str(), userName.c_str());
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301045 auto reply = bus.call(method);
1046 }
1047 catch (const sdbusplus::exception::SdBusError& e)
1048 {
1049 log<level::DEBUG>("Failed to excute method",
1050 entry("METHOD=%s", renameUserMethod),
1051 entry("PATH=%s", userMgrObjBasePath));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001052 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301053 }
1054 std::fill(static_cast<uint8_t*>(userInfo->userName),
1055 static_cast<uint8_t*>(userInfo->userName) +
1056 sizeof(userInfo->userName),
1057 0);
jayaprakash Mutyala76363302020-02-14 23:50:38 +00001058
1059 std::memset(userInfo->userName, 0, sizeof(userInfo->userName));
1060 std::memcpy(userInfo->userName,
1061 static_cast<const void*>(userName.data()), userName.size());
1062
1063 ipmiRenameUserEntryPassword(oldUser, userName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301064 userInfo->userInSystem = true;
1065 }
1066 else if (!validUser)
1067 {
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001068 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301069 }
1070 try
1071 {
1072 writeUserData();
1073 }
1074 catch (const std::exception& e)
1075 {
1076 log<level::DEBUG>("Write user data failed");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001077 return ccUnspecifiedError;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301078 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +00001079 return ccSuccess;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301080}
1081
1082static constexpr const char* jsonUserName = "user_name";
1083static constexpr const char* jsonPriv = "privilege";
1084static constexpr const char* jsonIpmiEnabled = "ipmi_enabled";
1085static constexpr const char* jsonLinkAuthEnabled = "link_auth_enabled";
1086static constexpr const char* jsonAccCallbk = "access_callback";
1087static constexpr const char* jsonUserEnabled = "user_enabled";
1088static constexpr const char* jsonUserInSys = "user_in_system";
1089static constexpr const char* jsonFixedUser = "fixed_user_name";
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001090static constexpr const char* payloadEnabledStr = "payload_enabled";
1091static constexpr const char* stdPayloadStr = "std_payload";
1092static constexpr const char* oemPayloadStr = "OEM_payload";
1093
1094/** @brief to construct a JSON object from the given payload access details.
1095 *
1096 * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input)
1097 * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input)
1098 *
1099 * @details Sample output JSON object format :
1100 * "payload_enabled":{
1101 * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1102 * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1103 * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1104 * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1105 * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1106 * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1107 * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1108 * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1109 * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1110 * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1111 * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1112 * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1113 * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1114 * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1115 * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1116 * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
1117 * }
1118 */
1119static const Json constructJsonPayloadEnables(
1120 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1121 stdPayload,
1122 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1123 oemPayload)
1124{
1125 Json jsonPayloadEnabled;
1126
1127 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1128 {
1129 std::ostringstream stdPayloadStream;
1130 std::ostringstream oemPayloadStream;
1131
1132 stdPayloadStream << stdPayloadStr << payloadNum;
1133 oemPayloadStream << oemPayloadStr << payloadNum;
1134
1135 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1136 stdPayloadStream.str(), stdPayload[payloadNum]));
1137
1138 jsonPayloadEnabled.push_back(Json::object_t::value_type(
1139 oemPayloadStream.str(), oemPayload[payloadNum]));
1140 }
1141 return jsonPayloadEnabled;
1142}
1143
1144void UserAccess::readPayloadAccessFromUserInfo(
1145 const UserInfo& userInfo,
1146 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload,
1147 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload)
1148{
1149 for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
1150 {
1151 for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1152 {
1153 stdPayload[payloadNum][chIndex] =
1154 userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum];
1155
1156 oemPayload[payloadNum][chIndex] =
1157 userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum];
1158 }
1159 }
1160}
1161
1162void UserAccess::updatePayloadAccessInUserInfo(
1163 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1164 stdPayload,
1165 const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
1166 oemPayload,
1167 UserInfo& userInfo)
1168{
1169 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1170 {
1171 // Ensure that reserved/unsupported payloads are marked to zero.
1172 userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset();
1173 userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset();
1174 userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset();
1175 userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset();
1176 // Update SOL status as it is the only supported payload currently.
1177 userInfo.payloadAccess[chIndex]
1178 .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] =
1179 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex];
1180 }
1181}
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301182
1183void UserAccess::readUserData()
1184{
1185 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1186 userLock{*userMutex};
1187
1188 std::ifstream iUsrData(ipmiUserDataFile, std::ios::in | std::ios::binary);
1189 if (!iUsrData.good())
1190 {
1191 log<level::ERR>("Error in reading IPMI user data file");
1192 throw std::ios_base::failure("Error opening IPMI user data file");
1193 }
1194
1195 Json jsonUsersTbl = Json::array();
1196 jsonUsersTbl = Json::parse(iUsrData, nullptr, false);
1197
1198 if (jsonUsersTbl.size() != ipmiMaxUsers)
1199 {
1200 log<level::ERR>(
1201 "Error in reading IPMI user data file - User count issues");
1202 throw std::runtime_error(
1203 "Corrupted IPMI user data file - invalid user count");
1204 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001205
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301206 // user index 0 is reserved, starts with 1
1207 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1208 {
1209 Json userInfo = jsonUsersTbl[usrIndex - 1]; // json array starts with 0.
1210 if (userInfo.is_null())
1211 {
1212 log<level::ERR>("Error in reading IPMI user data file - "
1213 "user info corrupted");
1214 throw std::runtime_error(
1215 "Corrupted IPMI user data file - invalid user info");
1216 }
1217 std::string userName = userInfo[jsonUserName].get<std::string>();
1218 std::strncpy(reinterpret_cast<char*>(usersTbl.user[usrIndex].userName),
1219 userName.c_str(), ipmiMaxUserName);
1220
1221 std::vector<std::string> privilege =
1222 userInfo[jsonPriv].get<std::vector<std::string>>();
1223 std::vector<bool> ipmiEnabled =
1224 userInfo[jsonIpmiEnabled].get<std::vector<bool>>();
1225 std::vector<bool> linkAuthEnabled =
1226 userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
1227 std::vector<bool> accessCallback =
1228 userInfo[jsonAccCallbk].get<std::vector<bool>>();
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001229
1230 // Payload Enables Processing.
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001231 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1232 stdPayload = {};
1233 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1234 oemPayload = {};
1235 try
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001236 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001237 const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr);
1238 for (auto payloadNum = 0; payloadNum < payloadsPerByte;
1239 payloadNum++)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001240 {
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001241 std::ostringstream stdPayloadStream;
1242 std::ostringstream oemPayloadStream;
1243
1244 stdPayloadStream << stdPayloadStr << payloadNum;
1245 oemPayloadStream << oemPayloadStr << payloadNum;
1246
1247 stdPayload[payloadNum] =
1248 jsonPayloadEnabled[stdPayloadStream.str()]
1249 .get<std::array<bool, ipmiMaxChannels>>();
1250 oemPayload[payloadNum] =
1251 jsonPayloadEnabled[oemPayloadStream.str()]
1252 .get<std::array<bool, ipmiMaxChannels>>();
1253
1254 if (stdPayload[payloadNum].size() != ipmiMaxChannels ||
1255 oemPayload[payloadNum].size() != ipmiMaxChannels)
1256 {
1257 log<level::ERR>("Error in reading IPMI user data file - "
1258 "payload properties corrupted");
1259 throw std::runtime_error(
1260 "Corrupted IPMI user data file - payload properties");
1261 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001262 }
1263 }
Saravanan Palanisamyc86045c2019-07-26 22:52:40 +00001264 catch (Json::out_of_range& e)
1265 {
1266 // Key not found in 'userInfo'; possibly an old JSON file. Use
1267 // default values for all payloads, and SOL payload default is true.
1268 stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true);
1269 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001270
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301271 if (privilege.size() != ipmiMaxChannels ||
1272 ipmiEnabled.size() != ipmiMaxChannels ||
1273 linkAuthEnabled.size() != ipmiMaxChannels ||
1274 accessCallback.size() != ipmiMaxChannels)
1275 {
1276 log<level::ERR>("Error in reading IPMI user data file - "
1277 "properties corrupted");
1278 throw std::runtime_error(
1279 "Corrupted IPMI user data file - properties");
1280 }
1281 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1282 {
1283 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege =
1284 static_cast<uint8_t>(
1285 convertToIPMIPrivilege(privilege[chIndex]));
1286 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled =
1287 ipmiEnabled[chIndex];
1288 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled =
1289 linkAuthEnabled[chIndex];
1290 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
1291 accessCallback[chIndex];
1292 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001293 updatePayloadAccessInUserInfo(stdPayload, oemPayload,
1294 usersTbl.user[usrIndex]);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301295 usersTbl.user[usrIndex].userEnabled =
1296 userInfo[jsonUserEnabled].get<bool>();
1297 usersTbl.user[usrIndex].userInSystem =
1298 userInfo[jsonUserInSys].get<bool>();
1299 usersTbl.user[usrIndex].fixedUserName =
1300 userInfo[jsonFixedUser].get<bool>();
1301 }
1302
1303 log<level::DEBUG>("User data read from IPMI data file");
1304 iUsrData.close();
1305 // Update the timestamp
1306 fileLastUpdatedTime = getUpdatedFileTime();
1307 return;
1308}
1309
1310void UserAccess::writeUserData()
1311{
1312 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1313 userLock{*userMutex};
1314
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301315 Json jsonUsersTbl = Json::array();
1316 // user index 0 is reserved, starts with 1
1317 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1318 {
1319 Json jsonUserInfo;
1320 jsonUserInfo[jsonUserName] = std::string(
1321 reinterpret_cast<char*>(usersTbl.user[usrIndex].userName), 0,
1322 ipmiMaxUserName);
1323 std::vector<std::string> privilege(ipmiMaxChannels);
1324 std::vector<bool> ipmiEnabled(ipmiMaxChannels);
1325 std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
1326 std::vector<bool> accessCallback(ipmiMaxChannels);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001327
1328 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1329 stdPayload;
1330 std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
1331 oemPayload;
1332
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301333 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
1334 {
1335 privilege[chIndex] =
1336 convertToSystemPrivilege(static_cast<CommandPrivilege>(
1337 usersTbl.user[usrIndex].userPrivAccess[chIndex].privilege));
1338 ipmiEnabled[chIndex] =
1339 usersTbl.user[usrIndex].userPrivAccess[chIndex].ipmiEnabled;
1340 linkAuthEnabled[chIndex] =
1341 usersTbl.user[usrIndex].userPrivAccess[chIndex].linkAuthEnabled;
1342 accessCallback[chIndex] =
1343 usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback;
1344 }
1345 jsonUserInfo[jsonPriv] = privilege;
1346 jsonUserInfo[jsonIpmiEnabled] = ipmiEnabled;
1347 jsonUserInfo[jsonLinkAuthEnabled] = linkAuthEnabled;
1348 jsonUserInfo[jsonAccCallbk] = accessCallback;
1349 jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
1350 jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
1351 jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +00001352
1353 readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload,
1354 oemPayload);
1355 Json jsonPayloadEnabledInfo =
1356 constructJsonPayloadEnables(stdPayload, oemPayload);
1357 jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo;
1358
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301359 jsonUsersTbl.push_back(jsonUserInfo);
1360 }
1361
Richard Marian Thomaiyar687df402019-05-09 00:16:53 +05301362 static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
1363 int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
1364 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1365 if (fd < 0)
1366 {
1367 log<level::ERR>("Error in creating temporary IPMI user data file");
1368 throw std::ios_base::failure(
1369 "Error in creating temporary IPMI user data file");
1370 }
1371 const auto& writeStr = jsonUsersTbl.dump();
1372 if (write(fd, writeStr.c_str(), writeStr.size()) !=
1373 static_cast<ssize_t>(writeStr.size()))
1374 {
1375 close(fd);
1376 log<level::ERR>("Error in writing temporary IPMI user data file");
1377 throw std::ios_base::failure(
1378 "Error in writing temporary IPMI user data file");
1379 }
1380 close(fd);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301381
1382 if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
1383 {
1384 log<level::ERR>("Error in renaming temporary IPMI user data file");
1385 throw std::runtime_error("Error in renaming IPMI user data file");
1386 }
1387 // Update the timestamp
1388 fileLastUpdatedTime = getUpdatedFileTime();
1389 return;
1390}
1391
1392bool UserAccess::addUserEntry(const std::string& userName,
1393 const std::string& sysPriv, const bool& enabled)
1394{
1395 UsersTbl* userData = getUsersTblPtr();
1396 size_t freeIndex = 0xFF;
1397 // user index 0 is reserved, starts with 1
1398 for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
1399 {
1400 std::string curName(
1401 reinterpret_cast<char*>(userData->user[usrIndex].userName), 0,
1402 ipmiMaxUserName);
1403 if (userName == curName)
1404 {
1405 log<level::DEBUG>("User name exists",
1406 entry("USER_NAME=%s", userName.c_str()));
1407 return false; // user name exists.
1408 }
1409
1410 if ((!userData->user[usrIndex].userInSystem) &&
1411 (userData->user[usrIndex].userName[0] == '\0') &&
1412 (freeIndex == 0xFF))
1413 {
1414 freeIndex = usrIndex;
1415 }
1416 }
1417 if (freeIndex == 0xFF)
1418 {
1419 log<level::ERR>("No empty slots found");
1420 return false;
1421 }
1422 std::strncpy(reinterpret_cast<char*>(userData->user[freeIndex].userName),
1423 userName.c_str(), ipmiMaxUserName);
1424 uint8_t priv =
1425 static_cast<uint8_t>(UserAccess::convertToIPMIPrivilege(sysPriv)) &
1426 privMask;
1427 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1428 {
1429 userData->user[freeIndex].userPrivAccess[chIndex].privilege = priv;
1430 userData->user[freeIndex].userPrivAccess[chIndex].ipmiEnabled = true;
1431 userData->user[freeIndex].userPrivAccess[chIndex].linkAuthEnabled =
1432 true;
1433 userData->user[freeIndex].userPrivAccess[chIndex].accessCallback = true;
1434 }
1435 userData->user[freeIndex].userInSystem = true;
1436 userData->user[freeIndex].userEnabled = enabled;
1437
1438 return true;
1439}
1440
1441void UserAccess::deleteUserIndex(const size_t& usrIdx)
1442{
1443 UsersTbl* userData = getUsersTblPtr();
1444
1445 std::string userName(
1446 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1447 ipmiMaxUserName);
1448 ipmiClearUserEntryPassword(userName);
1449 std::fill(static_cast<uint8_t*>(userData->user[usrIdx].userName),
1450 static_cast<uint8_t*>(userData->user[usrIdx].userName) +
1451 sizeof(userData->user[usrIdx].userName),
1452 0);
1453 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1454 {
1455 userData->user[usrIdx].userPrivAccess[chIndex].privilege = privNoAccess;
1456 userData->user[usrIdx].userPrivAccess[chIndex].ipmiEnabled = false;
1457 userData->user[usrIdx].userPrivAccess[chIndex].linkAuthEnabled = false;
1458 userData->user[usrIdx].userPrivAccess[chIndex].accessCallback = false;
1459 }
1460 userData->user[usrIdx].userInSystem = false;
1461 userData->user[usrIdx].userEnabled = false;
1462 return;
1463}
1464
1465void UserAccess::checkAndReloadUserData()
1466{
1467 std::time_t updateTime = getUpdatedFileTime();
1468 if (updateTime != fileLastUpdatedTime || updateTime == -EIO)
1469 {
1470 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1471 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1472 readUserData();
1473 }
1474 return;
1475}
1476
1477UsersTbl* UserAccess::getUsersTblPtr()
1478{
1479 // reload data before using it.
1480 checkAndReloadUserData();
1481 return &usersTbl;
1482}
1483
1484void UserAccess::getSystemPrivAndGroups()
1485{
1486 std::map<std::string, PrivAndGroupType> properties;
1487 try
1488 {
1489 auto method = bus.new_method_call(
1490 getUserServiceName().c_str(), userMgrObjBasePath,
1491 dBusPropertiesInterface, getAllPropertiesMethod);
1492 method.append(userMgrInterface);
1493
1494 auto reply = bus.call(method);
1495 reply.read(properties);
1496 }
1497 catch (const sdbusplus::exception::SdBusError& e)
1498 {
1499 log<level::DEBUG>("Failed to excute method",
1500 entry("METHOD=%s", getAllPropertiesMethod),
1501 entry("PATH=%s", userMgrObjBasePath));
1502 return;
1503 }
1504 for (const auto& t : properties)
1505 {
1506 auto key = t.first;
1507 if (key == allPrivProperty)
1508 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001509 availablePrivileges = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301510 }
1511 else if (key == allGrpProperty)
1512 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001513 availableGroups = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301514 }
1515 }
1516 // TODO: Implement Supported Privilege & Groups verification logic
1517 return;
1518}
1519
1520std::time_t UserAccess::getUpdatedFileTime()
1521{
1522 struct stat fileStat;
1523 if (stat(ipmiUserDataFile, &fileStat) != 0)
1524 {
1525 log<level::DEBUG>("Error in getting last updated time stamp");
1526 return -EIO;
1527 }
1528 return fileStat.st_mtime;
1529}
1530
1531void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
1532 std::vector<std::string>& usrGrps,
1533 std::string& usrPriv, bool& usrEnabled)
1534{
1535 for (const auto& t : properties)
1536 {
1537 std::string key = t.first;
1538 if (key == userPrivProperty)
1539 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001540 usrPriv = std::get<std::string>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301541 }
1542 else if (key == userGrpProperty)
1543 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001544 usrGrps = std::get<std::vector<std::string>>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301545 }
1546 else if (key == userEnabledProperty)
1547 {
Vernon Maueryf442e112019-04-09 11:44:36 -07001548 usrEnabled = std::get<bool>(t.second);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301549 }
1550 }
1551 return;
1552}
1553
1554int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
1555 std::vector<std::string>& usrGrps,
1556 std::string& usrPriv, bool& usrEnabled)
1557{
1558 auto usrObj = userObjs.find(usersInterface);
1559 if (usrObj != userObjs.end())
1560 {
1561 getUserProperties(usrObj->second, usrGrps, usrPriv, usrEnabled);
1562 return 0;
1563 }
1564 return -EIO;
1565}
1566
arun-pmbbe728c2020-01-10 15:18:04 +05301567void UserAccess::cacheUserDataFile()
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301568{
1569 boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
1570 userLock{*userMutex};
1571 try
1572 {
1573 readUserData();
1574 }
1575 catch (const std::ios_base::failure& e)
1576 { // File is empty, create it for the first time
1577 std::fill(reinterpret_cast<uint8_t*>(&usersTbl),
1578 reinterpret_cast<uint8_t*>(&usersTbl) + sizeof(usersTbl), 0);
1579 // user index 0 is reserved, starts with 1
1580 for (size_t userIndex = 1; userIndex <= ipmiMaxUsers; ++userIndex)
1581 {
1582 for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
1583 {
1584 usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
1585 privNoAccess;
Saravanan Palanisamy92d81192019-08-07 18:00:04 +00001586 usersTbl.user[userIndex]
1587 .payloadAccess[chIndex]
1588 .stdPayloadEnables1[static_cast<uint8_t>(
1589 ipmi::PayloadType::SOL)] = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301590 }
1591 }
1592 writeUserData();
1593 }
arun-pmbbe728c2020-01-10 15:18:04 +05301594 sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
1595 // Register it for single object and single process either netipimd /
1596 // host-ipmid
1597 if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
1598 {
1599 log<level::DEBUG>("Registering signal handler");
1600 userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
1601 bus,
1602 sdbusplus::bus::match::rules::type::signal() +
1603 sdbusplus::bus::match::rules::interface(dBusObjManager) +
1604 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1605 [&](sdbusplus::message::message& msg) {
1606 userUpdatedSignalHandler(*this, msg);
1607 });
1608 userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
1609 bus,
1610 sdbusplus::bus::match::rules::type::signal() +
1611 sdbusplus::bus::match::rules::interface(userMgrInterface) +
1612 sdbusplus::bus::match::rules::path(userMgrObjBasePath),
1613 [&](sdbusplus::message::message& msg) {
1614 userUpdatedSignalHandler(*this, msg);
1615 });
1616 userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
1617 bus,
1618 sdbusplus::bus::match::rules::type::signal() +
1619 sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
1620 sdbusplus::bus::match::rules::interface(
1621 dBusPropertiesInterface) +
1622 sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
1623 sdbusplus::bus::match::rules::argN(0, usersInterface),
1624 [&](sdbusplus::message::message& msg) {
1625 userUpdatedSignalHandler(*this, msg);
1626 });
1627 signalHndlrObject = true;
1628 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301629 std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
1630 try
1631 {
1632 auto method = bus.new_method_call(getUserServiceName().c_str(),
1633 userMgrObjBasePath, dBusObjManager,
1634 getManagedObjectsMethod);
1635 auto reply = bus.call(method);
1636 reply.read(managedObjs);
1637 }
1638 catch (const sdbusplus::exception::SdBusError& e)
1639 {
1640 log<level::DEBUG>("Failed to excute method",
1641 entry("METHOD=%s", getSubTreeMethod),
1642 entry("PATH=%s", userMgrObjBasePath));
1643 return;
1644 }
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301645 bool updateRequired = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301646 UsersTbl* userData = &usersTbl;
1647 // user index 0 is reserved, starts with 1
1648 for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
1649 {
1650 if ((userData->user[usrIdx].userInSystem) &&
1651 (userData->user[usrIdx].userName[0] != '\0'))
1652 {
1653 std::vector<std::string> usrGrps;
1654 std::string usrPriv;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301655
1656 std::string userName(
1657 reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
1658 ipmiMaxUserName);
1659 std::string usersPath =
1660 std::string(userObjBasePath) + "/" + userName;
1661
1662 auto usrObj = managedObjs.find(usersPath);
1663 if (usrObj != managedObjs.end())
1664 {
Chen,Yugang0e862fa2019-09-06 11:03:05 +08001665 bool usrEnabled = false;
Patrick Venture3a697ad2019-08-19 11:12:05 -07001666
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301667 // User exist. Lets check and update other fileds
1668 getUserObjProperties(usrObj->second, usrGrps, usrPriv,
1669 usrEnabled);
1670 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
1671 usrGrps.end())
1672 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301673 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301674 // Group "ipmi" is removed so lets remove user in IPMI
1675 deleteUserIndex(usrIdx);
1676 }
1677 else
1678 {
1679 // Group "ipmi" is present so lets update other properties
1680 // in IPMI
1681 uint8_t priv =
1682 UserAccess::convertToIPMIPrivilege(usrPriv) & privMask;
1683 // Update all channels priv, only if it is not equivalent to
1684 // getUsrMgmtSyncIndex()
1685 if (userData->user[usrIdx]
1686 .userPrivAccess[getUsrMgmtSyncIndex()]
1687 .privilege != priv)
1688 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301689 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301690 for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
1691 ++chIndex)
1692 {
1693 userData->user[usrIdx]
1694 .userPrivAccess[chIndex]
1695 .privilege = priv;
1696 }
1697 }
1698 if (userData->user[usrIdx].userEnabled != usrEnabled)
1699 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301700 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301701 userData->user[usrIdx].userEnabled = usrEnabled;
1702 }
1703 }
1704
1705 // We are done with this obj. lets delete from MAP
1706 managedObjs.erase(usrObj);
1707 }
1708 else
1709 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301710 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301711 deleteUserIndex(usrIdx);
1712 }
1713 }
1714 }
1715
1716 // Walk through remnaining managedObj users list
1717 // Add them to ipmi data base
1718 for (const auto& usrObj : managedObjs)
1719 {
1720 std::vector<std::string> usrGrps;
1721 std::string usrPriv, userName;
Chen,Yugang0e862fa2019-09-06 11:03:05 +08001722 bool usrEnabled = false;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301723 std::string usrObjPath = std::string(usrObj.first);
1724 if (getUserNameFromPath(usrObj.first.str, userName) != 0)
1725 {
1726 log<level::ERR>("Error in user object path");
1727 continue;
1728 }
1729 getUserObjProperties(usrObj.second, usrGrps, usrPriv, usrEnabled);
1730 // Add 'ipmi' group users
1731 if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
1732 usrGrps.end())
1733 {
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301734 updateRequired = true;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301735 // CREATE NEW USER
1736 if (true != addUserEntry(userName, usrPriv, usrEnabled))
1737 {
1738 break;
1739 }
1740 }
1741 }
1742
Richard Marian Thomaiyare004e222019-05-09 00:37:55 +05301743 if (updateRequired)
1744 {
1745 // All userData slots update done. Lets write the data
1746 writeUserData();
1747 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301748
1749 return;
1750}
1751} // namespace ipmi