lsalogonuser (secur32)
Last changed: -61.17.131.34

.
Summary
The LsaLogonUser function authenticates a security principal's logon data using stored credentials information.

C# Signature:

[DllImport("secur32.dll", SetLastError=false)]
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
                    );

VB Signature:

Declare Function LsaLogonUser Lib "secur32.dll" (TODO) As TODO

User-Defined Types:

None.

Notes:

None.

Tips & Tricks:

Please add some!

Sample Code:

using System;
using System.Runtime.InteropServices;

namespace CCSecurityUtilities
{
    /// <remarks>
    /// This sample uses S4U security, which requires Windows Server 2003 and a W2003 domain controller
    /// </remarks>
    public sealed class CCWinLogonUtilities
    {
        private CCWinLogonUtilities()
        {
        }

        #region "Win32 stuff"
        private class Win32
        {
            internal class OSCalls
            {
                public enum WinStatusCodes : uint
                {
                    STATUS_SUCCESS = 0
                }

                public enum WinErrors : uint
                {
                    NO_ERROR = 0,
                }
                public enum WinLogonType
                {
                    LOGON32_LOGON_INTERACTIVE       =2,
                    LOGON32_LOGON_NETWORK       =3,
                    LOGON32_LOGON_BATCH         =4,
                    LOGON32_LOGON_SERVICE       =5,
                    LOGON32_LOGON_UNLOCK        =7,
                    LOGON32_LOGON_NETWORK_CLEARTEXT =8,
                    LOGON32_LOGON_NEW_CREDENTIALS   =9
                }

                // SECURITY_LOGON_TYPE
                public enum SecurityLogonType
                {
                    Interactive = 2,    // Interactively logged on (locally or remotely)
                    Network,        // Accessing system via network
                    Batch,          // Started via a batch queue
                    Service,        // Service started by service controller
                    Proxy,          // Proxy logon
                    Unlock,         // Unlock workstation
                    NetworkCleartext,   // Network logon with cleartext credentials
                    NewCredentials,     // Clone caller, new default credentials
                    RemoteInteractive,  // Remote, yet interactive. Terminal server
                    CachedInteractive,  // Try cached credentials without hitting the net.
                    CachedRemoteInteractive, // Same as RemoteInteractive, this is used internally for auditing purpose
                    CachedUnlock    // Cached Unlock workstation
                }

                [StructLayout(LayoutKind.Sequential)]
                    public struct LSA_UNICODE_STRING
                {
                    public UInt16 Length;
                    public UInt16 MaximumLength;
                    public IntPtr Buffer;
                }

                [StructLayout(LayoutKind.Sequential)]
                    public struct TOKEN_SOURCE
                {
                    public TOKEN_SOURCE(string name)
                    {
                        SourceName = new byte[8];
                        System.Text.Encoding.GetEncoding(1252).GetBytes(name,0,name.Length,SourceName,0);
                        if (!AllocateLocallyUniqueId(out SourceIdentifier))
                            throw new System.ComponentModel.Win32Exception();
                    }

                    [MarshalAs(UnmanagedType.ByValArray,SizeConst=8)] public byte[] SourceName;
                    public UInt64 SourceIdentifier;
                }

                [StructLayout(LayoutKind.Sequential)]
                    public struct QUOTA_LIMITS
                {
                    UInt32 PagedPoolLimit;
                    UInt32 NonPagedPoolLimit;
                    UInt32 MinimumWorkingSetSize;
                    UInt32 MaximumWorkingSetSize;  
                    UInt32 PagefileLimit;  
                    Int64 TimeLimit;
                }

                [StructLayout(LayoutKind.Sequential)]
                    public struct LSA_STRING
                {
                    public UInt16 Length;
                    public UInt16 MaximumLength;
                    public /*PCHAR*/ IntPtr Buffer;
                }

                public class LsaStringWrapper : IDisposable
                {
                    public LSA_STRING _string;

                    public LsaStringWrapper(string value)
                    {
                        _string = new LSA_STRING();
                        _string.Length = (ushort)value.Length;
                        _string.MaximumLength = (ushort)value.Length;
                        _string.Buffer = Marshal.StringToHGlobalAnsi(value);
                    }

                    ~LsaStringWrapper()
                    {
                        Dispose(false);
                    }

                    private void Dispose(bool disposing)
                    {
                        if (_string.Buffer != IntPtr.Zero)
                        {
                            Marshal.FreeHGlobal(_string.Buffer);
                            _string.Buffer = IntPtr.Zero;
                        }
                        if (disposing)
                            GC.SuppressFinalize(this);
                    }

                    #region IDisposable Members

                    public void Dispose()
                    {
                        Dispose(true);
                    }

                    #endregion
                }

                public class KerbS4ULogon : IDisposable
                {
                    [StructLayout(LayoutKind.Sequential)]
                        public struct KERB_S4U_LOGON
                    {
                        public Int32 MessageType;    // Should be 12
                        public Int32 Flags; // Reserved, should be 0
                        public LSA_UNICODE_STRING ClientUpn;   // REQUIRED: UPN for client
                        public LSA_UNICODE_STRING ClientRealm; // Optional: Client Realm, if known
                    }

                    public KerbS4ULogon(string clientUpn) : this(clientUpn,null)
                    {
                    }

                    public KerbS4ULogon(string clientUpn,string clientRealm)
                    {
                        int clientUpnLen = (clientUpn == null) ? 0 : clientUpn.Length;
                        int clientRealmLen = (clientRealm == null) ? 0 : clientRealm.Length;
                        _bufferLength = Marshal.SizeOf(typeof(KERB_S4U_LOGON)) + 2 * (clientUpnLen + clientRealmLen);
                        _bufferContent = Marshal.AllocHGlobal(_bufferLength);
                        if (_bufferContent == IntPtr.Zero)
                            throw new OutOfMemoryException("Could not allocate memory for KerbS4ULogon structure");
                        try
                        {
                            KERB_S4U_LOGON baseStructure = new KERB_S4U_LOGON();
                            baseStructure.MessageType = 12;    // KerbS4ULogon
                            baseStructure.Flags = 0;
                            baseStructure.ClientUpn.Length = (UInt16)(2*clientUpnLen);
                            baseStructure.ClientUpn.MaximumLength = (UInt16)(2*clientUpnLen);
                            IntPtr curPtr = new IntPtr(_bufferContent.ToInt32()+Marshal.SizeOf(typeof(KERB_S4U_LOGON)));
                            if (clientUpnLen > 0)
                            {
                                baseStructure.ClientUpn.Buffer = curPtr;
                                Marshal.Copy(clientUpn.ToCharArray(),0,curPtr,clientUpnLen);
                                curPtr = new IntPtr(curPtr.ToInt32()+clientUpnLen*2);
                            }
                            else
                                baseStructure.ClientUpn.Buffer = IntPtr.Zero;
                            baseStructure.ClientRealm.Length = (UInt16)(2*clientRealmLen);
                            baseStructure.ClientRealm.MaximumLength = (UInt16)(2*clientRealmLen);
                            if (clientRealmLen > 0)
                            {
                                baseStructure.ClientRealm.Buffer = curPtr;
                                Marshal.Copy(clientRealm.ToCharArray(),0,curPtr,clientRealmLen);
                            }
                            else
                                baseStructure.ClientRealm.Buffer = IntPtr.Zero;
                            Marshal.StructureToPtr(baseStructure,_bufferContent,false);
                        }
                        catch
                        {
                            Dispose(true);
                            throw;
                        }
                    }

                    private IntPtr _bufferContent;
                    private int _bufferLength;

                    public IntPtr Ptr
                    {
                        get {return _bufferContent;}
                    }

                    public int Length
                    {
                        get {return _bufferLength;}
                    }

                    private void Dispose(bool disposing)
                    {
                        if (_bufferContent != IntPtr.Zero)
                        {
                            Marshal.FreeHGlobal(_bufferContent);
                            _bufferContent = IntPtr.Zero;
                        }
                        if (disposing)
                            GC.SuppressFinalize(this);
                    }

                    ~KerbS4ULogon()
                    {
                        Dispose(false);
                    }

                    #region IDisposable Members

                    public void Dispose()
                    {
                        Dispose(true);
                    }

                    #endregion
                }

                [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=false)]
                public static extern WinErrors LsaNtStatusToWinError(WinStatusCodes status);

                [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
                public static extern bool AllocateLocallyUniqueId([Out] out UInt64 Luid);

                [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
                public static extern int CloseHandle(IntPtr hObject);

                [DllImport("secur32.dll", SetLastError=false)]
                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
                    );

                [DllImport("secur32.dll", SetLastError=false)]
                public static extern WinStatusCodes LsaFreeReturnBuffer(
                    [In] IntPtr buffer);

                [DllImport("secur32.dll", SetLastError=false)]
                public static extern WinStatusCodes LsaConnectUntrusted([Out] out IntPtr LsaHandle);

                [DllImport("secur32.dll", SetLastError=false)]
                public static extern WinStatusCodes LsaDeregisterLogonProcess([In] IntPtr LsaHandle);

                [DllImport("secur32.dll", SetLastError=false)]
                public static extern WinStatusCodes LsaLookupAuthenticationPackage([In] IntPtr LsaHandle,[In] ref LSA_STRING PackageName,[Out] out UInt32 AuthenticationPackage);

            }

            public sealed class HandleSecurityToken
                : IDisposable
            {
                private IntPtr m_hToken = IntPtr.Zero;

                // using S4U logon
                public HandleSecurityToken(string UserName,
                    string Domain,
                    OSCalls.WinLogonType LogonType
                    )
                {
                    using (OSCalls.KerbS4ULogon authPackage = new OSCalls.KerbS4ULogon(UserName,Domain))
                    {
                        IntPtr lsaHandle;
                        OSCalls.WinStatusCodes status = OSCalls.LsaConnectUntrusted(out lsaHandle);
                        if (status != OSCalls.WinStatusCodes.STATUS_SUCCESS)
                            throw new System.ComponentModel.Win32Exception((int)OSCalls.LsaNtStatusToWinError(status));
                        try
                        {
                            UInt32 kerberosPackageId;
                            using (OSCalls.LsaStringWrapper kerberosPackageName = new OSCalls.LsaStringWrapper("Kerberos"))
                            {
                                status = OSCalls.LsaLookupAuthenticationPackage(lsaHandle,ref kerberosPackageName._string,out kerberosPackageId);
                                if (status != OSCalls.WinStatusCodes.STATUS_SUCCESS)
                                    throw new System.ComponentModel.Win32Exception((int)OSCalls.LsaNtStatusToWinError(status));
                            }
                            OSCalls.LsaStringWrapper originName = null;
                            try
                            {
                                originName = new OSCalls.LsaStringWrapper("CCSecurityUtilities");
                                OSCalls.TOKEN_SOURCE sourceContext = new OSCalls.TOKEN_SOURCE("CCSecUt");
                                System.IntPtr profileBuffer = IntPtr.Zero;
                                UInt32 profileBufferLength = 0;
                                Int64 logonId;
                                OSCalls.WinStatusCodes subStatus;
                                OSCalls.QUOTA_LIMITS quotas;
                                status = OSCalls.LsaLogonUser(
                                    lsaHandle,
                                    ref originName._string,
                                    (OSCalls.SecurityLogonType)LogonType,
                                    kerberosPackageId,
                                    authPackage.Ptr,
                                    (uint)authPackage.Length,
                                    IntPtr.Zero,
                                    ref sourceContext,
                                    out profileBuffer,
                                    out profileBufferLength,
                                    out logonId,
                                    out m_hToken,
                                    out quotas,
                                    out subStatus);
                                if (status != OSCalls.WinStatusCodes.STATUS_SUCCESS)
                                    throw new System.ComponentModel.Win32Exception((int)OSCalls.LsaNtStatusToWinError(status));
                                if (profileBuffer != IntPtr.Zero)
                                    OSCalls.LsaFreeReturnBuffer(profileBuffer);
                            }
                            finally
                            {
                                if (originName != null)
                                    originName.Dispose();
                            }
                        }
                        finally
                        {
                            OSCalls.LsaDeregisterLogonProcess(lsaHandle);
                        }
                    }
                }

                ~HandleSecurityToken()
                {
                    Dispose(false);
                }

                public void Dispose()
                {
                    Dispose(true);
                }

                private void Dispose(bool disposing )
                {
                    lock(this)
                    {
                        if (!m_hToken.Equals(IntPtr.Zero))
                        {
                            OSCalls.CloseHandle(m_hToken);
                            m_hToken = IntPtr.Zero;
                        }
                        if (disposing)
                            GC.SuppressFinalize(this);
                    }
                }

                public System.Security.Principal.WindowsIdentity BuildIdentity()
                {
                    System.Security.Principal.WindowsIdentity retVal = new System.Security.Principal.WindowsIdentity(m_hToken);
                    GC.KeepAlive(this);
                    return retVal;
                }
            }

        }

        #endregion

        /// <summary>
        /// The Windows Logon Types.
        /// </summary>
        public enum WinLogonType
        {
            /// <summary>
            /// Interactive logon
            /// </summary>
            LOGON32_LOGON_INTERACTIVE       = Win32.OSCalls.WinLogonType.LOGON32_LOGON_INTERACTIVE,
            /// <summary>
            /// Network logon
            /// </summary>
            LOGON32_LOGON_NETWORK       = Win32.OSCalls.WinLogonType.LOGON32_LOGON_NETWORK,
            /// <summary>
            /// Batch logon
            /// </summary>
            LOGON32_LOGON_BATCH         = Win32.OSCalls.WinLogonType.LOGON32_LOGON_BATCH,
            /// <summary>
            /// Logon as a service
            /// </summary>
            LOGON32_LOGON_SERVICE       = Win32.OSCalls.WinLogonType.LOGON32_LOGON_SERVICE,
            /// <summary>
            /// Unlock logon
            /// </summary>
            LOGON32_LOGON_UNLOCK        = Win32.OSCalls.WinLogonType.LOGON32_LOGON_UNLOCK,
            /// <summary>
            /// Preserve password logon
            /// </summary>
            LOGON32_LOGON_NETWORK_CLEARTEXT = Win32.OSCalls.WinLogonType.LOGON32_LOGON_NETWORK_CLEARTEXT,
            /// <summary>
            /// Current token for local access, credentials for network access
            /// </summary>
            LOGON32_LOGON_NEW_CREDENTIALS   = Win32.OSCalls.WinLogonType.LOGON32_LOGON_NEW_CREDENTIALS
        }

        /// <summary>
        /// Logs in a credential for server apps. No need to provide password.
        /// </summary>
        /// <param name="credential">The credential to log in. Password is ignored.</param>
        /// <param name="logonType">The type of logon to use</param>
        /// <remarks>
        /// Requires Windows Server 2003 domain account running in Win2003 native domain mode
        /// </remarks>
        /// <returns>Returns a <c>System.Security.Principal.WindowsIdentity</c> object</returns>
        /// Raises an exception with error information if the user cannot log in
        public static System.Security.Principal.WindowsIdentity CreateIdentityS4U(System.Net.NetworkCredential credential, WinLogonType logonType)
        {
            using (Win32.HandleSecurityToken handleToken =
                       new Win32.HandleSecurityToken(credential.UserName,credential.Domain,(Win32.OSCalls.WinLogonType)logonType))
                return handleToken.BuildIdentity();
        }

    }
}

Alternative Managed API:

System.Security.Principal.WindowsIdentity has a constructor that you can use if you know the user's principal name (UPN). It does not work however for domain\username.

Documentation