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.

1555 lines
52 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. devfcb.c
  5. Abstract:
  6. This module implements all ioctls and fsctls that can be applied to
  7. a device fcb.
  8. Author:
  9. Joe Linn
  10. Rohan Kumar [RohanK] 13-March-1999
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "fsctlbuf.h"
  15. #include "webdav.h"
  16. //
  17. // Mentioned below are the prototypes of functions tht are used only within
  18. // this module (file). These functions should not be exposed outside.
  19. //
  20. NTSTATUS
  21. MRxDAVOuterStart(
  22. IN PRX_CONTEXT RxContext
  23. );
  24. NTSTATUS
  25. MRxDAVOuterStop(
  26. IN PRX_CONTEXT RxContext
  27. );
  28. NTSTATUS
  29. MRxDAVDeleteConnection(
  30. IN PRX_CONTEXT RxContext,
  31. OUT PBOOLEAN PostToFsp
  32. );
  33. NTSTATUS
  34. MRxDavDeleteConnection(
  35. IN OUT PRX_CONTEXT RxContext
  36. );
  37. VOID
  38. MRxDAVGetLockOwnerFromFileName(
  39. IN PWEBDAV_DEVICE_OBJECT MRxDAVDeviceObject,
  40. IN OUT PWCHAR InputBuffer,
  41. IN ULONG InputBufferLength,
  42. OUT PWCHAR OutputBuffer,
  43. IN ULONG OutputBufferLength,
  44. OUT PIO_STATUS_BLOCK IoStatus
  45. );
  46. #ifdef ALLOC_PRAGMA
  47. #pragma alloc_text(PAGE, MRxDAVDevFcbXXXControlFile)
  48. #pragma alloc_text(PAGE, MRxDAVOuterStart)
  49. #pragma alloc_text(PAGE, MRxDAVStart)
  50. #pragma alloc_text(PAGE, MRxDAVOuterStop)
  51. #pragma alloc_text(PAGE, MRxDAVStop)
  52. #pragma alloc_text(PAGE, MRxDAVDeleteConnection)
  53. #pragma alloc_text(PAGE, MRxDAVFastIoDeviceControl)
  54. #pragma alloc_text(PAGE, MRxDAVFormatTheDAVContext)
  55. #pragma alloc_text(PAGE, MRxDavDeleteConnection)
  56. #endif
  57. //
  58. // Implementation of functions begins here.
  59. //
  60. NTSTATUS
  61. MRxDAVDevFcbXXXControlFile(
  62. IN OUT PRX_CONTEXT RxContext
  63. )
  64. /*++
  65. Routine Description:
  66. This routine handles all the device FCB related FSCTL's in the mini rdr.
  67. Arguments:
  68. RxContext - Describes the Fsctl and Context.
  69. Return Value:
  70. STATUS_SUCCESS - The Startup sequence was successfully completed. Any other
  71. value indicates the appropriate error in the startup
  72. sequence.
  73. --*/
  74. {
  75. NTSTATUS NtStatus = STATUS_SUCCESS;
  76. RxCaptureFobx;
  77. UCHAR MajorFunctionCode = RxContext->MajorFunction;
  78. PLOWIO_CONTEXT LowIoContext = &(RxContext->LowIoContext);
  79. UCHAR MinorFunctionCode = LowIoContext->ParamsFor.FsCtl.MinorFunction;
  80. ULONG ControlCode = LowIoContext->ParamsFor.FsCtl.FsControlCode;
  81. LUID LocalServiceLogonID = LOCALSERVICE_LUID, ClientLogonID;
  82. LUID SystemLogonID = SYSTEM_LUID;
  83. BOOLEAN IsInLocalServiceProcess = FALSE, IsInSystemProcess = FALSE;
  84. SECURITY_SUBJECT_CONTEXT ClientContext;
  85. PWEBDAV_DEVICE_OBJECT DavDeviceObject = NULL;
  86. PUMRX_DEVICE_OBJECT UMRefDeviceObject = NULL;
  87. PVOID OutputBuffer = NULL;
  88. PAGED_CODE();
  89. DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)(RxContext->RxDeviceObject);
  90. UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)&(DavDeviceObject->UMRefDeviceObject);
  91. DavDbgTrace(DAV_TRACE_DETAIL,
  92. ("%ld: Entering MRxDAVDevFcbXXXControlFile!!!!\n",
  93. PsGetCurrentThreadId()));
  94. DavDbgTrace(DAV_TRACE_CONTEXT,
  95. ("%ld: MRxDAVDevFcbXXXControlFile: RxContext: %08lx.\n",
  96. PsGetCurrentThreadId(), RxContext));
  97. DavDbgTrace(DAV_TRACE_DETAIL,
  98. ("%ld: MRxDAVDevFcbXXXControlFile: MajorFunctionCode = %d, MinorFunctionCode = %d, ControlCode = %08lx\n",
  99. PsGetCurrentThreadId(), MajorFunctionCode, MinorFunctionCode, ControlCode));
  100. SeCaptureSubjectContext( &(ClientContext) );
  101. SeLockSubjectContext( &(ClientContext) );
  102. NtStatus = SeQueryAuthenticationIdToken(SeQuerySubjectContextToken(&(ClientContext)),
  103. &(ClientLogonID));
  104. if (NtStatus == STATUS_SUCCESS) {
  105. IsInLocalServiceProcess = RtlEqualLuid( &(ClientLogonID), &(LocalServiceLogonID) );
  106. IsInSystemProcess = RtlEqualLuid( &(ClientLogonID), &(SystemLogonID) );
  107. } else {
  108. DavDbgTrace(DAV_TRACE_ERROR,
  109. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile/SeQueryAuthenticationIdToken: "
  110. "NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  111. }
  112. SeUnlockSubjectContext( &(ClientContext) );
  113. SeReleaseSubjectContext( &(ClientContext) );
  114. DavDbgTrace(DAV_TRACE_DETAIL,
  115. ("%ld: MRxDAVDevFcbXXXControlFile: IsInLocalServiceProcess = %d, IsInSystemProcess = %d\n",
  116. PsGetCurrentThreadId(), IsInLocalServiceProcess, IsInSystemProcess));
  117. DavDbgTrace(DAV_TRACE_DETAIL,
  118. ("%ld: MRxDAVDevFcbXXXControlFile: ClientLogonID.HighPart = %x, ClientLogonID.LowPart = %x\n",
  119. PsGetCurrentThreadId(), ClientLogonID.HighPart, ClientLogonID.LowPart));
  120. switch (MajorFunctionCode) {
  121. case IRP_MJ_FILE_SYSTEM_CONTROL: {
  122. switch (MinorFunctionCode) {
  123. case IRP_MN_USER_FS_REQUEST: {
  124. switch (ControlCode) {
  125. case FSCTL_UMRX_START:
  126. if (!IsInLocalServiceProcess && !IsInSystemProcess) {
  127. DavDbgTrace(DAV_TRACE_ERROR,
  128. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
  129. PsGetCurrentThreadId()));
  130. NtStatus = STATUS_ACCESS_DENIED;
  131. goto EXIT_THE_FUNCTION;
  132. }
  133. ASSERT (!capFobx);
  134. NtStatus = MRxDAVOuterStart(RxContext);
  135. break;
  136. case FSCTL_UMRX_STOP:
  137. if (!IsInLocalServiceProcess && !IsInSystemProcess) {
  138. DavDbgTrace(DAV_TRACE_ERROR,
  139. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile: !IsInLocalServiceProcess AND !IsInSystemProcess(2)\n",
  140. PsGetCurrentThreadId()));
  141. NtStatus = STATUS_ACCESS_DENIED;
  142. goto EXIT_THE_FUNCTION;
  143. }
  144. ASSERT (!capFobx);
  145. if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0) {
  146. return STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
  147. } else {
  148. NtStatus = MRxDAVOuterStop(RxContext);
  149. }
  150. break;
  151. case FSCTL_DAV_DELETE_CONNECTION:
  152. NtStatus = MRxDavDeleteConnection(RxContext);
  153. break;
  154. default:
  155. DavDbgTrace(DAV_TRACE_ERROR,
  156. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile: "
  157. "ControlCode = %d\n",
  158. PsGetCurrentThreadId(), ControlCode));
  159. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  160. break;
  161. }
  162. }
  163. break;
  164. default :
  165. DavDbgTrace(DAV_TRACE_ERROR,
  166. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile: "
  167. "MinorFunctionCode = %d\n",
  168. PsGetCurrentThreadId(), MinorFunctionCode));
  169. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  170. break;
  171. }
  172. }
  173. break;
  174. case IRP_MJ_DEVICE_CONTROL:
  175. case IRP_MJ_INTERNAL_DEVICE_CONTROL: {
  176. switch (ControlCode) {
  177. case IOCTL_UMRX_RELEASE_THREADS:
  178. if (!IsInLocalServiceProcess && !IsInSystemProcess) {
  179. DavDbgTrace(DAV_TRACE_ERROR,
  180. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
  181. PsGetCurrentThreadId()));
  182. NtStatus = STATUS_ACCESS_DENIED;
  183. goto EXIT_THE_FUNCTION;
  184. }
  185. UMRxReleaseCapturedThreads(UMRefDeviceObject);
  186. RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
  187. RxContext->CurrentIrp->IoStatus.Information = 0;
  188. NtStatus = STATUS_SUCCESS;
  189. break;
  190. case IOCTL_UMRX_GET_REQUEST:
  191. case IOCTL_UMRX_RESPONSE_AND_REQUEST:
  192. case IOCTL_UMRX_RESPONSE:
  193. if (!IsInLocalServiceProcess && !IsInSystemProcess) {
  194. DavDbgTrace(DAV_TRACE_ERROR,
  195. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
  196. PsGetCurrentThreadId()));
  197. NtStatus = STATUS_ACCESS_DENIED;
  198. goto EXIT_THE_FUNCTION;
  199. }
  200. //
  201. // The above IOCTLs are "METHOD_OUT_DIRECT" type.
  202. // The InputBuffer is stored at this location:
  203. // "RxContext->CurrentIrp->AssociatedIrp.SystemBuffer"
  204. // The OutputBuffer is an MDL stored at this location:
  205. // "RxContext->CurrentIrp->MdlAddress"
  206. //
  207. if (RxContext->CurrentIrp->MdlAddress != NULL) {
  208. OutputBuffer = MmGetSystemAddressForMdlSafe(RxContext->CurrentIrp->MdlAddress, LowPagePriority);
  209. if (OutputBuffer == NULL) {
  210. DavDbgTrace(DAV_TRACE_ERROR,
  211. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile/MmGetSystemAddressForMdlSafe\n",
  212. PsGetCurrentThreadId()));
  213. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  214. goto EXIT_THE_FUNCTION;
  215. }
  216. }
  217. UMRxAssignWork(UMRefDeviceObject,
  218. RxContext->CurrentIrp->AssociatedIrp.SystemBuffer,
  219. RxContext->CurrentIrpSp->Parameters.DeviceIoControl.InputBufferLength,
  220. OutputBuffer,
  221. RxContext->CurrentIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  222. &(RxContext->CurrentIrp->IoStatus));
  223. NtStatus = RxContext->CurrentIrp->IoStatus.Status;
  224. break;
  225. case IOCTL_UMRX_GET_LOCK_OWNER:
  226. MRxDAVGetLockOwnerFromFileName(DavDeviceObject,
  227. RxContext->CurrentIrp->AssociatedIrp.SystemBuffer,
  228. RxContext->CurrentIrpSp->Parameters.DeviceIoControl.InputBufferLength,
  229. RxContext->CurrentIrp->AssociatedIrp.SystemBuffer,
  230. RxContext->CurrentIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  231. &(RxContext->CurrentIrp->IoStatus));
  232. NtStatus = RxContext->CurrentIrp->IoStatus.Status;
  233. break;
  234. default :
  235. DavDbgTrace(DAV_TRACE_ERROR,
  236. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile: ControlCode = %d\n",
  237. PsGetCurrentThreadId(), ControlCode));
  238. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  239. break;
  240. }
  241. }
  242. break;
  243. default:
  244. DavDbgTrace(DAV_TRACE_ERROR,
  245. ("%ld: ERROR: MRxDAVDevFcbXXXControlFile: "
  246. "MajorFunction = %d\n",
  247. PsGetCurrentThreadId(), MajorFunctionCode));
  248. NtStatus = STATUS_INVALID_DEVICE_REQUEST;
  249. break;
  250. }
  251. EXIT_THE_FUNCTION:
  252. DavDbgTrace(DAV_TRACE_DETAIL,
  253. ("%ld: Leaving MRxDAVDevFcbXXXControlFile with NtStatus = "
  254. "%08lx.\n", PsGetCurrentThreadId(), NtStatus));
  255. //
  256. // This suppresses the second call to my lowio Fsctl routine.
  257. //
  258. RxContext->pFobx = NULL;
  259. return(NtStatus);
  260. }
  261. NTSTATUS
  262. MRxDAVOuterStart(
  263. IN PRX_CONTEXT RxContext
  264. )
  265. /*++
  266. Routine Description:
  267. This routine starts the Mini-Redir if it hasn't been started already.
  268. Arguments:
  269. RxContext - Describes the Fsctl and Context.
  270. Return Value:
  271. STATUS_SUCCESS or the appropriate error code.
  272. --*/
  273. {
  274. NTSTATUS NtStatus = STATUS_SUCCESS;
  275. PWEBDAV_DEVICE_OBJECT DavDeviceObject = NULL;
  276. PUMRX_DEVICE_OBJECT UMRefDeviceObject = NULL;
  277. PLOWIO_CONTEXT LowIoContext = NULL;
  278. PDAV_USERMODE_DATA DavUserModeData = NULL;
  279. ULONG DavUserModeDataLength = 0;
  280. PAGED_CODE();
  281. DavDbgTrace(DAV_TRACE_DETAIL,
  282. ("%ld: Entering MRxDAVOuterStart!!!!\n",
  283. PsGetCurrentThreadId()));
  284. DavDbgTrace(DAV_TRACE_CONTEXT,
  285. ("%ld: MRxDAVOuterStart: RxContext: %08lx.\n",
  286. PsGetCurrentThreadId(), RxContext));
  287. DavDbgTrace(DAV_TRACE_DETAIL,
  288. ("%ld: MRxDAVOuterStart: Try to Start the Mini-Redir\n",
  289. PsGetCurrentThreadId()));
  290. DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)(RxContext->RxDeviceObject);
  291. UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)&(DavDeviceObject->UMRefDeviceObject);
  292. LowIoContext= &(RxContext->LowIoContext);
  293. //
  294. // The WinInet cache path and the process id are stored in the input buffer
  295. // of the FSCTL.
  296. //
  297. DavUserModeData = (PDAV_USERMODE_DATA)LowIoContext->ParamsFor.FsCtl.pInputBuffer;
  298. ASSERT(DavUserModeData != NULL);
  299. DavUserModeDataLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
  300. ASSERT(DavUserModeDataLength == sizeof(DAV_USERMODE_DATA));
  301. //
  302. // Set the DeviceFcb, now that we have an RxContext.
  303. //
  304. DavDeviceObject->CachedRxDeviceFcb = RxContext->pFcb;
  305. //
  306. // We call ExAcquireFastMutexUnsafe instead of ExAcquireFastMutex because the
  307. // APCs have already been disabled by the FsrtlEnterFileSystem() call in the
  308. // RxFsdCommonDispatch function. This is done because a ExAcquireFastMutex
  309. // raises the IRQL level to APC_LEVEL (1) which is wrong since we are calling
  310. // into RxStartMiniRedir which calls FsrtlRegisterUncProvider which lands
  311. // up calling into the Dav MiniRedir again. If the IRQL level is raised here,
  312. // the MiniRedir will get called at a raised IRQL which is wrong.
  313. //
  314. ExAcquireFastMutexUnsafe( &(MRxDAVSerializationMutex) );
  315. try {
  316. if (DavDeviceObject->IsStarted) {
  317. DavDbgTrace(DAV_TRACE_DETAIL,
  318. ("%ld: MRxDAVOuterStart: Mini-Redir already started.\n",
  319. PsGetCurrentThreadId()));
  320. try_return(NtStatus = STATUS_REDIRECTOR_STARTED);
  321. }
  322. NtStatus = RxStartMinirdr(RxContext, &RxContext->PostRequest);
  323. if (NtStatus == STATUS_SUCCESS) {
  324. DavDeviceObject->IsStarted = TRUE;
  325. DavDbgTrace(DAV_TRACE_DETAIL,
  326. ("%ld: MRxDAVOuterStart: Mini-Redir started.\n",
  327. PsGetCurrentThreadId()));
  328. //
  329. // Copy the DavWinInetCachePath value into the global variable. This
  330. // value is used to satisy the volume relalted queries.
  331. //
  332. wcscpy(DavWinInetCachePath, DavUserModeData->WinInetCachePath);
  333. //
  334. // Copy the ProcessId of the svchost.exe process that loads the
  335. // webclnt.dll.
  336. //
  337. DavSvcHostProcessId = DavUserModeData->ProcessId;
  338. DavDbgTrace(DAV_TRACE_DETAIL,
  339. ("%ld: MRxDAVOuterStart: DavWinInetCachePath = %ws, DavSvcHostProcessId = %x\n",
  340. PsGetCurrentThreadId(), DavWinInetCachePath, DavSvcHostProcessId));
  341. //
  342. // Start the timer thread. This thread wakes up every few minutes
  343. // (RequestTimeoutValueInSec) and cancels all the requests that
  344. // have not completed for more than RequestTimeoutValueInSec.
  345. //
  346. NtStatus = PsCreateSystemThread(&(TimerThreadHandle),
  347. PROCESS_ALL_ACCESS,
  348. NULL,
  349. NULL,
  350. NULL,
  351. MRxDAVContextTimerThread,
  352. NULL);
  353. if (NtStatus != STATUS_SUCCESS) {
  354. DavDbgTrace(DAV_TRACE_ERROR,
  355. ("%ld: ERROR: MRxDAVOuterStart/PsCreateSystemThread: NtStatus"
  356. " = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  357. }
  358. } else {
  359. DavDbgTrace(DAV_TRACE_ERROR,
  360. ("%ld: ERROR: MRxDAVOuterStart/RxStartMinirdr: NtStatus"
  361. " = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  362. try_return(NtStatus);
  363. }
  364. try_exit: NOTHING;
  365. } finally {
  366. //
  367. // Since we called ExAcquireFastMutexUnsafe to acquire this mutex, we
  368. // call ExReleaseFastMutexUnsafe to release it.
  369. //
  370. ExReleaseFastMutexUnsafe( &(MRxDAVSerializationMutex) );
  371. }
  372. DavDbgTrace(DAV_TRACE_DETAIL,
  373. ("%ld: Leaving MRxDAVOuterStart with NtStatus = %08lx.\n",
  374. PsGetCurrentThreadId(), NtStatus));
  375. return(NtStatus);
  376. }
  377. NTSTATUS
  378. MRxDAVStart(
  379. PRX_CONTEXT RxContext,
  380. IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
  381. )
  382. /*++
  383. Routine Description:
  384. This routine completes the initialization of the mini redirector fromn the
  385. RDBSS perspective. Note that this is different from the initialization done
  386. in DriverEntry. Any initialization that depends on RDBSS should be done as
  387. part of this routine while the initialization that is independent of RDBSS
  388. should be done in the DriverEntry routine.
  389. Arguments:
  390. RxContext - Supplies the Irp that was used to startup the rdbss
  391. Return Value:
  392. RXSTATUS - The return status for the operation
  393. --*/
  394. {
  395. NTSTATUS NtStatus = STATUS_SUCCESS;
  396. PAGED_CODE();
  397. return NtStatus;
  398. }
  399. NTSTATUS
  400. MRxDAVOuterStop(
  401. IN PRX_CONTEXT RxContext
  402. )
  403. /*++
  404. Routine Description:
  405. This routine stops the Mini-Redir if it has been started.
  406. Arguments:
  407. RxContext - Describes the Fsctl and Context.
  408. Return Value:
  409. STATUS_SUCCESS or the appropriate error code.
  410. --*/
  411. {
  412. NTSTATUS NtStatus = STATUS_SUCCESS;
  413. PWEBDAV_DEVICE_OBJECT DavDeviceObject = NULL;
  414. PUMRX_DEVICE_OBJECT UMRefDeviceObject = NULL;
  415. PVOID HeapHandle = NULL;
  416. PLIST_ENTRY pFirstListEntry = NULL;
  417. PUMRX_SHARED_HEAP sharedHeap = NULL;
  418. BOOLEAN TimerState = FALSE;
  419. PAGED_CODE();
  420. DavDbgTrace(DAV_TRACE_DETAIL,
  421. ("%ld: Entering MRxDAVOuterStop!!!!\n",
  422. PsGetCurrentThreadId()));
  423. DavDbgTrace(DAV_TRACE_CONTEXT,
  424. ("%ld: MRxDAVOuterStop: RxContext: %08lx.\n",
  425. PsGetCurrentThreadId(), RxContext));
  426. DavDbgTrace(DAV_TRACE_DETAIL,
  427. ("%ld: MRxDAVOuterStop: Try to Stop the Mini-Redir.\n",
  428. PsGetCurrentThreadId()));
  429. DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)(RxContext->RxDeviceObject);
  430. UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)&(DavDeviceObject->UMRefDeviceObject);
  431. //
  432. // Tell the timer thread that its time to shutdown to its job is done.
  433. //
  434. ExAcquireResourceExclusiveLite(&(MRxDAVTimerThreadLock), TRUE);
  435. if (!TimerThreadShutDown) {
  436. TimerThreadShutDown = TRUE;
  437. //
  438. // Read the state of the timer. If its NOT signalled, call KeSetTimerEx
  439. // with 0 DueTime (2nd argument) to signal it.
  440. //
  441. TimerState = KeReadStateTimer( &(DavTimerObject) );
  442. if (!TimerState) {
  443. LARGE_INTEGER TimeOutNow;
  444. TimeOutNow.QuadPart = 0;
  445. KeSetTimerEx(&(DavTimerObject), TimeOutNow, 0, NULL);
  446. }
  447. ExReleaseResourceLite(&(MRxDAVTimerThreadLock));
  448. //
  449. // We now call MRxDAVCleanUpTheLockConflictList to free up all the
  450. // entries from the global LockConflictEntryList.
  451. //
  452. MRxDAVCleanUpTheLockConflictList(TRUE);
  453. //
  454. // Complete all the currently active contexts.
  455. //
  456. MRxDAVTimeOutTheContexts(TRUE);
  457. } else {
  458. //
  459. // If we have already shutdown the timer thread, then we don't need to
  460. // do it again. Just release the resource and move on.
  461. //
  462. ExReleaseResourceLite(&(MRxDAVTimerThreadLock));
  463. }
  464. //
  465. // Free the list of shared memory heaps. This has to happen in the context
  466. // of the DAV's usermode process. It cannot happen at Unload time since
  467. // unload happens in the context of a system thread.
  468. //
  469. while (!IsListEmpty(&UMRefDeviceObject->SharedHeapList)) {
  470. pFirstListEntry = RemoveHeadList(&UMRefDeviceObject->SharedHeapList);
  471. sharedHeap = (PUMRX_SHARED_HEAP) CONTAINING_RECORD(pFirstListEntry,
  472. UMRX_SHARED_HEAP,
  473. HeapListEntry);
  474. DavDbgTrace(DAV_TRACE_DETAIL,
  475. ("%ld: MRxDAVOuterStop: sharedHeap: %08lx.\n",
  476. PsGetCurrentThreadId(), sharedHeap));
  477. // ASSERT(sharedHeap->HeapAllocationCount == 0);
  478. HeapHandle = RtlDestroyHeap(sharedHeap->Heap);
  479. if (HeapHandle != NULL) {
  480. DavDbgTrace(DAV_TRACE_ERROR,
  481. ("%ld: ERROR: MRxDAVOuterStop/RtlDestroyHeap.\n",
  482. PsGetCurrentThreadId()));
  483. }
  484. ZwFreeVirtualMemory(NtCurrentProcess(),
  485. &sharedHeap->VirtualMemoryBuffer,
  486. &sharedHeap->VirtualMemoryLength,
  487. MEM_RELEASE);
  488. RxFreePool(sharedHeap);
  489. }
  490. //
  491. // We call ExAcquireFastMutexUnsafe instead of ExAcquireFastMutex because the
  492. // APCs have already been disabled by the FsrtlEnterFileSystem() call in the
  493. // RxFsdCommonDispatch function. This is done because a ExAcquireFastMutex
  494. // raises the IRQL level to APC_LEVEL (1) which is wrong since we are calling
  495. // into RxStartMiniRedir which calls FsrtlRegisterUncProvider which lands
  496. // up calling into the Dav MiniRedir again. If the IRQL level is raised here,
  497. // the MiniRedir will get called at a raised IRQL which is wrong.
  498. //
  499. ExAcquireFastMutexUnsafe(&MRxDAVSerializationMutex);
  500. try {
  501. if (!DavDeviceObject->IsStarted) {
  502. DavDbgTrace(DAV_TRACE_DETAIL,
  503. ("%ld: MRxDAVOuterStop: Mini-Redir not started.\n",
  504. PsGetCurrentThreadId()));
  505. try_return(NtStatus = STATUS_REDIRECTOR_NOT_STARTED);
  506. }
  507. NtStatus = RxStopMinirdr(RxContext, &RxContext->PostRequest);
  508. if (NtStatus == STATUS_SUCCESS) {
  509. DavDeviceObject->IsStarted = FALSE;
  510. DavDbgTrace(DAV_TRACE_DETAIL,
  511. ("%ld: MRxDAVOuterStop: Mini-Redir stopped.\n",
  512. PsGetCurrentThreadId()));
  513. } else {
  514. DavDbgTrace(DAV_TRACE_ERROR,
  515. ("%ld: ERROR: MRxDAVOuterStop/RxStopMinirdr: NtStatus"
  516. " = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  517. try_return(NtStatus);
  518. }
  519. try_exit: NOTHING;
  520. } finally {
  521. //
  522. // Since we called ExAcquireFastMutexUnsafe to acquire this mutex, we
  523. // call ExReleaseFastMutexUnsafe to release it.
  524. //
  525. ExReleaseFastMutexUnsafe(&MRxDAVSerializationMutex);
  526. }
  527. DavDbgTrace(DAV_TRACE_DETAIL,
  528. ("%ld: Leaving MRxDAVOuterStop with NtStatus = %08lx.\n",
  529. PsGetCurrentThreadId(), NtStatus));
  530. return(NtStatus);
  531. }
  532. NTSTATUS
  533. MRxDAVStop(
  534. PRX_CONTEXT RxContext,
  535. IN OUT PRDBSS_DEVICE_OBJECT RxDeviceObject
  536. )
  537. /*++
  538. Routine Description:
  539. This routine is used to activate the mini redirector from the RDBSS perspective
  540. Arguments:
  541. RxContext - the context that was used to start the mini redirector
  542. Return Value:
  543. RXSTATUS - The return status for the operation
  544. --*/
  545. {
  546. NTSTATUS NtStatus = STATUS_SUCCESS;
  547. PAGED_CODE();
  548. return NtStatus;
  549. }
  550. NTSTATUS
  551. MRxDAVDeleteConnection(
  552. IN PRX_CONTEXT RxContext,
  553. OUT PBOOLEAN PostToFsp
  554. )
  555. /*++
  556. Routine Description:
  557. This routine deletes a single vnetroot.
  558. Arguments:
  559. IN PRX_CONTEXT RxContext - Describes the Fsctl and Context....for later when i need the buffers
  560. Return Value:
  561. RXSTATUS
  562. --*/
  563. {
  564. NTSTATUS Status;
  565. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  566. RxCaptureFobx;
  567. BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
  568. PNET_ROOT NetRoot;
  569. PV_NET_ROOT VNetRoot;
  570. PAGED_CODE();
  571. if (!Wait) {
  572. *PostToFsp = TRUE;
  573. return(STATUS_PENDING);
  574. }
  575. try {
  576. if (NodeType(capFobx)==RDBSS_NTC_V_NETROOT) {
  577. VNetRoot = (PV_NET_ROOT)capFobx;
  578. NetRoot = (PNET_ROOT)VNetRoot->NetRoot;
  579. } else {
  580. ASSERT(FALSE);
  581. try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
  582. NetRoot = (PNET_ROOT)capFobx;
  583. VNetRoot = NULL;
  584. }
  585. Status = RxFinalizeConnection(NetRoot,VNetRoot,TRUE);
  586. try_return(Status);
  587. try_exit:NOTHING;
  588. } finally {
  589. RxDbgTraceUnIndent(-1,Dbg);
  590. }
  591. return Status;
  592. }
  593. BOOLEAN
  594. MRxDAVFastIoDeviceControl(
  595. IN struct _FILE_OBJECT *FileObject,
  596. IN BOOLEAN Wait,
  597. IN PVOID InputBuffer OPTIONAL,
  598. IN ULONG InputBufferLength,
  599. OUT PVOID OutputBuffer OPTIONAL,
  600. IN ULONG OutputBufferLength,
  601. IN ULONG IoControlCode,
  602. OUT PIO_STATUS_BLOCK IoStatus,
  603. IN struct _DEVICE_OBJECT *DeviceObject
  604. )
  605. /*++
  606. Routine Description:
  607. This routine handles the Fast I/O path of the WebDav miniredir.
  608. Arguments:
  609. FileObject - The file object of the file involved in the I/O request.
  610. Wait -
  611. InputBuffer - Buffer which holds the inputs for the I/O request.
  612. InputBufferLength - Length of the InputBuffer.
  613. OutputBuffer - Where the results of the I/O request are placed.
  614. OutputBufferLength - Length of the OutputBuffer.
  615. IoControlCode - The controlcode describing the I/O to be done.
  616. IoStatus - The results of the assignment.
  617. DeviceObject - The device object which handles the I/O request.
  618. Return Value:
  619. TRUE - The I/O operation was handled and FALSE otherwise.
  620. --*/
  621. {
  622. NTSTATUS NtStatus = STATUS_SUCCESS;
  623. PWEBDAV_DEVICE_OBJECT DavDeviceObject = (PWEBDAV_DEVICE_OBJECT)DeviceObject;
  624. PUMRX_DEVICE_OBJECT UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)DeviceObject;
  625. LUID LocalServiceLogonID = LOCALSERVICE_LUID, ClientLogonID;
  626. LUID SystemLogonID = SYSTEM_LUID;
  627. BOOLEAN IsInLocalServiceProcess = FALSE, IsInSystemProcess = FALSE;
  628. SECURITY_SUBJECT_CONTEXT ClientContext;
  629. PAGED_CODE();
  630. DavDbgTrace(DAV_TRACE_DETAIL,
  631. ("%ld: Entering MRxDAVFastIoDeviceControl. IoControlCode = %08lx\n",
  632. PsGetCurrentThreadId(), IoControlCode));
  633. if (FileObject->FsContext != DavDeviceObject->CachedRxDeviceFcb) {
  634. DavDbgTrace(DAV_TRACE_ERROR,
  635. ("%ld: ERROR: MRxDAVFastIoDeviceControl: Wrong DeviceFcb!!\n",
  636. PsGetCurrentThreadId()));
  637. return FALSE;
  638. }
  639. SeCaptureSubjectContext( &(ClientContext) );
  640. SeLockSubjectContext( &(ClientContext) );
  641. NtStatus = SeQueryAuthenticationIdToken(SeQuerySubjectContextToken(&(ClientContext)),
  642. &(ClientLogonID));
  643. if (NtStatus == STATUS_SUCCESS) {
  644. IsInLocalServiceProcess = RtlEqualLuid( &(ClientLogonID), &(LocalServiceLogonID) );
  645. IsInSystemProcess = RtlEqualLuid( &(ClientLogonID), &(SystemLogonID) );
  646. } else {
  647. DavDbgTrace(DAV_TRACE_ERROR,
  648. ("%ld: ERROR: MRxDAVFastIoDeviceControl/SeQueryAuthenticationIdToken: "
  649. "NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  650. }
  651. SeUnlockSubjectContext( &(ClientContext) );
  652. SeReleaseSubjectContext( &(ClientContext) );
  653. //
  654. // It's the right kind of fileobject. Go for it.
  655. //
  656. switch (IoControlCode) {
  657. case IOCTL_UMRX_RELEASE_THREADS:
  658. if (!IsInLocalServiceProcess && !IsInSystemProcess) {
  659. DavDbgTrace(DAV_TRACE_ERROR,
  660. ("%ld: ERROR: MRxDAVFastIoDeviceControl: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
  661. PsGetCurrentThreadId()));
  662. IoStatus->Status = STATUS_ACCESS_DENIED;
  663. IoStatus->Information = 0;
  664. return (FALSE);
  665. }
  666. UMRxReleaseCapturedThreads(UMRefDeviceObject);
  667. IoStatus->Status = STATUS_SUCCESS;
  668. IoStatus->Information = 0;
  669. return (TRUE);
  670. case IOCTL_UMRX_GET_REQUEST:
  671. case IOCTL_UMRX_RESPONSE_AND_REQUEST:
  672. case IOCTL_UMRX_RESPONSE:
  673. if (!IsInLocalServiceProcess && !IsInSystemProcess) {
  674. DavDbgTrace(DAV_TRACE_ERROR,
  675. ("%ld: ERROR: MRxDAVFastIoDeviceControl: !IsInLocalServiceProcess AND !IsInSystemProcess(1)\n",
  676. PsGetCurrentThreadId()));
  677. IoStatus->Status = STATUS_ACCESS_DENIED;
  678. IoStatus->Information = 0;
  679. return (FALSE);
  680. }
  681. UMRxAssignWork(UMRefDeviceObject,
  682. InputBuffer,
  683. InputBufferLength,
  684. OutputBuffer,
  685. OutputBufferLength,
  686. IoStatus);
  687. return(TRUE);
  688. case IOCTL_UMRX_GET_LOCK_OWNER:
  689. //
  690. // Validate the InputBuffer sent by the application.
  691. //
  692. try {
  693. ProbeForRead(InputBuffer, InputBufferLength, sizeof(UCHAR));
  694. } except (EXCEPTION_EXECUTE_HANDLER) {
  695. DavDbgTrace(DAV_TRACE_ERROR,
  696. ("%ld: ERROR: MRxDAVFastIoDeviceControl. STATUS_INVALID_USER_BUFFER(1)\n",
  697. PsGetCurrentThreadId()));
  698. IoStatus->Status = STATUS_INVALID_USER_BUFFER;
  699. IoStatus->Information = 0;
  700. return (FALSE);
  701. }
  702. //
  703. // Validate the OutputBuffer sent by the application.
  704. //
  705. try {
  706. ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(UCHAR));
  707. } except (EXCEPTION_EXECUTE_HANDLER) {
  708. DavDbgTrace(DAV_TRACE_ERROR,
  709. ("%ld: ERROR: MRxDAVFastIoDeviceControl. STATUS_INVALID_USER_BUFFER(2)\n",
  710. PsGetCurrentThreadId()));
  711. IoStatus->Status = STATUS_INVALID_USER_BUFFER;
  712. IoStatus->Information = 0;
  713. return (FALSE);
  714. }
  715. MRxDAVGetLockOwnerFromFileName(DavDeviceObject,
  716. InputBuffer,
  717. InputBufferLength,
  718. OutputBuffer,
  719. OutputBufferLength,
  720. IoStatus);
  721. return(TRUE);
  722. default:
  723. break;
  724. }
  725. //
  726. // The I/O operation could not be handled.
  727. //
  728. return(FALSE);
  729. }
  730. NTSTATUS
  731. MRxDAVFormatTheDAVContext(
  732. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  733. USHORT EntryPoint
  734. )
  735. /*++
  736. Routine Description:
  737. This routine formats the DAV Mini-Redir portion of the context.
  738. Arguments:
  739. AsyncEngineContext - The Reflector's context.
  740. EntryPoint - The operation being performed.
  741. Return Value:
  742. none.
  743. --*/
  744. {
  745. NTSTATUS NtStatus = STATUS_SUCCESS;
  746. PWEBDAV_CONTEXT DavContext = (PWEBDAV_CONTEXT)AsyncEngineContext;
  747. PRX_CONTEXT RxContext = AsyncEngineContext->RxContext;
  748. PNT_CREATE_PARAMETERS NtCP = &(RxContext->Create.NtCreateParameters);
  749. PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = NULL;
  750. PMRX_SRV_CALL SrvCall = NULL;
  751. PWEBDAV_SRV_CALL DavSrvCall = NULL;
  752. PMRX_V_NET_ROOT VNetRoot = NULL;
  753. PWEBDAV_V_NET_ROOT DavVNetRoot = NULL;
  754. PSECURITY_CLIENT_CONTEXT SecClnCtx = NULL;
  755. BOOL AlreadyInitialized = FALSE, SecurityClientContextCreated = FALSE;
  756. SECURITY_QUALITY_OF_SERVICE SecurityQos;
  757. PSECURITY_SUBJECT_CONTEXT SecSubCtx = NULL;
  758. PSECURITY_QUALITY_OF_SERVICE SecQOS = NULL;
  759. PAGED_CODE();
  760. DavDbgTrace(DAV_TRACE_DETAIL,
  761. ("%ld: Entering MRxDAVFormatTheDAVContext!!!!\n",
  762. PsGetCurrentThreadId()));
  763. DavDbgTrace(DAV_TRACE_CONTEXT,
  764. ("%ld: MRxDAVFormatTheDAVContext: AsyncEngineContext: %08lx, "
  765. "EntryPoint: %d.\n", PsGetCurrentThreadId(),
  766. AsyncEngineContext, EntryPoint));
  767. ASSERT(DavContext != NULL);
  768. ASSERT(RxContext != NULL);
  769. //
  770. // Set the EntryPoint field. If this is not a Create operation, we can
  771. // return.
  772. //
  773. DavContext->EntryPoint = EntryPoint;
  774. if (EntryPoint != DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL &&
  775. EntryPoint != DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT) {
  776. return NtStatus;
  777. }
  778. //
  779. // Since this is a create call, get the client's security context. This is
  780. // used to impersonate the client before sending the requests to the server.
  781. //
  782. if ( NtCP->SecurityContext != NULL &&
  783. NtCP->SecurityContext->AccessState != NULL ) {
  784. //
  785. // Check whether its a CreateSrvCall call or a CreateVNetRoot call.
  786. //
  787. if ( EntryPoint != DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL ) {
  788. //
  789. // This is s CreateVNetRoot call.
  790. //
  791. ASSERT(EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT);
  792. DavDbgTrace(DAV_TRACE_DETAIL,
  793. ("%ld: MRxDAVFormatTheDAVContext. CreateVNetRoot.\n",
  794. PsGetCurrentThreadId()));
  795. //
  796. // The VNetRoot pointer is stored in the MRxContext[1] pointer of the
  797. // RxContext structure. This is done in the MRxDAVCreateVNetRoot function.
  798. //
  799. VNetRoot = RxContext->MRxContext[1];
  800. DavDbgTrace(DAV_TRACE_DETAIL,
  801. ("%ld: MRxDAVFormatTheDAVContext. VNetRoot = %08lx\n",
  802. PsGetCurrentThreadId(), VNetRoot));
  803. //
  804. // The context pointer of the V_NET_ROOT already points to a blob of
  805. // memory, the size of which is sizeof(WEBDAV_V_NET_ROOT). This
  806. // should never be NULL.
  807. //
  808. DavVNetRoot = MRxDAVGetVNetRootExtension(VNetRoot);
  809. if(DavVNetRoot == NULL) {
  810. ASSERT(FALSE);
  811. goto EXIT_THE_FUNCTION;
  812. }
  813. SecClnCtx = &(DavVNetRoot->SecurityClientContext);
  814. //
  815. // Only need to initialize on the first create call by the user.
  816. //
  817. if (DavVNetRoot->SCAlreadyInitialized) {
  818. AlreadyInitialized = TRUE;
  819. }
  820. } else {
  821. //
  822. // This is a CreateSrvCall call.
  823. //
  824. ASSERT(EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL);
  825. DavDbgTrace(DAV_TRACE_DETAIL,
  826. ("%ld: MRxDAVFormatTheDAVContext. CreateSrvCall.\n",
  827. PsGetCurrentThreadId()));
  828. //
  829. // The SrvCall pointer is stored in the SCCBC structure which is
  830. // stored in the MRxContext[1] pointer of the RxContext structure.
  831. // This is done in the MRxDAVCreateSrvCall function.
  832. //
  833. ASSERT(RxContext->MRxContext[1] != NULL);
  834. SCCBC = (PMRX_SRVCALL_CALLBACK_CONTEXT)RxContext->MRxContext[1];
  835. SrvCall = SCCBC->SrvCalldownStructure->SrvCall;
  836. ASSERT(SrvCall != NULL);
  837. DavSrvCall = MRxDAVGetSrvCallExtension(SrvCall);
  838. ASSERT(DavSrvCall != NULL);
  839. //
  840. // At this time, we don't have a V_NET_ROOT and hence cannot store
  841. // the SecurityClientContext. We just use MRxContext[2] of RxContext
  842. // to pass the SecurityClientContext.
  843. //
  844. SecClnCtx = RxAllocatePoolWithTag(NonPagedPool,
  845. sizeof(SECURITY_CLIENT_CONTEXT),
  846. DAV_SRVCALL_POOLTAG);
  847. if (SecClnCtx == NULL) {
  848. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  849. DavDbgTrace(DAV_TRACE_ERROR,
  850. ("%ld: ERROR: MRxDAVFormatTheDAVContext/RxAllocatePoolWithTag.\n",
  851. PsGetCurrentThreadId()));
  852. goto EXIT_THE_FUNCTION;
  853. }
  854. ASSERT(RxContext->MRxContext[2] == NULL);
  855. RxContext->MRxContext[2] = (PVOID)SecClnCtx;
  856. }
  857. if (!AlreadyInitialized) {
  858. SecSubCtx = &(NtCP->SecurityContext->AccessState->SubjectSecurityContext);
  859. SecQOS = ( (NtCP->SecurityContext->SecurityQos) ?
  860. (NtCP->SecurityContext->SecurityQos) : &(SecurityQos) );
  861. //
  862. // If the user did not specify the security QOS structure, create
  863. // one. We set the value of SecurityQos.EffectiveOnly to FALSE
  864. // to keep the privilege so that we can do certain operations
  865. // later on. This is specifically needed for the EFS operations.
  866. // If set to TRUE, any privilege not enabled at this time will be
  867. // lost. In the EFS case, the "restore" privilege is lost.
  868. //
  869. if (NtCP->SecurityContext->SecurityQos == NULL) {
  870. SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  871. SecurityQos.ImpersonationLevel = DEFAULT_IMPERSONATION_LEVEL;
  872. SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  873. SecurityQos.EffectiveOnly = FALSE;
  874. }
  875. //
  876. // This call sets the SecurityClientContext of the user. This is
  877. // stored in the V_NET_ROOT since its a per user thing. This
  878. // strucutre is used later on in impersonating the client that
  879. // issued the I/O request.
  880. //
  881. NtStatus = SeCreateClientSecurityFromSubjectContext(SecSubCtx,
  882. SecQOS,
  883. // Srv Remote ?
  884. FALSE,
  885. SecClnCtx);
  886. //
  887. // If unsuccessful, return NULL.
  888. //
  889. if (NtStatus != STATUS_SUCCESS) {
  890. DavDbgTrace(DAV_TRACE_ERROR,
  891. ("%ld: ERROR: MRxDAVFormatTheDAVContext/"
  892. "SeCreateClientSecurityFromSubjectContext. Error "
  893. "Val = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  894. goto EXIT_THE_FUNCTION;
  895. }
  896. SecurityClientContextCreated = TRUE;
  897. //
  898. // If this was a create call, set the bool in the DavVNetRoot to
  899. // indicate that the SecurityClientContext has been initialized.
  900. //
  901. if (EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATEVNETROOT) {
  902. DavVNetRoot->SCAlreadyInitialized = TRUE;
  903. } else{
  904. ASSERT(EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL);
  905. DavSrvCall->SCAlreadyInitialized = TRUE;
  906. }
  907. }
  908. } else {
  909. DavDbgTrace(DAV_TRACE_ERROR,
  910. ("%ld: ERROR: MRxDAVFormatTheDAVContext. Could not get SecClnCtx."
  911. "EntryPoint = %d.\n", PsGetCurrentThreadId(), EntryPoint));
  912. }
  913. EXIT_THE_FUNCTION:
  914. if (NtStatus != STATUS_SUCCESS) {
  915. if (EntryPoint == DAV_MINIRDR_ENTRY_FROM_CREATESRVCALL && SecClnCtx != NULL) {
  916. if (SecurityClientContextCreated) {
  917. SeDeleteClientSecurity(SecClnCtx);
  918. DavSrvCall->SCAlreadyInitialized = FALSE;
  919. }
  920. RxFreePool(SecClnCtx);
  921. RxContext->MRxContext[2] = NULL;
  922. }
  923. }
  924. DavDbgTrace(DAV_TRACE_DETAIL,
  925. ("%ld: Leaving MRxDAVFormatTheDAVContext with NtStatus = %08lx.\n",
  926. PsGetCurrentThreadId(), NtStatus));
  927. return NtStatus;
  928. }
  929. NTSTATUS
  930. MRxDavDeleteConnection(
  931. IN OUT PRX_CONTEXT RxContext
  932. )
  933. /*++
  934. Routine Description:
  935. This routine deletes a VNetroot. The result depends on the forcelevel. If called
  936. with maximum force, this will delete all connections and orphan the fileobjects
  937. working on files for this VNetRoot.
  938. Arguments:
  939. RxContext - the RDBSS context
  940. Return Value:
  941. RXSTATUS - The return status for the operation
  942. Notes:
  943. --*/
  944. {
  945. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  946. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  947. RxCaptureFobx;
  948. BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
  949. BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
  950. PLMR_REQUEST_PACKET InputBuffer = LowIoContext->ParamsFor.FsCtl.pInputBuffer;
  951. ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
  952. ULONG Level;
  953. PMRX_V_NET_ROOT VNetRoot;
  954. PMRX_NET_ROOT NetRoot;
  955. PAGED_CODE();
  956. #if 0
  957. if (!Wait) {
  958. //just post right now!
  959. *PostToFsp = TRUE;
  960. return(STATUS_PENDING);
  961. }
  962. #endif
  963. try {
  964. if (NodeType(capFobx)==RDBSS_NTC_V_NETROOT) {
  965. VNetRoot = (PMRX_V_NET_ROOT)capFobx;
  966. NetRoot = (PMRX_NET_ROOT)VNetRoot->pNetRoot;
  967. } else {
  968. ASSERT(FALSE);
  969. try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
  970. }
  971. if (InputBufferLength < sizeof(DWORD)) {
  972. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  973. }
  974. Level = *((DWORD *)InputBuffer);
  975. if (Level <= USE_LOTS_OF_FORCE) {
  976. if (VNetRoot != NULL && Level == USE_LOTS_OF_FORCE) {
  977. }
  978. Status = RxFinalizeConnection(
  979. (PNET_ROOT)NetRoot,
  980. (PV_NET_ROOT)VNetRoot,
  981. (BOOLEAN)(Level == USE_LOTS_OF_FORCE));
  982. } else {
  983. Status = STATUS_INVALID_PARAMETER;
  984. }
  985. try_return(Status);
  986. try_exit:NOTHING;
  987. } finally {
  988. #if 0
  989. if (TableLockHeld) {
  990. RxReleasePrefixTableLock( &RxNetNameTable );
  991. }
  992. #endif
  993. }
  994. return Status;
  995. }
  996. VOID
  997. MRxDAVGetLockOwnerFromFileName(
  998. IN PWEBDAV_DEVICE_OBJECT MRxDAVDeviceObject,
  999. IN OUT PWCHAR InputBuffer,
  1000. IN ULONG InputBufferLength,
  1001. OUT PWCHAR OutputBuffer,
  1002. IN ULONG OutputBufferLength,
  1003. OUT PIO_STATUS_BLOCK IoStatus
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This routine goes through the global LockConflictEntryList and deletes
  1008. all the expired entries. It then looks at the entry whose CompletePathName
  1009. matches the FileName of the InputBuffer and fills in the LockOwner of
  1010. that entry in the OutputBuffer.
  1011. Arguments:
  1012. MRxDAVDeviceObject - The WebDav deviceobject that is in play.
  1013. InputBuffer - The Input buffer that came down from the user mode. This
  1014. contains the CompletePathName of the file in question.
  1015. InputBufferLength - Length of the InputBuffer.
  1016. OutputBuffer - The Output buffer that came down from the user mode. The
  1017. LockOwner (if one is found) is filled here.
  1018. OutputBufferLength - Length of the OutputBuffer.
  1019. IoStatus - The results of the assignment.
  1020. Return Value:
  1021. None.
  1022. --*/
  1023. {
  1024. NTSTATUS NtStatus = STATUS_SUCCESS;
  1025. PLIST_ENTRY ConflictListEntry = NULL;
  1026. PWEBDAV_LOCK_CONFLICT_ENTRY LockConflictEntry = NULL;
  1027. BOOL lockAcquired = FALSE, entryFound = FALSE;
  1028. //
  1029. // Note: InputBuffer and OutputBuffer may point to the same address since
  1030. // this IOCTL is METHOD_BUFFERED, and we could have enterd it via the IRP
  1031. // path instead of Fast I/O path.
  1032. //
  1033. //
  1034. // We need to disable APCs on this thread now.
  1035. //
  1036. FsRtlEnterFileSystem();
  1037. //
  1038. // First, go through the list and free up all the old entries. We supply
  1039. // FALSE since we only want to cleanup the expired entries.
  1040. //
  1041. MRxDAVCleanUpTheLockConflictList(FALSE);
  1042. //
  1043. // Now that we have cleaned up all the old entries, go through the list
  1044. // and find out the entry that matches the PathName. Fill the OutputBuffer
  1045. // with the LockOwner string.
  1046. //
  1047. ExAcquireResourceExclusiveLite(&(LockConflictEntryListLock), TRUE);
  1048. lockAcquired = TRUE;
  1049. ConflictListEntry = LockConflictEntryList.Flink;
  1050. while ( ConflictListEntry != &(LockConflictEntryList) ) {
  1051. //
  1052. // Get the pointer to the WEBDAV_LOCK_CONFLICT_ENTRY structure.
  1053. //
  1054. LockConflictEntry = CONTAINING_RECORD(ConflictListEntry,
  1055. WEBDAV_LOCK_CONFLICT_ENTRY,
  1056. listEntry);
  1057. ConflictListEntry = ConflictListEntry->Flink;
  1058. //
  1059. // If the SizeInBytes of the LockConflictEntry->CompletePathName is
  1060. // greater than the InputBufferLength, then we continue.
  1061. //
  1062. if ( ((1 + wcslen(LockConflictEntry->CompletePathName)) * sizeof(WCHAR)) > InputBufferLength ) {
  1063. continue;
  1064. }
  1065. try {
  1066. //
  1067. // If the CompletePathName exactly matches the InputBuffer string
  1068. // that was passed then this is the LockConflictEntry we are
  1069. // interested in.
  1070. //
  1071. if ( !_wcsnicmp(LockConflictEntry->CompletePathName, InputBuffer, wcslen(LockConflictEntry->CompletePathName)) ) {
  1072. if ( InputBuffer[wcslen(LockConflictEntry->CompletePathName)] == L'\0' ) {
  1073. entryFound = TRUE;
  1074. break;
  1075. }
  1076. }
  1077. } except (EXCEPTION_EXECUTE_HANDLER) {
  1078. NtStatus = STATUS_INVALID_USER_BUFFER;
  1079. goto EXIT_THE_FUNCTION;
  1080. }
  1081. }
  1082. if (entryFound) {
  1083. DavDbgTrace(DAV_TRACE_DETAIL,
  1084. ("%ld: MRxDAVGetLockOwnerFromFileName. entryFound == TRUE\n",
  1085. PsGetCurrentThreadId()));
  1086. //
  1087. // We need to make sure that the OutputBuffer is large enough to hold
  1088. // the LockOwner string.
  1089. //
  1090. if ( OutputBufferLength < ((1 + wcslen(LockConflictEntry->LockOwner)) * sizeof(WCHAR)) ) {
  1091. NtStatus = STATUS_BUFFER_TOO_SMALL;
  1092. DavDbgTrace(DAV_TRACE_ERROR,
  1093. ("%ld: ERROR: MRxDAVGetLockOwnerFromFileName. STATUS_BUFFER_TOO_SMALL\n",
  1094. PsGetCurrentThreadId()));
  1095. goto EXIT_THE_FUNCTION;
  1096. }
  1097. try {
  1098. wcsncpy(OutputBuffer, LockConflictEntry->LockOwner, wcslen(LockConflictEntry->LockOwner));
  1099. OutputBuffer[wcslen(LockConflictEntry->LockOwner)] = L'\0';
  1100. } except (EXCEPTION_EXECUTE_HANDLER) {
  1101. NtStatus = STATUS_INVALID_USER_BUFFER;
  1102. DavDbgTrace(DAV_TRACE_ERROR,
  1103. ("%ld: ERROR: MRxDAVGetLockOwnerFromFileName. STATUS_INVALID_USER_BUFFER(3)\n",
  1104. PsGetCurrentThreadId()));
  1105. goto EXIT_THE_FUNCTION;
  1106. }
  1107. NtStatus = STATUS_SUCCESS;
  1108. } else {
  1109. DavDbgTrace(DAV_TRACE_DETAIL,
  1110. ("%ld: MRxDAVGetLockOwnerFromFileName. entryFound == FALSE\n",
  1111. PsGetCurrentThreadId()));
  1112. NtStatus = STATUS_NO_SUCH_FILE;
  1113. }
  1114. EXIT_THE_FUNCTION:
  1115. IoStatus->Status = NtStatus;
  1116. //
  1117. // If NtStatus is STATUS_BUFFER_TOO_SMALL, we need to return the size
  1118. // needed to hold the LoackOwner name.
  1119. //
  1120. if (NtStatus == STATUS_SUCCESS || NtStatus == STATUS_BUFFER_TOO_SMALL) {
  1121. IoStatus->Information = ( (1 + wcslen(LockConflictEntry->LockOwner)) * sizeof(WCHAR) );
  1122. } else {
  1123. IoStatus->Information = 0;
  1124. }
  1125. if (lockAcquired) {
  1126. ExReleaseResourceLite(&(LockConflictEntryListLock));
  1127. lockAcquired = FALSE;
  1128. }
  1129. FsRtlExitFileSystem();
  1130. return;
  1131. }
  1132. VOID
  1133. MRxDAVCleanUpTheLockConflictList(
  1134. BOOL CleanUpAllEntries
  1135. )
  1136. /*++
  1137. Routine Description:
  1138. This routine goes through the global LockConflictEntryList and deletes
  1139. all the expired entries or all the entries depending upon the value of
  1140. CleanUpAllEntries.
  1141. Arguments:
  1142. CleanUpAllEntries - If TRUE, it cleans up all the entries.
  1143. If FALSE, it cleans up only the expired items.
  1144. Return Value:
  1145. None.
  1146. --*/
  1147. {
  1148. PLIST_ENTRY ConflictListEntry = NULL;
  1149. PWEBDAV_LOCK_CONFLICT_ENTRY LockConflictEntry = NULL;
  1150. LARGE_INTEGER CurrentSystemTickCount, TickCountDifference;
  1151. LARGE_INTEGER EntryTimeoutValueInTickCount;
  1152. //
  1153. // Go through the list and free up all the old entries. Acquire the LOCK
  1154. // first.
  1155. //
  1156. ExAcquireResourceExclusiveLite(&(LockConflictEntryListLock), TRUE);
  1157. ConflictListEntry = LockConflictEntryList.Flink;
  1158. while ( ConflictListEntry != &(LockConflictEntryList) ) {
  1159. //
  1160. // Get the pointer to the WEBDAV_LOCK_CONFLICT_ENTRY structure.
  1161. //
  1162. LockConflictEntry = CONTAINING_RECORD(ConflictListEntry,
  1163. WEBDAV_LOCK_CONFLICT_ENTRY,
  1164. listEntry);
  1165. ConflictListEntry = ConflictListEntry->Flink;
  1166. //
  1167. // Calculate the timeout value in TickCount (100 nano seconds) using
  1168. // the timeout value in seconds). Step1 below calculates the number of
  1169. // ticks that happen in one second. Step2 below calculates the number
  1170. // of ticks in WEBDAV_LOCKCONFLICTENTRY_LIFETIMEINSEC.
  1171. //
  1172. EntryTimeoutValueInTickCount.QuadPart = ( (1000 * 1000 * 10) / KeQueryTimeIncrement() );
  1173. EntryTimeoutValueInTickCount.QuadPart *= WEBDAV_LOCKCONFLICTENTRY_LIFETIMEINSEC;
  1174. KeQueryTickCount( &(CurrentSystemTickCount) );
  1175. //
  1176. // Get the time elapsed (in system tick counts) since the time this
  1177. // LockConflictEntry was created.
  1178. //
  1179. TickCountDifference.QuadPart = (CurrentSystemTickCount.QuadPart - LockConflictEntry->CreationTimeInTickCount.QuadPart);
  1180. //
  1181. // If the TickCountDifference is greater than EntryTimeoutValueInTickCount
  1182. // we need to remove this this entry from the list and free it. If
  1183. // CleanUpAllEntries is TRUE, we free it whether its expired or not.
  1184. //
  1185. if ( (CleanUpAllEntries) ||
  1186. (TickCountDifference.QuadPart > EntryTimeoutValueInTickCount.QuadPart) ) {
  1187. RemoveEntryList( &(LockConflictEntry->listEntry) );
  1188. RxFreePool(LockConflictEntry->CompletePathName);
  1189. LockConflictEntry->CompletePathName = NULL;
  1190. RxFreePool(LockConflictEntry->LockOwner);
  1191. LockConflictEntry->LockOwner = NULL;
  1192. RxFreePool(LockConflictEntry);
  1193. LockConflictEntry = NULL;
  1194. }
  1195. }
  1196. ExReleaseResourceLite(&(LockConflictEntryListLock));
  1197. return;
  1198. }