user - consistently create user home directory on Linux ()

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  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
changelogs/fragments
lib/ansible/modules
test/integration/targets/user

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