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