diff options
author | Strahinja Kustudic <kustodian@gmail.com> | 2019-01-14 22:01:26 +0100 |
---|---|---|
committer | ansibot <ansibot@users.noreply.github.com> | 2019-01-14 16:01:26 -0500 |
commit | eb8294e6d98b0ab7db587be3c8e99a51da6e245d (patch) | |
tree | 39091985ad5d26341ab2a15b6f0550ac50214dbb /lib/ansible/modules/system/user.py | |
parent | 37960ccc87fb3711893d986e6d512920e095044f (diff) | |
download | ansible-eb8294e6d98b0ab7db587be3c8e99a51da6e245d.tar.gz |
Fix create home dir fallback (#49262)
When a user home dir is not created with `useradd`, the home dir will now
be created with umask from /etc/login.defs. Also fixed a bug in which
after a local user is deleted, and the same user exists in the central
user management system, the module would create that user's home.
Diffstat (limited to 'lib/ansible/modules/system/user.py')
-rw-r--r-- | lib/ansible/modules/system/user.py | 171 |
1 files changed, 95 insertions, 76 deletions
diff --git a/lib/ansible/modules/system/user.py b/lib/ansible/modules/system/user.py index d7d52e7a80..03a7ce5be6 100644 --- a/lib/ansible/modules/system/user.py +++ b/lib/ansible/modules/system/user.py @@ -421,6 +421,7 @@ class User(object): distribution = None SHADOWFILE = '/etc/shadow' SHADOWFILE_EXPIRE_INDEX = 7 + LOGIN_DEFS = '/etc/login.defs' DATE_FORMAT = '%Y-%m-%d' def __new__(cls, *args, **kwargs): @@ -854,10 +855,11 @@ class User(object): elif self.SHADOWFILE: # Read shadow file for user's encrypted password string if os.path.exists(self.SHADOWFILE) and os.access(self.SHADOWFILE, os.R_OK): - for line in open(self.SHADOWFILE).readlines(): - if line.startswith('%s:' % self.name): - passwd = line.split(':')[1] - expires = line.split(':')[self.SHADOWFILE_EXPIRE_INDEX] or -1 + with open(self.SHADOWFILE, 'r') as f: + for line in f: + if line.startswith('%s:' % self.name): + passwd = line.split(':')[1] + expires = line.split(':')[self.SHADOWFILE_EXPIRE_INDEX] or -1 return passwd, expires def get_ssh_key_path(self): @@ -970,9 +972,8 @@ class User(object): def get_ssh_public_key(self): ssh_public_key_file = '%s.pub' % self.get_ssh_key_path() try: - f = open(ssh_public_key_file) - ssh_public_key = f.read().strip() - f.close() + with open(ssh_public_key_file, 'r') as f: + ssh_public_key = f.read().strip() except IOError: return None return ssh_public_key @@ -1001,11 +1002,23 @@ class User(object): shutil.copytree(skeleton, path, symlinks=True) except OSError as e: self.module.exit_json(failed=True, msg="%s" % to_native(e)) - else: - try: - os.makedirs(path) - except OSError as e: - self.module.exit_json(failed=True, msg="%s" % to_native(e)) + else: + try: + os.makedirs(path) + except OSError as e: + self.module.exit_json(failed=True, msg="%s" % to_native(e)) + # get umask from /etc/login.defs and set correct home mode + if os.path.exists(self.LOGIN_DEFS): + with open(self.LOGIN_DEFS, 'r') as f: + for line in f: + m = re.match(r'^UMASK\s+(\d+)$', line) + if m: + umask = int(m.group(1), 8) + mode = 0o777 & ~umask + try: + os.chmod(path, mode) + except OSError as e: + self.module.exit_json(failed=True, msg="%s" % to_native(e)) def chown_homedir(self, uid, gid, path): try: @@ -1173,9 +1186,10 @@ class FreeBsdUser(User): # find current login class user_login_class = None if os.path.exists(self.SHADOWFILE) and os.access(self.SHADOWFILE, os.R_OK): - for line in open(self.SHADOWFILE).readlines(): - if line.startswith('%s:' % self.name): - user_login_class = line.split(':')[4] + with open(self.SHADOWFILE, 'r') as f: + for line in f: + if line.startswith('%s:' % self.name): + user_login_class = line.split(':')[4] # act only if login_class change if self.login_class != user_login_class: @@ -1632,20 +1646,21 @@ class SunOS(User): minweeks = '' maxweeks = '' warnweeks = '' - for line in open("/etc/default/passwd", 'r'): - line = line.strip() - if (line.startswith('#') or line == ''): - continue - m = re.match(r'^([^#]*)#(.*)$', line) - if m: # The line contains a hash / comment - line = m.group(1) - key, value = line.split('=') - if key == "MINWEEKS": - minweeks = value.rstrip('\n') - elif key == "MAXWEEKS": - maxweeks = value.rstrip('\n') - elif key == "WARNWEEKS": - warnweeks = value.rstrip('\n') + with open("/etc/default/passwd", 'r') as f: + for line in f: + line = line.strip() + if (line.startswith('#') or line == ''): + continue + m = re.match(r'^([^#]*)#(.*)$', line) + if m: # The line contains a hash / comment + line = m.group(1) + key, value = line.split('=') + if key == "MINWEEKS": + minweeks = value.rstrip('\n') + elif key == "MAXWEEKS": + maxweeks = value.rstrip('\n') + elif key == "WARNWEEKS": + warnweeks = value.rstrip('\n') except Exception as err: self.module.fail_json(msg="failed to read /etc/default/passwd: %s" % to_native(err)) @@ -1724,35 +1739,37 @@ class SunOS(User): minweeks, maxweeks, warnweeks = self.get_password_defaults() try: lines = [] - for line in open(self.SHADOWFILE, 'rb').readlines(): - line = to_native(line, errors='surrogate_or_strict') - fields = line.strip().split(':') - if not fields[0] == self.name: - lines.append(line) - continue - fields[1] = self.password - fields[2] = str(int(time.time() // 86400)) - if minweeks: - try: - fields[3] = str(int(minweeks) * 7) - except ValueError: - # mirror solaris, which allows for any value in this field, and ignores anything that is not an int. - pass - if maxweeks: - try: - fields[4] = str(int(maxweeks) * 7) - except ValueError: - # mirror solaris, which allows for any value in this field, and ignores anything that is not an int. - pass - if warnweeks: - try: - fields[5] = str(int(warnweeks) * 7) - except ValueError: - # mirror solaris, which allows for any value in this field, and ignores anything that is not an int. - pass - line = ':'.join(fields) - lines.append('%s\n' % line) - open(self.SHADOWFILE, 'w+').writelines(lines) + with open(self.SHADOWFILE, 'rb') as f: + for line in f: + line = to_native(line, errors='surrogate_or_strict') + fields = line.strip().split(':') + if not fields[0] == self.name: + lines.append(line) + continue + fields[1] = self.password + fields[2] = str(int(time.time() // 86400)) + if minweeks: + try: + fields[3] = str(int(minweeks) * 7) + except ValueError: + # mirror solaris, which allows for any value in this field, and ignores anything that is not an int. + pass + if maxweeks: + try: + fields[4] = str(int(maxweeks) * 7) + except ValueError: + # mirror solaris, which allows for any value in this field, and ignores anything that is not an int. + pass + if warnweeks: + try: + fields[5] = str(int(warnweeks) * 7) + except ValueError: + # mirror solaris, which allows for any value in this field, and ignores anything that is not an int. + pass + line = ':'.join(fields) + lines.append('%s\n' % line) + with open(self.SHADOWFILE, 'w+') as f: + f.writelines(lines) except Exception as err: self.module.fail_json(msg="failed to update users password: %s" % to_native(err)) @@ -1843,23 +1860,25 @@ class SunOS(User): minweeks, maxweeks, warnweeks = self.get_password_defaults() try: lines = [] - for line in open(self.SHADOWFILE, 'rb').readlines(): - line = to_native(line, errors='surrogate_or_strict') - fields = line.strip().split(':') - if not fields[0] == self.name: - lines.append(line) - continue - fields[1] = self.password - fields[2] = str(int(time.time() // 86400)) - if minweeks: - fields[3] = str(int(minweeks) * 7) - if maxweeks: - fields[4] = str(int(maxweeks) * 7) - if warnweeks: - fields[5] = str(int(warnweeks) * 7) - line = ':'.join(fields) - lines.append('%s\n' % line) - open(self.SHADOWFILE, 'w+').writelines(lines) + with open(self.SHADOWFILE, 'rb') as f: + for line in f: + line = to_native(line, errors='surrogate_or_strict') + fields = line.strip().split(':') + if not fields[0] == self.name: + lines.append(line) + continue + fields[1] = self.password + fields[2] = str(int(time.time() // 86400)) + if minweeks: + fields[3] = str(int(minweeks) * 7) + if maxweeks: + fields[4] = str(int(maxweeks) * 7) + if warnweeks: + fields[5] = str(int(warnweeks) * 7) + line = ':'.join(fields) + lines.append('%s\n' % line) + with open(self.SHADOWFILE, 'w+'): + f.writelines(lines) rc = 0 except Exception as err: self.module.fail_json(msg="failed to update users password: %s" % to_native(err)) @@ -2638,7 +2657,7 @@ def main(): if err: result['stderr'] = err - if user.user_exists(): + if user.user_exists() and user.state == 'present': info = user.user_info() if info is False: result['msg'] = "failed to look up user name: %s" % user.name |