📄 context.cxx
字号:
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
context.cxx
Abstract:
API and support routines for handling security contexts.
Author:
Cliff Van Dyke (CliffV) 13-Jul-1993
Revision History:
ChandanS 03-Aug-1996 Stolen from net\svcdlls\ntlmssp\common\context.c
--*/
//
// Common include files.
//
#include <global.h>
#include <align.h> // ALIGN_WCHAR, etc
extern "C"
{
#include <crypt.h> // Encryption constants and routine
#include <rc4.h> // RC4 encryption types and functions
#include <md5.h>
}
// Globals for manipulating Context Lists while in Lsa Mode
CRITICAL_SECTION SspContextCritSect;
LIST_ENTRY SspContextList;
//
// Performance counters
//
#define TRACK_REQUESTS
#ifdef TRACK_REQUESTS
LONG ServerAuthentications;
LONG ClientAuthentications;
#define INC_CLIENT_AUTH() (InterlockedIncrement(&ClientAuthentications))
#define INC_SERVER_AUTH() (InterlockedIncrement(&ServerAuthentications))
#else
#define INC_CLIENT_AUTH()
#define INC_SERVER_AUTH()
#endif
PSSP_CONTEXT
SspContextReferenceContext(
IN ULONG_PTR ContextHandle,
IN BOOLEAN RemoveContext
)
/*++
Routine Description:
This routine checks to see if the Context is for the specified
Client Connection, and references the Context if it is valid.
The caller may optionally request that the Context be
removed from the list of valid Contexts - preventing future
requests from finding this Context.
Arguments:
ContextHandle - Points to the ContextHandle of the Context
to be referenced.
RemoveContext - This boolean value indicates whether the caller
wants the Context to be removed from the list
of Contexts. TRUE indicates the Context is to be removed.
FALSE indicates the Context is not to be removed.
Return Value:
NULL - the Context was not found.
Otherwise - returns a pointer to the referenced Context.
--*/
{
PLIST_ENTRY ListEntry;
PSSP_CONTEXT Context;
SspPrint(( SSP_API_MORE, "Entering SspContextReferenceContext\n" ));
#if 0
//
// check that usermode/kernel mode caller matches.
//
SECPKG_CALL_INFO CallInfo;
BOOLEAN KernelCaller;
if( LsaFunctions->GetCallInfo(&CallInfo) ) {
KernelCaller = ((CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE) != 0);
}
#endif
//
// Acquire exclusive access to the Context list
//
EnterCriticalSection( &SspContextCritSect );
//
// Now walk the list of Contexts looking for a match.
//
for ( ListEntry = SspContextList.Flink;
ListEntry != &SspContextList;
ListEntry = ListEntry->Flink ) {
Context = CONTAINING_RECORD( ListEntry, SSP_CONTEXT, Next );
//
// Found a match ... reference this Context
// (if the Context is being removed, we would increment
// and then decrement the reference, so don't bother doing
// either - since they cancel each other out).
//
if ( Context == (PSSP_CONTEXT) ContextHandle)
{
#if 0
ASSERT( (KernelCaller == Context->KernelClient) );
#endif
if (!RemoveContext)
{
//
// Timeout this context if caller is not trying to remove it.
// We only timeout contexts that are being setup, not
// fully authenticated contexts.
//
if (SspTimeHasElapsed( Context->StartTime, Context->Interval))
{
if ((Context->State != AuthenticatedState) &&
(Context->State != AuthenticateSentState) &&
(Context->State != PassedToServiceState))
{
SspPrint(( SSP_CRITICAL, "Context 0x%lx has timed out.\n",
ContextHandle ));
LeaveCriticalSection( &SspContextCritSect );
return NULL;
}
}
Context->References += 1;
}
else
{
RemoveEntryList( &Context->Next );
SspPrint(( SSP_API_MORE, "Delinked Context 0x%lx\n",
Context ));
}
SspPrint(( SSP_LEAK_TRACK, "SspContextReferenceContext for Context = 0x%x, RemoveContext = %d, ReferenceCount = %d\n", Context, RemoveContext, Context->References));
LeaveCriticalSection( &SspContextCritSect );
SspPrint(( SSP_API_MORE, "Leaving SspContextReferenceContext\n" ));
return Context;
}
}
//
// No match found
//
SspPrint(( SSP_API_MORE, "Tried to reference unknown Context 0x%lx\n",
ContextHandle ));
LeaveCriticalSection( &SspContextCritSect );
return NULL;
}
VOID
SspContextDereferenceContext(
PSSP_CONTEXT Context
)
/*++
Routine Description:
This routine decrements the specified Context's reference count.
If the reference count drops to zero, then the Context is deleted
Arguments:
Context - Points to the Context to be dereferenced.
Return Value:
None.
--*/
{
ULONG References;
SspPrint(( SSP_API_MORE, "Entering SspContextDereferenceContext\n" ));
//
// Decrement the reference count
//
EnterCriticalSection( &SspContextCritSect );
ASSERT( Context->References >= 1 );
References = -- Context->References;
SspPrint(( SSP_LEAK_TRACK, "SspContextDereferenceContext for Context = 0x%x, ReferenceCount = %d\n", Context, Context->References));
LeaveCriticalSection( &SspContextCritSect );
//
// If the count dropped to zero, then run-down the Context
//
if (References == 0) {
SspPrint(( SSP_API_MORE, "Deleting Context 0x%lx\n",
Context ));
if ( Context->DomainName.Buffer != NULL ) {
(VOID) NtLmFree( Context->DomainName.Buffer );
}
if ( Context->UserName.Buffer != NULL ) {
(VOID) NtLmFree( Context->UserName.Buffer );
}
if ( Context->Password.Buffer != NULL ) {
// note: Password.Length may contain run-encoding hint, so size may be illegal.
ZeroMemory( Context->Password.Buffer, Context->Password.MaximumLength );
(VOID) NtLmFree( Context->Password.Buffer );
}
if ( Context->TokenHandle != NULL ) {
NTSTATUS IgnoreStatus;
IgnoreStatus = NtClose( Context->TokenHandle );
ASSERT( NT_SUCCESS(IgnoreStatus) );
}
if (Context->Credential != NULL) {
SspCredentialDereferenceCredential( Context->Credential );
}
ZeroMemory( Context, sizeof(SSP_CONTEXT) );
(VOID) NtLmFree( Context );
}
return;
}
PSSP_CONTEXT
SspContextAllocateContext(
)
/*++
Routine Description:
This routine allocates the security context block, initializes it and
links it onto the specified credential.
Arguments: None
Return Value:
NULL -- Not enough memory to allocate context.
otherwise -- pointer to allocated and referenced context.
--*/
{
SspPrint(( SSP_API_MORE, "Entering SspContextAllocateContext\n" ));
PSSP_CONTEXT Context;
SECPKG_CALL_INFO CallInfo;
//
// Allocate a Context block and initialize it.
//
Context = (PSSP_CONTEXT)NtLmAllocate(sizeof(SSP_CONTEXT) );
if ( Context == NULL ) {
SspPrint(( SSP_CRITICAL, "SspContextAllocateContext: Error allocating Context.\n" ));
return NULL;
}
ZeroMemory( Context, sizeof(SSP_CONTEXT) );
if( LsaFunctions->GetCallInfo(&CallInfo) ) {
Context->ClientProcessID = CallInfo.ProcessId;
Context->KernelClient = ((CallInfo.Attributes & SECPKG_CALL_KERNEL_MODE) != 0);
}
//
// The reference count is set to 2. 1 to indicate it is on the
// valid Context list, and one for the our own reference.
//
Context->References = 2;
Context->State = IdleState;
//
// Timeout this context.
//
(VOID) NtQuerySystemTime( &Context->StartTime );
Context->Interval = NTLMSSP_MAX_LIFETIME;
//
// Add it to the list of valid Context handles.
//
EnterCriticalSection( &SspContextCritSect );
InsertHeadList( &SspContextList, &Context->Next );
SspPrint(( SSP_LEAK_TRACK, "SspContextAllocateContext for Context = 0x%x, ReferenceCount = %d\n", Context, Context->References));
LeaveCriticalSection( &SspContextCritSect );
SspPrint(( SSP_API_MORE, "Added Context 0x%lx\n", Context ));
SspPrint(( SSP_API_MORE, "Leaving SspContextAllocateContext\n" ));
return Context;
}
NTSTATUS
SspContextGetMessage(
IN PVOID InputMessage,
IN ULONG InputMessageSize,
IN NTLM_MESSAGE_TYPE ExpectedMessageType,
OUT PVOID* OutputMessage
)
/*++
Routine Description:
This routine copies the InputMessage into the local address space.
This routine then validates the message header.
Arguments:
InputMessage - Address of the message in the client process.
InputMessageSize - Size of the message (in bytes).
ExpectedMessageType - The type of message the should be in the message
header.
OutputMessage - Returns a pointer to an allocated buffer that contains
the message. The buffer should be freed using NtLmFree.
Return Value:
STATUS_SUCCESS - Call completed successfully
SEC_E_INVALID_TOKEN -- Message improperly formatted
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory to allocate message
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PNEGOTIATE_MESSAGE TypicalMessage = NULL;
//
// Allocate a local buffer for the message.
//
ASSERT( NTLMSP_MAX_TOKEN_SIZE >= NTLMSSP_MAX_MESSAGE_SIZE );
if ( InputMessageSize > NTLMSSP_MAX_MESSAGE_SIZE ) {
Status = SEC_E_INVALID_TOKEN;
SspPrint(( SSP_CRITICAL, "SspContextGetMessage, invalid input message size.\n" ));
goto Cleanup;
}
TypicalMessage = (PNEGOTIATE_MESSAGE)NtLmAllocate(InputMessageSize );
if ( TypicalMessage == NULL ) {
Status = STATUS_NO_MEMORY;
SspPrint(( SSP_CRITICAL, "SspContextGetMessage: Error allocating TypicalMessage.\n" ));
goto Cleanup;
}
//
// Copy the message into the buffer
//
RtlCopyMemory( TypicalMessage,
InputMessage,
InputMessageSize );
//
// Validate the message header.
//
if ( strncmp( (const char *)TypicalMessage->Signature,
NTLMSSP_SIGNATURE,
sizeof(NTLMSSP_SIGNATURE)) != 0 ||
TypicalMessage->MessageType != ExpectedMessageType ) {
(VOID) NtLmFree( TypicalMessage );
TypicalMessage = NULL;
Status = SEC_E_INVALID_TOKEN;
SspPrint(( SSP_CRITICAL, "SspContextGetMessage, Bogus Message.\n" ));
goto Cleanup;
}
Cleanup:
*OutputMessage = TypicalMessage;
return Status;
}
VOID
SspContextCopyString(
IN PVOID MessageBuffer,
OUT PSTRING32 OutString,
IN PSTRING InString,
IN OUT PCHAR *Where
)
/*++
Routine Description:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -