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.

1818 lines
61 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. Init.c
  5. Abstract:
  6. This module implements the Driver Initialization routine for the WebDav
  7. miniredir.
  8. Author:
  9. Joe Linn
  10. Rohan Kumar [RohanK] 10-March-1999
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "ntverp.h"
  16. #include "netevent.h"
  17. #include "nvisible.h"
  18. #include "webdav.h"
  19. #include "ntddmup.h"
  20. #include "rxdata.h"
  21. #include "fsctlbuf.h"
  22. #include "tdikrnl.h"
  23. //
  24. // Global data declarations.
  25. //
  26. PEPROCESS MRxDAVSystemProcess;
  27. FAST_MUTEX MRxDAVSerializationMutex;
  28. KIRQL MRxDAVGlobalSpinLockSavedIrql;
  29. KSPIN_LOCK MRxDAVGlobalSpinLock;
  30. BOOLEAN MRxDAVGlobalSpinLockAcquired;
  31. BOOLEAN MRxDAVTransportReady = FALSE;
  32. HANDLE MRxDAVTdiNotificationHandle = NULL;
  33. //
  34. // The Exchange Registry key from where we read their DeviceObject name.
  35. //
  36. #define DavExchangeRegistryKey L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Lsifs\\Parameters"
  37. //
  38. // The exchange device name will be stored in this KEY_VALUE_PARTIAL_INFORMATION
  39. // structure.
  40. //
  41. PBYTE DavExchangeDeviceName = NULL;
  42. //
  43. // The DavWinInetCachePath which is used in satisfying volume related queries.
  44. //
  45. WCHAR DavWinInetCachePath[MAX_PATH];
  46. //
  47. // The ProcessId of the svchost.exe process that loads the webclnt.dll.
  48. //
  49. ULONG DavSvcHostProcessId = 0;
  50. //
  51. // Name cache stuff. These values are read from the registry during init time.
  52. //
  53. ULONG FileInformationCacheLifeTimeInSec = 0;
  54. ULONG FileNotFoundCacheLifeTimeInSec = 0;
  55. ULONG NameCacheMaxEntries = 0;
  56. #define MRXDAV_DEBUG_KEY L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\MRxDAV\\Parameters"
  57. #define NAME_CACHE_OBJ_GET_FILE_ATTRIB_LIFETIME L"FileInformationCacheLifeTimeInSec"
  58. #define NAME_CACHE_OBJ_NAME_NOT_FOUND_LIFETIME L"FileNotFoundCacheLifeTimeInSec"
  59. #define NAME_CACHE_NETROOT_MAX_ENTRIES L"NameCacheMaxEntries"
  60. #define CREATE_REQUEST_TIMEOUT_IN_SEC L"CreateRequestTimeoutInSec"
  61. #define CREATEVNETROOT_REQUEST_TIMEOUT_IN_SEC L"CreateVNetRootRequestTimeoutInSec"
  62. #define QUERYDIRECTORY_REQUEST_TIMEOUT_IN_SEC L"QueryDirectoryRequestTimeoutInSec"
  63. #define CLOSE_REQUEST_TIMEOUT_IN_SEC L"CloseRequestTimeoutInSec"
  64. #define CREATESRVCALL_REQUEST_TIMEOUT_IN_SEC L"CreateSrvCallRequestTimeoutInSec"
  65. #define FINALIZESRVCALL_REQUEST_TIMEOUT_IN_SEC L"FinalizeSrvCallRequestTimeoutInSec"
  66. #define FINALIZEFOBX_REQUEST_TIMEOUT_IN_SEC L"FinalizeFobxRequestTimeoutInSec"
  67. #define FINALIZEVNETROOT_REQUEST_TIMEOUT_IN_SEC L"FinalizeVNetRootRequestTimeoutInSec"
  68. #define RENAME_REQUEST_TIMEOUT_IN_SEC L"ReNameRequestTimeoutInSec"
  69. #define SETFILEINFO_REQUEST_TIMEOUT_IN_SEC L"SetFileInfoRequestTimeoutInSec"
  70. #define QUERYFILEINFO_REQUEST_TIMEOUT_IN_SEC L"QueryFileInfoRequestTimeoutInSec"
  71. #define QUERYVOLUMEINFO_REQUEST_TIMEOUT_IN_SEC L"QueryVolumeInfoRequestTimeoutInSec"
  72. #define LOCKREFRESH_REQUEST_TIMEOUT_IN_SEC L"LockRefreshRequestTimeoutInSec"
  73. #if DBG
  74. #define MRXDAV_DEBUG_VALUE L"DAVDebugFlag"
  75. #endif
  76. //
  77. // Define the size of the shared memory area that we allocate as a heap
  78. // between user and server.
  79. //
  80. #define DAV_SHARED_MEMORY_SIZE (1024 * 512)
  81. //
  82. // The Debug vector flags that control the amount of tracing in the debugger.
  83. //
  84. #if DBG
  85. ULONG MRxDavDebugVector = 0;
  86. #endif
  87. //
  88. // Mini Redirector global variables.
  89. //
  90. struct _MINIRDR_DISPATCH MRxDAVDispatch;
  91. PWEBDAV_DEVICE_OBJECT MRxDAVDeviceObject;
  92. FAST_IO_DISPATCH MRxDAVFastIoDispatch;
  93. #define DAV_SVCHOST_NAME_SIZE 22
  94. UNICODE_STRING uniSvcHost = {DAV_SVCHOST_NAME_SIZE+2,DAV_SVCHOST_NAME_SIZE+2,L"svchost.exe"};
  95. FAST_MUTEX MRxDAVFileInfoCacheLock;
  96. //
  97. // Mentioned below are the prototypes of functions tht are used only within
  98. // this module (file). These functions should not be exposed outside.
  99. //
  100. NTSTATUS
  101. DriverEntry(
  102. IN PDRIVER_OBJECT DriverObject,
  103. IN PUNICODE_STRING RegistryPath
  104. );
  105. VOID
  106. MRxDAVInitUnwind(
  107. IN PDRIVER_OBJECT DriverObject,
  108. IN WEBDAV_INIT_STATES MRxDAVInitState
  109. );
  110. VOID
  111. MRxDAVUnload(
  112. IN PDRIVER_OBJECT DriverObject
  113. );
  114. VOID
  115. MRxDAVInitializeTables(
  116. VOID
  117. );
  118. NTSTATUS
  119. MRxDAVFsdDispatch (
  120. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  121. IN PIRP Irp
  122. );
  123. VOID
  124. MRxDAVDeregisterAndCleanupDeviceObject (
  125. PUMRX_DEVICE_OBJECT UMRdrDeviceObject
  126. );
  127. NTSTATUS
  128. MRxDAVRegisterForPnpNotifications(
  129. VOID
  130. );
  131. NTSTATUS
  132. MRxDAVDeregisterForPnpNotifications(
  133. VOID
  134. );
  135. VOID
  136. MRxDAVPnPBindingHandler(
  137. IN TDI_PNP_OPCODE PnPOpcode,
  138. IN PUNICODE_STRING pTransportName,
  139. IN PWSTR BindingList
  140. );
  141. VOID
  142. MRxDAVInitializeTheTimeValues(
  143. VOID
  144. );
  145. NTSTATUS
  146. MRxDAVSkipIrps(
  147. IN PIRP Irp,
  148. IN PUNICODE_STRING pFileName,
  149. IN BOOL fCheckAny
  150. );
  151. UCHAR *
  152. PsGetProcessImageFileName(
  153. PEPROCESS Process
  154. );
  155. #ifdef ALLOC_PRAGMA
  156. #pragma alloc_text(PAGE, DriverEntry)
  157. #pragma alloc_text(PAGE, MRxDAVInitUnwind)
  158. #pragma alloc_text(PAGE, MRxDAVUnload)
  159. #pragma alloc_text(PAGE, MRxDAVInitializeTables)
  160. #pragma alloc_text(PAGE, MRxDAVFsdDispatch)
  161. #pragma alloc_text(PAGE, MRxDAVDeregisterAndCleanupDeviceObject)
  162. #pragma alloc_text(PAGE, MRxDAVFlush)
  163. #pragma alloc_text(PAGE, MRxDAVPnPBindingHandler)
  164. #pragma alloc_text(PAGE, MRxDAVRegisterForPnpNotifications)
  165. #pragma alloc_text(PAGE, MRxDAVDeregisterForPnpNotifications)
  166. #pragma alloc_text(PAGE, MRxDAVProbeForReadWrite)
  167. #pragma alloc_text(PAGE, MRxDAVSkipIrps)
  168. #pragma alloc_text(PAGE, MRxDAVInitializeTheTimeValues)
  169. #endif
  170. //
  171. // Implementation of functions begins here.
  172. //
  173. NTSTATUS
  174. DriverEntry(
  175. IN PDRIVER_OBJECT DriverObject,
  176. IN PUNICODE_STRING RegistryPath
  177. )
  178. /*++
  179. Routine Description:
  180. This is the initialization routine for the usermode reflector.
  181. Arguments:
  182. DriverObject - Pointer to driver object created by the system.
  183. Return Value:
  184. RXSTATUS - The function value is the final status from the initialization
  185. operation.
  186. --*/
  187. {
  188. NTSTATUS NtStatus = STATUS_SUCCESS;
  189. NTSTATUS RegNtStatus = STATUS_SUCCESS;
  190. WEBDAV_INIT_STATES MRxDAVInitState = 0;
  191. UNICODE_STRING MRxDAVMiniRedirectorName;
  192. PUMRX_DEVICE_OBJECT UMRefDeviceObject;
  193. OBJECT_ATTRIBUTES ObjectAttributes;
  194. HANDLE KeyHandle = INVALID_HANDLE_VALUE;
  195. UNICODE_STRING UnicodeRegKeyName, UnicodeValueName;
  196. ULONG RequiredLength = 0;
  197. PKEY_VALUE_PARTIAL_INFORMATION DavKeyValuePartialInfo = NULL;
  198. PAGED_CODE();
  199. DavDbgTrace(DAV_TRACE_DETAIL,
  200. ("%ld: Entering DriverEntry!!!!\n", PsGetCurrentThreadId()));
  201. DavDbgTrace(DAV_TRACE_CONTEXT,
  202. ("%ld: DriverEntry: Starting MRxDAV. DriverObject: %08lx.\n",
  203. PsGetCurrentThreadId(), DriverObject));
  204. //
  205. // The first thing we do is set some globals in the driver by calling
  206. // MRxDAVInitializeTheTimeValues().
  207. //
  208. MRxDAVInitializeTheTimeValues();
  209. #ifdef MONOLITHIC_MINIRDR
  210. DavDbgTrace(DAV_TRACE_DETAIL,
  211. ("%ld: DriverEntry: Calling RxDriverEntry.\n",
  212. PsGetCurrentThreadId()));
  213. NtStatus = RxDriverEntry(DriverObject, RegistryPath);
  214. DavDbgTrace(DAV_TRACE_DETAIL,
  215. ("%ld: DriverEntry: Back from RxDriverEntry. NtStatus: %08lx.\n",
  216. PsGetCurrentThreadId(), NtStatus));
  217. if (NtStatus != STATUS_SUCCESS) {
  218. DavDbgTrace(DAV_TRACE_ERROR,
  219. ("%ld: ERROR: DriverEntry/RxDriverEntry: NtStatus = %08lx\n",
  220. PsGetCurrentThreadId(), NtStatus));
  221. return(NtStatus);
  222. }
  223. #endif
  224. //
  225. // The Dav redirector needs to register for PNP notifications to handle the
  226. // following scenario. The SMB redirector does not accept connections till
  227. // the net is ready as indicated by a PNP event. If during this time DAV
  228. // forwards the connection requests to WinInet it will in turn spin up RAS
  229. // connections. By registering for PNP notifications we provide an easy
  230. // mechanism for short circuiting the requests till transports are ready.
  231. //
  232. MRxDAVRegisterForPnpNotifications();
  233. MRxDAVSystemProcess = RxGetRDBSSProcess();
  234. ExInitializeFastMutex(&MRxDAVSerializationMutex);
  235. KeInitializeSpinLock(&MRxDAVGlobalSpinLock);
  236. MRxDAVGlobalSpinLockAcquired = FALSE;
  237. //
  238. // 1. We need to initialize the TimerObject which will be used by the timer
  239. // thread.
  240. // 2. Set TimerThreadShutDown to FALSE. This will be set to TRUE
  241. // when the system is being shutdown.
  242. // 3. Initialize the resource that is used to synchronize the timer thread
  243. // when the service is stopped.
  244. // 4. Initialize the event that is signalled by the timer thread just
  245. // before it terminates itself.
  246. //
  247. KeInitializeTimerEx( &(DavTimerObject), NotificationTimer );
  248. TimerThreadShutDown = FALSE;
  249. ExInitializeResourceLite( &(MRxDAVTimerThreadLock) );
  250. KeInitializeEvent( &(TimerThreadEvent), NotificationEvent, FALSE );
  251. //
  252. // Initialize the global LockTokenEntryList and the resource that is used
  253. // to synchronize access to it.
  254. //
  255. InitializeListHead( &(LockTokenEntryList) );
  256. ExInitializeResourceLite( &(LockTokenEntryListLock) );
  257. //
  258. // Initialize the global LockConflictEntryList and the resource that is used
  259. // to synchronize access to it.
  260. //
  261. InitializeListHead( &(LockConflictEntryList) );
  262. ExInitializeResourceLite( &(LockConflictEntryListLock) );
  263. //
  264. // If QueueLockRefreshWorkItem is TRUE, the TimerThread (which cancels all the
  265. // AsyncEngineContexts that haven't completed in a specified time) queues a
  266. // WorkItem to refresh the locks. We initialize it to TRUE and the lock
  267. // which is used to synchronize it.
  268. //
  269. QueueLockRefreshWorkItem = TRUE;
  270. ExInitializeResourceLite( &(QueueLockRefreshWorkItemLock) );
  271. //
  272. // Zero the WinInetCachePath global. This will be initialized to the local
  273. // WinInetCachePath value when the MiniRedir is started.
  274. //
  275. RtlZeroMemory ( DavWinInetCachePath, MAX_PATH * sizeof(WCHAR) );
  276. try {
  277. MRxDAVInitState = MRxDAVINIT_START;
  278. RtlInitUnicodeString(&MRxDAVMiniRedirectorName, DD_DAV_DEVICE_NAME_U);
  279. DavDbgTrace(DAV_TRACE_DETAIL,
  280. ("%ld: DriverEntry: Registering the Mini-Rdr with RDBSS.\n",
  281. PsGetCurrentThreadId()));
  282. NtStatus = RxRegisterMinirdr((PRDBSS_DEVICE_OBJECT *)(&MRxDAVDeviceObject),
  283. DriverObject,
  284. &MRxDAVDispatch,
  285. RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS,
  286. &MRxDAVMiniRedirectorName,
  287. WEBDAV_DEVICE_OBJECT_EXTENSION_SIZE,
  288. FILE_DEVICE_NETWORK_FILE_SYSTEM,
  289. FILE_REMOTE_DEVICE);
  290. if (NtStatus != STATUS_SUCCESS) {
  291. DavDbgTrace(DAV_TRACE_ERROR,
  292. ("%ld: ERROR: DriverEntry/RxRegisterMinirdr: NtStatus "
  293. "= %08lx\n", PsGetCurrentThreadId(), NtStatus));
  294. try_return(NtStatus);
  295. }
  296. MRxDAVInitState = MRxDAVINIT_MINIRDR_REGISTERED;
  297. //
  298. // Now initialize the reflector's portion of the Device object.
  299. //
  300. UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)&(MRxDAVDeviceObject->UMRefDeviceObject);
  301. NtStatus = UMRxInitializeDeviceObject(UMRefDeviceObject,
  302. 1024,
  303. 512,
  304. DAV_SHARED_MEMORY_SIZE);
  305. if (!NT_SUCCESS(NtStatus)) {
  306. DavDbgTrace(DAV_TRACE_ERROR,
  307. ("%ld: ERROR: DriverEntry/UMRxInitializeDeviceObject:"
  308. " NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  309. try_return(NtStatus);
  310. }
  311. //
  312. // Initialize the DAV Mini-Redir specific fields of the device object.
  313. //
  314. MRxDAVDeviceObject->IsStarted = FALSE;
  315. MRxDAVDeviceObject->CachedRxDeviceFcb = NULL;
  316. MRxDAVDeviceObject->RegisteringProcess = IoGetCurrentProcess();
  317. try_exit: NOTHING;
  318. } finally {
  319. if (NtStatus != STATUS_SUCCESS) {
  320. DavDbgTrace(DAV_TRACE_ERROR,
  321. ("%ld: ERROR: DriverEntry: Calling MRxDAVInitUnwind.\n",
  322. PsGetCurrentThreadId()));
  323. MRxDAVInitUnwind(DriverObject, MRxDAVInitState);
  324. }
  325. }
  326. if (NtStatus != STATUS_SUCCESS) {
  327. DavDbgTrace(DAV_TRACE_ERROR,
  328. ("%ld: ERROR: DriverEntry failed with NtStatus = %08lx\n",
  329. PsGetCurrentThreadId(), NtStatus));
  330. return(NtStatus);
  331. }
  332. //
  333. // Initialize the dispatch vector used by RDBSS.
  334. //
  335. MRxDAVInitializeTables();
  336. //
  337. // Initialize the major function dispatch vector of the Driver object.
  338. //
  339. {
  340. DWORD i;
  341. for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  342. DriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)MRxDAVFsdDispatch;
  343. }
  344. }
  345. //
  346. // Setup Unload Routine for the Driver Object.
  347. //
  348. DriverObject->DriverUnload = MRxDAVUnload;
  349. //
  350. // Set the Driver Object's FastIoDispatch function.
  351. //
  352. DriverObject->FastIoDispatch = &(MRxDAVFastIoDispatch);
  353. MRxDAVFastIoDispatch.SizeOfFastIoDispatch = sizeof(MRxDAVFastIoDispatch);
  354. MRxDAVFastIoDispatch.FastIoDeviceControl = MRxDAVFastIoDeviceControl;
  355. MRxDAVFastIoDispatch.FastIoRead = MRxDAVFastIoRead;
  356. MRxDAVFastIoDispatch.FastIoWrite = MRxDAVFastIoWrite;
  357. #ifdef DAV_DEBUG_READ_WRITE_CLOSE_PATH
  358. InitializeListHead( &(DavGlobalFileTable) );
  359. #endif // DAV_DEBUG_READ_WRITE_CLOSE_PATH
  360. //
  361. // Since the Exchange Redir is not shipping with Whistler, we don't need
  362. // to execute the code below. We can exit right away.
  363. //
  364. goto EXIT_THE_FUNCTION;
  365. //
  366. // Finally find out if the Exchange Redir is installed on this machine. If
  367. // it is, get its Device Name.
  368. //
  369. RtlInitUnicodeString( &(UnicodeRegKeyName), DavExchangeRegistryKey );
  370. InitializeObjectAttributes(&(ObjectAttributes),
  371. &(UnicodeRegKeyName),
  372. OBJ_CASE_INSENSITIVE,
  373. 0,
  374. NULL);
  375. //
  376. // Open a handle to the Exchange Key.
  377. //
  378. RegNtStatus = ZwOpenKey(&(KeyHandle), KEY_READ, &(ObjectAttributes));
  379. if (RegNtStatus != STATUS_SUCCESS) {
  380. KeyHandle = INVALID_HANDLE_VALUE;
  381. DavDbgTrace(DAV_TRACE_ERROR,
  382. ("%ld: ERROR: DriverEntry/ZwOpenKey: NtStatus = %08lx\n",
  383. PsGetCurrentThreadId(), RegNtStatus));
  384. goto EXIT_THE_FUNCTION;
  385. }
  386. //
  387. // We are looking for the DeviceName Value.
  388. //
  389. RtlInitUnicodeString( &(UnicodeValueName), L"DeviceName" );
  390. // RtlInitUnicodeString( &(UnicodeValueName), L"Name" );
  391. //
  392. // Find out the number of bytes needed to store this value.
  393. //
  394. RegNtStatus = ZwQueryValueKey(KeyHandle,
  395. &(UnicodeValueName),
  396. KeyValuePartialInformation,
  397. NULL,
  398. 0,
  399. &(RequiredLength));
  400. if (RegNtStatus != STATUS_BUFFER_TOO_SMALL) {
  401. DavDbgTrace(DAV_TRACE_ERROR,
  402. ("%ld: ERROR: DriverEntry/ZwQueryValueKey(1): NtStatus = %08lx\n",
  403. PsGetCurrentThreadId(), RegNtStatus));
  404. goto EXIT_THE_FUNCTION;
  405. }
  406. DavExchangeDeviceName = RxAllocatePoolWithTag(PagedPool, RequiredLength, DAV_EXCHANGE_POOLTAG);
  407. if (DavExchangeDeviceName == NULL) {
  408. RegNtStatus = STATUS_INSUFFICIENT_RESOURCES;
  409. DavDbgTrace(DAV_TRACE_ERROR,
  410. ("ld: ERROR: DriverEntry/RxAllocatePoolWithTag. NtStatus = %08lx\n",
  411. PsGetCurrentThreadId(), RegNtStatus));
  412. goto EXIT_THE_FUNCTION;
  413. }
  414. RtlZeroMemory(DavExchangeDeviceName, RequiredLength);
  415. DavKeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)DavExchangeDeviceName;
  416. RegNtStatus = ZwQueryValueKey(KeyHandle,
  417. &(UnicodeValueName),
  418. KeyValuePartialInformation,
  419. (PVOID)DavKeyValuePartialInfo,
  420. RequiredLength,
  421. &(RequiredLength));
  422. if (RegNtStatus != STATUS_SUCCESS || DavKeyValuePartialInfo->Type != REG_SZ) {
  423. DavDbgTrace(DAV_TRACE_ERROR,
  424. ("%ld: ERROR: DriverEntry/ZwQueryValueKey(2): NtStatus = %08lx\n",
  425. PsGetCurrentThreadId(), RegNtStatus));
  426. goto EXIT_THE_FUNCTION;
  427. }
  428. DavDbgTrace(DAV_TRACE_DETAIL,
  429. ("%ld: DriverEntry: ExchangeDeviceName = %ws\n",
  430. PsGetCurrentThreadId(), DavKeyValuePartialInfo->Data));
  431. DavDbgTrace(DAV_TRACE_DETAIL,
  432. ("%ld: DriverEntry: ExchangeDeviceNameLength = %d\n",
  433. PsGetCurrentThreadId(), DavKeyValuePartialInfo->DataLength));
  434. EXIT_THE_FUNCTION:
  435. //
  436. // We are done with the handle now, so close it.
  437. //
  438. if (KeyHandle != INVALID_HANDLE_VALUE) {
  439. ZwClose(KeyHandle);
  440. }
  441. DavDbgTrace(DAV_TRACE_DETAIL,
  442. ("%ld: Leaving DriverEntry with NtStatus = %08lx\n",
  443. PsGetCurrentThreadId(), NtStatus));
  444. return NtStatus;
  445. }
  446. VOID
  447. MRxDAVInitUnwind(
  448. IN PDRIVER_OBJECT DriverObject,
  449. IN WEBDAV_INIT_STATES MRxDAVInitState
  450. )
  451. /*++
  452. Routine Description:
  453. This routine does the common uninit work for unwinding from a bad driver entry or for unloading.
  454. Arguments:
  455. RxInitState - tells how far we got into the intialization
  456. Return Value:
  457. None
  458. --*/
  459. {
  460. PAGED_CODE();
  461. switch (MRxDAVInitState) {
  462. case MRxDAVINIT_MINIRDR_REGISTERED:
  463. RxUnregisterMinirdr(&MRxDAVDeviceObject->RxDeviceObject);
  464. //
  465. // Lack of break intentional.
  466. //
  467. case MRxDAVINIT_START:
  468. break;
  469. }
  470. }
  471. VOID
  472. MRxDAVUnload(
  473. IN PDRIVER_OBJECT DriverObject
  474. )
  475. /*++
  476. Routine Description:
  477. This is the unload routine for the usermode reflector.
  478. Arguments:
  479. DriverObject - pointer to the driver object for the UMRx
  480. Return Value:
  481. None
  482. --*/
  483. {
  484. PUMRX_DEVICE_OBJECT UMRefDeviceObject = NULL;
  485. PAGED_CODE();
  486. UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)&(MRxDAVDeviceObject->UMRefDeviceObject);
  487. DavDbgTrace(DAV_TRACE_DETAIL,
  488. ("%ld: Entering MRxDAVUnload!!!!\n", PsGetCurrentThreadId()));
  489. DavDbgTrace(DAV_TRACE_CONTEXT,
  490. ("%ld: MRxDAVUnload: DriverObject = %08lx.\n",
  491. PsGetCurrentThreadId(), DriverObject));
  492. //
  493. // If we allocated memory for the exchange device name, we need to free it
  494. // now.
  495. //
  496. if (DavExchangeDeviceName != NULL) {
  497. RxFreePool(DavExchangeDeviceName);
  498. }
  499. //
  500. // Deregister the device object before calling RxUnload.
  501. //
  502. MRxDAVDeregisterAndCleanupDeviceObject(UMRefDeviceObject);
  503. //
  504. // Wait for the timer thread to finish before we delete the global locks
  505. // MRxDAVTimerThreadLock and the others (see below) used to synchronize
  506. // TimerThreadShutDown and other global variables.
  507. //
  508. KeWaitForSingleObject(&(TimerThreadEvent),
  509. Executive,
  510. KernelMode,
  511. FALSE,
  512. NULL);
  513. ExDeleteResourceLite( &(MRxDAVTimerThreadLock) );
  514. ExDeleteResourceLite( &(LockTokenEntryListLock) );
  515. ExDeleteResourceLite( &(LockConflictEntryListLock) );
  516. ExDeleteResourceLite( &(QueueLockRefreshWorkItemLock) );
  517. //
  518. // The TDI registration needs to be undone.
  519. //
  520. MRxDAVDeregisterForPnpNotifications();
  521. #ifdef MONOLITHIC_MINIRDR
  522. RxUnload(DriverObject);
  523. #endif
  524. DavDbgTrace(DAV_TRACE_DETAIL,
  525. ("%ld: Leaving MRxDAVUnload.\n", PsGetCurrentThreadId()));
  526. return;
  527. }
  528. VOID
  529. MRxDAVInitializeTables(
  530. VOID
  531. )
  532. /*++
  533. Routine Description:
  534. This routine sets up the mini redirector dispatch vector and also calls to initialize any other tables needed.
  535. Return Value:
  536. RXSTATUS - The return status for the operation
  537. --*/
  538. {
  539. PAGED_CODE();
  540. //
  541. // Local minirdr dispatch table init.
  542. //
  543. ZeroAndInitializeNodeType(&MRxDAVDispatch,
  544. RDBSS_NTC_MINIRDR_DISPATCH,
  545. sizeof(MINIRDR_DISPATCH));
  546. //
  547. // Reflector extension sizes and allocation policies.
  548. // CODE.IMPROVEMENT. Currently we do not allocate the NET_ROOT and
  549. // SRV_CALL extensions in the wrapper. Except for V_NET_ROOT wherein it is
  550. // shared across multiple instances in the wrapper all the other data
  551. // structure management should be left to the wrappers.
  552. //
  553. MRxDAVDispatch.MRxFlags = (RDBSS_MANAGE_FCB_EXTENSION |
  554. RDBSS_MANAGE_SRV_OPEN_EXTENSION |
  555. RDBSS_MANAGE_FOBX_EXTENSION |
  556. RDBSS_MANAGE_V_NET_ROOT_EXTENSION |
  557. RDBSS_NO_DEFERRED_CACHE_READAHEAD);
  558. MRxDAVDispatch.MRxSrvCallSize = 0;
  559. MRxDAVDispatch.MRxNetRootSize = 0;
  560. MRxDAVDispatch.MRxVNetRootSize = sizeof(WEBDAV_V_NET_ROOT);
  561. MRxDAVDispatch.MRxFcbSize = sizeof(WEBDAV_FCB);
  562. MRxDAVDispatch.MRxSrvOpenSize = sizeof(WEBDAV_SRV_OPEN);
  563. MRxDAVDispatch.MRxFobxSize = sizeof(WEBDAV_FOBX);
  564. //
  565. // Mini redirector cancel routine.
  566. //
  567. MRxDAVDispatch.MRxCancel = NULL;
  568. //
  569. // Mini redirector Start/Stop
  570. //
  571. MRxDAVDispatch.MRxStart = MRxDAVStart;
  572. MRxDAVDispatch.MRxStop = MRxDAVStop;
  573. MRxDAVDispatch.MRxDevFcbXXXControlFile = MRxDAVDevFcbXXXControlFile;
  574. //
  575. // Mini redirector name resolution
  576. //
  577. MRxDAVDispatch.MRxCreateSrvCall = MRxDAVCreateSrvCall;
  578. MRxDAVDispatch.MRxSrvCallWinnerNotify = MRxDAVSrvCallWinnerNotify;
  579. MRxDAVDispatch.MRxCreateVNetRoot = MRxDAVCreateVNetRoot;
  580. MRxDAVDispatch.MRxUpdateNetRootState = MRxDAVUpdateNetRootState;
  581. MRxDAVDispatch.MRxExtractNetRootName = MRxDAVExtractNetRootName;
  582. MRxDAVDispatch.MRxFinalizeSrvCall = MRxDAVFinalizeSrvCall;
  583. MRxDAVDispatch.MRxFinalizeNetRoot = MRxDAVFinalizeNetRoot;
  584. MRxDAVDispatch.MRxFinalizeVNetRoot = MRxDAVFinalizeVNetRoot;
  585. //
  586. // File System Object Creation/Deletion.
  587. //
  588. MRxDAVDispatch.MRxCreate = MRxDAVCreate;
  589. MRxDAVDispatch.MRxCollapseOpen = MRxDAVCollapseOpen;
  590. MRxDAVDispatch.MRxShouldTryToCollapseThisOpen = MRxDAVShouldTryToCollapseThisOpen;
  591. MRxDAVDispatch.MRxExtendForCache = MRxDAVExtendForCache;
  592. MRxDAVDispatch.MRxExtendForNonCache = MRxDAVExtendForNonCache;
  593. MRxDAVDispatch.MRxTruncate = MRxDAVTruncate;
  594. MRxDAVDispatch.MRxCleanupFobx = MRxDAVCleanupFobx;
  595. MRxDAVDispatch.MRxCloseSrvOpen = MRxDAVCloseSrvOpen;
  596. MRxDAVDispatch.MRxFlush = MRxDAVFlush;
  597. MRxDAVDispatch.MRxForceClosed = MRxDAVForcedClose;
  598. MRxDAVDispatch.MRxDeallocateForFcb = MRxDAVDeallocateForFcb;
  599. MRxDAVDispatch.MRxDeallocateForFobx = MRxDAVDeallocateForFobx;
  600. // MRxDAVDispatch.MRxIsLockRealizable = UMRxIsLockRealizable;
  601. //
  602. // File System Objects query/Set.
  603. //
  604. MRxDAVDispatch.MRxQueryDirectory = MRxDAVQueryDirectory;
  605. MRxDAVDispatch.MRxQueryVolumeInfo = MRxDAVQueryVolumeInformation;
  606. MRxDAVDispatch.MRxQueryEaInfo = MRxDAVQueryEaInformation;
  607. MRxDAVDispatch.MRxSetEaInfo = MRxDAVSetEaInformation;
  608. // MRxDAVDispatch.MRxQuerySdInfo = UMRxQuerySecurityInformation;
  609. // MRxDAVDispatch.MRxSetSdInfo = UMRxSetSecurityInformation;
  610. MRxDAVDispatch.MRxQueryFileInfo = MRxDAVQueryFileInformation;
  611. MRxDAVDispatch.MRxSetFileInfo = MRxDAVSetFileInformation;
  612. // MRxDAVDispatch.MRxSetFileInfoAtCleanup = UMRxSetFileInformationAtCleanup;
  613. MRxDAVDispatch.MRxIsValidDirectory= MRxDAVIsValidDirectory;
  614. //
  615. // Buffering state change.
  616. //
  617. MRxDAVDispatch.MRxComputeNewBufferingState = MRxDAVComputeNewBufferingState;
  618. //
  619. // File System Object I/O.
  620. //
  621. MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_READ] = MRxDAVRead;
  622. MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_WRITE] = MRxDAVWrite;
  623. // MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_SHAREDLOCK] = UMRxLocks;
  624. // MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_EXCLUSIVELOCK] = UMRxLocks;
  625. // MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_UNLOCK] = UMRxLocks;
  626. // MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_UNLOCK_MULTIPLE] = UMRxLocks;
  627. MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_FSCTL] = MRxDAVFsCtl;
  628. // MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_IOCTL] = UMRxIoCtl;
  629. //
  630. // Shouldn't flush come through lowio?
  631. //
  632. // MRxDAVDispatch.MRxLowIOSubmit[LOWIO_OP_NOTIFY_CHANGE_DIRECTORY] =
  633. // UMRxNotifyChangeDirectory;
  634. //
  635. // Miscellanous.
  636. //
  637. // MRxDAVDispatch.MRxCompleteBufferingStateChangeRequest =
  638. // UMRxCompleteBufferingStateChangeRequest;
  639. // initialize the mutex which protect the file info cache expire timer
  640. ExInitializeFastMutex(&MRxDAVFileInfoCacheLock);
  641. return;
  642. }
  643. NTSTATUS
  644. MRxDAVFsdDispatch(
  645. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  646. IN PIRP Irp
  647. )
  648. /*++
  649. Routine Description:
  650. This routine implements the FSD dispatch for the DAV miniredir.
  651. Arguments:
  652. RxDeviceObject - Supplies the device object for the packet being processed.
  653. Irp - Supplies the Irp being processed.
  654. Return Value:
  655. RXSTATUS - The Fsd status for the Irp
  656. --*/
  657. {
  658. NTSTATUS NtStatus = STATUS_SUCCESS;
  659. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  660. UCHAR MajorFunctionCode = IrpSp->MajorFunction;
  661. UCHAR MinorFunctionCode = IrpSp->MinorFunction;
  662. PFILE_OBJECT FileObject = IrpSp->FileObject;
  663. PWCHAR SaveInitialString = NULL;
  664. BOOL JustAServer = FALSE;
  665. ULONG IoControlCode = 0;
  666. PQUERY_PATH_REQUEST qpRequest = NULL;
  667. PWCHAR QueryPathBuffer = NULL;
  668. ULONG QueryPathBufferLength = 0; // Length in Bytes of QueryPathBuffer.
  669. KPROCESSOR_MODE ReqMode = 0;
  670. PAGED_CODE();
  671. //
  672. // Check if the PNP event indicating that the transports are ready has been
  673. // received. Till that time there is no point in forwarding requests to
  674. // the user mode agent since this could put WinInet in a wierd state.
  675. //
  676. if (!MRxDAVTransportReady) {
  677. DavDbgTrace(DAV_TRACE_ERROR,
  678. ("%ld: ERROR: MRxDAVFsdDispatch. MRxDAVTransportReady == FALSE\n",
  679. PsGetCurrentThreadId()));
  680. NtStatus = STATUS_REDIRECTOR_NOT_STARTED;
  681. goto COMPLETE_THE_REQUEST;
  682. }
  683. //
  684. // The first thing we need to check is whehter we got a DeviceIoControl
  685. // from MUP "IOCTL_REDIR_QUERY_PATH", to figure out if some UNC path is
  686. // owned by DAV or not. We need to check to see if the share supplied
  687. // in the path is one of the special SMB shares. These include PIPE, IPC$
  688. // and mailslot. If its one of these, then we reject the path at this stage
  689. // with a STATUS_BAD_NETOWRK_PATH response. This is better than rejecting
  690. // it at the creation of netroot becuase we save a network trip to the
  691. // server while creating the SrvCall.
  692. //
  693. try {
  694. if (MajorFunctionCode == IRP_MJ_DEVICE_CONTROL) {
  695. ReqMode = Irp->RequestorMode;
  696. //
  697. // Get the IoControlCode from IrpSp.
  698. //
  699. IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  700. //
  701. // If the IoControlCode is "IOCTL_REDIR_QUERY_PATH", we need to do the
  702. // following. We basically check to see if the request came down for
  703. // any of the special SMB shares. If it did, then we return.
  704. //
  705. if (IoControlCode == IOCTL_REDIR_QUERY_PATH) {
  706. PWCHAR QPPtr1 = NULL;
  707. BOOL FirstWack = TRUE, SpecialShare = FALSE;
  708. UNICODE_STRING UnicodeShareName, uniFileName;
  709. ULONG ShareNameLengthInBytes = 0;
  710. //
  711. // This particular IOCTL should only come to us from the MUP and
  712. // hence the requestor mode of the IRP should always be
  713. // KernelMode. If its not we return STATUS_INVALID_DEVICE_REQUEST.
  714. //
  715. if (ReqMode != KernelMode) {
  716. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  717. goto COMPLETE_THE_REQUEST;
  718. }
  719. qpRequest = METHODNEITHER_OriginalInputBuffer(IrpSp);
  720. //
  721. // If the requestor mode is not Kernel, we need to probe the buffer.
  722. // Probe the buffer that was supplied by the caller of the IOCTL to
  723. // make sure that its valid. This is to prevent hacker programs from
  724. // using this IOCTL to pass in invalid buffers.
  725. //
  726. if (ReqMode != KernelMode) {
  727. NtStatus = MRxDAVProbeForReadWrite((PBYTE)qpRequest, sizeof(QUERY_PATH_REQUEST), TRUE, FALSE);
  728. if (NtStatus != STATUS_SUCCESS) {
  729. DavDbgTrace(DAV_TRACE_ERROR,
  730. ("%ld: ERROR: MRxDAVFsdDispatch/MRxDAVProbeForReadWrite(1). "
  731. "NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  732. goto COMPLETE_THE_REQUEST;
  733. }
  734. }
  735. QueryPathBuffer = (PWCHAR)(qpRequest->FilePathName);
  736. ASSERT(QueryPathBuffer != NULL);
  737. QueryPathBufferLength = qpRequest->PathNameLength;
  738. //
  739. // If the requestor mode is not Kernel, we need to probe the buffer.
  740. // Probe the file name buffer (which is a part of the structure)
  741. // that was supplied by the caller of the IOCTL to make sure that
  742. // its valid.
  743. //
  744. if (ReqMode != KernelMode) {
  745. NtStatus = MRxDAVProbeForReadWrite((PBYTE)QueryPathBuffer, QueryPathBufferLength, TRUE, FALSE);
  746. if (NtStatus != STATUS_SUCCESS) {
  747. DavDbgTrace(DAV_TRACE_ERROR,
  748. ("%ld: ERROR: MRxDAVFsdDispatch/MRxDAVProbeForReadWrite(2). "
  749. "NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  750. goto COMPLETE_THE_REQUEST;
  751. }
  752. }
  753. DavDbgTrace(DAV_TRACE_DETAIL,
  754. ("%ld: MRxDAVFsdDispatch: Type3InputBuffer = %ws\n",
  755. PsGetCurrentThreadId(), QueryPathBuffer));
  756. //
  757. // The Type3InputBuffer is of the form \server\share or
  758. // \server\share\ or \server\share\path. We make the
  759. // QueryPathBuffer point to the char after the \ character.
  760. //
  761. QueryPathBuffer += 1;
  762. ASSERT(QueryPathBuffer != NULL);
  763. //
  764. // We subtract ( sizeof(WCHAR) ) from the buffer length because
  765. // the QueryPathBuffer points starting from the server name. It
  766. // skips the first WCHAR which is \.
  767. //
  768. QueryPathBufferLength -= sizeof(WCHAR);
  769. DavDbgTrace(DAV_TRACE_DETAIL,
  770. ("%ld: MRxDAVFsdDispatch: QueryPathBufferLength = %d\n",
  771. PsGetCurrentThreadId(), QueryPathBufferLength));
  772. //
  773. // If we just got a \ down from the MUP, then the value of
  774. // QueryPathBufferLength will now be zero since we have already
  775. // taken out 2 bytes above. We return right away in such a situation.
  776. //
  777. if (QueryPathBufferLength == 0) {
  778. NtStatus = STATUS_BAD_NETWORK_PATH;
  779. DavDbgTrace(DAV_TRACE_ERROR,
  780. ("%ld: ERROR: MRxDAVFsdDispatch: QueryPathBufferLength == 0\n",
  781. PsGetCurrentThreadId()));
  782. goto COMPLETE_THE_REQUEST;
  783. }
  784. //
  785. // The loop below is to set the start of the sharename and to
  786. // calculate the length of the sharename in bytes.
  787. //
  788. while (TRUE) {
  789. if ( *QueryPathBuffer == L'\\' ) {
  790. if (FirstWack) {
  791. QPPtr1 = QueryPathBuffer;
  792. FirstWack = FALSE;
  793. } else {
  794. break;
  795. }
  796. }
  797. if (!FirstWack) {
  798. ShareNameLengthInBytes += sizeof(WCHAR);
  799. }
  800. QueryPathBufferLength -= sizeof(WCHAR);
  801. if (QueryPathBufferLength == 0) {
  802. break;
  803. }
  804. QueryPathBuffer++;
  805. }
  806. //
  807. // If only a server name was specified then QPPrt1 will be NULL or
  808. // QPPtr1 will not be NULL but ShareNameLengthInBytes == sizeof(WCHAR).
  809. // QPPtr1 == NULL ==> \server
  810. // ShareNameLengthInBytes == sizeof(WCHAR) ==> \server\
  811. //
  812. if ( QPPtr1 == NULL || ShareNameLengthInBytes == sizeof(WCHAR) ) {
  813. NtStatus = STATUS_BAD_NETWORK_PATH;
  814. if (QPPtr1 == NULL) {
  815. DavDbgTrace(DAV_TRACE_ERROR,
  816. ("%ld: ERROR: MRxDAVFsdDispatch: QPPtr1 == NULL\n",
  817. PsGetCurrentThreadId()));
  818. } else {
  819. DavDbgTrace(DAV_TRACE_ERROR,
  820. ("%ld: ERROR: MRxDAVFsdDispatch: "
  821. "ShareNameLengthInBytes == sizeof(WCHAR)\n",
  822. PsGetCurrentThreadId()));
  823. }
  824. goto COMPLETE_THE_REQUEST;
  825. }
  826. DavDbgTrace(DAV_TRACE_DETAIL,
  827. ("%ld: MRxDAVFsdDispatch: QPPtr1 = %ws\n",
  828. PsGetCurrentThreadId(), QPPtr1));
  829. DavDbgTrace(DAV_TRACE_DETAIL,
  830. ("%ld: MRxDAVFsdDispatch: ShareNameLengthInBytes = %d\n",
  831. PsGetCurrentThreadId(), ShareNameLengthInBytes));
  832. //
  833. // Set the Unicode string. The OPPtr1 pointer points to the \ before
  834. // the share name. So if the path was \server\share\dir,
  835. // \server\share\dir
  836. // ^
  837. // |
  838. // QPPtr1
  839. // Accordingly, the ShareNameLengthInBytes contains an extra
  840. // sizeof(WCHAR) bytes for the \ char.
  841. //
  842. UnicodeShareName.Buffer = QPPtr1;
  843. UnicodeShareName.Length = (USHORT)ShareNameLengthInBytes;
  844. UnicodeShareName.MaximumLength = (USHORT)ShareNameLengthInBytes;
  845. //
  846. // We now take this name and see if it matches any of the special
  847. // SMB shares. If it does, we return STATUS_BAD_NETWORK_PATH.
  848. //
  849. SpecialShare = RtlEqualUnicodeString(&(UnicodeShareName),
  850. &(s_PipeShareName),
  851. TRUE);
  852. if (SpecialShare) {
  853. NtStatus = STATUS_BAD_NETWORK_PATH;
  854. DavDbgTrace(DAV_TRACE_DETAIL,
  855. ("%ld: ERROR: MRxDAVFsdDispatch: PIPE == TRUE\n",
  856. PsGetCurrentThreadId()));
  857. goto COMPLETE_THE_REQUEST;
  858. }
  859. SpecialShare = RtlEqualUnicodeString(&(UnicodeShareName),
  860. &(s_MailSlotShareName),
  861. TRUE);
  862. if (SpecialShare) {
  863. NtStatus = STATUS_BAD_NETWORK_PATH;
  864. DavDbgTrace(DAV_TRACE_DETAIL,
  865. ("%ld: ERROR: MRxDAVFsdDispatch: MAILSLOT == TRUE\n",
  866. PsGetCurrentThreadId()));
  867. goto COMPLETE_THE_REQUEST;
  868. }
  869. SpecialShare = RtlEqualUnicodeString(&(UnicodeShareName),
  870. &(s_IpcShareName),
  871. TRUE);
  872. if (SpecialShare) {
  873. NtStatus = STATUS_BAD_NETWORK_PATH;
  874. DavDbgTrace(DAV_TRACE_DETAIL,
  875. ("%ld: ERROR: MRxDAVFsdDispatch: IPC$ == TRUE\n",
  876. PsGetCurrentThreadId()));
  877. goto COMPLETE_THE_REQUEST;
  878. }
  879. //
  880. // Check whether we need to skip some files. See the explanation
  881. // below (in the function definition) for why IRPs are skipped.
  882. //
  883. uniFileName.Buffer=(PWCHAR)(qpRequest->FilePathName);
  884. uniFileName.Length = uniFileName.MaximumLength = (USHORT)(qpRequest->PathNameLength);
  885. if (MRxDAVSkipIrps(Irp, &uniFileName, TRUE) == STATUS_SUCCESS)
  886. {
  887. NtStatus = STATUS_BAD_NETWORK_PATH;
  888. DavDbgTrace(DAV_TRACE_DETAIL,
  889. ("%ld: ERROR: MRxDAVFsdDispatch: Skipped\n",
  890. PsGetCurrentThreadId()));
  891. goto COMPLETE_THE_REQUEST;
  892. }
  893. }
  894. }
  895. if (MajorFunctionCode == IRP_MJ_CREATE) {
  896. //
  897. // See the explanation below (in the function definition) for why
  898. // IRPs are skipped. Send the filename in the fileobject.
  899. //
  900. if (MRxDAVSkipIrps(Irp, &FileObject->FileName, FALSE) == STATUS_SUCCESS)
  901. {
  902. NtStatus = STATUS_BAD_NETWORK_PATH;
  903. DavDbgTrace(DAV_TRACE_DETAIL,
  904. ("%ld: ERROR: MRxDAVFsdDispatch: Skipped\n",
  905. PsGetCurrentThreadId()));
  906. goto COMPLETE_THE_REQUEST;
  907. }
  908. }
  909. } except (EXCEPTION_EXECUTE_HANDLER) {
  910. NtStatus = STATUS_INVALID_PARAMETER;
  911. DavDbgTrace(DAV_TRACE_ERROR,
  912. ("%ld: ERROR: MRxDAVFsdDispatch: Exception!!!\n",
  913. PsGetCurrentThreadId()));
  914. goto COMPLETE_THE_REQUEST;
  915. }
  916. //
  917. // Save the filename passed in by the I/O manager. This is freed up later.
  918. //
  919. if (FileObject) {
  920. SaveInitialString = FileObject->FileName.Buffer;
  921. }
  922. DavDbgTrace(DAV_TRACE_DETAIL,
  923. ("%ld: MRxDAVFsdDispatch. MajorFunction = %d, MinorFunction = %d"
  924. ", FileObject = %08lx.\n", PsGetCurrentThreadId(),
  925. MajorFunctionCode, MinorFunctionCode, FileObject));
  926. if (SaveInitialString) {
  927. ULONG MaxNameLengthInWChars = 0;
  928. MaxNameLengthInWChars = ( FileObject->FileName.Length / sizeof(WCHAR) );
  929. //
  930. // If the first and the second chars are '\'s, then its possible that
  931. // the name is just a \\server. Its possible that the name is of the
  932. // form \;X:0\path and hence we check for the second \ as well. So,
  933. // only if the first two chars are \ and \ we proceed to check whether
  934. // the create is just for just a server.
  935. //
  936. if ( MaxNameLengthInWChars >= 2 &&
  937. SaveInitialString[0] == L'\\' && SaveInitialString[1] == L'\\' ) {
  938. PWCHAR wcPtr1 = NULL;
  939. //
  940. // We assume that this is of the form \\server. If its not, then
  941. // this value is changed to FALSE below.
  942. //
  943. JustAServer = TRUE;
  944. //
  945. // Is the FileName just a server? Its possible that the FileName is
  946. // of the form \\server.
  947. //
  948. wcPtr1 = &(SaveInitialString[2]);
  949. //
  950. // If we have a '\' after the first two chars and atleast a single
  951. // char after that, it means that the name is not of the form
  952. // \\server or \\server\.
  953. //
  954. while ( (MaxNameLengthInWChars - 2) > 0 ) {
  955. if ( *wcPtr1 == L'\\' && *(wcPtr1 + 1) != L'\0' ) {
  956. JustAServer = FALSE;
  957. break;
  958. }
  959. MaxNameLengthInWChars--;
  960. wcPtr1++;
  961. }
  962. }
  963. }
  964. //
  965. // If JustAServer is TRUE then the network path name is invalid.
  966. //
  967. if (JustAServer) {
  968. NtStatus = STATUS_BAD_NETWORK_PATH;
  969. DavDbgTrace(DAV_TRACE_ERROR,
  970. ("%ld: ERROR: MRxDAVFsdDispatch: JustAServer == TRUE. SaveInitialString = %ws\n",
  971. PsGetCurrentThreadId(), SaveInitialString));
  972. goto COMPLETE_THE_REQUEST;
  973. }
  974. //
  975. // Call RxFsdDispatch.
  976. //
  977. NtStatus = RxFsdDispatch(RxDeviceObject, Irp);
  978. if (NtStatus != STATUS_SUCCESS && NtStatus != STATUS_PENDING) {
  979. DavDbgTrace(DAV_TRACE_DETAIL,
  980. ("%ld: Leaving MRxDAVFsdDispatch with NtStatus(2) = %08lx,"
  981. " FileObject = %08lx, MjFn = %d, MiFn = %d.\n",
  982. PsGetCurrentThreadId(), NtStatus, FileObject,
  983. MajorFunctionCode, MinorFunctionCode));
  984. }
  985. goto EXIT_THE_FUNCTION;
  986. COMPLETE_THE_REQUEST:
  987. //
  988. // We come here if we did not call into RDBSS and need to complete the
  989. // IRP ourselves.
  990. //
  991. Irp->IoStatus.Status = NtStatus;
  992. Irp->IoStatus.Information = 0;
  993. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  994. EXIT_THE_FUNCTION:
  995. return NtStatus;
  996. }
  997. VOID
  998. MRxDAVDeregisterAndCleanupDeviceObject(
  999. PUMRX_DEVICE_OBJECT UMRefDeviceObject
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. Note: The mutex is already acquired and we're already off the list.
  1004. Arguments:
  1005. UMRdrDeviceObject - The device object being deregistered and cleaned.
  1006. Return Value:
  1007. None.
  1008. --*/
  1009. {
  1010. NTSTATUS NtStatus = STATUS_SUCCESS;
  1011. PAGED_CODE();
  1012. DavDbgTrace(DAV_TRACE_DETAIL,
  1013. ("%ld: Entering MRxDAVDeregisterAndCleanupDeviceObject!!!!\n",
  1014. PsGetCurrentThreadId()));
  1015. DavDbgTrace(DAV_TRACE_CONTEXT,
  1016. ("%ld: MRxDAVDeregisterAndCleanupDeviceObject: "
  1017. "UMRefDeviceObject: %08lx.\n",
  1018. PsGetCurrentThreadId(), UMRefDeviceObject));
  1019. NtStatus = UMRxCleanUpDeviceObject(UMRefDeviceObject);
  1020. if (!NT_SUCCESS(NtStatus)) {
  1021. DavDbgTrace(DAV_TRACE_ERROR,
  1022. ("%ld: ERROR: MRxDAVDeregisterAndCleanupDeviceObject/"
  1023. "UMRxCleanUpDeviceObject: NtStatus = %08lx\n",
  1024. PsGetCurrentThreadId(), NtStatus));
  1025. }
  1026. RxUnregisterMinirdr(&UMRefDeviceObject->RxDeviceObject);
  1027. DavDbgTrace(DAV_TRACE_DETAIL,
  1028. ("%ld: Leaving MRxDAVDeregisterAndCleanupDeviceObject.\n",
  1029. PsGetCurrentThreadId()));
  1030. }
  1031. NTSTATUS
  1032. MRxDAVFlush(
  1033. IN OUT PRX_CONTEXT RxContext
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. This routine handles the "File Flush" requests.
  1038. Arguments:
  1039. RxContext - The context created by RDBSS.
  1040. Return Value:
  1041. NTSTATUS or the appropriate NT error code.
  1042. --*/
  1043. {
  1044. PAGED_CODE();
  1045. return STATUS_SUCCESS;
  1046. }
  1047. VOID
  1048. MRxDAVPnPBindingHandler(
  1049. IN TDI_PNP_OPCODE PnPOpcode,
  1050. IN PUNICODE_STRING pTransportName,
  1051. IN PWSTR BindingList
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. The TDI callbacks routine for binding changes.
  1056. Arguments:
  1057. PnPOpcode - The PNP op code.
  1058. pTransportName - The transport name.
  1059. BindingList - The binding order.
  1060. Return Value:
  1061. None.
  1062. --*/
  1063. {
  1064. PAGED_CODE();
  1065. switch (PnPOpcode) {
  1066. case TDI_PNP_OP_NETREADY: {
  1067. MRxDAVTransportReady = TRUE;
  1068. }
  1069. break;
  1070. default:
  1071. break;
  1072. }
  1073. return;
  1074. }
  1075. NTSTATUS
  1076. MRxDAVRegisterForPnpNotifications(
  1077. VOID
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. This routine registers with TDI for receiving transport notifications.
  1082. Arguments:
  1083. None.
  1084. Return Value:
  1085. The NTSTATUS code.
  1086. --*/
  1087. {
  1088. NTSTATUS NtStatus = STATUS_SUCCESS;
  1089. PAGED_CODE();
  1090. if ( MRxDAVTdiNotificationHandle == NULL ) {
  1091. UNICODE_STRING ClientName;
  1092. TDI_CLIENT_INTERFACE_INFO ClientInterfaceInfo;
  1093. RtlInitUnicodeString( &(ClientName), L"WebClient");
  1094. ClientInterfaceInfo.MajorTdiVersion = 2;
  1095. ClientInterfaceInfo.MinorTdiVersion = 0;
  1096. ClientInterfaceInfo.Unused = 0;
  1097. ClientInterfaceInfo.ClientName = &ClientName;
  1098. ClientInterfaceInfo.BindingHandler = MRxDAVPnPBindingHandler;
  1099. ClientInterfaceInfo.AddAddressHandler = NULL;
  1100. ClientInterfaceInfo.DelAddressHandler = NULL;
  1101. ClientInterfaceInfo.PnPPowerHandler = NULL;
  1102. NtStatus = TdiRegisterPnPHandlers ( &(ClientInterfaceInfo),
  1103. sizeof(ClientInterfaceInfo),
  1104. &(MRxDAVTdiNotificationHandle) );
  1105. }
  1106. return NtStatus;
  1107. }
  1108. NTSTATUS
  1109. MRxDAVDeregisterForPnpNotifications(
  1110. VOID
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. This routine deregisters the TDI notification mechanism.
  1115. Arguments:
  1116. None.
  1117. Return Value:
  1118. The NTSTATUS code.
  1119. --*/
  1120. {
  1121. NTSTATUS NtStatus = STATUS_SUCCESS;
  1122. PAGED_CODE();
  1123. if ( MRxDAVTdiNotificationHandle != NULL ) {
  1124. NtStatus = TdiDeregisterPnPHandlers( MRxDAVTdiNotificationHandle );
  1125. if( NT_SUCCESS( NtStatus ) ) {
  1126. MRxDAVTdiNotificationHandle = NULL;
  1127. }
  1128. }
  1129. return NtStatus;
  1130. }
  1131. NTSTATUS
  1132. MRxDAVProbeForReadWrite(
  1133. IN PBYTE BufferToBeValidated,
  1134. IN DWORD BufferSize,
  1135. IN BOOL doProbeForRead,
  1136. IN BOOL doProbeForWrite
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. This function probes the buffer that is supplied by the caller for read/write
  1141. access. This is done because the caller of an IOCTL might supply a invalid
  1142. buffer accessing which might cause a bugcheck.
  1143. Arguments:
  1144. BufferToBeValidated - The Buffer which has to be validated for read/write
  1145. access.
  1146. BufferSize - The size of the buffer being validated.
  1147. doProbeForRead - If TRUE, then probe the buffer for read.
  1148. doProbeForWrite - If TRUE, then probe the buffer for write.
  1149. Return Value:
  1150. STATUS_SUCCESS or STATUS_INVALID_USER_BUFFER.
  1151. --*/
  1152. {
  1153. NTSTATUS NtStatus = STATUS_SUCCESS;
  1154. PAGED_CODE();
  1155. //
  1156. // We call the functions ProbeForRead and ProbeForWrite in a try/except
  1157. // loop because these functions throw an exception if the buffer supplied
  1158. // is invalid. We catch the exception and set the appropriate NtStatus
  1159. // value.
  1160. //
  1161. try {
  1162. if (BufferToBeValidated != NULL) {
  1163. if (doProbeForRead) {
  1164. ProbeForRead(BufferToBeValidated, BufferSize, 1);
  1165. }
  1166. if (doProbeForWrite) {
  1167. ProbeForWrite(BufferToBeValidated, BufferSize, 1);
  1168. }
  1169. }
  1170. } except(EXCEPTION_EXECUTE_HANDLER) {
  1171. NtStatus = STATUS_INVALID_USER_BUFFER;
  1172. }
  1173. return NtStatus;
  1174. }
  1175. NTSTATUS
  1176. MRxDAVSkipIrps(
  1177. IN PIRP Irp,
  1178. IN PUNICODE_STRING fileName,
  1179. IN BOOL fCheckAny
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. This routine skips IRPs coming to the DAV redir which may cause deadlock.
  1184. Webdav's user mode component uses wininet to get to DAV servers. When a
  1185. service which is running this server process satisfying key wininet needs
  1186. makes a remote call we deadlock. The two such services are winsock and Sense.
  1187. When another service in the svchost which they are running under tries to do
  1188. a loadlibrary located on a remote machine (in our famous example of \\davis\
  1189. tools\ifsproxy.dll), loader APIs get invoked. These APis take the loader lock
  1190. and issue an NtQueryAttributes call. This call is translated into QUERY_PATH
  1191. ioctl by the MUP whci it send to all redirs, including webdav. Webdav refelcts
  1192. it up to the usermode and the webdav service issues wininet call to look for
  1193. the server (davis in the above example). Wininet issues a call to winsock to
  1194. makes a sockets call. This call ends up issuing an rpc to the NLA service in
  1195. another svchost which is the same svchost process that initiated the loadlibrary
  1196. call. The server now tries to take the loader lock and the webdav redir is now
  1197. deadlocked.
  1198. This scheme also protects us from looping back to ourselves because of
  1199. wininet's loadlibrary calls as webdav service also runs as part of an svchost.
  1200. This routine looks for the process issuing the irp to webdav and if it is an
  1201. svchost process and it is trying to look for a dll or an exe then we return it
  1202. as being not found. This implies that dlls and exes kept on a webdav server
  1203. cannot be loaded from svchosts till we get away from wininet.
  1204. Arguments:
  1205. Irp - The irp that came to webdav.
  1206. filename - Name of the file if any.
  1207. fCheckAny - If this is TRUE, then we reject this IRP if the process is
  1208. svchost.exe. If this is FALSE, then we only reject the IRP if
  1209. the filename has the extension dll or exe and the process is
  1210. svchost.exe.
  1211. Return Value:
  1212. STATUS_SUCCESS - Skip this IRP.
  1213. STATUS_UNSUCCESSFUL - Do not skip this IRP.
  1214. --*/
  1215. {
  1216. WCHAR ImageFileName[DAV_SVCHOST_NAME_SIZE]; //keep some reasonable stack space
  1217. ULONG UnicodeSize = 0;
  1218. UNICODE_STRING uniImageFileName;
  1219. UCHAR *pchImageFileName = PsGetProcessImageFileName(PsGetCurrentProcess());
  1220. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1221. PAGED_CODE();
  1222. RtlZeroMemory(ImageFileName, sizeof(ImageFileName));
  1223. RtlMultiByteToUnicodeN(ImageFileName, sizeof(ImageFileName), &UnicodeSize, pchImageFileName, 16);
  1224. uniImageFileName.Buffer = ImageFileName;
  1225. uniImageFileName.Length = uniImageFileName.MaximumLength = uniSvcHost.Length;
  1226. //
  1227. // Check whether the calling process is svchost.exe.
  1228. //
  1229. if (!RtlCompareUnicodeString(&uniImageFileName, &uniSvcHost, TRUE))
  1230. {
  1231. if (!fCheckAny)
  1232. {
  1233. UNICODE_STRING exe = { 3*sizeof(WCHAR), 3*sizeof(WCHAR), L"exe" };
  1234. UNICODE_STRING dll = { 3*sizeof(WCHAR), 3*sizeof(WCHAR), L"dll" };
  1235. UNICODE_STRING s;
  1236. //
  1237. // If the filename ends in .DLL or .exe, we return success, which will
  1238. // end up failing the operation.
  1239. //
  1240. if( fileName->Length > 4 * sizeof(WCHAR) &&
  1241. fileName->Buffer[ fileName->Length/sizeof(WCHAR) - 4 ] == L'.'){
  1242. s.Length = s.MaximumLength = 3 * sizeof( WCHAR );
  1243. s.Buffer = &fileName->Buffer[ (fileName->Length - s.Length)/sizeof(WCHAR) ];
  1244. if( RtlCompareUnicodeString( &s, &exe, TRUE ) == 0 ||
  1245. RtlCompareUnicodeString( &s, &dll, TRUE ) == 0 ) {
  1246. return STATUS_SUCCESS;
  1247. }
  1248. }
  1249. }
  1250. else
  1251. {
  1252. return STATUS_SUCCESS;
  1253. }
  1254. }
  1255. return STATUS_UNSUCCESSFUL;
  1256. }
  1257. VOID
  1258. MRxDAVInitializeTheTimeValues(
  1259. VOID
  1260. )
  1261. /*++
  1262. Routine Description:
  1263. This routine reads some time values (various timeout values, namecache etc.)
  1264. from the registry and initialized the corresponding global variables in the
  1265. driver. If a particular time value is not present in the registry, then it
  1266. is set to some default value. It also sets TimerThreadSleepTimeInSec to be
  1267. the minimum of all the operation timeout values.
  1268. Arguments:
  1269. None.
  1270. Return Value:
  1271. None.
  1272. --*/
  1273. {
  1274. NTSTATUS RegNtStatus = STATUS_SUCCESS;
  1275. PAGED_CODE();
  1276. //
  1277. // Read the name cache related timeout values.
  1278. //
  1279. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1280. NAME_CACHE_OBJ_GET_FILE_ATTRIB_LIFETIME,
  1281. &(FileInformationCacheLifeTimeInSec));
  1282. if (RegNtStatus != STATUS_SUCCESS) {
  1283. FileInformationCacheLifeTimeInSec = 60;
  1284. }
  1285. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1286. NAME_CACHE_OBJ_NAME_NOT_FOUND_LIFETIME,
  1287. &(FileNotFoundCacheLifeTimeInSec));
  1288. if (RegNtStatus != STATUS_SUCCESS) {
  1289. FileNotFoundCacheLifeTimeInSec = 60;
  1290. }
  1291. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1292. NAME_CACHE_NETROOT_MAX_ENTRIES,
  1293. &(NameCacheMaxEntries));
  1294. if (RegNtStatus != STATUS_SUCCESS) {
  1295. NameCacheMaxEntries = 300;
  1296. }
  1297. //
  1298. // Read the timeout values for the various operations. Set the value of
  1299. // TimerThreadSleepTimeInSec to be the minimum of all the timeout values.
  1300. //
  1301. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1302. CREATE_REQUEST_TIMEOUT_IN_SEC,
  1303. &(CreateRequestTimeoutValueInSec));
  1304. if (RegNtStatus != STATUS_SUCCESS) {
  1305. CreateRequestTimeoutValueInSec = (10 * 60);
  1306. }
  1307. TimerThreadSleepTimeInSec = CreateRequestTimeoutValueInSec;
  1308. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1309. CREATEVNETROOT_REQUEST_TIMEOUT_IN_SEC,
  1310. &(CreateVNetRootRequestTimeoutValueInSec));
  1311. if (RegNtStatus != STATUS_SUCCESS) {
  1312. CreateVNetRootRequestTimeoutValueInSec = 60;
  1313. }
  1314. if (CreateVNetRootRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1315. TimerThreadSleepTimeInSec = CreateVNetRootRequestTimeoutValueInSec;
  1316. }
  1317. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1318. QUERYDIRECTORY_REQUEST_TIMEOUT_IN_SEC,
  1319. &(QueryDirectoryRequestTimeoutValueInSec));
  1320. if (RegNtStatus != STATUS_SUCCESS) {
  1321. QueryDirectoryRequestTimeoutValueInSec = (10 * 60);
  1322. }
  1323. if (QueryDirectoryRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1324. TimerThreadSleepTimeInSec = QueryDirectoryRequestTimeoutValueInSec;
  1325. }
  1326. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1327. CLOSE_REQUEST_TIMEOUT_IN_SEC,
  1328. &(CloseRequestTimeoutValueInSec));
  1329. if (RegNtStatus != STATUS_SUCCESS) {
  1330. CloseRequestTimeoutValueInSec = (10 * 60);
  1331. }
  1332. if (CloseRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1333. TimerThreadSleepTimeInSec = CloseRequestTimeoutValueInSec;
  1334. }
  1335. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1336. CREATESRVCALL_REQUEST_TIMEOUT_IN_SEC,
  1337. &(CreateSrvCallRequestTimeoutValueInSec));
  1338. if (RegNtStatus != STATUS_SUCCESS) {
  1339. CreateSrvCallRequestTimeoutValueInSec = 60;
  1340. }
  1341. if (CreateSrvCallRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1342. TimerThreadSleepTimeInSec = CreateSrvCallRequestTimeoutValueInSec;
  1343. }
  1344. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1345. FINALIZESRVCALL_REQUEST_TIMEOUT_IN_SEC,
  1346. &(FinalizeSrvCallRequestTimeoutValueInSec));
  1347. if (RegNtStatus != STATUS_SUCCESS) {
  1348. FinalizeSrvCallRequestTimeoutValueInSec = (10 * 60);
  1349. }
  1350. if (FinalizeSrvCallRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1351. TimerThreadSleepTimeInSec = FinalizeSrvCallRequestTimeoutValueInSec;
  1352. }
  1353. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1354. FINALIZEFOBX_REQUEST_TIMEOUT_IN_SEC,
  1355. &(FinalizeFobxRequestTimeoutValueInSec));
  1356. if (RegNtStatus != STATUS_SUCCESS) {
  1357. FinalizeFobxRequestTimeoutValueInSec = (10 * 60);
  1358. }
  1359. if (FinalizeFobxRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1360. TimerThreadSleepTimeInSec = FinalizeFobxRequestTimeoutValueInSec;
  1361. }
  1362. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1363. FINALIZEVNETROOT_REQUEST_TIMEOUT_IN_SEC,
  1364. &(FinalizeVNetRootRequestTimeoutValueInSec));
  1365. if (RegNtStatus != STATUS_SUCCESS) {
  1366. FinalizeVNetRootRequestTimeoutValueInSec = (10 * 60);
  1367. }
  1368. if (FinalizeVNetRootRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1369. TimerThreadSleepTimeInSec = FinalizeVNetRootRequestTimeoutValueInSec;
  1370. }
  1371. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1372. RENAME_REQUEST_TIMEOUT_IN_SEC,
  1373. &(ReNameRequestTimeoutValueInSec));
  1374. if (RegNtStatus != STATUS_SUCCESS) {
  1375. ReNameRequestTimeoutValueInSec = (10 * 60);
  1376. }
  1377. if (ReNameRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1378. TimerThreadSleepTimeInSec = ReNameRequestTimeoutValueInSec;
  1379. }
  1380. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1381. SETFILEINFO_REQUEST_TIMEOUT_IN_SEC,
  1382. &(SetFileInfoRequestTimeoutValueInSec));
  1383. if (RegNtStatus != STATUS_SUCCESS) {
  1384. SetFileInfoRequestTimeoutValueInSec = (10 * 60);
  1385. }
  1386. if (SetFileInfoRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1387. TimerThreadSleepTimeInSec = SetFileInfoRequestTimeoutValueInSec;
  1388. }
  1389. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1390. QUERYFILEINFO_REQUEST_TIMEOUT_IN_SEC,
  1391. &(QueryFileInfoRequestTimeoutValueInSec));
  1392. if (RegNtStatus != STATUS_SUCCESS) {
  1393. QueryFileInfoRequestTimeoutValueInSec = (10 * 60);
  1394. }
  1395. if (QueryFileInfoRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1396. TimerThreadSleepTimeInSec = QueryFileInfoRequestTimeoutValueInSec;
  1397. }
  1398. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1399. QUERYVOLUMEINFO_REQUEST_TIMEOUT_IN_SEC,
  1400. &(QueryVolumeInfoRequestTimeoutValueInSec));
  1401. if (RegNtStatus != STATUS_SUCCESS) {
  1402. QueryVolumeInfoRequestTimeoutValueInSec = (10 * 60);
  1403. }
  1404. if (QueryVolumeInfoRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1405. TimerThreadSleepTimeInSec = QueryVolumeInfoRequestTimeoutValueInSec;
  1406. }
  1407. RegNtStatus = UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY,
  1408. LOCKREFRESH_REQUEST_TIMEOUT_IN_SEC,
  1409. &(LockRefreshRequestTimeoutValueInSec));
  1410. if (RegNtStatus != STATUS_SUCCESS) {
  1411. LockRefreshRequestTimeoutValueInSec = (10 * 60);
  1412. }
  1413. if (LockRefreshRequestTimeoutValueInSec < TimerThreadSleepTimeInSec) {
  1414. TimerThreadSleepTimeInSec = LockRefreshRequestTimeoutValueInSec;
  1415. }
  1416. // DbgPrint("MRxDAVInitializeTheTimeValues: TimerThreadSleepTimeInSec = %d\n", TimerThreadSleepTimeInSec);
  1417. //
  1418. // Initialize the debug tracing for the Mini-Redir.
  1419. //
  1420. #if DBG
  1421. UMRxReadDWORDFromTheRegistry(MRXDAV_DEBUG_KEY, MRXDAV_DEBUG_VALUE, &(MRxDavDebugVector));
  1422. #endif
  1423. return;
  1424. }