Last active
October 8, 2018 19:26
-
-
Save fritzy/1b2c1f45afc4ecaa54263cd92d5cea96 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
using System.Security.Principal; | |
using System.Security.Cryptography.X509Certificates; | |
using System.Collections.Generic; | |
namespace LoginImpersonate | |
{ | |
internal class Impersonation : IDisposable | |
{ | |
public bool valid; | |
public WindowsImpersonationContext context; | |
internal Impersonation(bool inValid, WindowsImpersonationContext inContext) | |
{ | |
valid = inValid; | |
context = inContext; | |
} | |
public void Dispose() | |
{ | |
context.Dispose(); | |
} | |
} | |
class LoginImpersonate | |
{ | |
internal static int CertCredential = 1; | |
internal static int LOGON32_LOGON_INTERACTIVE = 2; | |
internal static int LOGON32_PROVIDER_WINNT50 = 3; | |
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | |
public static extern bool CredMarshalCredential( | |
int credType, | |
IntPtr credential, | |
out IntPtr marshaledCredential | |
); | |
[DllImport("advapi32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
internal static extern bool LogonUser( | |
[MarshalAs(UnmanagedType.LPStr)] string pszUserName, | |
[MarshalAs(UnmanagedType.LPStr)] string pszDomain, | |
[MarshalAs(UnmanagedType.LPStr)] string pszPassword, | |
int dwLogonType, | |
int dwLogonProvider, | |
ref IntPtr phToken); | |
[DllImport("user32.dll")] | |
private static extern IntPtr GetDC(IntPtr hWnd); | |
[StructLayout(LayoutKind.Sequential)] | |
internal struct CERT_CREDENTIAL_INFO | |
{ | |
public uint cbSize; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] | |
public byte[] rgbHashOfCert; | |
} | |
[DllImport("kernel32.dll", SetLastError = true)] | |
static extern bool CloseHandle(IntPtr hHandle); | |
public string marshaledUser; | |
internal string authPin; | |
internal Dictionary<string, (DateTime expire, IntPtr handle)> loginTokens = new Dictionary<string, (DateTime expire, IntPtr handle)>(); | |
//var pin = "135791"; | |
~LoginImpersonate() | |
{ | |
string[] keys = new string[loginTokens.Keys.Count]; | |
loginTokens.Keys.CopyTo(keys, 0); | |
foreach(var key in keys) | |
{ | |
(DateTime expire, IntPtr handle) entry; | |
loginTokens.TryGetValue(key, out entry); | |
CloseHandle(entry.handle); | |
loginTokens.Remove(key); | |
} | |
} | |
public (bool, string) LoginWithUser(string user, string domain, string pass) | |
{ | |
IntPtr token = IntPtr.Zero; | |
var logon = LogonUser( | |
user, | |
domain, | |
pass, | |
LOGON32_LOGON_INTERACTIVE, | |
LOGON32_PROVIDER_WINNT50, | |
ref token | |
); | |
if (logon) | |
{ | |
return (logon, addLogin(token)); | |
} | |
return (false, null); | |
} | |
internal string addLogin(IntPtr login) | |
{ | |
expireLogins(); | |
string lookup = Guid.NewGuid().ToString(); | |
DateTime expire = DateTime.Now.AddMinutes(10); | |
loginTokens.Add(lookup, (expire, login)); | |
return lookup; | |
} | |
internal IntPtr getLogin(string lookup) | |
{ | |
expireLogins(); | |
(DateTime expire, IntPtr handle) entry; | |
if (lookup == null) return IntPtr.Zero; | |
loginTokens.TryGetValue(lookup, out entry); | |
return entry.handle; | |
} | |
internal void expireLogins() | |
{ | |
List<string> removeKeys = new List<string>(); | |
foreach(var entry in loginTokens) | |
{ | |
if (DateTime.Compare(DateTime.Now, entry.Value.expire) > 0) | |
{ | |
CloseHandle(entry.Value.handle); | |
removeKeys.Add(entry.Key); | |
} | |
} | |
foreach (var key in removeKeys) | |
{ | |
loginTokens.Remove(key); | |
} | |
} | |
public (bool, string) LoginWithCert(X509Certificate2 cert, string pin) | |
{ | |
var hash = cert.GetCertHash(); | |
authPin = pin; | |
CERT_CREDENTIAL_INFO certInfo = | |
new CERT_CREDENTIAL_INFO(); | |
certInfo.cbSize = (uint)Marshal.SizeOf(typeof(CERT_CREDENTIAL_INFO)); | |
certInfo.rgbHashOfCert = cert.GetCertHash(); | |
int size = Marshal.SizeOf(certInfo); | |
IntPtr pCertInfo = Marshal.AllocHGlobal(size); | |
Marshal.StructureToPtr(certInfo, pCertInfo, false); | |
IntPtr marshaledCredential = IntPtr.Zero; | |
bool isMarshaled = | |
CredMarshalCredential(CertCredential, | |
pCertInfo, | |
out marshaledCredential); | |
var marshaledUser = Marshal.PtrToStringAuto(marshaledCredential); | |
var token = IntPtr.Zero; | |
var logon = LogonUser( | |
marshaledUser, | |
null, | |
authPin, | |
LOGON32_LOGON_INTERACTIVE, | |
LOGON32_PROVIDER_WINNT50, | |
ref token | |
); | |
if (logon) | |
{ | |
return (true, addLogin(token)); | |
} | |
return (false, null); | |
} | |
public Impersonation Impersonate(string lookup) | |
{ | |
var login = getLogin(lookup); | |
bool valid = login != IntPtr.Zero; | |
var impersonate = WindowsIdentity.Impersonate(getLogin(lookup)); | |
return new Impersonation(valid, impersonate); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment