mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
Fix runas when using the onedir bundled packages
This commit is contained in:
parent
1a57b8ea79
commit
46ac0767fb
5 changed files with 268 additions and 8 deletions
1
changelog/62565.fixed
Normal file
1
changelog/62565.fixed
Normal file
|
@ -0,0 +1 @@
|
|||
Fix runas with cmd module when using the onedir bundled packages
|
|
@ -25,6 +25,7 @@ import salt.utils.data
|
|||
import salt.utils.files
|
||||
import salt.utils.json
|
||||
import salt.utils.path
|
||||
import salt.utils.pkg
|
||||
import salt.utils.platform
|
||||
import salt.utils.powershell
|
||||
import salt.utils.stringutils
|
||||
|
@ -509,30 +510,51 @@ def _run(
|
|||
env_cmd.extend(["-s", "--", shell, "-c"])
|
||||
else:
|
||||
env_cmd.extend(["-i", "--"])
|
||||
env_cmd.extend([sys.executable])
|
||||
elif __grains__["os"] in ["FreeBSD"]:
|
||||
env_cmd = (
|
||||
env_cmd = [
|
||||
"su",
|
||||
"-",
|
||||
runas,
|
||||
"-c",
|
||||
"{} -c {}".format(shell, sys.executable),
|
||||
)
|
||||
]
|
||||
elif __grains__["os_family"] in ["Solaris"]:
|
||||
env_cmd = ("su", "-", runas, "-c", sys.executable)
|
||||
env_cmd = ["su", "-", runas, "-c"]
|
||||
elif __grains__["os_family"] in ["AIX"]:
|
||||
env_cmd = ("su", "-", runas, "-c", sys.executable)
|
||||
env_cmd = ["su", "-", runas, "-c"]
|
||||
else:
|
||||
env_cmd = ("su", "-s", shell, "-", runas, "-c", sys.executable)
|
||||
env_cmd = ["su", "-s", shell, "-", runas, "-c"]
|
||||
|
||||
if not salt.utils.pkg.check_bundled():
|
||||
if __grains__["os"] in ["FreeBSD"]:
|
||||
env_cmd.extend(["{} -c {}".format(shell, sys.executable)])
|
||||
else:
|
||||
env_cmd.extend([sys.executable])
|
||||
else:
|
||||
with tempfile.NamedTemporaryFile("w", delete=False) as fp:
|
||||
if __grains__["os"] in ["FreeBSD"]:
|
||||
env_cmd.extend(
|
||||
[
|
||||
"{} -c {} python {}".format(
|
||||
shell, sys.executable, fp.name
|
||||
)
|
||||
]
|
||||
)
|
||||
else:
|
||||
env_cmd.extend(["{} python {}".format(sys.executable, fp.name)])
|
||||
fp.write(py_code)
|
||||
fp.seek(0)
|
||||
shutil.chown(fp.name, runas)
|
||||
|
||||
msg = "env command: {}".format(env_cmd)
|
||||
log.debug(log_callback(msg))
|
||||
|
||||
env_bytes, env_encoded_err = subprocess.Popen(
|
||||
env_cmd,
|
||||
stderr=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE,
|
||||
).communicate(salt.utils.stringutils.to_bytes(py_code))
|
||||
if salt.utils.pkg.check_bundled():
|
||||
os.remove(fp.name)
|
||||
marker_count = env_bytes.count(marker_b)
|
||||
if marker_count == 0:
|
||||
# Possibly PAM prevented the login
|
||||
|
|
|
@ -6,6 +6,7 @@ import errno
|
|||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import salt.utils.data
|
||||
import salt.utils.files
|
||||
|
@ -92,3 +93,12 @@ def match_version(desired, available, cmp_func=None, ignore_epoch=False):
|
|||
):
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def check_bundled():
|
||||
"""
|
||||
Gather run-time information to indicate if we are running from source or bundled.
|
||||
"""
|
||||
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
||||
return True
|
||||
return False
|
||||
|
|
25
tests/pytests/functional/modules/cmd/test_runas.py
Normal file
25
tests/pytests/functional/modules/cmd/test_runas.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
import pytest
|
||||
import salt.modules.cmdmod as cmdmod
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def account():
|
||||
with pytest.helpers.create_account(create_group=True) as _account:
|
||||
yield _account
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def configure_loader_modules():
|
||||
return {
|
||||
cmdmod: {
|
||||
"__grains__": {"os": "linux", "os_family": "linux"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.skip_on_windows
|
||||
@pytest.mark.skip_if_not_root
|
||||
def test_run_as(account, caplog):
|
||||
ret = cmdmod.run("id", runas=account.username)
|
||||
assert "gid={}".format(account.info.gid) in ret
|
||||
assert "uid={}".format(account.info.uid) in ret
|
|
@ -844,3 +844,205 @@ def test_cmd_script_saltenv_from_config_windows():
|
|||
assert mock_cp_get_template.call_args[0][3] == "base"
|
||||
assert mock_run.call_count == 2
|
||||
assert mock_run.call_args[1]["saltenv"] == "base"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"test_os,test_family",
|
||||
[
|
||||
("FreeBSD", "FreeBSD"),
|
||||
("linux", "Solaris"),
|
||||
("linux", "AIX"),
|
||||
("linux", "linux"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.skip_on_darwin
|
||||
@pytest.mark.skip_on_windows
|
||||
def test_runas_env_all_os(test_os, test_family):
|
||||
"""
|
||||
cmd.run executes command and the environment is returned
|
||||
when the runas parameter is specified
|
||||
on all different OS types and os_family
|
||||
"""
|
||||
bundled = [False, True]
|
||||
|
||||
for _bundled in bundled:
|
||||
with patch("pwd.getpwnam") as getpwnam_mock:
|
||||
with patch("subprocess.Popen") as popen_mock:
|
||||
popen_mock.return_value = Mock(
|
||||
communicate=lambda *args, **kwags: [b"", None],
|
||||
pid=lambda: 1,
|
||||
retcode=0,
|
||||
)
|
||||
file_name = "/tmp/doesnotexist"
|
||||
|
||||
with patch.dict(
|
||||
cmdmod.__grains__, {"os": test_os, "os_family": test_family}
|
||||
):
|
||||
with patch("salt.utils.pkg.check_bundled", return_value=_bundled):
|
||||
with patch("shutil.chown"):
|
||||
with patch("os.remove"):
|
||||
with patch.object(
|
||||
tempfile, "NamedTemporaryFile"
|
||||
) as mock_fp:
|
||||
mock_fp.return_value.__enter__.return_value.name = (
|
||||
file_name
|
||||
)
|
||||
if sys.platform.startswith(("freebsd", "openbsd")):
|
||||
shell = "/bin/sh"
|
||||
else:
|
||||
shell = "/bin/bash"
|
||||
_user = "foobar"
|
||||
cmdmod._run(
|
||||
"ls",
|
||||
cwd=tempfile.gettempdir(),
|
||||
runas=_user,
|
||||
shell=shell,
|
||||
)
|
||||
if not _bundled:
|
||||
if test_family in ("Solaris", "AIX"):
|
||||
env_cmd = ["su", "-", _user, "-c"]
|
||||
elif test_os == "FreeBSD":
|
||||
env_cmd = ["su", "-", _user, "-c"]
|
||||
else:
|
||||
env_cmd = [
|
||||
"su",
|
||||
"-s",
|
||||
shell,
|
||||
"-",
|
||||
_user,
|
||||
"-c",
|
||||
]
|
||||
if test_os == "FreeBSD":
|
||||
env_cmd.extend(
|
||||
[
|
||||
"{} -c {}".format(
|
||||
shell, sys.executable
|
||||
)
|
||||
]
|
||||
)
|
||||
else:
|
||||
env_cmd.extend([sys.executable])
|
||||
assert (
|
||||
popen_mock.call_args_list[0][0][0]
|
||||
== env_cmd
|
||||
)
|
||||
else:
|
||||
if test_family in ("Solaris", "AIX"):
|
||||
env_cmd = ["su", "-", _user, "-c"]
|
||||
elif test_os == "FreeBSD":
|
||||
env_cmd = ["su", "-", _user, "-c"]
|
||||
else:
|
||||
env_cmd = [
|
||||
"su",
|
||||
"-s",
|
||||
shell,
|
||||
"-",
|
||||
_user,
|
||||
"-c",
|
||||
]
|
||||
if test_os == "FreeBSD":
|
||||
env_cmd.extend(
|
||||
[
|
||||
"{} -c {} python {}".format(
|
||||
shell, sys.executable, file_name
|
||||
)
|
||||
]
|
||||
)
|
||||
else:
|
||||
env_cmd.extend(
|
||||
[
|
||||
"{} python {}".format(
|
||||
sys.executable, file_name
|
||||
)
|
||||
]
|
||||
)
|
||||
assert (
|
||||
popen_mock.call_args_list[0][0][0]
|
||||
== env_cmd
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skip_on_darwin
|
||||
@pytest.mark.skip_on_windows
|
||||
def test_runas_env_sudo_group():
|
||||
"""
|
||||
cmd.run executes command and the environment is returned
|
||||
when the runas parameter is specified
|
||||
when group is passed and use_sudo=True
|
||||
"""
|
||||
bundled = [False, True]
|
||||
|
||||
for _bundled in bundled:
|
||||
|
||||
with patch("pwd.getpwnam") as getpwnam_mock:
|
||||
with patch("subprocess.Popen") as popen_mock:
|
||||
popen_mock.return_value = Mock(
|
||||
communicate=lambda *args, **kwags: [b"", None],
|
||||
pid=lambda: 1,
|
||||
retcode=0,
|
||||
)
|
||||
file_name = "/tmp/doesnotexist"
|
||||
|
||||
with patch.dict(
|
||||
cmdmod.__grains__, {"os": "linux", "os_family": "linux"}
|
||||
):
|
||||
with patch("grp.getgrnam"):
|
||||
with patch(
|
||||
"salt.utils.pkg.check_bundled", return_value=_bundled
|
||||
):
|
||||
with patch("shutil.chown"):
|
||||
with patch("os.remove"):
|
||||
with patch.object(
|
||||
tempfile, "NamedTemporaryFile"
|
||||
) as mock_fp:
|
||||
mock_fp.return_value.__enter__.return_value.name = (
|
||||
file_name
|
||||
)
|
||||
if sys.platform.startswith(
|
||||
("freebsd", "openbsd")
|
||||
):
|
||||
shell = "/bin/sh"
|
||||
else:
|
||||
shell = "/bin/bash"
|
||||
_user = "foobar"
|
||||
_group = "foobar"
|
||||
|
||||
cmdmod._run(
|
||||
"ls",
|
||||
cwd=tempfile.gettempdir(),
|
||||
runas=_user,
|
||||
shell=shell,
|
||||
group=_group,
|
||||
)
|
||||
if not _bundled:
|
||||
assert popen_mock.call_args_list[0][0][
|
||||
0
|
||||
] == [
|
||||
"sudo",
|
||||
"-u",
|
||||
_user,
|
||||
"-g",
|
||||
_group,
|
||||
"-s",
|
||||
"--",
|
||||
shell,
|
||||
"-c",
|
||||
sys.executable,
|
||||
]
|
||||
else:
|
||||
assert popen_mock.call_args_list[0][0][
|
||||
0
|
||||
] == [
|
||||
"sudo",
|
||||
"-u",
|
||||
_user,
|
||||
"-g",
|
||||
_group,
|
||||
"-s",
|
||||
"--",
|
||||
shell,
|
||||
"-c",
|
||||
"{} python {}".format(
|
||||
sys.executable, file_name
|
||||
),
|
||||
]
|
||||
|
|
Loading…
Add table
Reference in a new issue