Handles FileNotFoundError exception in shadow.info

Musl libc getspnam implementation returns ENOENT when user is not found
Changing the linux_shadow.info to deal with FileNotFoundError, allowing
the user.present state to work in musl based systems, like the Alpine
Linux.
This commit is contained in:
piterpunk 2021-03-11 01:28:33 -03:00 committed by Gareth J. Greenaway
parent 1f74210c03
commit 0f777f5221
3 changed files with 56 additions and 11 deletions

1
changelog/50979.fixed Normal file
View file

@ -0,0 +1 @@
Allow user.present to work on Alpine Linux by fixing linux_shadow.info

View file

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Manage the shadow file on Linux systems
@ -8,21 +7,16 @@ Manage the shadow file on Linux systems
*'shadow.info' is not available*), see :ref:`here
<module-provider-override>`.
"""
from __future__ import absolute_import, print_function, unicode_literals
import datetime
import functools
import logging
# Import python libs
import os
# Import salt libs
import salt.utils.data
import salt.utils.files
import salt.utils.stringutils
from salt.exceptions import CommandExecutionError
from salt.ext import six
from salt.ext.six.moves import range
try:
@ -93,7 +87,7 @@ def info(name, root=None):
"inact": data.sp_inact,
"expire": data.sp_expire,
}
except KeyError:
except (KeyError, FileNotFoundError):
return {
"name": "",
"passwd": "",
@ -385,7 +379,7 @@ def set_password(name, password, use_usermod=False, root=None):
# ALT Linux uses tcb to store password hashes. More information found
# in manpage (http://docs.altlinux.org/manpages/tcb.5.html)
if __grains__["os"] == "ALT":
s_file = "/etc/tcb/{0}/shadow".format(name)
s_file = "/etc/tcb/{}/shadow".format(name)
else:
s_file = "/etc/shadow"
if root:
@ -396,9 +390,7 @@ def set_password(name, password, use_usermod=False, root=None):
return ret
lines = []
user_found = False
lstchg = six.text_type(
(datetime.datetime.today() - datetime.datetime(1970, 1, 1)).days
)
lstchg = str((datetime.datetime.today() - datetime.datetime(1970, 1, 1)).days)
with salt.utils.files.fopen(s_file, "rb") as fp_:
for line in fp_:
line = salt.utils.stringutils.to_unicode(line)

View file

@ -2,6 +2,7 @@
:codeauthor: Erik Johnson <erik@saltstack.com>
"""
import spwd
import textwrap
import pytest
@ -143,6 +144,57 @@ class LinuxShadowTest(TestCase, LoaderModuleMockMixin):
# Make sure we wrote the correct info
assert filehandles[1].write_calls[0].split(":")[:2] == [user, password]
def test_info(self):
"""
Test if info shows the correct user information
"""
# First test is with a succesful call
expected_result = [
("expire", -1),
("inact", -1),
("lstchg", 31337),
("max", 99999),
("min", 0),
("name", "foo"),
("passwd", _HASHES["sha512"]["pw_hash"]),
("warn", 7),
]
getspnam_return = spwd.struct_spwd(
["foo", _HASHES["sha512"]["pw_hash"], 31337, 0, 99999, 7, -1, -1, -1]
)
with patch("spwd.getspnam", return_value=getspnam_return):
result = shadow.info("foo")
self.assertEqual(
expected_result, sorted(result.items(), key=lambda x: x[0])
)
# The next two is for a non-existent user
expected_result = [
("expire", ""),
("inact", ""),
("lstchg", ""),
("max", ""),
("min", ""),
("name", ""),
("passwd", ""),
("warn", ""),
]
# We get KeyError exception for non-existent users in glibc based systems
getspnam_return = KeyError
with patch("spwd.getspnam", side_effect=getspnam_return):
result = shadow.info("foo")
self.assertEqual(
expected_result, sorted(result.items(), key=lambda x: x[0])
)
# And FileNotFoundError in musl based systems
getspnam_return = FileNotFoundError
with patch("spwd.getspnam", side_effect=getspnam_return):
result = shadow.info("foo")
self.assertEqual(
expected_result, sorted(result.items(), key=lambda x: x[0])
)
@pytest.mark.skip_if_not_root
def test_list_users(self):
"""