public static unsafe extern int LsaCallAuthenticationPackage( LsaSafeHandle LsaHandle, int AuthenticationPackage, void *ProtocolSubmitBuffer, int SubmitBufferLength, out LsaBufferSafeHandle ProtocolReturnBuffer, out int ReturnBufferLength, out int ProtocolStatus );
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 );
private unsafe void LsaCallAuthenticationPackage(void *pBuffer, int bufferSize) { LsaBufferSafeHandle returnBuffer = null; try { var result = NativeMethods.LsaCallAuthenticationPackage( this.lsaHandle, this.selectedAuthPackage, pBuffer, bufferSize, out returnBuffer, out int returnBufferLength, out int protocolStatus ); LsaThrowIfError(result); LsaThrowIfError(protocolStatus); } finally { returnBuffer?.Dispose(); } }
/// <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); }
/// <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(); }