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