Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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