Add umask option to user module (#73821)

* Add umask option to user module

* Fail on setting both umask and local: True

* Add integration test

* Add changelog

* Run integration tests only if HOME_MODE is not set

* Run integration tests only on Linux

Co-authored-by: Matt Clay <matt@mystile.com>
This commit is contained in:
Amin Vakil 2021-04-20 20:31:56 +04:30 committed by GitHub
parent 5f391a72ee
commit 49d4442378
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 0 deletions

View file

@ -0,0 +1,3 @@
---
minor_changes:
- user - Add ``umask`` option (https://github.com/ansible/ansible/issues/40359).

View file

@ -250,6 +250,14 @@ options:
- Supported on Linux only. - Supported on Linux only.
type: int type: int
version_added: "2.11" version_added: "2.11"
umask:
description:
- Sets the umask of the user.
- Does nothing when used with other platforms.
- Currently supported on Linux.
- Requires C(local) is omitted or False.
type: str
version_added: "2.12"
notes: notes:
- There are specific requirements per platform on user management utilities. However - There are specific requirements per platform on user management utilities. However
@ -529,6 +537,10 @@ class User(object):
self.role = module.params['role'] self.role = module.params['role']
self.password_expire_max = module.params['password_expire_max'] self.password_expire_max = module.params['password_expire_max']
self.password_expire_min = module.params['password_expire_min'] self.password_expire_min = module.params['password_expire_min']
self.umask = module.params['umask']
if self.umask is not None and self.local:
module.fail_json(msg="'umask' can not be used with 'local'")
if module.params['groups'] is not None: if module.params['groups'] is not None:
self.groups = ','.join(module.params['groups']) self.groups = ','.join(module.params['groups'])
@ -708,6 +720,10 @@ class User(object):
if self.skeleton is not None: if self.skeleton is not None:
cmd.append('-k') cmd.append('-k')
cmd.append(self.skeleton) cmd.append(self.skeleton)
if self.umask is not None:
cmd.append('-K')
cmd.append('UMASK=' + self.umask)
else: else:
cmd.append('-M') cmd.append('-M')
@ -1357,6 +1373,10 @@ class FreeBsdUser(User):
cmd.append('-k') cmd.append('-k')
cmd.append(self.skeleton) cmd.append(self.skeleton)
if self.umask is not None:
cmd.append('-K')
cmd.append('UMASK=' + self.umask)
if self.shell is not None: if self.shell is not None:
cmd.append('-s') cmd.append('-s')
cmd.append(self.shell) cmd.append(self.shell)
@ -1434,6 +1454,10 @@ class FreeBsdUser(User):
cmd.append('-k') cmd.append('-k')
cmd.append(self.skeleton) cmd.append(self.skeleton)
if self.umask is not None:
cmd.append('-K')
cmd.append('UMASK=' + self.umask)
if self.group is not None: if self.group is not None:
if not self.group_exists(self.group): if not self.group_exists(self.group):
self.module.fail_json(msg="Group %s does not exist" % self.group) self.module.fail_json(msg="Group %s does not exist" % self.group)
@ -1613,6 +1637,10 @@ class OpenBSDUser(User):
cmd.append('-k') cmd.append('-k')
cmd.append(self.skeleton) cmd.append(self.skeleton)
if self.umask is not None:
cmd.append('-K')
cmd.append('UMASK=' + self.umask)
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -1786,6 +1814,10 @@ class NetBSDUser(User):
cmd.append('-k') cmd.append('-k')
cmd.append(self.skeleton) cmd.append(self.skeleton)
if self.umask is not None:
cmd.append('-K')
cmd.append('UMASK=' + self.umask)
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -1971,6 +2003,10 @@ class SunOS(User):
cmd.append('-k') cmd.append('-k')
cmd.append(self.skeleton) cmd.append(self.skeleton)
if self.umask is not None:
cmd.append('-K')
cmd.append('UMASK=' + self.umask)
if self.profile is not None: if self.profile is not None:
cmd.append('-P') cmd.append('-P')
cmd.append(self.profile) cmd.append(self.profile)
@ -2576,6 +2612,10 @@ class AIX(User):
cmd.append('-k') cmd.append('-k')
cmd.append(self.skeleton) cmd.append(self.skeleton)
if self.umask is not None:
cmd.append('-K')
cmd.append('UMASK=' + self.umask)
cmd.append(self.name) cmd.append(self.name)
(rc, out, err) = self.execute_command(cmd) (rc, out, err) = self.execute_command(cmd)
@ -2901,6 +2941,10 @@ class BusyBox(User):
cmd.append('-k') cmd.append('-k')
cmd.append(self.skeleton) cmd.append(self.skeleton)
if self.umask is not None:
cmd.append('-K')
cmd.append('UMASK=' + self.umask)
if self.system: if self.system:
cmd.append('-S') cmd.append('-S')
@ -3046,6 +3090,7 @@ def main():
profile=dict(type='str'), profile=dict(type='str'),
authorization=dict(type='str'), authorization=dict(type='str'),
role=dict(type='str'), role=dict(type='str'),
umask=dict(type='str'),
), ),
supports_check_mode=True, supports_check_mode=True,
) )

View file

@ -37,3 +37,5 @@
- import_tasks: test_password_lock.yml - import_tasks: test_password_lock.yml
- import_tasks: test_password_lock_new_user.yml - import_tasks: test_password_lock_new_user.yml
- import_tasks: test_local.yml - import_tasks: test_local.yml
- import_tasks: test_umask.yml
when: ansible_facts.system == 'Linux'

View file

@ -0,0 +1,57 @@
---
- name: remove comments of /etc/login.defs
command: sed -e '/^[ \t]*#/d' /etc/login.defs
register: logindefs
- block:
- name: Create user with 000 umask
user:
name: umaskuser_test_1
umask: "000"
register: umaskuser_test_1
- name: Create user with 077 umask
user:
name: umaskuser_test_2
umask: "077"
register: umaskuser_test_2
- name: check permissions on created home folder
stat:
path: "{{ user_home_prefix[ansible_facts.system] }}/umaskuser_test_1"
register: umaskuser_test_1_path
- name: check permissions on created home folder
stat:
path: "{{ user_home_prefix[ansible_facts.system] }}/umaskuser_test_2"
register: umaskuser_test_2_path
- name: remove created users
user:
name: "{{ item }}"
state: absent
register: umaskuser_test_remove
loop:
- umaskuser_test_1
- umaskuser_test_2
- name: Ensure correct umask has been set on created users
assert:
that:
- umaskuser_test_1_path.stat.mode == "0777"
- umaskuser_test_2_path.stat.mode == "0700"
- umaskuser_test_remove is changed
when: logindefs.stdout_lines is not search ("HOME_MODE")
- name: Create user with setting both umask and local
user:
name: umaskuser_test_3
umask: "077"
local: true
register: umaskuser_test_3
ignore_errors: true
- name: Ensure task has been failed
assert:
that:
- umaskuser_test_3 is failed