Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

870 lines
20 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
browsenet.c
Abstract:
Code to manage network requests.
Author:
Larry Osterman (LarryO) 24-Mar-1992
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
RTL_CRITICAL_SECTION
NetworkLock = {0};
LIST_ENTRY
ServicedNetworks = {0};
ULONG
NumberOfServicedNetworks = 0;
NET_API_STATUS
BrDestroyNetwork(
IN PNETWORK Network,
IN PVOID Context
);
NET_API_STATUS
BrDumpNetworksWorker(
IN PNETWORK Network,
IN PVOID Context
);
NET_API_STATUS
BrInitializeNetworks(
VOID
)
/*++
Routine Description:
This function will query the NT bowser device driver to determine the
list of networks that the bowser is servicing.
Arguments:
None.
Return Value:
Status of operation.
--*/
{
NET_API_STATUS Status;
PLMDR_TRANSPORT_LIST TransportList;
PLMDR_TRANSPORT_LIST TransportEntry;
InitializeListHead(&ServicedNetworks);
RtlInitializeCriticalSection(&NetworkLock);
Status = BrGetTransportList(&TransportList);
TransportEntry = TransportList;
while (TransportEntry != NULL) {
UNICODE_STRING TransportName;
TransportName.Buffer = TransportEntry->TransportName;
TransportName.Length = (USHORT)TransportEntry->TransportNameLength;
//
// We know the bowser sticks in a null at the end, so the max length
// is the length + 1.
//
TransportName.MaximumLength = (USHORT)TransportEntry->TransportNameLength+sizeof(WCHAR);
Status = BrCreateNetwork(&TransportName,
(BOOLEAN)((TransportEntry->Flags & LMDR_TRANSPORT_WANNISH) != 0),
(BOOLEAN)((TransportEntry->Flags & LMDR_TRANSPORT_RAS) != 0),
NULL);
if (!NT_SUCCESS(Status)) {
MIDL_user_free(TransportList);
return Status;
}
NumberOfServicedNetworks += 1;
if (TransportEntry->NextEntryOffset == 0) {
TransportEntry = NULL;
} else {
TransportEntry = (PLMDR_TRANSPORT_LIST)((PCHAR)TransportEntry+TransportEntry->NextEntryOffset);
}
}
MIDL_user_free(TransportList);
return Status;
}
NET_API_STATUS
BrCreateNetwork(
PUNICODE_STRING TransportName,
IN BOOLEAN Wannish,
IN BOOLEAN Ras,
IN PUNICODE_STRING AlternateTransportName OPTIONAL
)
/*++
Routine Description:
This routine allocates memory to hold a network structure, and initializes
all of its associated data structures.
Arguments:
TransportName - The name of the transport to add.
Return Value:
Status of operation (mostly status of allocations).
--*/
{
NET_API_STATUS Status;
PNETWORK Network;
BOOLEAN NetworkLockInitialized = FALSE;
BOOLEAN MasterFlagsInitialized = FALSE;
BOOLEAN BackupBrowserTimerCreated = FALSE;
BOOLEAN MasterBrowserTimerCreated =FALSE;
BOOLEAN AnnouncementTimerCreated = FALSE;
BOOLEAN ResponseCacheLockInitialized = FALSE;
//
// Check to see if the transport already exists.
//
if ((Network = BrFindNetwork(TransportName)) != NULL) {
return NERR_AlreadyExists;
}
//
// If this transport is explicitly on our list of transports to unbind,
// simply ignore the transport.
//
if (BrInfo.UnboundBindings != NULL) {
LPTSTR_ARRAY TStrArray = BrInfo.UnboundBindings;
while (!NetpIsTStrArrayEmpty(TStrArray)) {
LPWSTR NewTransportName;
#define NAME_PREFIX L"\\Device\\"
#define NAME_PREFIX_LENGTH 8
//
// The transport name in the registry is only optionally prefixed with \device\
//
if ( _wcsnicmp( NAME_PREFIX, TStrArray, NAME_PREFIX_LENGTH) == 0 ) {
NewTransportName = TransportName->Buffer;
} else {
NewTransportName = TransportName->Buffer + NAME_PREFIX_LENGTH;
}
if ( _wcsicmp( TStrArray, NewTransportName ) == 0 ) {
dprintf(INIT, ("Binding is marked as unbound: %s (Silently ignoring)\n", TransportName->Buffer ));
return NERR_Success;
}
TStrArray = NetpNextTStrArrayEntry(TStrArray);
}
}
//
// If this transport isn't bound to the SMB server,
// don't create the transport here.
// we do announcments through the SMB server.
//
Status = I_NetServerSetServiceBits(NULL, TransportName->Buffer, 0, TRUE);
if (Status == ERROR_PATH_NOT_FOUND ) {
dprintf(INIT, ("SMB Server doesn't have this transport: %s (Silently unbinding)\n", TransportName->Buffer ));
return NERR_Success;
}
//
// Create the transport.
//
try {
Network = MIDL_user_allocate(sizeof(NETWORK));
if (Network == NULL) {
try_return(Status = ERROR_NOT_ENOUGH_MEMORY);
}
RtlInitializeResource(&Network->Lock);
NetworkLockInitialized = TRUE;
Network->LockCount = 0;
Network->ReferenceCount = 1;
Network->Role = BrDefaultRole;
Network->NumberOfFailedBackupTimers = 0;
Network->NumberOfFailedPromotions = 0;
Network->NumberOfPromotionEventsLogged = 0;
Network->LastBackupBrowserReturned = 0;
Network->LastDomainControllerBrowserReturned = 0;
Network->TimeStoppedBackup = 0;
Network->BackupServerList = NULL;
Network->BackupDomainList = NULL;
Network->TotalBackupServerListEntries = 0;
Network->TotalBackupDomainListEntries = 0;
Network->NetworkName.Buffer = MIDL_user_allocate(TransportName->MaximumLength);
if (Network->NetworkName.Buffer == NULL) {
try_return(Status = ERROR_NOT_ENOUGH_MEMORY);
}
Network->NetworkName.MaximumLength = TransportName->MaximumLength;
RtlCopyUnicodeString(&Network->NetworkName, TransportName);
Network->Flags = 0;
if (ARGUMENT_PRESENT(AlternateTransportName)) {
PNETWORK AlternateNetwork = BrFindNetwork(AlternateTransportName);
//
// If we didn't find an alternate network, or if that network
// already has an alternate network, return an error.
//
if (AlternateNetwork == NULL ||
AlternateNetwork->AlternateNetwork != NULL) {
try_return(Status = NERR_InternalError);
}
Network->Flags |= NETWORK_IPX;
//
// Link the two networks together.
//
Network->AlternateNetwork = AlternateNetwork;
AlternateNetwork->AlternateNetwork = Network;
} else {
Network->AlternateNetwork = NULL;
}
//
// Null terminate the network name buffer.
//
Network->NetworkName.Buffer[Network->NetworkName.Length/sizeof(WCHAR)] = UNICODE_NULL;
RtlInitUnicodeString(&Network->MasterBrowserName, NULL);
if (Wannish) {
Network->Flags |= NETWORK_WANNISH;
}
if (Ras) {
Network->Flags |= NETWORK_RAS;
}
Network->LastBowserServerQueried = 0;
RtlInitializeCriticalSection(&Network->MasterFlagsLock);
MasterFlagsInitialized = TRUE;
Network->MasterFlags = 0;
InitializeInterimServerList(&Network->BrowseTable,
BrBrowseTableInsertRoutine,
BrBrowseTableUpdateRoutine,
BrBrowseTableDeleteRoutine,
BrBrowseTableAgeRoutine);
Network->LastBowserDomainQueried = 0;
InitializeInterimServerList(&Network->DomainList,
BrDomainTableInsertRoutine,
BrDomainTableUpdateRoutine,
BrDomainTableDeleteRoutine,
BrDomainTableAgeRoutine);
InitializeListHead(&Network->OtherDomainsList);
Status = BrCreateTimer(&Network->BackupBrowserTimer);
if (Status != NERR_Success) {
try_return(Status);
}
BackupBrowserTimerCreated = TRUE;
Status = BrCreateTimer(&Network->MasterBrowserTimer);
if (Status != NERR_Success) {
try_return(Status);
}
MasterBrowserTimerCreated = TRUE;
Status = BrCreateTimer(&Network->MasterBrowserAnnouncementTimer);
if (Status != NERR_Success) {
try_return(Status);
}
AnnouncementTimerCreated = TRUE;
InitializeCriticalSection(&Network->ResponseCacheLock);
ResponseCacheLockInitialized = TRUE;
InitializeListHead(&Network->ResponseCache);
Network->TimeCacheFlushed = 0;
Network->NumberOfCachedResponses = 0;
Status = RtlEnterCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
try_return(Status = BrMapStatus(Status));
}
InsertHeadList(&ServicedNetworks, &Network->NextNet);
Status = RtlLeaveCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to release browser critical section\n"));
}
try_exit:NOTHING;
} finally {
if (Status != NERR_Success) {
if (Network != NULL) {
if (ResponseCacheLockInitialized) {
DeleteCriticalSection(&Network->ResponseCacheLock);
}
if (MasterFlagsInitialized) {
RtlDeleteCriticalSection(&Network->MasterFlagsLock);
}
if (NetworkLockInitialized) {
RtlDeleteResource(&Network->Lock);
}
if (AnnouncementTimerCreated) {
BrDestroyTimer(&Network->MasterBrowserAnnouncementTimer);
}
if (MasterBrowserTimerCreated) {
BrDestroyTimer(&Network->MasterBrowserTimer);
}
if (BackupBrowserTimerCreated) {
BrDestroyTimer(&Network->BackupBrowserTimer);
}
if (Network->NetworkName.Buffer != NULL) {
MIDL_user_free(Network->NetworkName.Buffer);
}
MIDL_user_free(Network);
}
}
}
return Status;
}
VOID
BrDestroyNetworks(
IN DWORD BrInitState
)
{
NET_API_STATUS status;
RtlEnterCriticalSection(&NetworkLock);
while (!IsListEmpty(&ServicedNetworks)) {
PNETWORK Network = CONTAINING_RECORD(ServicedNetworks.Flink, NETWORK, NextNet);
//
// If this is an IPX transport, we need to manually unbind from the transport.
//
if (Network->Flags & NETWORK_IPX) {
status = BrUnbindFromTransport(Network->NetworkName.Buffer);
if (status != NERR_Success) {
KdPrint(("Unable to unbind from IPX transport %wS\n", &Network->NetworkName));
}
}
BrDestroyNetwork(Network, NULL);
}
RtlLeaveCriticalSection(&NetworkLock);
RtlDeleteCriticalSection(&NetworkLock);
NumberOfServicedNetworks = 0;
}
NET_API_STATUS
BrDestroyNetwork(
IN PNETWORK Network,
IN PVOID Context
)
/*++
Routine Description:
This routine removes a reference to a network. If the network reference
count goes to 0, remove the network.
Arguments:
Network - The network to remove
Return Value:
Status of operation (mostly status of allocations).
--*/
{
NTSTATUS Status;
Status = RtlEnterCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to acquire browser critical section\n"));
return BrMapStatus(Status);
}
RemoveEntryList(&Network->NextNet);
Status = RtlLeaveCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to release browser critical section\n"));
return BrMapStatus(Status);
}
if (Network->Role & ROLE_MASTER) {
//
// Stop being the master on this network. This means removing
// our name from the bowser driver and forcing an election.
//
BrStopMaster(Network);
}
if (Network->Role & (ROLE_POTENTIAL_BACKUP | ROLE_BACKUP)) {
//
// Stop being a backup on this network. This means downgrading our
// machine to idle.
//
BrStopBackup(Network);
}
//
// Ensure that there are no browser related names active in the browser.
//
BrUpdateBrowserStatus(Network, 0);
UninitializeInterimServerList(&Network->BrowseTable);
UninitializeInterimServerList(&Network->DomainList);
if (Network->BackupServerList != NULL) {
MIDL_user_free(Network->BackupServerList);
}
if (Network->BackupDomainList != NULL) {
MIDL_user_free(Network->BackupDomainList);
}
// RtlDeleteCriticalSection(&Network->Lock);
RtlDeleteResource(&Network->Lock);
RtlDeleteCriticalSection(&Network->MasterFlagsLock);
BrDestroyTimer(&Network->MasterBrowserAnnouncementTimer);
BrDestroyTimer(&Network->MasterBrowserTimer);
BrDestroyTimer(&Network->BackupBrowserTimer);
BrDestroyResponseCache(Network);
RtlDeleteCriticalSection(&Network->ResponseCacheLock);
MIDL_user_free(Network->NetworkName.Buffer);
if (Network->MasterBrowserName.Buffer != NULL) {
MIDL_user_free(Network->MasterBrowserName.Buffer);
}
MIDL_user_free(Network);
return NERR_Success;
UNREFERENCED_PARAMETER(Context);
}
PNETWORK
BrFindNetwork(
PUNICODE_STRING TransportName
)
/*++
Routine Description:
This routine will look up a network given a name.
Arguments:
TransportName - The name of the transport to look up.
Return Value:
Status of operation (mostly status of allocations).
--*/
{
NTSTATUS Status;
PLIST_ENTRY NetEntry;
Status = RtlEnterCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to acquire browser critical section\n"));
return NULL;
}
for (NetEntry = ServicedNetworks.Flink ;
NetEntry != &ServicedNetworks;
NetEntry = NetEntry->Flink ) {
PNETWORK Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
if (RtlEqualUnicodeString(&Network->NetworkName, TransportName, TRUE)) {
Status = RtlLeaveCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to release browser critical section\n"));
return NULL;
}
return Network;
}
}
Status = RtlLeaveCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to release browser critical section\n"));
return NULL;
}
return NULL;
}
NET_API_STATUS
BrEnumerateNetworks(
PNET_ENUM_CALLBACK Callback,
PVOID Context
)
/*++
Routine Description:
This routine enumerates all the networks and calls back the specified
callback routine with the specified context.
Arguments:
Callback - The callback routine to call.
Context - Context for the routine.
Return Value:
Status of operation (mostly status of allocations).
--*/
{
NTSTATUS Status;
PLIST_ENTRY NetEntry;
Status = RtlEnterCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to acquire browser critical section\n"));
return Status;
}
for (NetEntry = ServicedNetworks.Flink ;
NetEntry != &ServicedNetworks;
NetEntry = NetEntry->Flink ) {
PNETWORK Network = CONTAINING_RECORD(NetEntry, NETWORK, NextNet);
Status = RtlLeaveCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to release browser critical section\n"));
return BrMapStatus(Status);
}
//
// Call into the callback routine with this network.
//
Status = (Callback)(Network, Context);
if (Status != NERR_Success) {
return Status;
}
Status = RtlEnterCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to acquire browser critical section\n"));
return BrMapStatus(Status);
}
}
Status = RtlLeaveCriticalSection(&NetworkLock);
if (!NT_SUCCESS(Status)) {
InternalError(("Unable to release browser critical section\n"));
return Status;
}
return NERR_Success;
}
#if DBG
BOOL
BrLockNetwork(
IN PNETWORK Network,
IN PCHAR FileName,
IN ULONG LineNumber
)
{
PCHAR File;
File = strrchr(FileName, '\\');
if (File == NULL) {
File = FileName;
}
dprintf(LOCKS, ("Acquring lock %s:%d on network %ws\n", File, LineNumber, (Network)->NetworkName.Buffer));
if (!RtlAcquireResourceExclusive(&(Network)->Lock, TRUE)) {
dprintf(LOCKS, ("Failed to acquire lock %s:%d on network %ws\n", File, LineNumber, (Network)->NetworkName.Buffer));
return FALSE;
} else {
InterlockedIncrement( &Network->LockCount );
dprintf(LOCKS, ("Lock %s:%d on network %ws acquired\n", File, LineNumber, (Network)->NetworkName.Buffer));
}
return TRUE;
}
BOOL
BrLockNetworkShared(
IN PNETWORK Network,
IN PCHAR FileName,
IN ULONG LineNumber
)
{
PCHAR File;
File = strrchr(FileName, '\\');
if (File == NULL) {
File = FileName;
}
dprintf(LOCKS, ("Acquring lock %s:%d on network %ws\n", File, LineNumber, (Network)->NetworkName.Buffer));
if (!RtlAcquireResourceShared(&(Network)->Lock, TRUE)) {
dprintf(LOCKS, ("Failed to acquire lock %s:%d on network %ws\n", File, LineNumber, (Network)->NetworkName.Buffer));
return FALSE;
} else {
// Use InterlockedIncrement since we only have a shared lock on the
// resource.
InterlockedIncrement( &Network->LockCount );
dprintf(LOCKS, ("Lock %s:%d on network %ws acquired\n", File, LineNumber, (Network)->NetworkName.Buffer));
}
return TRUE;
}
VOID
BrUnlockNetwork(
IN PNETWORK Network,
IN PCHAR FileName,
IN ULONG LineNumber
)
{
PCHAR File;
LONG ReturnValue;
File = strrchr(FileName, '\\');
if (File == NULL) {
File = FileName;
}
dprintf(LOCKS, ("Releasing lock %s:%d on network %ws\n", File, LineNumber, (Network)->NetworkName.Buffer));
//
// Decrement the lock count.
//
ReturnValue = InterlockedDecrement( &Network->LockCount );
if ( ReturnValue < 0) {
dprintf(LOCKS, ("Over released lock %s:%d on network %ws\n", File, LineNumber, (Network)->NetworkName.Buffer));
KdPrint(("BROWSER: Over released lock %s:%d on network %ws\n", File, LineNumber, (Network)->NetworkName.Buffer));
}
RtlReleaseResource(&(Network)->Lock);
return;
}
#endif
#if DBG
VOID
BrDumpNetworks(
VOID
)
/*++
Routine Description:
This routine will dump the contents of each of the browser network
structures.
Arguments:
None.
Return Value:
None.
--*/
{
BrEnumerateNetworks(BrDumpNetworksWorker, NULL);
}
NET_API_STATUS
BrDumpNetworksWorker(
IN PNETWORK Network,
IN PVOID Context
)
{
if (!LOCK_NETWORK(Network)) {
return NERR_InternalError;
}
DbgPrint("Network at %lx (%wZ)\n", Network, &Network->NetworkName);
DbgPrint(" Reference Count: %lx\n", Network->ReferenceCount);
DbgPrint(" Flags: %lx\n", Network->Flags);
DbgPrint(" Role: %lx\n", Network->Role);
DbgPrint(" Master Browser Name: %wZ (%ws)\n", &Network->MasterBrowserName,
Network->MasterBrowserName.Buffer);
UNLOCK_NETWORK(Network);
return(NERR_Success);
}
#endif