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