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