switch become/runas to LogonUser/CreateProcessWithTokenW (#28253)

* non-uac works

* switch become/runas to LogonUser/CreateProcessWithTokenW

* fixes #22218
* provides consistent behavior across authtypes
* auto-elevates on UAC if target user has SE_TCB_NAME ("Act as part of the operating system") privilege
* sets us up for much more granular capabilities later (eg, network/service/batch logons)
pull/28256/head
Matt Davis 7 years ago committed by GitHub
parent 1b6b74f655
commit 9b383403ce

@ -34,6 +34,7 @@ Ansible Changes By Release
- TODO: build upon this to add many features detailed in ansible-config proposal https://github.com/ansible/proposals/issues/35 - TODO: build upon this to add many features detailed in ansible-config proposal https://github.com/ansible/proposals/issues/35
* Windows modules now support the use of multiple shared module_utils files in the form of Powershell modules (.psm1), via `#Requires -Module Ansible.ModuleUtils.Whatever.psm1` * Windows modules now support the use of multiple shared module_utils files in the form of Powershell modules (.psm1), via `#Requires -Module Ansible.ModuleUtils.Whatever.psm1`
* Python module argument_spec now supports custom validation logic by accepting a callable as the `type` argument. * Python module argument_spec now supports custom validation logic by accepting a callable as the `type` argument.
* Windows become_method: runas now works across all authtypes and will auto-elevate under UAC if WinRM user has "Act as part of the operating system" privilege
### Deprecations ### Deprecations
* The behaviour when specifying `--tags` (or `--skip-tags`) multiple times on the command line * The behaviour when specifying `--tags` (or `--skip-tags`) multiple times on the command line

@ -147,7 +147,6 @@ Function Run($payload) {
} }
''' # end leaf_exec ''' # end leaf_exec
become_wrapper = br''' become_wrapper = br'''
Set-StrictMode -Version 2 Set-StrictMode -Version 2
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
@ -174,7 +173,7 @@ namespace Ansible.Shell
string so = null, se = null; string so = null, se = null;
ThreadPool.QueueUserWorkItem((s)=> ThreadPool.QueueUserWorkItem((s) =>
{ {
so = stdoutStream.ReadToEnd(); so = stdoutStream.ReadToEnd();
sowait.Set(); sowait.Set();
@ -186,13 +185,50 @@ namespace Ansible.Shell
sewait.Set(); sewait.Set();
}); });
foreach(var wh in new WaitHandle[] { sowait, sewait }) foreach (var wh in new WaitHandle[] { sowait, sewait })
wh.WaitOne(); wh.WaitOne();
stdout = so; stdout = so;
stderr = se; stderr = se;
} }
public static IntPtr GetElevatedToken(IntPtr hToken)
{
uint requestedLength;
IntPtr pTokenInfo = Marshal.AllocHGlobal(sizeof(int));
try
{
if(!GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevationType, pTokenInfo, sizeof(int), out requestedLength))
throw new Win32Exception("Unable to get TokenElevationType");
var tet = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(pTokenInfo);
// we already have the best token we can get, just use it
if(tet != TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
return hToken;
GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, IntPtr.Zero, 0, out requestedLength);
IntPtr pLinkedToken = Marshal.AllocHGlobal((int)requestedLength);
if(!GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken, requestedLength, out requestedLength))
throw new Win32Exception("Unable to get linked token");
IntPtr linkedToken = Marshal.ReadIntPtr(pLinkedToken);
Marshal.FreeHGlobal(pLinkedToken);
return linkedToken;
}
finally
{
Marshal.FreeHGlobal(pTokenInfo);
}
}
// http://stackoverflow.com/a/30687230/139652 // http://stackoverflow.com/a/30687230/139652
public static void GrantAccessToWindowStationAndDesktop(string username) public static void GrantAccessToWindowStationAndDesktop(string username)
{ {
@ -207,18 +243,19 @@ namespace Ansible.Shell
StringBuilder sbOut = new StringBuilder(1024); StringBuilder sbOut = new StringBuilder(1024);
IntPtr filePartOut; IntPtr filePartOut;
if(SearchPath(null, findThis, null, sbOut.Capacity, sbOut, out filePartOut) == 0) if (SearchPath(null, findThis, null, sbOut.Capacity, sbOut, out filePartOut) == 0)
throw new FileNotFoundException("Couldn't locate " + findThis + " on path"); throw new FileNotFoundException("Couldn't locate " + findThis + " on path");
return sbOut.ToString(); return sbOut.ToString();
} }
public static uint GetProcessExitCode(IntPtr processHandle) { public static uint GetProcessExitCode(IntPtr processHandle)
{
new NativeWaitHandle(processHandle).WaitOne(); new NativeWaitHandle(processHandle).WaitOne();
uint exitCode; uint exitCode;
if(!GetExitCodeProcess(processHandle, out exitCode)) { if (!GetExitCodeProcess(processHandle, out exitCode))
throw new Exception("Error getting process exit code: " + Marshal.GetLastWin32Error()); throw new Win32Exception("Error getting process exit code");
}
return exitCode; return exitCode;
} }
@ -233,8 +270,8 @@ namespace Ansible.Shell
security.Persist(safeHandle, AccessControlSections.Access); security.Persist(safeHandle, AccessControlSections.Access);
} }
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)] [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint SearchPath ( public static extern uint SearchPath(
string lpPath, string lpPath,
string lpFileName, string lpFileName,
string lpExtension, string lpExtension,
@ -243,25 +280,25 @@ namespace Ansible.Shell
StringBuilder lpBuffer, StringBuilder lpBuffer,
out IntPtr lpFilePart); out IntPtr lpFilePart);
[DllImport("kernel32.dll", SetLastError=true)] [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode); private static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
public static extern bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, SECURITY_ATTRIBUTES lpPipeAttributes, uint nSize); public static extern bool CreatePipe(out IntPtr hReadPipe, out IntPtr hWritePipe, SECURITY_ATTRIBUTES lpPipeAttributes, uint nSize);
[DllImport("kernel32.dll", SetLastError=true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(StandardHandleValues nStdHandle); public static extern IntPtr GetStdHandle(StandardHandleValues nStdHandle);
[DllImport("kernel32.dll", SetLastError=true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetHandleInformation(IntPtr hObject, HandleFlags dwMask, int dwFlags); public static extern bool SetHandleInformation(IntPtr hObject, HandleFlags dwMask, int dwFlags);
[DllImport("kernel32.dll", SetLastError=true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject); public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError=true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref int lpSize); public static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref int lpSize);
[DllImport("kernel32.dll", SetLastError=true)] [DllImport("kernel32.dll", SetLastError = true)]
public static extern bool UpdateProcThreadAttribute( public static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList, IntPtr lpAttributeList,
uint dwFlags, uint dwFlags,
@ -271,7 +308,16 @@ namespace Ansible.Shell
IntPtr lpPreviousValue, IntPtr lpPreviousValue,
IntPtr lpReturnSize); IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode, BestFitMapping=false)] [DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
public static extern bool CreateProcess( public static extern bool CreateProcess(
[MarshalAs(UnmanagedType.LPTStr)] [MarshalAs(UnmanagedType.LPTStr)]
string lpApplicationName, string lpApplicationName,
@ -286,20 +332,25 @@ namespace Ansible.Shell
STARTUPINFO lpStartupInfo, STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation); out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CreateProcessWithTokenW(
IntPtr hToken,
LOGON_FLAGS dwLogonFlags,
string lpApplicationName,
string lpCommandLine,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)] [DllImport("advapi32.dll", SetLastError=true)]
public static extern bool CreateProcessWithLogonW( public static extern bool GetTokenInformation(
string userName, IntPtr TokenHandle,
string domain, TOKEN_INFORMATION_CLASS TokenInformationClass,
string password, IntPtr TokenInformation,
LOGON_FLAGS logonFlags, uint TokenInformationLength,
string applicationName, out uint ReturnLength);
string commandLine,
uint creationFlags,
IntPtr environment,
string currentDirectory,
STARTUPINFOEX startupInfo,
out PROCESS_INFORMATION processInformation);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetProcessWindowStation(); private static extern IntPtr GetProcessWindowStation();
@ -313,7 +364,8 @@ namespace Ansible.Shell
private class GenericAccessRule : AccessRule private class GenericAccessRule : AccessRule
{ {
public GenericAccessRule(IdentityReference identity, int accessMask, AccessControlType type) : public GenericAccessRule(IdentityReference identity, int accessMask, AccessControlType type) :
base(identity, accessMask, false, InheritanceFlags.None, PropagationFlags.None, type) { } base(identity, accessMask, false, InheritanceFlags.None, PropagationFlags.None, type)
{ }
} }
private class GenericSecurity : NativeObjectSecurity private class GenericSecurity : NativeObjectSecurity
@ -328,12 +380,14 @@ namespace Ansible.Shell
public override Type AccessRightType { get { throw new NotImplementedException(); } } public override Type AccessRightType { get { throw new NotImplementedException(); } }
public override AccessRule AccessRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, public override AccessRule AccessRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited,
InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type) { throw new NotImplementedException(); } InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
{ throw new NotImplementedException(); }
public override Type AccessRuleType { get { return typeof(AccessRule); } } public override Type AccessRuleType { get { return typeof(AccessRule); } }
public override AuditRule AuditRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, public override AuditRule AuditRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited,
InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags) { throw new NotImplementedException(); } InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
{ throw new NotImplementedException(); }
public override Type AuditRuleType { get { return typeof(AuditRule); } } public override Type AuditRuleType { get { return typeof(AuditRule); } }
} }
@ -348,8 +402,25 @@ namespace Ansible.Shell
} }
class NativeWaitHandle : WaitHandle { public class Win32Exception : System.ComponentModel.Win32Exception
public NativeWaitHandle(IntPtr handle) { {
private string _msg;
public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
public Win32Exception(int errorCode, string message) : base(errorCode)
{
_msg = String.Format("{0} ({1}, Win32ErrorCode {2})", message, base.Message, errorCode);
}
public override string Message { get { return _msg; } }
public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
}
class NativeWaitHandle : WaitHandle
{
public NativeWaitHandle(IntPtr handle)
{
this.Handle = handle; this.Handle = handle;
} }
} }
@ -357,8 +428,8 @@ namespace Ansible.Shell
[Flags] [Flags]
public enum LOGON_FLAGS public enum LOGON_FLAGS
{ {
LOGON_WITH_PROFILE = 0x00000001, LOGON_WITH_PROFILE = 0x00000001,
LOGON_NETCREDENTIALS_ONLY = 0x00000002 LOGON_NETCREDENTIALS_ONLY = 0x00000002
} }
[Flags] [Flags]
@ -371,8 +442,6 @@ namespace Ansible.Shell
EXTENDED_STARTUPINFO_PRESENT = 0x00080000, EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
} }
[Flags] [Flags]
public enum StartupInfoFlags : uint public enum StartupInfoFlags : uint
{ {
@ -393,6 +462,42 @@ namespace Ansible.Shell
INHERIT = 1 INHERIT = 1
} }
public enum TOKEN_INFORMATION_CLASS
{
TokenType = 8,
TokenImpersonationLevel = 9,
TokenElevationType = 18,
TokenLinkedToken = 19,
}
public enum TOKEN_ELEVATION_TYPE
{
TokenElevationTypeDefault = 1,
TokenElevationTypeFull,
TokenElevationTypeLimited
}
[StructLayout(LayoutKind.Sequential)]
public class PROFILEINFO {
public int dwSize;
public int dwFlags;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpUserName;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpProfilePath;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpDefaultPath;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public String lpPolicyPath;
public IntPtr hProfile;
public PROFILEINFO()
{
dwSize = Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public class SECURITY_ATTRIBUTES public class SECURITY_ATTRIBUTES
@ -401,7 +506,8 @@ namespace Ansible.Shell
public IntPtr lpSecurityDescriptor; public IntPtr lpSecurityDescriptor;
public bool bInheritHandle = false; public bool bInheritHandle = false;
public SECURITY_ATTRIBUTES() { public SECURITY_ATTRIBUTES()
{
nLength = Marshal.SizeOf(this); nLength = Marshal.SizeOf(this);
} }
} }
@ -429,17 +535,20 @@ namespace Ansible.Shell
public IntPtr hStdOutput; public IntPtr hStdOutput;
public IntPtr hStdError; public IntPtr hStdError;
public STARTUPINFO() { public STARTUPINFO()
{
cb = Marshal.SizeOf(this); cb = Marshal.SizeOf(this);
} }
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public class STARTUPINFOEX { public class STARTUPINFOEX
{
public STARTUPINFO startupInfo; public STARTUPINFO startupInfo;
public IntPtr lpAttributeList; public IntPtr lpAttributeList;
public STARTUPINFOEX() { public STARTUPINFOEX()
{
startupInfo = new STARTUPINFO(); startupInfo = new STARTUPINFO();
startupInfo.cb = Marshal.SizeOf(this); startupInfo.cb = Marshal.SizeOf(this);
} }
@ -453,9 +562,6 @@ namespace Ansible.Shell
public int dwProcessId; public int dwProcessId;
public int dwThreadId; public int dwThreadId;
} }
} }
"@ "@
@ -546,8 +652,6 @@ Function Run($payload) {
$acl.AddAccessRule($(New-Object System.Security.AccessControl.FileSystemAccessRule($username, "FullControl", "Allow"))) $acl.AddAccessRule($(New-Object System.Security.AccessControl.FileSystemAccessRule($username, "FullControl", "Allow")))
Set-Acl $temp $acl | Out-Null Set-Acl $temp $acl | Out-Null
# TODO: grant target user permissions on tempfile/tempdir
Try { Try {
$exec_args = @("-noninteractive", $temp) $exec_args = @("-noninteractive", $temp)
@ -568,17 +672,18 @@ Function Run($payload) {
$stdout_read = $stdout_write = $stderr_read = $stderr_write = 0 $stdout_read = $stdout_write = $stderr_read = $stderr_write = 0
If(-not [Ansible.Shell.NativeProcessUtil]::CreatePipe([ref]$stdout_read, [ref]$stdout_write, $pipesec, 0)) { If(-not [Ansible.Shell.NativeProcessUtil]::CreatePipe([ref]$stdout_read, [ref]$stdout_write, $pipesec, 0)) {
throw "Stdout pipe setup failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" throw [Ansible.Shell.Win32Exception] "Stdout pipe setup failed"
} }
If(-not [Ansible.Shell.NativeProcessUtil]::SetHandleInformation($stdout_read, [Ansible.Shell.HandleFlags]::INHERIT, 0)) { If(-not [Ansible.Shell.NativeProcessUtil]::SetHandleInformation($stdout_read, [Ansible.Shell.HandleFlags]::INHERIT, 0)) {
throw "Stdout handle setup failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" throw [Ansible.Shell.Win32Exception] "Stdout handle setup failed"
} }
If(-not [Ansible.Shell.NativeProcessUtil]::CreatePipe([ref]$stderr_read, [ref]$stderr_write, $pipesec, 0)) { If(-not [Ansible.Shell.NativeProcessUtil]::CreatePipe([ref]$stderr_read, [ref]$stderr_write, $pipesec, 0)) {
throw "Stderr pipe setup failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" throw [Ansible.Shell.Win32Exception] "Stderr pipe setup failed"
} }
If(-not [Ansible.Shell.NativeProcessUtil]::SetHandleInformation($stderr_read, [Ansible.Shell.HandleFlags]::INHERIT, 0)) { If(-not [Ansible.Shell.NativeProcessUtil]::SetHandleInformation($stderr_read, [Ansible.Shell.HandleFlags]::INHERIT, 0)) {
throw "Stderr handle setup failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" throw [Ansible.Shell.Win32Exception] "Stderr handle setup failed"
} }
# setup stdin redirection, we'll leave stdout/stderr as normal # setup stdin redirection, we'll leave stdout/stderr as normal
@ -592,14 +697,13 @@ Function Run($payload) {
$pipesec.bInheritHandle = $true $pipesec.bInheritHandle = $true
If(-not [Ansible.Shell.NativeProcessUtil]::CreatePipe([ref]$stdin_read, [ref]$stdin_write, $pipesec, 0)) { If(-not [Ansible.Shell.NativeProcessUtil]::CreatePipe([ref]$stdin_read, [ref]$stdin_write, $pipesec, 0)) {
throw "Stdin pipe setup failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" throw [Ansible.Shell.Win32Exception] "Stdin pipe setup failed"
} }
If(-not [Ansible.Shell.NativeProcessUtil]::SetHandleInformation($stdin_write, [Ansible.Shell.HandleFlags]::INHERIT, 0)) { If(-not [Ansible.Shell.NativeProcessUtil]::SetHandleInformation($stdin_write, [Ansible.Shell.HandleFlags]::INHERIT, 0)) {
throw "Stdin handle setup failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" throw [Ansible.Shell.Win32Exception] "Stdin handle setup failed"
} }
$si.startupInfo.hStdInput = $stdin_read $si.startupInfo.hStdInput = $stdin_read
# create an attribute list with our explicit handle inheritance list to pass to CreateProcess # create an attribute list with our explicit handle inheritance list to pass to CreateProcess
[int]$buf_sz = 0 [int]$buf_sz = 0
@ -607,7 +711,7 @@ Function Run($payload) {
If(-not [Ansible.Shell.NativeProcessUtil]::InitializeProcThreadAttributeList([IntPtr]::Zero, 1, 0, [ref]$buf_sz)) { If(-not [Ansible.Shell.NativeProcessUtil]::InitializeProcThreadAttributeList([IntPtr]::Zero, 1, 0, [ref]$buf_sz)) {
$last_err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() $last_err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
If($last_err -ne 122) { # ERROR_INSUFFICIENT_BUFFER If($last_err -ne 122) { # ERROR_INSUFFICIENT_BUFFER
throw "Attribute list size query failed, Win32Error: $last_err" throw New-Object Ansible.Shell.Win32Exception $last_err, "Attribute list size query failed"
} }
} }
@ -615,7 +719,7 @@ Function Run($payload) {
# initialize the attribute list # initialize the attribute list
If(-not [Ansible.Shell.NativeProcessUtil]::InitializeProcThreadAttributeList($si.lpAttributeList, 1, 0, [ref]$buf_sz)) { If(-not [Ansible.Shell.NativeProcessUtil]::InitializeProcThreadAttributeList($si.lpAttributeList, 1, 0, [ref]$buf_sz)) {
throw "Attribute list init failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" throw [Ansible.Shell.Win32Exception] "Attribute list init failed"
} }
$handles_to_inherit = [IntPtr[]]@($stdin_read,$stdout_write,$stderr_write) $handles_to_inherit = [IntPtr[]]@($stdin_read,$stdout_write,$stderr_write)
@ -625,7 +729,7 @@ Function Run($payload) {
If(-not [Ansible.Shell.NativeProcessUtil]::UpdateProcThreadAttribute($si.lpAttributeList, 0, 0x20002, ` If(-not [Ansible.Shell.NativeProcessUtil]::UpdateProcThreadAttribute($si.lpAttributeList, 0, 0x20002, `
$pinned_handles.AddrOfPinnedObject(), [System.Runtime.InteropServices.Marshal]::SizeOf([type][IntPtr]) * $handles_to_inherit.Length, ` $pinned_handles.AddrOfPinnedObject(), [System.Runtime.InteropServices.Marshal]::SizeOf([type][IntPtr]) * $handles_to_inherit.Length, `
[System.IntPtr]::Zero, [System.IntPtr]::Zero)) { [System.IntPtr]::Zero, [System.IntPtr]::Zero)) {
throw "Attribute list update failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" throw [Ansible.Shell.Win32Exception] "Attribute list update failed"
} }
# need to use a preamble-free version of UTF8Encoding # need to use a preamble-free version of UTF8Encoding
@ -653,12 +757,26 @@ Function Run($payload) {
$domain = "." $domain = "."
} }
# TODO: use proper Win32Exception + error [System.IntPtr]$hToken = [System.IntPtr]::Zero
If(-not [Ansible.Shell.NativeProcessUtil]::CreateProcessWithLogonW($username, $domain, $password, [Ansible.Shell.LOGON_FLAGS]::LOGON_WITH_PROFILE,
$exec_cmd, $exec_args, If(-not [Ansible.Shell.NativeProcessUtil]::LogonUser($username, $domain, $password, 2, 0, [ref]$hToken)) {
$pstartup_flags, [IntPtr]::Zero, $env:windir, $si, [ref]$pi)) { throw [Ansible.Shell.Win32Exception] "LogonUser failed"
#throw New-Object System.ComponentModel.Win32Exception }
throw "Worker creation failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())"
$hTokenElevated = [Ansible.Shell.NativeProcessUtil]::GetElevatedToken($hToken);
$launch_success = $false
foreach($ht in @($hTokenElevated, $hToken)) {
If([Ansible.Shell.NativeProcessUtil]::CreateProcessWithTokenW($ht, [Ansible.Shell.LOGON_FLAGS]::LOGON_WITH_PROFILE,
$exec_cmd, $exec_args, $pstartup_flags, [System.IntPtr]::Zero, $env:windir, $si, [ref]$pi)) {
$launch_success = $true
break
}
}
If(-not $launch_success) {
throw [Ansible.Shell.Win32Exception] "Failed to create process with new token"
} }
$stdout_fs = New-Object System.IO.FileStream @($stdout_read, [System.IO.FileAccess]::Read, $true, 4096) $stdout_fs = New-Object System.IO.FileStream @($stdout_read, [System.IO.FileAccess]::Read, $true, 4096)
@ -682,10 +800,6 @@ Function Run($payload) {
# FUTURE: decode CLIXML stderr output (and other streams?) # FUTURE: decode CLIXML stderr output (and other streams?)
#$proc.WaitForExit() | Out-Null
# TODO: wait on process handle for exit, get process exit code
$rc = [Ansible.Shell.NativeProcessUtil]::GetProcessExitCode($pi.hProcess) $rc = [Ansible.Shell.NativeProcessUtil]::GetProcessExitCode($pi.hProcess)
If ($rc -eq 0) { If ($rc -eq 0) {
@ -709,7 +823,6 @@ Function Run($payload) {
''' # end become_wrapper ''' # end become_wrapper
async_wrapper = br''' async_wrapper = br'''
Set-StrictMode -Version 2 Set-StrictMode -Version 2
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
@ -1256,9 +1369,6 @@ class ShellModule(object):
# env provider's limitations don't appear to be documented. # env provider's limitations don't appear to be documented.
safe_envkey = re.compile(r'^[\d\w_]{1,255}$') safe_envkey = re.compile(r'^[\d\w_]{1,255}$')
# TODO: implement module transfer
# TODO: implement #Requires -Modules parser/locator
# TODO: add KEEP_REMOTE_FILES support + debug wrapper dump
# TODO: add binary module support # TODO: add binary module support
def assert_safe_env_key(self, key): def assert_safe_env_key(self, key):

Loading…
Cancel
Save