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)
This commit is contained in:
parent
1b6b74f655
commit
9b383403ce
2 changed files with 183 additions and 72 deletions
|
@ -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
|
||||
* 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.
|
||||
* 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
|
||||
* The behaviour when specifying `--tags` (or `--skip-tags`) multiple times on the command line
|
||||
|
|
|
@ -147,7 +147,6 @@ Function Run($payload) {
|
|||
}
|
||||
''' # end leaf_exec
|
||||
|
||||
|
||||
become_wrapper = br'''
|
||||
Set-StrictMode -Version 2
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
@ -174,7 +173,7 @@ namespace Ansible.Shell
|
|||
|
||||
string so = null, se = null;
|
||||
|
||||
ThreadPool.QueueUserWorkItem((s)=>
|
||||
ThreadPool.QueueUserWorkItem((s) =>
|
||||
{
|
||||
so = stdoutStream.ReadToEnd();
|
||||
sowait.Set();
|
||||
|
@ -186,13 +185,50 @@ namespace Ansible.Shell
|
|||
sewait.Set();
|
||||
});
|
||||
|
||||
foreach(var wh in new WaitHandle[] { sowait, sewait })
|
||||
foreach (var wh in new WaitHandle[] { sowait, sewait })
|
||||
wh.WaitOne();
|
||||
|
||||
stdout = so;
|
||||
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
|
||||
public static void GrantAccessToWindowStationAndDesktop(string username)
|
||||
{
|
||||
|
@ -207,18 +243,19 @@ namespace Ansible.Shell
|
|||
StringBuilder sbOut = new StringBuilder(1024);
|
||||
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");
|
||||
|
||||
return sbOut.ToString();
|
||||
}
|
||||
|
||||
public static uint GetProcessExitCode(IntPtr processHandle) {
|
||||
public static uint GetProcessExitCode(IntPtr processHandle)
|
||||
{
|
||||
new NativeWaitHandle(processHandle).WaitOne();
|
||||
uint exitCode;
|
||||
if(!GetExitCodeProcess(processHandle, out exitCode)) {
|
||||
throw new Exception("Error getting process exit code: " + Marshal.GetLastWin32Error());
|
||||
}
|
||||
if (!GetExitCodeProcess(processHandle, out exitCode))
|
||||
throw new Win32Exception("Error getting process exit code");
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
|
@ -233,8 +270,8 @@ namespace Ansible.Shell
|
|||
security.Persist(safeHandle, AccessControlSections.Access);
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
|
||||
public static extern uint SearchPath (
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern uint SearchPath(
|
||||
string lpPath,
|
||||
string lpFileName,
|
||||
string lpExtension,
|
||||
|
@ -243,25 +280,25 @@ namespace Ansible.Shell
|
|||
StringBuilder lpBuffer,
|
||||
out IntPtr lpFilePart);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
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);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
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);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
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(
|
||||
IntPtr lpAttributeList,
|
||||
uint dwFlags,
|
||||
|
@ -271,7 +308,16 @@ namespace Ansible.Shell
|
|||
IntPtr lpPreviousValue,
|
||||
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(
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
string lpApplicationName,
|
||||
|
@ -286,20 +332,25 @@ namespace Ansible.Shell
|
|||
STARTUPINFO lpStartupInfo,
|
||||
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)]
|
||||
public static extern bool CreateProcessWithLogonW(
|
||||
string userName,
|
||||
string domain,
|
||||
string password,
|
||||
LOGON_FLAGS logonFlags,
|
||||
string applicationName,
|
||||
string commandLine,
|
||||
uint creationFlags,
|
||||
IntPtr environment,
|
||||
string currentDirectory,
|
||||
STARTUPINFOEX startupInfo,
|
||||
out PROCESS_INFORMATION processInformation);
|
||||
[DllImport("advapi32.dll", SetLastError=true)]
|
||||
public static extern bool GetTokenInformation(
|
||||
IntPtr TokenHandle,
|
||||
TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||
IntPtr TokenInformation,
|
||||
uint TokenInformationLength,
|
||||
out uint ReturnLength);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GetProcessWindowStation();
|
||||
|
@ -313,7 +364,8 @@ namespace Ansible.Shell
|
|||
private class GenericAccessRule : AccessRule
|
||||
{
|
||||
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
|
||||
|
@ -328,12 +380,14 @@ namespace Ansible.Shell
|
|||
public override Type AccessRightType { get { throw new NotImplementedException(); } }
|
||||
|
||||
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 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); } }
|
||||
}
|
||||
|
@ -348,8 +402,25 @@ namespace Ansible.Shell
|
|||
|
||||
}
|
||||
|
||||
class NativeWaitHandle : WaitHandle {
|
||||
public NativeWaitHandle(IntPtr handle) {
|
||||
public class Win32Exception : System.ComponentModel.Win32Exception
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -357,8 +428,8 @@ namespace Ansible.Shell
|
|||
[Flags]
|
||||
public enum LOGON_FLAGS
|
||||
{
|
||||
LOGON_WITH_PROFILE = 0x00000001,
|
||||
LOGON_NETCREDENTIALS_ONLY = 0x00000002
|
||||
LOGON_WITH_PROFILE = 0x00000001,
|
||||
LOGON_NETCREDENTIALS_ONLY = 0x00000002
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
@ -371,8 +442,6 @@ namespace Ansible.Shell
|
|||
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Flags]
|
||||
public enum StartupInfoFlags : uint
|
||||
{
|
||||
|
@ -393,6 +462,42 @@ namespace Ansible.Shell
|
|||
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)]
|
||||
public class SECURITY_ATTRIBUTES
|
||||
|
@ -401,7 +506,8 @@ namespace Ansible.Shell
|
|||
public IntPtr lpSecurityDescriptor;
|
||||
public bool bInheritHandle = false;
|
||||
|
||||
public SECURITY_ATTRIBUTES() {
|
||||
public SECURITY_ATTRIBUTES()
|
||||
{
|
||||
nLength = Marshal.SizeOf(this);
|
||||
}
|
||||
}
|
||||
|
@ -429,17 +535,20 @@ namespace Ansible.Shell
|
|||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
|
||||
public STARTUPINFO() {
|
||||
public STARTUPINFO()
|
||||
{
|
||||
cb = Marshal.SizeOf(this);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class STARTUPINFOEX {
|
||||
public class STARTUPINFOEX
|
||||
{
|
||||
public STARTUPINFO startupInfo;
|
||||
public IntPtr lpAttributeList;
|
||||
|
||||
public STARTUPINFOEX() {
|
||||
public STARTUPINFOEX()
|
||||
{
|
||||
startupInfo = new STARTUPINFO();
|
||||
startupInfo.cb = Marshal.SizeOf(this);
|
||||
}
|
||||
|
@ -453,9 +562,6 @@ namespace Ansible.Shell
|
|||
public int dwProcessId;
|
||||
public int dwThreadId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
"@
|
||||
|
||||
|
@ -546,8 +652,6 @@ Function Run($payload) {
|
|||
$acl.AddAccessRule($(New-Object System.Security.AccessControl.FileSystemAccessRule($username, "FullControl", "Allow")))
|
||||
Set-Acl $temp $acl | Out-Null
|
||||
|
||||
# TODO: grant target user permissions on tempfile/tempdir
|
||||
|
||||
Try {
|
||||
$exec_args = @("-noninteractive", $temp)
|
||||
|
||||
|
@ -568,17 +672,18 @@ Function Run($payload) {
|
|||
$stdout_read = $stdout_write = $stderr_read = $stderr_write = 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)) {
|
||||
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)) {
|
||||
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)) {
|
||||
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
|
||||
|
@ -592,14 +697,13 @@ Function Run($payload) {
|
|||
$pipesec.bInheritHandle = $true
|
||||
|
||||
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)) {
|
||||
throw "Stdin handle setup failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())"
|
||||
throw [Ansible.Shell.Win32Exception] "Stdin handle setup failed"
|
||||
}
|
||||
$si.startupInfo.hStdInput = $stdin_read
|
||||
|
||||
|
||||
# create an attribute list with our explicit handle inheritance list to pass to CreateProcess
|
||||
[int]$buf_sz = 0
|
||||
|
||||
|
@ -607,7 +711,7 @@ Function Run($payload) {
|
|||
If(-not [Ansible.Shell.NativeProcessUtil]::InitializeProcThreadAttributeList([IntPtr]::Zero, 1, 0, [ref]$buf_sz)) {
|
||||
$last_err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
|
||||
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
|
||||
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)
|
||||
|
@ -625,7 +729,7 @@ Function Run($payload) {
|
|||
If(-not [Ansible.Shell.NativeProcessUtil]::UpdateProcThreadAttribute($si.lpAttributeList, 0, 0x20002, `
|
||||
$pinned_handles.AddrOfPinnedObject(), [System.Runtime.InteropServices.Marshal]::SizeOf([type][IntPtr]) * $handles_to_inherit.Length, `
|
||||
[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
|
||||
|
@ -653,12 +757,26 @@ Function Run($payload) {
|
|||
$domain = "."
|
||||
}
|
||||
|
||||
# TODO: use proper Win32Exception + error
|
||||
If(-not [Ansible.Shell.NativeProcessUtil]::CreateProcessWithLogonW($username, $domain, $password, [Ansible.Shell.LOGON_FLAGS]::LOGON_WITH_PROFILE,
|
||||
$exec_cmd, $exec_args,
|
||||
$pstartup_flags, [IntPtr]::Zero, $env:windir, $si, [ref]$pi)) {
|
||||
#throw New-Object System.ComponentModel.Win32Exception
|
||||
throw "Worker creation failed, Win32Error: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())"
|
||||
[System.IntPtr]$hToken = [System.IntPtr]::Zero
|
||||
|
||||
If(-not [Ansible.Shell.NativeProcessUtil]::LogonUser($username, $domain, $password, 2, 0, [ref]$hToken)) {
|
||||
throw [Ansible.Shell.Win32Exception] "LogonUser failed"
|
||||
}
|
||||
|
||||
$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)
|
||||
|
@ -682,10 +800,6 @@ Function Run($payload) {
|
|||
|
||||
# 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)
|
||||
|
||||
If ($rc -eq 0) {
|
||||
|
@ -709,7 +823,6 @@ Function Run($payload) {
|
|||
|
||||
''' # end become_wrapper
|
||||
|
||||
|
||||
async_wrapper = br'''
|
||||
Set-StrictMode -Version 2
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
@ -1256,9 +1369,6 @@ class ShellModule(object):
|
|||
# env provider's limitations don't appear to be documented.
|
||||
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
|
||||
|
||||
def assert_safe_env_key(self, key):
|
||||
|
|
Loading…
Reference in a new issue