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;
|
||
}
|