windows-nt/Source/XPSP1/NT/base/fs/rdr2/bowser/domain.c
2020-09-26 16:20:57 +08:00

484 lines
12 KiB
C

/*++
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);
//
// 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 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 );
}