Fix issues with win_runas

modules/file.py:     Pass the right parameters to `check_perms` on Windows
platform/win.py:     Return actual error on runas failure
platform/win.py:     Setup environment for CreateProcessWithLogonW
states/file.py:      Pass the right parameters to `file.check_perms` on
                     Windows
states/zfs.py:       Fix __virtual__ so it doesn't stacktrace in Windows
                     logs
states/zpool.py:     Fix __virtual__ so it doesn't stacktrace in Windows
                     logs
utils/win_runas.py:  Cleanup the handles a little better by using some
                     try/finally blocks.
states/test_file.py: Just use os.mkdir on Windows as the mode is ignored
This commit is contained in:
twangboy 2019-06-13 17:06:34 -06:00
parent bceffa1d92
commit 4a9c020787
No known key found for this signature in database
GPG key ID: 93FF3BDEB278C9EB
7 changed files with 114 additions and 95 deletions

View file

@ -2759,11 +2759,16 @@ def blockreplace(path,
backup_path = '{0}{1}'.format(path, backup)
shutil.copy2(path, backup_path)
# copy2 does not preserve ownership
check_perms(backup_path,
None,
perms['user'],
perms['group'],
perms['mode'])
if salt.utils.platform.is_windows():
check_perms(path=backup_path,
ret=None,
owner=perms['user'])
else:
check_perms(name=backup_path,
ret=None,
user=perms['user'],
group=perms['group'],
mode=perms['mode'])
# write new content in the file while avoiding partial reads
try:
@ -2774,11 +2779,16 @@ def blockreplace(path,
fh_.close()
# this may have overwritten file attrs
check_perms(path,
None,
perms['user'],
perms['group'],
perms['mode'])
if salt.utils.platform.is_windows():
check_perms(path=path,
ret=None,
owner=perms['user'])
else:
check_perms(path,
ret=None,
user=perms['user'],
group=perms['group'],
mode=perms['mode'])
if show_changes:
return diff
@ -5397,7 +5407,7 @@ def manage_file(name,
# on Windows. The local function will be overridden
# pylint: disable=E1120,E1121,E1123
ret = check_perms(
path=name,
path=name,
ret=ret,
owner=kwargs.get('win_owner'),
grant_perms=kwargs.get('win_perms'),

View file

@ -10,9 +10,9 @@ Much of what is here was adapted from the following:
http://stackoverflow.com/questions/29566330
'''
from __future__ import absolute_import, unicode_literals
import os
import collections
import logging
import os
import psutil
import ctypes
@ -21,7 +21,6 @@ from ctypes import wintypes
from salt.ext.six.moves import range
from salt.ext.six.moves import zip
import win32con
import win32con
import win32api
import win32process
@ -598,7 +597,7 @@ class HANDLE_IHV(wintypes.HANDLE):
def errcheck_ihv(result, func, args):
if result.value == INVALID_HANDLE_VALUE:
raise ctypes.WinError()
raise ctypes.WinError(ctypes.get_last_error())
return result.value
@ -608,13 +607,13 @@ class DWORD_IDV(wintypes.DWORD):
def errcheck_idv(result, func, args):
if result.value == INVALID_DWORD_VALUE:
raise ctypes.WinError()
raise ctypes.WinError(ctypes.get_last_error())
return result.value
def errcheck_bool(result, func, args):
if not result:
raise ctypes.WinError()
raise ctypes.WinError(ctypes.get_last_error())
return args
@ -1035,10 +1034,8 @@ def CreateProcessWithTokenW(token,
startupinfo = STARTUPINFO()
if currentdirectory is not None:
currentdirectory = ctypes.create_unicode_buffer(currentdirectory)
if environment:
environment = ctypes.pointer(
environment_string(environment)
)
if environment is not None:
environment = ctypes.pointer(environment_string(environment))
process_info = PROCESS_INFORMATION()
ret = advapi32.CreateProcessWithTokenW(
token,
@ -1174,14 +1171,23 @@ def make_inheritable(token):
)
def CreateProcessWithLogonW(username=None, domain=None, password=None,
logonflags=0, applicationname=None, commandline=None, creationflags=0,
environment=None, currentdirectory=None, startupinfo=None):
def CreateProcessWithLogonW(username=None,
domain=None,
password=None,
logonflags=0,
applicationname=None,
commandline=None,
creationflags=0,
environment=None,
currentdirectory=None,
startupinfo=None):
creationflags |= win32con.CREATE_UNICODE_ENVIRONMENT
if commandline is not None:
commandline = ctypes.create_unicode_buffer(commandline)
if startupinfo is None:
startupinfo = STARTUPINFO()
if environment is not None:
environment = ctypes.pointer(environment_string(environment))
process_info = PROCESS_INFORMATION()
advapi32.CreateProcessWithLogonW(
username,

View file

@ -6343,7 +6343,14 @@ def copy_(name,
# the filesystem we're copying to is squashed or doesn't support chown
# then we shouldn't be checking anything.
if not preserve:
__salt__['file.check_perms'](name, ret, user, group, mode)
if salt.utils.platform.is_windows():
# TODO: Add the other win_* parameters to this function
ret = __salt__['file.check_perms'](
path=name,
ret=ret,
owner=user)
else:
__salt__['file.check_perms'](name, ret, user, group, mode)
except (IOError, OSError):
return _error(
ret, 'Failed to copy "{0}" to "{1}"'.format(source, name))

View file

@ -68,10 +68,9 @@ def __virtual__():
'''
Provides zfs state
'''
if __grains__['zfs_support']:
return __virtualname__
else:
return (False, "The zfs state cannot be loaded: zfs not supported")
if not __grains__.get('zfs_support'):
return False, 'The zfs state cannot be loaded: zfs not supported'
return __virtualname__
def _absent(name, dataset_type, force=False, recursive=False):

View file

@ -88,10 +88,9 @@ def __virtual__():
'''
Provides zpool state
'''
if __grains__['zfs_support']:
return __virtualname__
else:
if not __grains__.get('zfs_support'):
return False, 'The zpool state cannot be loaded: zfs not supported'
return __virtualname__
def _layout_to_vdev(layout, device_dir=None):

View file

@ -95,6 +95,7 @@ def runas(cmdLine, username, password=None, cwd=None):
except WindowsError: # pylint: disable=undefined-variable
log.debug("Unable to impersonate SYSTEM user")
impersonation_token = None
win32api.CloseHandle(th)
# Impersonation of the SYSTEM user failed. Fallback to an un-privileged
# runas.
@ -105,7 +106,6 @@ def runas(cmdLine, username, password=None, cwd=None):
if domain == 'NT AUTHORITY':
# Logon as a system level account, SYSTEM, LOCAL SERVICE, or NETWORK
# SERVICE.
logonType = win32con.LOGON32_LOGON_SERVICE
user_token = win32security.LogonUser(
username,
domain,
@ -172,53 +172,56 @@ def runas(cmdLine, username, password=None, cwd=None):
# Create the environment for the user
env = win32profile.CreateEnvironmentBlock(user_token, False)
# Start the process in a suspended state.
process_info = salt.platform.win.CreateProcessWithTokenW(
int(user_token),
logonflags=1,
applicationname=None,
commandline=cmdLine,
currentdirectory=cwd,
creationflags=creationflags,
startupinfo=startup_info,
environment=env,
)
try:
# Start the process in a suspended state.
process_info = salt.platform.win.CreateProcessWithTokenW(
int(user_token),
logonflags=1,
applicationname=None,
commandline=cmdLine,
currentdirectory=cwd,
creationflags=creationflags,
startupinfo=startup_info,
environment=env,
)
hProcess = process_info.hProcess
hThread = process_info.hThread
dwProcessId = process_info.dwProcessId
dwThreadId = process_info.dwThreadId
hProcess = process_info.hProcess
hThread = process_info.hThread
dwProcessId = process_info.dwProcessId
dwThreadId = process_info.dwThreadId
salt.platform.win.kernel32.CloseHandle(stdin_write.handle)
salt.platform.win.kernel32.CloseHandle(stdout_write.handle)
salt.platform.win.kernel32.CloseHandle(stderr_write.handle)
# We don't use these so let's close the handle
salt.platform.win.kernel32.CloseHandle(stdin_write.handle)
salt.platform.win.kernel32.CloseHandle(stdout_write.handle)
salt.platform.win.kernel32.CloseHandle(stderr_write.handle)
ret = {'pid': dwProcessId}
# Resume the process
psutil.Process(dwProcessId).resume()
ret = {'pid': dwProcessId}
# Resume the process
psutil.Process(dwProcessId).resume()
# Wait for the process to exit and get it's return code.
if win32event.WaitForSingleObject(hProcess, win32event.INFINITE) == win32con.WAIT_OBJECT_0:
exitcode = win32process.GetExitCodeProcess(hProcess)
ret['retcode'] = exitcode
# Wait for the process to exit and get it's return code.
if win32event.WaitForSingleObject(hProcess, win32event.INFINITE) == win32con.WAIT_OBJECT_0:
exitcode = win32process.GetExitCodeProcess(hProcess)
ret['retcode'] = exitcode
# Read standard out
fd_out = msvcrt.open_osfhandle(stdout_read.handle, os.O_RDONLY | os.O_TEXT)
with os.fdopen(fd_out, 'r') as f_out:
stdout = f_out.read()
ret['stdout'] = stdout
# Read standard out
fd_out = msvcrt.open_osfhandle(stdout_read.handle, os.O_RDONLY | os.O_TEXT)
with os.fdopen(fd_out, 'r') as f_out:
stdout = f_out.read()
ret['stdout'] = stdout
# Read standard error
fd_err = msvcrt.open_osfhandle(stderr_read.handle, os.O_RDONLY | os.O_TEXT)
with os.fdopen(fd_err, 'r') as f_err:
stderr = f_err.read()
ret['stderr'] = stderr
salt.platform.win.kernel32.CloseHandle(hProcess)
win32api.CloseHandle(user_token)
if impersonation_token:
win32security.RevertToSelf()
win32api.CloseHandle(impersonation_token)
# Read standard error
fd_err = msvcrt.open_osfhandle(stderr_read.handle, os.O_RDONLY | os.O_TEXT)
with os.fdopen(fd_err, 'r') as f_err:
stderr = f_err.read()
ret['stderr'] = stderr
finally:
salt.platform.win.kernel32.CloseHandle(hProcess)
win32api.CloseHandle(th)
win32api.CloseHandle(user_token)
if impersonation_token:
win32security.RevertToSelf()
win32api.CloseHandle(impersonation_token)
return ret
@ -258,20 +261,21 @@ def runas_unpriv(cmd, username, password, cwd=None):
hStdError=errwrite,
)
# Run command and return process info structure
process_info = salt.platform.win.CreateProcessWithLogonW(
username=username,
domain=domain,
password=password,
logonflags=salt.platform.win.LOGON_WITH_PROFILE,
commandline=cmd,
startupinfo=startup_info,
currentdirectory=cwd)
salt.platform.win.kernel32.CloseHandle(dupin)
salt.platform.win.kernel32.CloseHandle(c2pwrite)
salt.platform.win.kernel32.CloseHandle(errwrite)
salt.platform.win.kernel32.CloseHandle(process_info.hThread)
try:
# Run command and return process info structure
process_info = salt.platform.win.CreateProcessWithLogonW(
username=username,
domain=domain,
password=password,
logonflags=salt.platform.win.LOGON_WITH_PROFILE,
commandline=cmd,
startupinfo=startup_info,
currentdirectory=cwd)
salt.platform.win.kernel32.CloseHandle(process_info.hThread)
finally:
salt.platform.win.kernel32.CloseHandle(dupin)
salt.platform.win.kernel32.CloseHandle(c2pwrite)
salt.platform.win.kernel32.CloseHandle(errwrite)
# Initialize ret and set first element
ret = {'pid': process_info.dwProcessId}

View file

@ -915,10 +915,7 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
tmp_dir = os.path.join(TMP, 'pgdata')
sym_dir = os.path.join(TMP, 'pg_data')
if IS_WINDOWS:
self.run_function('file.mkdir', [tmp_dir, 'Administrators'])
else:
os.mkdir(tmp_dir, 0o700)
os.mkdir(tmp_dir, 0o700)
self.run_function('file.symlink', [tmp_dir, sym_dir])
@ -1254,10 +1251,7 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
null_file = '{0}/null'.format(tmp_dir)
broken_link = '{0}/broken'.format(tmp_dir)
if IS_WINDOWS:
self.run_function('file.mkdir', [tmp_dir, 'Administrators'])
else:
os.mkdir(tmp_dir, 0o700)
os.mkdir(tmp_dir, 0o700)
self.run_function('file.symlink', [null_file, broken_link])