Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1271 lines
36 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: logon32.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 9-30-94 RichardW Created
//
//----------------------------------------------------------------------------
#undef UNICODE
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <crypt.h>
#include <mpr.h>
#include <ntlsa.h>
#include <ntmsv1_0.h>
#include <wchar.h>
#include <stdlib.h>
#include <lmcons.h>
#define SECURITY_WIN32
#define SECURITY_KERBEROS
#include <security.h>
//
// We dynamically load mpr.dll (no big surprise there), in order to call
// WNetLogonNotify, as defined in private\inc\mpr.h. This prototype matches
// it -- consult the header file for all the parameters.
//
typedef (* LOGONNOTIFYFN)(LPCWSTR, PLUID, LPCWSTR, LPVOID,
LPCWSTR, LPVOID, LPWSTR, LPVOID, LPWSTR *);
//
// The QuotaLimits are global, because the defaults
// are always used for accounts, based on server/wksta, and no one ever
// calls lsasetaccountquota
//
HANDLE Logon32LsaHandle = NULL;
ULONG Logon32MsvHandle = 0xFFFFFFFF;
ULONG Logon32KerbHandle = 0xFFFFFFFF;
WCHAR Logon32DomainName[16] = L""; // NOTE: This should be DNLEN from
// lmcons.h, but that would be a
// lot of including
QUOTA_LIMITS Logon32QuotaLimits;
HINSTANCE Logon32MprHandle = NULL;
LOGONNOTIFYFN Logon32LogonNotify = NULL;
RTL_CRITICAL_SECTION Logon32Lock;
#define LockLogon() RtlEnterCriticalSection( &Logon32Lock )
#define UnlockLogon() RtlLeaveCriticalSection( &Logon32Lock )
SID_IDENTIFIER_AUTHORITY L32SystemSidAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY L32LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY;
#define COMMON_CREATE_SUSPENDED 0x00000001 // Suspended, do not Resume()
#define COMMON_CREATE_PROCESSSD 0x00000002 // Whack the process SD
#define COMMON_CREATE_THREADSD 0x00000004 // Whack the thread SD
#define BaseSetLastNTError(_x_) \
{ \
ULONG dwErrorCode; \
dwErrorCode = RtlNtStatusToDosError( (_x_) ); \
SetLastError( dwErrorCode ); \
}
//+---------------------------------------------------------------------------
//
// Function: Logon32Initialize
//
// Synopsis: Initializes the critical section
//
// Arguments: [hMod] --
// [Reason] --
// [Context] --
//
//----------------------------------------------------------------------------
BOOL
Logon32Initialize(
VOID
)
{
NTSTATUS Status;
Status = RtlInitializeCriticalSection( &Logon32Lock );
return( Status == STATUS_SUCCESS );
}
/***************************************************************************\
* CreateLogonSid
*
* Creates a logon sid for a new logon.
*
* If LogonId is non NULL, on return the LUID that is part of the logon
* sid is returned here.
*
* History:
* 12-05-91 Davidc Created
\***************************************************************************/
PSID
L32CreateLogonSid(
PLUID LogonId OPTIONAL
)
{
NTSTATUS Status;
ULONG Length;
PSID Sid;
LUID Luid;
//
// Generate a locally unique id to include in the logon sid
//
Status = NtAllocateLocallyUniqueId(&Luid);
if (!NT_SUCCESS(Status)) {
return(NULL);
}
//
// Allocate space for the sid and fill it in.
//
Length = RtlLengthRequiredSid(SECURITY_LOGON_IDS_RID_COUNT);
Sid = (PSID)LocalAlloc(LMEM_FIXED, Length);
if (Sid != NULL) {
RtlInitializeSid(Sid, &L32SystemSidAuthority, SECURITY_LOGON_IDS_RID_COUNT);
ASSERT(SECURITY_LOGON_IDS_RID_COUNT == 3);
*(RtlSubAuthoritySid(Sid, 0)) = SECURITY_LOGON_IDS_RID;
*(RtlSubAuthoritySid(Sid, 1 )) = Luid.HighPart;
*(RtlSubAuthoritySid(Sid, 2 )) = Luid.LowPart;
}
//
// Return the logon LUID if required.
//
if (LogonId != NULL) {
*LogonId = Luid;
}
return(Sid);
}
/*******************************************************************
NAME: GetDefaultDomainName
SYNOPSIS: Fills in the given array with the name of the default
domain to use for logon validation.
ENTRY: pszDomainName - Pointer to a buffer that will receive
the default domain name.
cchDomainName - The size (in charactesr) of the domain
name buffer.
RETURNS: TRUE if successful, FALSE if not.
HISTORY:
KeithMo 05-Dec-1994 Created.
RichardW 10-Jan-95 Liberated from sockets and stuck in base
********************************************************************/
BOOL
L32GetDefaultDomainName(
PUNICODE_STRING pDomainName
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS NtStatus;
INT Result;
DWORD err = 0;
LSA_HANDLE LsaPolicyHandle = NULL;
PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
PUNICODE_STRING pDomain;
if (Logon32DomainName[0] != L'\0')
{
RtlInitUnicodeString(pDomainName, Logon32DomainName);
return(TRUE);
}
//
// Open a handle to the local machine's LSA policy object.
//
InitializeObjectAttributes( &ObjectAttributes, // object attributes
NULL, // name
0L, // attributes
NULL, // root directory
NULL ); // security descriptor
NtStatus = LsaOpenPolicy( NULL, // system name
&ObjectAttributes, // object attributes
POLICY_EXECUTE, // access mask
&LsaPolicyHandle ); // policy handle
if( !NT_SUCCESS( NtStatus ) )
{
BaseSetLastNTError(NtStatus);
return(FALSE);
}
//
// Query the domain information from the policy object.
//
NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
PolicyAccountDomainInformation,
(PVOID *) &DomainInfo );
if (!NT_SUCCESS(NtStatus))
{
BaseSetLastNTError(NtStatus);
LsaClose(LsaPolicyHandle);
return(FALSE);
}
(void) LsaClose(LsaPolicyHandle);
//
// Copy the domain name into our cache, and
//
CopyMemory( Logon32DomainName,
DomainInfo->DomainName.Buffer,
DomainInfo->DomainName.Length );
//
// Null terminate it appropriately
//
Logon32DomainName[DomainInfo->DomainName.Length / sizeof(WCHAR)] = L'\0';
//
// Clean up
//
LsaFreeMemory( (PVOID)DomainInfo );
//
// And init the string
//
RtlInitUnicodeString(pDomainName, Logon32DomainName);
return TRUE;
} // GetDefaultDomainName
//+---------------------------------------------------------------------------
//
// Function: L32pInitLsa
//
// Synopsis: Initialize connection with LSA
//
// Arguments: (none)
//
// History: 4-21-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
L32pInitLsa(void)
{
char MyName[MAX_PATH];
char * ModuleName;
STRING LogonProcessName;
STRING PackageName;
ULONG dummy;
NTSTATUS Status;
BOOLEAN WasEnabled;
Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
return(FALSE);
}
GetModuleFileNameA(NULL, MyName, MAX_PATH);
ModuleName = strrchr(MyName, '\\');
if (!ModuleName)
{
ModuleName = MyName;
}
//
// Hookup to the LSA and locate our authentication package.
//
RtlInitString(&LogonProcessName, ModuleName);
Status = LsaRegisterLogonProcess(
&LogonProcessName,
&Logon32LsaHandle,
&dummy
);
//
// Turn off the privilege now.
//
if (!WasEnabled)
{
(VOID) RtlAdjustPrivilege(SE_TCB_PRIVILEGE, FALSE, FALSE, &WasEnabled);
}
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
return(FALSE);
}
//
// Connect with the MSV1_0 authentication package
//
RtlInitString(&PackageName, "MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
Status = LsaLookupAuthenticationPackage (
Logon32LsaHandle,
&PackageName,
&Logon32MsvHandle
);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
(VOID) LsaDeregisterLogonProcess( Logon32LsaHandle );
Logon32LsaHandle = NULL;
return(FALSE);
}
//
// Connect with the Kerberos authentication package
//
RtlInitString(&PackageName, MICROSOFT_KERBEROS_NAME_A);
Status = LsaLookupAuthenticationPackage (
Logon32LsaHandle,
&PackageName,
&Logon32KerbHandle
);
if (!NT_SUCCESS(Status)) {
BaseSetLastNTError(Status);
(VOID) LsaDeregisterLogonProcess( Logon32LsaHandle );
Logon32LsaHandle = NULL;
return(FALSE);
}
return(TRUE);
}
//+---------------------------------------------------------------------------
//
// Function: L32pNotifyMpr
//
// Synopsis: Loads the MPR DLL and notifies the network providers (like
// csnw) so they know about this logon session and the credentials
//
// Arguments: [NewLogon] -- New logon information
// [LogonId] -- Logon ID
//
// History: 4-24-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
L32pNotifyMpr(
PMSV1_0_INTERACTIVE_LOGON NewLogon,
PLUID LogonId
)
{
MSV1_0_INTERACTIVE_LOGON OldLogon;
LPWSTR LogonScripts;
DWORD status;
if ( Logon32MprHandle == NULL )
{
LockLogon();
if ( Logon32MprHandle == NULL)
{
Logon32MprHandle = LoadLibrary("mpr.dll");
if (Logon32MprHandle != NULL) {
Logon32LogonNotify = (LOGONNOTIFYFN) GetProcAddress(
Logon32MprHandle,
"WNetLogonNotify");
}
}
UnlockLogon();
}
if ( Logon32LogonNotify != NULL )
{
CopyMemory(&OldLogon, NewLogon, sizeof(OldLogon));
status = Logon32LogonNotify(
L"Windows NT Network Provider",
LogonId,
L"MSV1_0:Interactive",
(LPVOID)NewLogon,
L"MSV1_0:Interactive",
(LPVOID)&OldLogon,
L"SvcCtl", // StationName
NULL, // StationHandle
&LogonScripts); // LogonScripts
if (status == NO_ERROR) {
if (LogonScripts != NULL ) {
(void) LocalFree(LogonScripts);
}
}
return( TRUE );
}
return( FALSE );
}
//+---------------------------------------------------------------------------
//
// Function: L32pLogonUser
//
// Synopsis: Wraps up the call to LsaLogonUser
//
// Arguments: [LsaHandle] --
// [AuthenticationPackage] --
// [LogonType] --
// [UserName] --
// [Domain] --
// [Password] --
// [LogonSid] --
// [LogonId] --
// [LogonToken] --
// [Quotas] --
// [pProfileBuffer] --
// [pProfileBufferLength] --
// [pSubStatus] --
//
// History: 4-24-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
L32pLogonUser(
IN HANDLE LsaHandle,
IN ULONG AuthenticationPackage,
IN SECURITY_LOGON_TYPE LogonType,
IN PUNICODE_STRING UserName,
IN PUNICODE_STRING Domain,
IN PUNICODE_STRING Password,
IN PSID LogonSid,
OUT PLUID LogonId,
OUT PHANDLE LogonToken,
OUT PQUOTA_LIMITS Quotas,
OUT PVOID *pProfileBuffer,
OUT PULONG pProfileBufferLength,
OUT PNTSTATUS pSubStatus
)
{
NTSTATUS Status;
STRING OriginName;
TOKEN_SOURCE SourceContext;
PMSV1_0_INTERACTIVE_LOGON MsvAuthInfo;
PKERB_INTERACTIVE_LOGON KerbAuthInfo;
PMSV1_0_LM20_LOGON MsvNetAuthInfo;
PVOID AuthInfoBuf;
ULONG AuthInfoSize;
PTOKEN_GROUPS TokenGroups;
PSID LocalSid;
WCHAR ComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
DWORD ComputerNameLength;
union {
LUID Luid;
NT_CHALLENGE NtChallenge;
} Challenge;
NT_OWF_PASSWORD PasswordHash;
OEM_STRING LmPassword;
UCHAR LmPasswordBuf[ LM20_PWLEN + 1 ];
LM_OWF_PASSWORD LmPasswordHash;
#if DBG
if (!RtlValidSid(LogonSid))
{
return(STATUS_INVALID_PARAMETER);
}
#endif
//
// Initialize source context structure
//
strncpy(SourceContext.SourceName, "Advapi ", sizeof(SourceContext.SourceName)); // LATER from res file
Status = NtAllocateLocallyUniqueId(&SourceContext.SourceIdentifier);
if (!NT_SUCCESS(Status)) {
return(Status);
}
//
// Set logon origin
//
RtlInitString(&OriginName, "LogonUser API");
//
// For network logons, do the magic.
//
if (AuthenticationPackage == Logon32MsvHandle)
{
if ( LogonType == Network )
{
ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerNameW( ComputerName, &ComputerNameLength ) )
{
return( STATUS_INVALID_PARAMETER );
}
AuthInfoSize = sizeof( MSV1_0_LM20_LOGON ) +
sizeof( WCHAR ) * ( wcslen( UserName->Buffer ) + 1 +
wcslen( Domain->Buffer ) + 1 +
ComputerNameLength + 1) +
NT_RESPONSE_LENGTH +
LM_RESPONSE_LENGTH ;
MsvNetAuthInfo = AuthInfoBuf = RtlAllocateHeap( RtlProcessHeap(),
HEAP_ZERO_MEMORY,
AuthInfoSize );
if ( !MsvNetAuthInfo )
{
return( STATUS_NO_MEMORY );
}
//
// Start packing in the string
//
MsvNetAuthInfo->MessageType = MsV1_0NetworkLogon;
//
// Copy the user name into the authentication buffer
//
MsvNetAuthInfo->UserName.Length =
(USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
MsvNetAuthInfo->UserName.MaximumLength =
MsvNetAuthInfo->UserName.Length + sizeof(WCHAR);
MsvNetAuthInfo->UserName.Buffer = (PWSTR)(MsvNetAuthInfo+1);
wcscpy(MsvNetAuthInfo->UserName.Buffer, UserName->Buffer);
//
// Copy the domain name into the authentication buffer
//
MsvNetAuthInfo->LogonDomainName.Length =
(USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
MsvNetAuthInfo->LogonDomainName.MaximumLength =
MsvNetAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
MsvNetAuthInfo->LogonDomainName.Buffer = (PWSTR)
((PBYTE)(MsvNetAuthInfo->UserName.Buffer) +
MsvNetAuthInfo->UserName.MaximumLength);
wcscpy(MsvNetAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
//
// Copy the workstation name into the buffer
//
MsvNetAuthInfo->Workstation.Length = (USHORT)
(sizeof(WCHAR) * ComputerNameLength);
MsvNetAuthInfo->Workstation.MaximumLength =
MsvNetAuthInfo->Workstation.Length + sizeof(WCHAR);
MsvNetAuthInfo->Workstation.Buffer = (PWSTR)
((PBYTE) (MsvNetAuthInfo->LogonDomainName.Buffer) +
MsvNetAuthInfo->LogonDomainName.MaximumLength );
wcscpy( MsvNetAuthInfo->Workstation.Buffer, ComputerName );
//
// Now, generate the bits for the challenge
//
Status = NtAllocateLocallyUniqueId( &Challenge.Luid );
if ( !NT_SUCCESS(Status) )
{
RtlFreeHeap( RtlProcessHeap(), 0, MsvNetAuthInfo );
return( Status );
}
RtlCopyMemory( MsvNetAuthInfo->ChallengeToClient,
& Challenge,
MSV1_0_CHALLENGE_LENGTH );
//
// Set up space for response
//
MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer = (PUCHAR)
((PBYTE) (MsvNetAuthInfo->Workstation.Buffer) +
MsvNetAuthInfo->Workstation.MaximumLength );
MsvNetAuthInfo->CaseSensitiveChallengeResponse.Length =
NT_RESPONSE_LENGTH;
MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength =
NT_RESPONSE_LENGTH;
RtlCalculateNtOwfPassword(
Password,
& PasswordHash );
RtlCalculateNtResponse(
& Challenge.NtChallenge,
& PasswordHash,
(PNT_RESPONSE) MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer );
//
// Now do the painful LM compatible hash, so anyone who is maintaining
// their account from a WfW machine will still have a password.
//
LmPassword.Buffer = LmPasswordBuf;
LmPassword.Length = LmPassword.MaximumLength = LM20_PWLEN + 1;
Status = RtlUpcaseUnicodeStringToOemString(
& LmPassword,
Password,
FALSE );
if ( NT_SUCCESS(Status) )
{
MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer = (PUCHAR)
((PBYTE) (MsvNetAuthInfo->CaseSensitiveChallengeResponse.Buffer) +
MsvNetAuthInfo->CaseSensitiveChallengeResponse.MaximumLength );
MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Length =
LM_RESPONSE_LENGTH;
MsvNetAuthInfo->CaseInsensitiveChallengeResponse.MaximumLength =
LM_RESPONSE_LENGTH;
RtlCalculateLmOwfPassword(
LmPassword.Buffer,
& LmPasswordHash );
ZeroMemory( LmPassword.Buffer, LmPassword.Length );
RtlCalculateLmResponse(
& Challenge.NtChallenge,
& LmPasswordHash,
(PLM_RESPONSE) MsvNetAuthInfo->CaseInsensitiveChallengeResponse.Buffer );
}
else
{
//
// If we're here, the NT (supplied) password is longer than the
// limit allowed for LM passwords. NULL out the field, so that
// MSV knows not to worry about it.
//
RtlZeroMemory( &MsvNetAuthInfo->CaseInsensitiveChallengeResponse,
sizeof( STRING ) );
}
}
else
{
//
// Build logon structure for non-network logons - service,
// batch, interactive
//
AuthInfoSize = sizeof(MSV1_0_INTERACTIVE_LOGON) +
sizeof(WCHAR)*(wcslen(UserName->Buffer) + 1 +
wcslen(Domain->Buffer) + 1 +
wcslen(Password->Buffer) + 1 );
MsvAuthInfo = AuthInfoBuf = RtlAllocateHeap(RtlProcessHeap(),
HEAP_ZERO_MEMORY,
AuthInfoSize);
if (MsvAuthInfo == NULL) {
return(STATUS_NO_MEMORY);
}
//
// This authentication buffer will be used for a logon attempt
//
MsvAuthInfo->MessageType = MsV1_0InteractiveLogon;
//
// Copy the user name into the authentication buffer
//
MsvAuthInfo->UserName.Length =
(USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
MsvAuthInfo->UserName.MaximumLength =
MsvAuthInfo->UserName.Length + sizeof(WCHAR);
MsvAuthInfo->UserName.Buffer = (PWSTR)(MsvAuthInfo+1);
wcscpy(MsvAuthInfo->UserName.Buffer, UserName->Buffer);
//
// Copy the domain name into the authentication buffer
//
MsvAuthInfo->LogonDomainName.Length =
(USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
MsvAuthInfo->LogonDomainName.MaximumLength =
MsvAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
MsvAuthInfo->LogonDomainName.Buffer = (PWSTR)
((PBYTE)(MsvAuthInfo->UserName.Buffer) +
MsvAuthInfo->UserName.MaximumLength);
wcscpy(MsvAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
//
// Copy the password into the authentication buffer
// Hide it once we have copied it. Use the same seed value
// that we used for the original password in pGlobals.
//
MsvAuthInfo->Password.Length =
(USHORT)sizeof(WCHAR)*wcslen(Password->Buffer);
MsvAuthInfo->Password.MaximumLength =
MsvAuthInfo->Password.Length + sizeof(WCHAR);
MsvAuthInfo->Password.Buffer = (PWSTR)
((PBYTE)(MsvAuthInfo->LogonDomainName.Buffer) +
MsvAuthInfo->LogonDomainName.MaximumLength);
wcscpy(MsvAuthInfo->Password.Buffer, Password->Buffer);
}
}
else if (AuthenticationPackage == Logon32KerbHandle)
{
//
// Build logon structure for non-network logons - service,
// batch, interactive
//
AuthInfoSize = sizeof(KERB_INTERACTIVE_LOGON) +
sizeof(WCHAR)*(wcslen(UserName->Buffer) + 1 +
wcslen(Domain->Buffer) + 1 +
wcslen(Password->Buffer) + 1 );
KerbAuthInfo = AuthInfoBuf = RtlAllocateHeap(RtlProcessHeap(),
HEAP_ZERO_MEMORY,
AuthInfoSize);
if (KerbAuthInfo == NULL) {
return(STATUS_NO_MEMORY);
}
//
// This authentication buffer will be used for a logon attempt
//
KerbAuthInfo->MessageType = KerbInteractiveLogon;
//
// Copy the user name into the authentication buffer
//
KerbAuthInfo->UserName.Length =
(USHORT)sizeof(WCHAR)*wcslen(UserName->Buffer);
KerbAuthInfo->UserName.MaximumLength =
KerbAuthInfo->UserName.Length + sizeof(WCHAR);
KerbAuthInfo->UserName.Buffer = (PWSTR)(KerbAuthInfo+1);
wcscpy(KerbAuthInfo->UserName.Buffer, UserName->Buffer);
//
// Copy the domain name into the authentication buffer
//
KerbAuthInfo->LogonDomainName.Length =
(USHORT)sizeof(WCHAR)*wcslen(Domain->Buffer);
KerbAuthInfo->LogonDomainName.MaximumLength =
KerbAuthInfo->LogonDomainName.Length + sizeof(WCHAR);
KerbAuthInfo->LogonDomainName.Buffer = (PWSTR)
((PBYTE)(KerbAuthInfo->UserName.Buffer) +
KerbAuthInfo->UserName.MaximumLength);
wcscpy(KerbAuthInfo->LogonDomainName.Buffer, Domain->Buffer);
//
// Copy the password into the authentication buffer
// Hide it once we have copied it. Use the same seed value
// that we used for the original password in pGlobals.
//
KerbAuthInfo->Password.Length =
(USHORT)sizeof(WCHAR)*wcslen(Password->Buffer);
KerbAuthInfo->Password.MaximumLength =
KerbAuthInfo->Password.Length + sizeof(WCHAR);
KerbAuthInfo->Password.Buffer = (PWSTR)
((PBYTE)(KerbAuthInfo->LogonDomainName.Buffer) +
KerbAuthInfo->LogonDomainName.MaximumLength);
wcscpy(KerbAuthInfo->Password.Buffer, Password->Buffer);
}
//
// Create logon token groups
//
#define TOKEN_GROUP_COUNT 2 // We'll add the local SID and the logon SID
TokenGroups = (PTOKEN_GROUPS) RtlAllocateHeap(RtlProcessHeap(), 0,
sizeof(TOKEN_GROUPS) +
(TOKEN_GROUP_COUNT - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES));
if (TokenGroups == NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
return(STATUS_NO_MEMORY);
}
//
// Fill in the logon token group list
//
Status = RtlAllocateAndInitializeSid(
&L32LocalSidAuthority,
1,
SECURITY_LOCAL_RID,
0, 0, 0, 0, 0, 0, 0,
&LocalSid
);
if ( NT_SUCCESS( Status ) )
{
TokenGroups->GroupCount = TOKEN_GROUP_COUNT;
TokenGroups->Groups[0].Sid = LogonSid;
TokenGroups->Groups[0].Attributes =
SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID;
TokenGroups->Groups[1].Sid = LocalSid;
TokenGroups->Groups[1].Attributes =
SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT;
//
// Now try to log this on
//
Status = LsaLogonUser (
LsaHandle,
&OriginName,
LogonType,
AuthenticationPackage,
AuthInfoBuf,
AuthInfoSize,
TokenGroups,
&SourceContext,
pProfileBuffer,
pProfileBufferLength,
LogonId,
LogonToken,
Quotas,
pSubStatus
);
RtlFreeSid(LocalSid);
}
//
// Discard token group list
//
RtlFreeHeap(RtlProcessHeap(), 0, TokenGroups);
//
// Notify all the network providers, if this is a NON network logon
//
if ( NT_SUCCESS( Status ) &&
(LogonType != Network) )
{
L32pNotifyMpr(AuthInfoBuf, LogonId);
}
//
// Discard authentication buffer
//
RtlFreeHeap(RtlProcessHeap(), 0, AuthInfoBuf);
return(Status);
}
//+---------------------------------------------------------------------------
//
// Function: LogonUserA
//
// Synopsis: ANSI wrapper for LogonUserW. See description below
//
// Arguments: [lpszUsername] --
// [lpszDomain] --
// [lpszPassword] --
// [dwLogonType] --
// [dwLogonProvider] --
// [phToken] --
//
// History: 4-25-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
WINAPI
KerbLogonUserA(
LPSTR lpszUsername,
LPSTR lpszDomain,
LPSTR lpszPassword,
DWORD dwLogonType,
DWORD dwLogonProvider,
HANDLE * phToken
)
{
UNICODE_STRING Username;
UNICODE_STRING Domain;
UNICODE_STRING Password;
NTSTATUS Status;
BOOL bRet;
Username.Buffer = NULL;
Domain.Buffer = NULL;
Password.Buffer = NULL;
Status = RtlCreateUnicodeStringFromAsciiz(&Username, lpszUsername);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
bRet = FALSE;
goto Cleanup;
}
Status = RtlCreateUnicodeStringFromAsciiz(&Domain, lpszDomain);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
bRet = FALSE;
goto Cleanup;
}
Status = RtlCreateUnicodeStringFromAsciiz(&Password, lpszPassword);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
bRet = FALSE;
goto Cleanup;
}
bRet = KerbLogonUserW(
Username.Buffer,
Domain.Buffer,
Password.Buffer,
dwLogonType,
dwLogonProvider,
phToken);
Cleanup:
if (Username.Buffer)
{
RtlFreeUnicodeString(&Username);
}
if (Domain.Buffer)
{
RtlFreeUnicodeString(&Domain);
}
if (Password.Buffer)
{
RtlZeroMemory(Password.Buffer, Password.Length);
RtlFreeUnicodeString(&Password);
}
return(bRet);
}
//+---------------------------------------------------------------------------
//
// Function: LogonUserW
//
// Synopsis: Logs a user on via plaintext password, username and domain
// name via the LSA.
//
// Arguments: [lpszUsername] -- User name
// [lpszDomain] -- Domain name
// [lpszPassword] -- Password
// [dwLogonType] -- Logon type
// [dwLogonProvider] -- Provider
// [phToken] -- Returned handle to primary token
//
// History: 4-25-95 RichardW Created
//
// Notes: Requires SeTcbPrivilege, and will enable it if not already
// present.
//
//----------------------------------------------------------------------------
BOOL
WINAPI
KerbLogonUserW(
PWSTR lpszUsername,
PWSTR lpszDomain,
PWSTR lpszPassword,
DWORD dwLogonType,
DWORD dwLogonProvider,
HANDLE * phToken
)
{
NTSTATUS Status;
ULONG PackageId;
UNICODE_STRING Username;
UNICODE_STRING Domain;
UNICODE_STRING Password;
LUID LogonId;
PSID pLogonSid;
PVOID Profile;
ULONG ProfileLength;
NTSTATUS SubStatus;
SECURITY_LOGON_TYPE LogonType;
//
// Validate the provider
//
if (dwLogonProvider == LOGON32_PROVIDER_DEFAULT)
{
dwLogonProvider = LOGON32_PROVIDER_WINNT35;
}
if (dwLogonProvider > LOGON32_PROVIDER_WINNT40)
{
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return(FALSE);
}
switch (dwLogonType)
{
case LOGON32_LOGON_INTERACTIVE:
LogonType = Interactive;
break;
case LOGON32_LOGON_BATCH:
LogonType = Batch;
break;
case LOGON32_LOGON_SERVICE:
LogonType = Service;
break;
case LOGON32_LOGON_NETWORK:
LogonType = Network;
break;
default:
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return(FALSE);
break;
}
//
// If the MSV handle is -1, grab the lock, and try again:
//
if (Logon32MsvHandle == 0xFFFFFFFF)
{
LockLogon();
//
// If the MSV handle is still -1, init our connection to lsa. We
// have the lock, so no other threads can be trying this right now.
//
if (Logon32MsvHandle == 0xFFFFFFFF)
{
if (!L32pInitLsa())
{
return( FALSE );
}
}
UnlockLogon();
}
//
// Validate the parameters. NULL or empty domain or NULL or empty
// user name is invalid.
//
RtlInitUnicodeString(&Username, lpszUsername);
if (Username.Length == 0)
{
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return(FALSE);
}
//
// Initialize the token handle, if the pointer is invalid, then catch
// the exception now.
//
*phToken = NULL;
//
// Parse that domain. Note, if the special token . is passed in for
// domain, we will use the right value from the LSA, meaning AccountDomain.
// If the domain is null, the lsa will talk to the local domain, the
// primary domain, and then on from there...
//
if (lpszDomain && *lpszDomain)
{
if ((lpszDomain[0] == L'.') &&
(lpszDomain[1] == L'\0') )
{
if (!L32GetDefaultDomainName(&Domain))
{
return(FALSE);
}
}
else
RtlInitUnicodeString(&Domain, lpszDomain);
}
else
{
RtlInitUnicodeString(&Domain, lpszDomain);
}
//
// Finally, init the password
//
RtlInitUnicodeString(&Password, lpszPassword);
//
// Get a logon sid to refer to this guy (not that anyone will be able to
// use it...
//
pLogonSid = L32CreateLogonSid(NULL);
if (!pLogonSid)
{
BaseSetLastNTError(STATUS_NO_MEMORY);
return(FALSE);
}
//
// Attempt the logon
//
Status = L32pLogonUser(
Logon32LsaHandle,
(dwLogonProvider == LOGON32_PROVIDER_WINNT35) ?
Logon32MsvHandle : Logon32KerbHandle,
LogonType,
&Username,
&Domain,
&Password,
pLogonSid,
&LogonId,
phToken,
&Logon32QuotaLimits,
&Profile,
&ProfileLength,
&SubStatus);
//
// Done with logon sid, regardless of result:
//
LocalFree( pLogonSid );
if (!NT_SUCCESS(Status))
{
if (Status == STATUS_ACCOUNT_RESTRICTION)
{
BaseSetLastNTError(SubStatus);
}
else
BaseSetLastNTError(Status);
return(FALSE);
}
if (Profile != NULL)
{
LsaFreeReturnBuffer(Profile);
}
return(TRUE);
}