user - consistently create user home directory on Linux (#71952)

Always use create_homedir when we are asked to create a home directory
in the User class. Don't use the -m and -k parameters from
useradd / luseradd as they behave differently with respect to
preexisting home directories. Instead always specify -M to ensure
that useradd / luseradd do not try to create the home directory.

This does not change potential different behaviours in child classes
of the User class.

Consider the new umask option from #73821 in create_homedir as well as
we do not let luseradd / useradd create the home directory any longer.
This commit is contained in:
Ruediger Pluem 2021-05-07 23:00:10 +02:00 committed by GitHub
parent 2e97240c67
commit 2f7e0b8489
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 31 deletions

View file

@ -0,0 +1,4 @@
bugfixes:
- >-
user - properly create home path on Linux when ``local: yes`` and parent directories
specified in ``home`` do not exist (https://github.com/ansible/ansible/pull/71952/)

View file

@ -685,13 +685,8 @@ class User(object):
cmd.append(self.comment)
if self.home is not None:
# If the specified path to the user home contains parent directories that
# do not exist and create_home is True first create the parent directory
# since useradd cannot create it.
if self.create_home:
parent = os.path.dirname(self.home)
if not os.path.isdir(parent):
self.create_homedir(self.home)
self.create_homedir(self.home)
cmd.append('-d')
cmd.append(self.home)
@ -713,19 +708,7 @@ class User(object):
else:
cmd.append(self.password)
if self.create_home:
if not self.local:
cmd.append('-m')
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')
cmd.append('-M')
if self.system:
cmd.append('-r')
@ -1250,18 +1233,26 @@ class User(object):
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))
umask_string = None
# If an umask was set take it from there
if self.umask is not None:
umask_string = self.umask
else:
# try to get umask from /etc/login.defs
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_string = m.group(1)
# set correct home mode if we have a umask
if umask_string is not None:
umask = int(umask_string, 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:

View file

@ -167,3 +167,6 @@
- name: Test expires for local users
import_tasks: test_local_expires.yml
- name: Test missing home directory parent directory for local users
import_tasks: test_local_missing_parent_dir.yml

View file

@ -0,0 +1,56 @@
---
# Create a new local user account with a path that has parent directories that do not exist
- name: Create local user with home path that has parents that do not exist
user:
name: ansibulluser2
state: present
local: yes
home: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/ansibulluser2"
register: create_home_local_with_no_parent_1
tags:
- user_test_local_mode
- name: Create local user with home path that has parents that do not exist again
user:
name: ansibulluser2
state: present
local: yes
home: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/ansibulluser2"
register: create_home_local_with_no_parent_2
tags:
- user_test_local_mode
- name: Check the created home directory
stat:
path: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/ansibulluser2"
register: home_local_with_no_parent_3
tags:
- user_test_local_mode
- name: Ensure user with non-existing parent paths was created successfully
assert:
that:
- create_home_local_with_no_parent_1 is changed
- create_home_local_with_no_parent_1.home == user_home_prefix[ansible_facts.system] ~ '/in2deep/ansibulluser2'
- create_home_local_with_no_parent_2 is not changed
- home_local_with_no_parent_3.stat.uid == create_home_local_with_no_parent_1.uid
- home_local_with_no_parent_3.stat.gr_name == default_local_user_group[ansible_facts.distribution] | default('ansibulluser2')
tags:
- user_test_local_mode
- name: Cleanup test account
user:
name: ansibulluser2
home: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/ansibulluser2"
state: absent
local: yes
remove: yes
tags:
- user_test_local_mode
- name: Remove testing dir
file:
path: "{{ user_home_prefix[ansible_facts.system] }}/in2deep/"
state: absent
tags:
- user_test_local_mode

View file

@ -11,3 +11,6 @@ status_command:
default_user_group:
openSUSE Leap: users
MacOSX: admin
default_local_user_group:
MacOSX: admin