mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-24 11:21:25 -07:00
win_become: get admin token and fix async (#32485)
* win_become: make it easier to become with an admin token * Fixed up pep8 whitespace * fix for Server 2008 * Added support for async and become on newer hosts and fix warnings
This commit is contained in:
parent
9cfd0a58b0
commit
15b492ca57
2 changed files with 387 additions and 113 deletions
|
@ -171,9 +171,12 @@ Set-StrictMode -Version 2
|
|||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$helper_def = @"
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
|
@ -212,9 +215,9 @@ namespace Ansible
|
|||
public Int16 wShowWindow;
|
||||
public Int16 cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
public SafeFileHandle hStdInput;
|
||||
public SafeFileHandle hStdOutput;
|
||||
public SafeFileHandle hStdError;
|
||||
public STARTUPINFO()
|
||||
{
|
||||
cb = Marshal.SizeOf(this);
|
||||
|
@ -254,6 +257,42 @@ namespace Ansible
|
|||
public SID_AND_ATTRIBUTES User;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct IO_COUNTERS
|
||||
{
|
||||
public UInt64 ReadOperationCount;
|
||||
public UInt64 WriteOperationCount;
|
||||
public UInt64 OtherOperationCount;
|
||||
public UInt64 ReadTransferCount;
|
||||
public UInt64 WriteTransferCount;
|
||||
public UInt64 OtherTransferCount;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct JOBOBJECT_BASIC_LIMIT_INFORMATION
|
||||
{
|
||||
public UInt64 PerProcessUserTimeLimit;
|
||||
public UInt64 PerJobUserTimeLimit;
|
||||
public LimitFlags LimitFlags;
|
||||
public UIntPtr MinimumWorkingSetSize;
|
||||
public UIntPtr MaximumWorkingSetSize;
|
||||
public UInt32 ActiveProcessLimit;
|
||||
public UIntPtr Affinity;
|
||||
public UInt32 PriorityClass;
|
||||
public UInt32 SchedulingClass;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
|
||||
{
|
||||
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
|
||||
public IO_COUNTERS IoInfo;
|
||||
public UIntPtr ProcessMemoryLimit;
|
||||
public UIntPtr JobMemoryLimit;
|
||||
public UIntPtr PeakProcessMemoryUsed;
|
||||
public UIntPtr PeakJobMemoryUsed;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum StartupInfoFlags : uint
|
||||
{
|
||||
|
@ -263,6 +302,7 @@ namespace Ansible
|
|||
[Flags]
|
||||
public enum CreationFlags : uint
|
||||
{
|
||||
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
|
||||
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
|
||||
CREATE_NEW_CONSOLE = 0x00000010,
|
||||
CREATE_NEW_PROCESS_GROUP = 0x00000200,
|
||||
|
@ -353,11 +393,35 @@ namespace Ansible
|
|||
TokenImpersonation
|
||||
}
|
||||
|
||||
enum JobObjectInfoType
|
||||
{
|
||||
AssociateCompletionPortInformation = 7,
|
||||
BasicLimitInformation = 2,
|
||||
BasicUIRestrictions = 4,
|
||||
EndOfJobTimeInformation = 6,
|
||||
ExtendedLimitInformation = 9,
|
||||
SecurityLimitInformation = 5,
|
||||
GroupInformation = 11
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum ThreadAccessRights : uint
|
||||
{
|
||||
SUSPEND_RESUME = 0x0002
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum LimitFlags : uint
|
||||
{
|
||||
JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800,
|
||||
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000
|
||||
}
|
||||
|
||||
class NativeWaitHandle : WaitHandle
|
||||
{
|
||||
public NativeWaitHandle(IntPtr handle)
|
||||
{
|
||||
this.Handle = handle;
|
||||
this.SafeWaitHandle = new SafeWaitHandle(handle, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,6 +444,69 @@ namespace Ansible
|
|||
public uint ExitCode { get; internal set; }
|
||||
}
|
||||
|
||||
public class Job : IDisposable
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr CreateJobObject(
|
||||
IntPtr lpJobAttributes,
|
||||
string lpName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool SetInformationJobObject(
|
||||
IntPtr hJob,
|
||||
JobObjectInfoType JobObjectInfoClass,
|
||||
IntPtr lpJobObjectInfo,
|
||||
UInt32 cbJobObjectInfoLength);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool AssignProcessToJobObject(
|
||||
IntPtr hJob,
|
||||
IntPtr hProcess);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool CloseHandle(
|
||||
IntPtr hObject);
|
||||
|
||||
private IntPtr handle;
|
||||
|
||||
public Job()
|
||||
{
|
||||
handle = CreateJobObject(IntPtr.Zero, null);
|
||||
if (handle == IntPtr.Zero)
|
||||
throw new Win32Exception("CreateJobObject() failed");
|
||||
|
||||
JOBOBJECT_BASIC_LIMIT_INFORMATION jobInfo = new JOBOBJECT_BASIC_LIMIT_INFORMATION();
|
||||
jobInfo.LimitFlags = LimitFlags.JOB_OBJECT_LIMIT_BREAKAWAY_OK | LimitFlags.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedJobInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
|
||||
extendedJobInfo.BasicLimitInformation = jobInfo;
|
||||
|
||||
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
|
||||
IntPtr pExtendedJobInfo = Marshal.AllocHGlobal(length);
|
||||
Marshal.StructureToPtr(extendedJobInfo, pExtendedJobInfo, false);
|
||||
|
||||
if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, pExtendedJobInfo, (UInt32)length))
|
||||
throw new Win32Exception("SetInformationJobObject() failed");
|
||||
}
|
||||
|
||||
public void AssignProcess(IntPtr processHandle)
|
||||
{
|
||||
if (!AssignProcessToJobObject(handle, processHandle))
|
||||
throw new Win32Exception("AssignProcessToJobObject() failed");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class BecomeUtil
|
||||
{
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
|
@ -407,14 +534,14 @@ namespace Ansible
|
|||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool CreatePipe(
|
||||
out IntPtr hReadPipe,
|
||||
out IntPtr hWritePipe,
|
||||
out SafeFileHandle hReadPipe,
|
||||
out SafeFileHandle hWritePipe,
|
||||
SECURITY_ATTRIBUTES lpPipeAttributes,
|
||||
uint nSize);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern bool SetHandleInformation(
|
||||
IntPtr hObject,
|
||||
SafeFileHandle hObject,
|
||||
HandleFlags dwMask,
|
||||
int dwFlags);
|
||||
|
||||
|
@ -431,7 +558,8 @@ namespace Ansible
|
|||
private static extern IntPtr GetProcessWindowStation();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GetThreadDesktop(int dwThreadId);
|
||||
private static extern IntPtr GetThreadDesktop(
|
||||
int dwThreadId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern int GetCurrentThreadId();
|
||||
|
@ -480,17 +608,27 @@ namespace Ansible
|
|||
out IntPtr phNewToken);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool ImpersonateLoggedOnUser(
|
||||
private static extern bool ImpersonateLoggedOnUser(
|
||||
IntPtr hToken);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool RevertToSelf();
|
||||
private static extern bool RevertToSelf();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern SafeFileHandle OpenThread(
|
||||
ThreadAccessRights dwDesiredAccess,
|
||||
bool bInheritHandle,
|
||||
int dwThreadId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern int ResumeThread(
|
||||
SafeHandle hThread);
|
||||
|
||||
public static CommandResult RunAsUser(string username, string password, string lpCommandLine, string lpCurrentDirectory, string stdinInput)
|
||||
{
|
||||
SecurityIdentifier account = GetBecomeSid(username);
|
||||
|
||||
CreationFlags startup_flags = CreationFlags.CREATE_UNICODE_ENVIRONMENT;
|
||||
CreationFlags startup_flags = CreationFlags.CREATE_UNICODE_ENVIRONMENT | CreationFlags.CREATE_BREAKAWAY_FROM_JOB | CreationFlags.CREATE_SUSPENDED;
|
||||
|
||||
STARTUPINFOEX si = new STARTUPINFOEX();
|
||||
si.startupInfo.dwFlags = (int)StartupInfoFlags.USESTDHANDLES;
|
||||
|
@ -499,7 +637,7 @@ namespace Ansible
|
|||
pipesec.bInheritHandle = true;
|
||||
|
||||
// Create the stdout, stderr and stdin pipes used in the process and add to the startupInfo
|
||||
IntPtr stdout_read, stdout_write, stderr_read, stderr_write, stdin_read, stdin_write = IntPtr.Zero;
|
||||
SafeFileHandle stdout_read, stdout_write, stderr_read, stderr_write, stdin_read, stdin_write;
|
||||
if (!CreatePipe(out stdout_read, out stdout_write, pipesec, 0))
|
||||
throw new Win32Exception("STDOUT pipe setup failed");
|
||||
if (!SetHandleInformation(stdout_read, HandleFlags.INHERIT, 0))
|
||||
|
@ -521,7 +659,7 @@ namespace Ansible
|
|||
|
||||
// Setup the stdin buffer
|
||||
UTF8Encoding utf8_encoding = new UTF8Encoding(false);
|
||||
FileStream stdin_fs = new FileStream(stdin_write, FileAccess.Write, true, 32768);
|
||||
FileStream stdin_fs = new FileStream(stdin_write, FileAccess.Write, 32768);
|
||||
StreamWriter stdin = new StreamWriter(stdin_fs, utf8_encoding, 32768);
|
||||
|
||||
// Create the environment block if set
|
||||
|
@ -554,26 +692,44 @@ namespace Ansible
|
|||
if (!launch_success)
|
||||
throw new Win32Exception("Failed to start become process");
|
||||
|
||||
// Setup the output buffers and get stdout/stderr
|
||||
FileStream stdout_fs = new FileStream(stdout_read, FileAccess.Read, true, 4096);
|
||||
StreamReader stdout = new StreamReader(stdout_fs, utf8_encoding, true, 4096);
|
||||
CloseHandle(stdout_write);
|
||||
|
||||
FileStream stderr_fs = new FileStream(stderr_read, FileAccess.Read, true, 4096);
|
||||
StreamReader stderr = new StreamReader(stderr_fs, utf8_encoding, true, 4096);
|
||||
CloseHandle(stderr_write);
|
||||
|
||||
stdin.WriteLine(stdinInput);
|
||||
stdin.Close();
|
||||
|
||||
string stdout_str, stderr_str = null;
|
||||
GetProcessOutput(stdout, stderr, out stdout_str, out stderr_str);
|
||||
uint rc = GetProcessExitCode(pi.hProcess);
|
||||
// If 2012/8+ OS, create new job with JOB_OBJECT_LIMIT_BREAKAWAY_OK
|
||||
// so that async can work
|
||||
Job job = null;
|
||||
if (Environment.OSVersion.Version >= new Version("6.2"))
|
||||
{
|
||||
job = new Job();
|
||||
job.AssignProcess(pi.hProcess);
|
||||
}
|
||||
ResumeProcessById(pi.dwProcessId);
|
||||
|
||||
CommandResult result = new CommandResult();
|
||||
result.StandardOut = stdout_str;
|
||||
result.StandardError = stderr_str;
|
||||
result.ExitCode = rc;
|
||||
try
|
||||
{
|
||||
// Setup the output buffers and get stdout/stderr
|
||||
FileStream stdout_fs = new FileStream(stdout_read, FileAccess.Read, 4096);
|
||||
StreamReader stdout = new StreamReader(stdout_fs, utf8_encoding, true, 4096);
|
||||
stdout_write.Close();
|
||||
|
||||
FileStream stderr_fs = new FileStream(stderr_read, FileAccess.Read, 4096);
|
||||
StreamReader stderr = new StreamReader(stderr_fs, utf8_encoding, true, 4096);
|
||||
stderr_write.Close();
|
||||
|
||||
stdin.WriteLine(stdinInput);
|
||||
stdin.Close();
|
||||
|
||||
string stdout_str, stderr_str = null;
|
||||
GetProcessOutput(stdout, stderr, out stdout_str, out stderr_str);
|
||||
UInt32 rc = GetProcessExitCode(pi.hProcess);
|
||||
|
||||
result.StandardOut = stdout_str;
|
||||
result.StandardError = stderr_str;
|
||||
result.ExitCode = rc;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (job != null)
|
||||
job.Dispose();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -604,71 +760,64 @@ namespace Ansible
|
|||
|
||||
GrantAccessToWindowStationAndDesktop(account);
|
||||
string account_sid = account.ToString();
|
||||
bool impersonated = false;
|
||||
IntPtr hSystemTokenDup = IntPtr.Zero;
|
||||
|
||||
// Try to get SYSTEM token handle so we can impersonate to get full admin token
|
||||
IntPtr hSystemToken = GetSystemUserHandle();
|
||||
if (hSystemToken == IntPtr.Zero && service_sids.Contains(account_sid))
|
||||
{
|
||||
// We need the SYSTEM token if we want to become one of those accounts, fail here
|
||||
throw new Win32Exception("Failed to get token for NT AUTHORITY\\SYSTEM");
|
||||
}
|
||||
else if (hSystemToken != IntPtr.Zero)
|
||||
{
|
||||
// We have the token, need to duplicate and impersonate
|
||||
bool dupResult = DuplicateTokenEx(
|
||||
hSystemToken,
|
||||
TokenAccessLevels.MaximumAllowed,
|
||||
IntPtr.Zero,
|
||||
SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
|
||||
TOKEN_TYPE.TokenPrimary,
|
||||
out hSystemTokenDup);
|
||||
int lastError = Marshal.GetLastWin32Error();
|
||||
CloseHandle(hSystemToken);
|
||||
|
||||
if (!dupResult && service_sids.Contains(account_sid))
|
||||
throw new Win32Exception(lastError, "Failed to duplicate token for NT AUTHORITY\\SYSTEM");
|
||||
else if (dupResult && account_sid != "S-1-5-18")
|
||||
{
|
||||
if (ImpersonateLoggedOnUser(hSystemTokenDup))
|
||||
impersonated = true;
|
||||
else if (service_sids.Contains(account_sid))
|
||||
throw new Win32Exception("Failed to impersonate as SYSTEM account");
|
||||
}
|
||||
}
|
||||
|
||||
LogonType logonType;
|
||||
string domain = null;
|
||||
if (service_sids.Contains(account_sid))
|
||||
{
|
||||
// We are trying to become to a service account
|
||||
IntPtr hToken = GetUserHandle();
|
||||
if (hToken == IntPtr.Zero)
|
||||
throw new Exception("Failed to get token for NT AUTHORITY\\SYSTEM");
|
||||
|
||||
IntPtr hTokenDup = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
if (!DuplicateTokenEx(
|
||||
hToken,
|
||||
TokenAccessLevels.MaximumAllowed,
|
||||
IntPtr.Zero,
|
||||
SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
|
||||
TOKEN_TYPE.TokenPrimary,
|
||||
out hTokenDup))
|
||||
{
|
||||
throw new Win32Exception("Failed to duplicate the SYSTEM account token");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
|
||||
string lpszDomain = "NT AUTHORITY";
|
||||
string lpszUsername = null;
|
||||
logonType = LogonType.LOGON32_LOGON_SERVICE;
|
||||
domain = "NT AUTHORITY";
|
||||
password = null;
|
||||
switch (account_sid)
|
||||
{
|
||||
case "S-1-5-18":
|
||||
tokens.Add(hTokenDup);
|
||||
tokens.Add(hSystemTokenDup);
|
||||
return tokens;
|
||||
case "S-1-5-19":
|
||||
lpszUsername = "LocalService";
|
||||
username = "LocalService";
|
||||
break;
|
||||
case "S-1-5-20":
|
||||
lpszUsername = "NetworkService";
|
||||
username = "NetworkService";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ImpersonateLoggedOnUser(hTokenDup))
|
||||
throw new Win32Exception("Failed to impersonate as SYSTEM account");
|
||||
|
||||
IntPtr newToken = IntPtr.Zero;
|
||||
if (!LogonUser(
|
||||
lpszUsername,
|
||||
lpszDomain,
|
||||
null,
|
||||
LogonType.LOGON32_LOGON_SERVICE,
|
||||
LogonProvider.LOGON32_PROVIDER_DEFAULT,
|
||||
out newToken))
|
||||
{
|
||||
throw new Win32Exception("LogonUser failed");
|
||||
}
|
||||
|
||||
RevertToSelf();
|
||||
tokens.Add(newToken);
|
||||
return tokens;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are trying to become a local or domain account
|
||||
string domain = null;
|
||||
logonType = LogonType.LOGON32_LOGON_INTERACTIVE;
|
||||
if (username.Contains(@"\"))
|
||||
{
|
||||
var user_split = username.Split(Convert.ToChar(@"\"));
|
||||
|
@ -679,31 +828,35 @@ namespace Ansible
|
|||
domain = null;
|
||||
else
|
||||
domain = ".";
|
||||
|
||||
// Logon and get the token
|
||||
IntPtr hToken = IntPtr.Zero;
|
||||
if (!LogonUser(
|
||||
username,
|
||||
domain,
|
||||
password,
|
||||
LogonType.LOGON32_LOGON_INTERACTIVE,
|
||||
LogonProvider.LOGON32_PROVIDER_DEFAULT,
|
||||
out hToken))
|
||||
{
|
||||
throw new Win32Exception("LogonUser failed");
|
||||
}
|
||||
|
||||
// Get the elevate token
|
||||
IntPtr hTokenElevated = GetElevatedToken(hToken);
|
||||
|
||||
tokens.Add(hTokenElevated);
|
||||
tokens.Add(hToken);
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
IntPtr hToken = IntPtr.Zero;
|
||||
if (!LogonUser(
|
||||
username,
|
||||
domain,
|
||||
password,
|
||||
logonType,
|
||||
LogonProvider.LOGON32_PROVIDER_DEFAULT,
|
||||
out hToken))
|
||||
{
|
||||
throw new Win32Exception("LogonUser failed");
|
||||
}
|
||||
|
||||
if (!service_sids.Contains(account_sid))
|
||||
{
|
||||
// Try and get the elevated token for local/domain account
|
||||
IntPtr hTokenElevated = GetElevatedToken(hToken);
|
||||
tokens.Add(hTokenElevated);
|
||||
}
|
||||
tokens.Add(hToken);
|
||||
|
||||
if (impersonated)
|
||||
RevertToSelf();
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static IntPtr GetUserHandle()
|
||||
private static IntPtr GetSystemUserHandle()
|
||||
{
|
||||
uint array_byte_size = 1024 * sizeof(uint);
|
||||
IntPtr[] pids = new IntPtr[1024];
|
||||
|
@ -864,6 +1017,44 @@ namespace Ansible
|
|||
security.Persist(safeHandle, AccessControlSections.Access);
|
||||
}
|
||||
|
||||
private static void ResumeThreadById(int threadId)
|
||||
{
|
||||
var threadHandle = OpenThread(ThreadAccessRights.SUSPEND_RESUME, false, threadId);
|
||||
if (threadHandle.IsInvalid)
|
||||
throw new Win32Exception(String.Format("Thread ID {0} is invalid", threadId));
|
||||
|
||||
try
|
||||
{
|
||||
if (ResumeThread(threadHandle) == -1)
|
||||
throw new Win32Exception(String.Format("Thread ID {0} cannot be resumed", threadId));
|
||||
}
|
||||
finally
|
||||
{
|
||||
threadHandle.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ResumeProcessById(int pid)
|
||||
{
|
||||
var proc = Process.GetProcessById(pid);
|
||||
|
||||
// wait for at least one suspended thread in the process (this handles possible slow startup race where
|
||||
// primary thread of created-suspended process has not yet become runnable)
|
||||
var retryCount = 0;
|
||||
while (!proc.Threads.OfType<ProcessThread>().Any(t => t.ThreadState == System.Diagnostics.ThreadState.Wait &&
|
||||
t.WaitReason == ThreadWaitReason.Suspended))
|
||||
{
|
||||
proc.Refresh();
|
||||
Thread.Sleep(50);
|
||||
if (retryCount > 100)
|
||||
throw new InvalidOperationException(String.Format("No threads were suspended in target PID {0} after 5s", pid));
|
||||
}
|
||||
|
||||
foreach (var thread in proc.Threads.OfType<ProcessThread>().Where(t => t.ThreadState == System.Diagnostics.ThreadState.Wait &&
|
||||
t.WaitReason == ThreadWaitReason.Suspended))
|
||||
ResumeThreadById(thread.Id);
|
||||
}
|
||||
|
||||
private class GenericSecurity : NativeObjectSecurity
|
||||
{
|
||||
public GenericSecurity(bool isContainer, ResourceType resType, SafeHandle objectHandle, AccessControlSections sectionsRequested)
|
||||
|
@ -969,8 +1160,7 @@ Function Run($payload) {
|
|||
$username = $payload.become_user
|
||||
$password = $payload.become_password
|
||||
|
||||
# FUTURE: convert to SafeHandle so we can stop ignoring warnings?
|
||||
Add-Type -TypeDefinition $helper_def -Debug:$false -IgnoreWarnings
|
||||
Add-Type -TypeDefinition $helper_def -Debug:$false
|
||||
|
||||
# NB: CreateProcessWithTokenW commandline maxes out at 1024 chars, must bootstrap via filesystem
|
||||
$temp = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName() + ".ps1")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue