456 lines
12 KiB
C
456 lines
12 KiB
C
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Copyright (C) 1996, Microsoft Corporation
|
|||
|
//
|
|||
|
// File: wsdfs.c
|
|||
|
//
|
|||
|
// Classes: None
|
|||
|
//
|
|||
|
// Functions: DfsDcName
|
|||
|
//
|
|||
|
// History: Feb 1, 1996 Milans Created
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#include <dfsfsctl.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <windows.h>
|
|||
|
#include <lm.h>
|
|||
|
|
|||
|
#include <dsgetdc.h> // DsGetDcName
|
|||
|
|
|||
|
#include "wsdfs.h"
|
|||
|
#include "dominfo.h"
|
|||
|
#include "wsmain.h"
|
|||
|
|
|||
|
#include "wsutil.h"
|
|||
|
#include <config.h>
|
|||
|
#include <confname.h>
|
|||
|
|
|||
|
//
|
|||
|
// Timeouts for domian change notifications
|
|||
|
//
|
|||
|
#define TIMEOUT_MINUTES(_x) (_x) * 1000 * 60
|
|||
|
#define DOMAIN_NAME_CHANGE_TIMEOUT 1
|
|||
|
#define DOMAIN_NAME_CHANGE_TIMEOUT_LONG 15
|
|||
|
|
|||
|
#define DFS_DC_NAME_DELAY TEXT("DfsDcNameDelay")
|
|||
|
extern
|
|||
|
NET_API_STATUS
|
|||
|
WsSetWorkStationDomainName(
|
|||
|
VOID);
|
|||
|
|
|||
|
DWORD
|
|||
|
DfsGetDelayInterval(void);
|
|||
|
|
|||
|
VOID
|
|||
|
DfsDcName(
|
|||
|
LPVOID pContext,
|
|||
|
BOOLEAN fReason
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsGetDomainNameInfo(void);
|
|||
|
|
|||
|
extern HANDLE hMupEvent;
|
|||
|
extern BOOLEAN MupEventSignaled;
|
|||
|
extern BOOLEAN GotDomainNameInfo;
|
|||
|
extern ULONG DfsDebug;
|
|||
|
|
|||
|
ULONG g_ulCount;
|
|||
|
ULONG g_ulLastCount;
|
|||
|
ULONG g_ulInitThreshold;
|
|||
|
ULONG g_ulForce;
|
|||
|
ULONG g_ulForceThreshold;
|
|||
|
|
|||
|
HANDLE PollDCNameEvent = NULL;
|
|||
|
HANDLE TearDownDoneEvent;
|
|||
|
|
|||
|
HANDLE WsDomainNameChangeEvent = NULL;
|
|||
|
HANDLE g_WsDomainNameChangeWorkItem;
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: WsInitializeDfs
|
|||
|
//
|
|||
|
// Synopsis: Initializes the Dfs thread that waits for calls from the
|
|||
|
// driver to map Domain names into DC lists
|
|||
|
//
|
|||
|
// Arguments: None
|
|||
|
//
|
|||
|
// Returns: WIN32 error from CreateThread
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsInitializeDfs()
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
NET_API_STATUS ApiStatus;
|
|||
|
OBJECT_ATTRIBUTES obja;
|
|||
|
|
|||
|
DWORD dwTimeout = INFINITE;
|
|||
|
HANDLE hEvent;
|
|||
|
|
|||
|
g_ulInitThreshold = 4;
|
|||
|
g_ulForceThreshold = 60;
|
|||
|
g_ulForce = g_ulForceThreshold;
|
|||
|
|
|||
|
// initialize workstation tear down done event
|
|||
|
InitializeObjectAttributes( &obja, NULL, OBJ_OPENIF, NULL, NULL );
|
|||
|
|
|||
|
Status = NtCreateEvent(
|
|||
|
&TearDownDoneEvent,
|
|||
|
SYNCHRONIZE | EVENT_QUERY_STATE | EVENT_MODIFY_STATE,
|
|||
|
&obja,
|
|||
|
SynchronizationEvent,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
if (Status != STATUS_SUCCESS) {
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (hMupEvent == NULL) {
|
|||
|
hMupEvent = CreateMupEvent();
|
|||
|
if (WsInAWorkgroup() == TRUE && MupEventSignaled == FALSE) {
|
|||
|
SetEvent(hMupEvent);
|
|||
|
MupEventSignaled = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Watch for Domain Name changes, and automatically pick them up
|
|||
|
//
|
|||
|
ApiStatus = NetRegisterDomainNameChangeNotification( &WsDomainNameChangeEvent );
|
|||
|
if (ApiStatus != NO_ERROR) {
|
|||
|
WsDomainNameChangeEvent = NULL;
|
|||
|
|
|||
|
InitializeObjectAttributes( &obja, NULL, OBJ_OPENIF, NULL, NULL );
|
|||
|
Status = NtCreateEvent(
|
|||
|
&PollDCNameEvent,
|
|||
|
SYNCHRONIZE | EVENT_QUERY_STATE | EVENT_MODIFY_STATE,
|
|||
|
&obja,
|
|||
|
SynchronizationEvent,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
if (Status != STATUS_SUCCESS) {
|
|||
|
NtClose(TearDownDoneEvent);
|
|||
|
TearDownDoneEvent = NULL;
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we aren't in a workgroup or are in one but
|
|||
|
// don't need to wait for domain name change.
|
|||
|
//
|
|||
|
if (WsInAWorkgroup() != TRUE || WsDomainNameChangeEvent != NULL) {
|
|||
|
|
|||
|
if (WsInAWorkgroup() != TRUE) {
|
|||
|
//
|
|||
|
// If we are not in a workgroup, set the timeout value to poll the DC name.
|
|||
|
//
|
|||
|
dwTimeout = 1;
|
|||
|
}
|
|||
|
|
|||
|
hEvent = WsDomainNameChangeEvent ? WsDomainNameChangeEvent : PollDCNameEvent;
|
|||
|
|
|||
|
Status = RtlRegisterWait(
|
|||
|
&g_WsDomainNameChangeWorkItem,
|
|||
|
hEvent,
|
|||
|
DfsDcName, // callback fcn
|
|||
|
hEvent, // parameter
|
|||
|
dwTimeout, // timeout
|
|||
|
WT_EXECUTEONLYONCE | // flags
|
|||
|
WT_EXECUTEINIOTHREAD |
|
|||
|
WT_EXECUTELONGFUNCTION);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
NtClose(TearDownDoneEvent);
|
|||
|
TearDownDoneEvent = NULL;
|
|||
|
|
|||
|
if (PollDCNameEvent != NULL) {
|
|||
|
NtClose(PollDCNameEvent);
|
|||
|
PollDCNameEvent = NULL;
|
|||
|
}
|
|||
|
|
|||
|
return( RtlNtStatusToDosError(Status) );
|
|||
|
} else {
|
|||
|
return( NERR_Success );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: WsShutdownDfs
|
|||
|
//
|
|||
|
// Synopsis: Stops the thread created by WsInitializeDfs
|
|||
|
//
|
|||
|
// Arguments: None
|
|||
|
//
|
|||
|
// Returns: Nothing
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
WsShutdownDfs()
|
|||
|
{
|
|||
|
DWORD dwReturn, cbRead;
|
|||
|
NTSTATUS Status;
|
|||
|
HANDLE hDfs;
|
|||
|
|
|||
|
Status = DfsOpen( &hDfs, NULL );
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
Status = DfsFsctl(
|
|||
|
hDfs,
|
|||
|
FSCTL_DFS_STOP_DFS,
|
|||
|
NULL,
|
|||
|
0L,
|
|||
|
NULL,
|
|||
|
0L);
|
|||
|
|
|||
|
NtClose( hDfs );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( WsDomainNameChangeEvent ) {
|
|||
|
//
|
|||
|
// Stop waiting for domain name changes
|
|||
|
//
|
|||
|
SetEvent( WsDomainNameChangeEvent );
|
|||
|
WaitForSingleObject(TearDownDoneEvent, INFINITE);
|
|||
|
NetUnregisterDomainNameChangeNotification( WsDomainNameChangeEvent );
|
|||
|
WsDomainNameChangeEvent = NULL;
|
|||
|
} else {
|
|||
|
SetEvent( PollDCNameEvent );
|
|||
|
WaitForSingleObject(TearDownDoneEvent, INFINITE);
|
|||
|
NtClose(PollDCNameEvent);
|
|||
|
PollDCNameEvent = NULL;
|
|||
|
}
|
|||
|
|
|||
|
NtClose(TearDownDoneEvent);
|
|||
|
TearDownDoneEvent = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsDcName
|
|||
|
//
|
|||
|
// Synopsis: Gets a DC name and sends it to the mup(dfs) driver
|
|||
|
//
|
|||
|
// This routine is intended to be called as the entry proc for a
|
|||
|
// thread.
|
|||
|
//
|
|||
|
// Arguments: pContext -- Context data (handle to domain name change event)
|
|||
|
// fReason -- TRUE if the wait timed out
|
|||
|
// FALSE if the event was signalled
|
|||
|
//
|
|||
|
// Returns:
|
|||
|
//
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
DfsDcName(
|
|||
|
LPVOID pContext,
|
|||
|
BOOLEAN fReason
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
HANDLE hDfs;
|
|||
|
DWORD dwTimeout = INFINITE;
|
|||
|
ULONG Flags = 0;
|
|||
|
BOOLEAN needRefresh = FALSE;
|
|||
|
BOOLEAN DcNameFailed;
|
|||
|
Status = RtlDeregisterWait(g_WsDomainNameChangeWorkItem);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
NetpKdPrint(("WKSTA DfsDcName: RtlDeregisterWait FAILED %#x\n", Status));
|
|||
|
}
|
|||
|
|
|||
|
if (WsGlobalData.Status.dwCurrentState == SERVICE_STOP_PENDING
|
|||
|
||
|
|||
|
WsGlobalData.Status.dwCurrentState == SERVICE_STOPPED)
|
|||
|
{
|
|||
|
//
|
|||
|
// The service is shutting down -- stop waiting for a domain name change
|
|||
|
//
|
|||
|
SetEvent(TearDownDoneEvent);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (fReason) {
|
|||
|
|
|||
|
//
|
|||
|
// TRUE == timeout
|
|||
|
//
|
|||
|
|
|||
|
if ((g_ulCount <= g_ulInitThreshold) ||
|
|||
|
(g_ulLastCount >= DfsGetDelayInterval())) {
|
|||
|
g_ulLastCount = 0;
|
|||
|
needRefresh = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (needRefresh) {
|
|||
|
|
|||
|
Status = DfsOpen( &hDfs, NULL );
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
Status = DfsFsctl(
|
|||
|
hDfs,
|
|||
|
FSCTL_DFS_PKT_SET_DC_NAME,
|
|||
|
L"",
|
|||
|
sizeof(WCHAR),
|
|||
|
NULL,
|
|||
|
0L);
|
|||
|
NtClose( hDfs );
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) && GotDomainNameInfo == FALSE) {
|
|||
|
DfsGetDomainNameInfo();
|
|||
|
}
|
|||
|
|
|||
|
if (g_ulCount > g_ulInitThreshold) {
|
|||
|
Flags |= DS_BACKGROUND_ONLY;
|
|||
|
}
|
|||
|
Status = DfsGetDCName(Flags, &DcNameFailed);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status) &&
|
|||
|
DcNameFailed == FALSE &&
|
|||
|
g_ulForce >= g_ulForceThreshold) {
|
|||
|
g_ulForce = 0;
|
|||
|
Flags |= DS_FORCE_REDISCOVERY;
|
|||
|
Status = DfsGetDCName(Flags, &DcNameFailed);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (MupEventSignaled == FALSE) {
|
|||
|
#if DBG
|
|||
|
if (DfsDebug)
|
|||
|
DbgPrint("Signaling mup event\n");
|
|||
|
#endif
|
|||
|
SetEvent(hMupEvent);
|
|||
|
MupEventSignaled = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) || (g_ulCount > g_ulInitThreshold)) {
|
|||
|
dwTimeout = DOMAIN_NAME_CHANGE_TIMEOUT_LONG;
|
|||
|
}
|
|||
|
else {
|
|||
|
dwTimeout = DOMAIN_NAME_CHANGE_TIMEOUT;
|
|||
|
}
|
|||
|
|
|||
|
g_ulCount += dwTimeout;
|
|||
|
g_ulForce += dwTimeout;
|
|||
|
g_ulLastCount += dwTimeout;
|
|||
|
dwTimeout = TIMEOUT_MINUTES(dwTimeout);
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
// set the new WorkStation domain name if the event is triggered by domain
|
|||
|
// name change event.
|
|||
|
NetpKdPrint(("WKSTA DfsDcName set WorkStation Domain Name\n"));
|
|||
|
WsSetWorkStationDomainName();
|
|||
|
|
|||
|
// timeout needs to be adjusted accordingly if change occurs between workgroup
|
|||
|
// and domain so that DC name is also updated on the DFS.
|
|||
|
if (WsInAWorkgroup() != TRUE) {
|
|||
|
dwTimeout = TIMEOUT_MINUTES(DOMAIN_NAME_CHANGE_TIMEOUT);
|
|||
|
} else {
|
|||
|
dwTimeout = INFINITE;
|
|||
|
|
|||
|
// DFS needs to take care of the transition from domain to workgroup.
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reregister the wait on the domain name change event
|
|||
|
//
|
|||
|
Status = RtlRegisterWait(
|
|||
|
&g_WsDomainNameChangeWorkItem,
|
|||
|
(HANDLE)pContext, // waitable handle
|
|||
|
DfsDcName, // callback fcn
|
|||
|
pContext, // parameter
|
|||
|
dwTimeout, // timeout
|
|||
|
WT_EXECUTEONLYONCE | // flags
|
|||
|
WT_EXECUTEINIOTHREAD |
|
|||
|
WT_EXECUTELONGFUNCTION);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#define DFS_DC_NAME_DELAY_POLICY_KEY TEXT("Software\\Policies\\Microsoft\\System\\DFSClient\\DfsDcNameDelay")
|
|||
|
|
|||
|
DWORD
|
|||
|
DfsGetDelayInterval(void)
|
|||
|
{
|
|||
|
NET_API_STATUS ApiStatus;
|
|||
|
LPNET_CONFIG_HANDLE SectionHandle = NULL;
|
|||
|
DWORD Value=0;
|
|||
|
HKEY hKey;
|
|||
|
LONG lResult=0;
|
|||
|
DWORD dwValue=0, dwSize = sizeof(dwValue);
|
|||
|
LPTSTR lpValueName = NULL;
|
|||
|
DWORD dwType = 0;
|
|||
|
|
|||
|
// First, check for a policy
|
|||
|
lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, DFS_DC_NAME_DELAY_POLICY_KEY, 0,
|
|||
|
KEY_READ, &hKey);
|
|||
|
if (lResult == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
lResult = RegQueryValueEx (hKey, lpValueName, 0, &dwType,
|
|||
|
(LPBYTE) &dwValue, &dwSize);
|
|||
|
RegCloseKey (hKey);
|
|||
|
}
|
|||
|
|
|||
|
// Exit now if a policy value was found
|
|||
|
if (lResult == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
return dwValue;
|
|||
|
}
|
|||
|
|
|||
|
// Second, check for a preference
|
|||
|
|
|||
|
//
|
|||
|
// Open section of config data.
|
|||
|
//
|
|||
|
ApiStatus = NetpOpenConfigData(
|
|||
|
&SectionHandle,
|
|||
|
NULL, // Local server.
|
|||
|
SECT_NT_WKSTA, // Section name.
|
|||
|
FALSE // Don't want read-only access.
|
|||
|
);
|
|||
|
|
|||
|
if (ApiStatus != NERR_Success) {
|
|||
|
return DOMAIN_NAME_CHANGE_TIMEOUT_LONG;
|
|||
|
}
|
|||
|
|
|||
|
ApiStatus = NetpGetConfigDword(
|
|||
|
SectionHandle,
|
|||
|
DFS_DC_NAME_DELAY,
|
|||
|
0,
|
|||
|
&Value
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
NetpCloseConfigData( SectionHandle );
|
|||
|
|
|||
|
if (ApiStatus != NERR_Success) {
|
|||
|
return DOMAIN_NAME_CHANGE_TIMEOUT_LONG;
|
|||
|
}
|
|||
|
|
|||
|
if (Value < DOMAIN_NAME_CHANGE_TIMEOUT_LONG) {
|
|||
|
Value = DOMAIN_NAME_CHANGE_TIMEOUT_LONG;
|
|||
|
}
|
|||
|
|
|||
|
return Value;
|
|||
|
}
|