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.

5173 lines
168 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: dnr.c
  6. //
  7. // Contents: Distributed name resolution process and control
  8. //
  9. // Functions: DnrStartNameResolution -- Start a name resolution
  10. // DnrNameResolve -- Main loop for DNR
  11. // DnrComposeFileName -- Canonicalize file name
  12. // DnrCaptureCredentials -- Capture user-defined creds for Dnr
  13. // DnrReleaseCredentials -- Dual of DnrCaptureCredentials
  14. // DnrRedirectFileOpen -- Redirect a create IRP to some provider
  15. // DnrPostProcessFileOpen -- Resume after return from redirect
  16. // DnrGetAuthenticatedConnection -- Using Dnr credentials
  17. // DnrReleaseAuthenticatedConnection -- returned by above func
  18. // DfsBuildConnectionRequest -- Builds name of server IPC$ share
  19. // DfsFreeConnectionRequest -- Free resources allocated above
  20. // DfsCreateConnection -- Create a connection to a server IPC$
  21. // DfsCloseConnection -- Close connection opened above
  22. // DnrBuildReferralRequest -- Build Irp for referral request
  23. // DnrInsertReferralAndResume -- Resume DNR after referral
  24. // DnrCompleteReferral -- DPC to process a referral response
  25. // DnrCompleteFileOpen -- DPC to process a file open completion
  26. // DnrBuildFsControlRequest -- Create an IRP for an Fsctrl
  27. // AllocateDnrContext -- Allocate a context record for DNR
  28. // DeallocateDnrContext -- Free context record
  29. // DnrConcatenateFilePath -- Construct path with backslashes etc
  30. // DnrLocateDC -- Locate the server for a Dfs root
  31. //
  32. //--------------------------------------------------------------------------
  33. #include "dfsprocs.h"
  34. #include <smbtypes.h>
  35. #include <smbtrans.h>
  36. #include "fsctrl.h"
  37. #include "fcbsup.h"
  38. #include "dnr.h"
  39. #include "creds.h"
  40. #include "know.h"
  41. #include "mupwml.h"
  42. #include <netevent.h>
  43. //
  44. // The debug trace level
  45. //
  46. #define Dbg (DEBUG_TRACE_DNR)
  47. //
  48. // Local function prototypes
  49. //
  50. #define DNR_SET_TARGET_INFO(_DnrC, _Entry) \
  51. if (((_DnrC)->pDfsTargetInfo == NULL) && (_Entry != NULL)) {\
  52. (_DnrC)->pDfsTargetInfo = (_Entry)->pDfsTargetInfo; \
  53. if ((_DnrC)->pDfsTargetInfo != NULL) { \
  54. PktAcquireTargetInfo( (_DnrC)->pDfsTargetInfo); \
  55. } \
  56. }
  57. PDNR_CONTEXT
  58. AllocateDnrContext(
  59. IN ULONG cbExtra
  60. );
  61. #define DeallocateDnrContext(pNRC) ExFreePool(pNRC);
  62. VOID
  63. DnrRebuildDnrContext(
  64. IN PDNR_CONTEXT DnrContext,
  65. IN PUNICODE_STRING NewDfsPrefix,
  66. IN PUNICODE_STRING RemainingPath);
  67. VOID
  68. DnrCaptureCredentials(
  69. IN PDNR_CONTEXT DnrContext);
  70. VOID
  71. DnrReleaseCredentials(
  72. IN PDNR_CONTEXT DnrContext);
  73. NTSTATUS
  74. DnrGetAuthenticatedConnection(
  75. IN OUT PDNR_CONTEXT DnrContext);
  76. VOID
  77. DnrReleaseAuthenticatedConnection(
  78. IN OUT PDNR_CONTEXT DnrContext);
  79. NTSTATUS
  80. DfsBuildConnectionRequest(
  81. IN PDFS_SERVICE pService,
  82. IN PPROVIDER_DEF pProvider,
  83. OUT PUNICODE_STRING pShareName);
  84. VOID
  85. DfsFreeConnectionRequest(
  86. IN OUT PUNICODE_STRING pShareName);
  87. NTSTATUS
  88. DnrRedirectFileOpen (
  89. IN PDNR_CONTEXT DnrContext
  90. );
  91. NTSTATUS
  92. DnrPostProcessFileOpen(
  93. IN PDNR_CONTEXT DnrContext
  94. );
  95. VOID
  96. DnrInsertReferralAndResume(
  97. IN PVOID Context);
  98. VOID
  99. DnrLocateDC(
  100. IN PUNICODE_STRING FileName);
  101. NTSTATUS
  102. DnrCompleteReferral(
  103. IN PDEVICE_OBJECT pDevice,
  104. IN PIRP Irp,
  105. IN PVOID Context
  106. );
  107. NTSTATUS
  108. DnrCompleteFileOpen(
  109. IN PDEVICE_OBJECT pDevice,
  110. IN PIRP Irp,
  111. IN PVOID Context
  112. );
  113. PIRP
  114. DnrBuildReferralRequest(
  115. IN PDNR_CONTEXT pDnrContext
  116. );
  117. VOID
  118. PktFlushChildren(
  119. PDFS_PKT_ENTRY pEntry
  120. );
  121. VOID
  122. MupInvalidatePrefixTable(
  123. VOID
  124. );
  125. NTSTATUS
  126. DnrGetTargetInfo(
  127. PDNR_CONTEXT pDnrContext);
  128. #define DFS_REFERENCE_OBJECT(d) \
  129. ObReferenceObjectByPointer(d,0,NULL,KernelMode);
  130. #define DFS_DEREFERENCE_OBJECT(d) \
  131. ObDereferenceObject((PVOID)(d));
  132. #ifdef ALLOC_PRAGMA
  133. #pragma alloc_text( PAGE, DnrStartNameResolution )
  134. #pragma alloc_text( PAGE, DnrNameResolve )
  135. #pragma alloc_text( PAGE, DnrComposeFileName )
  136. #pragma alloc_text( PAGE, DnrCaptureCredentials )
  137. #pragma alloc_text( PAGE, DnrReleaseCredentials )
  138. #pragma alloc_text( PAGE, DnrGetAuthenticatedConnection )
  139. #pragma alloc_text( PAGE, DnrReleaseAuthenticatedConnection )
  140. #pragma alloc_text( PAGE, DnrRedirectFileOpen )
  141. #pragma alloc_text( PAGE, DnrPostProcessFileOpen )
  142. #pragma alloc_text( PAGE, DfsBuildConnectionRequest )
  143. #pragma alloc_text( PAGE, DfsFreeConnectionRequest )
  144. #pragma alloc_text( PAGE, DnrBuildReferralRequest )
  145. #pragma alloc_text( PAGE, DfsCreateConnection )
  146. #pragma alloc_text( PAGE, DfsCloseConnection )
  147. #pragma alloc_text( PAGE, DnrBuildFsControlRequest )
  148. #pragma alloc_text( PAGE, DnrInsertReferralAndResume )
  149. #pragma alloc_text( PAGE, DnrLocateDC )
  150. #pragma alloc_text( PAGE, AllocateDnrContext )
  151. #pragma alloc_text( PAGE, DnrRebuildDnrContext )
  152. #pragma alloc_text( PAGE, DnrConcatenateFilePath )
  153. #pragma alloc_text( PAGE, DfspGetOfflineEntry)
  154. #pragma alloc_text( PAGE, DfspMarkServerOnline)
  155. #pragma alloc_text( PAGE, DfspMarkServerOffline)
  156. #pragma alloc_text( PAGE, DfspIsRootOnline)
  157. //
  158. // The following are not pageable since they can be called at DPC level
  159. //
  160. // DnrCompleteReferral
  161. // DnrCompleteFileOpen
  162. //
  163. #endif
  164. //+-------------------------------------------------------------------
  165. //
  166. // Function: DfsIsShareNull
  167. //
  168. // Synopsis: Is this name of the form "\server\"?
  169. //
  170. // Arguments: [FileName] - pointer to the UNICODE_STRING we are checking
  171. //
  172. // Returns: TRUE if FileName is "\server\", FALSE otherwise
  173. //
  174. //--------------------------------------------------------------------
  175. BOOLEAN
  176. DfsIsShareNull(PUNICODE_STRING FileName)
  177. {
  178. USHORT RootEnd = 0;
  179. USHORT ShareEnd = 0;
  180. BOOLEAN result = FALSE;
  181. USHORT Length = 0;
  182. // find the first '\'
  183. // we start at 1 because the first character is also '\'
  184. for (RootEnd = 1;
  185. RootEnd < FileName->Length/sizeof(WCHAR) &&
  186. FileName->Buffer[RootEnd] != UNICODE_PATH_SEP;
  187. RootEnd++) {
  188. NOTHING;
  189. }
  190. // now FileName->Buffer[RootEnd] == '\' and we are beyond the root part of the name
  191. // find the end of the share part.
  192. for (ShareEnd = RootEnd+1;
  193. ShareEnd < FileName->Length/sizeof(WCHAR) &&
  194. FileName->Buffer[ShareEnd] != UNICODE_PATH_SEP;
  195. ShareEnd++) {
  196. NOTHING;
  197. }
  198. // the length of the share name is ShareEnd - RootEnd - 1
  199. // the -1 is becasue we have actually stepped one char beyond the
  200. // share name's end
  201. // For example: \root\share\link RootEnd=5, ShareEnd=11
  202. // \root\share RootEnd=5, ShareEnd=11
  203. // \root\ RootEnd=5, ShareEnd=6
  204. Length = (USHORT) (ShareEnd - RootEnd - 1) * sizeof(WCHAR);
  205. if(Length == 0) {
  206. result = TRUE;
  207. } else {
  208. result = FALSE;
  209. }
  210. return result;
  211. }
  212. NTSTATUS
  213. DfsRerouteOpenToMup(
  214. IN PFILE_OBJECT FileObject,
  215. IN PUNICODE_STRING FileName)
  216. {
  217. UNICODE_STRING NewName;
  218. ULONG nameLength;
  219. NTSTATUS status;
  220. nameLength = sizeof(DD_MUP_DEVICE_NAME ) + FileName->Length + sizeof(WCHAR);
  221. if (nameLength > MAXUSHORT) {
  222. status = STATUS_NAME_TOO_LONG;
  223. MUP_TRACE_HIGH(ERROR, DfsRerouteOpenToMup_Error_NameTooLong,
  224. LOGSTATUS(status)
  225. LOGPTR(FileObject));
  226. return status;
  227. }
  228. NewName.Buffer = ExAllocatePoolWithTag(
  229. PagedPool,
  230. nameLength,
  231. ' puM');
  232. if ( NewName.Buffer == NULL) {
  233. return STATUS_INSUFFICIENT_RESOURCES;
  234. }
  235. NewName.MaximumLength = (USHORT)nameLength;
  236. NewName.Length = 0;
  237. RtlAppendUnicodeToString(&NewName, DD_MUP_DEVICE_NAME);
  238. RtlAppendUnicodeStringToString(&NewName, FileName);
  239. if (MupVerbose) {
  240. DbgPrint("Newname %wZ\n", &NewName);
  241. }
  242. ExFreePool(FileObject->FileName.Buffer);
  243. FileObject->FileName = NewName;
  244. return STATUS_REPARSE;
  245. }
  246. // The name resolution process operates as a state machine in
  247. // which the current step in the process is indicated by a state
  248. // variable, and responses to requests from the network will
  249. // transition the process to other states, from which actions
  250. // are taken.
  251. //
  252. // When a user request needs further processing, an IRP is
  253. // dispatched with a Completion Routine that will
  254. // pick up processing when the sub-request is completed. The
  255. // completion routine will adjust the name resolution state and restart the
  256. // main loop of the state machine.
  257. //
  258. // The following state/action table describes the actions of
  259. // the procedures which implement the state machine:
  260. //
  261. // Current Condition/ Next
  262. // State Action State
  263. // ------- ---------- -----
  264. //
  265. // Enter Acquire Pkt, canonicalize file LocalCompletion
  266. // name, optimistic allocation of
  267. // FCB fails/
  268. // No action
  269. //
  270. // Enter Acquire Pkt, canonicalize file Start
  271. // name, allocated FCB/
  272. // Capture Credentials to use
  273. //
  274. // Start Got a referral, new pkt entry GetFirstReplica
  275. // is already in DnrContext and
  276. // pkt entry is not inter-dfs/
  277. // Capture USN of pkt entry
  278. //
  279. // Start lookup in PKT returns match GetFirstReplica
  280. // and pkt entry is not inter-dfs/
  281. // Capture USN of pkt entry
  282. //
  283. // Start pkt entry from referral or Start
  284. // lookup is inter-dfs/
  285. // Change file name in DnrContext
  286. // to name in new Dfs, rebuild
  287. // DnrContext
  288. //
  289. // Start lookup in PKT, no match/ GetFirstDC
  290. // No action
  291. //
  292. // GetFirstReplica Find First replica fails and Done
  293. // we have already got a referral/
  294. // Set final status to
  295. // NO_SUCH_DEVICE (must be
  296. // because we don't have an
  297. // appropriate redirector)
  298. //
  299. // GetFirstReplica Find First replica fails and GetFirstDC
  300. // we haven't yet got a referral/
  301. // locate first DC to send
  302. // referral request to.
  303. //
  304. // GetFirstReplica Replica found has no address, GetFirstDC
  305. // means a domain-based Dfs with
  306. // no DCs/
  307. // No action
  308. //
  309. // GetFirstReplica Replica found with valid SendRequest
  310. // address/
  311. // Capture provider info under
  312. // lock protection, Reference
  313. // provider's device object,
  314. //
  315. // SendRequest Supplied credentials, and tree Done
  316. // connect using creds fails/
  317. // Set final status, dereference
  318. // provider's device object
  319. //
  320. // SendRequest Allocate pool for new name/ PostProcessOpen
  321. // Change file name into one that
  322. // the provider can parse, pass
  323. // the Create request to the
  324. // provider, Derefence provider's
  325. // device object when provider
  326. // completes the request.
  327. //
  328. // SendRequest Pool Allocation fails/ Done
  329. // Set final status, dereference
  330. // provider's device object
  331. //
  332. // PostProcessOpen Underlying FS returned REPARSE, SendRequest
  333. // successfully created or found a
  334. // provider for the target redir/
  335. // Capture provider information
  336. // under lock protection,
  337. // Reference providers Device obj.
  338. //
  339. // PostProcessOpen Underlying FS returned SUCCESS/ Done
  340. // Insert optimistically allocated
  341. // FCB into Fcb table, set final
  342. // status
  343. //
  344. // PostProcessOpen Open failed with GetFirstDC
  345. // PATH_NOT_COVERED or
  346. // DFS_EXIT_POINT_FOUND, and
  347. // we haven't yet gotten a
  348. // referral/
  349. // No action
  350. //
  351. // PostProcessOpen Open failed with Start
  352. // OBJECT_TYPE_MISMATCH (ie,
  353. // downlevel open found an
  354. // interdfs link)/Change
  355. // name in DnrContext to name
  356. // in new Dfs, rebuild DnrContext
  357. //
  358. // PostProcessOpen Open failed with GetFirstReplica
  359. // PATH_NOT_COVERED or
  360. // DFS_EXIT_POINT_FOUND, and we
  361. // already got a referral, and
  362. // we have never reported an
  363. // inconsistency/
  364. // Report inconsistency
  365. //
  366. // PostProcessOpen Same as above, but we already GetNextReplica
  367. // reported the inconsistency/
  368. // Report the inconsistency
  369. //
  370. // PostProcessOpen Open failed with network error/ GetNextReplica
  371. // No action
  372. //
  373. // PostProcessOpen Open failed with non-network Done
  374. // error/
  375. // Set final status
  376. //
  377. // GetNextReplica No more replicas and haven't GetFirstDC
  378. // gotten a referral yet/
  379. // no action
  380. //
  381. // GetNextReplica No more replicas and got a Done
  382. // referral/
  383. // no action
  384. //
  385. // GetNextReplica Replica found/ SendRequest
  386. // Capture provider information
  387. // under lock protection,
  388. // Reference provider Device obj
  389. //
  390. // GetFirstDC Lookup referral entry not Done
  391. // found or has no services, and
  392. // we have already called DC
  393. // Locator once/
  394. // Set final status to
  395. // CANT_ACCESS_DOMAIN_INFO
  396. //
  397. // GetFirstDC Lookup referral entry returned Done
  398. // valid entry, but can't find a
  399. // provider for it/
  400. // Set final status to
  401. // CANT_ACCESS_DOMAIN_INFO
  402. //
  403. // GetFirstDC Lookup referral entry returned GetReferrals
  404. // valid entry, and found
  405. // provider/
  406. // Set DnrContext->pPktEntry to
  407. // DC's entry, Capture provider
  408. // info under lock protection,
  409. // Reference provider's Device obj
  410. //
  411. // GetReferrals Unable to open DC's IPC$ share/ GetNextDC
  412. // Dereference provider's device
  413. // object
  414. //
  415. // GetReferrals Opened DC's IPC$ share, but Done
  416. // unable to build referral
  417. // request Irp/
  418. // Dereference provider's device,
  419. // Set final status to
  420. // INSUFFICIENT_RESOURCES
  421. //
  422. // GetReferrals Opened DC's IPC$ share and CompleteReferral
  423. // built referral request/
  424. // Release Pkt, Send referral
  425. // request
  426. //
  427. // GetNextDC Successfully found another GetReferrals
  428. // DC/
  429. // Capture provider info under
  430. // lock protection, Reference
  431. // provider's Device object
  432. //
  433. // GetNextDC Can't find another DC/ Done
  434. // Set final status to
  435. // CANT_ACCESS_DOMAIN_INFO
  436. //
  437. // Done Complete create Irp with
  438. // DnrContext->FinalStatus
  439. //
  440. // LocalCompletion Complete create Irp with
  441. // local status.
  442. //
  443. // CompleteReferral Referral returned with GetReferrals
  444. // BUFFER_OVERFLOW/
  445. // Set referral size to
  446. // indicated amount
  447. //
  448. // CompleteReferral Referral returned, but Done
  449. // error in creating entry/
  450. // Dereference provider's
  451. // device, set final status to
  452. // result of creating entry
  453. //
  454. // CompleteReferral Referral returned and GetFirstDC
  455. // successfully created entry,
  456. // entry is inter-dfs/
  457. // Dereference provider's device,
  458. // Reset ReferralSize
  459. //
  460. // CompleteReferral Same as above, but entry Start
  461. // is storage entry/
  462. // Dereference provider's device,
  463. // Adjust DnrContext->
  464. // RemainingPart to correspond
  465. // to the new entry
  466. //
  467. // CompleteReferral Referral request failed with GetNextDC
  468. // some network error/
  469. // Dereference Provider's device
  470. //
  471. // CompleteReferral Referral request failed with Done
  472. // some non-network error/
  473. // Dereference provider's Device,
  474. // Set final status to this error
  475. //
  476. //+-------------------------------------------------------------------------
  477. //
  478. // Function: DnrStartNameResolution - Start a distributed name resolution
  479. //
  480. // Synopsis: DnrStartNameResolution starts the name resolution process
  481. // for a request (typically an NtCreateFile).
  482. //
  483. // Effects: Could change the state of the PKT or individual
  484. // PKT entries.
  485. //
  486. // Arguments: [IrpContext] - pointer to a IRP_CONTEXT structure for the
  487. // current request.
  488. // [Irp] - IRP being processed.
  489. // [Vcb] - Vcb of logical root.
  490. //
  491. // Returns: NTSTATUS - Status to be returned to the I/O subsystem.
  492. //
  493. // Notes:
  494. //
  495. //--------------------------------------------------------------------------
  496. NTSTATUS
  497. DnrStartNameResolution(
  498. IN PIRP_CONTEXT IrpContext,
  499. IN PIRP Irp,
  500. IN PDFS_VCB Vcb
  501. ) {
  502. PDNR_CONTEXT DnrContext;
  503. NTSTATUS Status;
  504. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  505. PFILE_OBJECT FileObject = IrpSp->FileObject;
  506. PUNICODE_STRING LogRootPrefix = &Vcb->LogRootPrefix;
  507. ULONG CreateOptions;
  508. USHORT cbFileName;
  509. SECURITY_QUALITY_OF_SERVICE sqos;
  510. ULONG cbFileNameLong;
  511. MUP_TRACE_NORM(TRACE_IRP, DnrStartNameResolution_Entry,
  512. LOGPTR(Irp)
  513. LOGPTR(Vcb)
  514. LOGPTR(FileObject)
  515. LOGUSTR(FileObject->FileName)
  516. LOGUSTR(*LogRootPrefix));
  517. cbFileNameLong = FileObject->FileName.Length +
  518. sizeof(UNICODE_PATH_SEP) +
  519. LogRootPrefix->Length +
  520. sizeof(UNICODE_NULL);
  521. cbFileName = (USHORT)cbFileNameLong;
  522. if( cbFileName != cbFileNameLong ) {
  523. //
  524. // The resulting name is too long -- we cannot deal with it
  525. //
  526. Status = STATUS_OBJECT_NAME_INVALID;
  527. DfsCompleteRequest(IrpContext, Irp, Status);
  528. DfsDbgTrace(0, Dbg, "DnrStartNameResolution: Exit ->%x\n", ULongToPtr(Status));
  529. MUP_TRACE_HIGH(ERROR, DnrStartNameResolution_Error_NameTooLong,
  530. LOGSTATUS(Status)
  531. LOGPTR(FileObject)
  532. LOGPTR(Irp));
  533. return Status;
  534. }
  535. //
  536. // Allocate the DnrContext used to resolve the name. We optimize
  537. // allocation by allocating room for the FileName at the end of the
  538. // DnrContext.
  539. //
  540. DnrContext = AllocateDnrContext(cbFileName);
  541. if (DnrContext == NULL) {
  542. Status = STATUS_INSUFFICIENT_RESOURCES;
  543. DfsCompleteRequest(IrpContext, Irp, Status);
  544. DfsDbgTrace(0, Dbg, "DnrStartNameResolution: Exit ->%x\n", ULongToPtr(Status));
  545. MUP_TRACE_HIGH(ERROR, DnrStartNameResolution_Error2,
  546. LOGSTATUS(Status)
  547. LOGPTR(FileObject)
  548. LOGPTR(Irp));
  549. return Status;
  550. }
  551. DnrContext->FileName.Length = 0;
  552. DnrContext->FileName.MaximumLength = cbFileName;
  553. DnrContext->FileName.Buffer = (PWCHAR) ( (PBYTE) DnrContext + sizeof(DNR_CONTEXT) );
  554. //
  555. // Since FileName.Buffer has not been separately allocated, we set this
  556. // to FALSE.
  557. //
  558. DnrContext->NameAllocated = FALSE;
  559. //
  560. // Capture the user's security token so we can later impersonate if
  561. // needed.
  562. //
  563. sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  564. sqos.ImpersonationLevel = SecurityImpersonation;
  565. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  566. sqos.EffectiveOnly = FALSE;
  567. Status = SeCreateClientSecurity(
  568. Irp->Tail.Overlay.Thread,
  569. &sqos,
  570. FALSE, // Remote Session
  571. &DnrContext->SecurityContext); // Return context.
  572. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrStartNameResolution_Error_SeCreateClientSecurity,
  573. LOGSTATUS(Status)
  574. LOGPTR(FileObject)
  575. LOGPTR(Irp)
  576. LOGUSTR(FileObject->FileName));
  577. if (!NT_SUCCESS(Status)) {
  578. DeallocateDnrContext( DnrContext );
  579. DfsCompleteRequest(IrpContext, Irp, Status);
  580. DfsDbgTrace(0, Dbg, "DnrStartNameResolution: Exit ->%x\n", ULongToPtr(Status));
  581. return( Status );
  582. }
  583. DnrContext->Impersonate = FALSE;
  584. ASSERT(NT_SUCCESS(Status));
  585. //
  586. // Initialize the rest of the DnrContext
  587. //
  588. DnrContext->AuthConn = NULL;
  589. DnrContext->OriginalIrp = Irp;
  590. DnrContext->pIrpContext = IrpContext;
  591. DnrContext->Credentials = NULL;
  592. DnrContext->FinalStatus = STATUS_SUCCESS;
  593. DnrContext->FcbToUse = NULL;
  594. DnrContext->Vcb = Vcb;
  595. DnrContext->State = DnrStateEnter;
  596. DnrContext->Attempts = 0;
  597. DnrContext->DnrActive = FALSE;
  598. DnrContext->ReleasePkt = FALSE;
  599. DnrContext->GotReferral = FALSE;
  600. DnrContext->FoundInconsistency = FALSE;
  601. DnrContext->CalledDCLocator = FALSE;
  602. DnrContext->CachedConnFile = FALSE;
  603. DnrContext->ReferralSize = MAX_REFERRAL_LENGTH;
  604. KeQuerySystemTime(&DnrContext->StartTime);
  605. CreateOptions = IrpSp->Parameters.Create.Options;
  606. //
  607. // ... and resolve the name
  608. //
  609. return DnrNameResolve(DnrContext);
  610. }
  611. //+-------------------------------------------------------------------------
  612. //
  613. // Function: DnrNameResolve - Main loop for DNR
  614. //
  615. // Synopsis: DnrNameResolve drives the name resolution process
  616. // for a request (typically an NtCreateFile).
  617. //
  618. // Effects: Could change the state of the PKT or individual
  619. // PKT entries.
  620. //
  621. // Arguments: [DnrContext] - pointer to a DNR_CONTEXT structure which
  622. // records the state of the DNR.
  623. //
  624. // Returns: NTSTATUS - Status to be returned to the I/O subsystem.
  625. //
  626. // Notes:
  627. //
  628. //--------------------------------------------------------------------------
  629. NTSTATUS
  630. DnrNameResolve(
  631. IN PDNR_CONTEXT DnrContext
  632. ) {
  633. PIO_STACK_LOCATION IrpSp;
  634. NTSTATUS Status = STATUS_SUCCESS;
  635. PDFS_VCB Vcb;
  636. PIRP Irp;
  637. BOOLEAN LastEntry;
  638. PDFS_PKT_ENTRY shortPfxMatch;
  639. UNICODE_STRING shortRemainingPart;
  640. LARGE_INTEGER EndTime;
  641. PFILE_OBJECT InputFileObject;
  642. DfsDbgTrace(+1, Dbg, "DnrNameResolve: Entered\n", 0);
  643. ASSERT( !DnrContext->DnrActive && "Recursive call to Dnr!\n");
  644. DnrContext->DnrActive = TRUE;
  645. //
  646. // If we need to impersonate the original caller, do so before doing
  647. // anything else.
  648. //
  649. Irp = DnrContext->OriginalIrp;
  650. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  651. InputFileObject = IrpSp->FileObject;
  652. Vcb = DnrContext->Vcb;
  653. if (DnrContext->Impersonate) {
  654. Status = SeImpersonateClientEx(
  655. &DnrContext->SecurityContext,
  656. (PETHREAD) NULL);
  657. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrNameResolve_Error_SeImpersonateClientEx,
  658. LOGSTATUS(Status)
  659. LOGPTR(InputFileObject));
  660. if (!NT_SUCCESS(Status)) {
  661. DnrContext->DnrActive = FALSE;
  662. DnrContext->State = DnrStateLocalCompletion;
  663. DfsDbgTrace(0, Dbg,
  664. "DnrNameResolve quitting due to SeImpersonateClientEx returning 0x%x\n", ULongToPtr(Status));
  665. }
  666. }
  667. //
  668. // Drive the name resolution process as far as possible before
  669. // it is necessary to wait for an I/O completion.
  670. //
  671. while (1) {
  672. PDFS_PKT_ENTRY pktEntry = NULL;
  673. PFILE_OBJECT FileObject = IrpSp->FileObject;
  674. if (DnrContext->State == DnrStateGetFirstReplica ||
  675. DnrContext->State == DnrStateGetFirstDC) {
  676. if (++DnrContext->Attempts > MAX_DNR_ATTEMPTS) {
  677. Status = STATUS_BAD_NETWORK_PATH;
  678. DnrContext->State = DnrStateLocalCompletion;
  679. DfsDbgTrace(0, 0,
  680. "DFS: DnrNameResolve quitting due to MAX_DNR_ATTEMPTS %d\n",
  681. UIntToPtr(DnrContext->Attempts));
  682. }
  683. }
  684. if (DnrContext->State == DnrStateStart)
  685. {
  686. if (DnrContext->Attempts > MAX_DNR_ATTEMPTS)
  687. {
  688. Status = STATUS_BAD_NETWORK_PATH;
  689. DnrContext->State = DnrStateLocalCompletion;
  690. }
  691. }
  692. MUP_TRACE_LOW(DNR, DnrNameResolve_TopOfLoop,
  693. LOGUSTR(FileObject->FileName)
  694. LOGULONG(DnrContext->State)
  695. );
  696. switch (DnrContext->State) {
  697. case DnrStateEnter:
  698. #if DBG
  699. if (MupVerbose) {
  700. KeQuerySystemTime(&EndTime);
  701. DbgPrint("[%d] FSM state DnrStateEnter\n",
  702. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  703. }
  704. #endif
  705. ASSERT(DnrContext->ReleasePkt == FALSE);
  706. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  707. //
  708. // We need to construct the fully qualified file name given the
  709. // logical root and the input file name relative to that root.
  710. // DnrComposeFileName will allocate memory to hold a string that
  711. // is the concatenation of the name of the logical root wrt org
  712. // and the file name.
  713. //
  714. //
  715. ASSERT((FileObject->FileName.Length & 0x1) == 0);
  716. DnrComposeFileName(
  717. &DnrContext->FileName,
  718. DnrContext->Vcb,
  719. FileObject->RelatedFileObject,
  720. &FileObject->FileName);
  721. DnrContext->ContextFileName = DnrContext->FileName;
  722. DfsDbgTrace(0, Dbg,
  723. "DnrComposeFileName -> %wZ\n", &FileObject->FileName);
  724. if(DfsIsShareNull(&DnrContext->FileName)) {
  725. //
  726. // It doesn't make sense for us to have a name in the form
  727. // "\server\" or "\domain\" so we reject it. If we didn't reject these
  728. // names we would wind up bugchecking when processing the
  729. // referral with a NULL sharename.
  730. //
  731. Status = STATUS_INVALID_PARAMETER;
  732. DnrContext->State = DnrStateLocalCompletion;
  733. break;
  734. }
  735. Status = DfspIsRootOnline(&DnrContext->FileName,
  736. (BOOLEAN)
  737. ((DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) != 0));
  738. if (!NT_SUCCESS(Status)) {
  739. DnrContext->State = DnrStateLocalCompletion;
  740. break;
  741. }
  742. #if DBG
  743. if (MupVerbose)
  744. DbgPrint(" DnrContext->FileName=(%wZ)\n", &DnrContext->FileName);
  745. #endif
  746. //
  747. // Allocate an FCB now for use if the DNR succeeds. We must, do
  748. // this, or we won't know how what to do if the underlying FS
  749. // opens the file and then we are unable to allocate the FCB.
  750. //
  751. ASSERT(DnrContext->FcbToUse == NULL);
  752. DnrContext->FcbToUse = DfsCreateFcb(
  753. NULL,
  754. DnrContext->Vcb,
  755. &DnrContext->ContextFileName);
  756. if (DnrContext->FcbToUse == NULL) {
  757. DfsDbgTrace(0, Dbg, "Could not create FCB!\n", 0);
  758. Status = STATUS_INSUFFICIENT_RESOURCES;
  759. DnrContext->State = DnrStateLocalCompletion;
  760. break;
  761. }
  762. DnrContext->FcbToUse->FileObject = FileObject;
  763. DfsSetFileObject(FileObject,
  764. RedirectedFileOpen,
  765. DnrContext->FcbToUse);
  766. DnrCaptureCredentials(DnrContext);
  767. DnrContext->State = DnrStateStart;
  768. //
  769. // Fall through
  770. //
  771. case DnrStateStart:
  772. DfsDbgTrace(0, Dbg, "FSM state Start\n", 0);
  773. #if DBG
  774. if (MupVerbose) {
  775. KeQuerySystemTime(&EndTime);
  776. DbgPrint("[%d] FSM state DnrStateStart\n",
  777. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  778. DbgPrint(" DnrContext->FileName=(%wZ)\n", &DnrContext->FileName);
  779. }
  780. #endif
  781. ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
  782. //
  783. // Try to match the filename with the best
  784. // PktEntry we have.
  785. //
  786. //
  787. // Do the match in the full prefix table
  788. //
  789. pktEntry = PktLookupEntryByPrefix(&DfsData.Pkt,
  790. &DnrContext->FileName,
  791. &DnrContext->RemainingPart);
  792. //
  793. // Then do a match in the short prefix table
  794. //
  795. shortPfxMatch = PktLookupEntryByShortPrefix(
  796. &DfsData.Pkt,
  797. &DnrContext->FileName,
  798. &shortRemainingPart);
  799. if (shortPfxMatch != NULL) {
  800. if (pktEntry == NULL) {
  801. pktEntry = shortPfxMatch;
  802. DnrContext->RemainingPart = shortRemainingPart;
  803. } else if (shortPfxMatch->Id.Prefix.Length >
  804. pktEntry->Id.Prefix.Length) {
  805. pktEntry = shortPfxMatch;
  806. DnrContext->RemainingPart = shortRemainingPart;
  807. }
  808. }
  809. //
  810. // If the entry found is stale and this is our first attempt at dnr,
  811. // force another referral request.
  812. //
  813. if (DnrContext->Attempts == 0 && pktEntry != NULL && pktEntry->ExpireTime <= 0) {
  814. #if DBG
  815. if (MupVerbose)
  816. DbgPrint(" pktEntry [%wZ] is stale - force getting another\n",
  817. &pktEntry->Id.Prefix);
  818. #endif
  819. DnrContext->pPktEntry = pktEntry;
  820. DnrContext->State = DnrStateGetFirstDC;
  821. //
  822. // Now break out so we restart Dnr and get a referral
  823. //
  824. break;
  825. }
  826. #if 0
  827. if (pktEntry == NULL) {
  828. PUNICODE_STRING filePath = &DnrContext->FileName;
  829. UNICODE_STRING dfsRootName;
  830. UNICODE_STRING shareName;
  831. NTSTATUS status;
  832. PDFS_SPECIAL_ENTRY pSpecialEntry;
  833. ULONG i, j;
  834. for (i = 1;
  835. i < filePath->Length/sizeof(WCHAR) &&
  836. filePath->Buffer[i] != UNICODE_PATH_SEP;
  837. i++) {
  838. NOTHING;
  839. }
  840. dfsRootName.Length = (USHORT) ((i-1) * sizeof(WCHAR));
  841. dfsRootName.MaximumLength = dfsRootName.Length;
  842. dfsRootName.Buffer = &filePath->Buffer[1];
  843. for (j = i+1;
  844. j < filePath->Length/sizeof(WCHAR) &&
  845. filePath->Buffer[j] != UNICODE_PATH_SEP;
  846. j++) {
  847. NOTHING;
  848. }
  849. shareName.Length = (USHORT) (j - i - 1) * sizeof(WCHAR);
  850. shareName.MaximumLength = shareName.Length;
  851. shareName.Buffer = &filePath->Buffer[i+1];
  852. PktRelease();
  853. DnrContext->ReleasePkt = FALSE;
  854. status = PktExpandSpecialName(
  855. &dfsRootName,
  856. &pSpecialEntry);
  857. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  858. if (NT_SUCCESS(status)) {
  859. ULONG Len;
  860. if ((j+1) < filePath->Length/sizeof(WCHAR)) {
  861. Len = filePath->Length - ((j+1) * sizeof(WCHAR));
  862. DnrContext->RemainingPart.Buffer = &filePath->Buffer[j+1];
  863. DnrContext->RemainingPart.Length = (USHORT) Len;
  864. DnrContext->RemainingPart.MaximumLength = (USHORT) Len;
  865. } else {
  866. DnrContext->RemainingPart.Buffer = NULL;
  867. DnrContext->RemainingPart.Length = 0;
  868. DnrContext->RemainingPart.MaximumLength = 0;
  869. }
  870. status = PktEntryFromSpecialEntry(
  871. pSpecialEntry,
  872. &shareName,
  873. &pktEntry);
  874. InterlockedDecrement(&pSpecialEntry->UseCount);
  875. }
  876. }
  877. #endif
  878. #if 0
  879. if (pktEntry != NULL) {
  880. pktEntry->ExpireTime = pktEntry->TimeToLive;
  881. }
  882. #endif
  883. DfsDbgTrace(0, Dbg, "DnrNameResolve: found pktEntry %08lx\n",
  884. pktEntry);
  885. DNR_SET_TARGET_INFO( DnrContext, pktEntry );
  886. if (pktEntry == NULL) {
  887. //
  888. // We didn't find any entry. We set pPktEntry to NULL so that
  889. // in GetFirstDC, the call to PktLookupReferralEntry will
  890. // return the right thing (ie, will give use the highest DC we
  891. // know about).
  892. //
  893. DnrContext->pPktEntry = NULL;
  894. DnrContext->State = DnrStateGetFirstDC;
  895. } else if (pktEntry->Type & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM) {
  896. DnrRebuildDnrContext(
  897. DnrContext,
  898. &pktEntry->Info.ServiceList[0].Address,
  899. &DnrContext->RemainingPart);
  900. //
  901. // The DnrContext has been rebuilt and programmed to
  902. // "restart" DNR. So, we'll just break out of the state
  903. // machine and reenter it with the reconstructed context
  904. //
  905. } else {
  906. ASSERT(pktEntry != NULL);
  907. DnrContext->pPktEntry = pktEntry;
  908. DnrContext->USN = pktEntry->USN;
  909. DnrContext->State = DnrStateGetFirstReplica;
  910. }
  911. break;
  912. case DnrStateGetFirstReplica:
  913. DfsDbgTrace(0, Dbg, "FSM state GetFirstReplica\n", 0);
  914. #if DBG
  915. if (MupVerbose) {
  916. KeQuerySystemTime(&EndTime);
  917. DbgPrint("[%d] FSM state DnrStateGetFirstReplica\n",
  918. (EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000));
  919. }
  920. #endif
  921. ASSERT(DnrContext->ReleasePkt == TRUE);
  922. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  923. Status = ReplFindFirstProvider(DnrContext->pPktEntry,
  924. NULL,
  925. NULL,
  926. &DnrContext->pService,
  927. &DnrContext->RSelectContext,
  928. &LastEntry);
  929. if (! NT_SUCCESS(Status)) {
  930. ULONG PktType = DnrContext->pPktEntry->Type;
  931. ExReleaseResourceLite(&DfsData.Resource);
  932. DfsDbgTrace(0, Dbg, "No provider found %08lx\n", ULongToPtr(Status));
  933. if (DnrContext->GotReferral ||
  934. (PktType & PKT_ENTRY_TYPE_SYSVOL) != 0 ||
  935. DnrContext->GotReparse == TRUE
  936. ) {
  937. DnrContext->FinalStatus = STATUS_NO_SUCH_DEVICE;
  938. DnrContext->State = DnrStateDone;
  939. break;
  940. } else {
  941. DnrContext->State = DnrStateGetFirstDC;
  942. break;
  943. }
  944. } else if (DnrContext->pService->Address.Length == 0) {
  945. ExReleaseResourceLite(&DfsData.Resource);
  946. DfsDbgTrace(0, Dbg, "Service with no address, going for referral\n", 0);
  947. DnrContext->State = DnrStateGetFirstDC;
  948. break;
  949. } else {
  950. ASSERT(DnrContext->pService != NULL);
  951. ASSERT(DnrContext->pService->pProvider != NULL);
  952. #if DBG
  953. if (MupVerbose)
  954. DbgPrint(" Alternate Name=[%wZ] Address=[%wZ]\n",
  955. &DnrContext->pService->Name,
  956. &DnrContext->pService->Address);
  957. #endif
  958. DnrContext->pProvider = DnrContext->pService->pProvider;
  959. DnrContext->ProviderId = DnrContext->pProvider->eProviderId;
  960. DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject;
  961. DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
  962. if (LastEntry == TRUE) {
  963. DnrContext->DfsNameContext.Flags |= DFS_FLAG_LAST_ALTERNATE;
  964. } else {
  965. DnrContext->DfsNameContext.Flags &= ~DFS_FLAG_LAST_ALTERNATE;
  966. }
  967. ExReleaseResourceLite(&DfsData.Resource);
  968. DnrContext->State = DnrStateSendRequest;
  969. }
  970. // FALL THROUGH ...
  971. case DnrStateSendRequest:
  972. #if DBG
  973. if (MupVerbose) {
  974. KeQuerySystemTime(&EndTime);
  975. DbgPrint("[%d] FSM state DnrStateSendRequest\n",
  976. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  977. }
  978. #endif
  979. DfsDbgTrace(0, Dbg, "FSM state SendRequest\n", 0);
  980. ASSERT(DnrContext->ReleasePkt == TRUE);
  981. ASSERT(DnrContext->pService != NULL);
  982. ASSERT(DnrContext->pProvider != NULL);
  983. ASSERT(DnrContext->TargetDevice != NULL);
  984. //
  985. // First of all, check to see if the volume is offline
  986. //
  987. if (DnrContext->pService->Type & DFS_SERVICE_TYPE_OFFLINE) {
  988. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  989. DnrContext->FinalStatus = STATUS_DEVICE_OFF_LINE;
  990. DnrContext->State = DnrStateDone;
  991. DfsDbgTrace(-1, Dbg, "DnrNameResolve: Device Offline\n",0);
  992. Status = STATUS_DEVICE_OFF_LINE;
  993. MUP_TRACE_HIGH(ERROR, DnrNameResolve_Error3,
  994. LOGSTATUS(Status)
  995. LOGPTR(FileObject));
  996. break;
  997. }
  998. //
  999. // Next, try to make an authenticated connection to the server, if needed
  1000. //
  1001. // The pkt lock may be dropped in this call, so keep the pkt entry from going
  1002. // away.
  1003. //
  1004. InterlockedIncrement(&DnrContext->pPktEntry->UseCount);
  1005. PktRelease();
  1006. DnrContext->ReleasePkt = FALSE;
  1007. Status = DnrGetAuthenticatedConnection( DnrContext );
  1008. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  1009. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  1010. if (!NT_SUCCESS(Status)) {
  1011. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  1012. DnrContext->FinalStatus = Status;
  1013. //
  1014. // If the error is such that we need to try another replica,
  1015. // do so here.
  1016. //
  1017. if (ReplIsRecoverableError(Status)) {
  1018. DnrContext->State = DnrStateGetNextReplica;
  1019. }
  1020. else {
  1021. DnrContext->State = DnrStateDone;
  1022. }
  1023. DfsDbgTrace(-1, Dbg,
  1024. "DnrNameResolve: Unable to get connection %08lx\n", ULongToPtr(Status));
  1025. break;
  1026. }
  1027. if (DnrContext->USN != DnrContext->pPktEntry->USN) {
  1028. //
  1029. // Dang, Pkt Entry changed when we made the
  1030. // connection. We'll have to retry.
  1031. //
  1032. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  1033. DnrReleaseAuthenticatedConnection(DnrContext);
  1034. DnrContext->State = DnrStateStart;
  1035. DfsDbgTrace(-1, Dbg, "DnrNameResolve: USN delta - restarting DNR\n", 0);
  1036. break;
  1037. }
  1038. Status = DnrRedirectFileOpen(DnrContext);
  1039. if (Status == STATUS_PENDING) {
  1040. return(Status);
  1041. }
  1042. break;
  1043. case DnrStatePostProcessOpen:
  1044. DfsDbgTrace(0, Dbg, "FSM state PostProcessOpen\n", 0);
  1045. #if DBG
  1046. if (MupVerbose) {
  1047. KeQuerySystemTime(&EndTime);
  1048. DbgPrint("[%d] FSM state DnrStatePostProcessOpen\n",
  1049. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  1050. }
  1051. #endif
  1052. //
  1053. // We come to this state only after sending an open request over
  1054. // the net. We should never hold the Pkt while going over the net.
  1055. // Hence the sense of the assert below.
  1056. //
  1057. ASSERT(DnrContext->ReleasePkt == FALSE);
  1058. Status = DnrPostProcessFileOpen(DnrContext);
  1059. pktEntry = DnrContext->pPktEntry;
  1060. break;
  1061. case DnrStateGetNextReplica:
  1062. DfsDbgTrace(0, Dbg, "FSM state GetNextReplica\n", 0);
  1063. #if DBG
  1064. if (MupVerbose) {
  1065. KeQuerySystemTime(&EndTime);
  1066. DbgPrint("[%d] FSM state DnrGetNextReplica\n",
  1067. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  1068. }
  1069. #endif
  1070. ASSERT(DnrContext->ReleasePkt == TRUE);
  1071. {
  1072. NTSTATUS ReplStatus;
  1073. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  1074. ReplStatus = ReplFindNextProvider(DnrContext->pPktEntry,
  1075. &DnrContext->pService,
  1076. &DnrContext->RSelectContext,
  1077. &LastEntry);
  1078. if (ReplStatus == STATUS_NO_MORE_ENTRIES) {
  1079. ULONG PktType = DnrContext->pPktEntry->Type;
  1080. #if DBG
  1081. if (MupVerbose)
  1082. DbgPrint(" No more alternates...\n");
  1083. #endif
  1084. //
  1085. // If all failed and we are about to give up due to one
  1086. // of two reasons :
  1087. // 1. None of the Services for the PkEntry being used
  1088. // responded (either they are down or network down!).
  1089. // 2. Some or all of the Services have inconsistencies
  1090. // which we detected and informed the DC about along
  1091. // the way.
  1092. // If we did land up with case 2 then we really have to
  1093. // try and get a new referral and use that - just in
  1094. // case things have changed since then at the DC. So let
  1095. // us get into a GetReferral State and try once again.
  1096. //
  1097. ExReleaseResourceLite( &DfsData.Resource );
  1098. if (DnrContext->GotReferral ||
  1099. (PktType & PKT_ENTRY_TYPE_SYSVOL) != 0 ||
  1100. DnrContext->GotReparse == TRUE
  1101. ) {
  1102. DnrContext->State = DnrStateDone;
  1103. } else {
  1104. DnrContext->State = DnrStateGetFirstDC;
  1105. }
  1106. } else if (NT_SUCCESS( ReplStatus )) {
  1107. //
  1108. // Found another replica, go back and retry.
  1109. //
  1110. ASSERT(DnrContext->pService != NULL);
  1111. ASSERT(DnrContext->pService->pProvider != NULL);
  1112. DnrContext->pProvider = DnrContext->pService->pProvider;
  1113. DnrContext->ProviderId = DnrContext->pProvider->eProviderId;
  1114. DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject;
  1115. DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
  1116. ExReleaseResourceLite(&DfsData.Resource);
  1117. DnrContext->State = DnrStateSendRequest;
  1118. #if DBG
  1119. if (MupVerbose)
  1120. DbgPrint(" Alternate Name=[%wZ] Address=[%wZ]\n",
  1121. &DnrContext->pService->Name,
  1122. &DnrContext->pService->Address);
  1123. #endif
  1124. if (LastEntry == TRUE) {
  1125. DnrContext->DfsNameContext.Flags |= DFS_FLAG_LAST_ALTERNATE;
  1126. } else {
  1127. DnrContext->DfsNameContext.Flags &= ~DFS_FLAG_LAST_ALTERNATE;
  1128. }
  1129. break;
  1130. } else {
  1131. ExReleaseResourceLite(&DfsData.Resource);
  1132. ASSERT(ReplStatus == STATUS_NO_MORE_ENTRIES);
  1133. }
  1134. }
  1135. break;
  1136. case DnrStateGetFirstDC:
  1137. DfsDbgTrace(0, Dbg, "FSM state GetFirstDC\n", 0);
  1138. #if DBG
  1139. if (MupVerbose) {
  1140. KeQuerySystemTime(&EndTime);
  1141. DbgPrint("[%d] FSM state DnrStateGetFirstDC\n",
  1142. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  1143. }
  1144. #endif
  1145. ASSERT(DnrContext->ReleasePkt == TRUE);
  1146. {
  1147. NTSTATUS ReplStatus;
  1148. PDFS_PKT_ENTRY pPktEntryDC = NULL;
  1149. pPktEntryDC = PktLookupReferralEntry(&DfsData.Pkt, DnrContext->pPktEntry);
  1150. //
  1151. // If there is no root entry, or it is stale, or it has no
  1152. // services, then try for a new referral entry for the root
  1153. //
  1154. if (
  1155. pPktEntryDC == NULL
  1156. ||
  1157. pPktEntryDC->ExpireTime <= 0
  1158. ||
  1159. pPktEntryDC->Info.ServiceCount == 0
  1160. ) {
  1161. if (DnrContext->CalledDCLocator) {
  1162. DnrContext->FinalStatus = STATUS_CANT_ACCESS_DOMAIN_INFO;
  1163. DnrContext->State = DnrStateDone;
  1164. break;
  1165. }
  1166. //
  1167. // We are unable to find a DC to go to for referrals.
  1168. // This can only happen if we don't have the pkt entry
  1169. // for the root of the Dfs. Try to get the root entry.
  1170. //
  1171. DfsDbgTrace(0, Dbg, "No DC info - will try locator\n", 0);
  1172. #if DBG
  1173. if (MupVerbose) {
  1174. if (pPktEntryDC != NULL && pPktEntryDC <= 0)
  1175. DbgPrint(" Entry is stale.\n");
  1176. DbgPrint(" No Root/DC info - will try locator\n");
  1177. }
  1178. #endif
  1179. PktRelease();
  1180. DnrContext->ReleasePkt = FALSE;
  1181. DnrLocateDC(&DnrContext->FileName);
  1182. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  1183. DnrContext->CalledDCLocator = TRUE;
  1184. DnrContext->State = DnrStateStart;
  1185. break;
  1186. }
  1187. #if DBG
  1188. if (MupVerbose) {
  1189. if (DnrContext->pPktEntry != NULL)
  1190. DbgPrint(" DnrContext->pPktEntry=[%wZ]\n",
  1191. &DnrContext->pPktEntry->Id.Prefix);
  1192. else
  1193. DbgPrint(" DnrContext->pPktEntry=NULL\n");
  1194. DbgPrint(" pPktEntryDC=[%wZ]\n", &pPktEntryDC->Id.Prefix);
  1195. }
  1196. #endif
  1197. DnrContext->pPktEntry = pPktEntryDC;
  1198. DNR_SET_TARGET_INFO( DnrContext, DnrContext->pPktEntry );
  1199. DnrContext->USN = pPktEntryDC->USN;
  1200. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  1201. ReplStatus = ReplFindFirstProvider(pPktEntryDC,
  1202. NULL,
  1203. NULL,
  1204. &DnrContext->pService,
  1205. &DnrContext->RDCSelectContext,
  1206. &LastEntry);
  1207. if (!NT_SUCCESS(ReplStatus)) {
  1208. ExReleaseResourceLite(&DfsData.Resource);
  1209. DnrContext->FinalStatus = STATUS_CANT_ACCESS_DOMAIN_INFO;
  1210. DnrContext->State = DnrStateDone;
  1211. break;
  1212. } else {
  1213. ASSERT(DnrContext->pService != NULL);
  1214. ASSERT(DnrContext->pService->pProvider != NULL);
  1215. InterlockedIncrement(&DnrContext->pPktEntry->UseCount);
  1216. DnrContext->pProvider = DnrContext->pService->pProvider;
  1217. DnrContext->ProviderId = DnrContext->pProvider->eProviderId;
  1218. DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject;
  1219. DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
  1220. ExReleaseResourceLite(&DfsData.Resource);
  1221. }
  1222. }
  1223. DnrContext->State = DnrStateGetReferrals;
  1224. /* FALL THROUGH */
  1225. case DnrStateGetReferrals:
  1226. DfsDbgTrace(0, Dbg, "FSM state GetReferrals\n", 0);
  1227. #if DBG
  1228. if (MupVerbose) {
  1229. KeQuerySystemTime(&EndTime);
  1230. DbgPrint("[%d] FSM state DnrStateGetReferrals\n",
  1231. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  1232. }
  1233. #endif
  1234. ASSERT(DnrContext->ReleasePkt == TRUE);
  1235. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  1236. //
  1237. // Attempt to open the Dfs Root's IPC$ share if we haven't already done
  1238. // so.
  1239. //
  1240. if (DnrContext->pService->ConnFile == NULL) {
  1241. HANDLE hDC;
  1242. SE_IMPERSONATION_STATE DisabledImpersonationState;
  1243. BOOLEAN RestoreImpersonationState = FALSE;
  1244. ExReleaseResourceLite(&DfsData.Resource);
  1245. KeQuerySystemTime(&EndTime);
  1246. #if DBG
  1247. if (MupVerbose)
  1248. DbgPrint(" [%d] Opening connection to [\\%wZ\\IPC$] using [%wZ]\n",
  1249. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)),
  1250. &DnrContext->pService->Name,
  1251. &DnrContext->pProvider->DeviceName);
  1252. #endif
  1253. if (MupUseNullSessionForDfs) {
  1254. RestoreImpersonationState = PsDisableImpersonation(
  1255. PsGetCurrentThread(),
  1256. &DisabledImpersonationState);
  1257. }
  1258. Status = DfsCreateConnection(
  1259. DnrContext->pService,
  1260. DnrContext->pProvider,
  1261. (BOOLEAN)
  1262. ((DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) != 0),
  1263. &hDC);
  1264. if (RestoreImpersonationState) {
  1265. PsRestoreImpersonation(
  1266. PsGetCurrentThread(),
  1267. &DisabledImpersonationState);
  1268. }
  1269. #if DBG
  1270. if (MupVerbose)
  1271. DbgPrint(" Open of connection Status=0x%x\n", Status);
  1272. #endif
  1273. if (NT_SUCCESS( Status )) {
  1274. if (DnrContext->USN != DnrContext->pPktEntry->USN) {
  1275. //
  1276. // Dang, Pkt Entry changed when we made the
  1277. // connection. We'll have to retry.
  1278. //
  1279. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  1280. ZwClose( hDC );
  1281. DnrContext->State = DnrStateGetFirstDC;
  1282. #if DBG
  1283. if (MupVerbose)
  1284. DbgPrint(" USN changed.\n");
  1285. #endif
  1286. break;
  1287. }
  1288. }
  1289. if ( NT_SUCCESS( Status ) ) {
  1290. PFILE_OBJECT DcFileObject; // Need stack based variable
  1291. // because ObRef... expects
  1292. // this parameter to be in
  1293. // non-paged memory.
  1294. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  1295. if (DnrContext->pService->ConnFile == NULL) {
  1296. //
  1297. // 426184, need to check return code for errors.
  1298. //
  1299. Status = ObReferenceObjectByHandle(
  1300. hDC,
  1301. 0,
  1302. NULL,
  1303. KernelMode,
  1304. (PVOID *)&DcFileObject,
  1305. NULL);
  1306. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrNameResolve_Error_ObReferenceObjectByHandle,
  1307. LOGSTATUS(Status)
  1308. LOGPTR(DcFileObject));
  1309. #if DBG
  1310. if (MupVerbose)
  1311. DbgPrint(" ObReferenceObjectByHandle returned 0x%x\n", Status);
  1312. #endif
  1313. if ( NT_SUCCESS( Status ) ) {
  1314. DnrContext->pService->ConnFile = DcFileObject;
  1315. }
  1316. ZwClose( hDC );
  1317. }
  1318. }
  1319. if ( NT_SUCCESS( Status ) ) {
  1320. DnrContext->DCConnFile = DnrContext->pService->ConnFile;
  1321. DnrContext->CachedConnFile = FALSE;
  1322. DFS_REFERENCE_OBJECT( DnrContext->DCConnFile );
  1323. ExReleaseResourceLite( &DfsData.Resource );
  1324. } else if (DfsEventLog > 0) {
  1325. LogWriteMessage(
  1326. DFS_CONNECTION_FAILURE,
  1327. Status,
  1328. 1,
  1329. &DnrContext->pService->Name);
  1330. }
  1331. } else {
  1332. //
  1333. // DnrContext->pService is protected by the Pkt lock. Since we
  1334. // will be using pService->ConnFile to send the referral request,
  1335. // we better reference and cache it.
  1336. //
  1337. DnrContext->DCConnFile = DnrContext->pService->ConnFile;
  1338. DFS_REFERENCE_OBJECT( DnrContext->DCConnFile );
  1339. DnrContext->CachedConnFile = TRUE;
  1340. ExReleaseResourceLite(&DfsData.Resource);
  1341. Status = STATUS_SUCCESS;
  1342. }
  1343. //
  1344. // Unable to get IPC$ share, try the next Dfs root
  1345. //
  1346. if (!NT_SUCCESS(Status)) {
  1347. DnrContext->State = DnrStateGetNextDC;
  1348. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  1349. break;
  1350. }
  1351. //
  1352. // Opened Dfs Root's IPC$ share - remember this DC is a good one.
  1353. //
  1354. ReplSetActiveService(
  1355. DnrContext->pPktEntry,
  1356. DnrContext->RDCSelectContext);
  1357. //
  1358. // Build the Referral request...
  1359. //
  1360. Irp = DnrBuildReferralRequest(DnrContext);
  1361. if (Irp == NULL) {
  1362. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  1363. Irp = DnrContext->OriginalIrp;
  1364. DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  1365. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  1366. DFS_DEREFERENCE_OBJECT(DnrContext->DCConnFile);
  1367. DnrContext->State = DnrStateDone;
  1368. #if DBG
  1369. if (MupVerbose)
  1370. DbgPrint(" DnrBuildReferralRequest returned NULL irp\n");
  1371. #endif
  1372. break;
  1373. }
  1374. DnrContext->State = DnrStateCompleteReferral;
  1375. PktRelease();
  1376. DnrContext->ReleasePkt = FALSE;
  1377. //
  1378. // The PktReferralRequests semaphore is used to control how
  1379. // many threads can simultaneously be going for referrals. The
  1380. // following Wait will decrement the PktReferralRequests
  1381. // semaphore by 1 if it is not already 0. If it is 0, then
  1382. // this thread will suspend until someone else bumps up the
  1383. // semaphore by 1. We will bump up the semaphore count in
  1384. // DnrCompleteReferral.
  1385. //
  1386. Status = KeWaitForSingleObject(
  1387. &DfsData.PktReferralRequests,
  1388. UserRequest, // WaitReason - don't care
  1389. KernelMode,
  1390. FALSE, // Alertable
  1391. NULL); // Timeout
  1392. ASSERT(Status == STATUS_SUCCESS);
  1393. KeQuerySystemTime(&EndTime);
  1394. #if DBG
  1395. if (MupVerbose)
  1396. DbgPrint(" [%d] asking for referral (IoCallDriver)\n",
  1397. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  1398. #endif
  1399. IoMarkIrpPending( DnrContext->OriginalIrp );
  1400. Status = IoCallDriver( DnrContext->TargetDevice, Irp );
  1401. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrNameResolve_Error_IoCallDriver,
  1402. LOGSTATUS(Status)
  1403. LOGPTR(FileObject));
  1404. //
  1405. // We now return STATUS_PENDING. DnrCompleteReferral will
  1406. // resume the Dnr.
  1407. //
  1408. DfsDbgTrace(-1, Dbg, "DnrNameResolve: returning %08lx\n", ULongToPtr(STATUS_PENDING));
  1409. return(STATUS_PENDING);
  1410. case DnrStateGetNextDC:
  1411. DfsDbgTrace(0, Dbg, "FSM State GetNextDC\n", 0);
  1412. #if DBG
  1413. if (MupVerbose) {
  1414. KeQuerySystemTime(&EndTime);
  1415. DbgPrint("[%d] FSM state DnrStateGetNextDC\n",
  1416. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  1417. }
  1418. #endif
  1419. {
  1420. NTSTATUS ReplStatus;
  1421. PDFS_PKT_ENTRY pPktEntry = NULL;
  1422. UNICODE_STRING RemPath;
  1423. pPktEntry = PktLookupEntryByPrefix(&DfsData.Pkt,
  1424. &DnrContext->FileName,
  1425. &RemPath);
  1426. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  1427. ReplStatus = ReplFindNextProvider(DnrContext->pPktEntry,
  1428. &DnrContext->pService,
  1429. &DnrContext->RDCSelectContext,
  1430. &LastEntry);
  1431. if (NT_SUCCESS(ReplStatus)) {
  1432. ASSERT(DnrContext->pService != NULL);
  1433. ASSERT(DnrContext->pService->pProvider != NULL);
  1434. DnrContext->pProvider = DnrContext->pService->pProvider;
  1435. DnrContext->ProviderId = DnrContext->pProvider->eProviderId;
  1436. DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject;
  1437. DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
  1438. DnrContext->State = DnrStateGetReferrals;
  1439. } else if (pPktEntry != NULL && pPktEntry->ExpireTime <= 0) {
  1440. ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
  1441. #if DBG
  1442. if (MupVerbose) {
  1443. DbgPrint(" Out of roots to try for referral for [%wZ]\n",
  1444. &DnrContext->FileName);
  1445. DbgPrint(" Found stale referral [%wZ], adding 60 sec to it\n",
  1446. &pPktEntry->Id.Prefix);
  1447. }
  1448. #endif
  1449. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  1450. DnrContext->State = DnrStateStart;
  1451. } else {
  1452. #if DBG
  1453. if (MupVerbose)
  1454. DbgPrint(" Out of roots to try for referral for [%wZ], no stale found\n",
  1455. &DnrContext->FileName);
  1456. #endif
  1457. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  1458. DnrContext->FinalStatus = STATUS_CANT_ACCESS_DOMAIN_INFO;
  1459. DnrContext->State = DnrStateDone;
  1460. }
  1461. ExReleaseResourceLite(&DfsData.Resource);
  1462. }
  1463. break;
  1464. case DnrStateDone:
  1465. #if DBG
  1466. if (MupVerbose) {
  1467. KeQuerySystemTime(&EndTime);
  1468. DbgPrint("[%d] FSM state DnrStateDone\n",
  1469. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  1470. }
  1471. #endif
  1472. Status = DnrContext->FinalStatus;
  1473. // FALL THROUGH ...
  1474. case DnrStateLocalCompletion:
  1475. DfsDbgTrace(0, Dbg, "FSM state Done\n", 0);
  1476. #if DBG
  1477. if (MupVerbose) {
  1478. KeQuerySystemTime(&EndTime);
  1479. DbgPrint("[%d] FSM state DnrStateLocalCompletion\n",
  1480. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  1481. }
  1482. #endif
  1483. if (Status != STATUS_LOGON_FAILURE && !ReplIsRecoverableError(Status)) {
  1484. if (DnrContext->pPktEntry != NULL &&
  1485. (DnrContext->pPktEntry->Type & PKT_ENTRY_TYPE_SYSVOL) &&
  1486. (DnrContext->pPktEntry->Link.Flink == &(DnrContext->pPktEntry->Link))) {
  1487. PDFS_PKT Pkt = _GetPkt();
  1488. PDFS_PKT_ENTRY Entry = DnrContext->pPktEntry;
  1489. PDFS_PKT_ENTRY pMatchEntry;
  1490. InterlockedIncrement(&Entry->UseCount);
  1491. if (DnrContext->ReleasePkt)
  1492. PktRelease();
  1493. PktAcquireExclusive(TRUE, &DnrContext->ReleasePkt);
  1494. InterlockedDecrement(&Entry->UseCount);
  1495. #if DBG
  1496. if ((MupVerbose) && (pktEntry != NULL)) {
  1497. //
  1498. // Temporary debug stuff.
  1499. //
  1500. if ((pktEntry->NodeTypeCode != DSFS_NTC_PKT_ENTRY) ||
  1501. (pktEntry->NodeByteSize != sizeof(*pktEntry))) {
  1502. DbgPrint("DnrNameResolve: Updating bogus Pkt entry avoided: Pkt Entry 0x%x\n", pktEntry);
  1503. }
  1504. }
  1505. #endif
  1506. pMatchEntry = PktFindEntryByPrefix(
  1507. Pkt,
  1508. &Entry->Id.Prefix);
  1509. if ((Entry->Type & PKT_ENTRY_TYPE_DELETE_PENDING) == 0) {
  1510. if (pMatchEntry == NULL) {
  1511. if (DfsInsertUnicodePrefix(&Pkt->PrefixTable,
  1512. &Entry->Id.Prefix,
  1513. &Entry->PrefixTableEntry)) {
  1514. //
  1515. // We successfully created the prefix entry, so now we link
  1516. // this entry into the PKT.
  1517. //
  1518. PktLinkEntry(Pkt, Entry);
  1519. }
  1520. } else {
  1521. //
  1522. // Destroy this entry if it isn't in the table, as we are
  1523. // about to orphan it.
  1524. //
  1525. if (pMatchEntry != NULL && pMatchEntry != Entry) {
  1526. Entry->ActiveService = NULL;
  1527. PktEntryIdDestroy(&Entry->Id, FALSE);
  1528. PktEntryInfoDestroy(&Entry->Info, FALSE);
  1529. ExFreePool(Entry);
  1530. }
  1531. }
  1532. }
  1533. PktRelease();
  1534. DnrContext->ReleasePkt = FALSE;
  1535. }
  1536. }
  1537. if (DnrContext->ReleasePkt)
  1538. PktRelease();
  1539. if ((Status == STATUS_DEVICE_OFF_LINE) &&
  1540. (IrpSp->FileObject->RelatedFileObject == NULL)) {
  1541. Status = DfsRerouteOpenToMup(IrpSp->FileObject, &DnrContext->FileName);
  1542. }
  1543. if (DnrContext->FcbToUse != NULL) {
  1544. DfsDetachFcb(DnrContext->FcbToUse->FileObject, DnrContext->FcbToUse);
  1545. ExFreePool( DnrContext->FcbToUse );
  1546. }
  1547. DfsCompleteRequest(DnrContext->pIrpContext, Irp, Status);
  1548. DnrReleaseCredentials(DnrContext);
  1549. SeDeleteClientSecurity( &DnrContext->SecurityContext );
  1550. if (DnrContext->NameAllocated)
  1551. ExFreePool( DnrContext->FileName.Buffer );
  1552. if (DnrContext->pDfsTargetInfo != NULL)
  1553. {
  1554. PktReleaseTargetInfo(DnrContext->pDfsTargetInfo);
  1555. DnrContext->pDfsTargetInfo = NULL;
  1556. }
  1557. KeQuerySystemTime(&EndTime);
  1558. #if DBG
  1559. if (MupVerbose)
  1560. DbgPrint("[%d] DnrNameResolve exit 0x%x\n",
  1561. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)),
  1562. Status);
  1563. #endif
  1564. DeallocateDnrContext(DnrContext);
  1565. DfsDbgTrace(-1, Dbg, "DnrNameResolve: Exit ->%x\n", ULongToPtr(Status));
  1566. return Status;
  1567. default:
  1568. BugCheck("DnrNameResolve: unexpected DNR state");
  1569. }
  1570. }
  1571. BugCheck("DnrNameResolve: unexpected exit from loop");
  1572. }
  1573. //+----------------------------------------------------------------------------
  1574. //
  1575. // Function: DnrComposeFileName
  1576. //
  1577. // Synopsis: Given a DFS_VCB (implicitly a Device Object), and a file name
  1578. // relative to that device, this routine will compose a fully
  1579. // qualified name (ie, a name relative to the highest (org) root).
  1580. //
  1581. // Arguments: [FullName] -- Fully qualified name destination.
  1582. // [Vcb] -- Pointer to Vcb of Device Object.
  1583. // [RelatedFile] -- Related file object.
  1584. // [FileName] -- The file being "name resolved"
  1585. //
  1586. // Returns:
  1587. //
  1588. // Note: This function assumes that file names are composed precisely
  1589. // of two parts - the name relative to org of the file object's
  1590. // device, followed by the name of the file relative to the device
  1591. // This may not be true if we have a related file object! In that
  1592. // case, the full name is three part - device name relative to
  1593. // org, related file name relative to device, and file name
  1594. // relative to related file. However, in create.c,
  1595. // DfsCommonCreate, we manipulate file objects so all opens look
  1596. // like "non-relative" opens. If one changes that code, then
  1597. // this function must be changed to correspond.
  1598. //
  1599. //-----------------------------------------------------------------------------
  1600. VOID
  1601. DnrComposeFileName(
  1602. OUT PUNICODE_STRING FullName,
  1603. IN PDFS_VCB Vcb,
  1604. IN PFILE_OBJECT RelatedFile,
  1605. IN PUNICODE_STRING FileName
  1606. )
  1607. {
  1608. PUNICODE_STRING LogRootPrefix = &(Vcb->LogRootPrefix);
  1609. ASSERT(FullName->MaximumLength >= FileName->Length + LogRootPrefix->Length);
  1610. ASSERT(FullName->Length == 0);
  1611. ASSERT(FullName->Buffer != NULL);
  1612. if ((LogRootPrefix->Length > 0) && (RelatedFile == NULL)) {
  1613. RtlMoveMemory(FullName->Buffer, LogRootPrefix->Buffer,
  1614. LogRootPrefix->Length);
  1615. FullName->Length = LogRootPrefix->Length;
  1616. } else {
  1617. FullName->Buffer[0] = UNICODE_PATH_SEP;
  1618. FullName->Length = sizeof(UNICODE_PATH_SEP);
  1619. }
  1620. DnrConcatenateFilePath(
  1621. FullName,
  1622. FileName->Buffer,
  1623. FileName->Length);
  1624. }
  1625. //+----------------------------------------------------------------------------
  1626. //
  1627. // Function: DnrCaptureCredentials
  1628. //
  1629. // Synopsis: Captures the credentials to use for Dnr.
  1630. //
  1631. // Arguments: [DnrContext] -- The DNR_CONTEXT record describing the Dnr.
  1632. //
  1633. // Returns: Nothing -- The DnrContext is simply updated.
  1634. //
  1635. //-----------------------------------------------------------------------------
  1636. VOID
  1637. DnrCaptureCredentials(
  1638. IN OUT PDNR_CONTEXT DnrContext)
  1639. {
  1640. #ifdef TERMSRV
  1641. NTSTATUS Status;
  1642. ULONG SessionID;
  1643. #endif // TERMSRV
  1644. LUID LogonID;
  1645. DfsDbgTrace(+1, Dbg, "DnrCaptureCredentials: Enter [%wZ] \n", &DnrContext->FileName);
  1646. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  1647. DfsGetLogonId( &LogonID );
  1648. #ifdef TERMSRV
  1649. Status = TSGetRequestorSessionId( DnrContext->OriginalIrp, & SessionID );
  1650. ASSERT( NT_SUCCESS( Status ) ) ;
  1651. if( NT_SUCCESS( Status ) ) {
  1652. DnrContext->Credentials = DfsLookupCredentials( &DnrContext->FileName, SessionID, &LogonID );
  1653. }
  1654. else {
  1655. DnrContext->Credentials = NULL;
  1656. }
  1657. #else // TERMSRV
  1658. DnrContext->Credentials = DfsLookupCredentials( &DnrContext->FileName, &LogonID );
  1659. #endif // TERMSRV
  1660. if (DnrContext->Credentials != NULL)
  1661. DnrContext->Credentials->RefCount++;
  1662. ExReleaseResourceLite( &DfsData.Resource );
  1663. DfsDbgTrace(-1, Dbg, "DnrCaptureCredentials: Exit. Creds %x\n", DnrContext->Credentials);
  1664. }
  1665. //+----------------------------------------------------------------------------
  1666. //
  1667. // Function: DnrReleaseCredentials
  1668. //
  1669. // Synopsis: Releases the credentials captured by DnrCaptureCredentials
  1670. //
  1671. // Arguments: [DnrContext] -- The DNR_CONTEXT into which credentials were
  1672. // captured.
  1673. //
  1674. // Returns: Nothing
  1675. //
  1676. //-----------------------------------------------------------------------------
  1677. VOID
  1678. DnrReleaseCredentials(
  1679. IN PDNR_CONTEXT DnrContext)
  1680. {
  1681. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  1682. if (DnrContext->Credentials != NULL)
  1683. DnrContext->Credentials->RefCount--;
  1684. ExReleaseResourceLite( &DfsData.Resource );
  1685. }
  1686. //+-------------------------------------------------------------------
  1687. //
  1688. // Function: DnrRedirectFileOpen, local
  1689. //
  1690. // Synopsis: This routine redirects a create IRP request to the specified
  1691. // provider by doing an IoCallDriver to the device object for
  1692. // which the file open is destined. This routine takes care of
  1693. // converting the FileObject's name from the Dfs namespace to
  1694. // the underlying file system's namespace.
  1695. //
  1696. // Arguments: [DnrContext] -- The context block for the DNR. All
  1697. // parameters for the operation will be taken from
  1698. // here.
  1699. //
  1700. // Returns: [STATUS_DEVICE_OFF_LINE] -- The service for the volume
  1701. // is currently off line.
  1702. //
  1703. // [STATUS_DEVICE_NOT_CONNECTED] -- The storage for the volume
  1704. // is not available at this time. Might have been blown
  1705. // off by a format etc.
  1706. //
  1707. // [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate room
  1708. // for the file name that the provider for this volume
  1709. // understands.
  1710. //
  1711. // [STATUS_PENDING] -- If the underlying file system returned
  1712. // STATUS_PENDING.
  1713. //
  1714. // Any other NTSTATUS that the underlying file system returned.
  1715. //
  1716. // Notes:
  1717. //
  1718. //--------------------------------------------------------------------
  1719. NTSTATUS
  1720. DnrRedirectFileOpen (
  1721. IN PDNR_CONTEXT DnrContext
  1722. ) {
  1723. PIRP Irp = DnrContext->OriginalIrp;
  1724. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1725. PIO_STACK_LOCATION NextIrpSp = NULL;
  1726. PFILE_OBJECT FileObject = IrpSp->FileObject;
  1727. PDFS_VCB Vcb = DnrContext->Vcb;
  1728. NTSTATUS Status;
  1729. UNICODE_STRING fileName;
  1730. ULONG CreateOptions;
  1731. PPROVIDER_DEF pProvider;
  1732. UNICODE_STRING ProviderDeviceName;
  1733. DfsDbgTrace(+1, Dbg, "DnrRedirectFileOpen: Entered\n", 0);
  1734. MUP_TRACE_NORM(DNR, DnrRedirectFileOpen_Entry,
  1735. LOGPTR(DnrContext->OriginalIrp)
  1736. LOGUSTR(DnrContext->FileName));
  1737. //
  1738. // If this is a csc agent open, force the open to the LanManRedirector,
  1739. // as this is the only redirector that works with csc.
  1740. //
  1741. DNR_SET_TARGET_INFO( DnrContext, DnrContext->pPktEntry );
  1742. DnrContext->DfsNameContext.pLMRTargetInfo = NULL;
  1743. DnrContext->DfsNameContext.pDfsTargetInfo = NULL;
  1744. if (DnrContext->pDfsTargetInfo != NULL) {
  1745. if (DnrContext->pDfsTargetInfo->DfsHeader.Flags & TARGET_INFO_DFS)
  1746. {
  1747. DnrContext->DfsNameContext.pDfsTargetInfo =
  1748. (PVOID)&DnrContext->pDfsTargetInfo->TargetInfo;
  1749. }
  1750. else {
  1751. DnrContext->DfsNameContext.pLMRTargetInfo =
  1752. (PVOID)&DnrContext->pDfsTargetInfo->LMRTargetInfo;
  1753. }
  1754. }
  1755. if (
  1756. (DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME)
  1757. &&
  1758. (DnrContext->pService->Type & DFS_SERVICE_TYPE_DOWN_LEVEL)
  1759. ) {
  1760. RtlInitUnicodeString(&ProviderDeviceName, DD_NFS_DEVICE_NAME_U);
  1761. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  1762. Status = DfsGetProviderForDevice(
  1763. &ProviderDeviceName,
  1764. &DnrContext->pProvider);
  1765. if (NT_SUCCESS( Status )) {
  1766. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  1767. if (MupVerbose)
  1768. DbgPrint(" CSCAGENT:Provider Device [%wZ] -> [%wZ]\n",
  1769. &DnrContext->TargetDevice->DriverObject->DriverName,
  1770. &DnrContext->pProvider->DeviceObject->DriverObject->DriverName);
  1771. DnrContext->ProviderId = DnrContext->pProvider->eProviderId;
  1772. DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject;
  1773. DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
  1774. } else {
  1775. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  1776. ExReleaseResourceLite( &DfsData.Resource );
  1777. DnrReleaseAuthenticatedConnection(DnrContext);
  1778. DnrContext->FinalStatus = STATUS_BAD_NETWORK_PATH;
  1779. DnrContext->State = DnrStateDone;
  1780. return(STATUS_BAD_NETWORK_PATH);
  1781. }
  1782. ExReleaseResourceLite( &DfsData.Resource );
  1783. }
  1784. //
  1785. // Prepare to hand of the open request to the next driver. We
  1786. // must give it a name that it will understand; so, we save the original
  1787. // file name in the DnrContext in case we need to restore it in the
  1788. // event of a failure.
  1789. //
  1790. DnrContext->SavedFileName = FileObject->FileName;
  1791. DnrContext->SavedRelatedFileObject = FileObject->RelatedFileObject;
  1792. ASSERT( DnrContext->SavedFileName.Buffer != NULL );
  1793. //
  1794. // Create the full path name to be opened from the target device
  1795. // object.
  1796. //
  1797. fileName.MaximumLength =
  1798. DnrContext->pService->Address.Length +
  1799. DnrContext->pPktEntry->Id.Prefix.Length +
  1800. sizeof (WCHAR) +
  1801. DnrContext->RemainingPart.Length;
  1802. fileName.Buffer = ExAllocatePoolWithTag(PagedPool, fileName.MaximumLength, ' puM');
  1803. if (fileName.Buffer == NULL) {
  1804. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  1805. DnrReleaseAuthenticatedConnection(DnrContext);
  1806. DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  1807. DnrContext->State = DnrStateDone;
  1808. return(STATUS_INSUFFICIENT_RESOURCES);
  1809. }
  1810. if (DnrContext->pService->Address.Buffer) {
  1811. RtlMoveMemory( fileName.Buffer,
  1812. DnrContext->pService->Address.Buffer,
  1813. DnrContext->pService->Address.Length
  1814. );
  1815. fileName.Length = DnrContext->pService->Address.Length;
  1816. } else {
  1817. fileName.Buffer[0] = UNICODE_PATH_SEP;
  1818. fileName.Length = sizeof(WCHAR);
  1819. }
  1820. //
  1821. // If we are supposed to strip the prefix, do it now.
  1822. //
  1823. if (!(DnrContext->pService->Capability & PROV_STRIP_PREFIX)) {
  1824. DnrConcatenateFilePath(
  1825. &fileName,
  1826. DnrContext->pPktEntry->Id.Prefix.Buffer,
  1827. DnrContext->pPktEntry->Id.Prefix.Length);
  1828. }
  1829. if (DnrContext->RemainingPart.Length > 0) {
  1830. DnrConcatenateFilePath(
  1831. &fileName,
  1832. DnrContext->RemainingPart.Buffer,
  1833. DnrContext->RemainingPart.Length);
  1834. }
  1835. DnrContext->NewNameLen = fileName.Length;
  1836. //
  1837. // Attempt to open the file. Copy all of the information
  1838. // from the create IRP we received.
  1839. //
  1840. DfsDbgTrace( 0, Dbg, "Attempt to open %wZ\n", &fileName );
  1841. //
  1842. // Copy the stack from one to the next...
  1843. //
  1844. NextIrpSp = IoGetNextIrpStackLocation(Irp);
  1845. (*NextIrpSp) = (*IrpSp);
  1846. CreateOptions = IrpSp->Parameters.Create.Options;
  1847. // Update the type of open in the DfsNameContext
  1848. if (DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) {
  1849. #if DBG
  1850. if (MupVerbose)
  1851. DbgPrint(" FsContext = DFS_CSCAGENT_NAME_CONTEXT\n");
  1852. #endif
  1853. DnrContext->DfsNameContext.NameContextType = DFS_CSCAGENT_NAME_CONTEXT;
  1854. } else {
  1855. #if DBG
  1856. if (MupVerbose)
  1857. DbgPrint(" FsContext = DFS_USER_NAME_CONTEXT\n");
  1858. #endif
  1859. DnrContext->DfsNameContext.NameContextType = DFS_USER_NAME_CONTEXT;
  1860. }
  1861. FileObject->FsContext = &(DnrContext->DfsNameContext);
  1862. if (DnrContext->pProvider->fProvCapability & PROV_DFS_RDR) {
  1863. //
  1864. // We are connecting to a dfs-aware server. Indicate this to the
  1865. // redirector.
  1866. //
  1867. FileObject->FsContext2 = UIntToPtr(DFS_OPEN_CONTEXT);
  1868. } else {
  1869. //
  1870. // We are connecting to a downlevel server. Indicate to the redirector
  1871. // that Dfs is trying a downlevel access.
  1872. //
  1873. FileObject->FsContext2 = UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT);
  1874. }
  1875. NextIrpSp->Parameters.Create.Options = CreateOptions;
  1876. FileObject->RelatedFileObject = NULL;
  1877. FileObject->FileName = fileName;
  1878. IoSetCompletionRoutine(
  1879. Irp,
  1880. DnrCompleteFileOpen,
  1881. DnrContext,
  1882. TRUE,
  1883. TRUE,
  1884. TRUE);
  1885. //
  1886. // Now, we are going to pass the buck to the provider for this volume.
  1887. // This can potentially go over the net. To avoid needless contentions,
  1888. // we release the Pkt.
  1889. //
  1890. ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
  1891. InterlockedIncrement(&DnrContext->pPktEntry->UseCount);
  1892. #if defined (USECOUNT_DBG)
  1893. {
  1894. LONG Count;
  1895. Count = InterlockedIncrement(&DnrContext->pService->pMachEntry->UseCount);
  1896. if (Count < DnrContext->pService->pMachEntry->SvcUseCount)
  1897. {
  1898. DbgPrint("DnrContext %x, 1\n", DnrContext);
  1899. DfsDbgBreakPoint;
  1900. }
  1901. }
  1902. #else
  1903. InterlockedIncrement(&DnrContext->pService->pMachEntry->UseCount);
  1904. #endif
  1905. DnrContext->FcbToUse->DfsMachineEntry = DnrContext->pService->pMachEntry;
  1906. DnrContext->FcbToUse->TargetDevice = DnrContext->TargetDevice;
  1907. DnrContext->FcbToUse->ProviderId = DnrContext->ProviderId;
  1908. PktRelease();
  1909. DnrContext->ReleasePkt = FALSE;
  1910. #if DBG
  1911. if (MupVerbose)
  1912. DbgPrint(" DnrRedirectFileOpen of [%wZ(%wZ):0x%x] to [%wZ]\n",
  1913. &fileName,
  1914. &DnrContext->DfsNameContext.UNCFileName,
  1915. DnrContext->DfsNameContext.Flags,
  1916. &DnrContext->TargetDevice->DriverObject->DriverName);
  1917. #endif
  1918. MUP_TRACE_NORM(DNR, DnrRedirectFileOpen_BeforeIoCallDriver,
  1919. LOGPTR(Irp)
  1920. LOGUSTR(DnrContext->FileName)
  1921. LOGUSTR(DnrContext->TargetDevice->DriverObject->DriverName));
  1922. Status = IoCallDriver(DnrContext->TargetDevice, Irp);
  1923. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrRedirectFileOpen_Error_IoCallDriver,
  1924. LOGSTATUS(Status)
  1925. LOGPTR(Irp)
  1926. LOGPTR(FileObject)
  1927. LOGPTR(DnrContext));
  1928. if (Status != STATUS_PENDING) {
  1929. DnrContext->State = DnrStatePostProcessOpen;
  1930. }
  1931. DfsDbgTrace( 0, Dbg, "IoCallDriver Status = %8lx\n", ULongToPtr(Status));
  1932. DfsDbgTrace(-1, Dbg, "DnrRedirectFileOpen: Exit -> %x\n", ULongToPtr(Status));
  1933. return(Status);
  1934. }
  1935. //+-------------------------------------------------------------------
  1936. //
  1937. // Function: DnrPostProcessFileOpen, local
  1938. //
  1939. // Synopsis: This routine picks up where DnrRedirectFileOpen left off.
  1940. // It figures out what the underlying file system returned
  1941. // in response to our IoCallDriver, and resumes DNR from there.
  1942. //
  1943. // Arguments: [DnrContext] -- The context block for the DNR. All
  1944. // parameters for the operation will be taken from
  1945. // here.
  1946. //
  1947. // Returns: NTSTATUS - The status of the operation.
  1948. //
  1949. //--------------------------------------------------------------------
  1950. ULONG StopOnError = 0;
  1951. NTSTATUS
  1952. DnrPostProcessFileOpen(
  1953. IN PDNR_CONTEXT DnrContext)
  1954. {
  1955. NTSTATUS Status;
  1956. PDFS_VCB Vcb = DnrContext->Vcb;
  1957. PIRP Irp = DnrContext->OriginalIrp;
  1958. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  1959. PFILE_OBJECT FileObject = IrpSp->FileObject;
  1960. LARGE_INTEGER EndTime;
  1961. DfsDbgTrace( +1, Dbg, "DnrPostProcessFileOpen Entered: DnrContext = %08lx\n",
  1962. DnrContext );
  1963. Status = DnrContext->FinalStatus;
  1964. if ((Status == STATUS_LOGON_FAILURE) || (Status == STATUS_ACCESS_DENIED))
  1965. {
  1966. if (MupVerbose)
  1967. {
  1968. DbgPrint("File %wZ, (%wZ), Status %x\n",
  1969. &DnrContext->ContextFileName, &FileObject->FileName, Status);
  1970. DbgPrint("Context used was %x, %x\n", DnrContext->DfsNameContext.pDfsTargetInfo,
  1971. DnrContext->DfsNameContext.pLMRTargetInfo );
  1972. DbgPrint("Driver is %wZ\n", &DnrContext->TargetDevice->DriverObject->DriverName);
  1973. }
  1974. }
  1975. #if DBG
  1976. if (MupVerbose) {
  1977. KeQuerySystemTime(&EndTime);
  1978. DbgPrint(" [%d] DnrPostProcessFileOpen entered [%wZ] Status = 0x%x\n",
  1979. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)),
  1980. &FileObject->FileName,
  1981. Status);
  1982. }
  1983. #endif
  1984. if ( Status == STATUS_REPARSE ) {
  1985. //
  1986. // This may have been an open sent to the MUP, who is now returning a status
  1987. // reparse. Figure out the name of the device that this is being
  1988. // reparsed to, create (if needed) a PROVIDER_DEF for this new device,
  1989. // and retry DnrRedirectFileOpen. Also, update the service
  1990. // structure to point to this new provider.
  1991. //
  1992. //
  1993. // If the device is not mup, clean out any child entries for the pkt
  1994. // entry that represents the root of the dfs, then stop dnr with
  1995. // STATUS_REPARSE
  1996. //
  1997. PDFS_PKT_ENTRY pEntry;
  1998. UNICODE_STRING ProviderDevice;
  1999. UNICODE_STRING MupDeviceName;
  2000. UNICODE_STRING FileName;
  2001. UNICODE_STRING RemPath;
  2002. USHORT i, j;
  2003. DfsDbgTrace(0, Dbg, "Processing STATUS_REPARSE...\n", 0);
  2004. ProviderDevice = FileObject->FileName;
  2005. RtlInitUnicodeString(&MupDeviceName, L"\\FileSystem\\Mup");
  2006. #if DBG
  2007. if (MupVerbose)
  2008. DbgPrint(" Comparing [%wZ] to [%wZ]\n",
  2009. &DnrContext->TargetDevice->DriverObject->DriverName,
  2010. &MupDeviceName);
  2011. #endif
  2012. if ( RtlCompareUnicodeString(
  2013. &DnrContext->TargetDevice->DriverObject->DriverName,
  2014. &MupDeviceName,
  2015. TRUE) != 0
  2016. ) {
  2017. //
  2018. // This is *not* the mup returning REPARSE
  2019. //
  2020. FileName = DnrContext->FileName;
  2021. //
  2022. // We want to work with the \Server\Share part of the FileName only,
  2023. // so count up to 3 backslashes, then stop.
  2024. //
  2025. for (i = j = 0; i < FileName.Length/sizeof(WCHAR) && j < 3; i++) {
  2026. if (FileName.Buffer[i] == UNICODE_PATH_SEP) {
  2027. j++;
  2028. }
  2029. }
  2030. FileName.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
  2031. #if DBG
  2032. if (MupVerbose)
  2033. DbgPrint(" Will remove all children of [%wZ]\n", &FileName);
  2034. #endif
  2035. PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
  2036. //
  2037. // Now find the pkt entry
  2038. //
  2039. pEntry = PktLookupEntryByPrefix(
  2040. &DfsData.Pkt,
  2041. &FileName,
  2042. &RemPath);
  2043. //
  2044. // And remove all children
  2045. //
  2046. if (pEntry != NULL) {
  2047. PktFlushChildren(pEntry);
  2048. }
  2049. PktRelease();
  2050. DnrContext->ReleasePkt = FALSE;
  2051. DnrContext->GotReparse = TRUE;
  2052. DnrContext->State = DnrStateDone;
  2053. Status = STATUS_REPARSE;
  2054. } else {
  2055. //
  2056. // This is the mup returning REPARSE
  2057. //
  2058. //
  2059. // We want to work with the \Device\Driver part of the ProviderDevice only,
  2060. // so count up to 3 backslashes, then stop.
  2061. //
  2062. for (i = j = 0; i < ProviderDevice.Length/sizeof(WCHAR) && j < 3; i++) {
  2063. if (ProviderDevice.Buffer[i] == UNICODE_PATH_SEP) {
  2064. j++;
  2065. }
  2066. }
  2067. ProviderDevice.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
  2068. DfsDbgTrace(0, Dbg, "Provider Device is [%wZ]\n", &ProviderDevice);
  2069. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  2070. Status = DfsGetProviderForDevice(
  2071. &ProviderDevice,
  2072. &DnrContext->pProvider);
  2073. if (NT_SUCCESS( Status )) {
  2074. DnrContext->ProviderId = DnrContext->pProvider->eProviderId;
  2075. DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject;
  2076. DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
  2077. DnrContext->State = DnrStateSendRequest;
  2078. } else {
  2079. if (DnrContext->FinalStatus != STATUS_REPARSE) {
  2080. DnrContext->FinalStatus = Status;
  2081. }
  2082. DnrContext->State = DnrStateDone;
  2083. }
  2084. ExReleaseResourceLite( &DfsData.Resource );
  2085. }
  2086. ASSERT(DnrContext->ReleasePkt == FALSE);
  2087. //
  2088. // Set active service only if we're going to
  2089. // continue DNR, and the USN hasn't changed.
  2090. //
  2091. // The exit code (see comment at end) will restart DNR if the USN
  2092. // has changed.
  2093. //
  2094. if (NT_SUCCESS( Status )) {
  2095. PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
  2096. if (DnrContext->USN == DnrContext->pPktEntry->USN) {
  2097. ReplSetActiveService(DnrContext->pPktEntry,
  2098. DnrContext->RSelectContext);
  2099. DnrContext->pService->ProviderId =
  2100. DnrContext->pProvider->eProviderId;
  2101. DnrContext->pService->pProvider = DnrContext->pProvider;
  2102. }
  2103. PktConvertExclusiveToShared();
  2104. } else {
  2105. if (Status == STATUS_FS_DRIVER_REQUIRED) {
  2106. Status = STATUS_REPARSE;
  2107. }
  2108. DnrContext->FinalStatus = Status;
  2109. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  2110. }
  2111. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  2112. #if defined (USECOUNT_DBG)
  2113. {
  2114. LONG Count;
  2115. Count = InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
  2116. if (Count < DnrContext->FcbToUse->DfsMachineEntry->SvcUseCount)
  2117. {
  2118. DbgPrint("DnrContext %x, 2\n", DnrContext);
  2119. DfsDbgBreakPoint;
  2120. }
  2121. }
  2122. #else
  2123. InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
  2124. #endif
  2125. DfsDbgTrace(0, Dbg, "State after Reparse is %d\n", DnrContext->State);
  2126. }
  2127. else if (( Status == STATUS_LOGON_FAILURE ) || (Status == STATUS_ACCESS_DENIED))
  2128. {
  2129. UNICODE_STRING ProviderDeviceName;
  2130. UNICODE_STRING MupDeviceName;
  2131. UNICODE_STRING ProviderDevice;
  2132. BOOLEAN ReturnError = FALSE;
  2133. NTSTATUS SavedStatus = Status;
  2134. ProviderDevice = FileObject->FileName;
  2135. RtlInitUnicodeString(&MupDeviceName, L"\\FileSystem\\Mup");
  2136. if ( RtlCompareUnicodeString(
  2137. &DnrContext->TargetDevice->DriverObject->DriverName,
  2138. &MupDeviceName,
  2139. TRUE) == 0 )
  2140. {
  2141. RtlInitUnicodeString(&ProviderDeviceName, DD_NFS_DEVICE_NAME_U);
  2142. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  2143. Status = DfsGetProviderForDevice( &ProviderDeviceName,
  2144. &DnrContext->pProvider);
  2145. if (Status == STATUS_SUCCESS) {
  2146. DnrContext->ProviderId = DnrContext->pProvider->eProviderId;
  2147. DnrContext->TargetDevice = DnrContext->pProvider->DeviceObject;
  2148. DFS_REFERENCE_OBJECT(DnrContext->TargetDevice);
  2149. DnrContext->State = DnrStateSendRequest;
  2150. }
  2151. ExReleaseResourceLite( &DfsData.Resource );
  2152. if (Status == STATUS_SUCCESS)
  2153. {
  2154. PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
  2155. if (DnrContext->USN == DnrContext->pPktEntry->USN) {
  2156. ReplSetActiveService(DnrContext->pPktEntry,
  2157. DnrContext->RSelectContext);
  2158. DnrContext->pService->ProviderId =
  2159. DnrContext->pProvider->eProviderId;
  2160. DnrContext->pService->pProvider = DnrContext->pProvider;
  2161. }
  2162. PktConvertExclusiveToShared();
  2163. }
  2164. }
  2165. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  2166. InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
  2167. if (Status != STATUS_SUCCESS)
  2168. {
  2169. DnrContext->FinalStatus = SavedStatus;
  2170. DnrContext->State = DnrStateDone;
  2171. ExFreePool( FileObject->FileName.Buffer );
  2172. FileObject->FileName = DnrContext->SavedFileName;
  2173. FileObject->RelatedFileObject = DnrContext->SavedRelatedFileObject;
  2174. }
  2175. }
  2176. else if ( Status == STATUS_OBJECT_TYPE_MISMATCH ) {
  2177. //
  2178. // This was an open sent to a downlevel server\share that failed
  2179. // because the server happens to be in a Dfs itself. If so, we
  2180. // simply change the name on which we are doing DNR and restart DNR.
  2181. //
  2182. DfsDbgTrace(0, Dbg, "Downlevel access found inter-dfs link!\n", 0);
  2183. DfsDbgTrace(
  2184. 0, Dbg, "Current File name is [%wZ]\n", &FileObject->FileName);
  2185. ASSERT(DnrContext->ReleasePkt == FALSE);
  2186. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  2187. //
  2188. // Bug: 332061. do not mark it as outside my dom.
  2189. //
  2190. // DnrContext->pPktEntry->Type |= PKT_ENTRY_TYPE_OUTSIDE_MY_DOM;
  2191. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  2192. #if defined (USECOUNT_DBG)
  2193. {
  2194. LONG Count;
  2195. Count = InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
  2196. if (Count < DnrContext->FcbToUse->DfsMachineEntry->SvcUseCount)
  2197. {
  2198. DbgPrint("DnrContext %x, 3\n", DnrContext);
  2199. DfsDbgBreakPoint;
  2200. }
  2201. }
  2202. #else
  2203. InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
  2204. #endif
  2205. DnrContext->RemainingPart.Length = 0;
  2206. DnrContext->RemainingPart.MaximumLength = 0;
  2207. DnrContext->RemainingPart.Buffer = 0;
  2208. DnrRebuildDnrContext(
  2209. DnrContext,
  2210. &FileObject->FileName,
  2211. &DnrContext->RemainingPart);
  2212. ExFreePool(FileObject->FileName.Buffer);
  2213. FileObject->FileName = DnrContext->SavedFileName;
  2214. FileObject->RelatedFileObject = DnrContext->SavedRelatedFileObject;
  2215. } else if ( NT_SUCCESS( Status ) ) {
  2216. PDFS_FCB Fcb;
  2217. DfsDbgTrace( 0, Dbg, "Open attempt succeeded\n", 0 );
  2218. ASSERT( (DnrContext->FileName.Length & 0x1) == 0 );
  2219. Fcb = DnrContext->FcbToUse;
  2220. DnrContext->FcbToUse = NULL;
  2221. DfsDbgTrace(0, Dbg, "Fcb = %08lx\n", Fcb);
  2222. Fcb->TargetDevice = DnrContext->TargetDevice;
  2223. Fcb->ProviderId = DnrContext->ProviderId;
  2224. //
  2225. // If we file (dir) happens to be a junction point, we capture its
  2226. // alternate name from the Pkt Entry, so we can field requests for
  2227. // FileAlternateNameInformation.
  2228. //
  2229. if (DnrContext->RemainingPart.Length == 0) {
  2230. UNICODE_STRING allButLast;
  2231. USHORT UseLength;
  2232. RemoveLastComponent(
  2233. &DnrContext->pPktEntry->Id.ShortPrefix,
  2234. &allButLast);
  2235. //
  2236. // 587769: Set alternate path only if we have enough
  2237. // space in target buffer.
  2238. //
  2239. UseLength = DnrContext->pPktEntry->Id.ShortPrefix.Length -
  2240. allButLast.Length;
  2241. if (Fcb->AlternateFileName.MaximumLength > UseLength)
  2242. {
  2243. Fcb->AlternateFileName.Length = UseLength;
  2244. RtlCopyMemory(
  2245. Fcb->AlternateFileName.Buffer,
  2246. &DnrContext->pPktEntry->Id.ShortPrefix.Buffer[allButLast.Length/sizeof(WCHAR)],
  2247. Fcb->AlternateFileName.Length);
  2248. DfsDbgTrace(
  2249. 0, Dbg, "Captured alternate name [%wZ]\n",
  2250. &Fcb->AlternateFileName);
  2251. }
  2252. }
  2253. InterlockedIncrement(&Fcb->Vcb->OpenFileCount);
  2254. PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
  2255. if (DnrContext->USN == DnrContext->pPktEntry->USN) {
  2256. ReplSetActiveService(DnrContext->pPktEntry,
  2257. DnrContext->RSelectContext);
  2258. }
  2259. //
  2260. // Reset the life time since we just used this PKT entry successfully.
  2261. //
  2262. DnrContext->pPktEntry->ExpireTime = DnrContext->pPktEntry->TimeToLive;
  2263. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  2264. PktConvertExclusiveToShared();
  2265. DnrContext->FinalStatus = Status;
  2266. DnrContext->State = DnrStateDone;
  2267. ExFreePool( DnrContext->SavedFileName.Buffer );
  2268. } else { // ! NT_SUCCESS( Status ) on IoCallDriver
  2269. DfsDbgTrace( 0, Dbg, "Open attempt failed %8lx\n", ULongToPtr(Status) );
  2270. if (Status == STATUS_PATH_NOT_COVERED || Status == STATUS_DFS_EXIT_PATH_FOUND) {
  2271. if (DnrContext->GotReferral) {
  2272. //
  2273. // We just got a referral, and the server is saying
  2274. // path_not_covered. Means DC and server are out
  2275. // of sync. Inform the DC
  2276. //
  2277. DfsDbgTrace(0, Dbg, "Dnr: Knowledge inconsistency discovered %wZ\n",
  2278. &FileObject->FileName);
  2279. (VOID) DfsTriggerKnowledgeVerification( DnrContext );
  2280. //
  2281. // If we never found an inconsistency let us now
  2282. // go back and try to see if we got this fixed.
  2283. // We won't be in an endless loop since we will
  2284. // not do this more than once.
  2285. //
  2286. if (DnrContext->FoundInconsistency == FALSE) {
  2287. DnrContext->State = DnrStateGetFirstReplica;
  2288. DnrContext->FoundInconsistency = TRUE;
  2289. } else
  2290. DnrContext->State = DnrStateGetNextReplica;
  2291. } else {
  2292. DnrContext->State = DnrStateGetFirstDC;
  2293. }
  2294. } else if (ReplIsRecoverableError( Status )) {
  2295. //
  2296. // Check to see if the error returned was something worth
  2297. // trying a replica for.
  2298. //
  2299. DnrContext->State = DnrStateGetNextReplica;
  2300. #if DBG
  2301. if (MupVerbose)
  2302. DbgPrint(" Recoverable error 0x%x State = DnrStateGetNextReplica\n", Status);
  2303. #endif
  2304. }
  2305. else if ((Status == STATUS_OBJECT_PATH_NOT_FOUND) &&
  2306. (DnrContext->RemainingPart.Length == 0)) {
  2307. //
  2308. // if we hit a PATH_NOT_FOUND at the root, it usually means
  2309. // that we have hit a machine that is no longer the root.
  2310. // If there is only one target, mark it as expired.
  2311. // otherwise, move on to the other targets.
  2312. //
  2313. if (DnrContext->pPktEntry->Info.ServiceCount > 1)
  2314. {
  2315. DnrContext->State = DnrStateGetNextReplica;
  2316. }
  2317. else
  2318. {
  2319. DnrContext->pPktEntry->ExpireTime = 0;
  2320. DnrContext->FinalStatus = Status;
  2321. DnrContext->State = DnrStateDone;
  2322. }
  2323. } else {
  2324. DnrContext->FinalStatus = Status;
  2325. DnrContext->State = DnrStateDone;
  2326. #if DBG
  2327. if (MupVerbose)
  2328. DbgPrint(" NON-Recoverable error 0x%x State = DnrStateDone\n", Status);
  2329. #endif
  2330. }
  2331. if (DfsEventLog > 0) {
  2332. UNICODE_STRING puStr[2];
  2333. if (!DnrContext->ReleasePkt)
  2334. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  2335. if (DnrContext->USN == DnrContext->pPktEntry->USN) {
  2336. puStr[0] = FileObject->FileName;
  2337. puStr[1] = DnrContext->pService->Name;
  2338. LogWriteMessage(DFS_OPEN_FAILURE, Status, 2, puStr);
  2339. }
  2340. }
  2341. //
  2342. // In either case, we are going back into DNR. Let's acquire shared
  2343. // access to Pkt. We had released the Pkt just before doing the
  2344. // IoCallDriver.
  2345. //
  2346. if (!DnrContext->ReleasePkt)
  2347. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  2348. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  2349. #if defined (USECOUNT_DBG)
  2350. {
  2351. LONG Count;
  2352. Count = InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
  2353. if (Count < DnrContext->FcbToUse->DfsMachineEntry->SvcUseCount)
  2354. {
  2355. DbgPrint("DnrContext %x, 4\n", DnrContext);
  2356. DfsDbgBreakPoint;
  2357. }
  2358. }
  2359. #else
  2360. InterlockedDecrement(&DnrContext->FcbToUse->DfsMachineEntry->UseCount);
  2361. #endif
  2362. ExFreePool( FileObject->FileName.Buffer );
  2363. FileObject->FileName = DnrContext->SavedFileName;
  2364. FileObject->RelatedFileObject = DnrContext->SavedRelatedFileObject;
  2365. }
  2366. //
  2367. // One last thing. If we are going back into DNR for whatever reason,
  2368. // check to see if the PktEntry we captured in the DNR_CONTEXT has
  2369. // changed. If so, we'll simply have to restart.
  2370. //
  2371. if (DnrContext->State != DnrStateDone &&
  2372. DnrContext->pPktEntry != NULL &&
  2373. DnrContext->pPktEntry->USN != DnrContext->USN) {
  2374. DnrContext->State = DnrStateStart;
  2375. }
  2376. #if DBG
  2377. if (MupVerbose) {
  2378. KeQuerySystemTime(&EndTime);
  2379. DbgPrint(" [%d] DnrPostProcessFileOpen Exited: Status = %08lx State = %d\n",
  2380. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)),
  2381. Status,
  2382. DnrContext->State);
  2383. }
  2384. #endif
  2385. DfsDbgTrace( -1, Dbg, "DnrPostProcessFileOpen Exited: Status = %08lx\n",
  2386. ULongToPtr(Status) );
  2387. return Status;
  2388. }
  2389. //+----------------------------------------------------------------------------
  2390. //
  2391. // Function: DnrGetAuthenticatedConnection
  2392. //
  2393. // Synopsis: If this Dnr is using user-supplied credentials, this routine
  2394. // will setup a tree connection using the user-supplied
  2395. // credentials.
  2396. //
  2397. // Notes: This routine might free and reacquire the Pkt lock. This
  2398. // means that the Pkt entry referenced in DnrContext might
  2399. // become invalid after this call. The caller is assumed to
  2400. // have cached and referenced everything she will need to
  2401. // use in DnrContext before making this call.
  2402. //
  2403. // Arguments: [DnrContext] -- The DNR_CONTEXT record for this Dnr
  2404. //
  2405. // Returns: [STATUS_SUCCESS] -- Operation completed successfully
  2406. //
  2407. // NT Status from the attempt to create the tree connection
  2408. //
  2409. //-----------------------------------------------------------------------------
  2410. NTSTATUS
  2411. DnrGetAuthenticatedConnection(
  2412. IN OUT PDNR_CONTEXT DnrContext)
  2413. {
  2414. NTSTATUS Status;
  2415. PDFS_SERVICE pService = DnrContext->pService;
  2416. BOOLEAN fDoConnection = TRUE;
  2417. LARGE_INTEGER EndTime;
  2418. PFILE_OBJECT TreeConnFileObj = NULL;
  2419. DfsDbgTrace(+1, Dbg, "DnrGetAuthenticatedConnection: Entered\n", 0);
  2420. #if DBG
  2421. if (MupVerbose) {
  2422. KeQuerySystemTime(&EndTime);
  2423. DbgPrint(" [%d] DnrGetAuthenticatedConnection(\\%wZ)\n",
  2424. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)),
  2425. &pService->Address);
  2426. }
  2427. #endif
  2428. ASSERT(DnrContext->pService != NULL);
  2429. ASSERT(DnrContext->pProvider != NULL);
  2430. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  2431. //
  2432. // See if we are using supplied credentials
  2433. //
  2434. if (DnrContext->Credentials == NULL) {
  2435. DfsDbgTrace(-1, Dbg,
  2436. "DnrGetAuthenticatedConnection: Dnr with no creds\n", 0);
  2437. #if DBG
  2438. if (MupVerbose) {
  2439. KeQuerySystemTime(&EndTime);
  2440. DbgPrint(" [%d] DnrGetAuthenticatedConnection: No creds exit STATUS_SUCCESS\n",
  2441. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  2442. }
  2443. #endif
  2444. ExReleaseResourceLite( &DfsData.Resource );
  2445. return( STATUS_SUCCESS );
  2446. }
  2447. //
  2448. // See if this is a credential record describing the use of default
  2449. // credentials
  2450. //
  2451. if (DnrContext->Credentials->EaLength == 0) {
  2452. DfsDbgTrace(-1, Dbg,
  2453. "DnrGetAuthenticatedConnection: Dnr with default creds\n", 0);
  2454. #if DBG
  2455. if (MupVerbose) {
  2456. KeQuerySystemTime(&EndTime);
  2457. DbgPrint(" [%d] DnrGetAuthenticatedConnection: Default creds exit STATUS_SUCCESS\n",
  2458. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  2459. }
  2460. #endif
  2461. ExReleaseResourceLite( &DfsData.Resource );
  2462. return( STATUS_SUCCESS );
  2463. }
  2464. //
  2465. // See if we already have a authenticated connection to the server, and
  2466. // the authenticated connection was established using the credentials
  2467. // we want to use.
  2468. //
  2469. if (pService->pMachEntry->AuthConn != NULL) {
  2470. if (
  2471. (DnrContext->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) != 0
  2472. &&
  2473. pService->pMachEntry->Credentials == DnrContext->Credentials
  2474. ) {
  2475. DnrContext->AuthConn = pService->pMachEntry->AuthConn;
  2476. DFS_REFERENCE_OBJECT( DnrContext->AuthConn );
  2477. fDoConnection = FALSE;
  2478. DfsDbgTrace(0, Dbg,
  2479. "Using existing tree connect %08lx\n", DnrContext->AuthConn);
  2480. #if DBG
  2481. if (MupVerbose) {
  2482. KeQuerySystemTime(&EndTime);
  2483. DbgPrint(" [%d] Using existing tree connect\n",
  2484. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  2485. }
  2486. #endif
  2487. Status = STATUS_SUCCESS;
  2488. } else {
  2489. DfsDbgTrace(0, Dbg,
  2490. "Deleting connect %08lx\n", pService->pMachEntry->AuthConn);
  2491. #if DBG
  2492. if (MupVerbose) {
  2493. KeQuerySystemTime(&EndTime);
  2494. DbgPrint(" [%d] Deleting tree connect connect\n",
  2495. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)));
  2496. }
  2497. #endif
  2498. TreeConnFileObj = pService->pMachEntry->AuthConn;
  2499. pService->pMachEntry->AuthConn = NULL;
  2500. pService->pMachEntry->Credentials->RefCount--;
  2501. pService->pMachEntry->Credentials = NULL;
  2502. if (pService->ConnFile != NULL)
  2503. DfsCloseConnection( pService );
  2504. }
  2505. }
  2506. ExReleaseResourceLite( &DfsData.Resource );
  2507. //
  2508. // We delete the tree connection after releasing the resource, since
  2509. // the delete involve a call to a lower level driver and we want to
  2510. // avoid resource lock conflicts.
  2511. //
  2512. if (TreeConnFileObj) {
  2513. DfsDeleteTreeConnection( TreeConnFileObj, USE_FORCE );
  2514. }
  2515. //
  2516. // If we need to establish a new authenticated connection, do it now.
  2517. // We need a new connection because either we had none, or the one we
  2518. // had was using a different set of credentials.
  2519. //
  2520. if (fDoConnection) {
  2521. UNICODE_STRING shareName;
  2522. HANDLE treeHandle;
  2523. OBJECT_ATTRIBUTES objectAttributes;
  2524. IO_STATUS_BLOCK ioStatusBlock;
  2525. USHORT i, k;
  2526. //
  2527. // Compute the share name...
  2528. //
  2529. shareName.MaximumLength =
  2530. sizeof(DD_NFS_DEVICE_NAME_U) +
  2531. pService->Address.Length;
  2532. shareName.Buffer = ExAllocatePoolWithTag(PagedPool, shareName.MaximumLength, ' puM');
  2533. if (shareName.Buffer != NULL) {
  2534. shareName.Length = 0;
  2535. RtlAppendUnicodeToString(
  2536. &shareName,
  2537. DD_NFS_DEVICE_NAME_U);
  2538. RtlAppendUnicodeStringToString(&shareName, &pService->Address);
  2539. //
  2540. // One can only do tree connects to server\share. So, in case
  2541. // pService->Address refers to something deeper than the share,
  2542. // make sure we setup a tree-conn only to server\share. Note that
  2543. // by now, shareName is of the form
  2544. // \Device\LanmanRedirector\server\share<\path>. So, count up to
  2545. // 4 slashes and terminate the share name there.
  2546. //
  2547. for (i = 0, k = 0;
  2548. i < shareName.Length/sizeof(WCHAR) && k < 5;
  2549. i++) {
  2550. if (shareName.Buffer[i] == UNICODE_PATH_SEP)
  2551. k++;
  2552. }
  2553. shareName.Length = i * sizeof(WCHAR);
  2554. if (k == 5)
  2555. shareName.Length -= sizeof(WCHAR);
  2556. InitializeObjectAttributes(
  2557. &objectAttributes,
  2558. &shareName,
  2559. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  2560. NULL,
  2561. NULL);
  2562. DfsDbgTrace(0, Dbg, "Tree connecting to %wZ\n", &shareName);
  2563. DfsDbgTrace(0, Dbg,
  2564. "Credentials @%08lx\n", DnrContext->Credentials);
  2565. Status = ZwCreateFile(
  2566. &treeHandle,
  2567. SYNCHRONIZE,
  2568. &objectAttributes,
  2569. &ioStatusBlock,
  2570. NULL,
  2571. FILE_ATTRIBUTE_NORMAL,
  2572. FILE_SHARE_READ |
  2573. FILE_SHARE_WRITE |
  2574. FILE_SHARE_DELETE,
  2575. FILE_OPEN_IF,
  2576. FILE_CREATE_TREE_CONNECTION |
  2577. FILE_SYNCHRONOUS_IO_NONALERT,
  2578. (PVOID) DnrContext->Credentials->EaBuffer,
  2579. DnrContext->Credentials->EaLength);
  2580. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrGetAuthenticatedConnection_Error_ZwCreateFile,
  2581. LOGSTATUS(Status));
  2582. #if DBG
  2583. if (MupVerbose) {
  2584. KeQuerySystemTime(&EndTime);
  2585. DbgPrint(" [%d] Tree connect to [%wZ] returned 0x%x\n",
  2586. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)),
  2587. &shareName,
  2588. Status);
  2589. }
  2590. #endif
  2591. if (NT_SUCCESS(Status)) {
  2592. PFILE_OBJECT fileObject;
  2593. DfsDbgTrace(0, Dbg, "Tree connect succeeded\n", 0);
  2594. //
  2595. // 426184, need to check return code for errors.
  2596. //
  2597. Status = ObReferenceObjectByHandle(
  2598. treeHandle,
  2599. 0,
  2600. NULL,
  2601. KernelMode,
  2602. (PVOID *)&fileObject,
  2603. NULL);
  2604. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DnrGetAuthenticatedConnection_Error_ObReferenceObjectByHandle,
  2605. LOGSTATUS(Status));
  2606. ZwClose( treeHandle );
  2607. if (NT_SUCCESS(Status)) {
  2608. DnrContext->AuthConn = fileObject;
  2609. }
  2610. }
  2611. if (NT_SUCCESS(Status)) {
  2612. //
  2613. // We have a new tree connect. Lets try to cache it for later
  2614. // use. Note that the Pkt could have changed when we went out
  2615. // over the net to establish the tree connect, so we cache
  2616. // the tree connect only if the Pkt hasn't changed.
  2617. //
  2618. PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
  2619. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  2620. if (DnrContext->USN == DnrContext->pPktEntry->USN) {
  2621. if (pService->pMachEntry->AuthConn == NULL) {
  2622. pService->pMachEntry->AuthConn = DnrContext->AuthConn;
  2623. DFS_REFERENCE_OBJECT( pService->pMachEntry->AuthConn );
  2624. pService->pMachEntry->Credentials =
  2625. DnrContext->Credentials;
  2626. pService->pMachEntry->Credentials->RefCount++;
  2627. }
  2628. }
  2629. ExReleaseResourceLite( &DfsData.Resource );
  2630. DnrContext->ReleasePkt = FALSE;
  2631. PktRelease();
  2632. }
  2633. ExFreePool( shareName.Buffer );
  2634. } else {
  2635. Status = STATUS_INSUFFICIENT_RESOURCES;
  2636. }
  2637. }
  2638. DfsDbgTrace(-1, Dbg,
  2639. "DnrGetAuthenticatedConnection: Exit %08lx\n", ULongToPtr(Status) );
  2640. #if DBG
  2641. if (MupVerbose) {
  2642. KeQuerySystemTime(&EndTime);
  2643. DbgPrint(" [%d] DnrGetAuthenticatedConnection exit 0x%x\n",
  2644. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)),
  2645. Status);
  2646. }
  2647. #endif
  2648. return( Status );
  2649. }
  2650. //+----------------------------------------------------------------------------
  2651. //
  2652. // Function: DnrReleaseAuthenticatedConnection
  2653. //
  2654. // Synopsis: Dereferences the authenticated connection we used during
  2655. // Dnr.
  2656. //
  2657. // Arguments: [DnrContext] -- The DNR_CONTEXT record for this Dnr
  2658. //
  2659. // Returns: Nothing
  2660. //
  2661. //-----------------------------------------------------------------------------
  2662. VOID
  2663. DnrReleaseAuthenticatedConnection(
  2664. IN PDNR_CONTEXT DnrContext)
  2665. {
  2666. if (DnrContext->AuthConn != NULL) {
  2667. DFS_DEREFERENCE_OBJECT( DnrContext->AuthConn );
  2668. DnrContext->AuthConn = NULL;
  2669. }
  2670. }
  2671. //+----------------------------------------------------------------------------
  2672. //
  2673. // Function: DfsBuildConnectionRequest
  2674. //
  2675. // Synopsis: Builds the file names necessary to setup an
  2676. // authenticated connection to a server's IPC$ share.
  2677. //
  2678. // Arguments: [pService] -- Pointer to DFS_SERVICE describing server
  2679. // [pProvider] -- Pointer to PROVIDER_DEF describing the
  2680. // provider to use to establish the connection.
  2681. // [pShareName] -- Share name to open.
  2682. //
  2683. // Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
  2684. //
  2685. //-----------------------------------------------------------------------------
  2686. NTSTATUS
  2687. DfsBuildConnectionRequest(
  2688. IN PDFS_SERVICE pService,
  2689. IN PPROVIDER_DEF pProvider,
  2690. OUT PUNICODE_STRING pShareName)
  2691. {
  2692. ASSERT(pService != NULL);
  2693. ASSERT(pProvider != NULL);
  2694. RtlInitUnicodeString(pShareName, NULL);
  2695. pShareName->Length = 0;
  2696. pShareName->MaximumLength = pProvider->DeviceName.Length +
  2697. sizeof(UNICODE_PATH_SEP_STR) +
  2698. pService->Name.Length +
  2699. sizeof(ROOT_SHARE_NAME);
  2700. pShareName->Buffer = ExAllocatePoolWithTag(PagedPool, pShareName->MaximumLength, ' puM');
  2701. if (pShareName->Buffer == NULL) {
  2702. DfsDbgTrace(0, Dbg, "Unable to allocate pool for share name!\n", 0);
  2703. pShareName->Length = pShareName->MaximumLength = 0;
  2704. return( STATUS_INSUFFICIENT_RESOURCES );
  2705. }
  2706. RtlAppendUnicodeStringToString( pShareName, &pProvider->DeviceName );
  2707. RtlAppendUnicodeToString( pShareName, UNICODE_PATH_SEP_STR );
  2708. RtlAppendUnicodeStringToString( pShareName, &pService->Name );
  2709. RtlAppendUnicodeToString( pShareName, ROOT_SHARE_NAME );
  2710. return( STATUS_SUCCESS );
  2711. }
  2712. //+----------------------------------------------------------------------------
  2713. //
  2714. // Function: DfsFreeConnectionRequest
  2715. //
  2716. // Synopsis: Frees up the stuff allocated on a successful call to
  2717. // DfsBuildConnectionRequest
  2718. //
  2719. // Arguments: [pShareName] -- Unicode string holding share name.
  2720. //
  2721. // Returns: Nothing
  2722. //
  2723. //-----------------------------------------------------------------------------
  2724. VOID
  2725. DfsFreeConnectionRequest(
  2726. IN OUT PUNICODE_STRING pShareName)
  2727. {
  2728. if (pShareName->Buffer != NULL) {
  2729. ExFreePool ( pShareName->Buffer );
  2730. }
  2731. }
  2732. //+-------------------------------------------------------------------------
  2733. //
  2734. // Function: DfsCreateConnection -- Create a connection to a server
  2735. //
  2736. // Synopsis: DfsCreateConnection will attempt to create a connection
  2737. // to some server's IPC$ share.
  2738. //
  2739. // Arguments: [pService] -- the Service entry, giving the server principal
  2740. // name
  2741. // [pProvider] --
  2742. //
  2743. // [CSCAgentCreate] -- TRUE if this is on behalf of CSC agent
  2744. //
  2745. // [remoteHandle] -- This is where the handle is returned.
  2746. //
  2747. // Returns: NTSTATUS - the status of the operation
  2748. //
  2749. // Notes: The Pkt must be acquired shared before calling this! It will
  2750. // be released and reacquired in this routine.
  2751. //
  2752. //--------------------------------------------------------------------------
  2753. NTSTATUS
  2754. DfsCreateConnection(
  2755. IN PDFS_SERVICE pService,
  2756. IN PPROVIDER_DEF pProvider,
  2757. IN BOOLEAN CSCAgentCreate,
  2758. OUT PHANDLE remoteHandle
  2759. ) {
  2760. PFILE_FULL_EA_INFORMATION EaBuffer;
  2761. ULONG EaBufferLength;
  2762. OBJECT_ATTRIBUTES ObjectAttributes;
  2763. IO_STATUS_BLOCK IoStatusBlock;
  2764. UNICODE_STRING ShareName;
  2765. NTSTATUS Status;
  2766. BOOLEAN pktLocked;
  2767. ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
  2768. ASSERT(pService != NULL);
  2769. ASSERT(pProvider != NULL);
  2770. Status = DfsBuildConnectionRequest(
  2771. pService,
  2772. pProvider,
  2773. &ShareName);
  2774. if (!NT_SUCCESS(Status)) {
  2775. return( Status );
  2776. }
  2777. InitializeObjectAttributes(
  2778. &ObjectAttributes,
  2779. &ShareName, // File Name
  2780. OBJ_KERNEL_HANDLE, // Attributes
  2781. NULL, // Root Directory
  2782. NULL // Security
  2783. );
  2784. //
  2785. // Create or open a connection to the server.
  2786. //
  2787. PktRelease();
  2788. if (CSCAgentCreate) {
  2789. EaBuffer = DfsData.CSCEaBuffer;
  2790. EaBufferLength = DfsData.CSCEaBufferLength;
  2791. } else {
  2792. EaBuffer = NULL;
  2793. EaBufferLength = 0;
  2794. }
  2795. Status = ZwCreateFile(
  2796. remoteHandle,
  2797. SYNCHRONIZE,
  2798. &ObjectAttributes,
  2799. &IoStatusBlock,
  2800. NULL,
  2801. FILE_ATTRIBUTE_NORMAL,
  2802. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2803. FILE_OPEN_IF,
  2804. FILE_SYNCHRONOUS_IO_NONALERT,
  2805. EaBuffer,
  2806. EaBufferLength);
  2807. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCreateConnection_Error_ZwCreateFile,
  2808. LOGSTATUS(Status));
  2809. PktAcquireShared( TRUE, &pktLocked );
  2810. if ( NT_SUCCESS( Status ) ) {
  2811. DfsDbgTrace(0, Dbg, "Created Connection Successfully\n", 0);
  2812. Status = IoStatusBlock.Status;
  2813. }
  2814. DfsFreeConnectionRequest( &ShareName );
  2815. return Status;
  2816. }
  2817. //+-------------------------------------------------------------------------
  2818. //
  2819. // Function: DfsCloseConnection -- Close a connection to a server
  2820. //
  2821. // Synopsis: DfsCloseConnection will attempt to Close a connection
  2822. // to some server.
  2823. //
  2824. // Effects: The file object referring to the the connection will be
  2825. // closed.
  2826. //
  2827. // Arguments: [pService] - the Service entry, giving the server connection
  2828. // handle
  2829. //
  2830. // Returns: NTSTATUS - the status of the operation
  2831. //
  2832. // History: 28 May 1992 Alanw Created
  2833. //
  2834. //--------------------------------------------------------------------------
  2835. NTSTATUS
  2836. DfsCloseConnection(
  2837. IN PDFS_SERVICE pService
  2838. )
  2839. {
  2840. ASSERT( pService->ConnFile != NULL );
  2841. ObDereferenceObject(pService->ConnFile);
  2842. pService->ConnFile = NULL;
  2843. InterlockedDecrement(&pService->pMachEntry->ConnectionCount);
  2844. return STATUS_SUCCESS;
  2845. }
  2846. //+----------------------------------------------------------------------------
  2847. //
  2848. // Function: DnrBuildReferralRequest
  2849. //
  2850. // Synopsis: This routine builds all the necessary things to send
  2851. // a referral request to a DC.
  2852. //
  2853. // Arguments: [pDnrContext] -- The context for building the referral.
  2854. //
  2855. // Returns: Pointer to an IRP that can be used to get a referral.
  2856. //
  2857. //-----------------------------------------------------------------------------
  2858. PIRP
  2859. DnrBuildReferralRequest(
  2860. IN PDNR_CONTEXT DnrContext)
  2861. {
  2862. PUCHAR pNameResBuf = NULL;
  2863. PREQ_GET_DFS_REFERRAL pRef;
  2864. PWCHAR ReferralPath;
  2865. PPROVIDER_DEF pProvider;
  2866. PIRP pIrp = NULL;
  2867. ULONG cbBuffer = 0;
  2868. NTSTATUS Status;
  2869. DfsDbgTrace(+1,Dbg, "DnrBuildReferralRequest Entered - DnrContext %08lx\n", DnrContext);
  2870. cbBuffer = DnrContext->FileName.Length + sizeof(UNICODE_NULL) + sizeof(PREQ_GET_DFS_REFERRAL);
  2871. if (DnrContext->ReferralSize > cbBuffer) {
  2872. cbBuffer = DnrContext->ReferralSize;
  2873. }
  2874. else {
  2875. DnrContext->ReferralSize = cbBuffer;
  2876. }
  2877. DfsDbgTrace(0, Dbg, "Referral Size = %d bytes\n", ULongToPtr(cbBuffer));
  2878. pNameResBuf = ExAllocatePoolWithTag(NonPagedPool, cbBuffer, ' puM');
  2879. if (pNameResBuf == NULL) {
  2880. DfsDbgTrace(-1, Dbg, "Unable to allocate %d bytes\n", ULongToPtr(cbBuffer));
  2881. return( NULL );
  2882. }
  2883. pRef = (PREQ_GET_DFS_REFERRAL) pNameResBuf;
  2884. pRef->MaxReferralLevel = 3;
  2885. ReferralPath = (PWCHAR) &pRef->RequestFileName[0];
  2886. RtlMoveMemory(
  2887. ReferralPath,
  2888. DnrContext->FileName.Buffer,
  2889. DnrContext->FileName.Length);
  2890. ReferralPath[ DnrContext->FileName.Length/sizeof(WCHAR) ] = UNICODE_NULL;
  2891. ASSERT( DnrContext->DCConnFile != NULL);
  2892. #if DBG
  2893. if (MupVerbose)
  2894. DbgPrint(" DnrBuildReferrlRequest:ReferralPath=[%ws]\n", ReferralPath);
  2895. #endif
  2896. Status = DnrGetTargetInfo( DnrContext );
  2897. if (Status == STATUS_SUCCESS)
  2898. {
  2899. pIrp = DnrBuildFsControlRequest( DnrContext->DCConnFile,
  2900. DnrContext,
  2901. FSCTL_DFS_GET_REFERRALS,
  2902. pNameResBuf,
  2903. FIELD_OFFSET(REQ_GET_DFS_REFERRAL, RequestFileName) +
  2904. (wcslen(ReferralPath) + 1) * sizeof(WCHAR),
  2905. pNameResBuf,
  2906. cbBuffer,
  2907. DnrCompleteReferral );
  2908. if (pIrp == NULL) {
  2909. DfsDbgTrace(-1, Dbg, "DnrBuildReferralRequest: Unable to allocate Irp!\n", 0);
  2910. ExFreePool(pNameResBuf);
  2911. } else {
  2912. DfsDbgTrace(-1, Dbg, "DnrBuildReferralRequest: returning %08lx\n", pIrp);
  2913. }
  2914. }
  2915. return( pIrp );
  2916. }
  2917. //+----------------------------------------------------------------------------
  2918. //
  2919. // Function: DnrInsertReferralAndResume
  2920. //
  2921. // Synopsis: This routine is queued as a work item from DnrComplete
  2922. // referral and does the work of actually inserting the
  2923. // referral and resuming DNR. We must not do this work
  2924. // directly in DnrCompleteReferral because it operates at
  2925. // raised IRQL.
  2926. //
  2927. // Arguments:
  2928. //
  2929. // Returns:
  2930. //
  2931. //-----------------------------------------------------------------------------
  2932. VOID
  2933. DnrInsertReferralAndResume(
  2934. IN PVOID Context)
  2935. {
  2936. PIRP_CONTEXT pIrpContext = (PIRP_CONTEXT) Context;
  2937. PDNR_CONTEXT DnrContext = (PDNR_CONTEXT) pIrpContext->Context;
  2938. PIRP Irp = pIrpContext->OriginatingIrp;
  2939. PRESP_GET_DFS_REFERRAL pRefResponse;
  2940. ULONG length, matchingLength;
  2941. NTSTATUS status;
  2942. LARGE_INTEGER EndTime;
  2943. ULONG referralType = 0;
  2944. NTSTATUS DiscardStatus;
  2945. DfsDbgTrace(+1, Dbg, "DnrInsertReferralAndResume: Entered\n", 0);
  2946. DfsDbgTrace(0, Dbg, "Irp = %x\n", Irp );
  2947. DfsDbgTrace(0, Dbg, "Context = %x\n", Context);
  2948. ASSERT(DnrContext->State == DnrStateCompleteReferral);
  2949. status = Irp->IoStatus.Status;
  2950. length = (ULONG)Irp->IoStatus.Information;
  2951. DfsDbgTrace(0, Dbg, "Irp->Status = %x\n", ULongToPtr(status) );
  2952. DfsDbgTrace(0, Dbg, "Irp->Length = %x\n", ULongToPtr(length) );
  2953. KeQuerySystemTime(&EndTime);
  2954. #if DBG
  2955. if (MupVerbose)
  2956. DbgPrint(" [%d] DnrInsertReferralAndResume entered for [%wZ] status = 0x%x\n",
  2957. (ULONG)((EndTime.QuadPart - DnrContext->StartTime.QuadPart)/(10 * 1000)),
  2958. &DnrContext->FileName,
  2959. status);
  2960. #endif
  2961. //
  2962. // If the DC returned STATUS_BUFFER_OVERFLOW, the referral didn't fit in
  2963. // the buffer we sent. Increase the buffer and retry the referral request
  2964. // Since we are going to retry the request, we won't dereference the
  2965. // provider's device object yet.
  2966. //
  2967. if (status == STATUS_BUFFER_OVERFLOW) {
  2968. PULONG pcbSize;
  2969. if (DnrContext->ReferralSize < MAX_REFERRAL_MAX) {
  2970. DfsDbgTrace(0, Dbg, "Referral buffer was too small; retrying...\n", 0);
  2971. DnrContext->ReferralSize = MAX_REFERRAL_MAX;
  2972. DnrContext->State = DnrStateGetReferrals;
  2973. //
  2974. // Going back into Dnr. Reacquire the Pkt shared, and release the
  2975. // PktReferralRequests semaphore, so we can go out again to get a
  2976. // referral.
  2977. //
  2978. goto Cleanup;
  2979. }
  2980. }
  2981. //
  2982. // If we got an error and we were using a cached IPC$ connection,
  2983. // close the cached IPC$ and retry the referral request.
  2984. //
  2985. if ( (DnrContext->CachedConnFile == TRUE) &&
  2986. (status != STATUS_SUCCESS) ) {
  2987. PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
  2988. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  2989. DnrContext->CachedConnFile = FALSE;
  2990. if (DnrContext->pService->ConnFile != NULL) {
  2991. DfsCloseConnection(DnrContext->pService);
  2992. }
  2993. DnrContext->State = DnrStateGetReferrals;
  2994. ExReleaseResourceLite( &DfsData.Resource );
  2995. PktConvertExclusiveToShared();
  2996. //
  2997. // Going back into Dnr. Reacquire the Pkt shared, and release the
  2998. // PktReferralRequests semaphore, so we can go out again to get a
  2999. // referral.
  3000. //
  3001. goto Cleanup;
  3002. }
  3003. //
  3004. // The referral request has terminated. Since we are done with the
  3005. // provider, dereference its device object now.
  3006. //
  3007. DFS_DEREFERENCE_OBJECT(DnrContext->TargetDevice);
  3008. //
  3009. // Next, handle the result of the Referral request. If we successfully
  3010. // got a referral, then try to insert it into our Pkt.
  3011. //
  3012. if (NT_SUCCESS(status) && length != 0) {
  3013. pRefResponse = (PRESP_GET_DFS_REFERRAL) Irp->AssociatedIrp.SystemBuffer;
  3014. DfsDbgTrace(0, Dbg, "Irp->Buffer = %x\n", pRefResponse );
  3015. PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
  3016. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  3017. status = PktCreateEntryFromReferral(
  3018. &DfsData.Pkt,
  3019. &DnrContext->FileName,
  3020. length,
  3021. pRefResponse,
  3022. PKT_ENTRY_SUPERSEDE,
  3023. DnrContext->pNewTargetInfo,
  3024. &matchingLength,
  3025. &referralType,
  3026. &DnrContext->pPktEntry);
  3027. DNR_SET_TARGET_INFO( DnrContext, DnrContext->pPktEntry );
  3028. if (status == STATUS_INVALID_USER_BUFFER) {
  3029. status = STATUS_BAD_NETWORK_NAME;
  3030. }
  3031. if (NT_SUCCESS(status) && DfsEventLog > 1) {
  3032. UNICODE_STRING puStr[2];
  3033. puStr[0] = DnrContext->FileName;
  3034. puStr[1] = DnrContext->pService->Name;
  3035. LogWriteMessage(DFS_REFERRAL_SUCCESS, status, 2, puStr);
  3036. }
  3037. if (NT_SUCCESS(status)) {
  3038. UNICODE_STRING fileName;
  3039. UNICODE_STRING RemPath;
  3040. PDFS_PKT_ENTRY pEntry = NULL;
  3041. PDFS_PKT_ENTRY pShortPfxEntry = NULL;
  3042. PDFS_PKT Pkt;
  3043. //
  3044. // See if we have to remove an entry
  3045. //
  3046. pEntry = PktLookupEntryByPrefix(
  3047. &DfsData.Pkt,
  3048. &DnrContext->FileName,
  3049. &RemPath);
  3050. pShortPfxEntry = PktLookupEntryByShortPrefix(
  3051. &DfsData.Pkt,
  3052. &DnrContext->FileName,
  3053. &RemPath);
  3054. if (pShortPfxEntry != NULL) {
  3055. if ((pEntry == NULL) ||
  3056. (pShortPfxEntry->Id.Prefix.Length > pEntry->Id.Prefix.Length)) {
  3057. pEntry = pShortPfxEntry;
  3058. }
  3059. }
  3060. if (pEntry != NULL && pEntry != DnrContext->pPktEntry) {
  3061. #if DBG
  3062. if (MupVerbose)
  3063. DbgPrint(" DnrInsertReferralAndResume: Need to remove pEntry [%wZ]\n",
  3064. &pEntry->Id.Prefix);
  3065. #endif
  3066. Pkt = _GetPkt();
  3067. if ((pEntry->Type & PKT_ENTRY_TYPE_PERMANENT) == 0) {
  3068. PktFlushChildren(pEntry);
  3069. if (pEntry->UseCount == 0) {
  3070. PktEntryDestroy(pEntry, Pkt, (BOOLEAN) TRUE);
  3071. } else {
  3072. pEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING;
  3073. pEntry->ExpireTime = 0;
  3074. DiscardStatus = DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(pEntry->Id.Prefix));
  3075. DiscardStatus = DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(pEntry->Id.ShortPrefix));
  3076. }
  3077. }
  3078. }
  3079. //
  3080. // At this point, we are essentially in the same state as we were
  3081. // when we started DNR, except that we have one more Pkt entry to
  3082. // match against. Continue with name resolution, after fixing up
  3083. // DnrContext->RemainingPart to reflect the match with the new
  3084. // PktEntry.
  3085. //
  3086. fileName = DnrContext->FileName;
  3087. DnrContext->RemainingPart.Length =
  3088. (USHORT) (fileName.Length - matchingLength);
  3089. DnrContext->RemainingPart.MaximumLength =
  3090. (USHORT) (fileName.MaximumLength - matchingLength);
  3091. DnrContext->RemainingPart.Buffer =
  3092. &fileName.Buffer[ matchingLength/sizeof(WCHAR) ];
  3093. DnrContext->GotReferral = TRUE;
  3094. DnrContext->State = DnrStateStart;
  3095. } else {
  3096. DnrContext->FinalStatus = status;
  3097. DnrContext->State = DnrStateDone;
  3098. }
  3099. PktConvertExclusiveToShared();
  3100. } else if (status == STATUS_NO_SUCH_DEVICE) {
  3101. UNICODE_STRING RemPath;
  3102. PDFS_PKT_ENTRY pEntry = NULL;
  3103. PDFS_PKT Pkt;
  3104. BOOLEAN pktLocked;
  3105. //
  3106. // Check if there is a pkt entry (probably stale) that needs to be removed
  3107. //
  3108. #if DBG
  3109. if (MupVerbose)
  3110. DbgPrint(" DnrInsertReferralAndResume: remove PKT entry for \\%wZ\n",
  3111. &DnrContext->FileName);
  3112. #endif
  3113. PktAcquireExclusive( TRUE, &DnrContext->ReleasePkt );
  3114. Pkt = _GetPkt();
  3115. #if DBG
  3116. if (MupVerbose)
  3117. DbgPrint(" Looking up %wZ\n", &DnrContext->FileName);
  3118. #endif
  3119. pEntry = PktLookupEntryByPrefix(
  3120. &DfsData.Pkt,
  3121. &DnrContext->FileName,
  3122. &RemPath);
  3123. #if DBG
  3124. if (MupVerbose)
  3125. DbgPrint(" pEntry=0x%x\n", pEntry);
  3126. #endif
  3127. if (pEntry != NULL && (pEntry->Type & PKT_ENTRY_TYPE_PERMANENT) == 0) {
  3128. PktFlushChildren(pEntry);
  3129. if (pEntry->UseCount == 0) {
  3130. PktEntryDestroy(pEntry, Pkt, (BOOLEAN) TRUE);
  3131. } else {
  3132. pEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING;
  3133. pEntry->ExpireTime = 0;
  3134. DiscardStatus = DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(pEntry->Id.Prefix));
  3135. DiscardStatus = DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(pEntry->Id.ShortPrefix));
  3136. }
  3137. }
  3138. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  3139. DnrContext->FinalStatus = status;
  3140. DnrContext->State = DnrStateDone;
  3141. PktConvertExclusiveToShared();
  3142. } else if (ReplIsRecoverableError(status)) {
  3143. DnrContext->State = DnrStateGetNextDC;
  3144. } else if (status == STATUS_BUFFER_OVERFLOW) {
  3145. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  3146. DnrContext->FinalStatus = status;
  3147. DnrContext->State = DnrStateDone;
  3148. } else if (DnrContext->Attempts > 0) {
  3149. #if DBG
  3150. if (MupVerbose)
  3151. DbgPrint(" DnrInsertReferralAndResume restarting Attempts = %d\n",
  3152. DnrContext->Attempts);
  3153. #endif
  3154. DnrContext->State = DnrStateStart;
  3155. } else {
  3156. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  3157. DnrContext->FinalStatus = status;
  3158. DnrContext->State = DnrStateDone;
  3159. }
  3160. if ( !NT_SUCCESS(status) && DfsEventLog > 0) {
  3161. UNICODE_STRING puStr[2];
  3162. if (!DnrContext->ReleasePkt)
  3163. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  3164. if (DnrContext->USN == DnrContext->pPktEntry->USN) {
  3165. puStr[0] = DnrContext->FileName;
  3166. puStr[1] = DnrContext->pService->Name;
  3167. LogWriteMessage(DFS_REFERRAL_FAILURE, status, 2, puStr);
  3168. }
  3169. }
  3170. Cleanup:
  3171. //
  3172. // Cleanup referral stuff.
  3173. //
  3174. if (Irp->UserBuffer && Irp->UserBuffer != Irp->AssociatedIrp.SystemBuffer)
  3175. ExFreePool( Irp->UserBuffer );
  3176. if (Irp->AssociatedIrp.SystemBuffer) {
  3177. ExFreePool( Irp->AssociatedIrp.SystemBuffer );
  3178. }
  3179. IoFreeIrp(Irp);
  3180. PktReleaseTargetInfo( DnrContext->pNewTargetInfo );
  3181. DnrContext->pNewTargetInfo = NULL;
  3182. DfsDeleteIrpContext(pIrpContext);
  3183. //
  3184. // We are going back into Dnr, so prepare for that:
  3185. //
  3186. // - Reacquire PKT shared
  3187. // - Release the semaphore for referral requests, so that the next
  3188. // thread can get its referral.
  3189. // - Restart Dnr
  3190. //
  3191. if (!DnrContext->ReleasePkt)
  3192. PktAcquireShared( TRUE, &DnrContext->ReleasePkt );
  3193. ASSERT(DnrContext->ReleasePkt == TRUE);
  3194. #if DBG
  3195. if (MupVerbose)
  3196. DbgPrint(" DnrInsertReferralAndResume next State=%d\n", DnrContext->State);
  3197. #endif
  3198. DnrContext->Impersonate = TRUE;
  3199. DnrContext->DnrActive = FALSE;
  3200. DnrNameResolve(DnrContext);
  3201. PsAssignImpersonationToken(PsGetCurrentThread(),NULL);
  3202. DfsDbgTrace(-1, Dbg, "DnrInsertReferralAndResume: Exit -> %x\n", ULongToPtr(status) );
  3203. }
  3204. //
  3205. // The following two functions are DPC functions which participate
  3206. // in the Distributed Name Resolution process. Each takes a
  3207. // PDNR_CONTEXT as input, transitions the state of the
  3208. // name resolution and any associated data structures, and
  3209. // invokes the next step of the process.
  3210. //
  3211. //+-------------------------------------------------------------------
  3212. //
  3213. // Function: DnrCompleteReferral, local
  3214. //
  3215. // Synopsis: This is the completion routine for processing a referral
  3216. // response. Cleanup the IRP and continue processing the name
  3217. // resolution request.
  3218. //
  3219. // Arguments: [pDevice] -- Pointer to target device object for
  3220. // the request.
  3221. // [Irp] -- Pointer to I/O request packet
  3222. // [Context] -- Caller-specified context parameter associated
  3223. // with IRP. This is actually a pointer to a DNR
  3224. // Context block.
  3225. //
  3226. // Returns: [STATUS_MORE_PROCESSING_REQUIRED] -- The referral Irp was
  3227. // constructed by Dnr and will be freed by us. So, we
  3228. // don't want the IO Subsystem to touch the Irp anymore.
  3229. //
  3230. // Notes: This routine executes at DPC level. We should do an absolutely
  3231. // minimum amount of work here.
  3232. //
  3233. //--------------------------------------------------------------------
  3234. NTSTATUS
  3235. DnrCompleteReferral(
  3236. IN PDEVICE_OBJECT pDevice,
  3237. IN PIRP Irp,
  3238. IN PVOID Context
  3239. ) {
  3240. PIRP_CONTEXT pIrpContext = NULL;
  3241. PDNR_CONTEXT DnrContext = (PDNR_CONTEXT) Context;
  3242. DfsDbgTrace(+1, Dbg, "DnrCompleteReferral: Entered\n", 0);
  3243. DfsDbgTrace(0, Dbg, "Irp = %x\n", Irp);
  3244. DfsDbgTrace(0, Dbg, "Context = %x\n", Context);
  3245. //
  3246. // Derefernce the file object over which we sent the referral request
  3247. //
  3248. DFS_DEREFERENCE_OBJECT( DnrContext->DCConnFile );
  3249. DnrContext->DCConnFile = NULL;
  3250. //
  3251. // Release the semaphore controlling number of referral requests
  3252. //
  3253. KeReleaseSemaphore(
  3254. &DfsData.PktReferralRequests,
  3255. 0, // Priority boost
  3256. 1, // Increment semaphore amount
  3257. FALSE); // Won't call wait immediately
  3258. try {
  3259. pIrpContext = DfsCreateIrpContext(Irp, TRUE);
  3260. if (pIrpContext == NULL)
  3261. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  3262. pIrpContext->Context = DnrContext;
  3263. ExInitializeWorkItem(
  3264. &pIrpContext->WorkQueueItem,
  3265. DnrInsertReferralAndResume,
  3266. pIrpContext);
  3267. ExQueueWorkItem( &pIrpContext->WorkQueueItem, CriticalWorkQueue );
  3268. } except(DfsExceptionFilter(pIrpContext, GetExceptionCode(), GetExceptionInformation())) {
  3269. //
  3270. // Ok, we can't queue the work item and complete Dnr. So, we have
  3271. // to do two things. First of all, clean up the current Irp (ie,
  3272. // the Referral Irp), then complete the original Dnr Irp
  3273. //
  3274. //
  3275. // Cleanup referral stuff.
  3276. //
  3277. if (Irp->UserBuffer && Irp->UserBuffer != Irp->AssociatedIrp.SystemBuffer)
  3278. ExFreePool( Irp->UserBuffer );
  3279. if (Irp->AssociatedIrp.SystemBuffer) {
  3280. ExFreePool( Irp->AssociatedIrp.SystemBuffer );
  3281. }
  3282. IoFreeIrp(Irp);
  3283. PktReleaseTargetInfo( DnrContext->pNewTargetInfo );
  3284. DnrContext->pNewTargetInfo = NULL;
  3285. if (pIrpContext) {
  3286. //
  3287. // Maybe this should be an assert that pIrpContext == NULL. If
  3288. // it is not NULL, then the Irp context was allocated, so who
  3289. // threw an exception anyway?
  3290. //
  3291. DfsDeleteIrpContext(pIrpContext);
  3292. }
  3293. //
  3294. // Now, call Dnr to complete the original Irp
  3295. //
  3296. InterlockedDecrement(&DnrContext->pPktEntry->UseCount);
  3297. DnrContext->DnrActive = FALSE;
  3298. DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  3299. DnrContext->State = DnrStateDone;
  3300. DnrNameResolve(DnrContext);
  3301. PsAssignImpersonationToken(PsGetCurrentThread(),NULL);
  3302. }
  3303. //
  3304. // Return more processing required to the IO system so that it
  3305. // doesn't attempt further processing on the IRP. The IRP will be
  3306. // freed by DnrInsertReferralAndResume, or has already been freed
  3307. // if we couldn't queue up DnrInsertReferralAndResume
  3308. //
  3309. DfsDbgTrace(-1, Dbg, "DnrCompleteReferral: Exit -> %x\n",
  3310. ULongToPtr(STATUS_MORE_PROCESSING_REQUIRED) );
  3311. UNREFERENCED_PARAMETER(pDevice);
  3312. return STATUS_MORE_PROCESSING_REQUIRED;
  3313. }
  3314. //+-------------------------------------------------------------------
  3315. //
  3316. // Function: DnrCompleteFileOpen, local
  3317. //
  3318. // Synopsis: This is the completion routine for processing a file open
  3319. // request. Cleanup the IRP and continue processing the name
  3320. // resolution request.
  3321. //
  3322. // Arguments: [pDevice] -- Pointer to target device object for
  3323. // the request.
  3324. // [Irp] -- Pointer to I/O request packet
  3325. // [Context] -- Caller-specified context parameter associated
  3326. // with IRP. This is actually a pointer to a DNR
  3327. // Context block.
  3328. //
  3329. // Returns: [STATUS_MORE_PROCESSING_REQUIRED] -- We still have to finish
  3330. // the DNR, so we halt further completion of this Irp
  3331. // by returning STATUS_MORE_PROCESSING_REQUIRED.
  3332. //
  3333. //--------------------------------------------------------------------
  3334. NTSTATUS
  3335. DnrCompleteFileOpen(
  3336. IN PDEVICE_OBJECT pDevice,
  3337. IN PIRP Irp,
  3338. IN PVOID Context
  3339. ) {
  3340. PDNR_CONTEXT DnrContext;
  3341. NTSTATUS status;
  3342. PFILE_OBJECT FileObject;
  3343. PIO_STACK_LOCATION IrpSp;
  3344. DfsDbgTrace(+1, Dbg, "DnrCompleteFileOpen: Entered\n", 0);
  3345. DfsDbgTrace(0, Dbg, "Irp = %x\n", Irp );
  3346. DfsDbgTrace(0, Dbg, "Context = %x\n", Context);
  3347. DnrContext = Context;
  3348. status = Irp->IoStatus.Status;
  3349. DfsDbgTrace(0, Dbg, "Irp->Status = %x\n", ULongToPtr(status) );
  3350. DnrContext->FinalStatus = status;
  3351. DnrReleaseAuthenticatedConnection( DnrContext );
  3352. DFS_DEREFERENCE_OBJECT( DnrContext->TargetDevice );
  3353. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  3354. FileObject = IrpSp->FileObject;
  3355. //
  3356. // If STATUS_PENDING was initially returned for the IRP, then we need
  3357. // to restart DNR. So, we post a workitem into the FSP, giving it the
  3358. // DnrContext to resume the DNR.
  3359. //
  3360. // If STATUS_PENDING was not returned, then we simply stop the
  3361. // unwinding of the IRP stack by returning STATUS_MORE_PROCESSING_REQUIRED
  3362. // IoCallDriver will eventually return to DnrRedirectFileOpen, which
  3363. // will continue with the DNR.
  3364. //
  3365. if (Irp->PendingReturned) {
  3366. //
  3367. // Schedule a work item to resume DNR
  3368. //
  3369. DnrContext->Impersonate = TRUE;
  3370. DnrContext->DnrActive = FALSE;
  3371. DnrContext->State = DnrStatePostProcessOpen;
  3372. ASSERT(DnrContext->pIrpContext->MajorFunction == IRP_MJ_CREATE);
  3373. DnrContext->pIrpContext->Context = (PVOID) DnrContext;
  3374. //
  3375. // We need to call IpMarkIrpPending so the IoSubsystem will realize
  3376. // that our FSD routine returned STATUS_PENDING. We can't call this
  3377. // from the FSD routine itself because the FSD routine doesn't have
  3378. // access to the stack location when the underlying guy returns
  3379. // STATUS_PENDING
  3380. //
  3381. IoMarkIrpPending( Irp );
  3382. DfsFsdPostRequest(DnrContext->pIrpContext, DnrContext->OriginalIrp);
  3383. }
  3384. //
  3385. // Return more processing required to the IO system so that it
  3386. // stops unwinding the completion routine stack. The DNR that will
  3387. // be resumed will call IoCompleteRequest when appropriate
  3388. // and resume the unwinding of the completion routine stack.
  3389. //
  3390. status = STATUS_MORE_PROCESSING_REQUIRED;
  3391. DfsDbgTrace(-1, Dbg, "DnrCompleteFileOpen: Exit -> %x\n", ULongToPtr(status) );
  3392. UNREFERENCED_PARAMETER(pDevice);
  3393. return status;
  3394. }
  3395. //+-------------------------------------------------------------------
  3396. //
  3397. // Function: DnrBuildFsControlRequest, local
  3398. //
  3399. // Synopsis: This function builds an I/O request packet for a device or
  3400. // file system I/O control request.
  3401. //
  3402. // Arguments: [FileObject] -- Supplies a pointer the file object to which this
  3403. // request is directed. This pointer is copied into the
  3404. // IRP, so that the called driver can find its file-based
  3405. // context. NOTE THAT THIS IS NOT A REFERENCED POINTER.
  3406. // The caller must ensure that the file object is not
  3407. // deleted while the I/O operation is in progress. The
  3408. // server accomplishes this by incrementing a reference
  3409. // count in a local block to account for the I/O; the
  3410. // local block in turn references the file object.
  3411. // [Context] -- Supplies a PVOID value that is passed to the
  3412. // completion routine.
  3413. // [FsControlCode] -- Supplies the control code for the operation.
  3414. // [MainBuffer] -- Supplies the address of the main buffer. This
  3415. // must be a system virtual address, and the buffer must
  3416. // be locked in memory. If ControlCode specifies a method
  3417. // 0 request, the actual length of the buffer must be the
  3418. // greater of InputBufferLength and OutputBufferLength.
  3419. // [InputBufferLength] -- Supplies the length of the input buffer.
  3420. // [AuxiliaryBuffer] -- Supplies the address of the auxiliary
  3421. // buffer. If the control code method is 0, this is a
  3422. // buffered I/O buffer, but the data returned by the
  3423. // called driver in the system buffer is not
  3424. // automatically copied into the auxiliary buffer.
  3425. // Instead, the auxiliary data ends up in MainBuffer.
  3426. // If the caller wishes the data to be in AuxiliaryBuffer,
  3427. // it must copy the data at some point after the
  3428. // completion routine runs.
  3429. // [CompletionRoutine] -- The IO completion routine.
  3430. //
  3431. // Returns: PIRP -- Returns a pointer to the constructed IRP. If the Irp
  3432. // parameter was not NULL on input, the function return value will
  3433. // be the same value (so it is safe to discard the return value in
  3434. // this case). It is the responsibility of the calling program to
  3435. // deallocate the IRP after the I/O request is complete.
  3436. //
  3437. // Notes: should we use IoBuildIoControlRequest instead?
  3438. //
  3439. //--------------------------------------------------------------------
  3440. PIRP
  3441. DnrBuildFsControlRequest (
  3442. IN PFILE_OBJECT FileObject OPTIONAL,
  3443. IN PVOID Context,
  3444. IN ULONG IoControlCode,
  3445. IN PVOID MainBuffer,
  3446. IN ULONG InputBufferLength,
  3447. IN PVOID AuxiliaryBuffer OPTIONAL,
  3448. IN ULONG OutputBufferLength,
  3449. IN PIO_COMPLETION_ROUTINE CompletionRoutine
  3450. ) {
  3451. CLONG method;
  3452. PDEVICE_OBJECT deviceObject;
  3453. PIRP Irp;
  3454. PIO_STACK_LOCATION irpSp;
  3455. const UCHAR MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  3456. ASSERT( MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL );
  3457. //
  3458. // Get the method with which the buffers are being passed.
  3459. //
  3460. method = IoControlCode & 3;
  3461. ASSERT( method == METHOD_BUFFERED );
  3462. //
  3463. // Allocate an IRP. The stack size is one higher
  3464. // than that of the target device, to allow for the caller's
  3465. // completion routine.
  3466. //
  3467. deviceObject = IoGetRelatedDeviceObject( FileObject );
  3468. //
  3469. // Get the address of the target device object.
  3470. //
  3471. Irp = IoAllocateIrp( (CCHAR)(deviceObject->StackSize + 1), FALSE );
  3472. if ( Irp == NULL ) {
  3473. //
  3474. // Unable to allocate an IRP. Inform the caller.
  3475. //
  3476. return NULL;
  3477. }
  3478. Irp->RequestorMode = KernelMode;
  3479. Irp->Tail.Overlay.OriginalFileObject = FileObject;
  3480. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3481. //
  3482. // Get a pointer to the current stack location and fill in the
  3483. // device object pointer.
  3484. //
  3485. IoSetNextIrpStackLocation( Irp );
  3486. irpSp = IoGetCurrentIrpStackLocation( Irp );
  3487. irpSp->DeviceObject = deviceObject;
  3488. //
  3489. // Set up the completion routine.
  3490. //
  3491. IoSetCompletionRoutine(
  3492. Irp,
  3493. CompletionRoutine,
  3494. Context,
  3495. TRUE,
  3496. TRUE,
  3497. TRUE
  3498. );
  3499. //
  3500. // Get a pointer to the next stack location. This one is used to
  3501. // hold the parameters for the device I/O control request.
  3502. //
  3503. irpSp = IoGetNextIrpStackLocation( Irp );
  3504. irpSp->MajorFunction = MajorFunction;
  3505. irpSp->MinorFunction = 0;
  3506. irpSp->FileObject = FileObject;
  3507. irpSp->DeviceObject = deviceObject;
  3508. //
  3509. // Copy the caller's parameters to the service-specific portion of the
  3510. // IRP for those parameters that are the same for all three methods.
  3511. //
  3512. irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
  3513. irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
  3514. irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
  3515. Irp->MdlAddress = NULL;
  3516. Irp->AssociatedIrp.SystemBuffer = MainBuffer;
  3517. Irp->UserBuffer = AuxiliaryBuffer;
  3518. Irp->Flags = (ULONG)IRP_BUFFERED_IO;
  3519. if ( ARGUMENT_PRESENT(AuxiliaryBuffer) ) {
  3520. Irp->Flags |= IRP_INPUT_OPERATION;
  3521. }
  3522. return Irp;
  3523. }
  3524. //+-------------------------------------------------------------------------
  3525. //
  3526. // Function: AllocateDnrContext, public
  3527. //
  3528. // Synopsis: AllocateDnrContext will allocate a DNR_CONTEXT
  3529. // record.
  3530. //
  3531. // Arguments: -none-
  3532. //
  3533. // Returns: PDNR_CONTEXT - a pointer to the allocated DNR_CONTEXT;
  3534. // NULL if not enough memory.
  3535. //
  3536. // Notes: We should investigate allocating this out of the
  3537. // IrpContext Zone if they are similar enough in size.
  3538. //
  3539. //--------------------------------------------------------------------------
  3540. PDNR_CONTEXT
  3541. AllocateDnrContext(
  3542. IN ULONG cbExtra
  3543. ) {
  3544. PDNR_CONTEXT pNRC;
  3545. pNRC = ExAllocatePoolWithTag( NonPagedPool, sizeof (DNR_CONTEXT) + cbExtra, ' puM');
  3546. if (pNRC == NULL) {
  3547. return NULL;
  3548. }
  3549. RtlZeroMemory(pNRC, sizeof (DNR_CONTEXT));
  3550. pNRC->NodeTypeCode = DSFS_NTC_DNR_CONTEXT;
  3551. pNRC->NodeByteSize = sizeof (DNR_CONTEXT);
  3552. return pNRC;
  3553. }
  3554. //+-------------------------------------------------------------------------
  3555. //
  3556. // Function: DnrConcatenateFilePath, public
  3557. //
  3558. // Synopsis: DnrConcatenateFilePath will concatenate two strings
  3559. // representing file path names, assuring that they are
  3560. // separated by a single '\' character.
  3561. //
  3562. // Arguments: [Dest] - a pointer to the destination string
  3563. // [RemainingPath] - the final part of the path name
  3564. // [Length] - the length (in bytes) of RemainingPath
  3565. //
  3566. // Returns: BOOLEAN - TRUE unless Dest is too small to
  3567. // hold the result (assert).
  3568. //
  3569. //--------------------------------------------------------------------------
  3570. BOOLEAN
  3571. DnrConcatenateFilePath (
  3572. IN PUNICODE_STRING Dest,
  3573. IN PWSTR RemainingPath,
  3574. IN USHORT Length
  3575. ) {
  3576. PWSTR OutBuf = (PWSTR)&(((PCHAR)Dest->Buffer)[Dest->Length]);
  3577. ULONG NewLen;
  3578. if (Dest->Length > 0) {
  3579. ASSERT(OutBuf[-1] != UNICODE_NULL);
  3580. }
  3581. if (Length == 0)
  3582. {
  3583. return TRUE;
  3584. }
  3585. if (Dest->Length > 0 && OutBuf[-1] != UNICODE_PATH_SEP) {
  3586. *OutBuf++ = UNICODE_PATH_SEP;
  3587. Dest->Length += sizeof (WCHAR);
  3588. }
  3589. if (Length > 0 && *RemainingPath == UNICODE_PATH_SEP) {
  3590. RemainingPath++;
  3591. Length -= sizeof (WCHAR);
  3592. }
  3593. NewLen = (ULONG)Dest->Length + (ULONG)Length;
  3594. if (NewLen > MAXUSHORT || NewLen > (ULONG)Dest->MaximumLength) {
  3595. return FALSE;
  3596. }
  3597. if (Length > 0) {
  3598. RtlMoveMemory(OutBuf, RemainingPath, Length);
  3599. Dest->Length += Length;
  3600. }
  3601. return TRUE;
  3602. }
  3603. //+----------------------------------------------------------------------------
  3604. //
  3605. // Function: DnrLocateDC, private
  3606. //
  3607. // Synopsis: Tries to create an entry for the Dfs root which will match
  3608. // FileName.
  3609. //
  3610. // Arguments: [FileName] -- File name for which DC/Root is being located.
  3611. //
  3612. // Returns: Nothing.
  3613. //
  3614. //-----------------------------------------------------------------------------
  3615. VOID
  3616. DnrLocateDC(
  3617. IN PUNICODE_STRING FileName)
  3618. {
  3619. BOOLEAN pktLocked;
  3620. NTSTATUS status;
  3621. UNICODE_STRING dfsRoot, dfsShare, remPath;
  3622. UNICODE_STRING RootShareName;
  3623. PDFS_PKT_ENTRY pktEntry;
  3624. PDFS_PKT pkt;
  3625. USHORT i, j;
  3626. ASSERT( FileName->Buffer[0] == UNICODE_PATH_SEP );
  3627. #if DBG
  3628. if (MupVerbose)
  3629. DbgPrint(" DnrLocateDC(%wZ)\n", FileName);
  3630. #endif
  3631. dfsRoot.Length = dfsRoot.MaximumLength = 0;
  3632. dfsRoot.Buffer = &FileName->Buffer[1];
  3633. for (i = 1;
  3634. i < FileName->Length/sizeof(WCHAR) &&
  3635. FileName->Buffer[i] != UNICODE_PATH_SEP;
  3636. i++) {
  3637. NOTHING;
  3638. }
  3639. for (j = i + 1;
  3640. j < FileName->Length/sizeof(WCHAR) &&
  3641. FileName->Buffer[j] != UNICODE_PATH_SEP;
  3642. j++) {
  3643. NOTHING;
  3644. }
  3645. if ((FileName->Buffer[i] == UNICODE_PATH_SEP) && (j > i)) {
  3646. dfsRoot.MaximumLength = dfsRoot.Length = (i - 1) * sizeof(WCHAR);
  3647. dfsShare.MaximumLength = dfsShare.Length = (j - i - 1) * sizeof(WCHAR);
  3648. dfsShare.Buffer = &FileName->Buffer[i+1];
  3649. #if DBG
  3650. if (MupVerbose)
  3651. DbgPrint(" DnrLocateDC dfsRoot=[%wZ] dfsShare=[%wZ]\n",
  3652. &dfsRoot,
  3653. &dfsShare);
  3654. #endif
  3655. status = PktCreateDomainEntry( &dfsRoot, &dfsShare, FALSE );
  3656. if (!NT_SUCCESS(status)) {
  3657. #if DBG
  3658. if (MupVerbose)
  3659. DbgPrint(" DnrLocateDC:PktCreateDomainEntry() returned 0x%x\n", status);
  3660. #endif
  3661. RootShareName.Buffer = FileName->Buffer;
  3662. RootShareName.Length = j * sizeof(WCHAR);
  3663. RootShareName.MaximumLength = FileName->MaximumLength;
  3664. #if DBG
  3665. if (MupVerbose)
  3666. DbgPrint(" DnrLocateDC:RootShareName=[%wZ]\n", &RootShareName);
  3667. #endif
  3668. //
  3669. // Failed getting referral - see if we have a stale one.
  3670. //
  3671. pkt = _GetPkt();
  3672. PktAcquireShared( TRUE, &pktLocked );
  3673. pktEntry = PktLookupEntryByPrefix( pkt, &RootShareName, &remPath );
  3674. if (pktEntry != NULL) {
  3675. #if DBG
  3676. if (MupVerbose)
  3677. DbgPrint(" DnrLocateDC:Found stale pkt entry %08lx - adding 60 sec to it\n",
  3678. pktEntry);
  3679. #endif
  3680. if (pktEntry->ExpireTime <= 0) {
  3681. pktEntry->ExpireTime = 60;
  3682. pktEntry->TimeToLive = 60;
  3683. }
  3684. status = STATUS_SUCCESS;
  3685. }
  3686. PktRelease();
  3687. }
  3688. } else {
  3689. status = STATUS_BAD_NETWORK_PATH;
  3690. }
  3691. #if DBG
  3692. if (MupVerbose)
  3693. DbgPrint(" DnrLocateDC exit 0x%x\n", status);
  3694. #endif
  3695. }
  3696. //+----------------------------------------------------------------------------
  3697. //
  3698. // Function: DnrRebuildDnrContext
  3699. //
  3700. // Synopsis: To handle inter-dfs links, we simply want to change the name
  3701. // of the file we are opening to the name in the new Dfs, and
  3702. // restart DNR afresh.
  3703. //
  3704. // This is most easily done by simply terminating this DNR with
  3705. // STATUS_REPARSE. However, if we do that, we would loose track
  3706. // of the credentials (if any) we originally came in with.
  3707. //
  3708. // Hence, this routine simply rebuilds the DnrContext. After
  3709. // calling this, Dnr starts all over again, just as if
  3710. // DnrNameResolve had been called by DnrStartNameResolution
  3711. //
  3712. //
  3713. // Arguments: [DnrContext] -- The context to rebuild.
  3714. // [NewDfsPrefix] -- The prefix of the Dfs in which the DNR
  3715. // should continue.
  3716. // [RemainingPath] -- Path relative to the NewDfsPrefix.
  3717. //
  3718. // Returns: Nothing.
  3719. //
  3720. //-----------------------------------------------------------------------------
  3721. VOID
  3722. DnrRebuildDnrContext(
  3723. IN PDNR_CONTEXT DnrContext,
  3724. IN PUNICODE_STRING NewDfsPrefix,
  3725. IN PUNICODE_STRING RemainingPath)
  3726. {
  3727. UNICODE_STRING newFileName;
  3728. ULONG newNameLen = 0;
  3729. PIRP Irp = DnrContext->OriginalIrp;
  3730. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  3731. PFILE_OBJECT FileObject = IrpSp->FileObject;
  3732. //
  3733. // Build the new file name
  3734. //
  3735. newFileName.Length = 0;
  3736. newNameLen = NewDfsPrefix->Length +
  3737. sizeof(UNICODE_PATH_SEP) +
  3738. RemainingPath->Length +
  3739. sizeof(UNICODE_NULL);
  3740. if (newNameLen >= MAXUSHORT) {
  3741. DnrContext->FinalStatus = STATUS_NAME_TOO_LONG;
  3742. DnrContext->State = DnrStateDone;
  3743. return;
  3744. }
  3745. newFileName.MaximumLength = (USHORT)newNameLen;
  3746. newFileName.Buffer = (PWCHAR) ExAllocatePoolWithTag(
  3747. NonPagedPool,
  3748. newFileName.MaximumLength,
  3749. ' puM');
  3750. if (newFileName.Buffer != NULL) {
  3751. newFileName.Length = NewDfsPrefix->Length;
  3752. RtlMoveMemory(
  3753. newFileName.Buffer,
  3754. NewDfsPrefix->Buffer,
  3755. newFileName.Length);
  3756. DnrConcatenateFilePath(
  3757. &newFileName,
  3758. RemainingPath->Buffer,
  3759. RemainingPath->Length);
  3760. if (DnrContext->NameAllocated)
  3761. ExFreePool(DnrContext->FileName.Buffer);
  3762. DnrContext->NameAllocated = TRUE;
  3763. DnrContext->FileName = newFileName;
  3764. } else {
  3765. DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  3766. DnrContext->State = DnrStateDone;
  3767. return;
  3768. }
  3769. //
  3770. // Rebuild the FcbToUse because the Fcb has room for the full file name
  3771. // and it might have changed its size.
  3772. //
  3773. ASSERT(DnrContext->FcbToUse != NULL);
  3774. DfsDetachFcb(DnrContext->FcbToUse->FileObject, DnrContext->FcbToUse);
  3775. ExFreePool(DnrContext->FcbToUse);
  3776. DnrContext->FcbToUse = DfsCreateFcb(
  3777. DnrContext->pIrpContext,
  3778. DnrContext->Vcb,
  3779. &DnrContext->ContextFileName);
  3780. if (DnrContext->FcbToUse == NULL) {
  3781. DnrContext->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  3782. DnrContext->State = DnrStateDone;
  3783. return;
  3784. }
  3785. DnrContext->FcbToUse->FileObject = FileObject;
  3786. DfsSetFileObject(FileObject,
  3787. RedirectedFileOpen,
  3788. DnrContext->FcbToUse);
  3789. //
  3790. // Now, whack the rest of the DnrContext. Clean it up so it is essentially
  3791. // zeroed out..
  3792. //
  3793. DnrContext->State = DnrStateStart;
  3794. DnrContext->pPktEntry = NULL;
  3795. DnrContext->USN = 0;
  3796. DnrContext->pService = NULL;
  3797. DnrContext->pProvider = NULL;
  3798. DnrContext->ProviderId = 0;
  3799. DnrContext->TargetDevice = NULL;
  3800. DnrContext->AuthConn = NULL;
  3801. DnrContext->DCConnFile = NULL;
  3802. DnrContext->ReferralSize = MAX_REFERRAL_LENGTH;
  3803. DnrContext->Attempts++;
  3804. DnrContext->GotReferral = FALSE;
  3805. DnrContext->FoundInconsistency = FALSE;
  3806. DnrContext->CalledDCLocator = FALSE;
  3807. DnrContext->CachedConnFile = FALSE;
  3808. DnrContext->DfsNameContext.Flags = 0;
  3809. DnrContext->GotReparse = FALSE;
  3810. }
  3811. //+-------------------------------------------------------------------------
  3812. //
  3813. // Function: DfspGetOfflineEntry -- Checks for a server marked offline.
  3814. //
  3815. // Synopsis: DfspGetOfflineEntry returns an offline entry for the given
  3816. // server, if it exists in our offline database.
  3817. //
  3818. // Arguments: [servername] - Name of the server of interest.
  3819. // DfsData.Resource assumed held on entry.
  3820. //
  3821. // Returns: PLIST_ENTRY: plist_entry of the offline structure.
  3822. //
  3823. //--------------------------------------------------------------------------
  3824. PLIST_ENTRY
  3825. DfspGetOfflineEntry(
  3826. PUNICODE_STRING ServerName)
  3827. {
  3828. PLIST_ENTRY listEntry;
  3829. PDFS_OFFLINE_SERVER server;
  3830. listEntry = DfsData.OfflineRoots.Flink;
  3831. while ( listEntry != &DfsData.OfflineRoots ) {
  3832. server = CONTAINING_RECORD(
  3833. listEntry,
  3834. DFS_OFFLINE_SERVER,
  3835. ListEntry);
  3836. if (RtlCompareUnicodeString(
  3837. &server->LogicalServerName, ServerName, TRUE) == 0) {
  3838. break;
  3839. }
  3840. listEntry = listEntry->Flink;
  3841. }
  3842. if (listEntry == &DfsData.OfflineRoots) {
  3843. listEntry = NULL;
  3844. }
  3845. return listEntry;
  3846. }
  3847. //+-------------------------------------------------------------------------
  3848. //
  3849. // Function: DfspMarkServerOnline -- Marks a server online
  3850. //
  3851. // Synopsis: DfspMarkServerOnline removes the server entry from its offline
  3852. // database, if it was marked as offline earlier.
  3853. //
  3854. // Arguments: [servername] - Name of the server of interest.
  3855. //
  3856. // Returns: NTSTATUS.
  3857. //
  3858. //--------------------------------------------------------------------------
  3859. NTSTATUS
  3860. DfspMarkServerOnline(
  3861. PUNICODE_STRING ServerName)
  3862. {
  3863. PLIST_ENTRY listEntry;
  3864. PDFS_OFFLINE_SERVER server;
  3865. NTSTATUS status;
  3866. UNICODE_STRING dfsRootName;
  3867. ULONG i;
  3868. DfsDbgTrace(+1, Dbg, "DfspMarkServerOnline: %wZ\n", ServerName);
  3869. //
  3870. // Extract server name when there is \server\share
  3871. //
  3872. dfsRootName = *ServerName;
  3873. if (dfsRootName.Buffer[0] == UNICODE_PATH_SEP) {
  3874. for (i = 1;
  3875. i < dfsRootName.Length/sizeof(WCHAR) &&
  3876. dfsRootName.Buffer[i] != UNICODE_PATH_SEP;
  3877. i++) {
  3878. NOTHING;
  3879. }
  3880. dfsRootName.Length = (USHORT) ((i-1) * sizeof(WCHAR));
  3881. dfsRootName.MaximumLength = dfsRootName.Length;
  3882. dfsRootName.Buffer = &ServerName->Buffer[1];
  3883. }
  3884. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  3885. listEntry = DfspGetOfflineEntry(&dfsRootName);
  3886. if (listEntry != NULL) {
  3887. RemoveEntryList(listEntry);
  3888. }
  3889. ExReleaseResourceLite( &DfsData.Resource );
  3890. if (listEntry != NULL) {
  3891. server = CONTAINING_RECORD(
  3892. listEntry,
  3893. DFS_OFFLINE_SERVER,
  3894. ListEntry);
  3895. ExFreePool(server->LogicalServerName.Buffer);
  3896. ExFreePool(server);
  3897. }
  3898. MupInvalidatePrefixTable();
  3899. status = STATUS_SUCCESS;
  3900. DfsDbgTrace(-1, Dbg, "DfspMarkServerOnline: status %x\n", ULongToPtr(status));
  3901. return status;
  3902. }
  3903. //+-------------------------------------------------------------------------
  3904. //
  3905. // Function: DfspMarkServerOffline -- Marks a server offline
  3906. //
  3907. // Synopsis: DfspMarkServerOffline adds the server entry to its offline
  3908. // database.
  3909. //
  3910. // Arguments: [servername] - Name of the server of interest.
  3911. //
  3912. // Returns: NTSTATUS.
  3913. //
  3914. //--------------------------------------------------------------------------
  3915. NTSTATUS
  3916. DfspMarkServerOffline(
  3917. PUNICODE_STRING ServerName)
  3918. {
  3919. UNICODE_STRING NewName;
  3920. PLIST_ENTRY listEntry;
  3921. PDFS_OFFLINE_SERVER server;
  3922. UNICODE_STRING dfsRootName;
  3923. ULONG i;
  3924. DfsDbgTrace(+1, Dbg, "DfspMarkServerOffline: %wZ \n", ServerName);
  3925. server = ExAllocatePoolWithTag( PagedPool, sizeof(DFS_OFFLINE_SERVER), ' puM' );
  3926. if (server == NULL) {
  3927. return STATUS_INSUFFICIENT_RESOURCES;
  3928. }
  3929. //
  3930. // Extract server name when there is \server\share
  3931. //
  3932. dfsRootName = *ServerName;
  3933. if (dfsRootName.Buffer[0] == UNICODE_PATH_SEP) {
  3934. for (i = 1;
  3935. i < dfsRootName.Length/sizeof(WCHAR) &&
  3936. dfsRootName.Buffer[i] != UNICODE_PATH_SEP;
  3937. i++) {
  3938. NOTHING;
  3939. }
  3940. dfsRootName.Length = (USHORT) ((i-1) * sizeof(WCHAR));
  3941. dfsRootName.MaximumLength = dfsRootName.Length;
  3942. dfsRootName.Buffer = &ServerName->Buffer[1];
  3943. }
  3944. NewName.Buffer = ExAllocatePoolWithTag(
  3945. PagedPool,
  3946. dfsRootName.Length + sizeof(WCHAR),
  3947. ' puM' );
  3948. if (NewName.Buffer == NULL) {
  3949. ExFreePool(server);
  3950. return STATUS_INSUFFICIENT_RESOURCES;
  3951. }
  3952. NewName.MaximumLength = dfsRootName.Length + sizeof(WCHAR);
  3953. NewName.Length = 0;
  3954. RtlCopyUnicodeString(&NewName, &dfsRootName);
  3955. server->LogicalServerName = NewName;
  3956. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  3957. listEntry = DfspGetOfflineEntry(&dfsRootName);
  3958. if (listEntry == NULL) {
  3959. InsertTailList( &DfsData.OfflineRoots, &server->ListEntry);
  3960. }
  3961. ExReleaseResourceLite( &DfsData.Resource );
  3962. if (listEntry != NULL) {
  3963. ExFreePool(NewName.Buffer);
  3964. ExFreePool(server);
  3965. }
  3966. DfsDbgTrace(-1, Dbg, "DfspMarkServerOffline exit STATUS_SUCCESS\n", 0);
  3967. return STATUS_SUCCESS;
  3968. }
  3969. //+-------------------------------------------------------------------------
  3970. //
  3971. // Function: DfspIsRootOnline -- Checks if a server is online
  3972. //
  3973. // Synopsis: DfspIsRootOnline checks if the server is marked in its offline
  3974. // database. If not, the server is online.
  3975. //
  3976. // Arguments: [servername] - Name of the server of interest.
  3977. //
  3978. // Returns: NTSTATUS. (Success or STATUS_DEVICE_OFFLINE)
  3979. //
  3980. //--------------------------------------------------------------------------
  3981. NTSTATUS
  3982. DfspIsRootOnline(
  3983. PUNICODE_STRING FileName,
  3984. BOOLEAN CSCAgentCreate)
  3985. {
  3986. NTSTATUS status;
  3987. PLIST_ENTRY listEntry;
  3988. UNICODE_STRING dfsRootName;
  3989. ULONG i;
  3990. DfsDbgTrace(+1, Dbg, "DfspIsRootOnline: %wZ\n", FileName);
  3991. if (CSCAgentCreate == TRUE) {
  3992. DfsDbgTrace(-1, Dbg, "CSCAgent, returning success!\n", 0);
  3993. status = STATUS_SUCCESS;
  3994. }
  3995. else {
  3996. dfsRootName = *FileName;
  3997. if (dfsRootName.Buffer[0] == UNICODE_PATH_SEP) {
  3998. for (i = 1;
  3999. i < dfsRootName.Length/sizeof(WCHAR) &&
  4000. dfsRootName.Buffer[i] != UNICODE_PATH_SEP;
  4001. i++) {
  4002. NOTHING;
  4003. }
  4004. dfsRootName.Length = (USHORT) ((i-1) * sizeof(WCHAR));
  4005. dfsRootName.MaximumLength = dfsRootName.Length;
  4006. dfsRootName.Buffer = &FileName->Buffer[1];
  4007. }
  4008. ExAcquireResourceSharedLite( &DfsData.Resource, TRUE );
  4009. listEntry = DfspGetOfflineEntry(&dfsRootName);
  4010. ExReleaseResourceLite( &DfsData.Resource );
  4011. if (listEntry != NULL) {
  4012. status = STATUS_DEVICE_OFF_LINE;
  4013. }
  4014. else {
  4015. status = STATUS_SUCCESS;
  4016. }
  4017. }
  4018. DfsDbgTrace(-1, Dbg, "DfspIsRootOnline: ret 0x%x\n", ULongToPtr(status) );
  4019. return status;
  4020. }
  4021. #if 0
  4022. NTSTATUS
  4023. DnrGetTargetInfo(
  4024. PDNR_CONTEXT pDnrContext)
  4025. {
  4026. UNICODE_STRING dfsRoot, dfsShare;
  4027. PUNICODE_STRING pFileName = &pDnrContext->FileName;
  4028. USHORT i, j;
  4029. NTSTATUS Status;
  4030. dfsRoot.Length = dfsRoot.MaximumLength = 0;
  4031. dfsRoot.Buffer = &pFileName->Buffer[1];
  4032. for (i = 1;
  4033. i < pFileName->Length/sizeof(WCHAR) &&
  4034. pFileName->Buffer[i] != UNICODE_PATH_SEP;
  4035. i++) {
  4036. NOTHING;
  4037. }
  4038. for (j = i + 1;
  4039. j < pFileName->Length/sizeof(WCHAR) &&
  4040. pFileName->Buffer[j] != UNICODE_PATH_SEP;
  4041. j++) {
  4042. NOTHING;
  4043. }
  4044. if ((pFileName->Buffer[i] == UNICODE_PATH_SEP) && (j > i)) {
  4045. dfsRoot.MaximumLength = dfsRoot.Length = (i - 1) * sizeof(WCHAR);
  4046. dfsShare.MaximumLength = dfsShare.Length = (j - i - 1) * sizeof(WCHAR);
  4047. dfsShare.Buffer = &pFileName->Buffer[i+1];
  4048. Status = PktGetTargetInfo( pDnrContext->DCConnFile,
  4049. &dfsRoot,
  4050. &dfsShare,
  4051. &pDnrContext->pNewTargetInfo );
  4052. }
  4053. else {
  4054. Status = STATUS_BAD_NETWORK_PATH;
  4055. }
  4056. return Status;
  4057. }
  4058. #endif
  4059. NTSTATUS
  4060. DnrGetTargetInfo(
  4061. PDNR_CONTEXT pDnrContext)
  4062. {
  4063. NTSTATUS Status = STATUS_SUCCESS;
  4064. PDFS_PKT_ENTRY pEntry;
  4065. pEntry = pDnrContext->pPktEntry;
  4066. if (pEntry != NULL)
  4067. {
  4068. pDnrContext->pNewTargetInfo = pEntry->pDfsTargetInfo;
  4069. if (pDnrContext->pNewTargetInfo != NULL)
  4070. {
  4071. PktAcquireTargetInfo(pDnrContext->pNewTargetInfo);
  4072. }
  4073. }
  4074. if (pDnrContext->pNewTargetInfo == NULL)
  4075. {
  4076. if (pDnrContext->pDfsTargetInfo != NULL)
  4077. {
  4078. pDnrContext->pNewTargetInfo = pDnrContext->pDfsTargetInfo;
  4079. if (pDnrContext->pNewTargetInfo != NULL)
  4080. {
  4081. PktAcquireTargetInfo(pDnrContext->pNewTargetInfo);
  4082. }
  4083. }
  4084. }
  4085. return Status;
  4086. }