Skip to content

Instantly share code, notes, and snippets.

@fritzy
Last active October 8, 2018 19:26
Show Gist options
  • Save fritzy/1b2c1f45afc4ecaa54263cd92d5cea96 to your computer and use it in GitHub Desktop.
Save fritzy/1b2c1f45afc4ecaa54263cd92d5cea96 to your computer and use it in GitHub Desktop.
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