Source code of Windows XP (NT5)
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.

2131 lines
56 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. create.c
  5. Abstract:
  6. This module implements the file create routine for the MUP.
  7. Author:
  8. Manny Weiser (mannyw) 16-Dec-1991
  9. Revision History:
  10. --*/
  11. #include "mup.h"
  12. //
  13. // The debug trace level
  14. //
  15. #define Dbg (DEBUG_TRACE_CREATE)
  16. //
  17. // Local functions
  18. //
  19. NTSTATUS
  20. CreateRedirectedFile(
  21. IN PIRP Irp,
  22. IN PFILE_OBJECT FileObject,
  23. IN PIO_SECURITY_CONTEXT Security
  24. );
  25. NTSTATUS
  26. QueryPathCompletionRoutine (
  27. IN PDEVICE_OBJECT DeviceObject,
  28. IN PIRP Irp,
  29. IN PVOID Context
  30. );
  31. NTSTATUS
  32. MupRerouteOpenToDfs (
  33. IN PFILE_OBJECT FileObject
  34. );
  35. NTSTATUS
  36. BroadcastOpen (
  37. IN PIRP Irp
  38. );
  39. IO_STATUS_BLOCK
  40. OpenMupFileSystem (
  41. IN PVCB Vcb,
  42. IN PFILE_OBJECT FileObject,
  43. IN ACCESS_MASK DesiredAccess,
  44. IN USHORT ShareAccess
  45. );
  46. NTSTATUS
  47. IsThisASysVolPath(
  48. IN PUNICODE_STRING PathName,
  49. IN PUNICODE_STRING DCName);
  50. NTSTATUS
  51. MupDomainToDC(
  52. PUNICODE_STRING RootName,
  53. PUNICODE_STRING DCName);
  54. BOOLEAN
  55. MupFlushPrefixEntry (
  56. PUNICODE_STRING pathName
  57. );
  58. VOID
  59. MupInvalidatePrefixTable (
  60. VOID
  61. );
  62. BOOLEAN
  63. DfspIsSysVolShare(
  64. PUNICODE_STRING ShareName);
  65. #ifdef ALLOC_PRAGMA
  66. #pragma alloc_text( PAGE, BroadcastOpen )
  67. #pragma alloc_text( PAGE, CreateRedirectedFile )
  68. #pragma alloc_text( PAGE, MupCreate )
  69. #pragma alloc_text( PAGE, MupRerouteOpenToDfs )
  70. #pragma alloc_text( PAGE, OpenMupFileSystem )
  71. #pragma alloc_text( PAGE, QueryPathCompletionRoutine )
  72. #pragma alloc_text( PAGE, MupFlushPrefixEntry)
  73. #pragma alloc_text( PAGE, MupInvalidatePrefixTable)
  74. #pragma alloc_text( PAGE, IsThisASysVolPath)
  75. #pragma alloc_text( PAGE, MupDomainToDC)
  76. #ifdef TERMSRV
  77. #pragma alloc_text( PAGE, TSGetRequestorSessionId )
  78. #endif // TERMSRV
  79. #endif
  80. #ifdef TERMSRV
  81. NTSTATUS
  82. TSGetRequestorSessionId(
  83. IN PIRP pIrp,
  84. OUT PULONG pulSessionId
  85. )
  86. /*++
  87. Routine Description:
  88. This routine returns the session ID for user that is creating a file
  89. via the IRP_MJ_CREATE, IRP_MJ_CREATE_NAMED_PIPE or IRP_MJ_CREATE_MAILSLOT
  90. IRP requests.
  91. Arguments:
  92. pIrp - pointer to the I/O Request Packet.
  93. pulSessionId - pointer to the session Id which is set upon successful
  94. return.
  95. Return Value:
  96. STATUS_SUCCESS - if the session ID was available.
  97. STATUS_UNSUCCESSFUL - otherwise
  98. --*/
  99. {
  100. NTSTATUS ntStatus;
  101. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  102. PFILE_OBJECT FileObject = pIrpSp->FileObject;
  103. PIO_SECURITY_CONTEXT pSecurityContext;
  104. PSECURITY_SUBJECT_CONTEXT pSecSubjectContext;
  105. UNICODE_STRING FileName = FileObject->FileName;
  106. switch (pIrpSp->MajorFunction) {
  107. case IRP_MJ_CREATE:
  108. case IRP_MJ_CREATE_NAMED_PIPE:
  109. case IRP_MJ_CREATE_MAILSLOT:
  110. pSecurityContext = pIrpSp->Parameters.Create.SecurityContext;
  111. break;
  112. #if 0
  113. case IRP_MJ_CREATE_NAMED_PIPE:
  114. pSecurityContext = pIrpSp->Parameters.CreatePipe.SecurityContext;
  115. break;
  116. case IRP_MJ_CREATE_MAILSLOT:
  117. pSecurityContext = pIrpSp->Parameters.CreateMailslot.SecurityContext;
  118. break;
  119. #endif // 0
  120. default:
  121. pSecurityContext = NULL;
  122. break;
  123. }
  124. if ( pSecurityContext == NULL ) {
  125. *pulSessionId = (ULONG) INVALID_SESSIONID;
  126. ntStatus = STATUS_UNSUCCESSFUL;
  127. MUP_TRACE_HIGH(ERROR, TSGetRequestorSessionId_Error1,
  128. LOGSTATUS(ntStatus)
  129. LOGPTR(pIrp)
  130. LOGPTR(FileObject)
  131. LOGUSTR(FileName));
  132. goto Cleanup;
  133. }
  134. pSecSubjectContext = &pSecurityContext->AccessState->SubjectSecurityContext;
  135. ntStatus = SeQuerySessionIdToken(
  136. ((pSecSubjectContext->ClientToken != NULL) ?
  137. pSecSubjectContext->ClientToken :
  138. pSecSubjectContext->PrimaryToken ),
  139. pulSessionId);
  140. Cleanup:
  141. if( !NT_SUCCESS( ntStatus ) ) {
  142. DebugTrace(0, Dbg,
  143. "TSGetRequestorSessionId returns error, 0x%lx\n",
  144. ntStatus);
  145. }
  146. else {
  147. DebugTrace(0, Dbg,
  148. "TSGetRequestorSessionId returns SessionID, %ld\n",
  149. *pulSessionId);
  150. }
  151. return(ntStatus);
  152. }
  153. #endif // TERMSRV
  154. NTSTATUS
  155. MupCreate (
  156. IN PMUP_DEVICE_OBJECT MupDeviceObject,
  157. IN PIRP Irp
  158. )
  159. /*++
  160. Routine Description:
  161. This routine implements the the Create IRP.
  162. Arguments:
  163. MupDeviceObject - Supplies the device object to use.
  164. Irp - Supplies the Irp being processed
  165. Return Value:
  166. NTSTATUS - The status for the IRP.
  167. --*/
  168. {
  169. NTSTATUS status;
  170. PIO_STACK_LOCATION irpSp;
  171. PFILE_OBJECT fileObject;
  172. PFILE_OBJECT relatedFileObject;
  173. STRING fileName;
  174. ACCESS_MASK desiredAccess;
  175. USHORT shareAccess;
  176. LARGE_INTEGER StartTime;
  177. LARGE_INTEGER EndTime;
  178. BOOLEAN caseInsensitive = TRUE; //**** Make all searches case insensitive
  179. PVCB vcb;
  180. PAGED_CODE();
  181. DebugTrace(+1, Dbg, "MupCreate\n", 0);
  182. //
  183. // Make local copies of our input parameters to make things easier.
  184. //
  185. irpSp = IoGetCurrentIrpStackLocation( Irp );
  186. fileObject = irpSp->FileObject;
  187. relatedFileObject = irpSp->FileObject->RelatedFileObject;
  188. fileName = *((PSTRING)(&irpSp->FileObject->FileName));
  189. desiredAccess = irpSp->Parameters.Create.SecurityContext->DesiredAccess;
  190. shareAccess = irpSp->Parameters.Create.ShareAccess;
  191. vcb = &MupDeviceObject->Vcb;
  192. DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp );
  193. DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)fileObject );
  194. DebugTrace( 0, Dbg, "FileName = %Z\n", (ULONG)&fileName );
  195. MUP_TRACE_HIGH(TRACE_IRP, MupCreate_Entry,
  196. LOGPTR(MupDeviceObject)
  197. LOGPTR(fileObject)
  198. LOGPTR(Irp)
  199. LOGUSTR(fileName));
  200. KeQuerySystemTime(&StartTime);
  201. #if DBG
  202. if (MupVerbose) {
  203. KeQuerySystemTime(&EndTime);
  204. DbgPrint("[%d] MupCreate(%wZ)\n",
  205. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  206. &fileObject->FileName);
  207. }
  208. #endif
  209. FsRtlEnterFileSystem();
  210. try {
  211. //
  212. // Check to see if this is an open that came in via a Dfs device
  213. // object.
  214. //
  215. if (MupEnableDfs) {
  216. if ((MupDeviceObject->DeviceObject.DeviceType == FILE_DEVICE_DFS) ||
  217. (MupDeviceObject->DeviceObject.DeviceType ==
  218. FILE_DEVICE_DFS_FILE_SYSTEM)) {
  219. status = DfsFsdCreate( (PDEVICE_OBJECT) MupDeviceObject, Irp );
  220. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, MupCreate_Error_DfsFsdCreate,
  221. LOGSTATUS(status)
  222. LOGPTR(fileObject)
  223. LOGPTR(Irp));
  224. try_return( NOTHING );
  225. }
  226. }
  227. //
  228. // Check if we are trying to open the mup file system
  229. //
  230. if ( fileName.Length == 0
  231. &&
  232. ( relatedFileObject == NULL ||
  233. BlockType(relatedFileObject->FsContext) == BlockTypeVcb ) ) {
  234. DebugTrace(0, Dbg, "Open MUP file system\n", 0);
  235. Irp->IoStatus = OpenMupFileSystem( &MupDeviceObject->Vcb,
  236. fileObject,
  237. desiredAccess,
  238. shareAccess );
  239. status = Irp->IoStatus.Status;
  240. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, MupCreate_Error_OpenMupFileSystem,
  241. LOGSTATUS(status)
  242. LOGPTR(fileObject)
  243. LOGPTR(Irp));
  244. MupCompleteRequest( Irp, status );
  245. try_return( NOTHING );
  246. }
  247. //
  248. // This is a UNC file open. Try to pass the request on.
  249. //
  250. status = CreateRedirectedFile(
  251. Irp,
  252. fileObject,
  253. irpSp->Parameters.Create.SecurityContext
  254. );
  255. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, MupCreate_Error_CreateRedirectedFile,
  256. LOGSTATUS(status)
  257. LOGPTR(fileObject)
  258. LOGPTR(Irp));
  259. try_exit: NOTHING;
  260. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  261. // we need to complete the IRP.
  262. // But first, get the error code.
  263. status = GetExceptionCode();
  264. MupCompleteRequest( Irp, status );
  265. }
  266. FsRtlExitFileSystem();
  267. MUP_TRACE_HIGH(TRACE_IRP, MupCreate_Exit,
  268. LOGSTATUS(status)
  269. LOGPTR(fileObject)
  270. LOGPTR(Irp));
  271. DebugTrace(-1, Dbg, "MupCreate -> %08lx\n", status);
  272. #if DBG
  273. if (MupVerbose) {
  274. KeQuerySystemTime(&EndTime);
  275. DbgPrint("[%d] MupCreate exit 0x%x\n",
  276. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  277. status);
  278. }
  279. #endif
  280. return status;
  281. }
  282. IO_STATUS_BLOCK
  283. OpenMupFileSystem (
  284. IN PVCB Vcb,
  285. IN PFILE_OBJECT FileObject,
  286. IN ACCESS_MASK DesiredAccess,
  287. IN USHORT ShareAccess
  288. )
  289. /*++
  290. Routine Description:
  291. This routine attempts to open the VCB.
  292. Arguments:
  293. Vcb - A pointer to the MUP volume control block.
  294. FileObject - A pointer to the IO system supplied file object for this
  295. Create IRP.
  296. DesiredAccess - The user specified desired access to the VCB.
  297. ShareAccess - The user specified share access to the VCB.
  298. Return Value:
  299. NTSTATUS - The status for the IRP.
  300. --*/
  301. {
  302. IO_STATUS_BLOCK iosb;
  303. PAGED_CODE();
  304. DebugTrace(+1, Dbg, "MupOpenMupFileSystem\n", 0 );
  305. MUP_TRACE_LOW(DEFAULT, OpenMupFileSystem_Entry,
  306. LOGPTR(Vcb)
  307. LOGPTR(FileObject)
  308. LOGULONG(DesiredAccess)
  309. LOGXSHORT(ShareAccess));
  310. ExAcquireResourceExclusiveLite( &MupVcbLock, TRUE );
  311. try {
  312. //
  313. // Set the new share access
  314. //
  315. if (!NT_SUCCESS(iosb.Status = IoCheckShareAccess( DesiredAccess,
  316. ShareAccess,
  317. FileObject,
  318. &Vcb->ShareAccess,
  319. TRUE ))) {
  320. DebugTrace(0, Dbg, "bad share access\n", 0);
  321. MUP_TRACE_ERROR_HIGH(iosb.Status, ALL_ERROR, OpenMupFileSystem_Error_IoCheckShareAccess,
  322. LOGSTATUS(iosb.Status)
  323. LOGPTR(FileObject));
  324. try_return( NOTHING );
  325. }
  326. //
  327. // Supply the file object with a referenced pointer to the VCB.
  328. //
  329. MupReferenceBlock( Vcb );
  330. MupSetFileObject( FileObject, Vcb, NULL );
  331. //
  332. // Set the return status.
  333. //
  334. iosb.Status = STATUS_SUCCESS;
  335. iosb.Information = FILE_OPENED;
  336. try_exit: NOTHING;
  337. } finally {
  338. ExReleaseResourceLite( &MupVcbLock );
  339. }
  340. //
  341. // Return to the caller.
  342. //
  343. MUP_TRACE_LOW(DEFAULT, OpenMupFileSystem_Exit,
  344. LOGSTATUS(iosb.Status)
  345. LOGPTR(FileObject));
  346. DebugTrace(-1, Dbg, "MupOpenMupFileSystem -> Iosb.Status = %08lx\n", iosb.Status);
  347. return iosb;
  348. }
  349. NTSTATUS
  350. CreateRedirectedFile(
  351. IN PIRP Irp,
  352. IN PFILE_OBJECT FileObject,
  353. IN PIO_SECURITY_CONTEXT SecurityContext
  354. )
  355. /*++
  356. Routine Description:
  357. This routine attempts to reroute a file create request to a redirector.
  358. It attempts to find the correct redirector in 2 steps.
  359. (1) The routine checks a list of known prefixes. If the file object -
  360. file name prefix matches a known prefix, the request is forwarded to
  361. the redirector that "owns" the prefix.
  362. (2) The routine queries each redirector in turn, until one claims
  363. ownership of the file. The request is then rerouted to that redirector.
  364. If after these steps no owner is located, the MUP fails the request.
  365. Arguments:
  366. Irp - A pointer to the create IRP.
  367. FileObject - A pointer to the IO system supplied file object for this
  368. create request.
  369. SecurityContext - A pointer to the IO security context for this request.
  370. Return Value:
  371. NTSTATUS - The status for the IRP.
  372. --*/
  373. {
  374. NTSTATUS status = STATUS_BAD_NETWORK_PATH;
  375. PUNICODE_PREFIX_TABLE_ENTRY entry;
  376. PKNOWN_PREFIX knownPrefix = NULL;
  377. PLIST_ENTRY listEntry;
  378. PUNC_PROVIDER provider;
  379. PWCH buffer;
  380. LONG length;
  381. BOOLEAN ownLock;
  382. BOOLEAN providerReferenced = FALSE;
  383. BOOLEAN firstProvider = TRUE;
  384. PQUERY_PATH_REQUEST qpRequest;
  385. PMASTER_QUERY_PATH_CONTEXT masterContext = NULL;
  386. PQUERY_PATH_CONTEXT queryContext;
  387. PIRP irp;
  388. PIO_STACK_LOCATION irpSp;
  389. LARGE_INTEGER now;
  390. UNICODE_STRING FileName = FileObject->FileName;
  391. PAGED_CODE();
  392. DebugTrace(+1, Dbg, "CreateRedirectedFile\n", 0);
  393. MUP_TRACE_LOW(DEFAULT, CreateRedirectedFile_Entry,
  394. LOGPTR(Irp)
  395. LOGPTR(FileObject)
  396. LOGUSTR(FileName));
  397. // #ifdef TERMSRV
  398. #if 0 // need to confirm with the citrix guys about this change.
  399. if( IsTerminalServer() ) {
  400. //
  401. // Translate the filename for terminal server based on the session ID.
  402. //
  403. // NOTE: This re-allocates FileObject->FileName as needed
  404. //
  405. TSTranslateClientName( Irp, FileObject );
  406. }
  407. #endif // TERMSRV
  408. //
  409. // Handle empty filename
  410. //
  411. if (FileObject->FileName.Length == 0) {
  412. MupCompleteRequest( Irp, STATUS_INVALID_DEVICE_REQUEST);
  413. status = STATUS_INVALID_DEVICE_REQUEST;
  414. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, CreateRedirectedFile_Error_EmptyFilename,
  415. LOGSTATUS(status)
  416. LOGPTR(Irp)
  417. LOGPTR(FileObject));
  418. DebugTrace(-1, Dbg, "CreateRedirectedFile exit 0x%x\n", status);
  419. return status;
  420. }
  421. //
  422. // Check to see if this file name begins with a known prefix.
  423. //
  424. ACQUIRE_LOCK( &MupPrefixTableLock );
  425. entry = RtlFindUnicodePrefix( &MupPrefixTable, &FileObject->FileName, TRUE );
  426. if ( entry != NULL ) {
  427. DebugTrace(0, Dbg, "Prefix %Z is known, rerouting...\n", (PSTRING)&FileObject->FileName);
  428. //
  429. // This is a known file, forward appropriately
  430. //
  431. knownPrefix = CONTAINING_RECORD( entry, KNOWN_PREFIX, TableEntry );
  432. KeQuerySystemTime( &now );
  433. if ( now.QuadPart < knownPrefix->LastUsedTime.QuadPart ) {
  434. //
  435. // The known prefix has not timed out yet, recalculate the
  436. // timeout time and reroute the open.
  437. //
  438. MupCalculateTimeout( &knownPrefix->LastUsedTime );
  439. status = MupRerouteOpen( FileObject, knownPrefix->UncProvider );
  440. RELEASE_LOCK( &MupPrefixTableLock );
  441. DebugTrace(-1, Dbg, "CreateRedirectedFile -> %8lx", status );
  442. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, CreateRedirectedFile_Error_MupRerouteOpen,
  443. LOGSTATUS(status)
  444. LOGPTR(Irp)
  445. LOGPTR(FileObject)
  446. LOGUSTR(FileObject->FileName));
  447. if (status == STATUS_REPARSE)
  448. Irp->IoStatus.Information = IO_REPARSE;
  449. MupCompleteRequest( Irp, status );
  450. return status;
  451. } else {
  452. DebugTrace(0, Dbg, "Prefix %Z has timed out\n", (PSTRING)&FileObject->FileName);
  453. //
  454. // The known prefix has timed out, dereference it so that
  455. // it will get removed from the table.
  456. //
  457. if ( knownPrefix->InTable ) {
  458. MupRemoveKnownPrefixEntry( knownPrefix);
  459. }
  460. RELEASE_LOCK( &MupPrefixTableLock );
  461. }
  462. } else {
  463. RELEASE_LOCK( &MupPrefixTableLock );
  464. }
  465. //
  466. // Is this a client side mailslot file? It is if the file name
  467. // is of the form \\server\mailslot\Anything, and this is a create
  468. // operation.
  469. //
  470. irpSp = IoGetCurrentIrpStackLocation( Irp );
  471. buffer = (PWCH)FileObject->FileName.Buffer;
  472. length = FileObject->FileName.Length;
  473. if ( *buffer == L'\\' && irpSp->MajorFunction == IRP_MJ_CREATE ) {
  474. buffer++;
  475. while ( (length -= sizeof(WCHAR)) > 0 && *buffer++ != L'\\' )
  476. NOTHING;
  477. length -= sizeof(WCHAR);
  478. if (
  479. length >= (sizeof(L"MAILSLOT") - sizeof(WCHAR))
  480. &&
  481. _wcsnicmp(
  482. buffer,
  483. L"Mailslot",
  484. MIN(length/sizeof(WCHAR),(sizeof(L"MAILSLOT")-sizeof(WCHAR))/sizeof(WCHAR))) == 0
  485. ) {
  486. //
  487. // This is a mailslot file. Forward the create IRP to all
  488. // redirectors that support broadcast.
  489. //
  490. DebugTrace(0, Dbg, "Prefix %Z is a mailslot\n", (ULONG)&FileObject->FileName);
  491. status = BroadcastOpen( Irp );
  492. if (status == STATUS_REPARSE)
  493. Irp->IoStatus.Information = IO_REPARSE;
  494. MUP_TRACE_LOW(DEFAULT, CreateRedirectedFile_Exit_Mailslot,
  495. LOGSTATUS(status)
  496. LOGPTR(Irp)
  497. LOGPTR(FileObject)
  498. LOGUSTR(FileName));
  499. MupCompleteRequest( Irp, status );
  500. DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
  501. return status;
  502. }
  503. }
  504. //
  505. // Check to see if this is a Dfs name. If so, we'll handle it separately
  506. //
  507. if (MupEnableDfs &&
  508. (FileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))) {
  509. UNICODE_STRING pathName;
  510. UNICODE_STRING DCName;
  511. status = DfsFsctrlIsThisADfsPath( &FileObject->FileName, FALSE, &pathName );
  512. if (status == STATUS_SUCCESS) {
  513. DebugTrace(-1, Dbg, "Rerouting open of [%wZ] to Dfs\n", &FileObject->FileName);
  514. status = MupRerouteOpenToDfs(FileObject);
  515. if (status == STATUS_REPARSE)
  516. Irp->IoStatus.Information = IO_REPARSE;
  517. MupCompleteRequest( Irp, status );
  518. return( status );
  519. }
  520. //
  521. // If special table is not init'ed, and this is \<domainname>\<specialname>,
  522. // rewrite into \<dcname>\<specialname>
  523. //
  524. if (DfsData.Pkt.SpecialTable.SpecialEntryCount == 0) {
  525. DCName.Buffer = NULL;
  526. DCName.Length = DCName.MaximumLength = 0;
  527. status = IsThisASysVolPath(&FileObject->FileName, &DCName);
  528. if (status == STATUS_SUCCESS)
  529. MupDomainToDC(&FileObject->FileName, &DCName);
  530. if (DCName.Buffer != NULL)
  531. ExFreePool(DCName.Buffer);
  532. }
  533. }
  534. //
  535. // We don't know who owns this file, query the redirectors in sequence
  536. // until one works.
  537. //
  538. IoMarkIrpPending(Irp);
  539. //
  540. // Allocate the master context and knownprefix. If either allocation fails, we'll
  541. // complete the irp with STATUS_INSUFFICIENT_RESOURCES
  542. //
  543. knownPrefix = MupAllocatePrefixEntry( 0 );
  544. if (knownPrefix == NULL) {
  545. MupCompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES);
  546. return STATUS_PENDING;
  547. }
  548. masterContext = MupAllocateMasterQueryContext();
  549. if (masterContext == NULL) {
  550. ExFreePool(knownPrefix);
  551. MupCompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES);
  552. return STATUS_PENDING;
  553. }
  554. try {
  555. masterContext->OriginalIrp = Irp;
  556. masterContext->FileObject = FileObject;
  557. masterContext->Provider = NULL;
  558. masterContext->KnownPrefix = knownPrefix;
  559. masterContext->ErrorStatus = STATUS_BAD_NETWORK_PATH;
  560. MupAcquireGlobalLock();
  561. // for debugging: insert the Master Context into the global list.
  562. InsertHeadList(&MupMasterQueryList, &masterContext->MasterQueryList);
  563. MupReferenceBlock( knownPrefix );
  564. MupReleaseGlobalLock();
  565. try {
  566. MupAcquireGlobalLock();
  567. ownLock = TRUE;
  568. listEntry = MupProviderList.Flink;
  569. while ( listEntry != &MupProviderList ) {
  570. provider = CONTAINING_RECORD(
  571. listEntry,
  572. UNC_PROVIDER,
  573. ListEntry
  574. );
  575. //
  576. // Reference the provider block so that it doesn't go away
  577. // while we are using it.
  578. //
  579. MupReferenceBlock( provider );
  580. providerReferenced = TRUE;
  581. MupReleaseGlobalLock();
  582. ownLock = FALSE;
  583. // only use this provider if it is registered
  584. if(provider->Registered) {
  585. //
  586. // Allocate buffers for the io request.
  587. //
  588. qpRequest = NULL;
  589. queryContext = NULL;
  590. qpRequest = ExAllocatePoolWithTag(
  591. PagedPool,
  592. sizeof( QUERY_PATH_REQUEST ) +
  593. FileObject->FileName.Length,
  594. ' puM');
  595. if (qpRequest == NULL) {
  596. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  597. }
  598. queryContext = ExAllocatePoolWithTag(
  599. PagedPool,
  600. sizeof( QUERY_PATH_CONTEXT ),
  601. ' puM');
  602. if (queryContext == NULL) {
  603. ExFreePool(qpRequest);
  604. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  605. }
  606. InitializeListHead(&queryContext->QueryList);
  607. queryContext->MasterContext = masterContext;
  608. queryContext->Buffer = qpRequest;
  609. //
  610. // Generate a query path request.
  611. //
  612. qpRequest->PathNameLength = FileObject->FileName.Length;
  613. qpRequest->SecurityContext = SecurityContext;
  614. RtlMoveMemory(
  615. qpRequest->FilePathName,
  616. FileObject->FileName.Buffer,
  617. FileObject->FileName.Length
  618. );
  619. //
  620. // Build the query path Io control IRP.
  621. //
  622. irp = MupBuildIoControlRequest(
  623. NULL,
  624. provider->FileObject,
  625. queryContext,
  626. IRP_MJ_DEVICE_CONTROL,
  627. IOCTL_REDIR_QUERY_PATH,
  628. qpRequest,
  629. sizeof( QUERY_PATH_REQUEST ) + FileObject->FileName.Length,
  630. qpRequest,
  631. sizeof( QUERY_PATH_RESPONSE ),
  632. QueryPathCompletionRoutine
  633. );
  634. if ( irp == NULL ) {
  635. ExFreePool(qpRequest);
  636. ExFreePool(queryContext);
  637. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  638. }
  639. //
  640. // Set the RequestorMode to KernelMode, since all the
  641. // parameters to this Irp are in kernel space
  642. //
  643. irp->RequestorMode = KernelMode;
  644. //
  645. // Get a referenced pointer to the provider, the reference
  646. // is release when the IO completes.
  647. //
  648. queryContext->Provider = provider;
  649. queryContext->QueryIrp = irp;
  650. MupAcquireGlobalLock();
  651. MupReferenceBlock( provider );
  652. MupReferenceBlock( masterContext );
  653. MupReleaseGlobalLock();
  654. // insert this query into the master context's list of queries (for debugging)
  655. ACQUIRE_LOCK( &masterContext->Lock );
  656. InsertHeadList(&masterContext->QueryList, &queryContext->QueryList);
  657. RELEASE_LOCK( &masterContext->Lock );
  658. //
  659. // Submit the request.
  660. //
  661. MUP_TRACE_HIGH(ALL_ERROR, CreateRedirectedFile_Before_IoCallDriver,
  662. LOGPTR(masterContext->OriginalIrp)
  663. LOGPTR(queryContext->QueryIrp)
  664. LOGPTR(FileObject)
  665. LOGUSTR(FileName)
  666. LOGUSTR(provider->DeviceName));
  667. status = IoCallDriver( provider->DeviceObject, irp );
  668. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, CreateRedirectedFile_Error_IoCallDriver,
  669. LOGSTATUS(status)
  670. LOGPTR(masterContext->OriginalIrp)
  671. LOGPTR(FileObject)
  672. LOGUSTR(provider->DeviceName));
  673. } // if registered
  674. //
  675. // Acquire the lock that protects the provider list, and get
  676. // a pointer to the next provider in the list.
  677. //
  678. MupAcquireGlobalLock();
  679. ownLock = TRUE;
  680. listEntry = listEntry->Flink;
  681. MupDereferenceUncProvider( provider );
  682. providerReferenced = FALSE;
  683. //
  684. // If this is the first provider and it responded with SUCCESS, we can return early.
  685. // The list of providers is sorted in order of priority, so we know that this is
  686. // the highest prority provider and it can get to the destination.
  687. //
  688. if( firstProvider && (status == STATUS_SUCCESS) ) {
  689. break;
  690. }
  691. firstProvider = FALSE;
  692. } // while
  693. } finally {
  694. //
  695. // Dereference the previous provider.
  696. //
  697. if ( providerReferenced ) {
  698. MupDereferenceUncProvider( provider );
  699. }
  700. if ( ownLock ) {
  701. MupReleaseGlobalLock();
  702. }
  703. }
  704. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  705. masterContext->ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
  706. }
  707. ASSERT(masterContext != NULL);
  708. //
  709. // Release our reference to the query context.
  710. //
  711. MupDereferenceMasterQueryContext( masterContext );
  712. status = STATUS_PENDING;
  713. MUP_TRACE_LOW(DEFAULT, CreateRedirectedFile_Exit,
  714. LOGSTATUS(status)
  715. LOGPTR(Irp)
  716. LOGPTR(FileObject));
  717. DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
  718. return status;
  719. }
  720. NTSTATUS
  721. MupRerouteOpen (
  722. IN PFILE_OBJECT FileObject,
  723. IN PUNC_PROVIDER UncProvider
  724. )
  725. /*++
  726. Routine Description:
  727. This routine redirects an create IRP request to the specified redirector
  728. by changing the name of the file and returning STATUS_REPARSE to the
  729. IO system
  730. Arguments:
  731. FileObject - The file object to open
  732. UncProvider - The UNC provider that will process the create IRP.
  733. Return Value:
  734. NTSTATUS - The status of the operation
  735. --*/
  736. {
  737. PCHAR buffer;
  738. ULONG deviceNameLength;
  739. ULONG nameLength;
  740. NTSTATUS status;
  741. UNICODE_STRING FileName = FileObject->FileName;
  742. //
  743. // Check that we won't create a name that is too long
  744. //
  745. nameLength = UncProvider->DeviceName.Length + FileObject->FileName.Length;
  746. if (nameLength > MAXUSHORT) {
  747. status = STATUS_NAME_TOO_LONG;
  748. MUP_TRACE_HIGH(ERROR, MupRerouteOpen_Error1,
  749. LOGSTATUS(status)
  750. LOGPTR(FileObject)
  751. LOGUSTR(FileName));
  752. return STATUS_NAME_TOO_LONG;
  753. }
  754. //
  755. // Allocate storage for the new file name.
  756. //
  757. buffer = ExAllocatePoolWithTag(
  758. PagedPool,
  759. UncProvider->DeviceName.Length + FileObject->FileName.Length,
  760. ' puM');
  761. if ( buffer == NULL) {
  762. status = STATUS_INSUFFICIENT_RESOURCES;
  763. MUP_TRACE_HIGH(ERROR, MupRerouteOpen_Error2,
  764. LOGSTATUS(status)
  765. LOGPTR(FileObject)
  766. LOGUSTR(FileName));
  767. return status;
  768. }
  769. //
  770. // Copy the device name to the string buffer.
  771. //
  772. RtlMoveMemory(
  773. buffer,
  774. UncProvider->DeviceName.Buffer,
  775. UncProvider->DeviceName.Length);
  776. deviceNameLength = UncProvider->DeviceName.Length;
  777. //
  778. // Append the file name
  779. //
  780. RtlMoveMemory(
  781. buffer + deviceNameLength,
  782. FileObject->FileName.Buffer,
  783. FileObject->FileName.Length);
  784. //
  785. // Free the old file name string buffer.
  786. //
  787. ExFreePool( FileObject->FileName.Buffer );
  788. FileObject->FileName.Buffer = (PWCHAR)buffer;
  789. FileObject->FileName.MaximumLength = FileObject->FileName.Length + (USHORT)deviceNameLength;
  790. FileObject->FileName.Length = FileObject->FileName.MaximumLength;
  791. //
  792. // Tell the file system to try again.
  793. //
  794. return STATUS_REPARSE;
  795. }
  796. NTSTATUS
  797. MupRerouteOpenToDfs (
  798. IN PFILE_OBJECT FileObject
  799. )
  800. /*++
  801. Routine Description:
  802. This routine redirects an create IRP request to the Dfs part of this
  803. driver by changing the name of the file and returning
  804. STATUS_REPARSE to the IO system
  805. Arguments:
  806. FileObject - The file object to open
  807. Return Value:
  808. NTSTATUS - The status of the operation
  809. --*/
  810. {
  811. PCHAR buffer;
  812. ULONG deviceNameLength;
  813. ULONG nameLength;
  814. NTSTATUS status;
  815. UNICODE_STRING FileName = FileObject->FileName;
  816. PAGED_CODE();
  817. MUP_TRACE_NORM(TRACE_IRP, MupRerouteOpenToDfs_Entry,
  818. LOGPTR(FileObject)
  819. LOGUSTR(FileName));
  820. #if DBG
  821. if (MupVerbose)
  822. DbgPrint("MupRerouteOpenToDfs(%wZ)\n", &FileObject->FileName);
  823. #endif
  824. deviceNameLength = sizeof(DFS_DEVICE_ROOT) - sizeof(UNICODE_NULL);
  825. //
  826. // Check that we won't create a name that is too long
  827. //
  828. nameLength = deviceNameLength + FileObject->FileName.Length;
  829. if (nameLength > MAXUSHORT) {
  830. status = STATUS_NAME_TOO_LONG;
  831. MUP_TRACE_HIGH(ERROR, MupRerouteOpenToDfs_Error1,
  832. LOGSTATUS(status)
  833. LOGPTR(FileObject)
  834. LOGUSTR(FileName));
  835. #if DBG
  836. if (MupVerbose)
  837. DbgPrint("MupRerouteOpenToDfs exit STATUS_NAME_TOO_LONG\n");
  838. #endif
  839. return STATUS_NAME_TOO_LONG;
  840. }
  841. //
  842. // Allocate storage for the new file name.
  843. //
  844. buffer = ExAllocatePoolWithTag(
  845. PagedPool,
  846. sizeof(DFS_DEVICE_ROOT) + FileObject->FileName.Length,
  847. ' puM');
  848. if ( buffer == NULL) {
  849. status = STATUS_INSUFFICIENT_RESOURCES;
  850. MUP_TRACE_HIGH(ERROR, MupRerouteOpenToDfs_Error2,
  851. LOGSTATUS(status)
  852. LOGPTR(FileObject)
  853. LOGUSTR(FileName));
  854. #if DBG
  855. if (MupVerbose)
  856. DbgPrint("MupRerouteOpenToDfs exit STATUS_INSUFFICIENT_RESOURCES\n");
  857. #endif
  858. return STATUS_INSUFFICIENT_RESOURCES;
  859. }
  860. //
  861. // Copy the device name to the string buffer.
  862. //
  863. RtlMoveMemory(
  864. buffer,
  865. DFS_DEVICE_ROOT,
  866. sizeof(DFS_DEVICE_ROOT));
  867. //
  868. // Append the file name
  869. //
  870. RtlMoveMemory(
  871. buffer + deviceNameLength,
  872. FileObject->FileName.Buffer,
  873. FileObject->FileName.Length);
  874. //
  875. // Free the old file name string buffer.
  876. //
  877. ExFreePool( FileObject->FileName.Buffer );
  878. FileObject->FileName.Buffer = (PWCHAR)buffer;
  879. FileObject->FileName.MaximumLength = FileObject->FileName.Length + (USHORT)deviceNameLength;
  880. FileObject->FileName.Length = FileObject->FileName.MaximumLength;
  881. //
  882. // Tell the file system to try again.
  883. //
  884. #if DBG
  885. if (MupVerbose)
  886. DbgPrint("MupRerouteOpenToDfs exit STATUS_REPARSE ->[%wZ]\n", &FileObject->FileName);
  887. #endif
  888. return STATUS_REPARSE;
  889. }
  890. NTSTATUS
  891. BroadcastOpen (
  892. PIRP Irp
  893. )
  894. /*++
  895. Routine Description:
  896. Arguments:
  897. Return Value:
  898. NTSTATUS - The status for the IRP.
  899. --*/
  900. {
  901. NTSTATUS status;
  902. PFCB fcb;
  903. PIO_STACK_LOCATION irpSp;
  904. PFILE_OBJECT fileObject;
  905. BOOLEAN requestForwarded;
  906. PLIST_ENTRY listEntry;
  907. PUNC_PROVIDER uncProvider, previousUncProvider = NULL;
  908. OBJECT_ATTRIBUTES objectAttributes;
  909. IO_STATUS_BLOCK ioStatusBlock;
  910. PCCB ccb;
  911. OBJECT_HANDLE_INFORMATION handleInformation;
  912. HANDLE handle;
  913. BOOLEAN lockHeld = FALSE;
  914. BOOLEAN providerReferenced = FALSE;
  915. ULONG Len;
  916. UNICODE_STRING FileName;
  917. NTSTATUS statusToReturn = STATUS_NO_SUCH_FILE;
  918. ULONG priorityOfStatus = 0xFFFFFFFF;
  919. PAGED_CODE();
  920. DebugTrace(+1, Dbg, "BroadcastOpen\n", 0 );
  921. irpSp = IoGetCurrentIrpStackLocation( Irp );
  922. FileName = irpSp->FileObject->FileName;
  923. try {
  924. //
  925. // Create a FCB for this file.
  926. //
  927. fcb = MupCreateFcb( );
  928. if (fcb == NULL) {
  929. status = STATUS_INSUFFICIENT_RESOURCES;
  930. MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error1,
  931. LOGSTATUS(status)
  932. LOGPTR(Irp)
  933. LOGPTR(irpSp->FileObject)
  934. LOGUSTR(FileName));
  935. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  936. }
  937. try {
  938. //
  939. // Set the file object back pointers and our pointer to the
  940. // server file object.
  941. //
  942. fileObject = irpSp->FileObject;
  943. MupAcquireGlobalLock();
  944. lockHeld = TRUE;
  945. MupSetFileObject( fileObject,
  946. fcb,
  947. NULL );
  948. fcb->FileObject = fileObject;
  949. //
  950. // Loop through the list of UNC providers and try to create the
  951. // file on all file systems that support broadcast.
  952. //
  953. requestForwarded = FALSE;
  954. listEntry = MupProviderList.Flink;
  955. while ( listEntry != &MupProviderList ) {
  956. uncProvider = CONTAINING_RECORD( listEntry, UNC_PROVIDER, ListEntry );
  957. //
  958. // Reference the provider so that it won't go away
  959. //
  960. MupReferenceBlock( uncProvider );
  961. providerReferenced = TRUE;
  962. MupReleaseGlobalLock();
  963. lockHeld = FALSE;
  964. Len = uncProvider->DeviceName.Length + fileObject->FileName.Length;
  965. if ( uncProvider->MailslotsSupported && Len <= MAXUSHORT) {
  966. //
  967. // Build the rerouted file name, consisting of the file
  968. // named we received appended to the UNC provider device
  969. // name.
  970. //
  971. UNICODE_STRING fileName;
  972. fileName.MaximumLength = fileName.Length = (USHORT) Len;
  973. fileName.Buffer =
  974. ExAllocatePoolWithTag(
  975. PagedPool,
  976. fileName.MaximumLength,
  977. ' puM');
  978. if (fileName.Buffer == NULL) {
  979. status = STATUS_INSUFFICIENT_RESOURCES;
  980. MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error2,
  981. LOGSTATUS(status)
  982. LOGPTR(Irp)
  983. LOGPTR(fileObject)
  984. LOGUSTR(FileName));
  985. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  986. }
  987. RtlMoveMemory(
  988. fileName.Buffer,
  989. uncProvider->DeviceName.Buffer,
  990. uncProvider->DeviceName.Length
  991. );
  992. RtlMoveMemory(
  993. (PCHAR)fileName.Buffer + uncProvider->DeviceName.Length,
  994. fileObject->FileName.Buffer,
  995. fileObject->FileName.Length
  996. );
  997. //
  998. // Attempt to open the file. Copy all of the information
  999. // from the create IRP we received, masking off additional
  1000. // baggage that the IO system added along the way.
  1001. //
  1002. DebugTrace( 0, Dbg, "Attempt to open %Z\n", (ULONG)&fileName );
  1003. InitializeObjectAttributes(
  1004. &objectAttributes,
  1005. &fileName,
  1006. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1007. 0,
  1008. NULL // !!! Security
  1009. );
  1010. status = IoCreateFile(
  1011. &handle,
  1012. irpSp->Parameters.Create.SecurityContext->DesiredAccess & 0x1FF,
  1013. &objectAttributes,
  1014. &ioStatusBlock,
  1015. NULL,
  1016. irpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS,
  1017. irpSp->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS,
  1018. FILE_OPEN,
  1019. irpSp->Parameters.Create.Options & FILE_VALID_SET_FLAGS,
  1020. NULL, // Ea buffer
  1021. 0, // Ea length
  1022. CreateFileTypeNone,
  1023. NULL, // parameters
  1024. IO_NO_PARAMETER_CHECKING
  1025. );
  1026. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, BroadcastOpen_Error_IoCreateFile,
  1027. LOGSTATUS(status)
  1028. LOGPTR(Irp)
  1029. LOGPTR(fileObject)
  1030. LOGUSTR(FileName));
  1031. ExFreePool( fileName.Buffer );
  1032. if ( NT_SUCCESS( status ) ) {
  1033. status = ioStatusBlock.Status;
  1034. ccb = MupCreateCcb( );
  1035. if (ccb == NULL) {
  1036. status = STATUS_INSUFFICIENT_RESOURCES;
  1037. MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error3,
  1038. LOGSTATUS(status)
  1039. LOGPTR(Irp)
  1040. LOGPTR(fileObject)
  1041. LOGUSTR(FileName));
  1042. }
  1043. }
  1044. if ( NT_SUCCESS( status ) ) {
  1045. DebugTrace( 0, Dbg, "Open attempt succeeded\n", 0 );
  1046. //
  1047. // 426184, need to check return code for errors.
  1048. //
  1049. status = ObReferenceObjectByHandle(
  1050. handle,
  1051. 0,
  1052. NULL,
  1053. KernelMode,
  1054. (PVOID *)&ccb->FileObject,
  1055. &handleInformation );
  1056. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, BroadcastOpen_Error_ObReferenceObjectByHandle,
  1057. LOGSTATUS(status)
  1058. LOGPTR(Irp)
  1059. LOGPTR(fileObject)
  1060. LOGUSTR(FileName));
  1061. ZwClose( handle );
  1062. }
  1063. if ( NT_SUCCESS( status ) ) {
  1064. ccb->DeviceObject =
  1065. IoGetRelatedDeviceObject( ccb->FileObject );
  1066. ccb->Fcb = fcb;
  1067. MupAcquireGlobalLock();
  1068. lockHeld = TRUE;
  1069. MupReferenceBlock( fcb );
  1070. MupReleaseGlobalLock();
  1071. lockHeld = FALSE;
  1072. //
  1073. // At least one provider will accept this mailslot
  1074. // request.
  1075. //
  1076. requestForwarded = TRUE;
  1077. //
  1078. // Keep a list of CCBs. Since we just created the FCB
  1079. // there is no need to use the lock to access the list.
  1080. //
  1081. InsertTailList( &fcb->CcbList, &ccb->ListEntry );
  1082. } else { // NT_SUCCESS( status ), IoCreateFile
  1083. DebugTrace( 0, Dbg, "Open attempt failed %8lx\n", status );
  1084. //
  1085. // Remember the status code if this is the highest
  1086. // priority provider so far. This code is returned if
  1087. // all providers fail the Create operation.
  1088. //
  1089. if ( uncProvider->Priority <= priorityOfStatus ) {
  1090. priorityOfStatus = uncProvider->Priority;
  1091. statusToReturn = status;
  1092. }
  1093. }
  1094. } // uncProvider->MailslotsSupported
  1095. MupAcquireGlobalLock();
  1096. lockHeld = TRUE;
  1097. listEntry = listEntry->Flink;
  1098. //
  1099. // It is now safe to dereference the previous provider.
  1100. //
  1101. MupDereferenceUncProvider( uncProvider );
  1102. providerReferenced = FALSE;
  1103. } // while
  1104. MupReleaseGlobalLock();
  1105. lockHeld = FALSE;
  1106. //
  1107. // And set our return status
  1108. //
  1109. if ( requestForwarded ) {
  1110. status = STATUS_SUCCESS;
  1111. } else {
  1112. status = statusToReturn;
  1113. }
  1114. } finally {
  1115. DebugTrace(-1, Dbg, "BroadcastOpen -> %08lx\n", status);
  1116. if ( providerReferenced ) {
  1117. MupDereferenceUncProvider( uncProvider );
  1118. }
  1119. if ( lockHeld ) {
  1120. MupReleaseGlobalLock();
  1121. }
  1122. //
  1123. // Now if we ever terminate the preceding try-statement with
  1124. // a status that is not successful and the FCB pointer
  1125. // is non-null then we need to deallocate the structure.
  1126. //
  1127. if (!NT_SUCCESS( status ) && fcb != NULL) {
  1128. MupFreeFcb( fcb );
  1129. }
  1130. }
  1131. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1132. NOTHING;
  1133. }
  1134. return status;
  1135. }
  1136. NTSTATUS
  1137. QueryPathCompletionRoutine (
  1138. IN PDEVICE_OBJECT DeviceObject,
  1139. IN PIRP Irp,
  1140. IN PVOID Context
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. This is the completion routine the querying a path. Cleanup our
  1145. IRP and complete the original IRP if necessary.
  1146. Arguments:
  1147. DeviceObject - Pointer to target device object for the request.
  1148. Irp - Pointer to I/O request packet
  1149. Context - Caller-specified context parameter associated with IRP.
  1150. This is actually a pointer to a Work Context block.
  1151. Return Value:
  1152. NTSTATUS - If STATUS_MORE_PROCESSING_REQUIRED is returned, I/O
  1153. completion processing by IoCompleteRequest terminates its
  1154. operation. Otherwise, IoCompleteRequest continues with I/O
  1155. completion.
  1156. --*/
  1157. {
  1158. PQUERY_PATH_RESPONSE qpResponse;
  1159. PMASTER_QUERY_PATH_CONTEXT masterContext;
  1160. PQUERY_PATH_CONTEXT queryPathContext;
  1161. PCH buffer;
  1162. PKNOWN_PREFIX knownPrefix;
  1163. ULONG lengthAccepted;
  1164. NTSTATUS status;
  1165. DeviceObject; // prevent compiler warnings
  1166. queryPathContext = Context;
  1167. masterContext = queryPathContext->MasterContext;
  1168. qpResponse = queryPathContext->Buffer;
  1169. lengthAccepted = qpResponse->LengthAccepted;
  1170. status = Irp->IoStatus.Status;
  1171. MUP_TRACE_NORM(TRACE_IRP, QueryPathCompletionRoutine_Enter,
  1172. LOGPTR(DeviceObject)
  1173. LOGPTR(Irp)
  1174. LOGUSTR(queryPathContext->Provider->DeviceName)
  1175. LOGPTR(masterContext->FileObject)
  1176. LOGUSTR(masterContext->FileObject->FileName)
  1177. LOGSTATUS(status)
  1178. );
  1179. //
  1180. // Acquire the lock to protect access to the master context Provider
  1181. // field.
  1182. //
  1183. ACQUIRE_LOCK( &masterContext->Lock );
  1184. // remove this query from the MasterQueryContext's list.
  1185. RemoveEntryList(&queryPathContext->QueryList);
  1186. if (NT_SUCCESS(status) && lengthAccepted != 0) {
  1187. knownPrefix = masterContext->KnownPrefix;
  1188. if ( masterContext->Provider != NULL ) {
  1189. if ( queryPathContext->Provider->Priority < masterContext->Provider->Priority ) {
  1190. //
  1191. // A provider of higher priority (i.e. a lower priority code)
  1192. // has claimed this prefix. Release the previous provider's
  1193. // claim.
  1194. //
  1195. ACQUIRE_LOCK( &MupPrefixTableLock );
  1196. if ( knownPrefix->InTable ) {
  1197. RtlRemoveUnicodePrefix(&MupPrefixTable, &knownPrefix->TableEntry);
  1198. RemoveEntryList(&knownPrefix->ListEntry);
  1199. knownPrefix->InTable = FALSE;
  1200. }
  1201. RELEASE_LOCK( &MupPrefixTableLock );
  1202. knownPrefix->Active = FALSE;
  1203. //
  1204. // If Dfs generated this query there will not have been anything
  1205. // stored in the knowPrefix->Prefix, so we check if there is indeed
  1206. // anything to free.
  1207. //
  1208. if (knownPrefix->Prefix.Length > 0 && knownPrefix->Prefix.Buffer != NULL) {
  1209. ExFreePool(knownPrefix->Prefix.Buffer);
  1210. knownPrefix->Prefix.Length = knownPrefix->Prefix.MaximumLength = 0;
  1211. knownPrefix->Prefix.Buffer = NULL;
  1212. knownPrefix->PrefixStringAllocated = FALSE;
  1213. }
  1214. if(knownPrefix->UncProvider) {
  1215. MupDereferenceUncProvider( knownPrefix->UncProvider );
  1216. knownPrefix->UncProvider = NULL;
  1217. }
  1218. } else {
  1219. //
  1220. // The current provider keeps ownership of the prefix.
  1221. //
  1222. MupDereferenceUncProvider( queryPathContext->Provider );
  1223. goto not_this_one;
  1224. }
  1225. }
  1226. //
  1227. // This provider gets the prefix.
  1228. //
  1229. masterContext->Provider = queryPathContext->Provider;
  1230. masterContext->ErrorStatus = status;
  1231. //
  1232. // We have found a match. Attempt to remember it.
  1233. //
  1234. if (masterContext->FileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT)) {
  1235. buffer = ExAllocatePoolWithTag(
  1236. PagedPool,
  1237. lengthAccepted,
  1238. ' puM');
  1239. if (buffer != NULL) {
  1240. RtlMoveMemory(
  1241. buffer,
  1242. masterContext->FileObject->FileName.Buffer,
  1243. lengthAccepted
  1244. );
  1245. //
  1246. // Copy the reference provider pointer for the known prefix
  1247. // block.
  1248. //
  1249. knownPrefix->UncProvider = masterContext->Provider;
  1250. knownPrefix->Prefix.Buffer = (PWCH)buffer;
  1251. knownPrefix->Prefix.Length = (USHORT)lengthAccepted;
  1252. knownPrefix->Prefix.MaximumLength = (USHORT)lengthAccepted;
  1253. knownPrefix->PrefixStringAllocated = TRUE;
  1254. ACQUIRE_LOCK( &MupPrefixTableLock );
  1255. if (RtlInsertUnicodePrefix(
  1256. &MupPrefixTable,
  1257. &knownPrefix->Prefix,
  1258. &knownPrefix->TableEntry) == TRUE) {
  1259. InsertTailList( &MupPrefixList, &knownPrefix->ListEntry);
  1260. knownPrefix->InTable = TRUE;
  1261. knownPrefix->Active = TRUE;
  1262. } else {
  1263. knownPrefix->InTable = FALSE;
  1264. }
  1265. RELEASE_LOCK( &MupPrefixTableLock );
  1266. } else {
  1267. knownPrefix->InTable = FALSE;
  1268. }
  1269. }
  1270. } else {
  1271. MupDereferenceUncProvider( queryPathContext->Provider );
  1272. if (masterContext->Provider == NULL) {
  1273. //
  1274. // If our error status is more significant than the error status
  1275. // stored in the masterContext, then put ours there
  1276. //
  1277. ULONG newError, oldError;
  1278. //
  1279. // MupOrderedErrorList is a list of error codes ordered from least
  1280. // important to most important. We're calling down to multiple
  1281. // redirectors, but we can only return 1 error code on complete failure.
  1282. //
  1283. // To figure out which error to return, we look at the stored error and
  1284. // the current error. We return the error having the highest index in
  1285. // the MupOrderedErrorList
  1286. //
  1287. if( NT_SUCCESS( masterContext->ErrorStatus ) ) {
  1288. masterContext->ErrorStatus = status;
  1289. } else {
  1290. for( oldError = 0; MupOrderedErrorList[ oldError ]; oldError++ )
  1291. if( masterContext->ErrorStatus == MupOrderedErrorList[ oldError ] )
  1292. break;
  1293. for( newError = 0; newError < oldError; newError++ )
  1294. if( status == MupOrderedErrorList[ newError ] )
  1295. break;
  1296. if( newError >= oldError ) {
  1297. masterContext->ErrorStatus = status;
  1298. }
  1299. }
  1300. }
  1301. }
  1302. not_this_one:
  1303. //
  1304. // Free our buffers
  1305. //
  1306. ExFreePool( qpResponse );
  1307. ExFreePool( queryPathContext );
  1308. IoFreeIrp( Irp );
  1309. RELEASE_LOCK( &masterContext->Lock );
  1310. MupDereferenceMasterQueryContext( masterContext );
  1311. //
  1312. // Return more processing required to the IO system so that it
  1313. // doesn't attempt further processing on the IRP we just freed.
  1314. //
  1315. return STATUS_MORE_PROCESSING_REQUIRED;
  1316. }
  1317. //+----------------------------------------------------------------------------
  1318. //
  1319. // Function: MupFlushPrefixEntry
  1320. //
  1321. // Synopsis: Given a pathname, checks if the mup has the prefix cached.
  1322. // It removes the entry if it exists from the mup cache
  1323. //
  1324. // Arguments: [FileName] -- pathname which needs to be removed.
  1325. //
  1326. // Returns: TRUE if entry found in mup cache. False otherwise.
  1327. //
  1328. //-----------------------------------------------------------------------------
  1329. BOOLEAN
  1330. MupFlushPrefixEntry(
  1331. PUNICODE_STRING pathName)
  1332. {
  1333. PUNICODE_PREFIX_TABLE_ENTRY entry;
  1334. PKNOWN_PREFIX knownPrefix;
  1335. ACQUIRE_LOCK( &MupPrefixTableLock );
  1336. entry = RtlFindUnicodePrefix( &MupPrefixTable, pathName, TRUE );
  1337. if (entry != NULL) {
  1338. knownPrefix = CONTAINING_RECORD( entry, KNOWN_PREFIX, TableEntry );
  1339. if ( knownPrefix->InTable ) {
  1340. MupRemoveKnownPrefixEntry( knownPrefix );
  1341. }
  1342. }
  1343. RELEASE_LOCK( &MupPrefixTableLock );
  1344. return (entry != NULL) ? TRUE : FALSE;
  1345. }
  1346. //+----------------------------------------------------------------------------
  1347. //
  1348. // Function: MupInvalidatePrefixTable
  1349. //
  1350. // Synopsis: Removes all the entries from the mup prefix table.
  1351. //
  1352. // Arguments: None.
  1353. //
  1354. // Returns: None.
  1355. //
  1356. //-----------------------------------------------------------------------------
  1357. VOID
  1358. MupInvalidatePrefixTable(VOID)
  1359. {
  1360. PLIST_ENTRY listEntry;
  1361. PKNOWN_PREFIX knownPrefix;
  1362. ACQUIRE_LOCK( &MupPrefixTableLock );
  1363. listEntry = MupPrefixList.Flink;
  1364. while ( listEntry != &MupPrefixList ) {
  1365. knownPrefix = CONTAINING_RECORD( listEntry, KNOWN_PREFIX, ListEntry );
  1366. listEntry = listEntry->Flink;
  1367. if ( knownPrefix->InTable ) {
  1368. MupRemoveKnownPrefixEntry( knownPrefix );
  1369. }
  1370. }
  1371. RELEASE_LOCK( &MupPrefixTableLock );
  1372. }
  1373. VOID
  1374. MupRemoveKnownPrefixEntry(
  1375. PKNOWN_PREFIX knownPrefix
  1376. )
  1377. {
  1378. MUP_TRACE_LOW(KNOWN_PREFIX, MupRemoveKnownPrefixEntry,
  1379. LOGPTR(knownPrefix));
  1380. RtlRemoveUnicodePrefix(&MupPrefixTable, &knownPrefix->TableEntry);
  1381. RemoveEntryList(&knownPrefix->ListEntry);
  1382. knownPrefix->InTable = FALSE;
  1383. MupDereferenceKnownPrefix(knownPrefix);
  1384. }
  1385. NTSTATUS
  1386. IsThisASysVolPath(
  1387. IN PUNICODE_STRING PathName,
  1388. IN PUNICODE_STRING DCName)
  1389. {
  1390. /*++
  1391. Routine Description:
  1392. Determines whether a given path is a domain-based path or not
  1393. The general algorithm is:
  1394. - Extract the first component of the path
  1395. - See if it the domain name
  1396. - If it is, and the 2nd component is SYSVOL or NETLOGON, return the DCName
  1397. Arguments
  1398. PathName - Name of entire file
  1399. DCName - If this is a domain-based path, this is the name of
  1400. a dc in the domain.
  1401. Returns value
  1402. STATUS_SUCCESS -- PathName is a domain-based path
  1403. STATUS_BAD_NETWORK_PATH -- PathName is not a domain-based path
  1404. --*/
  1405. NTSTATUS status;
  1406. PDFS_SPECIAL_ENTRY pSpecialEntry;
  1407. PUNICODE_STRING pName;
  1408. UNICODE_STRING RootName;
  1409. UNICODE_STRING ShareName;
  1410. USHORT i;
  1411. USHORT j;
  1412. PDFS_PKT Pkt;
  1413. BOOLEAN pktLocked;
  1414. DfsDbgTrace(+1, Dbg, "IsThisASysVolPath: PathName %wZ \n", PathName);
  1415. //
  1416. // Only proceed if the first character is a backslash.
  1417. //
  1418. if (PathName->Buffer[0] != UNICODE_PATH_SEP) {
  1419. DfsDbgTrace(-1, Dbg, "PathName does not begin with backslash\n", 0);
  1420. return( STATUS_BAD_NETWORK_PATH );
  1421. }
  1422. //
  1423. // Find the first component in the name.
  1424. //
  1425. for (i = 1;
  1426. i < PathName->Length/sizeof(WCHAR) &&
  1427. PathName->Buffer[i] != UNICODE_PATH_SEP;
  1428. i++) {
  1429. NOTHING;
  1430. }
  1431. if (PathName->Buffer[i] != UNICODE_PATH_SEP) {
  1432. DfsDbgTrace(-1, Dbg, "Did not find second backslash\n", 0);
  1433. return( STATUS_BAD_NETWORK_PATH );
  1434. }
  1435. RootName.Length = (i-1) * sizeof(WCHAR);
  1436. RootName.MaximumLength = RootName.Length;
  1437. RootName.Buffer = &PathName->Buffer[1];
  1438. if (RootName.Length == 0)
  1439. return( STATUS_BAD_NETWORK_PATH );
  1440. //
  1441. // Figure out the share name
  1442. //
  1443. for (j = i+1;
  1444. j < PathName->Length/sizeof(WCHAR) &&
  1445. PathName->Buffer[j] != UNICODE_PATH_SEP;
  1446. j++) {
  1447. NOTHING;
  1448. }
  1449. ShareName.Length = (j - i - 1) * sizeof(WCHAR);
  1450. ShareName.MaximumLength = ShareName.Length;
  1451. ShareName.Buffer = &PathName->Buffer[i+1];
  1452. if (ShareName.Length == 0 || DfspIsSysVolShare(&ShareName) == FALSE)
  1453. return( STATUS_BAD_NETWORK_PATH );
  1454. Pkt = _GetPkt();
  1455. PktAcquireShared(TRUE, &pktLocked);
  1456. if (
  1457. (Pkt->DomainNameFlat.Buffer != NULL
  1458. &&
  1459. Pkt->DomainNameDns.Buffer != NULL
  1460. &&
  1461. Pkt->DCName.Buffer != NULL)
  1462. &&
  1463. (RtlCompareUnicodeString(&RootName, &Pkt->DomainNameFlat, TRUE) == 0
  1464. ||
  1465. RtlCompareUnicodeString(&RootName, &Pkt->DomainNameDns, TRUE) == 0)
  1466. ) {
  1467. pName = &Pkt->DCName;
  1468. DCName->Buffer = ExAllocatePoolWithTag(
  1469. PagedPool,
  1470. pName->MaximumLength,
  1471. ' puM');
  1472. if (DCName->Buffer != NULL) {
  1473. DCName->Length = pName->Length;
  1474. DCName->MaximumLength = pName->MaximumLength;
  1475. RtlCopyMemory(
  1476. DCName->Buffer,
  1477. pName->Buffer,
  1478. pName->MaximumLength);
  1479. status = STATUS_SUCCESS;
  1480. } else {
  1481. status = STATUS_INSUFFICIENT_RESOURCES;
  1482. }
  1483. } else {
  1484. status = STATUS_BAD_NETWORK_PATH;
  1485. }
  1486. PktRelease();
  1487. DfsDbgTrace(-1, Dbg, "IsThisASysVolPath: Exit -> %08lx\n", LongToPtr( status ) );
  1488. return status;
  1489. }
  1490. NTSTATUS
  1491. MupDomainToDC(
  1492. PUNICODE_STRING RootName,
  1493. PUNICODE_STRING DCName)
  1494. {
  1495. /*++
  1496. Routine Description:
  1497. This routine rewrites the file name of a domain-based path into a dc-based
  1498. path. Ex: \domainfoo\sysvol -> \dc1\sysvol
  1499. Arguments:
  1500. RootName - The RootName to rewrite
  1501. DCName - The name of the DC to change the path to
  1502. Return Value:
  1503. NTSTATUS - The status of the operation
  1504. --*/
  1505. ULONG Size;
  1506. PCHAR Buffer;
  1507. PWCHAR pBuf;
  1508. PWCHAR OrgBuffer;
  1509. PAGED_CODE();
  1510. DfsDbgTrace(+1, Dbg, "MupDomainToDC: RootName = %wZ\n", RootName);
  1511. //
  1512. // Only proceed if the first character is a backslash.
  1513. //
  1514. if (RootName->Buffer == NULL) {
  1515. DfsDbgTrace(-1, Dbg, "RootName is NULL\n", 0);
  1516. return( STATUS_BAD_NETWORK_PATH );
  1517. }
  1518. if (RootName->Buffer[0] != UNICODE_PATH_SEP) {
  1519. DfsDbgTrace(-1, Dbg, "RootName does not begin with backslash\n", 0);
  1520. return( STATUS_BAD_NETWORK_PATH );
  1521. }
  1522. OrgBuffer = RootName->Buffer;
  1523. //
  1524. // Skip over leading UNICODE_PATH_SEP
  1525. //
  1526. RootName->Length -= sizeof(WCHAR);
  1527. RootName->MaximumLength -= sizeof(WCHAR);
  1528. RootName->Buffer++;
  1529. //
  1530. // Motor along until end of string or a UNICODE_PATH_SEP
  1531. //
  1532. while (RootName->Length > 0 && RootName->Buffer[0] != UNICODE_PATH_SEP) {
  1533. RootName->Length -= sizeof(WCHAR);
  1534. RootName->MaximumLength -= sizeof(WCHAR);
  1535. RootName->Buffer++;
  1536. }
  1537. if (RootName->Length == 0) {
  1538. DfsDbgTrace(-1, Dbg, "Did not find second backslash\n", 0);
  1539. return( STATUS_BAD_NETWORK_PATH );
  1540. }
  1541. //
  1542. // Allocate storage for the new file name.
  1543. //
  1544. Size = sizeof(WCHAR) + // leading UNICODE_PATH_SEP
  1545. DCName->Length +
  1546. RootName->Length;
  1547. Buffer = ExAllocatePoolWithTag(
  1548. PagedPool,
  1549. Size,
  1550. ' puM');
  1551. if ( Buffer == NULL)
  1552. return STATUS_INSUFFICIENT_RESOURCES;
  1553. //
  1554. // Leading UNICODE_PATH_SEP's
  1555. //
  1556. pBuf = (WCHAR *)Buffer;
  1557. *pBuf++ = UNICODE_PATH_SEP;
  1558. //
  1559. // Copy the DC name to the buffer
  1560. //
  1561. RtlMoveMemory(
  1562. pBuf,
  1563. DCName->Buffer,
  1564. DCName->Length);
  1565. pBuf += DCName->Length / sizeof(WCHAR);
  1566. //
  1567. // Append the trailing file name
  1568. //
  1569. RtlMoveMemory(
  1570. pBuf,
  1571. RootName->Buffer,
  1572. RootName->Length);
  1573. //
  1574. // Free the old file name string buffer.
  1575. //
  1576. ExFreePool( OrgBuffer );
  1577. RootName->Buffer = (PWCHAR)Buffer;
  1578. RootName->Length = (USHORT) Size;
  1579. RootName->MaximumLength = (USHORT) Size;
  1580. DfsDbgTrace(+1, Dbg, "MupDomainToDC: Exit\n", 0);
  1581. return STATUS_SUCCESS;
  1582. }