/*++ Copyright (c) 1995 Microsoft Corporation Module Name: domain.c Abstract: Code to manage primary and emulated networks. Author: Cliff Van Dyke (CliffV) 23-Jan-1995 Revision History: --*/ #include "precomp.h" #pragma hdrstop // // Module specific globals // // Serialized by BowserTransportDatabaseResource LIST_ENTRY BowserServicedDomains = {0}; // // Local procedure forwards. // #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, BowserInitializeDomains) #pragma alloc_text(PAGE, BowserCreateDomain) #pragma alloc_text(PAGE, BowserSetDomainName) #pragma alloc_text(PAGE, BowserFindDomain) #pragma alloc_text(PAGE, BowserDereferenceDomain) #endif VOID BowserInitializeDomains( VOID ) /*++ Routine Description: Initialize domain.c. Arguments: None Return Value: None. --*/ { PAGED_CODE(); // // Initialize globals // InitializeListHead(&BowserServicedDomains); } PDOMAIN_INFO BowserCreateDomain( PUNICODE_STRING DomainName, PUNICODE_STRING ComputerName ) /*++ Routine Description: Find the existing domain definition or create a new domain to browse on. Arguments: DomainName - Name of the domain to browse on ComputerName - emulated computer name for this domain. Return Value: NULL - No such domain exists A pointer to the domain found/created. The found/created domain should be dereferenced using BowserDereferenceDomain. --*/ { NTSTATUS Status; PDOMAIN_INFO DomainInfo = NULL; ULONG OemComputerNameLength; PAGED_CODE(); dlog(DPRT_DOMAIN, ("%wZ: BowserCreateDomain\n", DomainName)); try { ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE); // // If the domain already exists, use it. // DomainInfo = BowserFindDomain( DomainName ); if ( DomainInfo == NULL) { // // Allocate a structure describing the new domain. // DomainInfo = ALLOCATE_POOL(NonPagedPool, sizeof(DOMAIN_INFO), POOL_DOMAIN_INFO); if ( DomainInfo == NULL ) { try_return( Status = STATUS_NO_MEMORY ); } RtlZeroMemory( DomainInfo, sizeof(DOMAIN_INFO) ); // // Create an interim reference count for this domain. // // One for the caller. // // We don't increment the reference count for being in the global list since // the domain info structure is merely a performance enchancements that lives // only because it is referenced by a network. // DomainInfo->ReferenceCount = 1; // // Link the domain into the list of domains // // The primary domain is at the front of the list. // InsertTailList(&BowserServicedDomains, &DomainInfo->Next); } // // Copy the DomainName into the structure // Status = BowserSetDomainName( DomainInfo, DomainName ); if (!NT_SUCCESS(Status)) { try_return( Status ); } // // Copy the OEM Computer name into the structure. // if ( ComputerName->Length > CNLEN*sizeof(WCHAR) ) { try_return( Status = STATUS_INVALID_PARAMETER ); } Status = RtlUpcaseUnicodeToOemN( DomainInfo->DomOemComputerNameBuffer, sizeof(DomainInfo->DomOemComputerNameBuffer)-1, &OemComputerNameLength, ComputerName->Buffer, ComputerName->Length ); if (!NT_SUCCESS(Status)) { try_return( Status ); } DomainInfo->DomOemComputerNameBuffer[OemComputerNameLength] = '\0'; DomainInfo->DomOemComputerName.Buffer = DomainInfo->DomOemComputerNameBuffer; DomainInfo->DomOemComputerName.Length = (USHORT)OemComputerNameLength; DomainInfo->DomOemComputerName.MaximumLength = (USHORT)(OemComputerNameLength + 1); // // Copy the upcased Unicode Computer name into the structure. // DomainInfo->DomUnicodeComputerName.Buffer = DomainInfo->DomUnicodeComputerNameBuffer; DomainInfo->DomUnicodeComputerName.MaximumLength = sizeof(DomainInfo->DomUnicodeComputerNameBuffer); Status = RtlOemStringToUnicodeString(&DomainInfo->DomUnicodeComputerName, &DomainInfo->DomOemComputerName, FALSE); if (!NT_SUCCESS(Status)) { try_return( Status ); } Status = STATUS_SUCCESS; try_exit:NOTHING; } finally { if ( !NT_SUCCESS(Status) && DomainInfo != NULL ) { BowserDereferenceDomain( DomainInfo ); DomainInfo = NULL; } ExReleaseResourceLite(&BowserTransportDatabaseResource); } return DomainInfo; } NTSTATUS BowserSetDomainName( PDOMAIN_INFO DomainInfo, PUNICODE_STRING DomainName ) /*++ Routine Description: Find the existing domain definition or create a new domain to browse on. Arguments: DomainName - Name of the domain to browse on ComputerName - emulated computer name for this domain. Return Value: Status of the operation --*/ { NTSTATUS Status; STRING OemDomainName; PAGED_CODE(); try { ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE); // if the alignment of the name given is bad, return error if ( !POINTER_IS_ALIGNED( DomainName->Buffer, ALIGN_WCHAR ) ) { try_return( STATUS_DATATYPE_MISALIGNMENT_ERROR ); } // // Copy the DomainName into the structure // Status = RtlUpcaseUnicodeToOemN( DomainInfo->DomOemDomainName, sizeof(DomainInfo->DomOemDomainName), &DomainInfo->DomOemDomainNameLength, DomainName->Buffer, DomainName->Length ); if (!NT_SUCCESS(Status)) { try_return( Status ); } DomainInfo->DomOemDomainName[DomainInfo->DomOemDomainNameLength] = '\0'; // // Build the domain name as a Netbios name // Trailing blank filled and <00> 16th byte // RtlCopyMemory( DomainInfo->DomNetbiosDomainName, DomainInfo->DomOemDomainName, DomainInfo->DomOemDomainNameLength ); RtlFillMemory( DomainInfo->DomNetbiosDomainName+DomainInfo->DomOemDomainNameLength, NETBIOS_NAME_LEN-1-DomainInfo->DomOemDomainNameLength, ' '); DomainInfo->DomNetbiosDomainName[NETBIOS_NAME_LEN-1] = PRIMARY_DOMAIN_SIGNATURE; // // Copy the upcased Unicode domain name into the structure. // OemDomainName.Buffer = DomainInfo->DomOemDomainName; OemDomainName.Length = (USHORT)DomainInfo->DomOemDomainNameLength; OemDomainName.MaximumLength = OemDomainName.Length + sizeof(WCHAR); DomainInfo->DomUnicodeDomainName.Buffer = DomainInfo->DomUnicodeDomainNameBuffer; DomainInfo->DomUnicodeDomainName.MaximumLength = sizeof(DomainInfo->DomUnicodeDomainNameBuffer); Status = RtlOemStringToUnicodeString(&DomainInfo->DomUnicodeDomainName, &OemDomainName, FALSE); if (!NT_SUCCESS(Status)) { try_return( Status ); } Status = STATUS_SUCCESS; try_exit:NOTHING; } finally { ExReleaseResourceLite(&BowserTransportDatabaseResource); } return Status; } PDOMAIN_INFO BowserFindDomain( PUNICODE_STRING DomainName OPTIONAL ) /*++ Routine Description: This routine will look up a domain given a name. Arguments: DomainName - The name of the domain to look up. Return Value: NULL - No such domain exists A pointer to the domain found. The found domain should be dereferenced using BowserDereferenceDomain. --*/ { NTSTATUS Status; PLIST_ENTRY DomainEntry; PDOMAIN_INFO DomainInfo = NULL; CHAR OemDomainName[DNLEN+1]; DWORD OemDomainNameLength; PAGED_CODE(); ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE); try { // If no domain was specified // try to return primary domain. // if ( DomainName == NULL || DomainName->Length == 0 ) { if ( !IsListEmpty( &BowserServicedDomains ) ) { DomainInfo = CONTAINING_RECORD(BowserServicedDomains.Flink, DOMAIN_INFO, Next); } // if the alignment of the name given is bad, return null } else if ( !POINTER_IS_ALIGNED( DomainName->Buffer, ALIGN_WCHAR ) ) { DomainInfo = NULL; // // If the domain name was specified, // Find it in the list of domains. // } else { // // Convert the domain name to OEM for faster comparison // Status = RtlUpcaseUnicodeToOemN( OemDomainName, DNLEN, &OemDomainNameLength, DomainName->Buffer, DomainName->Length ); if ( NT_SUCCESS(Status)) { // // The PrimaryDomainInfo structure is allocated with no // domain name during bowser driver initialization. // Detect that case here and always return that domain // entry for all lookups. // if ( !IsListEmpty( &BowserServicedDomains ) ) { DomainInfo = CONTAINING_RECORD(BowserServicedDomains.Flink, DOMAIN_INFO, Next); if ( DomainInfo->DomOemDomainNameLength == 0 ) { try_return( DomainInfo ); } } // // Loop trying to find this domain name. // for (DomainEntry = BowserServicedDomains.Flink ; DomainEntry != &BowserServicedDomains; DomainEntry = DomainEntry->Flink ) { DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next); if ( DomainInfo->DomOemDomainNameLength == OemDomainNameLength && RtlCompareMemory( DomainInfo->DomOemDomainName, OemDomainName, OemDomainNameLength ) == OemDomainNameLength ) { try_return( DomainInfo ); } } DomainInfo = NULL; } } try_exit:NOTHING; } finally { // // Reference the domain. // if ( DomainInfo != NULL ) { DomainInfo->ReferenceCount ++; dprintf(DPRT_REF, ("Reference domain %lx. Count now %lx\n", DomainInfo, DomainInfo->ReferenceCount)); } ExReleaseResourceLite(&BowserTransportDatabaseResource); } return DomainInfo; } VOID BowserDereferenceDomain( IN PDOMAIN_INFO DomainInfo ) /*++ Routine Description: Decrement the reference count on a domain. If the reference count goes to 0, remove the domain. On entry, the global BowserTransportDatabaseResource may not be locked Arguments: DomainInfo - The domain to dereference Return Value: None --*/ { NTSTATUS Status; ULONG ReferenceCount; PAGED_CODE(); // // Decrement the reference count // ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE); ReferenceCount = -- DomainInfo->ReferenceCount; if ( ReferenceCount == 0 ) { RemoveEntryList( &DomainInfo->Next ); } ExReleaseResourceLite(&BowserTransportDatabaseResource); dprintf(DPRT_REF, ("Dereference domain %lx. Count now %lx\n", DomainInfo, DomainInfo->ReferenceCount)); if ( ReferenceCount != 0 ) { return; } // // Free the Domain Info structure. // dlog(DPRT_DOMAIN, ("%s: BowserDereferenceDomain: domain deleted.\n", DomainInfo->DomOemDomainName )); FREE_POOL(DomainInfo ); }