Exemple #1
0
        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);
        }
Exemple #2
0
        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);
        }
Exemple #3
0
 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
     );
Exemple #4
0
 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
     );
Exemple #5
0
 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
     );
Exemple #6
0
 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
     );
Exemple #7
0
        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));
        }
Exemple #8
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);
        }
Exemple #9
0
        /// <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);
                }
Exemple #10
0
 public static extern bool GetTokenInformation(int TokenHandle,
     TOKEN_INFORMATION_CLASS TokenInformationClass, ref TOKEN_SOURCE TokenInformation,
     int TokenInformationLength, out int ReturnLength);
Exemple #11
0
        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();
                }
            }
        }
Exemple #12
0
        /// <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();
        }
Exemple #13
0
 public static extern bool GetTokenInformation(int TokenHandle,
                                               TOKEN_INFORMATION_CLASS TokenInformationClass, ref TOKEN_SOURCE TokenInformation,
                                               int TokenInformationLength, out int ReturnLength);
        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();
                }
            }
        }