summaryrefslogtreecommitdiffstats
path: root/private/net/svcdlls/browser2/server/brdomain.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/net/svcdlls/browser2/server/brdomain.c')
-rw-r--r--private/net/svcdlls/browser2/server/brdomain.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/private/net/svcdlls/browser2/server/brdomain.c b/private/net/svcdlls/browser2/server/brdomain.c
new file mode 100644
index 000000000..185b290fd
--- /dev/null
+++ b/private/net/svcdlls/browser2/server/brdomain.c
@@ -0,0 +1,790 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ brdomain.c
+
+Abstract:
+
+ Code to manage primary and emulated networks.
+
+Author:
+
+ Cliff Van Dyke (CliffV) 11-Jan-1995
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Module specific globals
+//
+
+// Serialized by NetworkCritSect
+LIST_ENTRY ServicedDomains = {0};
+
+//
+// Local procedure forwards.
+//
+
+NET_API_STATUS
+BrCreateDomain(
+ LPWSTR DomainName,
+ LPWSTR ComputerName,
+ BOOLEAN IsEmulatedDomain,
+ BOOLEAN IsPrimaryDomainController
+ );
+
+VOID
+BrCreateDomainWorker(
+ IN PVOID Ctx
+ );
+
+
+
+NET_API_STATUS
+BrInitializeDomains(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize brdomain.c and create the primary domain.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Status of operation.
+
+--*/
+{
+ NET_API_STATUS NetStatus;
+ LPWSTR ComputerName = NULL;
+ LPWSTR DomainName = NULL;
+
+ //
+ // Initialize globals
+ //
+
+ InitializeListHead(&ServicedDomains);
+
+ //
+ // Initialize actual domain of this machine.
+ //
+ // Get the configured computer name. NetpGetComputerName allocates
+ // the memory to hold the computername string using LocalAlloc.
+ //
+
+ NetStatus = NetpGetComputerName( &ComputerName );
+
+ if ( NetStatus != NERR_Success ) {
+ goto Cleanup;
+ }
+
+ NetStatus = NetpGetDomainName( &DomainName );
+
+ if ( NetStatus != NERR_Success ) {
+ goto Cleanup;
+ }
+
+ NetStatus = BrCreateDomain( DomainName,
+ ComputerName,
+ FALSE,
+ (BOOLEAN) BrInfo.IsPrimaryDomainController );
+
+ if ( NetStatus != NERR_Success ) {
+ goto Cleanup;
+ }
+
+
+ NetStatus = NERR_Success;
+
+ //
+ // Free locally used resources
+ //
+Cleanup:
+ if ( ComputerName != NULL ) {
+ (VOID)LocalFree( ComputerName );
+ }
+ if ( DomainName != NULL ) {
+ (VOID)LocalFree( DomainName );
+ }
+
+ return NetStatus;
+}
+
+
+NET_API_STATUS
+BrCreateDomain(
+ LPWSTR DomainName,
+ LPWSTR ComputerName,
+ BOOLEAN IsEmulatedDomain,
+ BOOLEAN IsPrimaryDomainController
+ )
+
+/*++
+
+Routine Description:
+
+ Create a new domain to browse on.
+
+Arguments:
+
+ DomainName - Name of the domain to browse on
+
+ ComputerName - Name of this computer in the specified domain.
+
+ IsEmulatedDomain - TRUE iff this domain is an emulated domain of this machine.
+
+ IsPrimaryDomainControler - TRUE iff this machine is the PDC of this domain.
+
+Return Value:
+
+ Status of operation.
+
+--*/
+{
+ NTSTATUS Status;
+ NET_API_STATUS NetStatus;
+
+ BOOLEAN CanCallBrDeleteDomain = FALSE;
+
+ PDOMAIN_INFO DomainInfo = NULL;
+ ULONG AComputerNameLength;
+
+ BrPrint(( BR_DOMAIN, "%ws: Added new domain and computer: %ws\n",
+ DomainName,
+ ComputerName ));
+
+ //
+ // Allocate a structure describing the new domain.
+ //
+
+ DomainInfo = LocalAlloc( LMEM_ZEROINIT, sizeof(DOMAIN_INFO) );
+
+ if ( DomainInfo == NULL ) {
+ NetStatus = GetLastError();
+ goto Cleanup;
+ }
+
+ //
+ // Create an interim reference count for this domain.
+ //
+
+ DomainInfo->ReferenceCount = 1;
+
+ DomainInfo->IsEmulatedDomain = IsEmulatedDomain;
+ DomainInfo->IsPrimaryDomainController = IsPrimaryDomainController;
+
+
+ //
+ // Copy the computer name into the structure.
+ //
+
+ NetStatus = I_NetNameCanonicalize(
+ NULL,
+ ComputerName,
+ DomainInfo->DomUnicodeComputerName,
+ sizeof(DomainInfo->DomUnicodeComputerName),
+ NAMETYPE_COMPUTER,
+ 0 );
+
+
+ if ( NetStatus != NERR_Success ) {
+ BrPrint(( BR_CRITICAL,
+ "ComputerName " FORMAT_LPWSTR " is invalid\n",
+ ComputerName ));
+ goto Cleanup;
+ }
+
+ DomainInfo->DomUnicodeComputerNameLength = wcslen(DomainInfo->DomUnicodeComputerName);
+
+ Status = RtlUpcaseUnicodeToOemN( DomainInfo->DomOemComputerName,
+ sizeof(DomainInfo->DomOemComputerName),
+ &DomainInfo->DomOemComputerNameLength,
+ DomainInfo->DomUnicodeComputerName,
+ DomainInfo->DomUnicodeComputerNameLength*sizeof(WCHAR));
+
+ if (!NT_SUCCESS(Status)) {
+ BrPrint(( BR_CRITICAL, "Unable to convert computer name to OEM %ws %lx\n", ComputerName, Status ));
+ NetStatus = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ DomainInfo->DomOemComputerName[DomainInfo->DomOemComputerNameLength] = '\0';
+
+
+ //
+ // Copy the domain name into the structure
+ //
+
+ NetStatus = I_NetNameCanonicalize(
+ NULL,
+ DomainName,
+ DomainInfo->DomUnicodeDomainName,
+ sizeof(DomainInfo->DomUnicodeDomainName),
+ NAMETYPE_DOMAIN,
+ 0 );
+
+
+ if ( NetStatus != NERR_Success ) {
+ BrPrint(( BR_CRITICAL, "%ws: DomainName is invalid\n", DomainName ));
+ goto Cleanup;
+ }
+
+ RtlInitUnicodeString( &DomainInfo->DomUnicodeDomainNameString,
+ DomainInfo->DomUnicodeDomainName );
+
+ Status = RtlUpcaseUnicodeToOemN( DomainInfo->DomOemDomainName,
+ sizeof(DomainInfo->DomOemDomainName),
+ &DomainInfo->DomOemDomainNameLength,
+ DomainInfo->DomUnicodeDomainNameString.Buffer,
+ DomainInfo->DomUnicodeDomainNameString.Length);
+
+ if (!NT_SUCCESS(Status)) {
+ BrPrint(( BR_CRITICAL, "%ws: Unable to convert Domain name to OEM\n", DomainName ));
+ NetStatus = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ DomainInfo->DomOemDomainName[DomainInfo->DomOemDomainNameLength] = '\0';
+
+ //
+ // Link the domain into the list of domains
+ // (And mark that any future cleanup can be done by calling BrDeleteDomain)
+
+ EnterCriticalSection(&NetworkCritSect);
+ InsertTailList(&ServicedDomains, &DomainInfo->Next);
+ LeaveCriticalSection(&NetworkCritSect);
+ CanCallBrDeleteDomain = TRUE;
+
+ //
+ // Create the various networks for this domain.
+ //
+
+ NetStatus = BrCreateNetworks( DomainInfo );
+
+ if ( NetStatus != NERR_Success ) {
+ goto Cleanup;
+ }
+ //
+ // If we're the PDC, then we're also the domain master.
+ //
+
+ if (DomainInfo->IsPrimaryDomainController) {
+ DomainInfo->IsDomainMasterBrowser = TRUE;
+ }
+
+
+ //
+ // If this machine is running as domain master browser server, post an
+ // FsControl to retreive master browser announcements.
+ //
+
+ if (DomainInfo->IsDomainMasterBrowser) {
+ NetStatus = BrPostGetMasterAnnouncement( DomainInfo );
+
+ BrPrint(( BR_INIT, "%ws: MasterAnnouncement posted.\n", DomainName));
+
+ if (NetStatus != NERR_Success) {
+ goto Cleanup;
+ }
+
+ }
+
+ //
+ // If we are on either a domain master, or on a lanman/NT machine,
+ // force an election on all our transports to make sure that we're
+ // the master
+ //
+
+ if (DomainInfo->IsDomainMasterBrowser || BrInfo.IsLanmanNt) {
+
+ BrForceElectionOnAllNetworks( DomainInfo, EVENT_BROWSER_ELECTION_SENT_LANMAN_NT_STARTED);
+
+ BrPrint(( BR_INIT, "%ws: Election forced on startup.\n", DomainName));
+
+ }
+
+ //
+ // This machine's browser has MaintainServerList set to either 0 or 1.
+ //
+
+ //
+ // If MaintainServerList = Auto,
+ // then asynchronously get the master server name for each network
+ // to ensure someone is the master.
+ //
+ // Ignore failures since this is just priming the domain.
+ //
+
+ EnterCriticalSection(&BrInfo.ConfigCritSect);
+ if (BrInfo.MaintainServerList == 0) {
+
+ BrGetMasterServerNamesAysnc( DomainInfo );
+
+ BrPrint(( BR_INIT, "%ws: FindMaster for all nets completed.\n", DomainName ));
+
+ //
+ // if we're a Lan Manager/NT machine, then we need to always be a backup
+ // browser.
+ //
+
+ //
+ // MaintainServerList == 1 means Yes
+ //
+
+ } else if (BrInfo.MaintainServerList == 1){
+
+ //
+ // Become a backup server now.
+ //
+
+ Status = BrBecomeBackup( DomainInfo );
+
+ if (Status != NERR_Success) {
+ goto Cleanup;
+ }
+
+ BrPrint(( BR_INIT, "%ws: BecomeBackup on all nets completed.\n", DomainName ));
+ }
+ LeaveCriticalSection(&BrInfo.ConfigCritSect);
+
+ Status = NERR_Success;
+
+
+ //
+ // Free Locally used resources
+ //
+Cleanup:
+
+ if (NetStatus != NERR_Success) {
+
+ if (DomainInfo != NULL) {
+
+ //
+ // If we've initialized to the point where we can call
+ // we can call BrDeleteDomain, do so.
+ //
+
+ if ( CanCallBrDeleteDomain ) {
+ (VOID) BrDeleteDomain( DomainInfo );
+
+ //
+ // Otherwise, just delete what we've created.
+ //
+ } else {
+
+ (VOID) LocalFree(DomainInfo);
+ }
+
+ }
+
+ }
+
+ return NetStatus;
+}
+
+typedef struct _BROWSER_CREATE_DOMAIN_CONTEXT {
+ LPWSTR DomainName;
+ LPWSTR ComputerName;
+ BOOLEAN IsEmulatedDomain;
+ BOOLEAN IsPrimaryDomainController;
+ HANDLE EventHandle;
+ NET_API_STATUS NetStatus;
+} BROWSER_CREATE_DOMAIN_CONTEXT, *PBROWSER_CREATE_DOMAIN_CONTEXT;
+
+NET_API_STATUS
+BrCreateDomainInWorker(
+ LPWSTR DomainName,
+ LPWSTR ComputerName,
+ BOOLEAN IsEmulatedDomain,
+ BOOLEAN IsPrimaryDomainController
+ )
+
+/*++
+
+Routine Description:
+
+ Wrapper for BrCreateDomain. Since BrCreateDomain starts several pending
+ IO's to the browser driver, the thread that calls BrCreateDomain must
+ remain around forever. This wrapper can be called by any transient thread
+ (e.g., an RPC thread). It simply causes BrCreateDomain to be called in a
+ worker thread.
+
+Arguments:
+
+ DomainName - Name of the domain to browse on
+
+ ComputerName - Name of this computer in the specified domain.
+
+ IsEmulatedDomain - TRUE iff this domain is an emulated domain of this machine.
+
+ IsPrimaryDomainControler - TRUE iff this machine is the PDC of this domain.
+
+Return Value:
+
+ Status of operation.
+
+--*/
+{
+ NET_API_STATUS NetStatus;
+ DWORD WaitStatus;
+
+ WORKER_ITEM WorkItem;
+ BROWSER_CREATE_DOMAIN_CONTEXT Context;
+
+ //
+ // Copy our arguments into a context block for the worker thread
+ //
+
+ Context.DomainName = DomainName;
+ Context.ComputerName = ComputerName;
+ Context.IsEmulatedDomain = IsEmulatedDomain;
+ Context.IsPrimaryDomainController = IsPrimaryDomainController;
+
+ //
+ // Create an event which we use to wait on the worker thread.
+ //
+
+ Context.EventHandle = CreateEvent(
+ NULL, // Event attributes
+ TRUE, // Event must be manually reset
+ FALSE, // Initial state not signalled
+ NULL ); // Event name
+
+ if ( Context.EventHandle == NULL ) {
+ NetStatus = GetLastError();
+ return NetStatus;
+ }
+
+ //
+ // Queue the request to the worker thread.
+ //
+
+ BrInitializeWorkItem( &WorkItem,
+ BrCreateDomainWorker,
+ &Context );
+
+ BrQueueWorkItem( &WorkItem );
+
+ //
+ // Wait for the worker thread to finish
+ //
+
+ WaitStatus = WaitForSingleObject( Context.EventHandle, INFINITE );
+
+ if ( WaitStatus == WAIT_OBJECT_0 ) {
+ NetStatus = Context.NetStatus;
+ } else {
+ NetStatus = GetLastError();
+ }
+
+ CloseHandle( Context.EventHandle );
+
+ return NetStatus;
+}
+
+ VOID
+BrCreateDomainWorker(
+ IN PVOID Ctx
+ )
+/*++
+
+Routine Description:
+
+ Worker routine for BrCreateDomainInWorker.
+
+ This routine executes in the context of a worker thread.
+
+Arguments:
+
+ Context - Context containing the workitem and the description of the
+ domain to create.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PBROWSER_CREATE_DOMAIN_CONTEXT Context = (PBROWSER_CREATE_DOMAIN_CONTEXT) Ctx;
+
+ //
+ // Create the domain.
+ //
+
+ Context->NetStatus = BrCreateDomain(
+ Context->DomainName,
+ Context->ComputerName,
+ Context->IsEmulatedDomain,
+ Context->IsPrimaryDomainController );
+
+ //
+ // Let the caller know we're done.
+ //
+ SetEvent( Context->EventHandle );
+
+}
+
+PDOMAIN_INFO
+BrFindDomain(
+ LPWSTR DomainName,
+ BOOLEAN DefaultToPrimary
+ )
+/*++
+
+Routine Description:
+
+ This routine will look up a domain given a name.
+
+Arguments:
+
+ DomainName - The name of the domain to look up.
+
+ DefaultToPrimary - Return the primary domain if DomainName is NULL or
+ can't be found.
+
+Return Value:
+
+ NULL - No such domain exists
+
+ A pointer to the domain found. The found domain should be dereferenced
+ using BrDereferenceDomain.
+
+--*/
+{
+ NTSTATUS Status;
+ PLIST_ENTRY DomainEntry;
+
+ PDOMAIN_INFO DomainInfo = NULL;
+
+ CHAR OemDomainName[DNLEN+1];
+ DWORD OemDomainNameLength;
+
+ EnterCriticalSection(&NetworkCritSect);
+
+
+ //
+ // If domain was specified,
+ // try to return primary domain.
+ //
+
+ if ( DomainName != NULL ) {
+
+
+
+ //
+ // Convert the domain name to OEM for faster comparison
+ //
+ Status = RtlUpcaseUnicodeToOemN( OemDomainName,
+ sizeof(OemDomainName),
+ &OemDomainNameLength,
+ DomainName,
+ wcslen(DomainName)*sizeof(WCHAR));
+
+ if (!NT_SUCCESS(Status)) {
+ BrPrint(( BR_CRITICAL, "%ws: Unable to convert Domain name to OEM\n", DomainName ));
+ DomainInfo = NULL;
+ goto Cleanup;
+ }
+
+
+ //
+ // Loop trying to find this domain name.
+ //
+
+ for (DomainEntry = ServicedDomains.Flink ;
+ DomainEntry != &ServicedDomains;
+ DomainEntry = DomainEntry->Flink ) {
+
+ DomainInfo = CONTAINING_RECORD(DomainEntry, DOMAIN_INFO, Next);
+
+ if ( DomainInfo->DomOemDomainNameLength == OemDomainNameLength &&
+ RtlCompareMemory( DomainInfo->DomOemDomainName,
+ OemDomainName,
+ OemDomainNameLength ) == OemDomainNameLength ) {
+ break;
+ }
+
+ DomainInfo = NULL;
+
+ }
+ }
+
+ //
+ // If we're to default to the primary domain,
+ // do so.
+ //
+
+ if ( DefaultToPrimary && DomainInfo == NULL ) {
+ if ( !IsListEmpty( &ServicedDomains ) ) {
+ DomainInfo = CONTAINING_RECORD(ServicedDomains.Flink, DOMAIN_INFO, Next);
+ }
+ }
+
+ //
+ // Reference the domain.
+ //
+
+ if ( DomainInfo != NULL ) {
+ DomainInfo->ReferenceCount ++;
+ }
+
+Cleanup:
+ LeaveCriticalSection(&NetworkCritSect);
+
+ return DomainInfo;
+}
+
+
+VOID
+BrDereferenceDomain(
+ IN PDOMAIN_INFO DomainInfo
+ )
+/*++
+
+Routine Description:
+
+ Decrement the reference count on a domain.
+
+ If the reference count goes to 0, remove the domain.
+
+ On entry, the global NetworkCritSect may not be locked
+
+Arguments:
+
+ DomainInfo - The domain to dereference
+
+Return Value:
+
+ None
+
+--*/
+{
+ NTSTATUS Status;
+ ULONG ReferenceCount;
+
+ //
+ // Decrement the reference count
+ //
+
+ EnterCriticalSection(&NetworkCritSect);
+ ReferenceCount = -- DomainInfo->ReferenceCount;
+ LeaveCriticalSection(&NetworkCritSect);
+
+ if ( ReferenceCount != 0 ) {
+ return;
+ }
+
+
+
+ //
+ // Free the Domain Info structure.
+ //
+ (VOID) LocalFree( DomainInfo );
+
+}
+
+VOID
+BrDeleteDomain(
+ IN PDOMAIN_INFO DomainInfo
+ )
+/*++
+
+Routine Description:
+
+ Force a domain to be deleted.
+
+Arguments:
+
+ DomainInfo - The domain to delete
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Delete each of the networks for this domain.
+ //
+
+ BrEnumerateNetworksForDomain(DomainInfo, BrDeleteNetwork, NULL );
+
+ //
+ // Delink the domain from the global list and remove the final reference.
+ //
+
+ EnterCriticalSection(&NetworkCritSect);
+ RemoveEntryList(&DomainInfo->Next);
+ LeaveCriticalSection(&NetworkCritSect);
+
+ BrDereferenceDomain( DomainInfo );
+
+}
+
+VOID
+BrUninitializeDomains(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Delete all of the domains.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Loop through the domains deleting each of them
+ //
+
+ EnterCriticalSection(&NetworkCritSect);
+
+ while (!IsListEmpty(&ServicedDomains)) {
+
+ PDOMAIN_INFO DomainInfo = CONTAINING_RECORD(ServicedDomains.Flink, DOMAIN_INFO, Next);
+
+ DomainInfo->ReferenceCount ++;
+
+ LeaveCriticalSection(&NetworkCritSect);
+
+ //
+ // Clean up the domain.
+ //
+
+ BrDeleteDomain( DomainInfo );
+
+ //
+ // Actually delete the delinked structure by removing the last reference
+ //
+
+ ASSERT( DomainInfo->ReferenceCount == 1 );
+ BrDereferenceDomain( DomainInfo );
+
+
+ EnterCriticalSection(&NetworkCritSect);
+
+ }
+ LeaveCriticalSection(&NetworkCritSect);
+
+}