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.
 
 
 
 
 
 

1541 lines
40 KiB

/*++
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 //
// //
//-------------------------------------------------------------------//
NET_API_STATUS
PostBecomeMaster(
PNETWORK Network,
PVOID Ctx
);
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
BrPostBecomeMaster(
VOID
)
{
return BrEnumerateNetworks(PostBecomeMaster, NULL);
}
NET_API_STATUS
PostBecomeMaster(
PNETWORK Network,
PVOID Ctx
)
/*++
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)) {
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.
//
Status = BrUpdateBrowserStatus(Network, BrGetBrowserServiceBits(Network) | SV_TYPE_POTENTIAL_BROWSER);
if (Status != NERR_Success) {
Network->Flags &= ~NETWORK_BECOME_MASTER_POSTED;
KdPrint(("Unable to update browser status\n"));
UNLOCK_NETWORK(Network);
return Status;
}
Status = BrIssueAsyncBrowserIoControl(Network,
IOCTL_LMDR_BECOME_MASTER,
BecomeMasterCompletion
);
}
UNLOCK_NETWORK(Network);
UNREFERENCED_PARAMETER(Ctx);
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;
if (!LOCK_NETWORK(Network)) {
return NERR_InternalError;
}
dprintf(MASTER, ("BrRecoverFromFailedPromotion on %ws\n", Network->NetworkName.Buffer));
NetworkLocked = TRUE;
try {
//
// 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) {
dprintf(MASTER, ("BrRecoverFromFailedPromotion. Become backup on %ws\n", Network->NetworkName.Buffer));
Status = BecomeBackup(Network, NULL);
if (Status != NERR_Success) {
KdPrint(("Browser: Could not become backup: %lx\n", Status));
}
} else {
dprintf(MASTER, ("BrRecoverFromFailedPromotion. FindMaster on %ws\n", 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)) {
return NERR_InternalError;
}
NetworkLocked = TRUE;
}
//
// Otherwise, just let sleeping dogs lie.
//
//try_exit:NOTHING;
} finally {
if (NetworkLocked) {
UNLOCK_NETWORK(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;
ULONG ServiceBits;
//
// Lock the network structure.
//
if (!LOCK_NETWORK(Network)) {
MIDL_user_free(Context->RequestPacket);
MIDL_user_free(Context);
return;
}
NetworkLocked = TRUE;
try {
Network->Flags &= ~NETWORK_BECOME_MASTER_POSTED;
if (!NT_SUCCESS(Context->IoStatusBlock.Status)) {
InternalError(("Browser: Failure in BecomeMaster: %X\n", Context->IoStatusBlock.Status));
try_return(NOTHING);
}
dprintf(MASTER, ("BecomeMasterCompletion. Now master on network %ws\n", 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)) {
KdPrint(("Browser: Could not stop backup timer: %lx\n", Status));
}
//
// Figure out what service bits we should be using when announcing ourselves
//
Network->Role |= ROLE_MASTER;
ServiceBits = BrGetBrowserServiceBits(Network);
Status = BrUpdateBrowserStatus(Network, ServiceBits | SV_TYPE_POTENTIAL_BROWSER);
if (Status != NERR_Success) {
dprintf(MASTER, ("Unable to set master announcement bits in browser: %ld\n", 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,
BrInfo.BrPrimaryDomainName,
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) {
InternalError(("Browser: Could not start browser master timer\n"));
}
Network->NumberOfFailedPromotions = 0;
Network->NumberOfPromotionEventsLogged = 0;
Network->MasterAnnouncementIndex = 0;
Status = I_NetServerSetServiceBits(NULL, Network->NetworkName.Buffer, ServiceBits, TRUE);
if (Status == NERR_Success) {
//
// 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);
}
} else {
BrLogEvent(EVENT_BROWSER_STATUS_BITS_UPDATE_FAILED, Status, 0, NULL);
//
// Stop being a master browser.
//
BrStopMaster(Network);
dprintf(MASTER, ("Unable to set master announcement bits to server: %ld\n", Status));
try_return(NOTHING);
}
try_return(NOTHING);
}
try_exit:NOTHING;
} finally {
//
// Make sure there's a become master oustanding.
//
PostBecomeMaster(Network, NULL);
if (NetworkLocked) {
UNLOCK_NETWORK(Network);
}
MIDL_user_free(Context->RequestPacket);
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;
}
//
// Don't worry about this being global. It's only used once during initialization.
WORKER_ITEM BrowserAsyncNamesWorkItem;
VOID
BrGetMasterServerNamesAysnc(
VOID
)
{
//
// 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)
//
BrInitializeWorkItem( &BrowserAsyncNamesWorkItem,
BrGetMasterServerNamesOnAllNets,
NULL );
BrQueueWorkItem( &BrowserAsyncNamesWorkItem );
return;
}
NET_API_STATUS
BrGetMasterServerNameForNet(
IN PNETWORK Network,
IN PVOID Context
)
{
//
// Checkpoint the service controller - this gives us 30 seconds/transport
// before the service controller gets unhappy.
//
(BrGlobalData.Status.dwCheckPoint)++;
(void) BrUpdateStatus();
dprintf(INIT, ("FindMaster for net %ws during startup\n", 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);
}
return NERR_Success;
}
VOID
BrGetMasterServerNamesOnAllNets(
IN PVOID Context
)
{
(VOID) BrEnumerateNetworks(BrGetMasterServerNameForNet, 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;
PWSTR OldBuffer;
dprintf(INIT, ("FindMaster on network %ws\n", Network->NetworkName.Buffer));
//
// This request could cause an election. Make sure that if we win
// the election that we can handle it.
//
PostBecomeMaster( Network, NULL );
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;
//
// Set level to TRUE to indicate that find master should initiate
// a findmaster request.
//
RequestPacket->Level = 1;
RequestPacket->TransportName = Network->NetworkName;
//
// 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) {
dprintf(INIT, ("FindMaster on network %ws failed: %ld\n", Network->NetworkName.Buffer, Status));
MIDL_user_free(RequestPacket);
return(Status);
}
if (!LOCK_NETWORK(Network)) {
MIDL_user_free(RequestPacket);
return NERR_InternalError;
}
OldBuffer = Network->MasterBrowserName.Buffer;
Network->MasterBrowserName.Buffer = MIDL_user_allocate(
(UINT) RequestPacket->Parameters.GetMasterName.MasterNameLength
+sizeof(WCHAR)
);
if (Network->MasterBrowserName.Buffer == NULL) {
Network->MasterBrowserName.Buffer = OldBuffer;
UNLOCK_NETWORK(Network);
MIDL_user_free(RequestPacket);
return(ERROR_NOT_ENOUGH_MEMORY);
}
Network->MasterBrowserName.MaximumLength = (USHORT)RequestPacket->Parameters.GetMasterName.MasterNameLength+sizeof(WCHAR);
Network->MasterBrowserName.Length = (USHORT)RequestPacket->Parameters.GetMasterName.MasterNameLength;
RtlCopyMemory(Network->MasterBrowserName.Buffer, RequestPacket->Parameters.GetMasterName.Name,
Network->MasterBrowserName.MaximumLength);
ASSERT ( NetpIsUncComputerNameValid( Network->MasterBrowserName.Buffer ) );
dprintf(INIT, ("FindMaster on network %ws succeeded. Master: %ws\n", Network->NetworkName.Buffer, Network->MasterBrowserName.Buffer));
UNLOCK_NETWORK(Network);
MIDL_user_free(RequestPacket);
if (OldBuffer != NULL) {
MIDL_user_free(OldBuffer);
}
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;
TransportName = Network->NetworkName.Buffer;
//
// If we're not a master any more, blow away this request.
//
if (!(Network->Role & ROLE_MASTER)) {
return;
}
if (!LOCK_NETWORK(Network)) {
return;
}
NetLocked = TRUE;
try {
//
// 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....
//
if (!BrInfo.IsPrimaryDomainController) {
ASSERT (NetLocked);
UNLOCK_NETWORK(Network);
NetLocked = FALSE;
Status = NetGetDCName(NULL, NULL, (LPBYTE *)&PrimaryDomainController);
//
// If the PDC can be found,
// Exchange server lists with it.
//
if (Status == NERR_Success) {
//
// 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);
}
//
// If we're on the PDC, we need to get the list of servers from
// the WINS server.
//
} else {
//
// Ensure a GetMasterAnnouncement request is posted to the bowser.
//
(VOID) PostGetMasterAnnouncement ( Network, NULL );
//
// 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) {
InternalError(("Browser: Unable to restart browser backup timer: %lx\n", 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) {
InternalError(("Browser: Unable to restart browser backup timer: %lx\n", Status));
try_return(NOTHING);
}
}
}
try_exit:NOTHING;
} finally {
if (NetLocked) {
UNLOCK_NETWORK(Network);
}
if (PrimaryDomainController != NULL) {
NetApiBufferFree(PrimaryDomainController);
}
if (PrimaryWinsServerAddress) {
MIDL_user_free(PrimaryWinsServerAddress);
}
if (SecondaryWinsServerAddress) {
MIDL_user_free(SecondaryWinsServerAddress);
}
if (WinsServerList) {
MIDL_user_free(WinsServerList);
}
}
}
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;
DWORD ServiceBits;
NET_API_STATUS Status;
if (!LOCK_NETWORK(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.
//
ServiceBits = BrGetBrowserServiceBits(Network);
Status = I_NetServerSetServiceBits(NULL, Network->NetworkName.Buffer, ServiceBits, FALSE);
if (Status != NERR_Success) {
BrLogEvent(EVENT_BROWSER_STATUS_BITS_UPDATE_FAILED, Status, 0, NULL);
}
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);
}
NET_API_STATUS
BrStopMaster(
IN PNETWORK Network
)
{
NET_API_STATUS Status;
ULONG ServiceBits;
//
// This guy is shutting down - set his role to 0 and announce.
//
if (!LOCK_NETWORK(Network)) {
return NERR_InternalError;
}
try {
dprintf(MASTER, ("Stopping being master on network %ws\n", 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);
ServiceBits = BrGetBrowserServiceBits(Network);
ASSERT ((ServiceBits & SV_TYPE_MASTER_BROWSER) == 0);
Status = BrUpdateBrowserStatus(Network, ServiceBits | SV_TYPE_POTENTIAL_BROWSER);
if (Status != NERR_Success) {
dprintf(MASTER, ("Unable to clear master announcement bits in browser: %ld\n", Status));
try_return(Status);
}
Status = I_NetServerSetServiceBits(NULL, Network->NetworkName.Buffer, ServiceBits, TRUE);
if (Status != NERR_Success) {
BrLogEvent(EVENT_BROWSER_STATUS_BITS_UPDATE_FAILED, Status, 0, NULL);
dprintf(MASTER, ("Unable to clear master announcement bits to server: %ld\n", 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;
CHAR Buffer[sizeof(MASTER_ANNOUNCEMENT)+CNLEN+1];
PMASTER_ANNOUNCEMENT MasterAnnouncementp = (PMASTER_ANNOUNCEMENT)Buffer;
OEM_STRING OemComputerName;
UNICODE_STRING UnicodeComputerName, ComputerNameU;
RtlInitUnicodeString(&ComputerNameU, BrInfo.BrComputerName);
RtlUpcaseUnicodeString(&UnicodeComputerName, &ComputerNameU, TRUE);
OemComputerName.Buffer = MasterAnnouncementp->MasterAnnouncement.MasterName;
OemComputerName.MaximumLength = CNLEN+1;
RtlUnicodeStringToOemString(&OemComputerName, &UnicodeComputerName, FALSE);
MasterAnnouncementp->Type = MasterAnnouncement;
Status = SendDatagram(BrDgReceiverDeviceHandle, &Network->NetworkName,
ServerName,
ComputerName,
MasterAnnouncementp,
FIELD_OFFSET(MASTER_ANNOUNCEMENT, MasterAnnouncement.MasterName) + OemComputerName.Length+sizeof(CHAR)
);
RtlFreeUnicodeString(&UnicodeComputerName);
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.
--*/
{
LSA_HANDLE LsaHandle;
NET_API_STATUS Status = NERR_Success;
PPOLICY_LSA_SERVER_ROLE_INFO ServerRole;
OBJECT_ATTRIBUTES ObjectAttributes;
if (! RtlAcquireResourceExclusive(&BrInfo.ConfigResource, TRUE)) {
return NERR_InternalError;
}
if (!BrInfo.IsLanmanNt) {
RtlReleaseResource(&BrInfo.ConfigResource);
return(NERR_NotPrimary);
}
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
Status = LsaOpenPolicy(NULL, &ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&LsaHandle);
if (!NT_SUCCESS(Status)) {
RtlReleaseResource(&BrInfo.ConfigResource);
return(BrMapStatus(Status));
}
Status = LsaQueryInformationPolicy(LsaHandle,
PolicyLsaServerRoleInformation,
(PVOID)&ServerRole
);
if (!NT_SUCCESS(Status)) {
LsaClose(LsaHandle);
RtlReleaseResource(&BrInfo.ConfigResource);
return(BrMapStatus(Status));
}
LsaClose(LsaHandle);
if (BrInfo.IsPrimaryDomainController) {
//
// We think we're the primary domain controller. If the
// LSA doesn't think we are the PDC, then update our information.
//
if (ServerRole->LsaServerRole != PolicyServerRolePrimary) {
BrInfo.IsPrimaryDomainController = FALSE;
//
// We're not a domain master any more, since we're not the PDC.
//
BrInfo.IsDomainMasterBrowser = FALSE;
}
} else {
//
// We don't think we're the primary domain controller. If the
// LSA thinks we are the PDC, then update our information.
//
if (ServerRole->LsaServerRole == PolicyServerRolePrimary) {
BrInfo.IsPrimaryDomainController = TRUE;
BrInfo.IsDomainMasterBrowser = TRUE;
//
// Make sure a GetMasterAnnouncement request is pending.
//
Status = BrPostGetMasterAnnouncementInWorker();
}
}
RtlReleaseResource(&BrInfo.ConfigResource);
//
// Update this information for all transports now. This will also update
// the status for the driver.
//
Status = BrUpdateAnnouncementBits(BrGlobalData.StatusHandle);
if (Status == NERR_Success) {
//
// The update worked. Now force an election and let the best server
// win.
//
BrForceElectionOnAllNetworks(EVENT_BROWSER_ELECTION_SENT_ROLE_CHANGED);
}
return Status;
}
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
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 );
UNREFERENCED_PARAMETER( DomainName );
UNREFERENCED_PARAMETER( EmulatedComputerName );
UNREFERENCED_PARAMETER( Role );
}
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.
--*/
{
return ERROR_NOT_SUPPORTED;
}