1786 lines
46 KiB
C
1786 lines
46 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
browser.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the worker routines for the NetWksta APIs
|
|||
|
implemented in the Workstation service.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Rita Wong (ritaw) 20-Feb-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Local structure definitions //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
ULONG
|
|||
|
DomainAnnouncementPeriodicity[] = {1*60*1000, 1*60*1000, 5*60*1000, 5*60*1000, 10*60*1000, 10*60*1000, 15*60*1000};
|
|||
|
|
|||
|
ULONG
|
|||
|
DomainAnnouncementMax = (sizeof(DomainAnnouncementPeriodicity) / sizeof(ULONG)) - 1;
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Local function prototypes //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
BrGetMasterServerNameForNet(
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
BecomeMasterCompletion (
|
|||
|
IN PVOID Ctx
|
|||
|
);
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
StartMasterBrowserTimer(
|
|||
|
IN PNETWORK Network
|
|||
|
);
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
AnnounceMasterToDomainMaster(
|
|||
|
IN PNETWORK Network,
|
|||
|
IN LPWSTR ServerName
|
|||
|
);
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Global function prototypes //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
PostBecomeMaster(
|
|||
|
PNETWORK Network
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the worker routine called to actually issue a BecomeMaster
|
|||
|
FsControl to the bowser driver on all the bound transports. It will
|
|||
|
complete when the machine becomes a master browser server.
|
|||
|
|
|||
|
Please note that this might never complete.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status = NERR_Success;
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
if (!(Network->Flags & NETWORK_BECOME_MASTER_POSTED)) {
|
|||
|
|
|||
|
//
|
|||
|
// Make certain that we have the browser election name added
|
|||
|
// before we allow ourselves to become a master. This is a NOP
|
|||
|
// if we already have the election name added.
|
|||
|
//
|
|||
|
|
|||
|
(VOID) BrUpdateNetworkAnnouncementBits(Network, (PVOID)BR_PARANOID );
|
|||
|
|
|||
|
Status = BrIssueAsyncBrowserIoControl(Network,
|
|||
|
IOCTL_LMDR_BECOME_MASTER,
|
|||
|
BecomeMasterCompletion,
|
|||
|
NULL );
|
|||
|
|
|||
|
if ( Status == NERR_Success ) {
|
|||
|
Network->Flags |= NETWORK_BECOME_MASTER_POSTED;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BrRecoverFromFailedPromotion(
|
|||
|
IN PVOID Ctx
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
When we attempt to promote a machine to master browser and fail, we will
|
|||
|
effectively shut down the browser for a period of time. When that period
|
|||
|
of time expires, we will call BrRecoverFromFailedPromotion to recover
|
|||
|
from the failure.
|
|||
|
|
|||
|
This routine will do one of the following:
|
|||
|
1) Force the machine to become a backup browser,
|
|||
|
or 2) Attempt to discover the name of the master.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN PVOID Ctx - The network structure we failed on.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation (usually ignored).
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
{
|
|||
|
PNETWORK Network = Ctx;
|
|||
|
NET_API_STATUS Status;
|
|||
|
BOOL NetworkLocked = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Prevent the network from being deleted while we're in this timer routine.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) == NULL ) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return( Status = NERR_InternalError);
|
|||
|
}
|
|||
|
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: BrRecoverFromFailedPromotion.\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer ));
|
|||
|
|
|||
|
NetworkLocked = TRUE;
|
|||
|
//
|
|||
|
// We had better not be the master now.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (!(Network->Role & ROLE_MASTER));
|
|||
|
|
|||
|
//
|
|||
|
// If we're configured to become a backup by default, then become
|
|||
|
// a backup now.
|
|||
|
//
|
|||
|
|
|||
|
if (BrInfo.MaintainServerList == 1) {
|
|||
|
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: BrRecoverFromFailedPromotion. Become backup.\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer ));
|
|||
|
Status = BecomeBackup(Network, NULL);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Could not become backup: %lx\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
|
|||
|
}
|
|||
|
} else {
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: BrRecoverFromFailedPromotion. FindMaster.\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
NetworkLocked = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Now try to figure out who is the master.
|
|||
|
//
|
|||
|
|
|||
|
Status = GetMasterServerNames(Network);
|
|||
|
|
|||
|
//
|
|||
|
// Ignore the status from this and re-lock the network to
|
|||
|
// recover cleanly.
|
|||
|
//
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return( Status = NERR_InternalError);
|
|||
|
}
|
|||
|
|
|||
|
NetworkLocked = TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Status = NO_ERROR;
|
|||
|
//
|
|||
|
// Otherwise, just let sleeping dogs lie.
|
|||
|
//
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
if (NetworkLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
BecomeMasterCompletion (
|
|||
|
IN PVOID Ctx
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called by the I/O system when the request to become a
|
|||
|
master completes.
|
|||
|
|
|||
|
Please note that it is possible that the request may complete with an
|
|||
|
error.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
PBROWSERASYNCCONTEXT Context = Ctx;
|
|||
|
PNETWORK Network = Context->Network;
|
|||
|
BOOLEAN NetworkLocked = FALSE;
|
|||
|
BOOLEAN NetReferenced = FALSE;
|
|||
|
|
|||
|
|
|||
|
try {
|
|||
|
//
|
|||
|
// Ensure the network wasn't deleted from under us.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) == NULL ) {
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
NetReferenced = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Lock the network structure.
|
|||
|
//
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
NetworkLocked = TRUE;
|
|||
|
|
|||
|
Network->Flags &= ~NETWORK_BECOME_MASTER_POSTED;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Context->IoStatusBlock.Status)) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Failure in BecomeMaster: %X\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Context->IoStatusBlock.Status));
|
|||
|
|
|||
|
try_return(NOTHING);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: BecomeMasterCompletion. Now master on network %ws\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
//
|
|||
|
// If we're already a master, ignore this request.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Cancel any outstanding backup timers - we don't download the list
|
|||
|
// anymore.
|
|||
|
//
|
|||
|
|
|||
|
Status = BrCancelTimer(&Network->BackupBrowserTimer);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Could not stop backup timer: %lx\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Figure out what service bits we should be using when announcing ourselves
|
|||
|
//
|
|||
|
|
|||
|
Network->Role |= ROLE_MASTER;
|
|||
|
|
|||
|
|
|||
|
Status = BrUpdateNetworkAnnouncementBits(Network, 0 );
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: Unable to set master announcement bits in browser: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
|
|||
|
//
|
|||
|
// When we're in this state, we can't rely on our being a backup
|
|||
|
// browser - we may not be able to retrieve a valid list of
|
|||
|
// browsers from the master.
|
|||
|
//
|
|||
|
|
|||
|
Network->Role &= ~ROLE_BACKUP;
|
|||
|
|
|||
|
Network->NumberOfFailedPromotions += 1;
|
|||
|
|
|||
|
//
|
|||
|
// Log every 5 failed promotion attempts, and after having logged 5
|
|||
|
// promotion events, stop logging them, this means that it's been
|
|||
|
// 25 times that we've tried to promote, and it's not likely to get
|
|||
|
// any better. We'll keep on trying, but we won't complain any more.
|
|||
|
//
|
|||
|
|
|||
|
if ((Network->NumberOfFailedPromotions % 5) == 0) {
|
|||
|
ULONG AStatStatus;
|
|||
|
LPWSTR SubString[1];
|
|||
|
WCHAR CurrentMasterName[CNLEN+1];
|
|||
|
|
|||
|
if (Network->NumberOfPromotionEventsLogged < 5) {
|
|||
|
|
|||
|
AStatStatus = GetNetBiosMasterName(
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
CurrentMasterName,
|
|||
|
BrLmsvcsGlobalData->NetBiosReset
|
|||
|
);
|
|||
|
|
|||
|
if (AStatStatus == NERR_Success) {
|
|||
|
SubString[0] = CurrentMasterName;
|
|||
|
|
|||
|
BrLogEvent(EVENT_BROWSER_MASTER_PROMOTION_FAILED, Status, 1, SubString);
|
|||
|
} else {
|
|||
|
BrLogEvent(EVENT_BROWSER_MASTER_PROMOTION_FAILED_NO_MASTER, Status, 0, NULL);
|
|||
|
}
|
|||
|
|
|||
|
Network->NumberOfPromotionEventsLogged += 1;
|
|||
|
|
|||
|
if (Network->NumberOfPromotionEventsLogged == 5) {
|
|||
|
BrLogEvent(EVENT_BROWSER_MASTER_PROMOTION_FAILED_STOPPING, Status, 0, NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We were unable to promote ourselves to master.
|
|||
|
//
|
|||
|
// We want to set our role back to browser, and re-issue the become
|
|||
|
// master request.
|
|||
|
//
|
|||
|
|
|||
|
BrStopMaster(Network);
|
|||
|
|
|||
|
BrSetTimer(&Network->MasterBrowserTimer, FAILED_PROMOTION_PERIODICITY*1000, BrRecoverFromFailedPromotion, Network);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the number of times the master timer has run.
|
|||
|
//
|
|||
|
|
|||
|
Network->MasterBrowserTimerCount = 0;
|
|||
|
|
|||
|
Status = StartMasterBrowserTimer(Network);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Could not start browser master timer: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status ));
|
|||
|
}
|
|||
|
|
|||
|
Network->NumberOfFailedPromotions = 0;
|
|||
|
|
|||
|
Network->NumberOfPromotionEventsLogged = 0;
|
|||
|
|
|||
|
Network->MasterAnnouncementIndex = 0;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We successfully became the master.
|
|||
|
//
|
|||
|
// Now announce ourselves as the new master for this domain.
|
|||
|
//
|
|||
|
|
|||
|
BrMasterAnnouncement(Network);
|
|||
|
|
|||
|
//
|
|||
|
// Populate the browse list with the information retrieved
|
|||
|
// while we were a backup browser.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->TotalBackupServerListEntries != 0) {
|
|||
|
MergeServerList(&Network->BrowseTable,
|
|||
|
101,
|
|||
|
Network->BackupServerList,
|
|||
|
Network->TotalBackupServerListEntries,
|
|||
|
Network->TotalBackupServerListEntries
|
|||
|
);
|
|||
|
MIDL_user_free(Network->BackupServerList);
|
|||
|
|
|||
|
Network->BackupServerList = NULL;
|
|||
|
|
|||
|
Network->TotalBackupServerListEntries = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (Network->TotalBackupDomainListEntries != 0) {
|
|||
|
MergeServerList(&Network->DomainList,
|
|||
|
101,
|
|||
|
Network->BackupDomainList,
|
|||
|
Network->TotalBackupDomainListEntries,
|
|||
|
Network->TotalBackupDomainListEntries
|
|||
|
);
|
|||
|
MIDL_user_free(Network->BackupDomainList);
|
|||
|
|
|||
|
Network->BackupDomainList = NULL;
|
|||
|
|
|||
|
Network->TotalBackupDomainListEntries = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Unlock the network before calling BrWanMasterInitialize.
|
|||
|
//
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
NetworkLocked = FALSE;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Run the master browser timer routine to get the entire domains
|
|||
|
// list of servers.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->Flags & NETWORK_WANNISH) {
|
|||
|
BrWanMasterInitialize(Network);
|
|||
|
MasterBrowserTimerRoutine(Network);
|
|||
|
}
|
|||
|
|
|||
|
try_return(NOTHING);
|
|||
|
|
|||
|
}
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
|
|||
|
//
|
|||
|
// Make sure there's a become master oustanding.
|
|||
|
//
|
|||
|
|
|||
|
if ( NetReferenced ) {
|
|||
|
PostBecomeMaster(Network);
|
|||
|
}
|
|||
|
|
|||
|
if (NetworkLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
if ( NetReferenced ) {
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
|
|||
|
MIDL_user_free(Context);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
ChangeMasterPeriodicityWorker(
|
|||
|
PNETWORK Network,
|
|||
|
PVOID Ctx
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function changes the master periodicity for a single network.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Lock the network
|
|||
|
//
|
|||
|
|
|||
|
if (LOCK_NETWORK(Network)) {
|
|||
|
|
|||
|
//
|
|||
|
// Ensure we're the master.
|
|||
|
//
|
|||
|
|
|||
|
if ( Network->Role & ROLE_MASTER ) {
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
//
|
|||
|
// Cancel the timer to ensure it doesn't go off while we're
|
|||
|
// processing this change.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = BrCancelTimer(&Network->MasterBrowserTimer);
|
|||
|
ASSERT (NetStatus == NERR_Success);
|
|||
|
|
|||
|
//
|
|||
|
// Unlock the network while we execute the timer routine.
|
|||
|
//
|
|||
|
UNLOCK_NETWORK( Network );
|
|||
|
|
|||
|
//
|
|||
|
// Call the timer routine immediately.
|
|||
|
//
|
|||
|
MasterBrowserTimerRoutine(Network);
|
|||
|
|
|||
|
} else {
|
|||
|
UNLOCK_NETWORK( Network );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(Ctx);
|
|||
|
|
|||
|
return NERR_Success;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
BrChangeMasterPeriodicity (
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called when the master periodicity is changed in the
|
|||
|
registry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
(VOID)BrEnumerateNetworks(ChangeMasterPeriodicityWorker, NULL);
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
StartMasterBrowserTimer(
|
|||
|
IN PNETWORK Network
|
|||
|
)
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
Status = BrSetTimer( &Network->MasterBrowserTimer,
|
|||
|
BrInfo.MasterPeriodicity*1000,
|
|||
|
MasterBrowserTimerRoutine,
|
|||
|
Network);
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
typedef struct _BROWSER_GETNAMES_CONTEXT {
|
|||
|
WORKER_ITEM WorkItem;
|
|||
|
|
|||
|
PNETWORK Network;
|
|||
|
|
|||
|
} BROWSER_GETNAMES_CONTEXT, *PBROWSER_GETNAMES_CONTEXT;
|
|||
|
|
|||
|
VOID
|
|||
|
BrGetMasterServerNameAysnc(
|
|||
|
PNETWORK Network
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Queue a workitem to asynchronously get the master browser names for a
|
|||
|
transport.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Network - Identifies the network to query.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PBROWSER_GETNAMES_CONTEXT Context;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate context for this async call.
|
|||
|
//
|
|||
|
|
|||
|
Context = LocalAlloc( 0, sizeof(BROWSER_GETNAMES_CONTEXT) );
|
|||
|
|
|||
|
if ( Context == NULL ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Just queue this for later execution.
|
|||
|
// We're doing this for information purposes only. In the case that
|
|||
|
// the master can't be found, we don't want to wait for completion.
|
|||
|
// (e.g., on a machine with multiple transports and the net cable is
|
|||
|
// pulled)
|
|||
|
//
|
|||
|
|
|||
|
BrReferenceNetwork( Network );
|
|||
|
Context->Network = Network;
|
|||
|
|
|||
|
BrInitializeWorkItem( &Context->WorkItem,
|
|||
|
BrGetMasterServerNameForNet,
|
|||
|
Context );
|
|||
|
|
|||
|
BrQueueWorkItem( &Context->WorkItem );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
BrGetMasterServerNameForNet(
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Routine to get the master browser name for a particular network.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Context containing the workitem and the description of the
|
|||
|
network to query.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PNETWORK Network = ((PBROWSER_GETNAMES_CONTEXT)Context)->Network;
|
|||
|
|
|||
|
BrPrint(( BR_NETWORK,
|
|||
|
"%ws: %ws: FindMaster during startup\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
//
|
|||
|
// We only call this on startup, so on IPX networks, don't bother to
|
|||
|
// find out the master.
|
|||
|
//
|
|||
|
|
|||
|
if (!(Network->Flags & NETWORK_IPX)) {
|
|||
|
GetMasterServerNames(Network);
|
|||
|
}
|
|||
|
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
(VOID) LocalFree( Context );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
GetMasterServerNames(
|
|||
|
IN PNETWORK Network
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is the worker routine called to determine the name of the
|
|||
|
master browser server for a particular network.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status - The status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
PLMDR_REQUEST_PACKET RequestPacket = NULL;
|
|||
|
|
|||
|
BrPrint(( BR_NETWORK,
|
|||
|
"%ws: %ws: FindMaster started\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
//
|
|||
|
// This request could cause an election. Make sure that if we win
|
|||
|
// the election that we can handle it.
|
|||
|
//
|
|||
|
|
|||
|
PostBecomeMaster( Network);
|
|||
|
|
|||
|
RequestPacket = MIDL_user_allocate(
|
|||
|
(UINT) sizeof(LMDR_REQUEST_PACKET)+
|
|||
|
MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)
|
|||
|
);
|
|||
|
|
|||
|
if (RequestPacket == NULL) {
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
|
|||
|
|
|||
|
//
|
|||
|
// Set level to TRUE to indicate that find master should initiate
|
|||
|
// a findmaster request.
|
|||
|
//
|
|||
|
|
|||
|
RequestPacket->Level = 1;
|
|||
|
|
|||
|
RequestPacket->TransportName = Network->NetworkName;
|
|||
|
RequestPacket->EmulatedDomainName = Network->DomainInfo->DomUnicodeDomainNameString;
|
|||
|
|
|||
|
//
|
|||
|
// Reference the network while the I/O is pending.
|
|||
|
//
|
|||
|
|
|||
|
Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
|
|||
|
IOCTL_LMDR_GET_MASTER_NAME,
|
|||
|
RequestPacket,
|
|||
|
sizeof(LMDR_REQUEST_PACKET)+Network->NetworkName.Length,
|
|||
|
RequestPacket,
|
|||
|
sizeof(LMDR_REQUEST_PACKET)+MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR),
|
|||
|
NULL);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: FindMaster failed: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
MIDL_user_free(RequestPacket);
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
MIDL_user_free(RequestPacket);
|
|||
|
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Copy the master browser name into the network structure
|
|||
|
//
|
|||
|
|
|||
|
wcsncpy( Network->UncMasterBrowserName,
|
|||
|
RequestPacket->Parameters.GetMasterName.Name,
|
|||
|
UNCLEN+1 );
|
|||
|
|
|||
|
Network->UncMasterBrowserName[UNCLEN] = L'\0';
|
|||
|
|
|||
|
ASSERT ( NetpIsUncComputerNameValid( Network->UncMasterBrowserName ) );
|
|||
|
|
|||
|
BrPrint(( BR_NETWORK, "%ws: %ws: FindMaster succeeded. Master: %ws\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Network->UncMasterBrowserName));
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
MIDL_user_free(RequestPacket);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
MasterBrowserTimerRoutine (
|
|||
|
IN PVOID TimerContext
|
|||
|
)
|
|||
|
{
|
|||
|
IN PNETWORK Network = TimerContext;
|
|||
|
NET_API_STATUS Status;
|
|||
|
PVOID ServerList = NULL;
|
|||
|
PVOID WinsServerList = NULL;
|
|||
|
ULONG EntriesInList;
|
|||
|
ULONG TotalEntriesInList;
|
|||
|
LPWSTR TransportName;
|
|||
|
BOOLEAN NetLocked = FALSE;
|
|||
|
LPWSTR PrimaryDomainController = NULL;
|
|||
|
LPWSTR PrimaryWinsServerAddress = NULL;
|
|||
|
LPWSTR SecondaryWinsServerAddress = NULL;
|
|||
|
PDOMAIN_CONTROLLER_INFO pDcInfo=NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Prevent the network from being deleted while we're in this timer routine.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) == NULL ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
//
|
|||
|
// If we're not a master any more, blow away this request.
|
|||
|
//
|
|||
|
|
|||
|
if (!(Network->Role & ROLE_MASTER)) {
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#ifdef ENABLE_PSEUDO_BROWSER
|
|||
|
if (BrInfo.PseudoServerLevel == BROWSER_PSEUDO) {
|
|||
|
BrFreeNetworkTables(Network);
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
|
|||
|
NetLocked = TRUE;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
TransportName = Network->NetworkName.Buffer;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now that we have the network locked, re-test to see if we are
|
|||
|
// still the master.
|
|||
|
//
|
|||
|
|
|||
|
if (!(Network->Role & ROLE_MASTER)) {
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
|
|||
|
Network->MasterBrowserTimerCount += 1;
|
|||
|
|
|||
|
//
|
|||
|
// If this is a wannish network, we always want to run the master
|
|||
|
// timer because we might have information about other subnets
|
|||
|
// in our list.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->Flags & NETWORK_WANNISH) {
|
|||
|
|
|||
|
//
|
|||
|
// Age out servers and domains from the server list.
|
|||
|
//
|
|||
|
|
|||
|
AgeInterimServerList(&Network->BrowseTable);
|
|||
|
|
|||
|
AgeInterimServerList(&Network->DomainList);
|
|||
|
|
|||
|
//
|
|||
|
// If we're not the PDC, then we need to retrieve the list
|
|||
|
// from the PDC....
|
|||
|
//
|
|||
|
// Skip processing if we're a semi-pseudo server (no dmb
|
|||
|
// communications
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
#ifdef ENABLE_PSEUDO_BROWSER
|
|||
|
if ( (Network->Flags & NETWORK_PDC) == 0 &&
|
|||
|
BrInfo.PseudoServerLevel != BROWSER_SEMI_PSEUDO_NO_DMB) {
|
|||
|
#else
|
|||
|
if ( (Network->Flags & NETWORK_PDC) == 0 ) {
|
|||
|
#endif
|
|||
|
|
|||
|
ASSERT (NetLocked);
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
|
|||
|
NetLocked = FALSE;
|
|||
|
|
|||
|
Status = DsGetDcName( NULL, NULL, NULL, NULL,
|
|||
|
DS_PDC_REQUIRED |
|
|||
|
DS_BACKGROUND_ONLY |
|
|||
|
DS_RETURN_FLAT_NAME,
|
|||
|
&pDcInfo );
|
|||
|
|
|||
|
//
|
|||
|
// If the PDC can be found,
|
|||
|
// Exchange server lists with it.
|
|||
|
//
|
|||
|
|
|||
|
if (Status == NERR_Success) {
|
|||
|
|
|||
|
PrimaryDomainController = pDcInfo->DomainControllerName;
|
|||
|
|
|||
|
//
|
|||
|
// Tell the Domain Master (PDC) that we're a master browser.
|
|||
|
//
|
|||
|
|
|||
|
(VOID) AnnounceMasterToDomainMaster (Network, &PrimaryDomainController[2]);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Retrieve the list of all the servers from the PDC.
|
|||
|
//
|
|||
|
|
|||
|
Status = RxNetServerEnum(PrimaryDomainController,
|
|||
|
TransportName,
|
|||
|
101,
|
|||
|
(LPBYTE *)&ServerList,
|
|||
|
0xffffffff,
|
|||
|
&EntriesInList,
|
|||
|
&TotalEntriesInList,
|
|||
|
SV_TYPE_ALL,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ((Status == NERR_Success) || (Status == ERROR_MORE_DATA)) {
|
|||
|
|
|||
|
ASSERT (!NetLocked);
|
|||
|
|
|||
|
if (LOCK_NETWORK(Network)) {
|
|||
|
|
|||
|
NetLocked = TRUE;
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
(VOID) MergeServerList(&Network->BrowseTable,
|
|||
|
101,
|
|||
|
ServerList,
|
|||
|
EntriesInList,
|
|||
|
TotalEntriesInList );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (ServerList != NULL) {
|
|||
|
MIDL_user_free(ServerList);
|
|||
|
ServerList = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (NetLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
NetLocked = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Retrieve the list of all the domains from the PDC.
|
|||
|
//
|
|||
|
|
|||
|
Status = RxNetServerEnum(PrimaryDomainController,
|
|||
|
TransportName,
|
|||
|
101,
|
|||
|
(LPBYTE *)&ServerList,
|
|||
|
0xffffffff,
|
|||
|
&EntriesInList,
|
|||
|
&TotalEntriesInList,
|
|||
|
SV_TYPE_DOMAIN_ENUM,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ((Status == NERR_Success) || (Status == ERROR_MORE_DATA)) {
|
|||
|
|
|||
|
ASSERT (!NetLocked);
|
|||
|
|
|||
|
if (LOCK_NETWORK(Network)) {
|
|||
|
|
|||
|
NetLocked = TRUE;
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
(VOID) MergeServerList(&Network->DomainList,
|
|||
|
101,
|
|||
|
ServerList,
|
|||
|
EntriesInList,
|
|||
|
TotalEntriesInList );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (ServerList != NULL) {
|
|||
|
MIDL_user_free(ServerList);
|
|||
|
ServerList = NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Unlock the network before calling BrWanMasterInitialize.
|
|||
|
//
|
|||
|
|
|||
|
if (NetLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
NetLocked = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
BrWanMasterInitialize(Network);
|
|||
|
|
|||
|
} // dsgetdc
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If we're on the PDC, we need to get the list of servers from
|
|||
|
// the WINS server.
|
|||
|
//
|
|||
|
|
|||
|
#ifdef ENABLE_PSEUDO_BROWSER
|
|||
|
} else if ((Network->Flags & NETWORK_PDC) != 0) {
|
|||
|
#else
|
|||
|
} else {
|
|||
|
#endif
|
|||
|
//
|
|||
|
// Ensure a GetMasterAnnouncement request is posted to the bowser.
|
|||
|
//
|
|||
|
|
|||
|
(VOID) PostGetMasterAnnouncement ( Network );
|
|||
|
|
|||
|
//
|
|||
|
// We want to contact the WINS server now, so we figure out the
|
|||
|
// IP address of our primary WINS server
|
|||
|
//
|
|||
|
|
|||
|
Status = BrGetWinsServerName(&Network->NetworkName,
|
|||
|
&PrimaryWinsServerAddress,
|
|||
|
&SecondaryWinsServerAddress);
|
|||
|
if (Status == NERR_Success) {
|
|||
|
|
|||
|
//
|
|||
|
// Don't keep the network locked during the WINS query
|
|||
|
//
|
|||
|
|
|||
|
if (NetLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
NetLocked = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This transport supports WINS queries, so query the WINS
|
|||
|
// server to retrieve the list of domains on this adapter.
|
|||
|
//
|
|||
|
|
|||
|
Status = BrQueryWinsServer(PrimaryWinsServerAddress,
|
|||
|
SecondaryWinsServerAddress,
|
|||
|
&WinsServerList,
|
|||
|
&EntriesInList,
|
|||
|
&TotalEntriesInList
|
|||
|
);
|
|||
|
|
|||
|
if (Status == NERR_Success) {
|
|||
|
|
|||
|
//
|
|||
|
// Lock the network to merge the server list
|
|||
|
//
|
|||
|
|
|||
|
ASSERT (!NetLocked);
|
|||
|
|
|||
|
if (LOCK_NETWORK(Network)) {
|
|||
|
NetLocked = TRUE;
|
|||
|
|
|||
|
if (Network->Role & ROLE_MASTER) {
|
|||
|
|
|||
|
//
|
|||
|
// Merge the list of domains from WINS into the one collected elsewhere
|
|||
|
//
|
|||
|
(VOID) MergeServerList(
|
|||
|
&Network->DomainList,
|
|||
|
1010, // Special level to not overide current values
|
|||
|
WinsServerList,
|
|||
|
EntriesInList,
|
|||
|
TotalEntriesInList );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Restart the timer for this domain.
|
|||
|
//
|
|||
|
// Wait to restart it until we're almost done with this iteration.
|
|||
|
// Otherwise, we could end up with two copies of this routine
|
|||
|
// running.
|
|||
|
//
|
|||
|
|
|||
|
Status = StartMasterBrowserTimer(Network);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Unable to restart browser backup timer: %lx\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// If it is a lan-ish transport, and we have run the master
|
|||
|
// timer for enough times (ie. we've been a master
|
|||
|
// for "long enough", we can toss the interim server list in the
|
|||
|
// master, because the bowser driver will have enough data in its
|
|||
|
// list by now.
|
|||
|
//
|
|||
|
|
|||
|
if (Network->MasterBrowserTimerCount >= MASTER_BROWSER_LAN_TIMER_LIMIT) {
|
|||
|
|
|||
|
ASSERT (NetLocked);
|
|||
|
|
|||
|
//
|
|||
|
// Make all the servers and domains in the interim server list
|
|||
|
// go away - they aren't needed any more for a LAN-ish transport.
|
|||
|
//
|
|||
|
|
|||
|
UninitializeInterimServerList(&Network->BrowseTable);
|
|||
|
|
|||
|
ASSERT (Network->BrowseTable.EntriesRead == 0);
|
|||
|
|
|||
|
ASSERT (Network->BrowseTable.TotalEntries == 0);
|
|||
|
|
|||
|
UninitializeInterimServerList(&Network->DomainList);
|
|||
|
|
|||
|
ASSERT (Network->DomainList.EntriesRead == 0);
|
|||
|
|
|||
|
ASSERT (Network->DomainList.TotalEntries == 0);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Age out servers and domains from the server list.
|
|||
|
//
|
|||
|
|
|||
|
AgeInterimServerList(&Network->BrowseTable);
|
|||
|
|
|||
|
AgeInterimServerList(&Network->DomainList);
|
|||
|
|
|||
|
//
|
|||
|
// Restart the timer for this domain.
|
|||
|
//
|
|||
|
|
|||
|
Status = StartMasterBrowserTimer(Network);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_CRITICAL,
|
|||
|
"%ws: %ws: Unable to restart browser backup timer: %lx\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
try_return(NOTHING);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
|
|||
|
|
|||
|
if (pDcInfo != NULL) {
|
|||
|
NetApiBufferFree((LPVOID)pDcInfo);
|
|||
|
}
|
|||
|
|
|||
|
if (PrimaryWinsServerAddress) {
|
|||
|
MIDL_user_free(PrimaryWinsServerAddress);
|
|||
|
}
|
|||
|
|
|||
|
if (SecondaryWinsServerAddress) {
|
|||
|
MIDL_user_free(SecondaryWinsServerAddress);
|
|||
|
}
|
|||
|
|
|||
|
if (WinsServerList) {
|
|||
|
MIDL_user_free(WinsServerList);
|
|||
|
}
|
|||
|
|
|||
|
if (NetLocked) {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
BrMasterAnnouncement(
|
|||
|
IN PVOID TimerContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to announce the domain on the local sub-net.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PNETWORK Network = TimerContext;
|
|||
|
ULONG Periodicity;
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
#ifdef ENABLE_PSEUDO_BROWSER
|
|||
|
if ( BrInfo.PseudoServerLevel == BROWSER_PSEUDO ) {
|
|||
|
// cancel announcements for phase out black hole server
|
|||
|
return;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Prevent the network from being deleted while we're in this timer routine.
|
|||
|
//
|
|||
|
if ( BrReferenceNetwork( Network ) == NULL ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Make absolutely certain that the server thinks that the browser service
|
|||
|
// bits for this transport are up to date. We do NOT have to force an
|
|||
|
// announcement, since theoretically, the status didn't change.
|
|||
|
//
|
|||
|
|
|||
|
(VOID) BrUpdateNetworkAnnouncementBits( Network, (PVOID) BR_PARANOID );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Setup the timer for the next announcement.
|
|||
|
//
|
|||
|
|
|||
|
Periodicity = DomainAnnouncementPeriodicity[Network->MasterAnnouncementIndex];
|
|||
|
|
|||
|
BrSetTimer(&Network->MasterBrowserAnnouncementTimer, Periodicity, BrMasterAnnouncement, Network);
|
|||
|
|
|||
|
if (Network->MasterAnnouncementIndex != DomainAnnouncementMax) {
|
|||
|
Network->MasterAnnouncementIndex += 1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Announce this domain to the world using the current periodicity.
|
|||
|
//
|
|||
|
|
|||
|
BrAnnounceDomain(Network, Periodicity);
|
|||
|
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
BrDereferenceNetwork( Network );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
BrStopMaster(
|
|||
|
IN PNETWORK Network
|
|||
|
)
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// This guy is shutting down - set his role to 0 and announce.
|
|||
|
//
|
|||
|
|
|||
|
if (!LOCK_NETWORK(Network)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: Stopping being master.\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer));
|
|||
|
|
|||
|
//
|
|||
|
// When we stop being a master, we can no longer be considered a
|
|||
|
// backup either, since backups maintain their server list
|
|||
|
// differently than the master.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
Network->Role &= ~(ROLE_MASTER | ROLE_BACKUP);
|
|||
|
|
|||
|
Status = BrUpdateNetworkAnnouncementBits(Network, 0);
|
|||
|
|
|||
|
if (Status != NERR_Success) {
|
|||
|
BrPrint(( BR_MASTER,
|
|||
|
"%ws: %ws: Unable to clear master announcement bits in browser: %ld\n",
|
|||
|
Network->DomainInfo->DomUnicodeDomainName,
|
|||
|
Network->NetworkName.Buffer,
|
|||
|
Status));
|
|||
|
|
|||
|
try_return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Stop our master related timers.
|
|||
|
//
|
|||
|
|
|||
|
Status = BrCancelTimer(&Network->MasterBrowserAnnouncementTimer);
|
|||
|
|
|||
|
ASSERT (Status == NERR_Success);
|
|||
|
|
|||
|
Status = BrCancelTimer(&Network->MasterBrowserTimer);
|
|||
|
|
|||
|
ASSERT (Status == NERR_Success);
|
|||
|
|
|||
|
try_exit:NOTHING;
|
|||
|
} finally {
|
|||
|
UNLOCK_NETWORK(Network);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
AnnounceMasterToDomainMaster(
|
|||
|
IN PNETWORK Network,
|
|||
|
IN LPWSTR ServerName
|
|||
|
)
|
|||
|
{
|
|||
|
NET_API_STATUS Status;
|
|||
|
UNICODE_STRING EmulatedDomainName;
|
|||
|
CHAR Buffer[sizeof(MASTER_ANNOUNCEMENT)+CNLEN+1];
|
|||
|
PMASTER_ANNOUNCEMENT MasterAnnouncementp = (PMASTER_ANNOUNCEMENT)Buffer;
|
|||
|
|
|||
|
lstrcpyA( MasterAnnouncementp->MasterAnnouncement.MasterName,
|
|||
|
Network->DomainInfo->DomOemComputerName );
|
|||
|
|
|||
|
MasterAnnouncementp->Type = MasterAnnouncement;
|
|||
|
|
|||
|
Status = SendDatagram( BrDgReceiverDeviceHandle,
|
|||
|
&Network->NetworkName,
|
|||
|
&Network->DomainInfo->DomUnicodeDomainNameString,
|
|||
|
ServerName,
|
|||
|
ComputerName,
|
|||
|
MasterAnnouncementp,
|
|||
|
FIELD_OFFSET(MASTER_ANNOUNCEMENT, MasterAnnouncement.MasterName) + Network->DomainInfo->DomOemComputerNameLength+sizeof(CHAR)
|
|||
|
);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
I_BrowserrResetNetlogonState(
|
|||
|
IN BROWSER_IDENTIFY_HANDLE ServerName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will reset the bowser's concept of the state of the netlogon
|
|||
|
service. It is called by the UI when it promotes or demotes a DC.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IN BROWSER_IDENTIFY_HANDLE ServerName - Ignored.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - The status of this request.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// This routine has been superceeded by I_BrowserrSetNetlogonState
|
|||
|
//
|
|||
|
return ERROR_NOT_SUPPORTED;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( ServerName );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
I_BrowserrSetNetlogonState(
|
|||
|
IN BROWSER_IDENTIFY_HANDLE ServerName,
|
|||
|
IN LPWSTR DomainName,
|
|||
|
IN LPWSTR EmulatedComputerName,
|
|||
|
IN DWORD Role
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will reset the bowser's concept of the state of the netlogon
|
|||
|
service. It is called by the Netlogon service when it promotes or demotes a DC.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Ignored.
|
|||
|
|
|||
|
DomainName - Name of the domain whose role has changed. If the domain name specified
|
|||
|
isn't the primary domain or an emulated domain, an emulated domain is added.
|
|||
|
|
|||
|
EmulatedComputerName - Name of the server within DomainName that's being emulated.
|
|||
|
|
|||
|
Role - New role of the machine.
|
|||
|
Zero implies emulated domain is to be deleted.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - The status of this request.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NERR_Success;
|
|||
|
PDOMAIN_INFO DomainInfo = NULL;
|
|||
|
BOOLEAN ConfigCritSectLocked = FALSE;
|
|||
|
|
|||
|
#ifdef notdef
|
|||
|
|
|||
|
// This routine no longer sets the role.
|
|||
|
|
|||
|
//
|
|||
|
// This routine is currently disabled since it doesn't work well with
|
|||
|
// the PNP logic. Specifically,
|
|||
|
//
|
|||
|
// When a hosted domain is created, this routine calls BrCreateNetwork.
|
|||
|
// That creates a network in the bowser. The bowser PNPs that up.
|
|||
|
// HandlePnpMessage tries to create the transport on all hosted domains.
|
|||
|
// Of course, that fails since all the transports exist.
|
|||
|
// This is just wasted effort.
|
|||
|
//
|
|||
|
// However,
|
|||
|
// When a hosted domain is deleted, we delete the transport. The bowser
|
|||
|
// PNPs that up to us. HandlePnpMessage then deletes the transport for
|
|||
|
// all hosted domains.
|
|||
|
//
|
|||
|
// I think the best solution to this would be for the browser to flag
|
|||
|
// the IOCTL_LMDR_BIND_TO_TRANSPORT_DOM calls it makes to the bowser. The
|
|||
|
// bowser would NOT PNP such creations up to the browser or netlogon.
|
|||
|
// (Be careful. Netlogon depends on getting the notification that NwLnkIpx
|
|||
|
// was created by the browser. Perhaps we can let that one through.)
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Perform access validation on the caller.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetpAccessCheck(
|
|||
|
BrGlobalBrowserSecurityDescriptor, // Security descriptor
|
|||
|
BROWSER_CONTROL_ACCESS, // Desired access
|
|||
|
&BrGlobalBrowserInfoMapping ); // Generic mapping
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success) {
|
|||
|
|
|||
|
BrPrint((BR_CRITICAL,
|
|||
|
"I_BrowserrSetNetlogonState failed NetpAccessCheck\n" ));
|
|||
|
return ERROR_ACCESS_DENIED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (!BrInfo.IsLanmanNt) {
|
|||
|
NetStatus = NERR_NotPrimary;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// See if we're handling the specified domain.
|
|||
|
//
|
|||
|
|
|||
|
DomainInfo = BrFindDomain( DomainName, FALSE );
|
|||
|
|
|||
|
if ( DomainInfo == NULL ) {
|
|||
|
|
|||
|
//
|
|||
|
// Try to create the domain.
|
|||
|
//
|
|||
|
|
|||
|
if ( EmulatedComputerName == NULL ||
|
|||
|
Role == 0 ||
|
|||
|
(Role & BROWSER_ROLE_AVOID_CREATING_DOMAIN) != 0 ) {
|
|||
|
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
NetStatus = BrCreateDomainInWorker(
|
|||
|
DomainName,
|
|||
|
EmulatedComputerName,
|
|||
|
TRUE );
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success ) {
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find the newly created domain
|
|||
|
//
|
|||
|
DomainInfo = BrFindDomain( DomainName, FALSE );
|
|||
|
|
|||
|
if ( DomainInfo == NULL ) {
|
|||
|
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Delete the Emulated domain.
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection(&BrInfo.ConfigCritSect);
|
|||
|
ConfigCritSectLocked = TRUE;
|
|||
|
|
|||
|
if ( Role == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// Don't allow the primary domain to be deleted.
|
|||
|
//
|
|||
|
|
|||
|
if ( !DomainInfo->IsEmulatedDomain ) {
|
|||
|
NetStatus = ERROR_NO_SUCH_DOMAIN;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
BrDeleteDomain( DomainInfo );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection(&BrInfo.ConfigCritSect);
|
|||
|
ConfigCritSectLocked = FALSE;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Free locally used resources
|
|||
|
//
|
|||
|
Cleanup:
|
|||
|
|
|||
|
if ( ConfigCritSectLocked ) {
|
|||
|
LeaveCriticalSection(&BrInfo.ConfigCritSect);
|
|||
|
}
|
|||
|
|
|||
|
if ( DomainInfo != NULL ) {
|
|||
|
BrDereferenceDomain( DomainInfo );
|
|||
|
}
|
|||
|
return NetStatus;
|
|||
|
#endif // notdef
|
|||
|
return ERROR_NOT_SUPPORTED;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS NET_API_FUNCTION
|
|||
|
I_BrowserrQueryEmulatedDomains (
|
|||
|
IN LPTSTR ServerName OPTIONAL,
|
|||
|
IN OUT PBROWSER_EMULATED_DOMAIN_CONTAINER EmulatedDomains
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Enumerate the emulated domain list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerName - Supplies the name of server to execute this function
|
|||
|
|
|||
|
EmulatedDomains - Returns a pointer to a an allocated array of emulated domain
|
|||
|
information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus;
|
|||
|
|
|||
|
PBROWSER_EMULATED_DOMAIN Domains = NULL;
|
|||
|
PLIST_ENTRY DomainEntry;
|
|||
|
PDOMAIN_INFO DomainInfo;
|
|||
|
DWORD BufferSize;
|
|||
|
DWORD Index;
|
|||
|
LPBYTE Where;
|
|||
|
DWORD EntryCount;
|
|||
|
|
|||
|
//
|
|||
|
// Perform access validation on the caller.
|
|||
|
//
|
|||
|
|
|||
|
NetStatus = NetpAccessCheck(
|
|||
|
BrGlobalBrowserSecurityDescriptor, // Security descriptor
|
|||
|
BROWSER_QUERY_ACCESS, // Desired access
|
|||
|
&BrGlobalBrowserInfoMapping ); // Generic mapping
|
|||
|
|
|||
|
if ( NetStatus != NERR_Success) {
|
|||
|
|
|||
|
BrPrint((BR_CRITICAL,
|
|||
|
"I_BrowserrQueryEmulatedDomains failed NetpAccessCheck\n" ));
|
|||
|
return ERROR_ACCESS_DENIED;
|
|||
|
}
|
|||
|
|
|||
|
// Do not accept pre-allocated IN param, since
|
|||
|
// we overwrite the pointer & this can lead to a mem leak.
|
|||
|
// (security attack defence).
|
|||
|
if ( EmulatedDomains->EntriesRead != 0 ||
|
|||
|
EmulatedDomains->Buffer ) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
ASSERT ( EmulatedDomains->EntriesRead == 0 );
|
|||
|
ASSERT ( EmulatedDomains->Buffer == NULL );
|
|||
|
|
|||
|
//
|
|||
|
// Initialization
|
|||
|
//
|
|||
|
|
|||
|
EnterCriticalSection(&NetworkCritSect);
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the list of emulated domains determining the size of the
|
|||
|
// return buffer.
|
|||
|
//
|
|||
|
|
|||
|
BufferSize = 0;
|
|||
|
EntryCount = 0;
|
|||
|
|
|||
|
for (DomainEntry = ServicedDomains.Flink ;
|
|||
|
DomainEntry != &ServicedDomains;
|
|||
|
DomainEntry = DomainEntry->Flink ) {
|
|||
|
|
|||
|
DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
|
|||
|
|
|||
|
if ( DomainInfo->IsEmulatedDomain ) {
|
|||
|
BufferSize += sizeof(BROWSER_EMULATED_DOMAIN) +
|
|||
|
DomainInfo->DomUnicodeDomainNameString.Length + sizeof(WCHAR) +
|
|||
|
DomainInfo->DomUnicodeComputerNameLength * sizeof(WCHAR) + sizeof(WCHAR);
|
|||
|
EntryCount ++;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the return buffer.
|
|||
|
//
|
|||
|
|
|||
|
Domains = MIDL_user_allocate( BufferSize );
|
|||
|
|
|||
|
if ( Domains == NULL ) {
|
|||
|
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Copy the information into the buffer
|
|||
|
//
|
|||
|
|
|||
|
Index = 0;
|
|||
|
Where = (LPBYTE)(Domains+EntryCount);
|
|||
|
|
|||
|
for (DomainEntry = ServicedDomains.Flink ;
|
|||
|
DomainEntry != &ServicedDomains;
|
|||
|
DomainEntry = DomainEntry->Flink ) {
|
|||
|
|
|||
|
DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
|
|||
|
|
|||
|
if ( DomainInfo->IsEmulatedDomain ) {
|
|||
|
|
|||
|
Domains[Index].DomainName = (LPWSTR)Where;
|
|||
|
wcscpy( (LPWSTR) Where, DomainInfo->DomUnicodeDomainNameString.Buffer );
|
|||
|
Where += DomainInfo->DomUnicodeDomainNameString.Length + sizeof(WCHAR);
|
|||
|
|
|||
|
Domains[Index].EmulatedServerName = (LPWSTR)Where;
|
|||
|
wcscpy( (LPWSTR) Where, DomainInfo->DomUnicodeComputerName );
|
|||
|
Where += DomainInfo->DomUnicodeComputerNameLength * sizeof(WCHAR) + sizeof(WCHAR);
|
|||
|
|
|||
|
Index ++;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Success
|
|||
|
//
|
|||
|
|
|||
|
EmulatedDomains->Buffer = (PVOID) Domains;
|
|||
|
EmulatedDomains->EntriesRead = EntryCount;
|
|||
|
NetStatus = NERR_Success;
|
|||
|
|
|||
|
|
|||
|
Cleanup:
|
|||
|
LeaveCriticalSection(&NetworkCritSect);
|
|||
|
|
|||
|
return NetStatus;
|
|||
|
}
|