Leaked source code of windows server 2003
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.

454 lines
12 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1996, Microsoft Corporation
  4. //
  5. // File: wsdfs.c
  6. //
  7. // Classes: None
  8. //
  9. // Functions: DfsDcName
  10. //
  11. // History: Feb 1, 1996 Milans Created
  12. //
  13. //-----------------------------------------------------------------------------
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <dfsfsctl.h>
  18. #include <stdlib.h>
  19. #include <windows.h>
  20. #include <lm.h>
  21. #include <dsgetdc.h> // DsGetDcName
  22. #include "wsdfs.h"
  23. #include "dominfo.h"
  24. #include "wsmain.h"
  25. #include "wsutil.h"
  26. #include <config.h>
  27. #include <confname.h>
  28. //
  29. // Timeouts for domian change notifications
  30. //
  31. #define TIMEOUT_MINUTES(_x) (_x) * 1000 * 60
  32. #define DOMAIN_NAME_CHANGE_TIMEOUT 1
  33. #define DOMAIN_NAME_CHANGE_TIMEOUT_LONG 15
  34. #define DFS_DC_NAME_DELAY TEXT("DfsDcNameDelay")
  35. extern
  36. NET_API_STATUS
  37. WsSetWorkStationDomainName(
  38. VOID);
  39. DWORD
  40. DfsGetDelayInterval(void);
  41. VOID
  42. DfsDcName(
  43. LPVOID pContext,
  44. BOOLEAN fReason
  45. );
  46. NTSTATUS
  47. DfsGetDomainNameInfo(void);
  48. extern HANDLE hMupEvent;
  49. extern BOOLEAN MupEventSignaled;
  50. extern BOOLEAN GotDomainNameInfo;
  51. extern ULONG DfsDebug;
  52. ULONG g_ulCount;
  53. ULONG g_ulLastCount;
  54. ULONG g_ulInitThreshold;
  55. ULONG g_ulForce;
  56. ULONG g_ulForceThreshold;
  57. HANDLE PollDCNameEvent = NULL;
  58. HANDLE TearDownDoneEvent;
  59. HANDLE WsDomainNameChangeEvent = NULL;
  60. HANDLE g_WsDomainNameChangeWorkItem;
  61. //+----------------------------------------------------------------------------
  62. //
  63. // Function: WsInitializeDfs
  64. //
  65. // Synopsis: Initializes the Dfs thread that waits for calls from the
  66. // driver to map Domain names into DC lists
  67. //
  68. // Arguments: None
  69. //
  70. // Returns: WIN32 error from CreateThread
  71. //
  72. //-----------------------------------------------------------------------------
  73. NET_API_STATUS
  74. WsInitializeDfs()
  75. {
  76. NTSTATUS Status = STATUS_SUCCESS;
  77. NET_API_STATUS ApiStatus;
  78. OBJECT_ATTRIBUTES obja;
  79. DWORD dwTimeout = INFINITE;
  80. HANDLE hEvent;
  81. g_ulInitThreshold = 4;
  82. g_ulForceThreshold = 60;
  83. g_ulForce = g_ulForceThreshold;
  84. // initialize workstation tear down done event
  85. InitializeObjectAttributes( &obja, NULL, OBJ_OPENIF, NULL, NULL );
  86. Status = NtCreateEvent(
  87. &TearDownDoneEvent,
  88. SYNCHRONIZE | EVENT_QUERY_STATE | EVENT_MODIFY_STATE,
  89. &obja,
  90. SynchronizationEvent,
  91. FALSE
  92. );
  93. if (Status != STATUS_SUCCESS) {
  94. return Status;
  95. }
  96. if (hMupEvent == NULL) {
  97. hMupEvent = CreateMupEvent();
  98. if (WsInAWorkgroup() == TRUE && MupEventSignaled == FALSE) {
  99. SetEvent(hMupEvent);
  100. MupEventSignaled = TRUE;
  101. }
  102. }
  103. //
  104. // Watch for Domain Name changes, and automatically pick them up
  105. //
  106. ApiStatus = NetRegisterDomainNameChangeNotification( &WsDomainNameChangeEvent );
  107. if (ApiStatus != NO_ERROR) {
  108. WsDomainNameChangeEvent = NULL;
  109. InitializeObjectAttributes( &obja, NULL, OBJ_OPENIF, NULL, NULL );
  110. Status = NtCreateEvent(
  111. &PollDCNameEvent,
  112. SYNCHRONIZE | EVENT_QUERY_STATE | EVENT_MODIFY_STATE,
  113. &obja,
  114. SynchronizationEvent,
  115. FALSE
  116. );
  117. if (Status != STATUS_SUCCESS) {
  118. NtClose(TearDownDoneEvent);
  119. TearDownDoneEvent = NULL;
  120. return Status;
  121. }
  122. }
  123. //
  124. // If we aren't in a workgroup or are in one but
  125. // don't need to wait for domain name change.
  126. //
  127. if (WsInAWorkgroup() != TRUE || WsDomainNameChangeEvent != NULL) {
  128. if (WsInAWorkgroup() != TRUE) {
  129. //
  130. // If we are not in a workgroup, set the timeout value to poll the DC name.
  131. //
  132. dwTimeout = 1;
  133. }
  134. hEvent = WsDomainNameChangeEvent ? WsDomainNameChangeEvent : PollDCNameEvent;
  135. Status = RtlRegisterWait(
  136. &g_WsDomainNameChangeWorkItem,
  137. hEvent,
  138. DfsDcName, // callback fcn
  139. hEvent, // parameter
  140. dwTimeout, // timeout
  141. WT_EXECUTEONLYONCE | // flags
  142. WT_EXECUTEDEFAULT |
  143. WT_EXECUTELONGFUNCTION);
  144. }
  145. if (!NT_SUCCESS(Status)) {
  146. NtClose(TearDownDoneEvent);
  147. TearDownDoneEvent = NULL;
  148. if (PollDCNameEvent != NULL) {
  149. NtClose(PollDCNameEvent);
  150. PollDCNameEvent = NULL;
  151. }
  152. return( RtlNtStatusToDosError(Status) );
  153. } else {
  154. return( NERR_Success );
  155. }
  156. }
  157. //+----------------------------------------------------------------------------
  158. //
  159. // Function: WsShutdownDfs
  160. //
  161. // Synopsis: Stops the thread created by WsInitializeDfs
  162. //
  163. // Arguments: None
  164. //
  165. // Returns: Nothing
  166. //
  167. //-----------------------------------------------------------------------------
  168. VOID
  169. WsShutdownDfs()
  170. {
  171. DWORD dwReturn, cbRead;
  172. NTSTATUS Status;
  173. HANDLE hDfs;
  174. Status = DfsOpen( &hDfs, NULL );
  175. if (NT_SUCCESS(Status)) {
  176. Status = DfsFsctl(
  177. hDfs,
  178. FSCTL_DFS_STOP_DFS,
  179. NULL,
  180. 0L,
  181. NULL,
  182. 0L);
  183. NtClose( hDfs );
  184. }
  185. if( WsDomainNameChangeEvent ) {
  186. //
  187. // Stop waiting for domain name changes
  188. //
  189. SetEvent( WsDomainNameChangeEvent );
  190. WaitForSingleObject(TearDownDoneEvent, INFINITE);
  191. NetUnregisterDomainNameChangeNotification( WsDomainNameChangeEvent );
  192. WsDomainNameChangeEvent = NULL;
  193. } else {
  194. SetEvent( PollDCNameEvent );
  195. WaitForSingleObject(TearDownDoneEvent, INFINITE);
  196. NtClose(PollDCNameEvent);
  197. PollDCNameEvent = NULL;
  198. }
  199. NtClose(TearDownDoneEvent);
  200. TearDownDoneEvent = NULL;
  201. }
  202. //+----------------------------------------------------------------------------
  203. //
  204. // Function: DfsDcName
  205. //
  206. // Synopsis: Gets a DC name and sends it to the mup(dfs) driver
  207. //
  208. // This routine is intended to be called as the entry proc for a
  209. // thread.
  210. //
  211. // Arguments: pContext -- Context data (handle to domain name change event)
  212. // fReason -- TRUE if the wait timed out
  213. // FALSE if the event was signalled
  214. //
  215. // Returns:
  216. //
  217. //-----------------------------------------------------------------------------
  218. VOID
  219. DfsDcName(
  220. LPVOID pContext,
  221. BOOLEAN fReason
  222. )
  223. {
  224. NTSTATUS Status;
  225. HANDLE hDfs;
  226. DWORD dwTimeout = INFINITE;
  227. ULONG Flags = 0;
  228. BOOLEAN needRefresh = FALSE;
  229. BOOLEAN DcNameFailed;
  230. Status = RtlDeregisterWait(g_WsDomainNameChangeWorkItem);
  231. if (!NT_SUCCESS(Status)) {
  232. NetpKdPrint(("WKSTA DfsDcName: RtlDeregisterWait FAILED %#x\n", Status));
  233. }
  234. if (WsGlobalData.Status.dwCurrentState == SERVICE_STOP_PENDING
  235. ||
  236. WsGlobalData.Status.dwCurrentState == SERVICE_STOPPED)
  237. {
  238. //
  239. // The service is shutting down -- stop waiting for a domain name change
  240. //
  241. SetEvent(TearDownDoneEvent);
  242. return;
  243. }
  244. if (fReason) {
  245. //
  246. // TRUE == timeout
  247. //
  248. if ((g_ulCount <= g_ulInitThreshold) ||
  249. (g_ulLastCount >= DfsGetDelayInterval())) {
  250. g_ulLastCount = 0;
  251. needRefresh = TRUE;
  252. }
  253. if (needRefresh) {
  254. Status = DfsOpen( &hDfs, NULL );
  255. if (NT_SUCCESS(Status)) {
  256. Status = DfsFsctl(
  257. hDfs,
  258. FSCTL_DFS_PKT_SET_DC_NAME,
  259. L"",
  260. sizeof(WCHAR),
  261. NULL,
  262. 0L);
  263. NtClose( hDfs );
  264. }
  265. if (NT_SUCCESS(Status) && GotDomainNameInfo == FALSE) {
  266. DfsGetDomainNameInfo();
  267. }
  268. if (g_ulCount > g_ulInitThreshold) {
  269. Flags |= DS_BACKGROUND_ONLY;
  270. }
  271. Status = DfsGetDCName(Flags, &DcNameFailed);
  272. if (!NT_SUCCESS(Status) &&
  273. DcNameFailed == FALSE &&
  274. g_ulForce >= g_ulForceThreshold) {
  275. g_ulForce = 0;
  276. Flags |= DS_FORCE_REDISCOVERY;
  277. Status = DfsGetDCName(Flags, &DcNameFailed);
  278. }
  279. }
  280. if (MupEventSignaled == FALSE) {
  281. #if DBG
  282. if (DfsDebug)
  283. DbgPrint("Signaling mup event\n");
  284. #endif
  285. SetEvent(hMupEvent);
  286. MupEventSignaled = TRUE;
  287. }
  288. if (NT_SUCCESS(Status) || (g_ulCount > g_ulInitThreshold)) {
  289. dwTimeout = DOMAIN_NAME_CHANGE_TIMEOUT_LONG;
  290. }
  291. else {
  292. dwTimeout = DOMAIN_NAME_CHANGE_TIMEOUT;
  293. }
  294. g_ulCount += dwTimeout;
  295. g_ulForce += dwTimeout;
  296. g_ulLastCount += dwTimeout;
  297. dwTimeout = TIMEOUT_MINUTES(dwTimeout);
  298. }
  299. else {
  300. // set the new WorkStation domain name if the event is triggered by domain
  301. // name change event.
  302. NetpKdPrint(("WKSTA DfsDcName set WorkStation Domain Name\n"));
  303. WsSetWorkStationDomainName();
  304. // timeout needs to be adjusted accordingly if change occurs between workgroup
  305. // and domain so that DC name is also updated on the DFS.
  306. if (WsInAWorkgroup() != TRUE) {
  307. dwTimeout = TIMEOUT_MINUTES(DOMAIN_NAME_CHANGE_TIMEOUT);
  308. } else {
  309. dwTimeout = INFINITE;
  310. // DFS needs to take care of the transition from domain to workgroup.
  311. }
  312. }
  313. //
  314. // Reregister the wait on the domain name change event
  315. //
  316. Status = RtlRegisterWait(
  317. &g_WsDomainNameChangeWorkItem,
  318. (HANDLE)pContext, // waitable handle
  319. DfsDcName, // callback fcn
  320. pContext, // parameter
  321. dwTimeout, // timeout
  322. WT_EXECUTEONLYONCE | // flags
  323. WT_EXECUTEDEFAULT |
  324. WT_EXECUTELONGFUNCTION);
  325. return;
  326. }
  327. #define DFS_DC_NAME_DELAY_POLICY_KEY TEXT("Software\\Policies\\Microsoft\\System\\DFSClient")
  328. DWORD
  329. DfsGetDelayInterval(void)
  330. {
  331. NET_API_STATUS ApiStatus;
  332. LPNET_CONFIG_HANDLE SectionHandle = NULL;
  333. DWORD Value=0;
  334. HKEY hKey;
  335. LONG lResult=0;
  336. DWORD dwValue=0, dwSize = sizeof(dwValue);
  337. DWORD dwType = 0;
  338. // First, check for a policy
  339. lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, DFS_DC_NAME_DELAY_POLICY_KEY, 0,
  340. KEY_READ, &hKey);
  341. if (lResult == ERROR_SUCCESS)
  342. {
  343. lResult = RegQueryValueEx (hKey, DFS_DC_NAME_DELAY, 0, &dwType,
  344. (LPBYTE) &dwValue, &dwSize);
  345. RegCloseKey (hKey);
  346. }
  347. // Exit now if a policy value was found
  348. if (lResult == ERROR_SUCCESS && dwType == REG_DWORD)
  349. {
  350. return dwValue;
  351. }
  352. // Second, check for a preference
  353. //
  354. // Open section of config data.
  355. //
  356. ApiStatus = NetpOpenConfigData(
  357. &SectionHandle,
  358. NULL, // Local server.
  359. SECT_NT_WKSTA, // Section name.
  360. FALSE // Don't want read-only access.
  361. );
  362. if (ApiStatus != NERR_Success) {
  363. return DOMAIN_NAME_CHANGE_TIMEOUT_LONG;
  364. }
  365. ApiStatus = NetpGetConfigDword(
  366. SectionHandle,
  367. DFS_DC_NAME_DELAY,
  368. 0,
  369. &Value
  370. );
  371. NetpCloseConfigData( SectionHandle );
  372. if (ApiStatus != NERR_Success) {
  373. return DOMAIN_NAME_CHANGE_TIMEOUT_LONG;
  374. }
  375. if (Value < DOMAIN_NAME_CHANGE_TIMEOUT_LONG) {
  376. Value = DOMAIN_NAME_CHANGE_TIMEOUT_LONG;
  377. }
  378. return Value;
  379. }