diff --git a/changelog/44736.fixed.md b/changelog/44736.fixed.md new file mode 100644 index 00000000000..eee06decc06 --- /dev/null +++ b/changelog/44736.fixed.md @@ -0,0 +1,2 @@ +Commands on Windows are now prefixed with ``cmd /c`` so that compound +commands (commands separated by ``&&``) run properly when using ``runas`` diff --git a/salt/utils/win_runas.py b/salt/utils/win_runas.py index fc8c9c82be5..5faf01d3e80 100644 --- a/salt/utils/win_runas.py +++ b/salt/utils/win_runas.py @@ -187,8 +187,10 @@ def runas(cmdLine, username, password=None, cwd=None): | win32process.CREATE_SUSPENDED ) + flags = win32con.STARTF_USESTDHANDLES + flags |= win32con.STARTF_USESHOWWINDOW startup_info = salt.platform.win.STARTUPINFO( - dwFlags=win32con.STARTF_USESTDHANDLES, + dwFlags=flags, hStdInput=stdin_read.handle, hStdOutput=stdout_write.handle, hStdError=stderr_write.handle, @@ -204,7 +206,7 @@ def runas(cmdLine, username, password=None, cwd=None): int(user_token), logonflags=1, applicationname=None, - commandline=cmdLine, + commandline=f'cmd /c "{cmdLine}"', currentdirectory=cwd, creationflags=creationflags, startupinfo=startup_info, @@ -286,8 +288,10 @@ def runas_unpriv(cmd, username, password, cwd=None): dupin = salt.platform.win.DuplicateHandle(srchandle=stdin, inherit=True) # Get startup info structure + flags = win32con.STARTF_USESTDHANDLES + flags |= win32con.STARTF_USESHOWWINDOW startup_info = salt.platform.win.STARTUPINFO( - dwFlags=win32con.STARTF_USESTDHANDLES, + dwFlags=flags, hStdInput=dupin, hStdOutput=c2pwrite, hStdError=errwrite, @@ -300,7 +304,7 @@ def runas_unpriv(cmd, username, password, cwd=None): domain=domain, password=password, logonflags=salt.platform.win.LOGON_WITH_PROFILE, - commandline=cmd, + commandline=f'cmd /c "{cmd}"', startupinfo=startup_info, currentdirectory=cwd, ) diff --git a/tests/pytests/functional/utils/test_win_runas.py b/tests/pytests/functional/utils/test_win_runas.py new file mode 100644 index 00000000000..e6f06d6948c --- /dev/null +++ b/tests/pytests/functional/utils/test_win_runas.py @@ -0,0 +1,38 @@ +""" +Test the win_runas util +""" + +import pytest + +import salt.utils.win_runas as win_runas + +pytestmark = [ + pytest.mark.windows_whitelisted, + pytest.mark.skip_unless_on_windows, +] + + +@pytest.fixture +def user(): + with pytest.helpers.create_account() as account: + yield account + + +def test_runas(user): + cmd = "hostname && echo foo" + result = win_runas.runas( + cmdLine=cmd, + username=user.username, + password=user.password, + ) + assert "foo" in result["stdout"] + + +def test_runas_unpriv(user): + cmd = "hostname && echo foo" + result = win_runas.runas_unpriv( + cmd=cmd, + username=user.username, + password=user.password, + ) + assert "foo" in result["stdout"] diff --git a/tests/support/pytest/helpers.py b/tests/support/pytest/helpers.py index 8766607a49f..78de282ba95 100644 --- a/tests/support/pytest/helpers.py +++ b/tests/support/pytest/helpers.py @@ -332,8 +332,9 @@ class TestAccount: if salt.utils.platform.is_windows(): log.debug("Configuring system account: %s", self) ret = self.sminion.functions.user.update( - self.username, password_never_expires=True + self.username, expired=False, password_never_expires=True ) + assert ret is True if salt.utils.platform.is_darwin() or salt.utils.platform.is_windows(): password = self.password else: