/// <summary>
        /// Logon a user.
        /// </summary>
        /// <param name="type">The type of logon.</param>
        /// <param name="auth_package">The authentication package to use.</param>
        /// <param name="origin_name">The name of the origin.</param>
        /// <param name="source_context">The token source context.</param>
        /// <param name="buffer">The authentication credentials buffer.</param>
        /// <param name="local_groups">Additional local groups.</param>
        /// <param name="throw_on_error">True to throw on error.</param>
        /// <returns>The LSA logon result.</returns>
        public NtResult <LsaLogonResult> LsaLogonUser(SecurityLogonType type, string auth_package, string origin_name,
                                                      TokenSource source_context, SafeBuffer buffer, IEnumerable <UserGroup> local_groups, bool throw_on_error)
        {
            using (var list = new DisposableList())
            {
                var auth_pkg = _handle.LookupAuthPackage(auth_package, throw_on_error);
                if (!auth_pkg.IsSuccess)
                {
                    return(auth_pkg.Cast <LsaLogonResult>());
                }

                var groups = local_groups == null ? SafeTokenGroupsBuffer.Null
                    : list.AddResource(SafeTokenGroupsBuffer.Create(local_groups));

                QUOTA_LIMITS quota_limits = new QUOTA_LIMITS();
                return(SecurityNativeMethods.LsaLogonUser(_handle, new LsaString(origin_name),
                                                          type, auth_pkg.Result, buffer, buffer.GetLength(), groups,
                                                          source_context, out SafeLsaReturnBufferHandle profile,
                                                          out int cbProfile, out Luid logon_id, out SafeKernelObjectHandle token_handle,
                                                          quota_limits, out NtStatus subStatus).CreateResult(throw_on_error, () =>
                {
                    profile.InitializeLength(cbProfile);
                    return new LsaLogonResult(NtToken.FromHandle(token_handle), profile, logon_id, quota_limits);
                }));
            }
        }
Beispiel #2
0
 internal LsaLogonResult(NtToken token, SafeBufferGeneric profile,
                         Luid logon_id, QUOTA_LIMITS quota_limits)
 {
     Token                 = token;
     Profile               = profile;
     LogonId               = logon_id;
     PagedPoolLimit        = quota_limits.PagedPoolLimit.ToInt64();
     NonPagedPoolLimit     = quota_limits.NonPagedPoolLimit.ToInt64();
     MinimumWorkingSetSize = quota_limits.MinimumWorkingSetSize.ToInt64();
     MaximumWorkingSetSize = quota_limits.MaximumWorkingSetSize.ToInt64();
     PagefileLimit         = quota_limits.PagefileLimit.ToInt64();
     TimeLimit             = TimeSpan.FromTicks(quota_limits.TimeLimit.QuadPart);
 }
Beispiel #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
     );
Beispiel #4
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
     );
Beispiel #5
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
     );
Beispiel #6
0
 public static extern bool LogonUserEx(string lpszUserName, string lpszDomain, string lpszPassword, LogonUserType dwLogonType, LogonUserProvider dwLogonProvider,
                                       out SafeHTOKEN phObject, out PSID ppLogonSid, out SafeLsaReturnBufferHandle ppProfileBuffer, out uint pdwProfileLength, out QUOTA_LIMITS pQuotaLimits);
Beispiel #7
0
 public static extern int ZwQueryInformationProcess(int ProcessHandle, PROCESS_INFORMATION_CLASS ProcessInformationClass,
     ref QUOTA_LIMITS ProcessInformation, int ProcessInformationLength, out int ReturnLength);
Beispiel #8
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();
                }
            }
        }
Beispiel #9
0
 public static extern int ZwQueryInformationProcess(int ProcessHandle, PROCESS_INFORMATION_CLASS ProcessInformationClass,
                                                    ref QUOTA_LIMITS ProcessInformation, int ProcessInformationLength, 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();
                }
            }
        }