mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-05-03 07:41:30 -07:00
User module - Check local database when local is specified in the task (#51088)
The output of pw.getpwnam() does not distinbuish between local and remote accounts. It will return a result if an account exists locally or in the directory. When local is set to True in the task parameters, look through the local password database explicitly. * Ensure luseradd is present for tests * Add docs and warnings about local mode
This commit is contained in:
parent
43a44e6f35
commit
1e595493d9
3 changed files with 118 additions and 7 deletions
|
@ -206,7 +206,9 @@ options:
|
|||
- Forces the use of "local" command alternatives on platforms that implement it.
|
||||
- This is useful in environments that use centralized authentification when you want to manipulate the local users
|
||||
(i.e. it uses C(luseradd) instead of C(useradd)).
|
||||
- This requires that these commands exist on the targeted host, otherwise it will be a fatal error.
|
||||
- This will check C(/etc/passwd) for an existing account before invoking commands. If the local account database
|
||||
exists somewhere other than C(/etc/passwd), this setting will not work properly.
|
||||
- This requires that the above commands as well as C(/etc/passwd) must exist on the target host, otherwise it will be a fatal error.
|
||||
type: bool
|
||||
default: no
|
||||
version_added: "2.4"
|
||||
|
@ -446,6 +448,7 @@ class User(object):
|
|||
|
||||
platform = 'Generic'
|
||||
distribution = None
|
||||
PASSWORDFILE = '/etc/passwd'
|
||||
SHADOWFILE = '/etc/shadow'
|
||||
SHADOWFILE_EXPIRE_INDEX = 7
|
||||
LOGIN_DEFS = '/etc/login.defs'
|
||||
|
@ -840,11 +843,35 @@ class User(object):
|
|||
return groups
|
||||
|
||||
def user_exists(self):
|
||||
try:
|
||||
if pwd.getpwnam(self.name):
|
||||
return True
|
||||
except KeyError:
|
||||
return False
|
||||
# The pwd module does not distinguish between local and directory accounts.
|
||||
# It's output cannot be used to determine whether or not an account exists locally.
|
||||
# It returns True if the account exists locally or in the directory, so instead
|
||||
# look in the local PASSWORD file for an existing account.
|
||||
if self.local:
|
||||
if not os.path.exists(self.PASSWORDFILE):
|
||||
self.module.fail_json(msg="'local: true' specified but unable to find local account file {0} to parse.".format(self.PASSWORDFILE))
|
||||
|
||||
exists = False
|
||||
name_test = '{0}:'.format(self.name)
|
||||
with open(self.PASSWORDFILE, 'rb') as f:
|
||||
reversed_lines = f.readlines()[::-1]
|
||||
for line in reversed_lines:
|
||||
if line.startswith(to_bytes(name_test)):
|
||||
exists = True
|
||||
break
|
||||
|
||||
self.module.warn(
|
||||
"'local: true' specified and user was not found in {file}. "
|
||||
"The local user account may already exist if the local account database exists somewhere other than {file}.".format(file=self.PASSWORDFILE))
|
||||
|
||||
return exists
|
||||
|
||||
else:
|
||||
try:
|
||||
if pwd.getpwnam(self.name):
|
||||
return True
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
def get_pwd_info(self):
|
||||
if not self.user_exists():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue