//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: logon32.c // // Contents: // // Classes: // // Functions: // // History: 9-30-94 RichardW Created // //---------------------------------------------------------------------------- #undef UNICODE #include #include #include #include #include #include #include #include #include #include #include #define SECURITY_WIN32 #define SECURITY_KERBEROS #include // // 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); }