windows-nt/Source/XPSP1/NT/ds/security/protocols/kerberos/kernel/ctxtmgr.cxx
2020-09-26 16:20:57 +08:00

813 lines
19 KiB
C++

//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1992 - 1996
//
// File: ctxtmgr.cxx
//
// Contents: Code for managing contexts list for the Kerberos package
//
//
// History: 17-April-1996 Created MikeSw
//
//------------------------------------------------------------------------
#define CTXTMGR_ALLOCATE
#include <kerbkrnl.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, KerbInitContextList)
#pragma alloc_text(PAGE, KerbFreeContextList)
#pragma alloc_text(PAGEMSG, KerbAllocateContext)
#pragma alloc_text(PAGEMSG, KerbInsertContext)
#pragma alloc_text(PAGEMSG, KerbReferenceContext)
#pragma alloc_text(PAGEMSG, KerbDereferenceContext)
#pragma alloc_text(PAGEMSG, KerbReferenceContextByPointer)
#pragma alloc_text(PAGEMSG, KerbReferenceContextByLsaHandle)
#pragma alloc_text(PAGEMSG, KerbCreateKernelModeContext)
#endif
#define MAYBE_PAGED_CODE() \
if ( KerbPoolType == PagedPool ) \
{ \
PAGED_CODE(); \
}
//+-------------------------------------------------------------------------
//
// Function: KerbInitContextList
//
// Synopsis: Initializes the contexts list
//
// Effects: allocates a resources
//
// Arguments: none
//
// Requires:
//
// Returns: STATUS_SUCCESS on success, other error codes
// on failure
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
KerbInitContextList(
VOID
)
{
NTSTATUS Status;
PAGED_CODE();
Status = ExInitializeResourceLite( &KerbContextResource );
if (!NT_SUCCESS(Status))
{
return(Status);
}
Status = KerbInitializeList( &KerbContextList );
if (!NT_SUCCESS(Status))
{
ExDeleteResourceLite( &KerbContextResource );
goto Cleanup;
}
KerberosContextsInitialized = TRUE;
Cleanup:
return(Status);
}
#if 0
//+-------------------------------------------------------------------------
//
// Function: KerbFreeContextList
//
// Synopsis: Frees the contexts list
//
// Effects:
//
// Arguments: none
//
// Requires:
//
// Returns: none
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID
KerbFreeContextList(
VOID
)
{
PLIST_ENTRY ListEntry;
PKERB_KERNEL_CONTEXT Context;
PAGED_CODE();
if (KerberosContextsInitialized)
{
KerbLockList(&KerbContextList);
//
// Go through the list of logon sessions and dereferences them all
//
while (!IsListEmpty(&KerbContextList.List))
{
Context = CONTAINING_RECORD(
KerbContextList.List.Flink,
KERB_KERNEL_CONTEXT,
ListEntry.Next
);
KerbReferenceListEntry(
&KerbContextList,
(PKERBEROS_LIST_ENTRY) Context,
TRUE
);
KerbDereferenceContext(Context);
}
KerbUnlockList(&KerbContextList);
KerbFreeList(&KerbContextList);
}
}
#endif
//+-------------------------------------------------------------------------
//
// Function: KerbAllocateContext
//
// Synopsis: Allocates a Context structure
//
// Effects: Allocates a Context, but does not add it to the
// list of Contexts
//
// Arguments: NewContext - receives a new Context allocated
// with KerbAllocate
//
// Requires:
//
// Returns: STATUS_SUCCESS on success
// STATUS_INSUFFICIENT_RESOURCES if the allocation fails
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
KerbAllocateContext(
PKERB_KERNEL_CONTEXT * NewContext
)
{
PKERB_KERNEL_CONTEXT Context;
NTSTATUS Status;
MAYBE_PAGED_CODE();
//
// Get the client process ID if we are running in the LSA
//
Context = (PKERB_KERNEL_CONTEXT) KerbAllocate(
sizeof(KERB_KERNEL_CONTEXT) );
if (Context == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
RtlZeroMemory(
Context,
sizeof(KERB_KERNEL_CONTEXT)
);
KsecInitializeListEntry( &Context->List, KERB_CONTEXT_SIGNATURE );
*NewContext = Context;
return(STATUS_SUCCESS);
}
//+-------------------------------------------------------------------------
//
// Function: KerbInsertContext
//
// Synopsis: Inserts a logon session into the list of logon sessions
//
// Effects: bumps reference count on logon session
//
// Arguments: Context - Context to insert
//
// Requires:
//
// Returns: STATUS_SUCCESS always
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
KerbInsertContext(
IN PKERB_KERNEL_CONTEXT Context
)
{
MAYBE_PAGED_CODE();
KSecInsertListEntry(
KerbActiveList,
(PKSEC_LIST_ENTRY) Context
);
return(STATUS_SUCCESS);
}
#if 0
//+-------------------------------------------------------------------------
//
// Function: KerbReferenceContextByLsaHandle
//
// Synopsis: Locates a context by lsa handle and references it
//
// Effects: Increments reference count and possible unlinks it from list
//
// Arguments: ContextHandle - Handle of context to reference.
// RemoveFromList - If TRUE, context will be delinked.
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
PKERB_KERNEL_CONTEXT
KerbReferenceContextByLsaHandle(
IN LSA_SEC_HANDLE ContextHandle,
IN BOOLEAN RemoveFromList
)
{
PLIST_ENTRY ListEntry;
PKERB_KERNEL_CONTEXT Context = NULL;
BOOLEAN Found = FALSE;
SECPKG_CLIENT_INFO ClientInfo;
NTSTATUS Status;
PAGED_CODE();
KerbLockList(&KerbContextList);
//
// Go through the list of logon sessions looking for the correct
// LUID
//
for (ListEntry = KerbContextList.List.Flink ;
ListEntry != &KerbContextList.List ;
ListEntry = ListEntry->Flink )
{
Context = CONTAINING_RECORD(ListEntry, KERB_KERNEL_CONTEXT, ListEntry.Next);
if (ContextHandle == Context->LsaContextHandle)
{
KerbReferenceListEntry(
&KerbContextList,
(PKERBEROS_LIST_ENTRY) Context,
RemoveFromList
);
Found = TRUE;
break;
}
}
if (!Found)
{
Context = NULL;
}
KerbUnlockList(&KerbContextList);
return(Context);
}
#endif
//+-------------------------------------------------------------------------
//
// Function: KerbReferenceContext
//
// Synopsis: Locates a context and references it
//
// Effects: Increments reference count and possible unlinks it from list
//
// Arguments: ContextHandle - Lsa Handle of context to reference.
// RemoveFromList - If TRUE, context will be delinked.
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
PKERB_KERNEL_CONTEXT
KerbReferenceContext(
IN LSA_SEC_HANDLE ContextHandle,
IN BOOLEAN RemoveFromList
)
{
PKERB_KERNEL_CONTEXT Context = NULL;
NTSTATUS Status;
MAYBE_PAGED_CODE();
Status = KSecReferenceListEntry(
(PKSEC_LIST_ENTRY) ContextHandle,
KERB_CONTEXT_SIGNATURE,
RemoveFromList );
if ( NT_SUCCESS( Status ) )
{
Context = (PKERB_KERNEL_CONTEXT) ContextHandle ;
}
//
// In kernel mode we trust the caller to provide a valid pointer, but
// make sure it is a kernel mode pointer.
//
return(Context);
}
#if 0
//+-------------------------------------------------------------------------
//
// Function: KerbReferenceContextByPointer
//
// Synopsis: References a context by the context pointer itself.
//
// Effects: Increments reference count and possible unlinks it from list
//
// Arguments: Context - The context to reference.
// RemoveFromList - If TRUE, context will be delinked
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID
KerbReferenceContextByPointer(
IN PKERB_KERNEL_CONTEXT Context,
IN BOOLEAN RemoveFromList
)
{
PAGED_CODE();
KerbLockList(&KerbContextList);
KerbReferenceListEntry(
&KerbContextList,
(PKERBEROS_LIST_ENTRY) Context,
RemoveFromList
);
if (RemoveFromList)
{
Context->ContextSignature = KERB_CONTEXT_DELETED_SIGNATURE;
}
KerbUnlockList(&KerbContextList);
}
#endif
//+-------------------------------------------------------------------------
//
// Function: KerbFreeContext
//
// Synopsis: Frees a context that is unlinked
//
// Effects: frees all storage associated with the context
//
// Arguments: Context - context to free
//
// Requires:
//
// Returns: none
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID
KerbFreeContext(
IN PKERB_KERNEL_CONTEXT Context
)
{
PAGED_CODE();
if (Context->TokenHandle != NULL)
{
NtClose(Context->TokenHandle);
}
if (Context->AccessToken != NULL)
{
ObDereferenceObject( Context->AccessToken );
}
if (Context->FullName.Buffer != NULL)
{
KerbFree(Context->FullName.Buffer);
}
if (Context->SessionKey.keyvalue.value != NULL)
{
KerbFree(Context->SessionKey.keyvalue.value);
}
if (Context->pbMarshalledTargetInfo != NULL)
{
KerbFree(Context->pbMarshalledTargetInfo);
}
KerbFree(Context);
}
//+-------------------------------------------------------------------------
//
// Function: KerbDereferenceContext
//
// Synopsis: Dereferences a logon session - if reference count goes
// to zero it frees the logon session
//
// Effects: decrements reference count
//
// Arguments: Context - Logon session to dereference
//
// Requires:
//
// Returns: none
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID
KerbDereferenceContext(
IN PKERB_KERNEL_CONTEXT Context
)
{
BOOLEAN Delete ;
MAYBE_PAGED_CODE();
KSecDereferenceListEntry(
(PKSEC_LIST_ENTRY) Context,
&Delete );
if ( Delete )
{
KerbFreeContext( Context );
}
}
//+-------------------------------------------------------------------------
//
// Function: KerbCreateKernelModeContext
//
// Synopsis: Creates a kernel-mode context to support impersonation and
// message integrity and privacy
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS
KerbCreateKernelModeContext(
IN LSA_SEC_HANDLE ContextHandle,
IN PSecBuffer MarshalledContext,
OUT PKERB_KERNEL_CONTEXT * NewContext
)
{
NTSTATUS Status;
PKERB_KERNEL_CONTEXT Context = NULL;
PKERB_PACKED_CONTEXT PackedContext ;
PUCHAR Where;
PAGED_CODE();
if (MarshalledContext->cbBuffer < sizeof(KERB_PACKED_CONTEXT))
{
DebugLog((DEB_ERROR,"Invalid buffer size for marshalled context: was 0x%x, needed 0x%x\n",
MarshalledContext->cbBuffer, sizeof(KERB_CONTEXT)));
return(STATUS_INVALID_PARAMETER);
}
PackedContext = (PKERB_PACKED_CONTEXT) MarshalledContext->pvBuffer;
Status = KerbAllocateContext( &Context );
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
KsecInitializeListEntry( &Context->List, KERB_CONTEXT_SIGNATURE );
Context->Lifetime = PackedContext->Lifetime;
Context->RenewTime = PackedContext->RenewTime;
Context->Nonce = PackedContext->Nonce;
Context->ReceiveNonce = PackedContext->ReceiveNonce;
Context->ContextFlags = PackedContext->ContextFlags;
Context->ContextAttributes = PackedContext->ContextAttributes;
Context->EncryptionType = PackedContext->EncryptionType;
Context->LsaContextHandle = ContextHandle;
Context->ReceiveNonce = Context->Nonce;
Context->TokenHandle = (HANDLE) ULongToPtr(PackedContext->TokenHandle);
//
// Fill in the full name, which is the concatenation of the client name
// and client realm with a '\\' separator
//
Context->FullName.MaximumLength = PackedContext->ClientName.Length +
PackedContext->ClientRealm.Length +
sizeof(WCHAR);
Context->FullName.Buffer = (LPWSTR) KerbAllocate(Context->FullName.MaximumLength);
if (Context->FullName.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Where = (PUCHAR) Context->FullName.Buffer;
if (PackedContext->ClientRealm.Length != 0)
{
RtlCopyMemory(
Where,
(PUCHAR) PackedContext + (ULONG_PTR) PackedContext->ClientRealm.Buffer,
PackedContext->ClientRealm.Length
);
Where += PackedContext->ClientRealm.Length;
*(LPWSTR) Where = L'\\';
Where += sizeof(WCHAR);
}
if (PackedContext->ClientName.Length != 0)
{
RtlCopyMemory(
Where,
(PUCHAR) PackedContext + (ULONG_PTR) PackedContext->ClientName.Buffer,
PackedContext->ClientName.Length
);
Where += PackedContext->ClientName.Length;
}
Context->FullName.Length = (USHORT) (Where - (PUCHAR) Context->FullName.Buffer);
//
// Copy in the session key
//
Context->SessionKey.keytype = PackedContext->SessionKeyType;
Context->SessionKey.keyvalue.length = PackedContext->SessionKeyLength;
if (Context->SessionKey.keyvalue.length != 0)
{
Context->SessionKey.keyvalue.value = (PUCHAR) KerbAllocate( Context->SessionKey.keyvalue.length );
if (Context->SessionKey.keyvalue.value == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
Context->SessionKey.keyvalue.value,
(PUCHAR) PackedContext + PackedContext->SessionKeyOffset,
Context->SessionKey.keyvalue.length
);
}
//
// copy in the marshalled target info.
//
Context->cbMarshalledTargetInfo = PackedContext->MarshalledTargetInfoLength;
if (PackedContext->MarshalledTargetInfo)
{
Context->pbMarshalledTargetInfo = (PUCHAR) KerbAllocate( Context->cbMarshalledTargetInfo );
if (Context->pbMarshalledTargetInfo == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
Context->pbMarshalledTargetInfo,
(PUCHAR) PackedContext + PackedContext->MarshalledTargetInfo,
Context->cbMarshalledTargetInfo
);
} else {
Context->pbMarshalledTargetInfo = NULL;
}
Status = KerbInsertContext(
Context
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to insert context: 0x%x\n",Status));
goto Cleanup;
}
*NewContext = Context;
Cleanup:
if (!NT_SUCCESS(Status))
{
if (Context != NULL)
{
KerbFreeContext(Context);
}
}
return(Status);
}
#if 0
NTSTATUS
KerbCreateKernelModeContext(
IN LSA_SEC_HANDLE ContextHandle,
IN PSecBuffer MarshalledContext,
OUT PKERB_KERNEL_CONTEXT * NewContext
)
{
NTSTATUS Status;
PKERB_KERNEL_CONTEXT Context = NULL;
PKERB_CONTEXT LsaContext;
PUCHAR Where;
PAGED_CODE();
if (MarshalledContext->cbBuffer < sizeof(KERB_CONTEXT))
{
DebugLog((DEB_ERROR,"Invalid buffer size for marshalled context: was 0x%x, needed 0x%x\n",
MarshalledContext->cbBuffer, sizeof(KERB_CONTEXT)));
return(STATUS_INVALID_PARAMETER);
}
LsaContext = (PKERB_CONTEXT) MarshalledContext->pvBuffer;
Status = KerbAllocateContext( &Context );
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
KsecInitializeListEntry( &Context->List, KERB_CONTEXT_SIGNATURE );
Context->Lifetime = LsaContext->Lifetime;
Context->RenewTime = LsaContext->RenewTime;
Context->Nonce = LsaContext->Nonce;
Context->ReceiveNonce = LsaContext->ReceiveNonce;
Context->ContextFlags = LsaContext->ContextFlags;
Context->ContextAttributes = LsaContext->ContextAttributes;
Context->EncryptionType = LsaContext->EncryptionType;
Context->LsaContextHandle = ContextHandle;
Context->ReceiveNonce = Context->Nonce;
Context->TokenHandle = LsaContext->TokenHandle;
//
// Fill in the full name, which is the concatenation of the client name
// and client realm with a '\\' separator
//
Context->FullName.MaximumLength = LsaContext->ClientName.Length +
LsaContext->ClientRealm.Length +
sizeof(WCHAR);
Context->FullName.Buffer = (LPWSTR) KerbAllocate(Context->FullName.MaximumLength);
if (Context->FullName.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
Where = (PUCHAR) Context->FullName.Buffer;
if (LsaContext->ClientRealm.Length != 0)
{
RtlCopyMemory(
Where,
(PUCHAR) LsaContext + (ULONG_PTR) LsaContext->ClientRealm.Buffer,
LsaContext->ClientRealm.Length
);
Where += LsaContext->ClientRealm.Length;
*(LPWSTR) Where = L'\\';
Where += sizeof(WCHAR);
}
if (LsaContext->ClientName.Length != 0)
{
RtlCopyMemory(
Where,
(PUCHAR) LsaContext + (ULONG_PTR) LsaContext->ClientName.Buffer,
LsaContext->ClientName.Length
);
Where += LsaContext->ClientName.Length;
}
Context->FullName.Length = (USHORT) (Where - (PUCHAR) Context->FullName.Buffer);
//
// Copy in the session key
//
LsaContext->SessionKey.keyvalue.value = (PUCHAR) LsaContext->SessionKey.keyvalue.value + (ULONG_PTR) LsaContext;
Context->SessionKey.keytype = LsaContext->SessionKey.keytype;
Context->SessionKey.keyvalue.length = LsaContext->SessionKey.keyvalue.length;
if (Context->SessionKey.keyvalue.length != 0)
{
Context->SessionKey.keyvalue.value = (PUCHAR) KerbAllocate(LsaContext->SessionKey.keyvalue.length);
if (Context->SessionKey.keyvalue.value == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(
Context->SessionKey.keyvalue.value,
LsaContext->SessionKey.keyvalue.value,
LsaContext->SessionKey.keyvalue.length
);
}
Status = KerbInsertContext(
Context
);
if (!NT_SUCCESS(Status))
{
DebugLog((DEB_ERROR,"Failed to insert context: 0x%x\n",Status));
goto Cleanup;
}
*NewContext = Context;
Cleanup:
if (!NT_SUCCESS(Status))
{
if (Context != NULL)
{
KerbFreeContext(Context);
}
}
return(Status);
}
#endif