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.

572 lines
14 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. unc.c
  5. Abstract:
  6. This file contains functions to support multiple UNC providers
  7. on a single NT machine.
  8. Author:
  9. Manny Weiser [MannyW] 20-Dec-1991
  10. Revision History:
  11. Isaac Heizer [IsaacHe] 16-Nov-1994 Defer loading the MUP
  12. Rewrite
  13. Milan Shah [MilanS] 7-Mar-1996 Check for Dfs client status
  14. before loading the MUP
  15. --*/
  16. #include "fsrtlp.h"
  17. #include <zwapi.h>
  18. #include <ntddmup.h>
  19. #include <ntddnull.h>
  20. #define MupRegKey L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup"
  21. #define UNCSymbolicLink L"\\DosDevices\\UNC"
  22. #define DevNull L"\\Device\\Null"
  23. #define DevMup DD_MUP_DEVICE_NAME
  24. //
  25. // Define a tag for general pool allocations from this module
  26. //
  27. #undef MODULE_POOL_TAG
  28. #define MODULE_POOL_TAG ('nuSF')
  29. //
  30. // Local prototypes
  31. //
  32. NTSTATUS
  33. FsRtlpRegisterProviderWithMUP
  34. (
  35. IN HANDLE mupHandle,
  36. IN PUNICODE_STRING RedirDevName,
  37. IN BOOLEAN MailslotsSupported
  38. );
  39. NTSTATUS
  40. FsRtlpOpenDev(
  41. IN OUT PHANDLE Handle,
  42. IN LPWSTR DevNameStr
  43. );
  44. VOID
  45. FsRtlpSetSymbolicLink(
  46. IN PUNICODE_STRING DevName OPTIONAL
  47. );
  48. BOOLEAN
  49. FsRtlpIsDfsEnabled();
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text(PAGE, FsRtlpRegisterProviderWithMUP)
  52. #pragma alloc_text(PAGE, FsRtlpOpenDev)
  53. #pragma alloc_text(PAGE, FsRtlpSetSymbolicLink)
  54. #pragma alloc_text(PAGE, FsRtlRegisterUncProvider)
  55. #pragma alloc_text(PAGE, FsRtlDeregisterUncProvider)
  56. #pragma alloc_text(PAGE, FsRtlpIsDfsEnabled)
  57. #endif
  58. #ifdef ALLOC_DATA_PRAGMA
  59. #pragma data_seg("PAGEDATA")
  60. #endif
  61. //
  62. // We defer calling the MUP with the registration data until
  63. // the second redir loads and Dfs is disabled. This structure holds the
  64. // data necessary to make that call.
  65. //
  66. struct {
  67. HANDLE MupHandle;
  68. HANDLE ReturnedHandle;
  69. UNICODE_STRING RedirDevName;
  70. BOOLEAN MailslotsSupported;
  71. } FsRtlpDRD = {0};
  72. //
  73. // Number of times we've loaded redirs.
  74. //
  75. ULONG FsRtlpRedirs = 0;
  76. #ifdef ALLOC_DATA_PRAGMA
  77. #pragma data_seg()
  78. #endif
  79. //
  80. // Resource protection
  81. //
  82. KSEMAPHORE FsRtlpUncSemaphore;
  83. NTSTATUS
  84. FsRtlpRegisterProviderWithMUP
  85. (
  86. IN HANDLE mupHandle,
  87. IN PUNICODE_STRING RedirDevName,
  88. IN BOOLEAN MailslotsSupported
  89. )
  90. /*++
  91. Routine Description:
  92. This private routine does the FSCTL to the MUP to tell it about
  93. a new redir
  94. Arguments:
  95. mupHandle - Handle to the MUP
  96. RedirDevName - The device name of the redir.
  97. MailslotsSupported - If TRUE, this redir supports mailslots.
  98. Return Value:
  99. NTSTATUS - The status of the operation.
  100. --*/
  101. {
  102. NTSTATUS status;
  103. IO_STATUS_BLOCK ioStatusBlock;
  104. ULONG paramLength;
  105. PREDIRECTOR_REGISTRATION params;
  106. PAGED_CODE();
  107. paramLength = sizeof( REDIRECTOR_REGISTRATION ) +
  108. RedirDevName->Length;
  109. params = ExAllocatePoolWithTag( NonPagedPool, paramLength, MODULE_POOL_TAG );
  110. if( params == NULL )
  111. return STATUS_INSUFFICIENT_RESOURCES;
  112. params->DeviceNameOffset = sizeof( REDIRECTOR_REGISTRATION );
  113. params->DeviceNameLength = RedirDevName->Length;
  114. params->MailslotsSupported = MailslotsSupported;
  115. RtlCopyMemory(
  116. (PCHAR)params + params->DeviceNameOffset,
  117. RedirDevName->Buffer,
  118. RedirDevName->Length
  119. );
  120. status = NtFsControlFile(
  121. mupHandle,
  122. 0,
  123. NULL,
  124. NULL,
  125. &ioStatusBlock,
  126. FSCTL_MUP_REGISTER_UNC_PROVIDER,
  127. params,
  128. paramLength,
  129. NULL,
  130. 0
  131. );
  132. if ( status == STATUS_PENDING ) {
  133. status = NtWaitForSingleObject( mupHandle, TRUE, NULL );
  134. }
  135. if ( NT_SUCCESS( status ) ) {
  136. status = ioStatusBlock.Status;
  137. }
  138. ASSERT( NT_SUCCESS( status ) );
  139. ExFreePool( params );
  140. return status;
  141. }
  142. NTSTATUS
  143. FsRtlpOpenDev(
  144. IN OUT PHANDLE Handle,
  145. IN LPWSTR DevNameStr
  146. )
  147. {
  148. NTSTATUS status;
  149. UNICODE_STRING DevName;
  150. OBJECT_ATTRIBUTES objectAttributes;
  151. IO_STATUS_BLOCK ioStatusBlock;
  152. PAGED_CODE();
  153. RtlInitUnicodeString( &DevName, DevNameStr );
  154. InitializeObjectAttributes(
  155. &objectAttributes,
  156. &DevName,
  157. 0,
  158. 0,
  159. NULL
  160. );
  161. status = ZwCreateFile(
  162. Handle,
  163. GENERIC_WRITE,
  164. &objectAttributes,
  165. &ioStatusBlock,
  166. NULL,
  167. FILE_ATTRIBUTE_NORMAL,
  168. FILE_SHARE_READ | FILE_SHARE_WRITE,
  169. FILE_OPEN,
  170. 0,
  171. NULL,
  172. 0
  173. );
  174. if ( NT_SUCCESS( status ) ) {
  175. status = ioStatusBlock.Status;
  176. }
  177. if( !NT_SUCCESS( status ) ) {
  178. *Handle = (HANDLE)-1;
  179. }
  180. return status;
  181. }
  182. VOID
  183. FsRtlpSetSymbolicLink( IN PUNICODE_STRING DevName OPTIONAL )
  184. {
  185. NTSTATUS status;
  186. UNICODE_STRING UncSymbolicName;
  187. PAGED_CODE();
  188. RtlInitUnicodeString( &UncSymbolicName, UNCSymbolicLink );
  189. (VOID)IoDeleteSymbolicLink( &UncSymbolicName );
  190. if( ARGUMENT_PRESENT( DevName ) ) {
  191. status = IoCreateSymbolicLink( &UncSymbolicName, DevName );
  192. ASSERT( NT_SUCCESS( status ) );
  193. }
  194. }
  195. NTSTATUS
  196. FsRtlRegisterUncProvider(
  197. IN OUT PHANDLE MupHandle,
  198. IN PUNICODE_STRING RedirDevName,
  199. IN BOOLEAN MailslotsSupported
  200. )
  201. /*++
  202. Routine Description:
  203. This routine registers a redir as a UNC provider.
  204. Arguments:
  205. Handle - Pointer to a handle. The handle is returned by the routine
  206. to be used when calling FsRtlDeregisterUncProvider.
  207. It is valid only if the routines returns STATUS_SUCCESS.
  208. RedirDevName - The device name of the redir.
  209. MailslotsSupported - If TRUE, this redir supports mailslots.
  210. Return Value:
  211. NTSTATUS - The status of the operation.
  212. --*/
  213. {
  214. NTSTATUS status;
  215. HANDLE mupHandle = (HANDLE)-1;
  216. UNICODE_STRING mupDriverName;
  217. BOOLEAN dfsEnabled;
  218. PAGED_CODE();
  219. KeWaitForSingleObject(&FsRtlpUncSemaphore, Executive, KernelMode, FALSE, NULL );
  220. if (FsRtlpRedirs == 0) {
  221. dfsEnabled = FsRtlpIsDfsEnabled();
  222. if (dfsEnabled) {
  223. FsRtlpRedirs = 1;
  224. RtlZeroMemory((PVOID) &FsRtlpDRD, sizeof(FsRtlpDRD));
  225. }
  226. }
  227. switch( FsRtlpRedirs ) {
  228. case 0:
  229. //
  230. // Ok, the MUP isn't there and we don't need to use the
  231. // MUP for the first redir.
  232. //
  233. // We need to return a handle, but we're not really using the MUP yet.
  234. // And we may never use it (if there's only 1 redir). Return
  235. // a handle to the NULL device object, since we're committed to returning
  236. // a handle to our caller. Our caller isn't supposed to do anything with
  237. // the handle except to call FsRtlDeregisterUncProvider() with it.
  238. //
  239. status = FsRtlpOpenDev( &mupHandle, DevNull );
  240. if( !NT_SUCCESS( status ) )
  241. break;
  242. //
  243. // Save up enough state to allow us to call the MUP later with
  244. // this registration info if necessary.
  245. //
  246. FsRtlpDRD.RedirDevName.Buffer = ExAllocatePoolWithTag( NonPagedPool,
  247. RedirDevName->MaximumLength,
  248. MODULE_POOL_TAG );
  249. if( FsRtlpDRD.RedirDevName.Buffer == NULL ) {
  250. status = STATUS_INSUFFICIENT_RESOURCES;
  251. break;
  252. }
  253. FsRtlpDRD.RedirDevName.Length = RedirDevName->Length;
  254. FsRtlpDRD.RedirDevName.MaximumLength = RedirDevName->MaximumLength;
  255. RtlCopyMemory(
  256. (PCHAR)FsRtlpDRD.RedirDevName.Buffer,
  257. RedirDevName->Buffer,
  258. RedirDevName->MaximumLength
  259. );
  260. FsRtlpDRD.MailslotsSupported = MailslotsSupported;
  261. FsRtlpDRD.ReturnedHandle = mupHandle;
  262. FsRtlpDRD.MupHandle = (HANDLE)-1;
  263. //
  264. // Set the UNC symbolic link to point to the redir we just loaded
  265. //
  266. FsRtlpSetSymbolicLink( RedirDevName );
  267. break;
  268. default:
  269. //
  270. // This is the second or later redir load -- MUST use the MUP
  271. //
  272. status = FsRtlpOpenDev( &mupHandle, DevMup );
  273. if( !NT_SUCCESS( status ) ) {
  274. RtlInitUnicodeString( &mupDriverName, MupRegKey );
  275. (VOID)ZwLoadDriver( &mupDriverName );
  276. status = FsRtlpOpenDev( &mupHandle, DevMup );
  277. if( !NT_SUCCESS( status ) )
  278. break;
  279. }
  280. //
  281. // See if we need to tell the MUP about the first redir that registered
  282. //
  283. if( FsRtlpDRD.RedirDevName.Buffer ) {
  284. status = FsRtlpRegisterProviderWithMUP( mupHandle,
  285. &FsRtlpDRD.RedirDevName,
  286. FsRtlpDRD.MailslotsSupported );
  287. if( !NT_SUCCESS( status ) )
  288. break;
  289. FsRtlpDRD.MupHandle = mupHandle;
  290. ExFreePool( FsRtlpDRD.RedirDevName.Buffer );
  291. FsRtlpDRD.RedirDevName.Buffer = NULL;
  292. //
  293. // Set the UNC symbolic link to point to the MUP
  294. //
  295. RtlInitUnicodeString( &mupDriverName, DevMup );
  296. FsRtlpSetSymbolicLink( &mupDriverName );
  297. status = FsRtlpOpenDev( &mupHandle, DevMup );
  298. if( !NT_SUCCESS( status ) )
  299. break;
  300. }
  301. //
  302. // Pass the request to the MUP for this redir
  303. //
  304. status = FsRtlpRegisterProviderWithMUP( mupHandle,
  305. RedirDevName,
  306. MailslotsSupported );
  307. break;
  308. }
  309. if( NT_SUCCESS( status ) ) {
  310. FsRtlpRedirs++;
  311. *MupHandle = mupHandle;
  312. } else {
  313. if( mupHandle != (HANDLE)-1 && mupHandle != NULL ) {
  314. ZwClose( mupHandle );
  315. }
  316. *MupHandle = (HANDLE)-1;
  317. }
  318. KeReleaseSemaphore(&FsRtlpUncSemaphore, 0, 1, FALSE );
  319. return status;
  320. }
  321. VOID
  322. FsRtlDeregisterUncProvider(
  323. IN HANDLE Handle
  324. )
  325. /*++
  326. Routine Description:
  327. This routine deregisters a redir as a UNC provider.
  328. Arguments:
  329. Handle - A handle to the Multiple UNC router, returned by the
  330. registration call.
  331. Return Value:
  332. None.
  333. --*/
  334. {
  335. NTSTATUS status;
  336. PAGED_CODE();
  337. if( Handle == (HANDLE)-1 || Handle == NULL )
  338. return;
  339. status = ZwClose( Handle );
  340. if( !NT_SUCCESS( status ) ) {
  341. return;
  342. }
  343. KeWaitForSingleObject(&FsRtlpUncSemaphore, Executive, KernelMode, FALSE, NULL );
  344. ASSERT( FsRtlpRedirs > 0 );
  345. if( Handle == FsRtlpDRD.ReturnedHandle ) {
  346. //
  347. // The first redir in the system is closing. Release the state we saved
  348. // for it, and pass the close on to the MUP if necessary
  349. //
  350. if( FsRtlpDRD.RedirDevName.Buffer != NULL ) {
  351. ExFreePool( FsRtlpDRD.RedirDevName.Buffer );
  352. FsRtlpDRD.RedirDevName.Buffer = NULL;
  353. }
  354. if( FsRtlpDRD.MupHandle != (HANDLE)-1 ) {
  355. ZwClose( FsRtlpDRD.MupHandle );
  356. FsRtlpDRD.MupHandle = (HANDLE)-1;
  357. }
  358. FsRtlpDRD.ReturnedHandle = (HANDLE)-1;
  359. }
  360. if( --FsRtlpRedirs == 0 ) {
  361. FsRtlpSetSymbolicLink( (PUNICODE_STRING)NULL );
  362. }
  363. KeReleaseSemaphore(&FsRtlpUncSemaphore, 0, 1, FALSE );
  364. }
  365. BOOLEAN
  366. FsRtlpIsDfsEnabled()
  367. /*++
  368. Routine Description:
  369. This routine checks a registry key to see if the Dfs client is enabled.
  370. The client is assumed to be enabled by default, and disabled only if there
  371. is a registry value indicating that it should be disabled.
  372. Arguments:
  373. None
  374. Return Value:
  375. TRUE if Dfs client is enabled, FALSE otherwise.
  376. --*/
  377. {
  378. NTSTATUS status;
  379. HANDLE mupRegHandle;
  380. OBJECT_ATTRIBUTES objectAttributes;
  381. ULONG valueSize;
  382. BOOLEAN dfsEnabled = TRUE;
  383. UNICODE_STRING mupRegKey = {
  384. sizeof(MupRegKey) - sizeof(WCHAR),
  385. sizeof(MupRegKey),
  386. MupRegKey};
  387. #define DISABLE_DFS_VALUE_NAME L"DisableDfs"
  388. UNICODE_STRING disableDfs = {
  389. sizeof(DISABLE_DFS_VALUE_NAME) - sizeof(WCHAR),
  390. sizeof(DISABLE_DFS_VALUE_NAME),
  391. DISABLE_DFS_VALUE_NAME};
  392. struct {
  393. KEY_VALUE_PARTIAL_INFORMATION Info;
  394. ULONG Buffer;
  395. } disableDfsValue;
  396. InitializeObjectAttributes(
  397. &objectAttributes,
  398. &mupRegKey,
  399. OBJ_CASE_INSENSITIVE,
  400. 0,
  401. NULL
  402. );
  403. status = ZwOpenKey(&mupRegHandle, KEY_READ, &objectAttributes);
  404. if (NT_SUCCESS(status)) {
  405. status = ZwQueryValueKey(
  406. mupRegHandle,
  407. &disableDfs,
  408. KeyValuePartialInformation,
  409. (PVOID) &disableDfsValue,
  410. sizeof(disableDfsValue),
  411. &valueSize);
  412. if (NT_SUCCESS(status) && disableDfsValue.Info.Type == REG_DWORD) {
  413. if ( (*((PULONG) disableDfsValue.Info.Data)) == 1 )
  414. dfsEnabled = FALSE;
  415. }
  416. ZwClose( mupRegHandle );
  417. }
  418. return( dfsEnabled );
  419. }