959 lines
24 KiB
C
959 lines
24 KiB
C
/*++
|
||
|
||
Copyright (c) 1987-1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ssiauth.c
|
||
|
||
Abstract:
|
||
|
||
Authentication related functions
|
||
|
||
Author:
|
||
|
||
Ported from Lan Man 2.0
|
||
|
||
Environment:
|
||
|
||
User mode only.
|
||
Contains NT-specific code.
|
||
Requires ANSI C extensions: slash-slash comments, long external names.
|
||
|
||
Revision History:
|
||
|
||
12-Jul-1991 (cliffv)
|
||
Ported to NT. Converted to NT style.
|
||
|
||
--*/
|
||
|
||
//
|
||
// Common include files.
|
||
//
|
||
|
||
#include "logonsrv.h" // Include files common to entire service
|
||
#pragma hdrstop
|
||
|
||
#include <cryptdll.h>
|
||
#include <wincrypt.h> // Crypto apis
|
||
|
||
|
||
LONG NlGlobalSessionCounter = 0;
|
||
|
||
|
||
NTSTATUS
|
||
NlMakeSessionKey(
|
||
IN ULONG NegotiatedFlags,
|
||
IN PNT_OWF_PASSWORD CryptKey,
|
||
IN PNETLOGON_CREDENTIAL ClientChallenge,
|
||
IN PNETLOGON_CREDENTIAL ServerChallenge,
|
||
OUT PNETLOGON_SESSION_KEY SessionKey
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build an encryption key for use in authentication for
|
||
this RequestorName.
|
||
|
||
Arguments:
|
||
|
||
NegotiatedFlags - Determines the strength of the key.
|
||
|
||
CryptKey -- The OWF password of the user account being used.
|
||
|
||
ClientChallenge -- 8 byte (64 bit) number generated by caller
|
||
|
||
ServerChallenge -- 8 byte (64 bit) number generated by primary
|
||
|
||
SessionKey -- 16 byte (128 bit) number generated at both ends
|
||
If the key strength is weak, the last 64 bits will be zero.
|
||
|
||
Return Value:
|
||
|
||
TRUE: Success
|
||
FALSE: Failure
|
||
|
||
NT status code.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
BLOCK_KEY BlockKey;
|
||
NETLOGON_SESSION_KEY TempSessionKey;
|
||
|
||
#ifndef NETSETUP_JOIN
|
||
PCHECKSUM_BUFFER CheckBuffer = NULL;
|
||
PCHECKSUM_FUNCTION Check;
|
||
#endif // NETSETUP_JOIN
|
||
|
||
//
|
||
// Start with a zero key
|
||
//
|
||
RtlZeroMemory(SessionKey, sizeof(NETLOGON_SESSION_KEY));
|
||
|
||
#ifdef NETSETUP_JOIN
|
||
UNREFERENCED_PARAMETER( NegotiatedFlags );
|
||
#else // NETSETUP_JOIN
|
||
//
|
||
// If the caller wants a strong key,
|
||
// Compute it.
|
||
//
|
||
if ( NegotiatedFlags & NETLOGON_SUPPORTS_STRONG_KEY ) {
|
||
|
||
// PCRYPTO_SYSTEM CryptSystem;
|
||
|
||
UCHAR LocalChecksum[sizeof(*SessionKey)];
|
||
// ULONG OutputSize;
|
||
|
||
//
|
||
// Initialize the checksum routines.
|
||
//
|
||
|
||
Status = CDLocateCheckSum( KERB_CHECKSUM_MD5_HMAC, &Check);
|
||
if (!NT_SUCCESS(Status)) {
|
||
NlPrint(( NL_CRITICAL,"NlMakeSessionKey: Failed to load checksum routines: 0x%x\n", Status));
|
||
goto Cleanup;
|
||
}
|
||
|
||
NlAssert(Check->CheckSumSize <= sizeof(LocalChecksum));
|
||
|
||
Status = Check->InitializeEx(
|
||
(LPBYTE)CryptKey,
|
||
sizeof( *CryptKey ),
|
||
0, // no message type
|
||
&CheckBuffer );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
NlPrint(( NL_CRITICAL,"NlMakeSessionKey: Failed to initialize checksum routines: 0x%x\n", Status));
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Sum in the client challenge, a constant, and the server challenge
|
||
//
|
||
|
||
Check->Sum( CheckBuffer,
|
||
sizeof(*ClientChallenge),
|
||
(PUCHAR)ClientChallenge );
|
||
|
||
Check->Sum( CheckBuffer,
|
||
sizeof(*ServerChallenge),
|
||
(PUCHAR)ServerChallenge );
|
||
|
||
//
|
||
// Finish the checksum
|
||
//
|
||
|
||
(void) Check->Finalize(CheckBuffer, LocalChecksum);
|
||
|
||
|
||
//
|
||
// Copy the checksum into the message.
|
||
//
|
||
|
||
NlAssert( sizeof(LocalChecksum) >= sizeof(*SessionKey) );
|
||
RtlCopyMemory( SessionKey, LocalChecksum, sizeof(*SessionKey) );
|
||
|
||
|
||
//
|
||
// Compute weaker (but backward compatible key)
|
||
//
|
||
} else {
|
||
#endif // NETSETUP_JOIN
|
||
|
||
//
|
||
// we will have a 128 bit key (64 bit encrypted rest padded with 0s)
|
||
//
|
||
// SessionKey = C + P (arithmetic sum ignore carry)
|
||
//
|
||
|
||
*((unsigned long * ) SessionKey) =
|
||
*((unsigned long * ) ClientChallenge) +
|
||
*((unsigned long * ) ServerChallenge);
|
||
|
||
*((unsigned long * )((LPBYTE)SessionKey + 4)) =
|
||
*((unsigned long * )((LPBYTE)ClientChallenge + 4)) +
|
||
*((unsigned long * )((LPBYTE)ServerChallenge + 4));
|
||
|
||
|
||
//
|
||
// CryptKey is our 16 byte key to be used as described in codespec
|
||
// use first 7 bytes of CryptKey for first encryption
|
||
//
|
||
|
||
RtlCopyMemory( &BlockKey, CryptKey, BLOCK_KEY_LENGTH );
|
||
|
||
Status = RtlEncryptBlock(
|
||
(PCLEAR_BLOCK) SessionKey, // Clear text
|
||
&BlockKey, // Key
|
||
(PCYPHER_BLOCK) &TempSessionKey); // Cypher Block
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Further encrypt the encrypted "SessionKey" using upper 7 bytes
|
||
//
|
||
|
||
NlAssert( LM_OWF_PASSWORD_LENGTH == 2*BLOCK_KEY_LENGTH+2 );
|
||
|
||
RtlCopyMemory( &BlockKey,
|
||
((PUCHAR)CryptKey) + 2 + BLOCK_KEY_LENGTH,
|
||
BLOCK_KEY_LENGTH );
|
||
|
||
Status = RtlEncryptBlock(
|
||
(PCLEAR_BLOCK) &TempSessionKey, // Clear text
|
||
&BlockKey, // Key
|
||
(PCYPHER_BLOCK) SessionKey); // Cypher Block
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
goto Cleanup;
|
||
}
|
||
#ifndef NETSETUP_JOIN
|
||
}
|
||
#endif // NETSETUP_JOIN
|
||
|
||
Cleanup:
|
||
#ifndef NETSETUP_JOIN
|
||
if (CheckBuffer != NULL) {
|
||
Status = Check->Finish(&CheckBuffer);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
NlPrint(( NL_CRITICAL,"NlMakeSessionKey: Failed to finish checksum: 0x%x\n", Status));
|
||
}
|
||
}
|
||
#endif // NETSETUP_JOIN
|
||
|
||
return Status;
|
||
}
|
||
|
||
#ifdef _DC_NETLOGON
|
||
|
||
NTSTATUS
|
||
NlCheckAuthenticator(
|
||
IN OUT PSERVER_SESSION ServerSession,
|
||
IN PNETLOGON_AUTHENTICATOR Authenticator,
|
||
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Verify that supplied Authenticator is valid.
|
||
It is intended for use by the server side after initial authentication
|
||
has succeeded. This routine will modify the seed by
|
||
first adding the time-of-day received from the Authenticator
|
||
and then by incrementing it.
|
||
|
||
A ReturnAuthenticator is built based on the final seed.
|
||
|
||
Arguments:
|
||
|
||
ServerSession - Pointer to the ServerSession structure. The following
|
||
fields are used:
|
||
|
||
SsAuthenticationSeed - Supplies the seed used for authentication and
|
||
returns the updated seed.
|
||
|
||
SsSessionKey - The session key used for encryption.
|
||
|
||
SsCheck - Is zeroed to indicate successful communication with the client.
|
||
|
||
Authenticator - The authenticator passed by the caller.
|
||
|
||
ReturnAuthenticator - The authenticator we'll return to the caller.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS;
|
||
STATUS_ACCESS_DENIED;
|
||
STATUS_TIME_DIFFERENCE_AT_DC;
|
||
|
||
--*/
|
||
{
|
||
|
||
NETLOGON_CREDENTIAL TargetCredential;
|
||
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES,"NlCheckAuthenticator: Seed = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &ServerSession->SsAuthenticationSeed, sizeof(ServerSession->SsAuthenticationSeed) );
|
||
|
||
NlPrint((NL_CHALLENGE_RES, "NlCheckAuthenticator: SessionKey = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &ServerSession->SsSessionKey, sizeof(ServerSession->SsSessionKey) );
|
||
|
||
NlPrint((NL_CHALLENGE_RES, "NlCheckAuthenticator: Client Authenticator GOT = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &Authenticator->Credential, sizeof(Authenticator->Credential) );
|
||
|
||
NlPrint((NL_CHALLENGE_RES, "NlCheckAuthenticator: Time = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &Authenticator->timestamp, sizeof(Authenticator->timestamp) );
|
||
|
||
|
||
|
||
//
|
||
// modify the seed before computing auth_credential for verification
|
||
// Two long words are added and overflow carry (if any) ignored
|
||
// This will leave upper 4 bytes unchanged
|
||
//
|
||
|
||
*((unsigned long * ) &ServerSession->SsAuthenticationSeed) += Authenticator->timestamp;
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES, "NlCheckAuthenticator: Seed + TIME = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &ServerSession->SsAuthenticationSeed, sizeof(ServerSession->SsAuthenticationSeed) );
|
||
|
||
|
||
//
|
||
// Compute TargetCredential to verify the one supplied in the Authenticator
|
||
//
|
||
|
||
NlComputeCredentials( &ServerSession->SsAuthenticationSeed,
|
||
&TargetCredential,
|
||
&ServerSession->SsSessionKey );
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES, "NlCheckAuthenticator: Client Authenticator MADE = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &TargetCredential, sizeof(TargetCredential) );
|
||
|
||
//
|
||
// verify the computed credentials with those supplied
|
||
// Authenticator must have used seed + time_of_day as seed
|
||
//
|
||
|
||
if (!RtlEqualMemory( &Authenticator->Credential,
|
||
&TargetCredential,
|
||
sizeof(TargetCredential)) ) {
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
//
|
||
// modify our seed before computing the ReturnAuthenticator.
|
||
// The requestor will increment his seed if he matches this credentials.
|
||
//
|
||
|
||
(*((unsigned long * ) &ServerSession->SsAuthenticationSeed))++;
|
||
|
||
//
|
||
// compute ClientCredential to send back to requestor
|
||
//
|
||
|
||
NlComputeCredentials( &ServerSession->SsAuthenticationSeed,
|
||
&ReturnAuthenticator->Credential,
|
||
&ServerSession->SsSessionKey);
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES,
|
||
"NlCheckAuthenticator: Server Authenticator SEND = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &ReturnAuthenticator->Credential, sizeof(ReturnAuthenticator->Credential) );
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES, "NlCheckAuthenticator: Seed + time + 1= " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &ServerSession->SsAuthenticationSeed, sizeof(ServerSession->SsAuthenticationSeed) );
|
||
|
||
|
||
//
|
||
// Indicate successful communication with the client
|
||
//
|
||
|
||
ServerSession->SsCheck = 0;
|
||
ServerSession->SsPulseTimeoutCount = 0;
|
||
ServerSession->SsFlags &= ~SS_PULSE_SENT;
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
#endif // _DC_NETLOGON
|
||
|
||
|
||
VOID
|
||
NlComputeCredentials(
|
||
IN PNETLOGON_CREDENTIAL Challenge,
|
||
OUT PNETLOGON_CREDENTIAL Credential,
|
||
IN PNETLOGON_SESSION_KEY SessionKey
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Calculate the credentials by encrypting the 8 byte
|
||
challenge with first 7 bytes of sessionkey and then
|
||
further encrypting it by next 7 bytes of sessionkey.
|
||
|
||
Arguments:
|
||
|
||
Challenge - Supplies the 8 byte (64 bit) challenge
|
||
|
||
Credential - Returns the 8 byte (64 bit) number generated
|
||
|
||
SessionKey - Supplies 14 byte (112 bit) encryption key
|
||
The buffer is 16 bytes (128 bits) long. For a weak key, the trailing 8 bytes
|
||
are zero. For a strong key, this routine ingored that trailing 2 bytes of
|
||
useful key.
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
BLOCK_KEY BlockKey;
|
||
CYPHER_BLOCK IntermediateBlock;
|
||
|
||
RtlZeroMemory(Credential, sizeof(*Credential));
|
||
|
||
//
|
||
// use first 7 bytes of SessionKey for first encryption
|
||
//
|
||
|
||
RtlCopyMemory( &BlockKey, SessionKey, BLOCK_KEY_LENGTH );
|
||
|
||
Status = RtlEncryptBlock( (PCLEAR_BLOCK) Challenge, // Cleartext
|
||
&BlockKey, // Key
|
||
&IntermediateBlock ); // Cypher Block
|
||
|
||
NlAssert( NT_SUCCESS(Status) );
|
||
|
||
//
|
||
// further encrypt the encrypted Credential using next 7 bytes
|
||
//
|
||
|
||
RtlCopyMemory( &BlockKey,
|
||
((PUCHAR)SessionKey) + BLOCK_KEY_LENGTH,
|
||
BLOCK_KEY_LENGTH );
|
||
|
||
Status = RtlEncryptBlock( (PCLEAR_BLOCK) &IntermediateBlock, // Cleartext
|
||
&BlockKey, // Key
|
||
Credential ); // Cypher Block
|
||
|
||
NlAssert( NT_SUCCESS(Status) );
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NlComputeChallenge(
|
||
OUT PNETLOGON_CREDENTIAL Challenge
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Generates a 64 bit challenge
|
||
|
||
Arguments:
|
||
|
||
Challenge - Returns the computed challenge
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Use an ideal random bit generator.
|
||
//
|
||
|
||
if (!NlGenerateRandomBits( (LPBYTE)Challenge, sizeof(*Challenge) )) {
|
||
NlPrint((NL_CRITICAL, "Can't NlGenerateRandomBits\n" ));
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NlBuildAuthenticator(
|
||
IN OUT PNETLOGON_CREDENTIAL AuthenticationSeed,
|
||
IN PNETLOGON_SESSION_KEY SessionKey,
|
||
OUT PNETLOGON_AUTHENTICATOR Authenticator
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build the authenticator to be sent to primary.
|
||
This routine will modify the seed by adding the
|
||
time-of-day before computing the credentials.
|
||
|
||
Arguments:
|
||
|
||
AuthenticationSeed -- The current authentication seed. This seed will
|
||
have the current time of day added to it prior to building the
|
||
Authenticator.
|
||
|
||
SessionKey - The Session Key used for encrypting the Authenticator.
|
||
|
||
Authenticator - The Authenticator to pass to the PDC for the current
|
||
call.
|
||
|
||
Return Value:
|
||
|
||
NT Status code
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
LARGE_INTEGER TimeNow;
|
||
|
||
//
|
||
// Use the current time of day to modify the authentication seed
|
||
//
|
||
|
||
RtlZeroMemory(Authenticator, sizeof(*Authenticator));
|
||
|
||
NlQuerySystemTime( &TimeNow );
|
||
|
||
Status = RtlTimeToSecondsSince1970( &TimeNow, &Authenticator->timestamp );
|
||
NlAssert( NT_SUCCESS(Status) );
|
||
|
||
//
|
||
// Modify the AuthenticationSeed before computing auth_credential for
|
||
// verification .
|
||
//
|
||
// Two long words are added and overflow carry (if any) ignored
|
||
// This will leave upper 4 bytes unchanged
|
||
//
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES,"NlBuildAuthenticator: Old Seed = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, AuthenticationSeed, sizeof(*AuthenticationSeed) );
|
||
|
||
NlPrint((NL_CHALLENGE_RES,"NlBuildAuthenticator: Time = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &Authenticator->timestamp, sizeof(Authenticator->timestamp) );
|
||
|
||
|
||
|
||
*((unsigned long * ) AuthenticationSeed) += Authenticator->timestamp;
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES,"NlBuildAuthenticator: New Seed = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, AuthenticationSeed, sizeof(*AuthenticationSeed) );
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES, "NlBuildAuthenticator: SessionKey = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, SessionKey, sizeof(*SessionKey) );
|
||
|
||
|
||
//
|
||
// compute AuthenticationSeed to verify the one supplied by Requestor
|
||
//
|
||
|
||
NlComputeCredentials( AuthenticationSeed,
|
||
&Authenticator->Credential,
|
||
SessionKey);
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES,"NlBuildAuthenticator: Client Authenticator = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &Authenticator->Credential, sizeof(Authenticator->Credential) );
|
||
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
BOOL
|
||
NlUpdateSeed(
|
||
IN OUT PNETLOGON_CREDENTIAL AuthenticationSeed,
|
||
IN PNETLOGON_CREDENTIAL TargetCredential,
|
||
IN PNETLOGON_SESSION_KEY SessionKey
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called by the initiator of a communication over the secure channel
|
||
following a successful transaction.
|
||
|
||
The PDC would have incremented the seed so we must do so also.
|
||
|
||
We also verify that the incremented seed builds a credential identical
|
||
to the one passed back by the PDC.
|
||
|
||
Arguments:
|
||
|
||
AuthenticationSeed - Pointer to the AuthenticationSeed to be incremented.
|
||
|
||
TargetCredential - Supplies the Credential that the incremented
|
||
AuthenticationSeed should encrypt to.
|
||
|
||
SessionKey - Supplies the encryption key to use for the encryption.
|
||
|
||
Return Value:
|
||
|
||
TRUE: Success
|
||
FALSE: Failure
|
||
|
||
--*/
|
||
{
|
||
NETLOGON_CREDENTIAL NewCredential;
|
||
|
||
//
|
||
// modify our AuthenticationSeed before computing NewCredential to check
|
||
// those returned from primary (NewSeed = AuthenticationSeed+1)
|
||
//
|
||
|
||
(*((unsigned long * ) AuthenticationSeed))++;
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES,"NlUpdateSeed: Seed + time + 1= " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, AuthenticationSeed, sizeof(*AuthenticationSeed) );
|
||
|
||
|
||
//
|
||
// Compute ClientCredential to check which came from primary
|
||
//
|
||
|
||
NlComputeCredentials(AuthenticationSeed, &NewCredential, SessionKey);
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES,"NlUpdateSeed: Server Authenticator GOT = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, TargetCredential, sizeof(*TargetCredential) );
|
||
|
||
|
||
NlPrint((NL_CHALLENGE_RES,"NlUpdateSeed: Server Authenticator MADE = " ));
|
||
NlpDumpBuffer(NL_CHALLENGE_RES, &NewCredential, sizeof(NewCredential) );
|
||
|
||
|
||
if ( !RtlEqualMemory( TargetCredential, &NewCredential, sizeof(NewCredential)) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
NlEncryptRC4(
|
||
IN OUT PVOID Buffer,
|
||
IN ULONG BufferSize,
|
||
IN PSESSION_INFO SessionInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Encrypt data using RC4 with the session key as the key.
|
||
|
||
Arguments:
|
||
|
||
Buffer -- Buffer containing the data to encrypt in place.
|
||
|
||
BufferSize -- Size (in bytes) of Buffer.
|
||
|
||
SessionInfo -- Info describing secure channel
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS NtStatus;
|
||
DATA_KEY KeyData;
|
||
CRYPT_BUFFER Data;
|
||
|
||
//
|
||
// Build a data buffer to describe the encryption key.
|
||
//
|
||
|
||
KeyData.Length = sizeof(NETLOGON_SESSION_KEY);
|
||
KeyData.MaximumLength = sizeof(NETLOGON_SESSION_KEY);
|
||
KeyData.Buffer = (PVOID)&SessionInfo->SessionKey;
|
||
|
||
NlAssert( SessionInfo->NegotiatedFlags & NETLOGON_SUPPORTS_RC4_ENCRYPTION );
|
||
|
||
//
|
||
// Build a data buffer to decribe the encrypted data.
|
||
//
|
||
|
||
Data.Length = Data.MaximumLength = BufferSize;
|
||
Data.Buffer = Buffer;
|
||
|
||
//
|
||
// Encrypt the data.
|
||
//
|
||
|
||
IF_NL_DEBUG( ENCRYPT ) {
|
||
NlPrint((NL_ENCRYPT, "NlEncryptRC4: Clear data: " ));
|
||
NlpDumpBuffer( NL_ENCRYPT, Data.Buffer, Data.Length );
|
||
}
|
||
|
||
NtStatus = RtlEncryptData2( &Data, &KeyData );
|
||
NlAssert( NT_SUCCESS(NtStatus) );
|
||
|
||
IF_NL_DEBUG( ENCRYPT ) {
|
||
NlPrint((NL_ENCRYPT, "NlEncryptRC4: Encrypted data: " ));
|
||
NlpDumpBuffer( NL_ENCRYPT, Data.Buffer, Data.Length );
|
||
}
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
NlDecryptRC4(
|
||
IN OUT PVOID Buffer,
|
||
IN ULONG BufferSize,
|
||
IN PSESSION_INFO SessionInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Decrypt data using RC4 with the session key as the key.
|
||
|
||
Arguments:
|
||
|
||
Buffer -- Buffer containing the data to decrypt in place.
|
||
|
||
BufferSize -- Size (in bytes) of Buffer.
|
||
|
||
SessionInfo -- Info describing secure channel
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS NtStatus;
|
||
DATA_KEY KeyData;
|
||
CRYPT_BUFFER Data;
|
||
|
||
//
|
||
// Build a data buffer to describe the encryption key.
|
||
//
|
||
|
||
KeyData.Length = sizeof(NETLOGON_SESSION_KEY);
|
||
KeyData.MaximumLength = sizeof(NETLOGON_SESSION_KEY);
|
||
KeyData.Buffer = (PVOID)&SessionInfo->SessionKey;
|
||
|
||
NlAssert( SessionInfo->NegotiatedFlags & NETLOGON_SUPPORTS_RC4_ENCRYPTION );
|
||
|
||
//
|
||
// Build a data buffer to decribe the encrypted data.
|
||
//
|
||
|
||
Data.Length = Data.MaximumLength = BufferSize;
|
||
Data.Buffer = Buffer;
|
||
|
||
//
|
||
// Encrypt the data.
|
||
//
|
||
|
||
|
||
IF_NL_DEBUG( ENCRYPT ) {
|
||
NlPrint((NL_ENCRYPT, "NlDecryptRC4: Encrypted data: " ));
|
||
NlpDumpBuffer( NL_ENCRYPT, Data.Buffer, Data.Length );
|
||
}
|
||
|
||
NtStatus = RtlDecryptData2( &Data, &KeyData );
|
||
NlAssert( NT_SUCCESS(NtStatus) );
|
||
|
||
IF_NL_DEBUG( ENCRYPT ) {
|
||
NlPrint((NL_ENCRYPT, "NlDecryptRC4: Clear data: " ));
|
||
NlpDumpBuffer( NL_ENCRYPT, Data.Buffer, Data.Length );
|
||
}
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
NlGenerateRandomBits(
|
||
PUCHAR Buffer,
|
||
ULONG BufferLen
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Generates random bits
|
||
|
||
Arguments:
|
||
|
||
pBuffer - Buffer to fill
|
||
|
||
cbBuffer - Number of bytes in buffer
|
||
|
||
Return Value:
|
||
|
||
Status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
if( !CryptGenRandom( NlGlobalCryptProvider, BufferLen, ( LPBYTE )Buffer ) )
|
||
{
|
||
NlPrint((NL_CRITICAL, "CryptGenRandom failed with %lu\n", GetLastError() ));
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
#ifndef NETSETUP_JOIN
|
||
|
||
VOID
|
||
NlPrintTrustedDomain(
|
||
PDS_DOMAIN_TRUSTSW TrustedDomain,
|
||
IN BOOLEAN VerbosePrint,
|
||
IN BOOLEAN AnsiOutput
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Print a trusted domain structure
|
||
|
||
Arguments:
|
||
|
||
TrustedDomain -- Structure to print
|
||
|
||
VerbosePrint - If TRUE, output domain's GUID and SID
|
||
|
||
AnsiOutput - If TRUE, names are in ansi format
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if ( AnsiOutput ) {
|
||
if ( TrustedDomain->NetbiosDomainName != NULL ) {
|
||
NlPrint(( NL_LOGON, " %s", TrustedDomain->NetbiosDomainName ));
|
||
}
|
||
if ( TrustedDomain->DnsDomainName != NULL ) {
|
||
NlPrint(( NL_LOGON, " %s", TrustedDomain->DnsDomainName ));
|
||
}
|
||
} else {
|
||
if ( TrustedDomain->NetbiosDomainName != NULL ) {
|
||
NlPrint(( NL_LOGON, " %ws", TrustedDomain->NetbiosDomainName ));
|
||
}
|
||
if ( TrustedDomain->DnsDomainName != NULL ) {
|
||
NlPrint(( NL_LOGON, " %ws", TrustedDomain->DnsDomainName ));
|
||
}
|
||
}
|
||
|
||
switch ( TrustedDomain->TrustType ) {
|
||
case TRUST_TYPE_DOWNLEVEL:
|
||
NlPrint(( NL_LOGON, " (NT 4)" ); break);
|
||
case TRUST_TYPE_UPLEVEL:
|
||
NlPrint(( NL_LOGON, " (NT 5)" ); break);
|
||
case TRUST_TYPE_MIT:
|
||
NlPrint(( NL_LOGON, " (MIT)" ); break);
|
||
case TRUST_TYPE_DCE:
|
||
NlPrint(( NL_LOGON, " (DCE)" ); break);
|
||
default:
|
||
NlPrint(( NL_LOGON, " (Unknown Trust Type: %ld)", TrustedDomain->TrustType ); break);
|
||
}
|
||
|
||
if ( TrustedDomain->Flags ) {
|
||
ULONG Flags;
|
||
Flags = TrustedDomain->Flags;
|
||
if ( Flags & DS_DOMAIN_IN_FOREST ) {
|
||
if ( Flags & DS_DOMAIN_TREE_ROOT ) {
|
||
NlPrint(( NL_LOGON, " (Forest Tree Root)" ));
|
||
Flags &= ~DS_DOMAIN_TREE_ROOT;
|
||
} else {
|
||
NlPrint(( NL_LOGON, " (Forest: %ld)", TrustedDomain->ParentIndex ));
|
||
}
|
||
Flags &= ~DS_DOMAIN_IN_FOREST;
|
||
}
|
||
if ( Flags & DS_DOMAIN_DIRECT_OUTBOUND ) {
|
||
NlPrint(( NL_LOGON, " (Direct Outbound)"));
|
||
Flags &= ~DS_DOMAIN_DIRECT_OUTBOUND;
|
||
}
|
||
if ( Flags & DS_DOMAIN_DIRECT_INBOUND ) {
|
||
NlPrint(( NL_LOGON, " (Direct Inbound)"));
|
||
Flags &= ~DS_DOMAIN_DIRECT_INBOUND;
|
||
}
|
||
if ( Flags & DS_DOMAIN_TREE_ROOT ) {
|
||
NlPrint(( NL_LOGON, " (Tree Root but not in forest!!!!)"));
|
||
Flags &= ~DS_DOMAIN_TREE_ROOT;
|
||
}
|
||
if ( Flags & DS_DOMAIN_PRIMARY ) {
|
||
NlPrint(( NL_LOGON, " (Primary Domain)"));
|
||
Flags &= ~DS_DOMAIN_PRIMARY;
|
||
}
|
||
if ( Flags & DS_DOMAIN_NATIVE_MODE ) {
|
||
NlPrint(( NL_LOGON, " (Native)"));
|
||
Flags &= ~DS_DOMAIN_NATIVE_MODE;
|
||
}
|
||
if ( Flags != 0 ) {
|
||
NlPrint(( NL_LOGON, " 0x%lX", Flags));
|
||
}
|
||
}
|
||
|
||
if ( TrustedDomain->TrustAttributes ) {
|
||
ULONG TrustAttributes = TrustedDomain->TrustAttributes;
|
||
NlPrint(( NL_LOGON, " ( Attr:" ));
|
||
if ( TrustAttributes & TRUST_ATTRIBUTE_NON_TRANSITIVE ) {
|
||
NlPrint(( NL_LOGON, " non-trans"));
|
||
TrustAttributes &= ~TRUST_ATTRIBUTE_NON_TRANSITIVE;
|
||
}
|
||
if ( TrustAttributes & TRUST_ATTRIBUTE_UPLEVEL_ONLY ) {
|
||
NlPrint(( NL_LOGON, " uplevel-only"));
|
||
TrustAttributes &= ~TRUST_ATTRIBUTE_UPLEVEL_ONLY;
|
||
}
|
||
if ( TrustAttributes & TRUST_ATTRIBUTE_FILTER_SIDS ) {
|
||
NlPrint(( NL_LOGON, " filtered"));
|
||
TrustAttributes &= ~TRUST_ATTRIBUTE_FILTER_SIDS;
|
||
}
|
||
if ( TrustAttributes != 0 ) {
|
||
NlPrint(( NL_LOGON, " 0x%lX", TrustAttributes));
|
||
}
|
||
NlPrint(( NL_LOGON, " )"));
|
||
}
|
||
|
||
//
|
||
// Output domain's GUID and SID
|
||
//
|
||
|
||
if ( VerbosePrint ) {
|
||
if ( !IsEqualGUID( &TrustedDomain->DomainGuid, &NlGlobalZeroGuid) ) {
|
||
RPC_STATUS RpcStatus;
|
||
char *StringGuid;
|
||
|
||
NlPrint(( NL_LOGON, "\n" ));
|
||
NlPrint(( NL_LOGON, " Dom Guid: " ));
|
||
RpcStatus = UuidToStringA( &TrustedDomain->DomainGuid, &StringGuid );
|
||
if ( RpcStatus == RPC_S_OK ) {
|
||
NlPrint(( NL_LOGON, "%s", StringGuid ));
|
||
RpcStringFreeA( &StringGuid );
|
||
} else {
|
||
NlPrint(( NL_LOGON, "Not available because UuidToStringA failed" ));
|
||
}
|
||
}
|
||
|
||
NlPrint(( NL_LOGON, "\n" ));
|
||
if ( TrustedDomain->DomainSid != NULL ) {
|
||
NlPrint(( NL_LOGON, " Dom Sid: " ));
|
||
NlpDumpSid( NL_LOGON, TrustedDomain->DomainSid );
|
||
}
|
||
} else {
|
||
NlPrint(( NL_LOGON, "\n" ));
|
||
}
|
||
}
|
||
#endif // NETSETUP_JOIN
|