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