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.

2144 lines
58 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. {
  530. UNICODE_STRING NewName = FileObject->FileName;
  531. status = MupDomainToDC(&NewName, &DCName);
  532. if (DCName.Buffer != NULL)
  533. ExFreePool(DCName.Buffer);
  534. if (status == STATUS_SUCCESS)
  535. {
  536. FileObject->FileName = NewName;
  537. }
  538. else
  539. {
  540. return status;
  541. }
  542. }
  543. }
  544. }
  545. //
  546. // We don't know who owns this file, query the redirectors in sequence
  547. // until one works.
  548. //
  549. IoMarkIrpPending(Irp);
  550. //
  551. // Allocate the master context and knownprefix. If either allocation fails, we'll
  552. // complete the irp with STATUS_INSUFFICIENT_RESOURCES
  553. //
  554. knownPrefix = MupAllocatePrefixEntry( 0 );
  555. if (knownPrefix == NULL) {
  556. MupCompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES);
  557. return STATUS_PENDING;
  558. }
  559. masterContext = MupAllocateMasterQueryContext();
  560. if (masterContext == NULL) {
  561. ExFreePool(knownPrefix);
  562. MupCompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES);
  563. return STATUS_PENDING;
  564. }
  565. try {
  566. masterContext->OriginalIrp = Irp;
  567. masterContext->FileObject = FileObject;
  568. masterContext->Provider = NULL;
  569. masterContext->KnownPrefix = knownPrefix;
  570. masterContext->ErrorStatus = STATUS_BAD_NETWORK_PATH;
  571. MupAcquireGlobalLock();
  572. // for debugging: insert the Master Context into the global list.
  573. InsertHeadList(&MupMasterQueryList, &masterContext->MasterQueryList);
  574. MupReferenceBlock( knownPrefix );
  575. MupReleaseGlobalLock();
  576. try {
  577. MupAcquireGlobalLock();
  578. ownLock = TRUE;
  579. listEntry = MupProviderList.Flink;
  580. while ( listEntry != &MupProviderList ) {
  581. provider = CONTAINING_RECORD(
  582. listEntry,
  583. UNC_PROVIDER,
  584. ListEntry
  585. );
  586. //
  587. // Reference the provider block so that it doesn't go away
  588. // while we are using it.
  589. //
  590. MupReferenceBlock( provider );
  591. providerReferenced = TRUE;
  592. MupReleaseGlobalLock();
  593. ownLock = FALSE;
  594. // only use this provider if it is registered
  595. if(provider->Registered) {
  596. //
  597. // Allocate buffers for the io request.
  598. //
  599. qpRequest = NULL;
  600. queryContext = NULL;
  601. qpRequest = ExAllocatePoolWithTag(
  602. PagedPool,
  603. sizeof( QUERY_PATH_REQUEST ) +
  604. FileObject->FileName.Length,
  605. ' puM');
  606. if (qpRequest == NULL) {
  607. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  608. }
  609. queryContext = ExAllocatePoolWithTag(
  610. PagedPool,
  611. sizeof( QUERY_PATH_CONTEXT ),
  612. ' puM');
  613. if (queryContext == NULL) {
  614. ExFreePool(qpRequest);
  615. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  616. }
  617. InitializeListHead(&queryContext->QueryList);
  618. queryContext->MasterContext = masterContext;
  619. queryContext->Buffer = qpRequest;
  620. //
  621. // Generate a query path request.
  622. //
  623. qpRequest->PathNameLength = FileObject->FileName.Length;
  624. qpRequest->SecurityContext = SecurityContext;
  625. RtlMoveMemory(
  626. qpRequest->FilePathName,
  627. FileObject->FileName.Buffer,
  628. FileObject->FileName.Length
  629. );
  630. //
  631. // Build the query path Io control IRP.
  632. //
  633. irp = MupBuildIoControlRequest(
  634. NULL,
  635. provider->FileObject,
  636. queryContext,
  637. IRP_MJ_DEVICE_CONTROL,
  638. IOCTL_REDIR_QUERY_PATH,
  639. qpRequest,
  640. sizeof( QUERY_PATH_REQUEST ) + FileObject->FileName.Length,
  641. qpRequest,
  642. sizeof( QUERY_PATH_RESPONSE ),
  643. QueryPathCompletionRoutine
  644. );
  645. if ( irp == NULL ) {
  646. ExFreePool(qpRequest);
  647. ExFreePool(queryContext);
  648. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  649. }
  650. //
  651. // Set the RequestorMode to KernelMode, since all the
  652. // parameters to this Irp are in kernel space
  653. //
  654. irp->RequestorMode = KernelMode;
  655. //
  656. // Get a referenced pointer to the provider, the reference
  657. // is release when the IO completes.
  658. //
  659. queryContext->Provider = provider;
  660. queryContext->QueryIrp = irp;
  661. MupAcquireGlobalLock();
  662. MupReferenceBlock( provider );
  663. MupReferenceBlock( masterContext );
  664. MupReleaseGlobalLock();
  665. // insert this query into the master context's list of queries (for debugging)
  666. ACQUIRE_LOCK( &masterContext->Lock );
  667. InsertHeadList(&masterContext->QueryList, &queryContext->QueryList);
  668. RELEASE_LOCK( &masterContext->Lock );
  669. //
  670. // Submit the request.
  671. //
  672. MUP_TRACE_HIGH(ALL_ERROR, CreateRedirectedFile_Before_IoCallDriver,
  673. LOGPTR(masterContext->OriginalIrp)
  674. LOGPTR(queryContext->QueryIrp)
  675. LOGPTR(FileObject)
  676. LOGUSTR(FileName)
  677. LOGUSTR(provider->DeviceName));
  678. status = IoCallDriver( provider->DeviceObject, irp );
  679. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, CreateRedirectedFile_Error_IoCallDriver,
  680. LOGSTATUS(status)
  681. LOGPTR(masterContext->OriginalIrp)
  682. LOGPTR(FileObject)
  683. LOGUSTR(provider->DeviceName));
  684. } // if registered
  685. //
  686. // Acquire the lock that protects the provider list, and get
  687. // a pointer to the next provider in the list.
  688. //
  689. MupAcquireGlobalLock();
  690. ownLock = TRUE;
  691. listEntry = listEntry->Flink;
  692. MupDereferenceUncProvider( provider );
  693. providerReferenced = FALSE;
  694. //
  695. // If this is the first provider and it responded with SUCCESS, we can return early.
  696. // The list of providers is sorted in order of priority, so we know that this is
  697. // the highest prority provider and it can get to the destination.
  698. //
  699. if( firstProvider && (status == STATUS_SUCCESS) ) {
  700. break;
  701. }
  702. firstProvider = FALSE;
  703. } // while
  704. } finally {
  705. //
  706. // Dereference the previous provider.
  707. //
  708. if ( providerReferenced ) {
  709. MupDereferenceUncProvider( provider );
  710. }
  711. if ( ownLock ) {
  712. MupReleaseGlobalLock();
  713. }
  714. }
  715. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  716. masterContext->ErrorStatus = STATUS_INSUFFICIENT_RESOURCES;
  717. }
  718. ASSERT(masterContext != NULL);
  719. //
  720. // Release our reference to the query context.
  721. //
  722. MupDereferenceMasterQueryContext( masterContext );
  723. status = STATUS_PENDING;
  724. MUP_TRACE_LOW(DEFAULT, CreateRedirectedFile_Exit,
  725. LOGSTATUS(status)
  726. LOGPTR(Irp)
  727. LOGPTR(FileObject));
  728. DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
  729. return status;
  730. }
  731. NTSTATUS
  732. MupRerouteOpen (
  733. IN PFILE_OBJECT FileObject,
  734. IN PUNC_PROVIDER UncProvider
  735. )
  736. /*++
  737. Routine Description:
  738. This routine redirects an create IRP request to the specified redirector
  739. by changing the name of the file and returning STATUS_REPARSE to the
  740. IO system
  741. Arguments:
  742. FileObject - The file object to open
  743. UncProvider - The UNC provider that will process the create IRP.
  744. Return Value:
  745. NTSTATUS - The status of the operation
  746. --*/
  747. {
  748. PCHAR buffer;
  749. ULONG deviceNameLength;
  750. ULONG nameLength;
  751. NTSTATUS status;
  752. UNICODE_STRING FileName = FileObject->FileName;
  753. //
  754. // Check that we won't create a name that is too long
  755. //
  756. nameLength = UncProvider->DeviceName.Length + FileObject->FileName.Length;
  757. if (nameLength > MAXUSHORT) {
  758. status = STATUS_NAME_TOO_LONG;
  759. MUP_TRACE_HIGH(ERROR, MupRerouteOpen_Error1,
  760. LOGSTATUS(status)
  761. LOGPTR(FileObject)
  762. LOGUSTR(FileName));
  763. return STATUS_NAME_TOO_LONG;
  764. }
  765. //
  766. // Allocate storage for the new file name.
  767. //
  768. buffer = ExAllocatePoolWithTag(
  769. PagedPool,
  770. UncProvider->DeviceName.Length + FileObject->FileName.Length,
  771. ' puM');
  772. if ( buffer == NULL) {
  773. status = STATUS_INSUFFICIENT_RESOURCES;
  774. MUP_TRACE_HIGH(ERROR, MupRerouteOpen_Error2,
  775. LOGSTATUS(status)
  776. LOGPTR(FileObject)
  777. LOGUSTR(FileName));
  778. return status;
  779. }
  780. //
  781. // Copy the device name to the string buffer.
  782. //
  783. RtlMoveMemory(
  784. buffer,
  785. UncProvider->DeviceName.Buffer,
  786. UncProvider->DeviceName.Length);
  787. deviceNameLength = UncProvider->DeviceName.Length;
  788. //
  789. // Append the file name
  790. //
  791. RtlMoveMemory(
  792. buffer + deviceNameLength,
  793. FileObject->FileName.Buffer,
  794. FileObject->FileName.Length);
  795. //
  796. // Free the old file name string buffer.
  797. //
  798. ExFreePool( FileObject->FileName.Buffer );
  799. FileObject->FileName.Buffer = (PWCHAR)buffer;
  800. FileObject->FileName.MaximumLength = FileObject->FileName.Length + (USHORT)deviceNameLength;
  801. FileObject->FileName.Length = FileObject->FileName.MaximumLength;
  802. //
  803. // Tell the file system to try again.
  804. //
  805. return STATUS_REPARSE;
  806. }
  807. NTSTATUS
  808. MupRerouteOpenToDfs (
  809. IN PFILE_OBJECT FileObject
  810. )
  811. /*++
  812. Routine Description:
  813. This routine redirects an create IRP request to the Dfs part of this
  814. driver by changing the name of the file and returning
  815. STATUS_REPARSE to the IO system
  816. Arguments:
  817. FileObject - The file object to open
  818. Return Value:
  819. NTSTATUS - The status of the operation
  820. --*/
  821. {
  822. PCHAR buffer;
  823. ULONG deviceNameLength;
  824. ULONG nameLength;
  825. NTSTATUS status;
  826. UNICODE_STRING FileName = FileObject->FileName;
  827. PAGED_CODE();
  828. MUP_TRACE_NORM(TRACE_IRP, MupRerouteOpenToDfs_Entry,
  829. LOGPTR(FileObject)
  830. LOGUSTR(FileName));
  831. #if DBG
  832. if (MupVerbose)
  833. DbgPrint("MupRerouteOpenToDfs(%wZ)\n", &FileObject->FileName);
  834. #endif
  835. deviceNameLength = sizeof(DFS_DEVICE_ROOT) - sizeof(UNICODE_NULL);
  836. //
  837. // Check that we won't create a name that is too long
  838. //
  839. nameLength = deviceNameLength + FileObject->FileName.Length;
  840. if (nameLength > MAXUSHORT) {
  841. status = STATUS_NAME_TOO_LONG;
  842. MUP_TRACE_HIGH(ERROR, MupRerouteOpenToDfs_Error1,
  843. LOGSTATUS(status)
  844. LOGPTR(FileObject)
  845. LOGUSTR(FileName));
  846. #if DBG
  847. if (MupVerbose)
  848. DbgPrint("MupRerouteOpenToDfs exit STATUS_NAME_TOO_LONG\n");
  849. #endif
  850. return STATUS_NAME_TOO_LONG;
  851. }
  852. //
  853. // Allocate storage for the new file name.
  854. //
  855. buffer = ExAllocatePoolWithTag(
  856. PagedPool,
  857. sizeof(DFS_DEVICE_ROOT) + FileObject->FileName.Length,
  858. ' puM');
  859. if ( buffer == NULL) {
  860. status = STATUS_INSUFFICIENT_RESOURCES;
  861. MUP_TRACE_HIGH(ERROR, MupRerouteOpenToDfs_Error2,
  862. LOGSTATUS(status)
  863. LOGPTR(FileObject)
  864. LOGUSTR(FileName));
  865. #if DBG
  866. if (MupVerbose)
  867. DbgPrint("MupRerouteOpenToDfs exit STATUS_INSUFFICIENT_RESOURCES\n");
  868. #endif
  869. return STATUS_INSUFFICIENT_RESOURCES;
  870. }
  871. //
  872. // Copy the device name to the string buffer.
  873. //
  874. RtlMoveMemory(
  875. buffer,
  876. DFS_DEVICE_ROOT,
  877. sizeof(DFS_DEVICE_ROOT));
  878. //
  879. // Append the file name
  880. //
  881. RtlMoveMemory(
  882. buffer + deviceNameLength,
  883. FileObject->FileName.Buffer,
  884. FileObject->FileName.Length);
  885. //
  886. // Free the old file name string buffer.
  887. //
  888. ExFreePool( FileObject->FileName.Buffer );
  889. FileObject->FileName.Buffer = (PWCHAR)buffer;
  890. FileObject->FileName.MaximumLength = FileObject->FileName.Length + (USHORT)deviceNameLength;
  891. FileObject->FileName.Length = FileObject->FileName.MaximumLength;
  892. //
  893. // Tell the file system to try again.
  894. //
  895. #if DBG
  896. if (MupVerbose)
  897. DbgPrint("MupRerouteOpenToDfs exit STATUS_REPARSE ->[%wZ]\n", &FileObject->FileName);
  898. #endif
  899. return STATUS_REPARSE;
  900. }
  901. NTSTATUS
  902. BroadcastOpen (
  903. PIRP Irp
  904. )
  905. /*++
  906. Routine Description:
  907. Arguments:
  908. Return Value:
  909. NTSTATUS - The status for the IRP.
  910. --*/
  911. {
  912. NTSTATUS status;
  913. PFCB fcb;
  914. PIO_STACK_LOCATION irpSp;
  915. PFILE_OBJECT fileObject;
  916. BOOLEAN requestForwarded;
  917. PLIST_ENTRY listEntry;
  918. PUNC_PROVIDER uncProvider, previousUncProvider = NULL;
  919. OBJECT_ATTRIBUTES objectAttributes;
  920. IO_STATUS_BLOCK ioStatusBlock;
  921. PCCB ccb;
  922. OBJECT_HANDLE_INFORMATION handleInformation;
  923. HANDLE handle;
  924. BOOLEAN lockHeld = FALSE;
  925. BOOLEAN providerReferenced = FALSE;
  926. ULONG Len;
  927. UNICODE_STRING FileName;
  928. NTSTATUS statusToReturn = STATUS_NO_SUCH_FILE;
  929. ULONG priorityOfStatus = 0xFFFFFFFF;
  930. PAGED_CODE();
  931. DebugTrace(+1, Dbg, "BroadcastOpen\n", 0 );
  932. irpSp = IoGetCurrentIrpStackLocation( Irp );
  933. FileName = irpSp->FileObject->FileName;
  934. try {
  935. //
  936. // Create a FCB for this file.
  937. //
  938. fcb = MupCreateFcb( );
  939. if (fcb == NULL) {
  940. status = STATUS_INSUFFICIENT_RESOURCES;
  941. MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error1,
  942. LOGSTATUS(status)
  943. LOGPTR(Irp)
  944. LOGPTR(irpSp->FileObject)
  945. LOGUSTR(FileName));
  946. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  947. }
  948. try {
  949. //
  950. // Set the file object back pointers and our pointer to the
  951. // server file object.
  952. //
  953. fileObject = irpSp->FileObject;
  954. MupAcquireGlobalLock();
  955. lockHeld = TRUE;
  956. MupSetFileObject( fileObject,
  957. fcb,
  958. NULL );
  959. fcb->FileObject = fileObject;
  960. //
  961. // Loop through the list of UNC providers and try to create the
  962. // file on all file systems that support broadcast.
  963. //
  964. requestForwarded = FALSE;
  965. listEntry = MupProviderList.Flink;
  966. while ( listEntry != &MupProviderList ) {
  967. uncProvider = CONTAINING_RECORD( listEntry, UNC_PROVIDER, ListEntry );
  968. //
  969. // Reference the provider so that it won't go away
  970. //
  971. MupReferenceBlock( uncProvider );
  972. providerReferenced = TRUE;
  973. MupReleaseGlobalLock();
  974. lockHeld = FALSE;
  975. Len = uncProvider->DeviceName.Length + fileObject->FileName.Length;
  976. if ( uncProvider->MailslotsSupported && Len <= MAXUSHORT) {
  977. //
  978. // Build the rerouted file name, consisting of the file
  979. // named we received appended to the UNC provider device
  980. // name.
  981. //
  982. UNICODE_STRING fileName;
  983. fileName.MaximumLength = fileName.Length = (USHORT) Len;
  984. fileName.Buffer =
  985. ExAllocatePoolWithTag(
  986. PagedPool,
  987. fileName.MaximumLength,
  988. ' puM');
  989. if (fileName.Buffer == NULL) {
  990. status = STATUS_INSUFFICIENT_RESOURCES;
  991. MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error2,
  992. LOGSTATUS(status)
  993. LOGPTR(Irp)
  994. LOGPTR(fileObject)
  995. LOGUSTR(FileName));
  996. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  997. }
  998. RtlMoveMemory(
  999. fileName.Buffer,
  1000. uncProvider->DeviceName.Buffer,
  1001. uncProvider->DeviceName.Length
  1002. );
  1003. RtlMoveMemory(
  1004. (PCHAR)fileName.Buffer + uncProvider->DeviceName.Length,
  1005. fileObject->FileName.Buffer,
  1006. fileObject->FileName.Length
  1007. );
  1008. //
  1009. // Attempt to open the file. Copy all of the information
  1010. // from the create IRP we received, masking off additional
  1011. // baggage that the IO system added along the way.
  1012. //
  1013. DebugTrace( 0, Dbg, "Attempt to open %Z\n", (ULONG)&fileName );
  1014. InitializeObjectAttributes(
  1015. &objectAttributes,
  1016. &fileName,
  1017. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1018. 0,
  1019. NULL // !!! Security
  1020. );
  1021. status = IoCreateFile(
  1022. &handle,
  1023. irpSp->Parameters.Create.SecurityContext->DesiredAccess & 0x1FF,
  1024. &objectAttributes,
  1025. &ioStatusBlock,
  1026. NULL,
  1027. irpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS,
  1028. irpSp->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS,
  1029. FILE_OPEN,
  1030. irpSp->Parameters.Create.Options & FILE_VALID_SET_FLAGS,
  1031. NULL, // Ea buffer
  1032. 0, // Ea length
  1033. CreateFileTypeNone,
  1034. NULL, // parameters
  1035. IO_NO_PARAMETER_CHECKING
  1036. );
  1037. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, BroadcastOpen_Error_IoCreateFile,
  1038. LOGSTATUS(status)
  1039. LOGPTR(Irp)
  1040. LOGPTR(fileObject)
  1041. LOGUSTR(FileName));
  1042. ExFreePool( fileName.Buffer );
  1043. if ( NT_SUCCESS( status ) ) {
  1044. status = ioStatusBlock.Status;
  1045. ccb = MupCreateCcb( );
  1046. if (ccb == NULL) {
  1047. status = STATUS_INSUFFICIENT_RESOURCES;
  1048. MUP_TRACE_HIGH(ERROR, BroadcastOpen_Error3,
  1049. LOGSTATUS(status)
  1050. LOGPTR(Irp)
  1051. LOGPTR(fileObject)
  1052. LOGUSTR(FileName));
  1053. }
  1054. }
  1055. if ( NT_SUCCESS( status ) ) {
  1056. DebugTrace( 0, Dbg, "Open attempt succeeded\n", 0 );
  1057. //
  1058. // 426184, need to check return code for errors.
  1059. //
  1060. status = ObReferenceObjectByHandle(
  1061. handle,
  1062. 0,
  1063. NULL,
  1064. KernelMode,
  1065. (PVOID *)&ccb->FileObject,
  1066. &handleInformation );
  1067. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, BroadcastOpen_Error_ObReferenceObjectByHandle,
  1068. LOGSTATUS(status)
  1069. LOGPTR(Irp)
  1070. LOGPTR(fileObject)
  1071. LOGUSTR(FileName));
  1072. ZwClose( handle );
  1073. }
  1074. if ( NT_SUCCESS( status ) ) {
  1075. ccb->DeviceObject =
  1076. IoGetRelatedDeviceObject( ccb->FileObject );
  1077. ccb->Fcb = fcb;
  1078. MupAcquireGlobalLock();
  1079. lockHeld = TRUE;
  1080. MupReferenceBlock( fcb );
  1081. MupReleaseGlobalLock();
  1082. lockHeld = FALSE;
  1083. //
  1084. // At least one provider will accept this mailslot
  1085. // request.
  1086. //
  1087. requestForwarded = TRUE;
  1088. //
  1089. // Keep a list of CCBs. Since we just created the FCB
  1090. // there is no need to use the lock to access the list.
  1091. //
  1092. InsertTailList( &fcb->CcbList, &ccb->ListEntry );
  1093. } else { // NT_SUCCESS( status ), IoCreateFile
  1094. DebugTrace( 0, Dbg, "Open attempt failed %8lx\n", status );
  1095. //
  1096. // Remember the status code if this is the highest
  1097. // priority provider so far. This code is returned if
  1098. // all providers fail the Create operation.
  1099. //
  1100. if ( uncProvider->Priority <= priorityOfStatus ) {
  1101. priorityOfStatus = uncProvider->Priority;
  1102. statusToReturn = status;
  1103. }
  1104. }
  1105. } // uncProvider->MailslotsSupported
  1106. MupAcquireGlobalLock();
  1107. lockHeld = TRUE;
  1108. listEntry = listEntry->Flink;
  1109. //
  1110. // It is now safe to dereference the previous provider.
  1111. //
  1112. MupDereferenceUncProvider( uncProvider );
  1113. providerReferenced = FALSE;
  1114. } // while
  1115. MupReleaseGlobalLock();
  1116. lockHeld = FALSE;
  1117. //
  1118. // And set our return status
  1119. //
  1120. if ( requestForwarded ) {
  1121. status = STATUS_SUCCESS;
  1122. } else {
  1123. status = statusToReturn;
  1124. }
  1125. } finally {
  1126. DebugTrace(-1, Dbg, "BroadcastOpen -> %08lx\n", status);
  1127. if ( providerReferenced ) {
  1128. MupDereferenceUncProvider( uncProvider );
  1129. }
  1130. if ( lockHeld ) {
  1131. MupReleaseGlobalLock();
  1132. }
  1133. //
  1134. // Now if we ever terminate the preceding try-statement with
  1135. // a status that is not successful and the FCB pointer
  1136. // is non-null then we need to deallocate the structure.
  1137. //
  1138. if (!NT_SUCCESS( status ) && fcb != NULL) {
  1139. MupFreeFcb( fcb );
  1140. }
  1141. }
  1142. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  1143. NOTHING;
  1144. }
  1145. return status;
  1146. }
  1147. NTSTATUS
  1148. QueryPathCompletionRoutine (
  1149. IN PDEVICE_OBJECT DeviceObject,
  1150. IN PIRP Irp,
  1151. IN PVOID Context
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. This is the completion routine the querying a path. Cleanup our
  1156. IRP and complete the original IRP if necessary.
  1157. Arguments:
  1158. DeviceObject - Pointer to target device object for the request.
  1159. Irp - Pointer to I/O request packet
  1160. Context - Caller-specified context parameter associated with IRP.
  1161. This is actually a pointer to a Work Context block.
  1162. Return Value:
  1163. NTSTATUS - If STATUS_MORE_PROCESSING_REQUIRED is returned, I/O
  1164. completion processing by IoCompleteRequest terminates its
  1165. operation. Otherwise, IoCompleteRequest continues with I/O
  1166. completion.
  1167. --*/
  1168. {
  1169. PQUERY_PATH_RESPONSE qpResponse;
  1170. PMASTER_QUERY_PATH_CONTEXT masterContext;
  1171. PQUERY_PATH_CONTEXT queryPathContext;
  1172. PCH buffer;
  1173. PKNOWN_PREFIX knownPrefix;
  1174. ULONG lengthAccepted;
  1175. NTSTATUS status;
  1176. DeviceObject; // prevent compiler warnings
  1177. queryPathContext = Context;
  1178. masterContext = queryPathContext->MasterContext;
  1179. qpResponse = queryPathContext->Buffer;
  1180. lengthAccepted = qpResponse->LengthAccepted;
  1181. status = Irp->IoStatus.Status;
  1182. MUP_TRACE_NORM(TRACE_IRP, QueryPathCompletionRoutine_Enter,
  1183. LOGPTR(DeviceObject)
  1184. LOGPTR(Irp)
  1185. LOGUSTR(queryPathContext->Provider->DeviceName)
  1186. LOGPTR(masterContext->FileObject)
  1187. LOGUSTR(masterContext->FileObject->FileName)
  1188. LOGSTATUS(status)
  1189. );
  1190. //
  1191. // Acquire the lock to protect access to the master context Provider
  1192. // field.
  1193. //
  1194. ACQUIRE_LOCK( &masterContext->Lock );
  1195. // remove this query from the MasterQueryContext's list.
  1196. RemoveEntryList(&queryPathContext->QueryList);
  1197. if (NT_SUCCESS(status) && lengthAccepted != 0) {
  1198. knownPrefix = masterContext->KnownPrefix;
  1199. if ( masterContext->Provider != NULL ) {
  1200. if ( queryPathContext->Provider->Priority < masterContext->Provider->Priority ) {
  1201. //
  1202. // A provider of higher priority (i.e. a lower priority code)
  1203. // has claimed this prefix. Release the previous provider's
  1204. // claim.
  1205. //
  1206. ACQUIRE_LOCK( &MupPrefixTableLock );
  1207. if ( knownPrefix->InTable ) {
  1208. RtlRemoveUnicodePrefix(&MupPrefixTable, &knownPrefix->TableEntry);
  1209. RemoveEntryList(&knownPrefix->ListEntry);
  1210. knownPrefix->InTable = FALSE;
  1211. }
  1212. RELEASE_LOCK( &MupPrefixTableLock );
  1213. knownPrefix->Active = FALSE;
  1214. //
  1215. // If Dfs generated this query there will not have been anything
  1216. // stored in the knowPrefix->Prefix, so we check if there is indeed
  1217. // anything to free.
  1218. //
  1219. if (knownPrefix->Prefix.Length > 0 && knownPrefix->Prefix.Buffer != NULL) {
  1220. ExFreePool(knownPrefix->Prefix.Buffer);
  1221. knownPrefix->Prefix.Length = knownPrefix->Prefix.MaximumLength = 0;
  1222. knownPrefix->Prefix.Buffer = NULL;
  1223. knownPrefix->PrefixStringAllocated = FALSE;
  1224. }
  1225. if(knownPrefix->UncProvider) {
  1226. MupDereferenceUncProvider( knownPrefix->UncProvider );
  1227. knownPrefix->UncProvider = NULL;
  1228. }
  1229. } else {
  1230. //
  1231. // The current provider keeps ownership of the prefix.
  1232. //
  1233. MupDereferenceUncProvider( queryPathContext->Provider );
  1234. goto not_this_one;
  1235. }
  1236. }
  1237. //
  1238. // This provider gets the prefix.
  1239. //
  1240. masterContext->Provider = queryPathContext->Provider;
  1241. masterContext->ErrorStatus = status;
  1242. //
  1243. // We have found a match. Attempt to remember it.
  1244. //
  1245. if (masterContext->FileObject->FsContext2 != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT)) {
  1246. buffer = ExAllocatePoolWithTag(
  1247. PagedPool,
  1248. lengthAccepted,
  1249. ' puM');
  1250. if (buffer != NULL) {
  1251. RtlMoveMemory(
  1252. buffer,
  1253. masterContext->FileObject->FileName.Buffer,
  1254. lengthAccepted
  1255. );
  1256. //
  1257. // Copy the reference provider pointer for the known prefix
  1258. // block.
  1259. //
  1260. knownPrefix->UncProvider = masterContext->Provider;
  1261. knownPrefix->Prefix.Buffer = (PWCH)buffer;
  1262. knownPrefix->Prefix.Length = (USHORT)lengthAccepted;
  1263. knownPrefix->Prefix.MaximumLength = (USHORT)lengthAccepted;
  1264. knownPrefix->PrefixStringAllocated = TRUE;
  1265. ACQUIRE_LOCK( &MupPrefixTableLock );
  1266. if (RtlInsertUnicodePrefix(
  1267. &MupPrefixTable,
  1268. &knownPrefix->Prefix,
  1269. &knownPrefix->TableEntry) == TRUE) {
  1270. InsertTailList( &MupPrefixList, &knownPrefix->ListEntry);
  1271. knownPrefix->InTable = TRUE;
  1272. knownPrefix->Active = TRUE;
  1273. } else {
  1274. knownPrefix->InTable = FALSE;
  1275. }
  1276. RELEASE_LOCK( &MupPrefixTableLock );
  1277. } else {
  1278. knownPrefix->InTable = FALSE;
  1279. }
  1280. }
  1281. } else {
  1282. MupDereferenceUncProvider( queryPathContext->Provider );
  1283. if (masterContext->Provider == NULL) {
  1284. //
  1285. // If our error status is more significant than the error status
  1286. // stored in the masterContext, then put ours there
  1287. //
  1288. ULONG newError, oldError;
  1289. //
  1290. // MupOrderedErrorList is a list of error codes ordered from least
  1291. // important to most important. We're calling down to multiple
  1292. // redirectors, but we can only return 1 error code on complete failure.
  1293. //
  1294. // To figure out which error to return, we look at the stored error and
  1295. // the current error. We return the error having the highest index in
  1296. // the MupOrderedErrorList
  1297. //
  1298. if( NT_SUCCESS( masterContext->ErrorStatus ) ) {
  1299. masterContext->ErrorStatus = status;
  1300. } else {
  1301. for( oldError = 0; MupOrderedErrorList[ oldError ]; oldError++ )
  1302. if( masterContext->ErrorStatus == MupOrderedErrorList[ oldError ] )
  1303. break;
  1304. for( newError = 0; newError < oldError; newError++ )
  1305. if( status == MupOrderedErrorList[ newError ] )
  1306. break;
  1307. if( newError >= oldError ) {
  1308. masterContext->ErrorStatus = status;
  1309. }
  1310. }
  1311. }
  1312. }
  1313. not_this_one:
  1314. //
  1315. // Free our buffers
  1316. //
  1317. ExFreePool( qpResponse );
  1318. ExFreePool( queryPathContext );
  1319. IoFreeIrp( Irp );
  1320. RELEASE_LOCK( &masterContext->Lock );
  1321. MupDereferenceMasterQueryContext( masterContext );
  1322. //
  1323. // Return more processing required to the IO system so that it
  1324. // doesn't attempt further processing on the IRP we just freed.
  1325. //
  1326. return STATUS_MORE_PROCESSING_REQUIRED;
  1327. }
  1328. //+----------------------------------------------------------------------------
  1329. //
  1330. // Function: MupFlushPrefixEntry
  1331. //
  1332. // Synopsis: Given a pathname, checks if the mup has the prefix cached.
  1333. // It removes the entry if it exists from the mup cache
  1334. //
  1335. // Arguments: [FileName] -- pathname which needs to be removed.
  1336. //
  1337. // Returns: TRUE if entry found in mup cache. False otherwise.
  1338. //
  1339. //-----------------------------------------------------------------------------
  1340. BOOLEAN
  1341. MupFlushPrefixEntry(
  1342. PUNICODE_STRING pathName)
  1343. {
  1344. PUNICODE_PREFIX_TABLE_ENTRY entry;
  1345. PKNOWN_PREFIX knownPrefix;
  1346. ACQUIRE_LOCK( &MupPrefixTableLock );
  1347. entry = RtlFindUnicodePrefix( &MupPrefixTable, pathName, TRUE );
  1348. if (entry != NULL) {
  1349. knownPrefix = CONTAINING_RECORD( entry, KNOWN_PREFIX, TableEntry );
  1350. if ( knownPrefix->InTable ) {
  1351. MupRemoveKnownPrefixEntry( knownPrefix );
  1352. }
  1353. }
  1354. RELEASE_LOCK( &MupPrefixTableLock );
  1355. return (entry != NULL) ? TRUE : FALSE;
  1356. }
  1357. //+----------------------------------------------------------------------------
  1358. //
  1359. // Function: MupInvalidatePrefixTable
  1360. //
  1361. // Synopsis: Removes all the entries from the mup prefix table.
  1362. //
  1363. // Arguments: None.
  1364. //
  1365. // Returns: None.
  1366. //
  1367. //-----------------------------------------------------------------------------
  1368. VOID
  1369. MupInvalidatePrefixTable(VOID)
  1370. {
  1371. PLIST_ENTRY listEntry;
  1372. PKNOWN_PREFIX knownPrefix;
  1373. ACQUIRE_LOCK( &MupPrefixTableLock );
  1374. listEntry = MupPrefixList.Flink;
  1375. while ( listEntry != &MupPrefixList ) {
  1376. knownPrefix = CONTAINING_RECORD( listEntry, KNOWN_PREFIX, ListEntry );
  1377. listEntry = listEntry->Flink;
  1378. if ( knownPrefix->InTable ) {
  1379. MupRemoveKnownPrefixEntry( knownPrefix );
  1380. }
  1381. }
  1382. RELEASE_LOCK( &MupPrefixTableLock );
  1383. }
  1384. VOID
  1385. MupRemoveKnownPrefixEntry(
  1386. PKNOWN_PREFIX knownPrefix
  1387. )
  1388. {
  1389. MUP_TRACE_LOW(KNOWN_PREFIX, MupRemoveKnownPrefixEntry,
  1390. LOGPTR(knownPrefix));
  1391. RtlRemoveUnicodePrefix(&MupPrefixTable, &knownPrefix->TableEntry);
  1392. RemoveEntryList(&knownPrefix->ListEntry);
  1393. knownPrefix->InTable = FALSE;
  1394. MupDereferenceKnownPrefix(knownPrefix);
  1395. }
  1396. NTSTATUS
  1397. IsThisASysVolPath(
  1398. IN PUNICODE_STRING PathName,
  1399. IN PUNICODE_STRING DCName)
  1400. {
  1401. /*++
  1402. Routine Description:
  1403. Determines whether a given path is a domain-based path or not
  1404. The general algorithm is:
  1405. - Extract the first component of the path
  1406. - See if it the domain name
  1407. - If it is, and the 2nd component is SYSVOL or NETLOGON, return the DCName
  1408. Arguments
  1409. PathName - Name of entire file
  1410. DCName - If this is a domain-based path, this is the name of
  1411. a dc in the domain.
  1412. Returns value
  1413. STATUS_SUCCESS -- PathName is a domain-based path
  1414. STATUS_BAD_NETWORK_PATH -- PathName is not a domain-based path
  1415. --*/
  1416. NTSTATUS status;
  1417. PDFS_SPECIAL_ENTRY pSpecialEntry;
  1418. PUNICODE_STRING pName;
  1419. UNICODE_STRING RootName;
  1420. UNICODE_STRING ShareName;
  1421. USHORT i;
  1422. USHORT j;
  1423. PDFS_PKT Pkt;
  1424. BOOLEAN pktLocked;
  1425. DfsDbgTrace(+1, Dbg, "IsThisASysVolPath: PathName %wZ \n", PathName);
  1426. //
  1427. // Only proceed if the first character is a backslash.
  1428. //
  1429. if (PathName->Buffer[0] != UNICODE_PATH_SEP) {
  1430. DfsDbgTrace(-1, Dbg, "PathName does not begin with backslash\n", 0);
  1431. return( STATUS_BAD_NETWORK_PATH );
  1432. }
  1433. //
  1434. // Find the first component in the name.
  1435. //
  1436. for (i = 1;
  1437. i < PathName->Length/sizeof(WCHAR) &&
  1438. PathName->Buffer[i] != UNICODE_PATH_SEP;
  1439. i++) {
  1440. NOTHING;
  1441. }
  1442. if (PathName->Buffer[i] != UNICODE_PATH_SEP) {
  1443. DfsDbgTrace(-1, Dbg, "Did not find second backslash\n", 0);
  1444. return( STATUS_BAD_NETWORK_PATH );
  1445. }
  1446. RootName.Length = (i-1) * sizeof(WCHAR);
  1447. RootName.MaximumLength = RootName.Length;
  1448. RootName.Buffer = &PathName->Buffer[1];
  1449. if (RootName.Length == 0)
  1450. return( STATUS_BAD_NETWORK_PATH );
  1451. //
  1452. // Figure out the share name
  1453. //
  1454. for (j = i+1;
  1455. j < PathName->Length/sizeof(WCHAR) &&
  1456. PathName->Buffer[j] != UNICODE_PATH_SEP;
  1457. j++) {
  1458. NOTHING;
  1459. }
  1460. ShareName.Length = (j - i - 1) * sizeof(WCHAR);
  1461. ShareName.MaximumLength = ShareName.Length;
  1462. ShareName.Buffer = &PathName->Buffer[i+1];
  1463. if (ShareName.Length == 0 || DfspIsSysVolShare(&ShareName) == FALSE)
  1464. return( STATUS_BAD_NETWORK_PATH );
  1465. Pkt = _GetPkt();
  1466. PktAcquireShared(TRUE, &pktLocked);
  1467. if (
  1468. (Pkt->DomainNameFlat.Buffer != NULL
  1469. &&
  1470. Pkt->DomainNameDns.Buffer != NULL
  1471. &&
  1472. Pkt->DCName.Buffer != NULL)
  1473. &&
  1474. (RtlCompareUnicodeString(&RootName, &Pkt->DomainNameFlat, TRUE) == 0
  1475. ||
  1476. RtlCompareUnicodeString(&RootName, &Pkt->DomainNameDns, TRUE) == 0)
  1477. ) {
  1478. pName = &Pkt->DCName;
  1479. DCName->Buffer = ExAllocatePoolWithTag(
  1480. PagedPool,
  1481. pName->MaximumLength,
  1482. ' puM');
  1483. if (DCName->Buffer != NULL) {
  1484. DCName->Length = pName->Length;
  1485. DCName->MaximumLength = pName->MaximumLength;
  1486. RtlCopyMemory(
  1487. DCName->Buffer,
  1488. pName->Buffer,
  1489. pName->MaximumLength);
  1490. status = STATUS_SUCCESS;
  1491. } else {
  1492. status = STATUS_INSUFFICIENT_RESOURCES;
  1493. }
  1494. } else {
  1495. status = STATUS_BAD_NETWORK_PATH;
  1496. }
  1497. PktRelease();
  1498. DfsDbgTrace(-1, Dbg, "IsThisASysVolPath: Exit -> %08lx\n", LongToPtr( status ) );
  1499. return status;
  1500. }
  1501. NTSTATUS
  1502. MupDomainToDC(
  1503. PUNICODE_STRING RootName,
  1504. PUNICODE_STRING DCName)
  1505. {
  1506. /*++
  1507. Routine Description:
  1508. This routine rewrites the file name of a domain-based path into a dc-based
  1509. path. Ex: \domainfoo\sysvol -> \dc1\sysvol
  1510. Arguments:
  1511. RootName - The RootName to rewrite
  1512. DCName - The name of the DC to change the path to
  1513. Return Value:
  1514. NTSTATUS - The status of the operation
  1515. --*/
  1516. ULONG Size;
  1517. PCHAR Buffer;
  1518. PWCHAR pBuf;
  1519. PWCHAR OrgBuffer;
  1520. PAGED_CODE();
  1521. DfsDbgTrace(+1, Dbg, "MupDomainToDC: RootName = %wZ\n", RootName);
  1522. //
  1523. // Only proceed if the first character is a backslash.
  1524. //
  1525. if (RootName->Buffer == NULL) {
  1526. DfsDbgTrace(-1, Dbg, "RootName is NULL\n", 0);
  1527. return( STATUS_BAD_NETWORK_PATH );
  1528. }
  1529. if (RootName->Buffer[0] != UNICODE_PATH_SEP) {
  1530. DfsDbgTrace(-1, Dbg, "RootName does not begin with backslash\n", 0);
  1531. return( STATUS_BAD_NETWORK_PATH );
  1532. }
  1533. OrgBuffer = RootName->Buffer;
  1534. //
  1535. // Skip over leading UNICODE_PATH_SEP
  1536. //
  1537. RootName->Length -= sizeof(WCHAR);
  1538. RootName->MaximumLength -= sizeof(WCHAR);
  1539. RootName->Buffer++;
  1540. //
  1541. // Motor along until end of string or a UNICODE_PATH_SEP
  1542. //
  1543. while (RootName->Length > 0 && RootName->Buffer[0] != UNICODE_PATH_SEP) {
  1544. RootName->Length -= sizeof(WCHAR);
  1545. RootName->MaximumLength -= sizeof(WCHAR);
  1546. RootName->Buffer++;
  1547. }
  1548. if (RootName->Length == 0) {
  1549. DfsDbgTrace(-1, Dbg, "Did not find second backslash\n", 0);
  1550. return( STATUS_BAD_NETWORK_PATH );
  1551. }
  1552. //
  1553. // Allocate storage for the new file name.
  1554. //
  1555. Size = sizeof(WCHAR) + // leading UNICODE_PATH_SEP
  1556. DCName->Length +
  1557. RootName->Length;
  1558. Buffer = ExAllocatePoolWithTag(
  1559. PagedPool,
  1560. Size,
  1561. ' puM');
  1562. if ( Buffer == NULL)
  1563. return STATUS_INSUFFICIENT_RESOURCES;
  1564. //
  1565. // Leading UNICODE_PATH_SEP's
  1566. //
  1567. pBuf = (WCHAR *)Buffer;
  1568. *pBuf++ = UNICODE_PATH_SEP;
  1569. //
  1570. // Copy the DC name to the buffer
  1571. //
  1572. RtlMoveMemory(
  1573. pBuf,
  1574. DCName->Buffer,
  1575. DCName->Length);
  1576. pBuf += DCName->Length / sizeof(WCHAR);
  1577. //
  1578. // Append the trailing file name
  1579. //
  1580. RtlMoveMemory(
  1581. pBuf,
  1582. RootName->Buffer,
  1583. RootName->Length);
  1584. //
  1585. // Free the old file name string buffer.
  1586. //
  1587. ExFreePool( OrgBuffer );
  1588. RootName->Buffer = (PWCHAR)Buffer;
  1589. RootName->Length = (USHORT) Size;
  1590. RootName->MaximumLength = (USHORT) Size;
  1591. DfsDbgTrace(+1, Dbg, "MupDomainToDC: Exit\n", 0);
  1592. return STATUS_SUCCESS;
  1593. }