xref: /openbmc/phosphor-user-manager/user_mgr.hpp (revision 0e427be810a3233f23186cce599e8bf680ae3f62)
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 <boost/process/child.hpp>
21 #include <boost/process/io.hpp>
22 #include <phosphor-logging/elog-errors.hpp>
23 #include <phosphor-logging/elog.hpp>
24 #include <phosphor-logging/lg2.hpp>
25 #include <sdbusplus/bus.hpp>
26 #include <sdbusplus/server/object.hpp>
27 #include <xyz/openbmc_project/Common/error.hpp>
28 #include <xyz/openbmc_project/User/AccountPolicy/server.hpp>
29 #include <xyz/openbmc_project/User/Manager/server.hpp>
30 #include <xyz/openbmc_project/User/MultiFactorAuthConfiguration/server.hpp>
31 #include <xyz/openbmc_project/User/TOTPState/server.hpp>
32 
33 #include <span>
34 #include <string>
35 #include <unordered_map>
36 #include <variant>
37 #include <vector>
38 
39 namespace phosphor
40 {
41 namespace user
42 {
43 
44 inline constexpr size_t ipmiMaxUsers = 15;
45 inline constexpr size_t maxSystemUsers = 30;
46 inline constexpr uint8_t minPasswdLength = 8;
47 inline constexpr size_t maxSystemGroupNameLength = 32;
48 inline constexpr size_t maxSystemGroupCount = 64;
49 
50 using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager;
51 using UserSSHLists =
52     std::pair<std::vector<std::string>, std::vector<std::string>>;
53 using AccountPolicyIface =
54     sdbusplus::xyz::openbmc_project::User::server::AccountPolicy;
55 
56 using MultiFactorAuthConfigurationIface =
57     sdbusplus::xyz::openbmc_project::User::server::MultiFactorAuthConfiguration;
58 
59 using TOTPStateIface = sdbusplus::xyz::openbmc_project::User::server::TOTPState;
60 
61 using Ifaces = sdbusplus::server::object_t<UserMgrIface, AccountPolicyIface,
62                                            MultiFactorAuthConfigurationIface,
63                                            TOTPStateIface>;
64 
65 using Privilege = std::string;
66 using GroupList = std::vector<std::string>;
67 using UserEnabled = bool;
68 using PropertyName = std::string;
69 using ServiceEnabled = bool;
70 
71 using UserInfo = std::variant<Privilege, GroupList, UserEnabled>;
72 using UserInfoMap = std::map<PropertyName, UserInfo>;
73 
74 using DbusUserObjPath = sdbusplus::message::object_path;
75 
76 using DbusUserPropVariant = std::variant<Privilege, ServiceEnabled>;
77 
78 using DbusUserObjProperties = std::map<PropertyName, DbusUserPropVariant>;
79 
80 using Interface = std::string;
81 
82 using DbusUserObjValue = std::map<Interface, DbusUserObjProperties>;
83 
84 using DbusUserObj = std::map<DbusUserObjPath, DbusUserObjValue>;
85 
86 using MultiFactorAuthType = sdbusplus::common::xyz::openbmc_project::user::
87     MultiFactorAuthConfiguration::Type;
88 std::string getCSVFromVector(std::span<const std::string> vec);
89 
90 bool removeStringFromCSV(std::string& csvStr, const std::string& delStr);
91 
92 template <typename... ArgTypes>
executeCmd(const char * path,ArgTypes &&...tArgs)93 std::vector<std::string> executeCmd(const char* path, ArgTypes&&... tArgs)
94 {
95     std::vector<std::string> stdOutput;
96     boost::process::ipstream stdOutStream;
97     boost::process::child execProg(path, const_cast<char*>(tArgs)...,
98                                    boost::process::std_out > stdOutStream);
99     std::string stdOutLine;
100 
101     while (stdOutStream && std::getline(stdOutStream, stdOutLine) &&
102            !stdOutLine.empty())
103     {
104         stdOutput.emplace_back(stdOutLine);
105     }
106 
107     execProg.wait();
108 
109     int retCode = execProg.exit_code();
110     if (retCode)
111     {
112         lg2::error("Command {PATH} execution failed, return code {RETCODE}",
113                    "PATH", path, "RETCODE", retCode);
114         phosphor::logging::elog<
115             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
116     }
117 
118     return stdOutput;
119 }
120 
121 /** @class UserMgr
122  *  @brief Responsible for managing user accounts over the D-Bus interface.
123  */
124 class UserMgr : public Ifaces
125 {
126   public:
127     UserMgr() = delete;
128     ~UserMgr() = default;
129     UserMgr(const UserMgr&) = delete;
130     UserMgr& operator=(const UserMgr&) = delete;
131     UserMgr(UserMgr&&) = delete;
132     UserMgr& operator=(UserMgr&&) = delete;
133 
134     /** @brief Constructs UserMgr object.
135      *
136      *  @param[in] bus  - sdbusplus handler
137      *  @param[in] path - D-Bus path
138      */
139     UserMgr(sdbusplus::bus_t& bus, const char* path);
140 
141     /** @brief create user method.
142      *  This method creates a new user as requested
143      *
144      *  @param[in] userName - Name of the user which has to be created
145      *  @param[in] groupNames - Group names list, to which user has to be added.
146      *  @param[in] priv - Privilege of the user.
147      *  @param[in] enabled - State of the user enabled / disabled.
148      */
149     void createUser(std::string userName, std::vector<std::string> groupNames,
150                     std::string priv, bool enabled) override;
151 
152     /** @brief rename user method.
153      *  This method renames the user as requested
154      *
155      *  @param[in] userName - current name of the user
156      *  @param[in] newUserName - new user name to which it has to be renamed.
157      */
158     void renameUser(std::string userName, std::string newUserName) override;
159 
160     /** @brief delete user method.
161      *  This method deletes the user as requested
162      *
163      *  @param[in] userName - Name of the user which has to be deleted
164      */
165     void deleteUser(std::string userName);
166 
167     /** @brief Update user groups & privilege.
168      *  This method updates user groups & privilege
169      *
170      *  @param[in] userName - user name, for which update is requested
171      *  @param[in] groupName - Group to be updated..
172      *  @param[in] priv - Privilege to be updated.
173      */
174     void updateGroupsAndPriv(const std::string& userName,
175                              std::vector<std::string> groups,
176                              const std::string& priv);
177 
178     /** @brief Update user enabled state.
179      *  This method enables / disables user
180      *
181      *  @param[in] userName - user name, for which update is requested
182      *  @param[in] enabled - enable / disable the user
183      */
184     void userEnable(const std::string& userName, bool enabled);
185 
186     /** @brief get user enabled state
187      *  method to get user enabled state.
188      *
189      *  @param[in] userName - name of the user
190      *  @return - user enabled status (true/false)
191      */
192     virtual bool isUserEnabled(const std::string& userName);
193 
194     /** @brief update minimum password length requirement
195      *
196      *  @param[in] val - minimum password length
197      *  @return - minimum password length
198      */
199     uint8_t minPasswordLength(uint8_t val) override;
200 
201     /** @brief update old password history count
202      *
203      *  @param[in] val - number of times old passwords has to be avoided
204      *  @return - number of times old password has to be avoided
205      */
206     uint8_t rememberOldPasswordTimes(uint8_t val) override;
207 
208     /** @brief update maximum number of failed login attempt before locked
209      *  out.
210      *
211      *  @param[in] val - number of allowed attempt
212      *  @return - number of allowed attempt
213      */
214     uint16_t maxLoginAttemptBeforeLockout(uint16_t val) override;
215 
216     /** @brief update timeout to unlock the account
217      *
218      *  @param[in] val - value in seconds
219      *  @return - value in seconds
220      */
221     uint32_t accountUnlockTimeout(uint32_t val) override;
222 
223     /** @brief parses the faillock output for locked user status
224      *
225      * @param[in] - output from faillock for the user
226      * @return - true / false indicating user locked / un-locked
227      **/
228     bool parseFaillockForLockout(
229         const std::vector<std::string>& faillockOutput);
230 
231     /** @brief lists user locked state for failed attempt
232      *
233      * @param[in] - user name
234      * @return - true / false indicating user locked / un-locked
235      **/
236     virtual bool userLockedForFailedAttempt(const std::string& userName);
237 
238     /** @brief lists user locked state for failed attempt
239      *
240      * @param[in]: user name
241      * @param[in]: value - false -unlock user account, true - no action taken
242      **/
243     bool userLockedForFailedAttempt(const std::string& userName,
244                                     const bool& value);
245 
246     /** @brief shows if the user's password is expired
247      *
248      * @param[in]: user name
249      * @return - true / false indicating user password expired
250      **/
251     virtual bool userPasswordExpired(const std::string& userName);
252 
253     /** @brief returns user info
254      * Checks if user is local user, then returns map of properties of user.
255      * like user privilege, list of user groups, user enabled state and user
256      * locked state. If its not local user, then it checks if its a ldap user,
257      * then it gets the privilege mapping of the LDAP group.
258      *
259      * @param[in] - user name
260      * @return -  map of user properties
261      **/
262     UserInfoMap getUserInfo(std::string userName) override;
263 
264     /** @brief get IPMI user count
265      *  method to get IPMI user count
266      *
267      * @return - returns user count
268      */
269     virtual size_t getIpmiUsersCount(void);
270 
271     void createGroup(std::string groupName) override;
272 
273     void deleteGroup(std::string groupName) override;
274 
getUserObject(const std::string & userName)275     phosphor::user::Users* getUserObject(const std::string& userName)
276     {
277         return usersList[userName].get();
278     }
279 
enabled() const280     MultiFactorAuthType enabled() const override
281     {
282         return MultiFactorAuthConfigurationIface::enabled();
283     }
284     MultiFactorAuthType enabled(MultiFactorAuthType value,
285                                 bool skipSignal) override;
286     bool secretKeyRequired(std::string userName) override;
287     static std::vector<std::string> readAllGroupsOnSystem();
288     void load();
getSerializer()289     JsonSerializer& getSerializer()
290     {
291         return serializer;
292     }
293 
294   protected:
295     /** @brief get pam argument value
296      *  method to get argument value from pam configuration
297      *
298      *  @param[in] moduleName - name of the module from where arg has to be read
299      *  @param[in] argName - argument name
300      *  @param[out] argValue - argument value
301      *
302      *  @return 0 - success state of the function
303      */
304     int getPamModuleArgValue(const std::string& moduleName,
305                              const std::string& argName, std::string& argValue);
306 
307     /** @brief get pam argument value
308      *  method to get argument value from pam configuration
309      *
310      *  @param[in] confFile - path of the module config file from where arg has
311      * to be read
312      *  @param[in] argName - argument name
313      *  @param[out] argValue - argument value
314      *
315      *  @return 0 - success state of the function
316      */
317     int getPamModuleConfValue(const std::string& confFile,
318                               const std::string& argName,
319                               std::string& argValue);
320 
321     /** @brief set pam argument value
322      *  method to set argument value in pam configuration
323      *
324      *  @param[in] moduleName - name of the module in which argument value has
325      * to be set
326      *  @param[in] argName - argument name
327      *  @param[out] argValue - argument value
328      *
329      *  @return 0 - success state of the function
330      */
331     int setPamModuleArgValue(const std::string& moduleName,
332                              const std::string& argName,
333                              const std::string& argValue);
334 
335     /** @brief set pam argument value
336      *  method to set argument value in pam configuration
337      *
338      *  @param[in] confFile - path of the module config file in which argument
339      * value has to be set
340      *  @param[in] argName - argument name
341      *  @param[out] argValue - argument value
342      *
343      *  @return 0 - success state of the function
344      */
345     int setPamModuleConfValue(const std::string& confFile,
346                               const std::string& argName,
347                               const std::string& argValue);
348 
349     /** @brief check for user presence
350      *  method to check for user existence
351      *
352      *  @param[in] userName - name of the user
353      *  @return -true if user exists and false if not.
354      */
355     bool isUserExist(const std::string& userName);
356 
357     size_t getNonIpmiUsersCount();
358 
359     /** @brief check user exists
360      *  method to check whether user exist, and throw if not.
361      *
362      *  @param[in] userName - name of the user
363      */
364     void throwForUserDoesNotExist(const std::string& userName);
365 
366     /** @brief check user does not exist
367      *  method to check whether does not exist, and throw if exists.
368      *
369      *  @param[in] userName - name of the user
370      */
371     void throwForUserExists(const std::string& userName);
372 
373     /** @brief check user name constraints
374      *  method to check user name constraints and throw if failed.
375      *
376      *  @param[in] userName - name of the user
377      *  @param[in] groupNames - user groups
378      */
379     void throwForUserNameConstraints(
380         const std::string& userName,
381         const std::vector<std::string>& groupNames);
382 
383     /** @brief check group user count
384      *  method to check max group user count, and throw if limit reached
385      *
386      *  @param[in] groupNames - group name
387      */
388     void throwForMaxGrpUserCount(const std::vector<std::string>& groupNames);
389 
390     virtual void executeUserAdd(const char* userName, const char* groups,
391                                 bool sshRequested, bool enabled);
392 
393     virtual void executeUserDelete(const char* userName);
394 
395     /** @brief clear user's failure records
396      *  method to clear user fail records and throw if failed.
397      *
398      *  @param[in] userName - name of the user
399      */
400     virtual void executeUserClearFailRecords(const char* userName);
401 
402     virtual void executeUserRename(const char* userName,
403                                    const char* newUserName);
404 
405     virtual void executeUserModify(const char* userName, const char* newGroups,
406                                    bool sshRequested);
407 
408     virtual void executeUserModifyUserEnable(const char* userName,
409                                              bool enabled);
410 
411     virtual void executeGroupCreation(const char* groupName);
412 
413     virtual void executeGroupDeletion(const char* groupName);
414 
415     virtual std::vector<std::string> getFailedAttempt(const char* userName);
416 
417     /** @brief check for valid privielge
418      *  method to check valid privilege, and throw if invalid
419      *
420      *  @param[in] priv - privilege of the user
421      */
422     void throwForInvalidPrivilege(const std::string& priv);
423 
424     /** @brief check for valid groups
425      *  method to check valid groups, and throw if invalid
426      *
427      *  @param[in] groupNames - user groups
428      */
429     void throwForInvalidGroups(const std::vector<std::string>& groupName);
430 
431     void initializeAccountPolicy();
432 
433     /** @brief checks if the group creation meets all constraints
434      * @param groupName - group to check
435      */
436     void checkCreateGroupConstraints(const std::string& groupName);
437 
438     /** @brief checks if the group deletion meets all constraints
439      * @param groupName - group to check
440      */
441     void checkDeleteGroupConstraints(const std::string& groupName);
442 
443     /** @brief checks if the group name is legal and whether it's allowed to
444      * change. The daemon doesn't allow arbitrary group to be created
445      * @param groupName - group to check
446      */
447     void checkAndThrowForDisallowedGroupCreation(const std::string& groupName);
448 
449   private:
450     /** @brief sdbusplus handler */
451     sdbusplus::bus_t& bus;
452 
453     /** @brief object path */
454     const std::string path;
455 
456     /** @brief serializer for mfa */
457     JsonSerializer serializer;
458     /** @brief privilege manager container */
459     const std::vector<std::string> privMgr = {"priv-admin", "priv-operator",
460                                               "priv-user"};
461 
462     /** @brief groups manager container */
463     std::vector<std::string> groupsMgr;
464 
465     /** @brief map container to hold users object */
466 
467     std::unordered_map<std::string, std::unique_ptr<phosphor::user::Users>>
468         usersList;
469 
470     /** @brief get users in group
471      *  method to get group user list
472      *
473      *  @param[in] groupName - group name
474      *
475      *  @return userList  - list of users in the group.
476      */
477     std::vector<std::string> getUsersInGroup(const std::string& groupName);
478 
479     /** @brief get user & SSH users list
480      *  method to get the users and ssh users list.
481      *
482      *@return - vector of User & SSH user lists
483      */
484     UserSSHLists getUserAndSshGrpList(void);
485 
486     /** @brief initialize the user manager objects
487      *  method to initialize the user manager objects accordingly
488      *
489      */
490     void initUserObjects(void);
491 
492     /** @brief get service name
493      *  method to get dbus service name
494      *
495      *  @param[in] path - object path
496      *  @param[in] intf - interface
497      *  @return - service name
498      */
499     std::string getServiceName(std::string&& path, std::string&& intf);
500 
501     /** @brief get primary group ID of specified user
502      *
503      * @param[in] - userName
504      * @return - primary group ID
505      */
506     virtual gid_t getPrimaryGroup(const std::string& userName) const;
507 
508     /** @brief check whether if the user is a member of the group
509      *
510      * @param[in] - userName
511      * @param[in] - ID of the user's primary group
512      * @param[in] - groupName
513      * @return - true if the user is a member of the group
514      */
515     virtual bool isGroupMember(const std::string& userName, gid_t primaryGid,
516                                const std::string& groupName) const;
517 
518   protected:
519     /** @brief get privilege mapper object
520      *  method to get dbus privilege mapper object
521      *
522      *  @return - map of user object
523      */
524     virtual DbusUserObj getPrivilegeMapperObject(void);
525 
526     friend class TestUserMgr;
527 
528     std::string faillockConfigFile;
529     std::string pwHistoryConfigFile;
530     std::string pwQualityConfigFile;
531 };
532 
533 } // namespace user
534 } // namespace phosphor
535