internal TokenSource(IntPtr ptr) { TOKEN_SOURCE ts = (TOKEN_SOURCE)Marshal.PtrToStructure(ptr, typeof(TOKEN_SOURCE)); _name = new string(ts.Name); _luid = new Luid(ts.Indentifier); }
public static void CreateNewSession() { var kli = new KERB_INTERACTIVE_LOGON { MessageType = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon, UserName = "", Password = "" }; IntPtr pluid; IntPtr lsaHan; uint authPackID; IntPtr kerbLogInfo; var logonProc = new LSA_STRING { Buffer = Marshal.StringToHGlobalAuto("InstaLogon"), Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")), MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")) }; var originName = new LSA_STRING { Buffer = Marshal.StringToHGlobalAuto("InstaLogon"), Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")), MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")) }; var authPackage = new LSA_STRING { Buffer = Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A"), Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A")), MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A")) }; var hLogonProc = Marshal.AllocHGlobal(Marshal.SizeOf(logonProc)); Marshal.StructureToPtr(logonProc, hLogonProc, false); ADVAPI32.AllocateLocallyUniqueId(out pluid); LsaConnectUntrusted(out lsaHan); //SECUR32.LsaRegisterLogonProcess(hLogonProc, out lsaHan, out secMode); LsaLookupAuthenticationPackage(lsaHan, ref authPackage, out authPackID); kerbLogInfo = Marshal.AllocHGlobal(Marshal.SizeOf(kli)); Marshal.StructureToPtr(kli, kerbLogInfo, false); var ts = new TOKEN_SOURCE("Insta"); IntPtr profBuf; uint profBufLen; long logonID; IntPtr logonToken; QUOTA_LIMITS quotas; WinStatusCodes subStatus; LsaLogonUser(lsaHan, ref originName, SecurityLogonType.Interactive, authPackID, kerbLogInfo, (uint)Marshal.SizeOf(kerbLogInfo), IntPtr.Zero, ref ts, out profBuf, out profBufLen, out logonID, out logonToken, out quotas, out subStatus); }
public static extern WinStatusCodes LsaLogonUser( [In] IntPtr LsaHandle, [In] ref LSA_STRING OriginName, [In] SecurityLogonType LogonType, [In] UInt32 AuthenticationPackage, [In] IntPtr AuthenticationInformation, [In] UInt32 AuthenticationInformationLength, [In] /*PTOKEN_GROUPS*/ IntPtr LocalGroups, [In] ref TOKEN_SOURCE SourceContext, [Out] /*PVOID*/ out IntPtr ProfileBuffer, [Out] out UInt32 ProfileBufferLength, [Out] out Int64 LogonId, [Out] out IntPtr Token, [Out] out QUOTA_LIMITS Quotas, [Out] out WinStatusCodes SubStatus );
public static extern int LsaLogonUser( LsaSafeHandle LsaHandle, ref LSA_STRING OriginName, SECURITY_LOGON_TYPE LogonType, int AuthenticationPackage, void *AuthenticationInformation, int AuthenticationInformationLength, IntPtr LocalGroups, ref TOKEN_SOURCE SourceContext, out LsaBufferSafeHandle ProfileBuffer, ref int ProfileBufferLength, out LUID LogonId, out LsaTokenSafeHandle Token, out IntPtr Quotas, out int SubStatus );
internal static extern int LsaLogonUser( [In] SafeLsaHandle LsaHandle, [In] ref LSA_STRING OriginName, [In] SECURITY_LOGON_TYPE LogonType, [In] int AuthenticationPackage, [In] IntPtr AuthenticationInformation, [In] int AuthenticationInformationLength, [In] IntPtr LocalGroups, [In] ref TOKEN_SOURCE SourceContext, [Out] out SafeLsaReturnBufferHandle ProfileBuffer, [Out] out int ProfileBufferLength, [Out] out LUID LogonId, [Out] out SafeAccessTokenHandle Token, [Out] out QUOTA_LIMITS Quotas, [Out] out int SubStatus );
public static extern /*WinStatusCodes */ uint LsaLogonUser( [In] IntPtr LsaHandle, [In] ref LSA_STRING OriginName, [In] SECURITY_LOGON_TYPE LogonType, [In] UInt32 AuthenticationPackage, [In] IntPtr AuthenticationInformation, [In] UInt32 AuthenticationInformationLength, [In] PTOKEN_GROUPS LocalGroups, [In] ref TOKEN_SOURCE SourceContext, [Out] /*PVOID*/ out IntPtr ProfileBuffer, [Out] out UInt32 ProfileBufferLength, [Out] out Int64 LogonId, [Out] out IntPtr Token, [Out] out QUOTA_LIMITS Quotas, [Out] out /*WinStatusCodes */ uint SubStatus );
public void LsaLogonUserTest() { const string user = "******", domain = "contoso", pwd = "password"; Assert.That(LsaLookupAuthenticationPackage(hLsaConn, MICROSOFT_KERBEROS_NAME, out var pkg), Is.EqualTo((NTStatus)0)); var kerb = new KERB_INTERACTIVE_LOGON { MessageType = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon, LogonDomainName = new LSA_UNICODE_STRING(domain), UserName = new LSA_UNICODE_STRING(user), Password = new LSA_UNICODE_STRING(pwd) }; var mem = SafeHGlobalHandle.CreateFromStructure(kerb); AllocateLocallyUniqueId(out var srcLuid); var source = new TOKEN_SOURCE { SourceName = "foobar12".ToCharArray(), SourceIdentifier = srcLuid }; Assert.That(LsaLogonUser(hLsaConn, "TestApp", SECURITY_LOGON_TYPE.Interactive, pkg, (IntPtr)mem, (uint)mem.Size, IntPtr.Zero, source, out var profBuf, out var profBufLen, out var logonId, out var hToken, out var quotas, out var subStat), Is.EqualTo((NTStatus)0)); }
public void LsaLogonUser_Success() { var connectStatus = LsaConnectUntrusted(out var lsaHande); var lsaString = new LSA_STRING("Kerberos"); var lsaStatus = LsaLookupAuthenticationPackage(lsaHande, ref lsaString, out var authenticationPackage); AllocateLocallyUniqueId(out var srcLuid); var tokenSource = new TOKEN_SOURCE { SourceName = "foobar12".ToCharArray(), SourceIdentifier = srcLuid }; var lsaOriginName = new LSA_STRING("Kerberos"); var kerb = new KERB_INTERACTIVE_LOGON() { MessageType = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon, LogonDomainName = new UNICODE_STRING("eu"), UserName = new UNICODE_STRING("martijn"), Password = new UNICODE_STRING("Unisys!1") }; IntPtr info = (IntPtr)1024;// Marshal.SizeOf(kerb); Marshal.StructureToPtr(kerb, info, false); PTOKEN_GROUPS groups = new PTOKEN_GROUPS() { GroupCount = 0 }; IntPtr profileBuffer = IntPtr.Zero; UInt32 profileBufferLength = 0; Int64 logonId; IntPtr token = IntPtr.Zero; UInt32 subStatus; QUOTA_LIMITS quotas; var logon = LsaLogonUser(lsaHande, ref lsaOriginName, SECURITY_LOGON_TYPE.Interactive, authenticationPackage, info, 1024, groups, ref tokenSource, out profileBuffer, out profileBufferLength, out logonId, out token, out quotas, out subStatus); }
/// <summary> /// Create a "NewCredentials" logon session for the current LSA Handle. This does not authenticate the user /// and only uses the credentials provided for outbound calls similar to the /netonly flag for runas.exe. /// /// Note: this will call <see cref="ImpersonateLoggedOnUser(LsaTokenSafeHandle)" /> and set the current /// thread's primary token to the generated NT Token. /// </summary> /// <param name="username">The username to be used. Note leaving this null will use the default value "user". /// Passing an empty string will cause LSA to treat this as an anonymous user.</param> /// <param name="password">The password to be used by LSA for any future outbound ticket requests not already cached.</param> /// <param name="realm">The default realm to be used by LSA for the any outbound ticket requests not already cached.</param> public unsafe void LogonUser(string username = null, string password = null, string realm = null) { if (username == null) { username = DefaultUserName; } if (password == null) { password = string.Empty; } if (realm == null) { realm = string.Empty; } var originName = new LSA_STRING { Buffer = ProcessName, Length = (ushort)(ProcessName.Length * 2), MaximumLength = (ushort)(ProcessName.Length * 2) }; var bufferSize = Marshal.SizeOf(typeof(KERB_INTERACTIVE_LOGON)) + (realm.Length * 2) + (username.Length * 2) + (password.Length * 2); if (this.impersonationContext != null) { this.impersonationContext.Dispose(); this.impersonationContext = null; } LsaBufferSafeHandle profileBuffer = null; WithFixedBuffer(bufferSize, (p, _) => { try { var pLogon = (KERB_INTERACTIVE_LOGON *)p; pLogon->MessageType = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon; int offset = Marshal.SizeOf(typeof(KERB_INTERACTIVE_LOGON)); SetString(realm, pLogon, ref pLogon->LogonDomainName, ref offset); SetString(username, pLogon, ref pLogon->UserName, ref offset); SetString(password, pLogon, ref pLogon->Password, ref offset); var tokenSource = new TOKEN_SOURCE() { SourceName = Encoding.UTF8.GetBytes("kerb.net") }; int profileLength = 0; int result = LsaLogonUser( this.lsaHandle, ref originName, SECURITY_LOGON_TYPE.NewCredentials, this.negotiateAuthPackage, pLogon, bufferSize, IntPtr.Zero, ref tokenSource, out profileBuffer, ref profileLength, out this.luid, out this.impersonationContext, out IntPtr pQuotas, out int subStatus ); LsaThrowIfError(result); }
public static extern bool GetTokenInformation(int TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, ref TOKEN_SOURCE TokenInformation, int TokenInformationLength, out int ReturnLength);
internal static WindowsIdentity KerberosCertificateLogon(X509Certificate2 certificate) { int status; SafeHGlobalHandle pSourceName = null; SafeHGlobalHandle pPackageName = null; SafeHGlobalHandle pLogonInfo = null; SafeLsaLogonProcessHandle logonHandle = null; SafeLsaReturnBufferHandle profileHandle = null; SafeCloseHandle tokenHandle = null; try { pSourceName = SafeHGlobalHandle.AllocHGlobal(NativeMethods.LsaSourceName.Length + 1); Marshal.Copy(NativeMethods.LsaSourceName, 0, pSourceName.DangerousGetHandle(), NativeMethods.LsaSourceName.Length); UNICODE_INTPTR_STRING sourceName = new UNICODE_INTPTR_STRING(NativeMethods.LsaSourceName.Length, NativeMethods.LsaSourceName.Length + 1, pSourceName.DangerousGetHandle()); Privilege privilege = null; RuntimeHelpers.PrepareConstrainedRegions(); // Try to get an impersonation token. try { // Try to enable the TCB privilege if possible try { privilege = new Privilege(Privilege.SeTcbPrivilege); privilege.Enable(); } catch (PrivilegeNotHeldException ex) { DiagnosticUtility.TraceHandledException(ex, TraceEventType.Information); } IntPtr dummy = IntPtr.Zero; status = NativeMethods.LsaRegisterLogonProcess(ref sourceName, out logonHandle, out dummy); if (NativeMethods.ERROR_ACCESS_DENIED == NativeMethods.LsaNtStatusToWinError(status)) { // We don't have the Tcb privilege. The best we can hope for is to get an Identification token. status = NativeMethods.LsaConnectUntrusted(out logonHandle); } if (status < 0) // non-negative numbers indicate success { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(NativeMethods.LsaNtStatusToWinError(status))); } } finally { // if reverting privilege fails, fail fast! int revertResult = -1; string message = null; try { revertResult = privilege.Revert(); if (revertResult != 0) { message = SR.GetString(SR.RevertingPrivilegeFailed, new Win32Exception(revertResult)); } } finally { if (revertResult != 0) { DiagnosticUtility.FailFast(message); } } } // package name ("Kerberos") pPackageName = SafeHGlobalHandle.AllocHGlobal(NativeMethods.LsaKerberosName.Length + 1); Marshal.Copy(NativeMethods.LsaKerberosName, 0, pPackageName.DangerousGetHandle(), NativeMethods.LsaKerberosName.Length); UNICODE_INTPTR_STRING packageName = new UNICODE_INTPTR_STRING(NativeMethods.LsaKerberosName.Length, NativeMethods.LsaKerberosName.Length + 1, pPackageName.DangerousGetHandle()); uint packageId = 0; status = NativeMethods.LsaLookupAuthenticationPackage(logonHandle, ref packageName, out packageId); if (status < 0) // non-negative numbers indicate success { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(NativeMethods.LsaNtStatusToWinError(status))); } // source context TOKEN_SOURCE sourceContext = new TOKEN_SOURCE(); if (!NativeMethods.AllocateLocallyUniqueId(out sourceContext.SourceIdentifier)) { int dwErrorCode = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(dwErrorCode)); } // SourceContext sourceContext.Name = new char[8]; sourceContext.Name[0] = 'W'; sourceContext.Name[1] = 'C'; sourceContext.Name[2] = 'F'; // LogonInfo byte[] certRawData = certificate.RawData; int logonInfoSize = KERB_CERTIFICATE_S4U_LOGON.Size + certRawData.Length; pLogonInfo = SafeHGlobalHandle.AllocHGlobal(logonInfoSize); unsafe { KERB_CERTIFICATE_S4U_LOGON *pInfo = (KERB_CERTIFICATE_S4U_LOGON *)pLogonInfo.DangerousGetHandle().ToPointer(); pInfo->MessageType = KERB_LOGON_SUBMIT_TYPE.KerbCertificateS4ULogon; pInfo->Flags = NativeMethods.KERB_CERTIFICATE_S4U_LOGON_FLAG_CHECK_LOGONHOURS; pInfo->UserPrincipalName = new UNICODE_INTPTR_STRING(0, 0, IntPtr.Zero); pInfo->DomainName = new UNICODE_INTPTR_STRING(0, 0, IntPtr.Zero); pInfo->CertificateLength = (uint)certRawData.Length; pInfo->Certificate = new IntPtr(pLogonInfo.DangerousGetHandle().ToInt64() + KERB_CERTIFICATE_S4U_LOGON.Size); Marshal.Copy(certRawData, 0, pInfo->Certificate, certRawData.Length); } 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; } if (status < 0) // non-negative numbers indicate success { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(NativeMethods.LsaNtStatusToWinError(status))); } if (subStatus < 0) // non-negative numbers indicate success { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(NativeMethods.LsaNtStatusToWinError(subStatus))); } return(new WindowsIdentity(tokenHandle.DangerousGetHandle(), SecurityUtils.AuthTypeCertMap)); } finally { if (tokenHandle != null) { tokenHandle.Close(); } if (pLogonInfo != null) { pLogonInfo.Close(); } if (profileHandle != null) { profileHandle.Close(); } if (pSourceName != null) { pSourceName.Close(); } if (pPackageName != null) { pPackageName.Close(); } if (logonHandle != null) { logonHandle.Close(); } } }
/// <summary> /// Create a "NewCredentials" logon session for the current LSA Handle. This does not authenticate the user /// and only uses the credentials provided for outbound calls similar to the /netonly flag for runas.exe. /// /// Note: this will call <see cref="ImpersonateLoggedOnUser(LsaTokenSafeHandle)" /> and set the current /// thread's primary token to the generated NT Token. /// </summary> /// <param name="username">The username to be used. Note leaving this null will use the default value "user". /// Passing an empty string will cause LSA to treat this as an anonymous user.</param> /// <param name="password">The password to be used by LSA for any future outbound ticket requests not already cached.</param> /// <param name="realm">The default realm to be used by LSA for the any outbound ticket requests not already cached.</param> public unsafe void LogonUser(string username = null, string password = null, string realm = null) { if (username == null) { username = DefaultUserName; } if (password == null) { password = string.Empty; } if (realm == null) { realm = string.Empty; } var originName = new LSA_STRING { Buffer = ProcessName, Length = (ushort)(ProcessName.Length * 2), MaximumLength = (ushort)(ProcessName.Length * 2) }; var bufferSize = Marshal.SizeOf(typeof(KERB_INTERACTIVE_LOGON)) + (realm.Length * 2) + (username.Length * 2) + (password.Length * 2); if (this.impersonationContext != null) { this.impersonationContext.Dispose(); this.impersonationContext = null; } LsaBufferSafeHandle profileBuffer = null; using (var pool = CryptoPool.Rent <byte>(bufferSize)) { var buffer = pool.Memory.Slice(0, bufferSize); try { fixed(byte *pBuffer = &MemoryMarshal.GetReference(buffer.Span)) { KERB_INTERACTIVE_LOGON *pLogon = (KERB_INTERACTIVE_LOGON *)pBuffer; pLogon->MessageType = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon; int offset = Marshal.SizeOf(typeof(KERB_INTERACTIVE_LOGON)); SetString(realm, (IntPtr)pLogon, ref pLogon->LogonDomainName, ref offset); SetString(username, (IntPtr)pLogon, ref pLogon->UserName, ref offset); SetString(password, (IntPtr)pLogon, ref pLogon->Password, ref offset); var tokenSource = new TOKEN_SOURCE() { SourceName = Encoding.UTF8.GetBytes("kerb.net") }; int profileLength = 0; int result = LsaLogonUser( this.lsaHandle, ref originName, SECURITY_LOGON_TYPE.NewCredentials, this.negotiateAuthPackage, pLogon, bufferSize, IntPtr.Zero, ref tokenSource, out profileBuffer, ref profileLength, out this.luid, out this.impersonationContext, out IntPtr pQuotas, out int subStatus ); LsaThrowIfError(result); } } finally { profileBuffer?.Dispose(); } } // this call to impersonate will set the current thread token to be the token out of LsaLogonUser // do we need to do anything special if this gets used within an async context? this.impersonationContext.Impersonate(); }
private static unsafe WindowsIdentity KerberosCertificateLogon(X509Certificate2 certificate) { SafeHGlobalHandle handle = null; SafeHGlobalHandle handle2 = null; SafeHGlobalHandle handle3 = null; SafeLsaLogonProcessHandle lsaHandle = null; SafeLsaReturnBufferHandle profileBuffer = null; SafeCloseHandle token = null; WindowsIdentity identity; try { int num; uint num6; handle = SafeHGlobalHandle.AllocHGlobal((int)(System.IdentityModel.NativeMethods.LsaSourceName.Length + 1)); Marshal.Copy(System.IdentityModel.NativeMethods.LsaSourceName, 0, handle.DangerousGetHandle(), System.IdentityModel.NativeMethods.LsaSourceName.Length); UNICODE_INTPTR_STRING logonProcessName = new UNICODE_INTPTR_STRING(System.IdentityModel.NativeMethods.LsaSourceName.Length, System.IdentityModel.NativeMethods.LsaSourceName.Length + 1, handle.DangerousGetHandle()); System.IdentityModel.Privilege privilege = null; RuntimeHelpers.PrepareConstrainedRegions(); try { try { privilege = new System.IdentityModel.Privilege("SeTcbPrivilege"); privilege.Enable(); } catch (PrivilegeNotHeldException exception) { if (DiagnosticUtility.ShouldTraceInformation) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Information); } } IntPtr zero = IntPtr.Zero; num = System.IdentityModel.NativeMethods.LsaRegisterLogonProcess(ref logonProcessName, out lsaHandle, out zero); if (5 == System.IdentityModel.NativeMethods.LsaNtStatusToWinError(num)) { num = System.IdentityModel.NativeMethods.LsaConnectUntrusted(out lsaHandle); } if (num < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(System.IdentityModel.NativeMethods.LsaNtStatusToWinError(num))); } } finally { int error = -1; string message = null; try { error = privilege.Revert(); if (error != 0) { message = System.IdentityModel.SR.GetString("RevertingPrivilegeFailed", new object[] { new Win32Exception(error) }); } } finally { if (error != 0) { DiagnosticUtility.FailFast(message); } } } handle2 = SafeHGlobalHandle.AllocHGlobal((int)(System.IdentityModel.NativeMethods.LsaKerberosName.Length + 1)); Marshal.Copy(System.IdentityModel.NativeMethods.LsaKerberosName, 0, handle2.DangerousGetHandle(), System.IdentityModel.NativeMethods.LsaKerberosName.Length); UNICODE_INTPTR_STRING packageName = new UNICODE_INTPTR_STRING(System.IdentityModel.NativeMethods.LsaKerberosName.Length, System.IdentityModel.NativeMethods.LsaKerberosName.Length + 1, handle2.DangerousGetHandle()); uint authenticationPackage = 0; num = System.IdentityModel.NativeMethods.LsaLookupAuthenticationPackage(lsaHandle, ref packageName, out authenticationPackage); if (num < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(System.IdentityModel.NativeMethods.LsaNtStatusToWinError(num))); } TOKEN_SOURCE sourceContext = new TOKEN_SOURCE(); if (!System.IdentityModel.NativeMethods.AllocateLocallyUniqueId(out sourceContext.SourceIdentifier)) { int num4 = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(num4)); } sourceContext.Name = new char[8]; sourceContext.Name[0] = 'W'; sourceContext.Name[1] = 'C'; sourceContext.Name[2] = 'F'; byte[] rawData = certificate.RawData; int cb = KERB_CERTIFICATE_S4U_LOGON.Size + rawData.Length; handle3 = SafeHGlobalHandle.AllocHGlobal(cb); KERB_CERTIFICATE_S4U_LOGON *kerb_certificate_su_logonPtr = (KERB_CERTIFICATE_S4U_LOGON *)handle3.DangerousGetHandle().ToPointer(); kerb_certificate_su_logonPtr->MessageType = KERB_LOGON_SUBMIT_TYPE.KerbCertificateS4ULogon; kerb_certificate_su_logonPtr->Flags = 2; kerb_certificate_su_logonPtr->UserPrincipalName = new UNICODE_INTPTR_STRING(0, 0, IntPtr.Zero); kerb_certificate_su_logonPtr->DomainName = new UNICODE_INTPTR_STRING(0, 0, IntPtr.Zero); kerb_certificate_su_logonPtr->CertificateLength = (uint)rawData.Length; kerb_certificate_su_logonPtr->Certificate = new IntPtr(handle3.DangerousGetHandle().ToInt64() + KERB_CERTIFICATE_S4U_LOGON.Size); Marshal.Copy(rawData, 0, kerb_certificate_su_logonPtr->Certificate, rawData.Length); QUOTA_LIMITS quotas = new QUOTA_LIMITS(); LUID logonId = new LUID(); int subStatus = 0; num = System.IdentityModel.NativeMethods.LsaLogonUser(lsaHandle, ref logonProcessName, System.IdentityModel.SecurityLogonType.Network, authenticationPackage, handle3.DangerousGetHandle(), (uint)cb, IntPtr.Zero, ref sourceContext, out profileBuffer, out num6, out logonId, out token, out quotas, out subStatus); if ((num == -1073741714) && (subStatus < 0)) { num = subStatus; } if (num < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(System.IdentityModel.NativeMethods.LsaNtStatusToWinError(num))); } if (subStatus < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(System.IdentityModel.NativeMethods.LsaNtStatusToWinError(subStatus))); } identity = new WindowsIdentity(token.DangerousGetHandle(), "SSL/PCT"); } finally { if (token != null) { token.Close(); } if (handle3 != null) { handle3.Close(); } if (profileBuffer != null) { profileBuffer.Close(); } if (handle != null) { handle.Close(); } if (handle2 != null) { handle2.Close(); } if (lsaHandle != null) { lsaHandle.Close(); } } return(identity); }
internal static WindowsIdentity KerberosCertificateLogon(X509Certificate2 certificate) { int status; SafeHGlobalHandle pSourceName = null; SafeHGlobalHandle pPackageName = null; SafeHGlobalHandle pLogonInfo = null; SafeLsaLogonProcessHandle logonHandle = null; SafeLsaReturnBufferHandle profileHandle = null; SafeCloseHandle tokenHandle = null; try { pSourceName = SafeHGlobalHandle.AllocHGlobal(NativeMethods.LsaSourceName.Length + 1); Marshal.Copy(NativeMethods.LsaSourceName, 0, pSourceName.DangerousGetHandle(), NativeMethods.LsaSourceName.Length); UNICODE_INTPTR_STRING sourceName = new UNICODE_INTPTR_STRING(NativeMethods.LsaSourceName.Length, NativeMethods.LsaSourceName.Length + 1, pSourceName.DangerousGetHandle()); Privilege privilege = null; RuntimeHelpers.PrepareConstrainedRegions(); // Try to get an impersonation token. try { // Try to enable the TCB privilege if possible try { privilege = new Privilege(Privilege.SeTcbPrivilege); privilege.Enable(); } catch (PrivilegeNotHeldException ex) { DiagnosticUtility.TraceHandledException(ex, TraceEventType.Information); } IntPtr dummy = IntPtr.Zero; status = NativeMethods.LsaRegisterLogonProcess(ref sourceName, out logonHandle, out dummy); if (NativeMethods.ERROR_ACCESS_DENIED == NativeMethods.LsaNtStatusToWinError(status)) { // We don't have the Tcb privilege. The best we can hope for is to get an Identification token. status = NativeMethods.LsaConnectUntrusted(out logonHandle); } if (status < 0) // non-negative numbers indicate success { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(NativeMethods.LsaNtStatusToWinError(status))); } } finally { // if reverting privilege fails, fail fast! int revertResult = -1; string message = null; try { revertResult = privilege.Revert(); if (revertResult != 0) { message = SR.GetString(SR.RevertingPrivilegeFailed, new Win32Exception(revertResult)); } } finally { if (revertResult != 0) { DiagnosticUtility.FailFast(message); } } } // package name ("Kerberos") pPackageName = SafeHGlobalHandle.AllocHGlobal(NativeMethods.LsaKerberosName.Length + 1); Marshal.Copy(NativeMethods.LsaKerberosName, 0, pPackageName.DangerousGetHandle(), NativeMethods.LsaKerberosName.Length); UNICODE_INTPTR_STRING packageName = new UNICODE_INTPTR_STRING(NativeMethods.LsaKerberosName.Length, NativeMethods.LsaKerberosName.Length + 1, pPackageName.DangerousGetHandle()); uint packageId = 0; status = NativeMethods.LsaLookupAuthenticationPackage(logonHandle, ref packageName, out packageId); if (status < 0) // non-negative numbers indicate success { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(NativeMethods.LsaNtStatusToWinError(status))); } // source context TOKEN_SOURCE sourceContext = new TOKEN_SOURCE(); if (!NativeMethods.AllocateLocallyUniqueId(out sourceContext.SourceIdentifier)) { int dwErrorCode = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(dwErrorCode)); } // SourceContext sourceContext.Name = new char[8]; sourceContext.Name[0] = 'W'; sourceContext.Name[1] = 'C'; sourceContext.Name[2] = 'F'; // LogonInfo byte[] certRawData = certificate.RawData; int logonInfoSize = KERB_CERTIFICATE_S4U_LOGON.Size + certRawData.Length; pLogonInfo = SafeHGlobalHandle.AllocHGlobal(logonInfoSize); unsafe { KERB_CERTIFICATE_S4U_LOGON* pInfo = (KERB_CERTIFICATE_S4U_LOGON*)pLogonInfo.DangerousGetHandle().ToPointer(); pInfo->MessageType = KERB_LOGON_SUBMIT_TYPE.KerbCertificateS4ULogon; pInfo->Flags = NativeMethods.KERB_CERTIFICATE_S4U_LOGON_FLAG_CHECK_LOGONHOURS; pInfo->UserPrincipalName = new UNICODE_INTPTR_STRING(0, 0, IntPtr.Zero); pInfo->DomainName = new UNICODE_INTPTR_STRING(0, 0, IntPtr.Zero); pInfo->CertificateLength = (uint)certRawData.Length; pInfo->Certificate = new IntPtr(pLogonInfo.DangerousGetHandle().ToInt64() + KERB_CERTIFICATE_S4U_LOGON.Size); Marshal.Copy(certRawData, 0, pInfo->Certificate, certRawData.Length); } 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; } if (status < 0) // non-negative numbers indicate success { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(NativeMethods.LsaNtStatusToWinError(status))); } if (subStatus < 0) // non-negative numbers indicate success { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(NativeMethods.LsaNtStatusToWinError(subStatus))); } return new WindowsIdentity(tokenHandle.DangerousGetHandle(), SecurityUtils.AuthTypeCertMap); } finally { if (tokenHandle != null) { tokenHandle.Close(); } if (pLogonInfo != null) { pLogonInfo.Close(); } if (profileHandle != null) { profileHandle.Close(); } if (pSourceName != null) { pSourceName.Close(); } if (pPackageName != null) { pPackageName.Close(); } if (logonHandle != null) { logonHandle.Close(); } } }