1 /*
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 #pragma once
17 #include "json_serializer.hpp"
18 #include "users.hpp"
19
20 #include <shadow.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23
24 #include <boost/process/v1/child.hpp>
25 #include <boost/process/v1/io.hpp>
26 #include <phosphor-logging/elog-errors.hpp>
27 #include <phosphor-logging/elog.hpp>
28 #include <phosphor-logging/lg2.hpp>
29 #include <sdbusplus/bus.hpp>
30 #include <sdbusplus/server/object.hpp>
31 #include <xyz/openbmc_project/Common/error.hpp>
32 #include <xyz/openbmc_project/User/AccountPolicy/server.hpp>
33 #include <xyz/openbmc_project/User/Manager/server.hpp>
34 #include <xyz/openbmc_project/User/MultiFactorAuthConfiguration/server.hpp>
35 #include <xyz/openbmc_project/User/TOTPState/server.hpp>
36
37 #include <optional>
38 #include <span>
39 #include <string>
40 #include <unordered_map>
41 #include <variant>
42 #include <vector>
43
44 namespace phosphor
45 {
46 namespace user
47 {
48
49 inline constexpr size_t ipmiMaxUsers = 15;
50 inline constexpr size_t maxSystemUsers = 30;
51 inline constexpr uint8_t minPasswdLength = 8;
52 extern uint8_t maxPasswdLength; // MAX_PASSWORD_LENGTH;
53 inline constexpr size_t maxSystemGroupNameLength = 32;
54 inline constexpr size_t maxSystemGroupCount = 64;
55
56 using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager;
57 using UserSSHLists =
58 std::pair<std::vector<std::string>, std::vector<std::string>>;
59 using AccountPolicyIface =
60 sdbusplus::xyz::openbmc_project::User::server::AccountPolicy;
61
62 using MultiFactorAuthConfigurationIface =
63 sdbusplus::xyz::openbmc_project::User::server::MultiFactorAuthConfiguration;
64
65 using TOTPStateIface = sdbusplus::xyz::openbmc_project::User::server::TOTPState;
66
67 using UserProperty =
68 sdbusplus::common::xyz::openbmc_project::user::Manager::UserProperty;
69
70 using Ifaces = sdbusplus::server::object_t<UserMgrIface, AccountPolicyIface,
71 MultiFactorAuthConfigurationIface,
72 TOTPStateIface>;
73
74 using Privilege = std::string;
75 using GroupList = std::vector<std::string>;
76 using UserEnabled = bool;
77 using PropertyName = std::string;
78 using ServiceEnabled = bool;
79 using PasswordExpiration = uint64_t;
80
81 using UserInfo =
82 std::variant<Privilege, GroupList, UserEnabled, PasswordExpiration>;
83
84 using UserInfoMap = std::map<PropertyName, UserInfo>;
85
86 using UserCreateMap = std::map<UserProperty, UserInfo>;
87
88 using DbusUserObjPath = sdbusplus::message::object_path;
89
90 using DbusUserPropVariant = std::variant<Privilege, ServiceEnabled>;
91
92 using DbusUserObjProperties = std::map<PropertyName, DbusUserPropVariant>;
93
94 using Interface = std::string;
95
96 using DbusUserObjValue = std::map<Interface, DbusUserObjProperties>;
97
98 using DbusUserObj = std::map<DbusUserObjPath, DbusUserObjValue>;
99
100 using MultiFactorAuthType = sdbusplus::common::xyz::openbmc_project::user::
101 MultiFactorAuthConfiguration::Type;
102 std::string getCSVFromVector(std::span<const std::string> vec);
103
104 bool removeStringFromCSV(std::string& csvStr, const std::string& delStr);
105
106 template <typename... ArgTypes>
executeCmd(const char * path,ArgTypes &&...tArgs)107 std::vector<std::string> executeCmd(const char* path, ArgTypes&&... tArgs)
108 {
109 int pipefd[2];
110
111 if (pipe(pipefd) == -1)
112 {
113 lg2::error("Failed to create pipe: {ERROR}", "ERROR", strerror(errno));
114 phosphor::logging::elog<
115 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
116 return {};
117 }
118
119 pid_t pid = fork();
120
121 if (pid == -1)
122 {
123 lg2::error("Failed to fork process: {ERROR}", "ERROR", strerror(errno));
124 phosphor::logging::elog<
125 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
126 close(pipefd[0]); // Close read end of pipe
127 close(pipefd[1]); // Close write end of pipe
128 return {};
129 }
130
131 if (pid == 0) // Child process
132 {
133 close(pipefd[0]); // Close read end of pipe
134
135 // Redirect write end of the pipe to stdout.
136 if (dup2(pipefd[1], STDOUT_FILENO) == -1)
137 {
138 lg2::error("Failed to redirect stdout: {ERROR}", "ERROR",
139 strerror(errno));
140 _exit(EXIT_FAILURE);
141 }
142 close(pipefd[1]); // Close write end of pipe
143
144 std::vector<const char*> args = {path};
145 (args.emplace_back(const_cast<const char*>(tArgs)), ...);
146 args.emplace_back(nullptr);
147
148 execv(path, const_cast<char* const*>(args.data()));
149
150 // If exec returns, an error occurred
151 lg2::error("Failed to execute command '{PATH}': {ERROR}", "PATH", path,
152 "ERROR", strerror(errno));
153 _exit(EXIT_FAILURE);
154 }
155
156 // Parent process.
157
158 close(pipefd[1]); // Close write end of pipe
159
160 FILE* fp = fdopen(pipefd[0], "r");
161 if (fp == nullptr)
162 {
163 lg2::error("Failed to open pipe for reading: {ERROR}", "ERROR",
164 strerror(errno));
165 close(pipefd[0]);
166 phosphor::logging::elog<
167 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
168 return {};
169 }
170
171 std::vector<std::string> results;
172 char buffer[256];
173 while (fgets(buffer, sizeof(buffer), fp) != nullptr)
174 {
175 std::string line = buffer;
176 if (!line.empty() && line.back() == '\n')
177 {
178 line.pop_back(); // Remove newline character
179 }
180 results.emplace_back(line);
181 }
182
183 fclose(fp);
184 close(pipefd[0]);
185
186 int status;
187 while (waitpid(pid, &status, 0) == -1)
188 {
189 // Need to retry on EINTR.
190 if (errno == EINTR)
191 {
192 continue;
193 }
194
195 lg2::error("Failed to wait for child process: {ERROR}", "ERROR",
196 strerror(errno));
197 phosphor::logging::elog<
198 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
199 return {};
200 }
201
202 if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
203 {
204 lg2::error("Command {PATH} execution failed, return code {RETCODE}",
205 "PATH", path, "RETCODE", WEXITSTATUS(status));
206 phosphor::logging::elog<
207 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
208 }
209
210 return results;
211 }
212
213 /** @class UserMgr
214 * @brief Responsible for managing user accounts over the D-Bus interface.
215 */
216 class UserMgr : public Ifaces
217 {
218 public:
219 UserMgr() = delete;
220 ~UserMgr() = default;
221 UserMgr(const UserMgr&) = delete;
222 UserMgr& operator=(const UserMgr&) = delete;
223 UserMgr(UserMgr&&) = delete;
224 UserMgr& operator=(UserMgr&&) = delete;
225
226 /** @brief Constructs UserMgr object.
227 *
228 * @param[in] bus - sdbusplus handler
229 * @param[in] path - D-Bus path
230 */
231 UserMgr(sdbusplus::bus_t& bus, const char* path);
232
233 /** @brief create user method.
234 * This method creates a new user as requested
235 *
236 * @param[in] userName - Name of the user which has to be created
237 * @param[in] groupNames - Group names list, to which user has to be added.
238 * @param[in] priv - Privilege of the user.
239 * @param[in] enabled - State of the user enabled / disabled.
240 */
241 void createUser(std::string userName, std::vector<std::string> groupNames,
242 std::string priv, bool enabled) override;
243
244 /** @brief create user with password expiration method.
245 * This method creates a new user as requested
246 *
247 * @param[in] userName - Name of the user which has to be created
248 * @param[in] props - Create user properties.
249 */
250 void createUser2(std::string userName, UserCreateMap props) override;
251
252 /** @brief rename user method.
253 * This method renames the user as requested
254 *
255 * @param[in] userName - current name of the user
256 * @param[in] newUserName - new user name to which it has to be renamed.
257 */
258 void renameUser(std::string userName, std::string newUserName) override;
259
260 /** @brief delete user method.
261 * This method deletes the user as requested
262 *
263 * @param[in] userName - Name of the user which has to be deleted
264 */
265 void deleteUser(std::string userName);
266
267 /** @brief Update user groups & privilege.
268 * This method updates user groups & privilege
269 *
270 * @param[in] userName - user name, for which update is requested
271 * @param[in] groupName - Group to be updated..
272 * @param[in] priv - Privilege to be updated.
273 */
274 void updateGroupsAndPriv(const std::string& userName,
275 std::vector<std::string> groups,
276 const std::string& priv);
277
278 /** @brief Update user enabled state.
279 * This method enables / disables user
280 *
281 * @param[in] userName - user name, for which update is requested
282 * @param[in] enabled - enable / disable the user
283 */
284 void userEnable(const std::string& userName, bool enabled);
285
286 /** @brief get user enabled state
287 * method to get user enabled state.
288 *
289 * @param[in] userName - name of the user
290 * @return - user enabled status (true/false)
291 */
292 virtual bool isUserEnabled(const std::string& userName);
293
294 /** @brief update minimum password length requirement
295 *
296 * @param[in] val - minimum password length
297 * @return - minimum password length
298 */
299 uint8_t minPasswordLength(uint8_t val) override;
300
301 /** @brief update old password history count
302 *
303 * @param[in] val - number of times old passwords has to be avoided
304 * @return - number of times old password has to be avoided
305 */
306 uint8_t rememberOldPasswordTimes(uint8_t val) override;
307
308 /** @brief update maximum number of failed login attempt before locked
309 * out.
310 *
311 * @param[in] val - number of allowed attempt
312 * @return - number of allowed attempt
313 */
314 uint16_t maxLoginAttemptBeforeLockout(uint16_t val) override;
315
316 /** @brief update timeout to unlock the account
317 *
318 * @param[in] val - value in seconds
319 * @return - value in seconds
320 */
321 uint32_t accountUnlockTimeout(uint32_t val) override;
322
323 /** @brief parses the faillock output for locked user status
324 *
325 * @param[in] - output from faillock for the user
326 * @return - true / false indicating user locked / un-locked
327 **/
328 bool parseFaillockForLockout(
329 const std::vector<std::string>& faillockOutput);
330
331 /** @brief lists user locked state for failed attempt
332 *
333 * @param[in] - user name
334 * @return - true / false indicating user locked / un-locked
335 **/
336 virtual bool userLockedForFailedAttempt(const std::string& userName);
337
338 /** @brief lists user locked state for failed attempt
339 *
340 * @param[in]: user name
341 * @param[in]: value - false -unlock user account, true - no action taken
342 **/
343 bool userLockedForFailedAttempt(const std::string& userName,
344 const bool& value);
345
346 /** @brief shows if the user's password is expired
347 *
348 * @param[in]: user name
349 * @return - true / false indicating user password expired
350 **/
351 virtual bool userPasswordExpired(const std::string& userName);
352
353 /** @brief returns user info
354 * Checks if user is local user, then returns map of properties of user.
355 * like user privilege, list of user groups, user enabled state and user
356 * locked state. If its not local user, then it checks if its a ldap user,
357 * then it gets the privilege mapping of the LDAP group.
358 *
359 * @param[in] - user name
360 * @return - map of user properties
361 **/
362 UserInfoMap getUserInfo(std::string userName) override;
363
364 /** @brief get IPMI user count
365 * method to get IPMI user count
366 *
367 * @return - returns user count
368 */
369 virtual size_t getIpmiUsersCount(void);
370
371 void createGroup(std::string groupName) override;
372
373 void deleteGroup(std::string groupName) override;
enabled() const374 MultiFactorAuthType enabled() const override
375 {
376 return MultiFactorAuthConfigurationIface::enabled();
377 }
378 MultiFactorAuthType enabled(MultiFactorAuthType value,
379 bool skipSignal) override;
380 bool secretKeyRequired(std::string userName) override;
381 static std::vector<std::string> readAllGroupsOnSystem();
382 void load();
getSerializer()383 JsonSerializer& getSerializer()
384 {
385 return serializer;
386 }
387
388 /** @brief user password expiration
389 *
390 * Password expiration is date time when the user password expires. The time
391 * is the Epoch time, number of seconds since 1 Jan 1970 00::00::00 UTC.
392 *When zero value is returned, it means that password does not expire.
393 *
394 * @param[in]: user name
395 * @return - Epoch time when the user password expires
396 **/
397 uint64_t getPasswordExpiration(const std::string& userName) const;
398
399 /** @brief update user password expiration
400 *
401 * Password expiration is date time when the user password expires. The time
402 * is the Epoch time, number of seconds since 1 Jan 1970 00::00::00 UTC.
403 *When zero value is provided, it means that password does not expire.
404 *
405 * @param[in]: user name
406 * @param[in]: Epoch time when the user password expires
407 **/
408 void setPasswordExpiration(const std::string& userName,
409 const uint64_t value);
410
411 protected:
412 /** @brief get pam argument value
413 * method to get argument value from pam configuration
414 *
415 * @param[in] moduleName - name of the module from where arg has to be read
416 * @param[in] argName - argument name
417 * @param[out] argValue - argument value
418 *
419 * @return 0 - success state of the function
420 */
421 int getPamModuleArgValue(const std::string& moduleName,
422 const std::string& argName, std::string& argValue);
423
424 /** @brief get pam argument value
425 * method to get argument value from pam configuration
426 *
427 * @param[in] confFile - path of the module config file from where arg has
428 * to be read
429 * @param[in] argName - argument name
430 * @param[out] argValue - argument value
431 *
432 * @return 0 - success state of the function
433 */
434 int getPamModuleConfValue(const std::string& confFile,
435 const std::string& argName,
436 std::string& argValue);
437
438 /** @brief set pam argument value
439 * method to set argument value in pam configuration
440 *
441 * @param[in] moduleName - name of the module in which argument value has
442 * to be set
443 * @param[in] argName - argument name
444 * @param[out] argValue - argument value
445 *
446 * @return 0 - success state of the function
447 */
448 int setPamModuleArgValue(const std::string& moduleName,
449 const std::string& argName,
450 const std::string& argValue);
451
452 /** @brief set pam argument value
453 * method to set argument value in pam configuration
454 *
455 * @param[in] confFile - path of the module config file in which argument
456 * value has to be set
457 * @param[in] argName - argument name
458 * @param[out] argValue - argument value
459 *
460 * @return 0 - success state of the function
461 */
462 int setPamModuleConfValue(const std::string& confFile,
463 const std::string& argName,
464 const std::string& argValue);
465
466 /** @brief check for user presence
467 * method to check for user existence
468 *
469 * @param[in] userName - name of the user
470 * @return -true if user exists and false if not.
471 */
472 bool isUserExist(const std::string& userName) const;
473
474 /** @brief check for user presence at the system level
475 * method to check for user existence
476 *
477 * @param[in] userName - name of the user
478 * @return -true if user exists and false if not.
479 */
480 virtual bool isUserExistSystem(const std::string& userName);
481
482 size_t getNonIpmiUsersCount();
483
484 /** @brief check user exists
485 * method to check whether user exist, and throw if not.
486 *
487 * @param[in] userName - name of the user
488 */
489 void throwForUserDoesNotExist(const std::string& userName) const;
490
491 /** @brief check user does not exist
492 * method to check whether does not exist, and throw if exists.
493 *
494 * @param[in] userName - name of the user
495 */
496 void throwForUserExists(const std::string& userName);
497
498 /** @brief check user name constraints
499 * method to check user name constraints and throw if failed.
500 *
501 * @param[in] userName - name of the user
502 * @param[in] groupNames - user groups
503 */
504 void throwForUserNameConstraints(
505 const std::string& userName,
506 const std::vector<std::string>& groupNames);
507
508 /** @brief check group user count
509 * method to check max group user count, and throw if limit reached
510 *
511 * @param[in] groupNames - group name
512 */
513 void throwForMaxGrpUserCount(const std::vector<std::string>& groupNames);
514
515 virtual void executeUserAdd(const char* userName, const char* groups,
516 bool sshRequested, bool enabled);
517
518 virtual void executeUserDelete(const char* userName);
519
520 /** @brief clear user's failure records
521 * method to clear user fail records and throw if failed.
522 *
523 * @param[in] userName - name of the user
524 */
525 virtual void executeUserClearFailRecords(const char* userName);
526
527 virtual void executeUserRename(const char* userName,
528 const char* newUserName);
529
530 virtual void executeUserModify(const char* userName, const char* newGroups,
531 bool sshRequested);
532
533 virtual void executeUserModifyUserEnable(const char* userName,
534 bool enabled);
535
536 virtual void executeGroupCreation(const char* groupName);
537
538 virtual void executeGroupDeletion(const char* groupName);
539
540 virtual void executeUserPasswordExpiration(
541 const char* userName, const long int passwordLastChange,
542 const long int passwordAge) const;
543
544 virtual std::vector<std::string> getFailedAttempt(const char* userName);
545
546 /** @brief check for valid privielge
547 * method to check valid privilege, and throw if invalid
548 *
549 * @param[in] priv - privilege of the user
550 */
551 void throwForInvalidPrivilege(const std::string& priv);
552
553 /** @brief check for valid groups
554 * method to check valid groups, and throw if invalid
555 *
556 * @param[in] groupNames - user groups
557 */
558 void throwForInvalidGroups(const std::vector<std::string>& groupName);
559
560 void initializeAccountPolicy();
561
562 /** @brief checks if the group creation meets all constraints
563 * @param groupName - group to check
564 */
565 void checkCreateGroupConstraints(const std::string& groupName);
566
567 /** @brief checks if the group deletion meets all constraints
568 * @param groupName - group to check
569 */
570 void checkDeleteGroupConstraints(const std::string& groupName);
571
572 /** @brief checks if the group name is legal and whether it's allowed to
573 * change. The daemon doesn't allow arbitrary group to be created
574 * @param groupName - group to check
575 */
576 void checkAndThrowForDisallowedGroupCreation(const std::string& groupName);
577
578 private:
579 /** @brief sdbusplus handler */
580 sdbusplus::bus_t& bus;
581
582 /** @brief object path */
583 const std::string path;
584
585 /** @brief serializer for mfa */
586 JsonSerializer serializer;
587 /** @brief privilege manager container */
588 const std::vector<std::string> privMgr = {"priv-admin", "priv-operator",
589 "priv-user"};
590
591 /** @brief groups manager container */
592 std::vector<std::string> groupsMgr;
593
594 /** @brief map container to hold users object */
595
596 std::unordered_map<std::string, std::unique_ptr<phosphor::user::Users>>
597 usersList;
598
599 /** @brief get users in group
600 * method to get group user list
601 *
602 * @param[in] groupName - group name
603 *
604 * @return userList - list of users in the group.
605 */
606 std::vector<std::string> getUsersInGroup(const std::string& groupName);
607
608 /** @brief get user & SSH users list
609 * method to get the users and ssh users list.
610 *
611 *@return - vector of User & SSH user lists
612 */
613 UserSSHLists getUserAndSshGrpList(void);
614
615 /** @brief initialize the user manager objects
616 * method to initialize the user manager objects accordingly
617 *
618 */
619 void initUserObjects(void);
620
621 /** @brief get service name
622 * method to get dbus service name
623 *
624 * @param[in] path - object path
625 * @param[in] intf - interface
626 * @return - service name
627 */
628 std::string getServiceName(std::string&& path, std::string&& intf);
629
630 /** @brief get primary group ID of specified user
631 *
632 * @param[in] - userName
633 * @return - primary group ID
634 */
635 virtual gid_t getPrimaryGroup(const std::string& userName) const;
636
637 /** @brief check whether if the user is a member of the group
638 *
639 * @param[in] - userName
640 * @param[in] - ID of the user's primary group
641 * @param[in] - groupName
642 * @return - true if the user is a member of the group
643 */
644 virtual bool isGroupMember(const std::string& userName, gid_t primaryGid,
645 const std::string& groupName) const;
646
647 protected:
648 /** @brief get privilege mapper object
649 * method to get dbus privilege mapper object
650 *
651 * @return - map of user object
652 */
653 virtual DbusUserObj getPrivilegeMapperObject(void);
654
655 friend class TestUserMgr;
656
657 std::string faillockConfigFile;
658 std::string pwHistoryConfigFile;
659 std::string pwQualityConfigFile;
660
661 private:
662 void createUserImpl(const std::string& userName, UserCreateMap props);
663
664 void setPasswordExpirationImpl(const std::string& userName,
665 const uint64_t value);
666
667 void deleteUserImpl(const std::string& userName);
668
669 public:
670 // This functions need to be public for tests
671
672 /** @brief value of a password maximum age indicating that the password does
673 * not expire
674 *
675 **/
getUnexpiringPasswordAge()676 static constexpr long int getUnexpiringPasswordAge()
677 {
678 return -1;
679 }
680
681 /** @brief date time value indicating that a password does not expire
682 *
683 **/
getUnexpiringPasswordTime()684 static constexpr uint64_t getUnexpiringPasswordTime()
685 {
686 return 0;
687 };
688
689 /** @brief date time value indicating that a password expiration is not set
690 *
691 **/
getDefaultPasswordExpiration()692 static constexpr uint64_t getDefaultPasswordExpiration()
693 {
694 // default password expiration value
695 return std::numeric_limits<uint64_t>::max();
696 };
697
698 protected:
699 // This function needs to be virtual and protected for tests
700 virtual void getShadowData(const std::string& userName,
701 struct spwd& spwd) const;
702 };
703
704 } // namespace user
705 } // namespace phosphor
706