//+----------------------------------------------------------------------- // // Microsoft Windows // // Copyright (c) Microsoft Corporation 1992 - 1996 // // File: bndcache.cxx // // Contents: Binding cache for Kerberos Package // // // History: 13-August-1996 Created MikeSw // //------------------------------------------------------------------------ #include #define BNDCACHE_ALLOCATE #include //+------------------------------------------------------------------------- // // Function: LsapInitializeList // // Synopsis: Initializes a lsap list by initializing the lock // and the list entry. // // Effects: // // Arguments: List - List to initialize // // Requires: // // Returns: STATUS_SUCCESS on success or errors from // RtlInitializeResources // // Notes: // // //-------------------------------------------------------------------------- NTSTATUS LsapInitializeList( IN PLSAP_LIST List ) { NTSTATUS Status = STATUS_SUCCESS; InitializeListHead(&List->List); Status = RtlInitializeCriticalSection( &List->Lock ); return(Status); } //+------------------------------------------------------------------------- // // Function: LsapFreeList // // Synopsis: Frees a lsap list by deleting the associated // critical section. // // Effects: List - the list to free. // // Arguments: // // Requires: // // Returns: none // // Notes: The list must be empty before freeing it. // // //-------------------------------------------------------------------------- VOID LsapFreeList( IN PLSAP_LIST List ) { // // Make sure the list is empty first // DsysAssert(List->List.Flink == List->List.Blink); RtlDeleteCriticalSection(&List->Lock); } //+------------------------------------------------------------------------- // // Function: LsapInitializeListEntry // // Synopsis: Initializes a newly created list entry for later // insertion onto the list. // // Effects: The reference count is set to one and the links are set // to NULL. // // Arguments: ListEntry - the list entry to initialize // // Requires: // // Returns: none // // Notes: // // //-------------------------------------------------------------------------- VOID LsapInitializeListEntry( IN OUT PLSAP_LIST_ENTRY ListEntry ) { ListEntry->ReferenceCount = 1; ListEntry->Next.Flink = ListEntry->Next.Blink = NULL; } //+------------------------------------------------------------------------- // // Function: LsapInsertListEntry // // Synopsis: Inserts an entry into a lsap list // // Effects: increments the reference count on the entry - if the // list entry was formly referenced it remains referenced. // // Arguments: ListEntry - the entry to insert // List - the list in which to insert the ListEntry // // Requires: // // Returns: nothing // // Notes: // // //-------------------------------------------------------------------------- VOID LsapInsertListEntry( IN PLSAP_LIST_ENTRY ListEntry, IN PLSAP_LIST List ) { ListEntry->ReferenceCount++; RtlEnterCriticalSection(&List->Lock); InsertHeadList( &List->List, &ListEntry->Next ); RtlLeaveCriticalSection(&List->Lock); } //+------------------------------------------------------------------------- // // Function: LsapReferenceListEntry // // Synopsis: References a list entry. If the flag RemoveFromList // has been specified, the entry is unlinked from the // list. // // Effects: bumps the reference count on the entry (unless it is // being removed from the list) // // Arguments: // // Requires: The list must be locked when calling this routine // // Returns: // // Notes: // // //-------------------------------------------------------------------------- VOID LsapReferenceListEntry( IN PLSAP_LIST List, IN PLSAP_LIST_ENTRY ListEntry, IN BOOLEAN RemoveFromList ) { // // If it has already been removed from the list // don't do it again. // if (RemoveFromList && ((ListEntry->Next.Flink != NULL) && (ListEntry->Next.Blink != NULL))) { RemoveEntryList(&ListEntry->Next); ListEntry->Next.Flink = NULL; ListEntry->Next.Blink = NULL; } else { ListEntry->ReferenceCount++; } } //+------------------------------------------------------------------------- // // Function: LsapDereferenceListEntry // // Synopsis: Dereferences a list entry and returns a flag indicating // whether the entry should be freed. // // Effects: decrements reference count on list entry // // Arguments: ListEntry - the list entry to dereference // List - the list containing the list entry // // Requires: // // Returns: TRUE - the list entry should be freed // FALSE - the list entry is still referenced // // Notes: // // //-------------------------------------------------------------------------- BOOLEAN LsapDereferenceListEntry( IN PLSAP_LIST_ENTRY ListEntry, IN PLSAP_LIST List ) { BOOLEAN DeleteEntry = FALSE; RtlEnterCriticalSection(&List->Lock); ListEntry->ReferenceCount -= 1; if (ListEntry->ReferenceCount == 0) { DeleteEntry = TRUE; } RtlLeaveCriticalSection(&List->Lock); return(DeleteEntry); } //+------------------------------------------------------------------------- // // Function: LsapInitBindingCache // // Synopsis: Initializes the binding cache // // Effects: allocates a resources // // Arguments: none // // Requires: // // Returns: STATUS_SUCCESS on success, other error codes // on failure // // Notes: // // //-------------------------------------------------------------------------- NTSTATUS LsapInitBindingCache( VOID ) { NTSTATUS Status; Status = LsapInitializeList( &LsapBindingCache ); if (!NT_SUCCESS(Status)) { goto Cleanup; } LsapBindingCacheInitialized = TRUE; Cleanup: if (!NT_SUCCESS(Status)) { LsapFreeList( &LsapBindingCache ); } return(Status); } //+------------------------------------------------------------------------- // // Function: LsapCleanupBindingCache // // Synopsis: Frees the binding cache // // Effects: // // Arguments: none // // Requires: // // Returns: none // // Notes: // // //-------------------------------------------------------------------------- VOID LsapCleanupBindingCache( VOID ) { PLSAP_BINDING_CACHE_ENTRY CacheEntry; if (LsapBindingCacheInitialized) { LsapLockList(&LsapBindingCache); // // Go through the list of bindings and dereference them all // while (!IsListEmpty(&LsapBindingCache.List)) { CacheEntry = CONTAINING_RECORD( LsapBindingCache.List.Flink, LSAP_BINDING_CACHE_ENTRY, ListEntry.Next ); LsapReferenceListEntry( &LsapBindingCache, &CacheEntry->ListEntry, TRUE ); LsapDereferenceBindingCacheEntry(CacheEntry); } LsapFreeList(&LsapBindingCache); } } //+------------------------------------------------------------------------- // // Function: LsapDereferenceBindingCacheEntry // // Synopsis: Dereferences a binding cache entry // // Effects: Dereferences the binding cache entry to make it go away // when it is no longer being used. // // Arguments: decrements reference count and delets cache entry if it goes // to zero // // Requires: BindingCacheEntry - The binding cache entry to dereference. // // Returns: none // // Notes: // // //-------------------------------------------------------------------------- VOID LsapDereferenceBindingCacheEntry( IN PLSAP_BINDING_CACHE_ENTRY BindingCacheEntry ) { if (LsapDereferenceListEntry( &BindingCacheEntry->ListEntry, &LsapBindingCache ) ) { LsapFreeBindingCacheEntry(BindingCacheEntry); } } //+------------------------------------------------------------------------- // // Function: LsapReferenceBindingCacheEntry // // Synopsis: References a binding cache entry // // Effects: Increments the reference count on the binding cache entry // // Arguments: BindingCacheEntry - binding cache entry to reference // // Requires: The binding cache must be locked // // Returns: none // // Notes: // // //-------------------------------------------------------------------------- VOID LsapReferenceBindingCacheEntry( IN PLSAP_BINDING_CACHE_ENTRY BindingCacheEntry, IN BOOLEAN RemoveFromList ) { LsapLockList(&LsapBindingCache); LsapReferenceListEntry( &LsapBindingCache, &BindingCacheEntry->ListEntry, RemoveFromList ); LsapUnlockList(&LsapBindingCache); } //+------------------------------------------------------------------------- // // Function: LsapLocateBindingCacheEntry // // Synopsis: References a binding cache entry by name // // Effects: Increments the reference count on the binding cache entry // // Arguments: RealmName - Contains the name of the realm for which to // obtain a binding handle. // RemoveFromList - Remove cache entry from cache when found. // // Requires: // // Returns: The referenced cache entry or NULL if it was not found. // // Notes: If an invalid entry is found it may be dereferenced // // //-------------------------------------------------------------------------- PLSAP_BINDING_CACHE_ENTRY LsapLocateBindingCacheEntry( IN PUNICODE_STRING RealmName, IN BOOLEAN RemoveFromList ) { PLIST_ENTRY ListEntry; PLSAP_BINDING_CACHE_ENTRY CacheEntry = NULL; BOOLEAN Found = FALSE; LsapLockList(&LsapBindingCache); // // Go through the binding cache looking for the correct entry // for (ListEntry = LsapBindingCache.List.Flink ; ListEntry != &LsapBindingCache.List ; ListEntry = ListEntry->Flink ) { CacheEntry = CONTAINING_RECORD(ListEntry, LSAP_BINDING_CACHE_ENTRY, ListEntry.Next); if (RtlEqualUnicodeString( &CacheEntry->RealmName, RealmName, TRUE )) { LsapReferenceBindingCacheEntry( CacheEntry, RemoveFromList ); Found = TRUE; NtQuerySystemTime( &CacheEntry->LastUsed ); break; } } if (!Found) { CacheEntry = NULL; } LsapUnlockList(&LsapBindingCache); return(CacheEntry); } //+------------------------------------------------------------------------- // // Function: LsapFreeBindingCacheEntry // // Synopsis: Frees memory associated with a binding cache entry // // Effects: // // Arguments: BindingCacheEntry - The cache entry to free. It must be // unlinked. // // Requires: // // Returns: none // // Notes: // // //-------------------------------------------------------------------------- VOID LsapFreeBindingCacheEntry( IN PLSAP_BINDING_CACHE_ENTRY BindingCacheEntry ) { if ( !BindingCacheEntry ) { return; } LsapFreeString(&BindingCacheEntry->RealmName); if (BindingCacheEntry->PolicyHandle != NULL) { LsaClose(BindingCacheEntry->PolicyHandle); } if (BindingCacheEntry->ServerName != NULL) { // // Note -- because I_NetLogonAuthData is not supported for NT4 and // below, ServerName won't always be allocated from NetLogon's MM. // So, the ServerName allocation is normalized to LocalAlloc/LocalFree // LocalFree(BindingCacheEntry->ServerName); } if (BindingCacheEntry->ServerPrincipalName != NULL) { I_NetLogonFree(BindingCacheEntry->ServerPrincipalName); } if (BindingCacheEntry->ClientContext != NULL) { I_NetLogonFree(BindingCacheEntry->ClientContext); } LsapFreeLsaHeap(BindingCacheEntry); } //+------------------------------------------------------------------------- // // Function: LsapInsertBinding // // Synopsis: Inserts a binding into the binding cache // // Effects: bumps reference count on binding // // Arguments: CacheEntry - Cache entry to insert // // Requires: // // Returns: STATUS_SUCCESS always // // Notes: // // //-------------------------------------------------------------------------- NTSTATUS LsapInsertBinding( IN PLSAP_BINDING_CACHE_ENTRY CacheEntry ) { LsapInsertListEntry( &CacheEntry->ListEntry, &LsapBindingCache ); return(STATUS_SUCCESS); } //+------------------------------------------------------------------------- // // Function: LsapCacheBinding // // Synopsis: Caches a binding in the binding cache // // Effects: creates a cache entry. // // Arguments: RealmName - The realm name of the LSA the binding is to. // Handle - LSA policy handle to the target machine. // ServerName,ServerPrincipalName, ClientContext - authenticated // rpc parameters needed to be cached for the duration // of the binding. // CacheEntry - Receives the new binding cache entry, // referenced. // // Requires: // // Returns: // // Notes: Locks the binding cache for write access while adding // the cache entry. // // //-------------------------------------------------------------------------- NTSTATUS LsapCacheBinding( IN PUNICODE_STRING RealmName, IN PLSA_HANDLE Handle, IN OUT LPWSTR * ServerName, IN OUT LPWSTR * ServerPrincipalName, IN OUT PVOID * ClientContext, OUT PLSAP_BINDING_CACHE_ENTRY * NewCacheEntry ) { PLSAP_BINDING_CACHE_ENTRY CacheEntry = NULL; PLSAP_BINDING_CACHE_ENTRY OldCacheEntry = NULL; NTSTATUS Status = STATUS_SUCCESS; *NewCacheEntry = NULL; CacheEntry = (PLSAP_BINDING_CACHE_ENTRY) LsapAllocateLsaHeap(sizeof(LSAP_BINDING_CACHE_ENTRY)); if (CacheEntry == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } RtlZeroMemory( CacheEntry, sizeof(LSAP_BINDING_CACHE_ENTRY) ); LsapInitializeListEntry( &CacheEntry->ListEntry ); NtQuerySystemTime( &CacheEntry->LastUsed ); Status = LsapDuplicateString( &CacheEntry->RealmName, RealmName ); if (!NT_SUCCESS(Status)) { goto Cleanup; } CacheEntry->PolicyHandle = *Handle; *Handle = NULL; CacheEntry->ServerName = *ServerName; *ServerName = NULL; CacheEntry->ServerPrincipalName = *ServerPrincipalName; *ServerPrincipalName = NULL; CacheEntry->ClientContext = *ClientContext; *ClientContext = NULL; // // Before we insert this binding we want to remove any // previous instances of bindings to the same realm. // OldCacheEntry = LsapLocateBindingCacheEntry( RealmName, TRUE // remove from cache ); if (OldCacheEntry != NULL) { LsapDereferenceBindingCacheEntry( OldCacheEntry ); } // // Insert the cache entry into the cache // Status = LsapInsertBinding( CacheEntry ); if (!NT_SUCCESS(Status)) { goto Cleanup; } *NewCacheEntry = CacheEntry; Cleanup: if (!NT_SUCCESS(Status)) { if ( CacheEntry ) { LsapFreeBindingCacheEntry(CacheEntry); } } return(Status); } //+------------------------------------------------------------------------- // // Function: LsapRemoveBindingCacheEntry // // Synopsis: removes an entry from the binding cache // // Effects: // // Arguments: CacheEntry - entry to remove // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- VOID LsapRemoveBindingCacheEntry( IN PLSAP_BINDING_CACHE_ENTRY CacheEntry ) { LsapLockList(&LsapBindingCache); LsapReferenceBindingCacheEntry( CacheEntry, TRUE ); LsapDereferenceBindingCacheEntry( CacheEntry ); LsapUnlockList(&LsapBindingCache); }