private static void FillUserNamePasswordLogonInfoBuffer(string domain, string username, string password, out int logonInfoSize, out SafeHGlobalHandle pLogonInfo) { //LogonInfo logonInfoSize = 0; int domainLength = 0; int usernameLength = 0; int passwordLength = 0; byte[] domainBytes = null; byte[] userNameBytes = null; byte[] passwordBytes = null; IntPtr LogonDomainNamePtr = IntPtr.Zero; IntPtr UsernamePtr = IntPtr.Zero; IntPtr PasswordPtr = IntPtr.Zero; if (!String.IsNullOrEmpty(domain)) { domainBytes = System.Text.Encoding.Unicode.GetBytes(domain); domainLength = domainBytes.Length; } if (!String.IsNullOrEmpty(username)) { userNameBytes = System.Text.Encoding.Unicode.GetBytes(username); usernameLength = userNameBytes.Length; } if (!String.IsNullOrEmpty(password)) { passwordBytes = System.Text.Encoding.Unicode.GetBytes(password); passwordLength = passwordBytes.Length; } logonInfoSize = checked (Marshal.SizeOf(typeof(INTERACTIVE_LOGON)) + usernameLength + passwordLength + domainLength); pLogonInfo = SafeHGlobalHandle.AllocHGlobal(logonInfoSize); unsafe { LogonDomainNamePtr = new IntPtr(pLogonInfo.DangerousGetHandle().ToInt64() + Marshal.SizeOf(typeof(INTERACTIVE_LOGON))); if (domainBytes != null) { Marshal.Copy(domainBytes, 0, LogonDomainNamePtr, domainLength); } UsernamePtr = new IntPtr(pLogonInfo.DangerousGetHandle().ToInt64() + Marshal.SizeOf(typeof(INTERACTIVE_LOGON)) + domainLength); if (userNameBytes != null) { Marshal.Copy(userNameBytes, 0, UsernamePtr, usernameLength); } PasswordPtr = new IntPtr(pLogonInfo.DangerousGetHandle().ToInt64() + Marshal.SizeOf(typeof(INTERACTIVE_LOGON)) + domainLength + usernameLength); if (passwordBytes != null) { Marshal.Copy(passwordBytes, 0, PasswordPtr, passwordLength); } INTERACTIVE_LOGON *pInfo = (INTERACTIVE_LOGON *)pLogonInfo.DangerousGetHandle().ToPointer(); pInfo->MessageType = (int)KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon; pInfo->LogonDomainName = new UNICODE_INTPTR_STRING(domainLength, domainLength + 1, LogonDomainNamePtr); pInfo->UserName = new UNICODE_INTPTR_STRING(usernameLength, usernameLength + 1, UsernamePtr); pInfo->Password = new UNICODE_INTPTR_STRING(passwordLength, passwordLength + 1, PasswordPtr); } }
internal static bool ValidateCredentials(string domain, string username, string password) { SafeHGlobalHandle pLogonInfo = null; try { int logonInfoSize; FillUserNamePasswordLogonInfoBuffer(domain, username, password, out logonInfoSize, out pLogonInfo); return(GetLsaLogonUserHandle(username, pLogonInfo, logonInfoSize)); } finally { pLogonInfo?.Close(); } }
public static SafeHGlobalHandle AllocHGlobal(int cb) { if (cb < 0) { throw new ArgumentOutOfRangeException("cb"); } SafeHGlobalHandle result = new SafeHGlobalHandle(); // CER RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { IntPtr ptr = Marshal.AllocHGlobal(cb); result.SetHandle(ptr); } return(result); }
private static bool GetLsaLogonUserHandle(string username, SafeHGlobalHandle pLogonInfo, int logonInfoSize) { if (null == pLogonInfo) { throw new ArgumentNullException("pLogonInfo"); } int status; SafeHGlobalHandle pSourceName = null; SafeHGlobalHandle pPackageName = null; SafeLsaLogonProcessHandle logonHandle = null; SafeLsaReturnBufferHandle profileHandle = null; SafeCloseHandle tokenHandle = null; try { UNICODE_INTPTR_STRING sourceName = NativeMethods.ConvertByteStringToUnicodeIntPtrString(NativeMethods.LsaSourceName, out pSourceName); logonHandle = NativeMethods.RegisterProcess(sourceName); RuntimeHelpers.PrepareConstrainedRegions(); //get packageId UNICODE_INTPTR_STRING packageName = NativeMethods.ConvertByteStringToUnicodeIntPtrString(NativeMethods.LsaNegotiateName, out pPackageName); uint packageId = 0; status = NativeMethods.LsaLookupAuthenticationPackage(logonHandle, ref packageName, out packageId); if (status < 0) // non-negative numbers indicate success { Trace.TraceError(string.Format("LsaLookupAuthenticationPackage failed for user {0} with status {1}", username, status)); throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(status)); } //get Source context TOKEN_SOURCE sourceContext = new TOKEN_SOURCE(); if (!NativeMethods.AllocateLocallyUniqueId(out sourceContext.SourceIdentifier)) { int dwErrorCode = Marshal.GetLastWin32Error(); Trace.TraceError(string.Format("AllocateLocallyUniqueId failed for user {0} with status {1}", username, dwErrorCode)); throw new Win32Exception(dwErrorCode); } sourceContext.Name = new char[8]; sourceContext.Name[0] = 'A'; sourceContext.Name[1] = 'D'; sourceContext.Name[2] = 'F'; sourceContext.Name[2] = 'S'; //other parameters QUOTA_LIMITS quotas = new QUOTA_LIMITS(); LUID logonId = new LUID(); uint profileBufferLength; int subStatus = 0; // Call LsaLogonUser status = NativeMethods.LsaLogonUser( logonHandle, ref sourceName, SecurityLogonType.Network, packageId, pLogonInfo.DangerousGetHandle(), (uint)logonInfoSize, IntPtr.Zero, ref sourceContext, out profileHandle, out profileBufferLength, out logonId, out tokenHandle, out quotas, out subStatus ); // LsaLogon has restriction (eg. password expired). SubStatus indicates the reason. if ((uint)status == NativeMethods.STATUS_ACCOUNT_RESTRICTION && subStatus < 0) { status = subStatus; Trace.TraceError(string.Format("Authentication failed for user {0} with account restriction error {1}", username, status)); return(false); } if (status < 0) // non-negative numbers indicate success { Trace.TraceError(string.Format("Authentication failed for user {0} with status {1}", username, status)); return(false); } if (subStatus < 0) // non-negative numbers indicate success { Trace.TraceError(string.Format("Authentication failed for user {0} with subStatus {1}", username, subStatus)); return(false); } return(true); } finally { pSourceName?.Close(); pPackageName?.Close(); tokenHandle?.Close(); profileHandle?.Close(); } }
//callers should delete the allocated memory by closing SafeHGlobalHandle pHandle internal static UNICODE_INTPTR_STRING ConvertByteStringToUnicodeIntPtrString(byte[] byteString, out SafeHGlobalHandle pHandle) { pHandle = SafeHGlobalHandle.AllocHGlobal(byteString.Length + 1); Marshal.Copy(byteString, 0, pHandle.DangerousGetHandle(), byteString.Length); return(new UNICODE_INTPTR_STRING(byteString.Length, byteString.Length + 1, pHandle.DangerousGetHandle())); }