summaryrefslogtreecommitdiffstats
path: root/lib/ansible/module_utils/csharp/Ansible.AccessToken.cs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/module_utils/csharp/Ansible.AccessToken.cs')
-rw-r--r--lib/ansible/module_utils/csharp/Ansible.AccessToken.cs460
1 files changed, 460 insertions, 0 deletions
diff --git a/lib/ansible/module_utils/csharp/Ansible.AccessToken.cs b/lib/ansible/module_utils/csharp/Ansible.AccessToken.cs
new file mode 100644
index 0000000..48c4a19
--- /dev/null
+++ b/lib/ansible/module_utils/csharp/Ansible.AccessToken.cs
@@ -0,0 +1,460 @@
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.ConstrainedExecution;
+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);
+ }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ 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; }
+
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+ 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;
+ }
+ }
+ }
+}