File: //lib/python3.9/site-packages/ansible/module_utils/csharp/Ansible.AccessToken.cs
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
namespace Ansible.AccessToken
{
internal class NativeHelpers
{
[StructLayout(LayoutKind.Sequential)]
public struct LUID_AND_ATTRIBUTES
{
public Luid Luid;
public UInt32 Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct SID_AND_ATTRIBUTES
{
public IntPtr Sid;
public int Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public LUID_AND_ATTRIBUTES[] Privileges;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_USER
{
public SID_AND_ATTRIBUTES User;
}
public enum TokenInformationClass : uint
{
TokenUser = 1,
TokenPrivileges = 3,
TokenStatistics = 10,
TokenElevationType = 18,
TokenLinkedToken = 19,
}
}
internal class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(
IntPtr hObject);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool DuplicateTokenEx(
SafeNativeHandle hExistingToken,
TokenAccessLevels dwDesiredAccess,
IntPtr lpTokenAttributes,
SecurityImpersonationLevel ImpersonationLevel,
TokenType TokenType,
out SafeNativeHandle phNewToken);
[DllImport("kernel32.dll")]
public static extern SafeNativeHandle GetCurrentProcess();
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool GetTokenInformation(
SafeNativeHandle TokenHandle,
NativeHelpers.TokenInformationClass TokenInformationClass,
SafeMemoryBuffer TokenInformation,
UInt32 TokenInformationLength,
out UInt32 ReturnLength);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool ImpersonateLoggedOnUser(
SafeNativeHandle hToken);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUserW(
string lpszUsername,
string lpszDomain,
string lpszPassword,
LogonType dwLogonType,
LogonProvider dwLogonProvider,
out SafeNativeHandle phToken);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LookupPrivilegeNameW(
string lpSystemName,
ref Luid lpLuid,
StringBuilder lpName,
ref UInt32 cchName);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeNativeHandle OpenProcess(
ProcessAccessFlags dwDesiredAccess,
bool bInheritHandle,
UInt32 dwProcessId);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool OpenProcessToken(
SafeNativeHandle ProcessHandle,
TokenAccessLevels DesiredAccess,
out SafeNativeHandle TokenHandle);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool RevertToSelf();
}
internal class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeMemoryBuffer() : base(true) { }
public SafeMemoryBuffer(int cb) : base(true)
{
base.SetHandle(Marshal.AllocHGlobal(cb));
}
public SafeMemoryBuffer(IntPtr handle) : base(true)
{
base.SetHandle(handle);
}
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
return true;
}
}
public enum LogonProvider
{
Default,
WinNT35,
WinNT40,
WinNT50,
}
public enum LogonType
{
Interactive = 2,
Network = 3,
Batch = 4,
Service = 5,
Unlock = 7,
NetworkCleartext = 8,
NewCredentials = 9,
}
[Flags]
public enum PrivilegeAttributes : uint
{
Disabled = 0x00000000,
EnabledByDefault = 0x00000001,
Enabled = 0x00000002,
Removed = 0x00000004,
UsedForAccess = 0x80000000,
}
[Flags]
public enum ProcessAccessFlags : uint
{
Terminate = 0x00000001,
CreateThread = 0x00000002,
VmOperation = 0x00000008,
VmRead = 0x00000010,
VmWrite = 0x00000020,
DupHandle = 0x00000040,
CreateProcess = 0x00000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
SuspendResume = 0x00000800,
QueryLimitedInformation = 0x00001000,
Delete = 0x00010000,
ReadControl = 0x00020000,
WriteDac = 0x00040000,
WriteOwner = 0x00080000,
Synchronize = 0x00100000,
}
public enum SecurityImpersonationLevel
{
Anonymous,
Identification,
Impersonation,
Delegation,
}
public enum TokenElevationType
{
Default = 1,
Full,
Limited,
}
public enum TokenType
{
Primary = 1,
Impersonation,
}
[StructLayout(LayoutKind.Sequential)]
public struct Luid
{
public UInt32 LowPart;
public Int32 HighPart;
public static explicit operator UInt64(Luid l)
{
return (UInt64)((UInt64)l.HighPart << 32) | (UInt64)l.LowPart;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct TokenStatistics
{
public Luid TokenId;
public Luid AuthenticationId;
public Int64 ExpirationTime;
public TokenType TokenType;
public SecurityImpersonationLevel ImpersonationLevel;
public UInt32 DynamicCharged;
public UInt32 DynamicAvailable;
public UInt32 GroupCount;
public UInt32 PrivilegeCount;
public Luid ModifiedId;
}
public class PrivilegeInfo
{
public string Name;
public PrivilegeAttributes Attributes;
internal PrivilegeInfo(NativeHelpers.LUID_AND_ATTRIBUTES la)
{
Name = TokenUtil.GetPrivilegeName(la.Luid);
Attributes = (PrivilegeAttributes)la.Attributes;
}
}
public class SafeNativeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeNativeHandle() : base(true) { }
public SafeNativeHandle(IntPtr handle) : base(true) { this.handle = handle; }
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(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} - 0x{2:X8})", message, base.Message, errorCode);
}
public override string Message { get { return _msg; } }
public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
}
public class TokenUtil
{
public static SafeNativeHandle DuplicateToken(SafeNativeHandle hToken, TokenAccessLevels access,
SecurityImpersonationLevel impersonationLevel, TokenType tokenType)
{
SafeNativeHandle dupToken;
if (!NativeMethods.DuplicateTokenEx(hToken, access, IntPtr.Zero, impersonationLevel, tokenType, out dupToken))
throw new Win32Exception("Failed to duplicate token");
return dupToken;
}
public static SecurityIdentifier GetTokenUser(SafeNativeHandle hToken)
{
using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken,
NativeHelpers.TokenInformationClass.TokenUser))
{
NativeHelpers.TOKEN_USER tokenUser = (NativeHelpers.TOKEN_USER)Marshal.PtrToStructure(
tokenInfo.DangerousGetHandle(),
typeof(NativeHelpers.TOKEN_USER));
return new SecurityIdentifier(tokenUser.User.Sid);
}
}
public static List<PrivilegeInfo> GetTokenPrivileges(SafeNativeHandle hToken)
{
using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken,
NativeHelpers.TokenInformationClass.TokenPrivileges))
{
NativeHelpers.TOKEN_PRIVILEGES tokenPrivs = (NativeHelpers.TOKEN_PRIVILEGES)Marshal.PtrToStructure(
tokenInfo.DangerousGetHandle(),
typeof(NativeHelpers.TOKEN_PRIVILEGES));
NativeHelpers.LUID_AND_ATTRIBUTES[] luidAttrs =
new NativeHelpers.LUID_AND_ATTRIBUTES[tokenPrivs.PrivilegeCount];
PtrToStructureArray(luidAttrs, IntPtr.Add(tokenInfo.DangerousGetHandle(),
Marshal.SizeOf(tokenPrivs.PrivilegeCount)));
return luidAttrs.Select(la => new PrivilegeInfo(la)).ToList();
}
}
public static TokenStatistics GetTokenStatistics(SafeNativeHandle hToken)
{
using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken,
NativeHelpers.TokenInformationClass.TokenStatistics))
{
TokenStatistics tokenStats = (TokenStatistics)Marshal.PtrToStructure(
tokenInfo.DangerousGetHandle(),
typeof(TokenStatistics));
return tokenStats;
}
}
public static TokenElevationType GetTokenElevationType(SafeNativeHandle hToken)
{
using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken,
NativeHelpers.TokenInformationClass.TokenElevationType))
{
return (TokenElevationType)Marshal.ReadInt32(tokenInfo.DangerousGetHandle());
}
}
public static SafeNativeHandle GetTokenLinkedToken(SafeNativeHandle hToken)
{
using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken,
NativeHelpers.TokenInformationClass.TokenLinkedToken))
{
return new SafeNativeHandle(Marshal.ReadIntPtr(tokenInfo.DangerousGetHandle()));
}
}
public static IEnumerable<SafeNativeHandle> EnumerateUserTokens(SecurityIdentifier sid,
TokenAccessLevels access = TokenAccessLevels.Query)
{
foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses())
{
// We always need the Query access level so we can query the TokenUser
using (process)
using (SafeNativeHandle hToken = TryOpenAccessToken(process, access | TokenAccessLevels.Query))
{
if (hToken == null)
continue;
if (!sid.Equals(GetTokenUser(hToken)))
continue;
yield return hToken;
}
}
}
public static void ImpersonateToken(SafeNativeHandle hToken)
{
if (!NativeMethods.ImpersonateLoggedOnUser(hToken))
throw new Win32Exception("Failed to impersonate token");
}
public static SafeNativeHandle LogonUser(string username, string domain, string password, LogonType logonType,
LogonProvider logonProvider)
{
SafeNativeHandle hToken;
if (!NativeMethods.LogonUserW(username, domain, password, logonType, logonProvider, out hToken))
throw new Win32Exception(String.Format("Failed to logon {0}",
String.IsNullOrEmpty(domain) ? username : domain + "\\" + username));
return hToken;
}
public static SafeNativeHandle OpenProcess()
{
return NativeMethods.GetCurrentProcess();
}
public static SafeNativeHandle OpenProcess(Int32 pid, ProcessAccessFlags access, bool inherit)
{
SafeNativeHandle hProcess = NativeMethods.OpenProcess(access, inherit, (UInt32)pid);
if (hProcess.IsInvalid)
throw new Win32Exception(String.Format("Failed to open process {0} with access {1}",
pid, access.ToString()));
return hProcess;
}
public static SafeNativeHandle OpenProcessToken(SafeNativeHandle hProcess, TokenAccessLevels access)
{
SafeNativeHandle hToken;
if (!NativeMethods.OpenProcessToken(hProcess, access, out hToken))
throw new Win32Exception(String.Format("Failed to open process token with access {0}",
access.ToString()));
return hToken;
}
public static void RevertToSelf()
{
if (!NativeMethods.RevertToSelf())
throw new Win32Exception("Failed to revert thread impersonation");
}
internal static string GetPrivilegeName(Luid luid)
{
UInt32 nameLen = 0;
NativeMethods.LookupPrivilegeNameW(null, ref luid, null, ref nameLen);
StringBuilder name = new StringBuilder((int)(nameLen + 1));
if (!NativeMethods.LookupPrivilegeNameW(null, ref luid, name, ref nameLen))
throw new Win32Exception("LookupPrivilegeName() failed");
return name.ToString();
}
private static SafeMemoryBuffer GetTokenInformation(SafeNativeHandle hToken,
NativeHelpers.TokenInformationClass infoClass)
{
UInt32 tokenLength;
bool res = NativeMethods.GetTokenInformation(hToken, infoClass, new SafeMemoryBuffer(IntPtr.Zero), 0,
out tokenLength);
int errCode = Marshal.GetLastWin32Error();
if (!res && errCode != 24 && errCode != 122) // ERROR_INSUFFICIENT_BUFFER, ERROR_BAD_LENGTH
throw new Win32Exception(errCode, String.Format("GetTokenInformation({0}) failed to get buffer length",
infoClass.ToString()));
SafeMemoryBuffer tokenInfo = new SafeMemoryBuffer((int)tokenLength);
if (!NativeMethods.GetTokenInformation(hToken, infoClass, tokenInfo, tokenLength, out tokenLength))
throw new Win32Exception(String.Format("GetTokenInformation({0}) failed", infoClass.ToString()));
return tokenInfo;
}
private static void PtrToStructureArray<T>(T[] array, IntPtr ptr)
{
IntPtr ptrOffset = ptr;
for (int i = 0; i < array.Length; i++, ptrOffset = IntPtr.Add(ptrOffset, Marshal.SizeOf(typeof(T))))
array[i] = (T)Marshal.PtrToStructure(ptrOffset, typeof(T));
}
private static SafeNativeHandle TryOpenAccessToken(System.Diagnostics.Process process, TokenAccessLevels access)
{
try
{
using (SafeNativeHandle hProcess = OpenProcess(process.Id, ProcessAccessFlags.QueryInformation, false))
return OpenProcessToken(hProcess, access);
}
catch (Win32Exception)
{
return null;
}
}
}
}