Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

733 lines
17 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
lsa.c
Abstract:
Implements security network logon
Author:
Ahmed Mohamed (ahmedm) 1-Feb-2000
Revision History:
--*/
#include <nt.h>
#include <ntdef.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntmsv1_0.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
//int lstrlenW(char *);
typedef int BOOL;
typedef unsigned int UINT;
typedef unsigned int *PUINT;
typedef unsigned char *LPBYTE;
#define LocalLSAInit() (LsaHandle != NULL)
#ifdef LSA_AUDIT_FLAG
int LsaAuditFlag = 0;
#endif
#define BUF_SIZ 512
void
replstar(
IN char * starred,
OUT LPWSTR UnicodeOut
)
/*++ replstar
Routine Description:
replaces the '*' in the string with either spaces or NULL
if it's the only memeber of the string. Used by parse().
Converts the resultant string to unicode.
Arguments:
char * starred -
Return Value:
void -
Warnings:
--*/
{
char *cp;
STRING AnsiString;
UNICODE_STRING UnicodeString;
if ( !strcmp(starred,"*") ) {
*starred = '\0';
} else {
for ( cp = starred; *cp; ++cp )
if (*cp == '*')
*cp = ' ';
}
//
// Convert the result to unicode
//
AnsiString.Buffer = starred;
AnsiString.Length = AnsiString.MaximumLength =
(USHORT) strlen( starred );
UnicodeString.Buffer = UnicodeOut;
UnicodeString.Length = 0;
UnicodeString.MaximumLength = BUF_SIZ * sizeof(WCHAR);
(VOID) RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
return;
}
VOID
NlpPutString(
IN PUNICODE_STRING OutString,
IN PUNICODE_STRING InString,
IN PUCHAR *Where
)
/*++ NlpPutString
Routine Description:
This routine copies the InString string to the memory pointed to by
the Where parameter, and fixes the OutString string to point to that
new copy.
Parameters:
OutString - A pointer to a destination NT string
InString - A pointer to an NT string to be copied
Where - A pointer to space to put the actual string for the
OutString. The pointer is adjusted to point to the first byte
following the copied string.
Return Values:
None.
--*/
{
ASSERT( OutString != NULL );
ASSERT( InString != NULL );
ASSERT( Where != NULL && *Where != NULL);
if ( InString->Length > 0 )
{
OutString->Buffer = (PWCH) *Where;
OutString->MaximumLength = InString->Length;
*Where += OutString->MaximumLength;
RtlCopyString( (PSTRING) OutString, (PSTRING) InString );
}
else
{
RtlInitUnicodeString(OutString, NULL);
}
return;
}
BOOL
LsapLogonNetwork(
IN HANDLE LsaHandle,
IN ULONG AuthenticationPackage,
IN LPWSTR Username,
IN PUCHAR ChallengeToClient,
IN PMSV1_0_GETCHALLENRESP_RESPONSE ChallengeResponse,
IN UINT cbChallengeResponse,
IN LPWSTR Domain,
OUT PLUID LogonId,
OUT PHANDLE TokenHandle
)
/*++ LogonNetwork
Routine Description:
Logs a user onto the network
Arguments:
IN LPWSTR Username - self explanatory
IN ChallengeToClient - The challenge sent to the client
IN ChallengeResponse - The response sent from the client
IN LPWSTR Domain - Logon Domain Name
OUT PLUID LogonId - Unique generated logon id
OUT PHANDLE TokenHandle - handle to the logon token
Return Value:
BOOL -
Warnings:
--*/
{
NTSTATUS Status;
UNICODE_STRING TempString;
UNICODE_STRING TempString2;
UNICODE_STRING OriginName;
PMSV1_0_LM20_LOGON Auth;
PCHAR Auth1[MSV1_0_CHALLENGE_LENGTH + BUF_SIZ*2];
PUCHAR Strings;
PMSV1_0_LM20_LOGON_PROFILE ProfileBuffer;
ULONG ProfileBufferSize;
NTSTATUS SubStatus;
TOKEN_SOURCE SourceContext;
QUOTA_LIMITS QuotaLimits;
/*
* Fill in the Authentication structure.
*/
Auth = (PMSV1_0_LM20_LOGON) Auth1;
Strings = (PUCHAR)(Auth + 1);
Auth->MessageType = MsV1_0Lm20Logon;
RtlMoveMemory( Auth->ChallengeToClient,
ChallengeToClient,
MSV1_0_CHALLENGE_LENGTH );
/* Init Strings
* username
*/
RtlInitUnicodeString( &TempString, Username );
NlpPutString( &Auth->UserName, &TempString, &Strings );
/*
* workstation name
*/
RtlInitUnicodeString( &TempString, L"NetQFS" );
NlpPutString( &Auth->Workstation, &TempString, &Strings );
/*
* Challenge Response
*/
Auth->CaseSensitiveChallengeResponse.Length = 0;
Auth->CaseSensitiveChallengeResponse.MaximumLength = 0;
Auth->CaseSensitiveChallengeResponse.Buffer = NULL;
#ifdef OLD
RtlInitUnicodeString(
(PUNICODE_STRING)&TempString2,
(PCWSTR)ChallengeResponse );
#else
TempString2.Buffer = (PWSTR)ChallengeResponse;
TempString2.Length = (USHORT)cbChallengeResponse;
TempString2.MaximumLength = TempString2.Length;
#endif
if( TempString2.Length > 24 ) {
TempString2.Length = 24;
}
NlpPutString(
(PUNICODE_STRING)&Auth->CaseInsensitiveChallengeResponse,
(PUNICODE_STRING)&TempString2,
&Strings );
/*
* domain
*/
RtlInitUnicodeString( &TempString, Domain );
NlpPutString( &Auth->LogonDomainName, &TempString, &Strings );
RtlInitUnicodeString( &OriginName, L"NetQFS" );
Status = LsaLogonUser(
LsaHandle,
(PSTRING)&OriginName,
Network,
AuthenticationPackage,
// LATER? AuthenticationPackage | LSA_CALL_LICENSE_SERVER,
Auth,
(ULONG)(Strings - (PUCHAR)Auth),
NULL,
&SourceContext,
(PVOID *)&ProfileBuffer,
&ProfileBufferSize,
LogonId,
TokenHandle,
&QuotaLimits,
&SubStatus );
if ( !NT_SUCCESS( Status ) )
{
extern void WINAPI debug_log(char *,...);
debug_log("Logon failed %x\n",Status);
// LSA Can't be trusted to not scrog our variables
*TokenHandle = NULL;
return( FALSE );
}
LsaFreeReturnBuffer( ProfileBuffer );
return( TRUE );
}
BOOL
LsapChallenge(
HANDLE LsaHandle,
ULONG AuthenticationPackage,
UCHAR *ChallengeToClient
)
/*++ Challenge
Routine Description:
get a challenge
Arguments:
OUT ChallengeToClient - Returns the challenge to send to the client
Return Value:
NTSTATUS -
Warnings:
--*/
{
NTSTATUS Status;
NTSTATUS ProtocolStatus;
ULONG ResponseSize;
MSV1_0_LM20_CHALLENGE_REQUEST Request;
PMSV1_0_LM20_CHALLENGE_RESPONSE Response;
/*
* Fill in the Authentication structure.
*/
Request.MessageType = MsV1_0Lm20ChallengeRequest;
Status = LsaCallAuthenticationPackage (
LsaHandle,
AuthenticationPackage,
&Request,
sizeof(Request),
(PVOID *)&Response,
&ResponseSize,
&ProtocolStatus );
if ( !NT_SUCCESS( Status ) || !NT_SUCCESS( ProtocolStatus) )
{
printf("ChallengeRequest failed %x\n",Status);
return( FALSE );
}
RtlMoveMemory( ChallengeToClient,
Response->ChallengeToClient,
MSV1_0_CHALLENGE_LENGTH );
LsaFreeReturnBuffer( Response );
return( TRUE );
}
BOOL
LsaGetChallenge(
HANDLE LsaHandle,
ULONG AuthenticationPackage,
LPBYTE lpChallenge,
UINT cbSize,
PUINT lpcbChallengeSize
)
{
#ifdef LSA_AUDIT_FLAG
if (LsaAuditFlag == TRUE) {
memset(lpChallenge, 0, MSV1_0_CHALLENGE_LENGTH);
*lpcbChallengeSize = MSV1_0_CHALLENGE_LENGTH;
return TRUE;
}
#endif
if( LocalLSAInit() ) {
*lpcbChallengeSize = MSV1_0_CHALLENGE_LENGTH;
return LsapChallenge( LsaHandle, AuthenticationPackage, lpChallenge );
} else {
return( FALSE );
}
}
BOOL
LsaValidateLogon(
HANDLE LsaHandle,
ULONG AuthenticationPackage,
LPBYTE lpChallenge,
UINT cbChallengeSize,
LPBYTE lpResponse,
UINT cbResponseSize,
LPSTR lpszUserName,
LPSTR lpszDomainName,
LUID *pLogonId,
PHANDLE phLogonToken
)
{
WCHAR wcUser[ BUF_SIZ ];
WCHAR wcDomain[ BUF_SIZ ];
BOOL nlRet;
DWORD sz = BUF_SIZ;
#ifdef LSA_AUDIT_FLAG
if (LsaAuditFlag == 1) {
pLogonId->LowPart = 10;
pLogonId->HighPart = 0;
*phLogonToken = INVALID_HANDLE_VALUE;
return TRUE;
}
#endif
if (GetUserName((LPSTR)wcUser, &sz)) {
if (lpszUserName != NULL && *lpszUserName != '\0' &&
_stricmp(lpszUserName, (LPSTR)wcUser) &&
_stricmp(lpszUserName, "administrator")) {
return FALSE;
}
}
if( !LocalLSAInit() ) {
return( FALSE );
}
replstar( lpszUserName, wcUser );
replstar( lpszDomainName, wcDomain );
nlRet = LsapLogonNetwork( LsaHandle, AuthenticationPackage,
wcUser, lpChallenge,
(PMSV1_0_GETCHALLENRESP_RESPONSE)lpResponse,
cbResponseSize, wcDomain, pLogonId, phLogonToken );
return( nlRet );
}
BOOL
LsaGetChallengeResponse(
HANDLE LsaHandle,
ULONG AuthenticationPackage,
LUID LogonId,
LPSTR lpszPasswordK1,
int cbPasswordK1,
LPSTR lpszChallenge,
int cbChallenge,
int *pcbPasswordK1,
BOOL *pbHasPasswordK1 )
{
NTSTATUS Status;
NTSTATUS ProtocolStatus;
ULONG ResponseSize;
PMSV1_0_GETCHALLENRESP_RESPONSE Response;
PMSV1_0_GETCHALLENRESP_REQUEST Request;
PCHAR Auth1[BUF_SIZ];
PUCHAR Strings;
if( !LocalLSAInit() ) {
*pbHasPasswordK1 = FALSE;
return( FALSE );
}
Request = (PMSV1_0_GETCHALLENRESP_REQUEST) Auth1;
Request->MessageType = MsV1_0Lm20GetChallengeResponse;
Request->ParameterControl = 0;
Request->ParameterControl |= USE_PRIMARY_PASSWORD;
Request->LogonId = LogonId;
Strings = (PUCHAR)(Request + 1);
RtlMoveMemory( Request->ChallengeToClient,
lpszChallenge,
cbChallenge );
RtlInitUnicodeString( &Request->Password, NULL );
Status = LsaCallAuthenticationPackage (
LsaHandle,
AuthenticationPackage,
Request,
sizeof(MSV1_0_GETCHALLENRESP_REQUEST),
(PVOID *)&Response,
&ResponseSize,
&ProtocolStatus );
if ( !NT_SUCCESS( Status ) || !NT_SUCCESS( ProtocolStatus) )
{
return( FALSE );
}
*pcbPasswordK1 = (Response)->CaseInsensitiveChallengeResponse.Length;
memcpy( lpszPasswordK1,
(Response)->CaseInsensitiveChallengeResponse.Buffer,
(Response)->CaseInsensitiveChallengeResponse.Length );
*pbHasPasswordK1 = TRUE;
LsaFreeReturnBuffer( Response );
return( TRUE );
}
#ifdef QON_TCB_REQUIRED
// When we have support for untrusted on REQUEST we disable this. Till then we need TCB.
// I am disabling this since the we don't need TCB anymore. Note if we
// want to run in win2k then we must have TCB and this code path reenabled.
NTSTATUS
LsaInit(HANDLE *pLsaHandle, ULONG *pAuthenticationPackage)
{
char MyName[MAX_PATH];
char * ModuleName;
STRING LogonProcessName;
STRING PackageName;
ULONG dummy;
NTSTATUS Status;
NTSTATUS TempStatus;
BOOLEAN WasEnabled;
HANDLE LsaHandle = NULL;
ULONG AuthenticationPackage;
BOOLEAN fThread = FALSE; // did we enable privilege in thread token?
BOOL fReverted = FALSE; // did we RevertToSelf() during call?
HANDLE hPreviousToken = NULL;
#ifdef LSA_AUDIT_FLAG
if (LsaAuditFlag == TRUE) {
*pLsaHandle = 0;
*pAuthenticationPackage = 0;
return STATUS_SUCCESS;
}
#endif
//
// three SeTcbPrivilege scenarios:
// 1. present in process token, thread not impersonating.
// 2. present in process token, thread is impersonating.
// 3. present in thread token.
//
//
// try in this order:
// process token (original method).
// if thread impersonating, thread token
// if thread impersonating, process token after reverting.
//
Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
if (!NT_SUCCESS(Status))
{
TempStatus = NtOpenThreadToken(
NtCurrentThread(),
TOKEN_IMPERSONATE,
FALSE,
&hPreviousToken
);
if( !NT_SUCCESS(TempStatus) ) {
//
// retry with accesscheck against process.
//
if( TempStatus != STATUS_ACCESS_DENIED )
goto Cleanup;
TempStatus = NtOpenThreadToken(
NtCurrentThread(),
TOKEN_IMPERSONATE,
TRUE,
&hPreviousToken
);
if( !NT_SUCCESS(TempStatus) )
goto Cleanup;
}
//
// thread token is present.
// first, try enabling the privilege in the thread token.
//
fThread = TRUE;
Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, fThread, &WasEnabled);
if( !NT_SUCCESS(Status) ) {
HANDLE NewToken = NULL;
//
// if that fails, try reverting and enabling privilege in process token.
//
TempStatus = NtSetInformationThread(
NtCurrentThread(),
ThreadImpersonationToken,
&NewToken,
sizeof(NewToken)
);
if( !NT_SUCCESS(TempStatus) )
goto Cleanup;
fThread = FALSE;
fReverted = TRUE;
Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, fThread, &WasEnabled);
if( !NT_SUCCESS(Status) )
goto Cleanup;
}
}
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,
&LsaHandle,
&dummy
);
//
// Turn off the privilege now.
//
if( !WasEnabled ) {
(VOID) RtlAdjustPrivilege(SE_TCB_PRIVILEGE, FALSE, fThread, &WasEnabled);
}
if (!NT_SUCCESS(Status)) {
LsaHandle = NULL;
goto Cleanup;
}
//
// Connect with the MSV1_0 authentication package
//
RtlInitString(&PackageName, MSV1_0_PACKAGE_NAME); //"MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
Status = LsaLookupAuthenticationPackage (
LsaHandle,
&PackageName,
&AuthenticationPackage
);
if (!NT_SUCCESS(Status)) {
goto Cleanup;
}
*pLsaHandle = LsaHandle;
*pAuthenticationPackage = AuthenticationPackage;
Cleanup:
if( hPreviousToken ) {
if( fReverted ) {
//
// put old token back...
//
(VOID) NtSetInformationThread(
NtCurrentThread(),
ThreadImpersonationToken,
&hPreviousToken,
sizeof(hPreviousToken)
);
}
NtClose( hPreviousToken );
}
if( !NT_SUCCESS(Status) ) {
if( LsaHandle ) {
(VOID) LsaDeregisterLogonProcess( LsaHandle );
LsaHandle = NULL;
}
}
return Status;
}
#else
NTSTATUS
LsaInit(HANDLE *pLsaHandle, ULONG *pAuthenticationPackage)
{
char MyName[MAX_PATH];
char * ModuleName;
STRING LogonProcessName;
STRING PackageName;
ULONG dummy;
NTSTATUS Status;
NTSTATUS TempStatus;
BOOLEAN WasEnabled;
HANDLE LsaHandle;
ULONG AuthenticationPackage;
BOOLEAN fThread = FALSE; // did we enable privilege in thread token?
BOOL fReverted = FALSE; // did we RevertToSelf() during call?
HANDLE hPreviousToken = NULL;
//
// Connect with LSA process
//
Status = LsaConnectUntrusted(&LsaHandle);
if (!NT_SUCCESS(Status))
return Status;
//
// Connect with the MSV1_0 authentication package
//
RtlInitString(&PackageName, MSV1_0_PACKAGE_NAME); //"MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
Status = LsaLookupAuthenticationPackage (
LsaHandle,
&PackageName,
&AuthenticationPackage
);
if (NT_SUCCESS(Status)) {
*pLsaHandle = LsaHandle;
*pAuthenticationPackage = AuthenticationPackage;
} else {
(VOID) LsaDeregisterLogonProcess( LsaHandle );
}
return Status;
}
#endif