//+----------------------------------------------------------------------- // // 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 #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