📄 msvsam.c
字号:
/*++
Copyright (c) 1987-1999 Microsoft Corporation
Module Name:
msvsam.c
Abstract:
Sam account validation interface.
These routines are shared by the MSV authentication package and
the Netlogon service.
Author:
Cliff Van Dyke (cliffv) 15-Jan-1992
Environment:
User mode only.
Contains NT-specific code.
Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
Chandana Surlu 21-Jul-96 Stolen from \\kernel\razzle3\src\security\msv1_0\msvsam.c
--*/
#include <global.h>
#undef EXTERN
#include "msp.h"
#include "nlp.h"
#include <stddef.h> // offsetof()
#include <msaudite.h> // SE_AUDITID_xxx
///////////////////////////////////////////////////////////////////////
// //
// SubAuth package zero helper routine //
// //
///////////////////////////////////////////////////////////////////////
NTSTATUS
Msv1_0SubAuthenticationRoutineZero(
IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
IN PVOID LogonInformation,
IN ULONG Flags,
IN PUSER_ALL_INFORMATION UserAll,
OUT PULONG WhichFields,
OUT PULONG UserFlags,
OUT PBOOLEAN Authoritative,
OUT PLARGE_INTEGER LogoffTime,
OUT PLARGE_INTEGER KickoffTime
);
BOOLEAN
MsvpLm3ValidateResponse (
IN PNT_OWF_PASSWORD pNtOwfPassword,
IN PUNICODE_STRING pUserName,
IN PUNICODE_STRING pLogonDomainName,
IN UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH],
IN PMSV1_0_LM3_RESPONSE pLm3Response
)
{
UCHAR Response[MSV1_0_NTLM3_RESPONSE_LENGTH];
ULONG i;
// compute the response again
MsvpLm3Response (
pNtOwfPassword,
pUserName,
pLogonDomainName,
ChallengeToClient,
pLm3Response,
Response
);
// compare with what we were passed
i = (ULONG)RtlCompareMemory(
pLm3Response->Response,
Response,
MSV1_0_NTLM3_RESPONSE_LENGTH);
return (i == MSV1_0_NTLM3_RESPONSE_LENGTH);
}
BOOLEAN
MsvpNtlm3ValidateResponse (
IN PNT_OWF_PASSWORD pNtOwfPassword,
IN PUNICODE_STRING pUserName,
IN PUNICODE_STRING pLogonDomainName,
IN UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH],
IN PMSV1_0_NTLM3_RESPONSE pNtlm3Response,
IN ULONG Ntlm3ResponseLength,
OUT PUSER_SESSION_KEY UserSessionKey,
OUT PLM_SESSION_KEY LmSessionKey
)
{
UCHAR Response[MSV1_0_NTLM3_RESPONSE_LENGTH];
ULONG i;
LARGE_INTEGER Time;
NTSTATUS Status;
const LONGLONG TicksPerSecond = 10*1000*1000; // 100 ns ticks per second
// check version numbers
if (pNtlm3Response->RespType > 1 ||
pNtlm3Response->HiRespType < 1)
return FALSE;
// check that the timestamp isn't too old
Status = NtQuerySystemTime ( &Time );
ASSERT( NT_SUCCESS(Status) );
#ifndef USE_CONSTANT_CHALLENGE
// make sure time hasn't expired
// don't forget that client's clock could be behind ours
if (Time.QuadPart > (LONGLONG)pNtlm3Response->TimeStamp) {
if (Time.QuadPart - (LONGLONG)pNtlm3Response->TimeStamp >
(MSV1_0_MAX_NTLM3_LIFE*TicksPerSecond))
return FALSE;
} else if ((LONGLONG)pNtlm3Response->TimeStamp - Time.QuadPart >
(MSV1_0_MAX_NTLM3_LIFE*TicksPerSecond)) {
return FALSE;
}
#endif
// compute the response itself
MsvpNtlm3Response (
pNtOwfPassword,
pUserName,
pLogonDomainName,
(Ntlm3ResponseLength-sizeof(MSV1_0_NTLM3_RESPONSE)),
ChallengeToClient,
pNtlm3Response,
Response,
UserSessionKey,
LmSessionKey
);
// compare with what we were passed
i = (ULONG)RtlCompareMemory(
pNtlm3Response->Response,
Response,
(size_t)MSV1_0_NTLM3_RESPONSE_LENGTH);
return (i == MSV1_0_NTLM3_RESPONSE_LENGTH);
}
BOOLEAN
MsvpPasswordValidate (
IN BOOLEAN UasCompatibilityRequired,
IN NETLOGON_LOGON_INFO_CLASS LogonLevel,
IN PVOID LogonInformation,
IN PUSER_INTERNAL1_INFORMATION Passwords,
OUT PULONG UserFlags,
OUT PUSER_SESSION_KEY UserSessionKey,
OUT PLM_SESSION_KEY LmSessionKey
)
/*++
Routine Description:
Process an interactive, network, or session logon. It calls
SamIUserValidation, validates the passed in credentials, updates the logon
statistics and packages the result for return to the caller.
This routine is called directly from the MSV Authentication package
on any system where LanMan is not installed. This routine is called
from the Netlogon Service otherwise.
Arguments:
UasCompatibilityRequired -- True, if UAS compatibility is required.
LogonLevel -- Specifies the level of information given in
LogonInformation.
LogonInformation -- Specifies the description for the user
logging on. The LogonDomainName field should be ignored.
The caller is responsible for validating this field.
Passwords -- Specifies the passwords for the user account.
UserFlags -- Returns flags identifying how the password was validated.
Returns LOGON_NOENCRYPTION if the password wasn't encrypted
Returns LOGON_USED_LM_PASSWORD if the LM password from SAM was used.
UserSessionKey -- Returns the NT User session key for this network logon
session.
LmSessionKey -- Returns the LM compatible session key for this network
logon session.
Return Value:
TRUE -- Password validation is successful
FALSE -- Password validation failed
--*/
{
NTSTATUS Status;
PNETLOGON_LOGON_IDENTITY_INFO LogonInfo;
PNETLOGON_INTERACTIVE_INFO LogonInteractiveInfo;
PNETLOGON_NETWORK_INFO LogonNetworkInfo;
BOOLEAN AlreadyValidated = FALSE;
UNICODE_STRING NullUnicodeString;
ULONG NtLmProtocolSupported;
//
// Initialization.
//
LogonInfo = (PNETLOGON_LOGON_IDENTITY_INFO) LogonInformation;
*UserFlags = LOGON_NTLMV2_ENABLED;
RtlZeroMemory( UserSessionKey, sizeof(*UserSessionKey) );
RtlZeroMemory( LmSessionKey, sizeof(*LmSessionKey) );
RtlInitUnicodeString( &NullUnicodeString, NULL );
//
// Ensure the OWF password is always defined
//
if ( !Passwords->NtPasswordPresent ){
RtlCopyMemory( &Passwords->NtOwfPassword,
&NlpNullNtOwfPassword,
sizeof(Passwords->NtOwfPassword) );
}
if ( !Passwords->LmPasswordPresent ){
RtlCopyMemory( &Passwords->LmOwfPassword,
&NlpNullLmOwfPassword,
sizeof(Passwords->LmOwfPassword) );
}
//
// Handle interactive/service validation.
//
// Simply compare the OWF password passed in with the one from the
// SAM database.
//
switch ( LogonLevel ) {
case NetlogonInteractiveInformation:
case NetlogonServiceInformation:
ASSERT( offsetof( NETLOGON_INTERACTIVE_INFO, LmOwfPassword)
== offsetof( NETLOGON_SERVICE_INFO, LmOwfPassword) );
ASSERT( offsetof( NETLOGON_INTERACTIVE_INFO, NtOwfPassword)
== offsetof( NETLOGON_SERVICE_INFO, NtOwfPassword) );
LogonInteractiveInfo =
(PNETLOGON_INTERACTIVE_INFO) LogonInformation;
//
// If we're in UasCompatibilityMode,
// and we don't have the NT password in SAM (but do have LM password),
// validate against the LM version of the password.
//
if ( UasCompatibilityRequired &&
!Passwords->NtPasswordPresent &&
Passwords->LmPasswordPresent ) {
if ( RtlCompareMemory( &Passwords->LmOwfPassword,
&LogonInteractiveInfo->LmOwfPassword,
LM_OWF_PASSWORD_LENGTH ) !=
LM_OWF_PASSWORD_LENGTH ) {
return FALSE;
}
*UserFlags |= LOGON_USED_LM_PASSWORD;
//
// In all other circumstances, use the NT version of the password.
// This enforces case sensitivity.
//
} else {
if ( RtlCompareMemory( &Passwords->NtOwfPassword,
&LogonInteractiveInfo->NtOwfPassword,
NT_OWF_PASSWORD_LENGTH ) !=
NT_OWF_PASSWORD_LENGTH ) {
return FALSE;
}
}
break;
//
// Handle network logon validation.
//
case NetlogonNetworkInformation:
//
// First, assume the passed password information is a challenge
// response.
//
LogonNetworkInfo =
(PNETLOGON_NETWORK_INFO) LogonInformation;
// If the NT response is an NTLM3 response, do NTLM3 or NTLM3 with LM OWF
// if the length is > NT_RESPONSE_LENGTH, then it's an NTLM3 response
if (LogonNetworkInfo->NtChallengeResponse.Length > NT_RESPONSE_LENGTH) {
AlreadyValidated = MsvpNtlm3ValidateResponse (
&Passwords->NtOwfPassword,
&LogonNetworkInfo->Identity.UserName,
&LogonNetworkInfo->Identity.LogonDomainName,
(PUCHAR)&LogonNetworkInfo->LmChallenge,
(PMSV1_0_NTLM3_RESPONSE) LogonNetworkInfo->NtChallengeResponse.Buffer,
LogonNetworkInfo->NtChallengeResponse.Length,
UserSessionKey,
LmSessionKey
);
//
// because a Subauth may have been used, we will only return failure
// here if we know the request was NTLMv2.
//
if( AlreadyValidated ||
(LogonNetworkInfo->Identity.ParameterControl & MSV1_0_USE_CLIENT_CHALLENGE) ) {
return AlreadyValidated;
}
}
//
// check the LM3 response based on NT OWF hash next
// this will be recieved from Win9x server with NTLMv2 client
//
if (LogonNetworkInfo->LmChallengeResponse.Length == NT_RESPONSE_LENGTH) {
AlreadyValidated = MsvpLm3ValidateResponse (
&Passwords->NtOwfPassword,
&LogonNetworkInfo->Identity.UserName,
&LogonNetworkInfo->Identity.LogonDomainName,
(PUCHAR)&LogonNetworkInfo->LmChallenge,
(PMSV1_0_LM3_RESPONSE) LogonNetworkInfo->LmChallengeResponse.Buffer
);
if (AlreadyValidated)
return TRUE;
}
NtLmProtocolSupported = NtLmGlobalLmProtocolSupported;
// if we're requiring all clients (Win9x and NT) to have been upgraded, fail out now
if (NtLmProtocolSupported >= RefuseNtlm)
return FALSE;
// if that fails, check the NTLM response if there is one of the
// appropriate size in either NT response or LM response
if (!AlreadyValidated &&
(Passwords->NtPasswordPresent || (!Passwords->NtPasswordPresent && !Passwords->LmPasswordPresent)) &&
(LogonNetworkInfo->NtChallengeResponse.Length == NT_RESPONSE_LENGTH ||
LogonNetworkInfo->LmChallengeResponse.Length == NT_RESPONSE_LENGTH)) {
NT_RESPONSE NtResponse;
//
// Compute what the response should be.
//
Status = RtlCalculateNtResponse(
&LogonNetworkInfo->LmChallenge,
&Passwords->NtOwfPassword,
&NtResponse );
if ( NT_SUCCESS(Status) ) {
//
// If the responses match, the passwords are valid.
// Try the NT response first, then the LM response
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -