Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/67119.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove usage of spwd
30 changes: 20 additions & 10 deletions salt/modules/linux_shadow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<module-provider-override>`.
"""

import collections
import datetime
import functools
import logging
Expand All @@ -17,12 +18,6 @@
import salt.utils.files
from salt.exceptions import CommandExecutionError

try:
import spwd
except ImportError:
pass


try:
import salt.utils.pycrypto

Expand All @@ -34,6 +29,21 @@

log = logging.getLogger(__name__)

struct_spwd = collections.namedtuple(
"struct_spwd",
[
"sp_namp",
"sp_pwdp",
"sp_lstchg",
"sp_min",
"sp_max",
"sp_warn",
"sp_inact",
"sp_expire",
"sp_flag",
],
)


def __virtual__():
return __virtualname__ if __grains__.get("kernel", "") == "Linux" else False
Expand Down Expand Up @@ -71,7 +81,7 @@ def info(name, root=None):
if root is not None:
getspnam = functools.partial(_getspnam, root=root)
else:
getspnam = functools.partial(spwd.getspnam)
getspnam = functools.partial(_getspnam, root="/")

try:
data = getspnam(name)
Expand Down Expand Up @@ -509,7 +519,7 @@ def list_users(root=None):
if root is not None:
getspall = functools.partial(_getspall, root=root)
else:
getspall = functools.partial(spwd.getspall)
getspall = functools.partial(_getspall, root="/")

return sorted(
user.sp_namp if hasattr(user, "sp_namp") else user.sp_nam for user in getspall()
Expand All @@ -529,7 +539,7 @@ def _getspnam(name, root=None):
# Generate a getspnam compatible output
for i in range(2, 9):
comps[i] = int(comps[i]) if comps[i] else -1
return spwd.struct_spwd(comps)
return struct_spwd(*comps)
raise KeyError


Expand All @@ -545,4 +555,4 @@ def _getspall(root=None):
# Generate a getspall compatible output
for i in range(2, 9):
comps[i] = int(comps[i]) if comps[i] else -1
yield spwd.struct_spwd(comps)
yield struct_spwd(*comps)
23 changes: 9 additions & 14 deletions tests/pytests/unit/modules/test_linux_shadow.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
:codeauthor: Erik Johnson <[email protected]>
:codeauthor: Erik Johnson <[email protected]>
"""

import types
Expand Down Expand Up @@ -175,6 +175,11 @@ def test_info(password):
Test if info shows the correct user information
"""

data = {
"/etc/shadow": f"foo:{password.pw_hash}:31337:0:99999:7:::",
"*": Exception("Attempted to open something other than /etc/shadow"),
}

# First test is with a succesful call
expected_result = [
("expire", -1),
Expand All @@ -186,10 +191,7 @@ def test_info(password):
("passwd", password.pw_hash),
("warn", 7),
]
getspnam_return = spwd.struct_spwd(
["foo", password.pw_hash, 31337, 0, 99999, 7, -1, -1, -1]
)
with patch("spwd.getspnam", return_value=getspnam_return):
with patch("salt.utils.files.fopen", mock_open(read_data=data)):
result = shadow.info("foo")
assert expected_result == sorted(result.items(), key=lambda x: x[0])

Expand All @@ -204,15 +206,8 @@ def test_info(password):
("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")
assert 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")
with patch("salt.utils.files.fopen", mock_open(read_data=data)):
result = shadow.info("bar")
assert expected_result == sorted(result.items(), key=lambda x: x[0])


Expand Down
Loading