diff --git a/changelogs/fragments/73821-user-add_umask_option.yaml b/changelogs/fragments/73821-user-add_umask_option.yaml new file mode 100644 index 00000000000..46364bae308 --- /dev/null +++ b/changelogs/fragments/73821-user-add_umask_option.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - user - Add ``umask`` option (https://github.com/ansible/ansible/issues/40359). diff --git a/lib/ansible/modules/user.py b/lib/ansible/modules/user.py index 71aa448b80b..9818f959f8c 100644 --- a/lib/ansible/modules/user.py +++ b/lib/ansible/modules/user.py @@ -250,6 +250,14 @@ options: - Supported on Linux only. type: int 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: - There are specific requirements per platform on user management utilities. However @@ -529,6 +537,10 @@ class User(object): self.role = module.params['role'] self.password_expire_max = module.params['password_expire_max'] 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: self.groups = ','.join(module.params['groups']) @@ -708,6 +720,10 @@ class User(object): if self.skeleton is not None: cmd.append('-k') cmd.append(self.skeleton) + + if self.umask is not None: + cmd.append('-K') + cmd.append('UMASK=' + self.umask) else: cmd.append('-M') @@ -1357,6 +1373,10 @@ class FreeBsdUser(User): cmd.append('-k') cmd.append(self.skeleton) + if self.umask is not None: + cmd.append('-K') + cmd.append('UMASK=' + self.umask) + if self.shell is not None: cmd.append('-s') cmd.append(self.shell) @@ -1434,6 +1454,10 @@ class FreeBsdUser(User): cmd.append('-k') 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 not self.group_exists(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(self.skeleton) + if self.umask is not None: + cmd.append('-K') + cmd.append('UMASK=' + self.umask) + cmd.append(self.name) return self.execute_command(cmd) @@ -1786,6 +1814,10 @@ class NetBSDUser(User): cmd.append('-k') cmd.append(self.skeleton) + if self.umask is not None: + cmd.append('-K') + cmd.append('UMASK=' + self.umask) + cmd.append(self.name) return self.execute_command(cmd) @@ -1971,6 +2003,10 @@ class SunOS(User): cmd.append('-k') cmd.append(self.skeleton) + if self.umask is not None: + cmd.append('-K') + cmd.append('UMASK=' + self.umask) + if self.profile is not None: cmd.append('-P') cmd.append(self.profile) @@ -2576,6 +2612,10 @@ class AIX(User): cmd.append('-k') cmd.append(self.skeleton) + if self.umask is not None: + cmd.append('-K') + cmd.append('UMASK=' + self.umask) + cmd.append(self.name) (rc, out, err) = self.execute_command(cmd) @@ -2901,6 +2941,10 @@ class BusyBox(User): cmd.append('-k') cmd.append(self.skeleton) + if self.umask is not None: + cmd.append('-K') + cmd.append('UMASK=' + self.umask) + if self.system: cmd.append('-S') @@ -3046,6 +3090,7 @@ def main(): profile=dict(type='str'), authorization=dict(type='str'), role=dict(type='str'), + umask=dict(type='str'), ), supports_check_mode=True, ) diff --git a/test/integration/targets/user/tasks/main.yml b/test/integration/targets/user/tasks/main.yml index d3bae05644f..5e1d2d220d8 100644 --- a/test/integration/targets/user/tasks/main.yml +++ b/test/integration/targets/user/tasks/main.yml @@ -37,3 +37,5 @@ - import_tasks: test_password_lock.yml - import_tasks: test_password_lock_new_user.yml - import_tasks: test_local.yml +- import_tasks: test_umask.yml + when: ansible_facts.system == 'Linux' diff --git a/test/integration/targets/user/tasks/test_umask.yml b/test/integration/targets/user/tasks/test_umask.yml new file mode 100644 index 00000000000..9e16297617e --- /dev/null +++ b/test/integration/targets/user/tasks/test_umask.yml @@ -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