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.

1651 lines
56 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. RxConnct.c
  5. Abstract:
  6. This module implements the nt version of the high level routines dealing with
  7. connections including both the routines for establishing connections and the
  8. winnet connection apis.
  9. Author:
  10. Joe Linn [JoeLinn] 1-mar-95
  11. Revision History:
  12. Balan Sethu Raman [SethuR] --
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include "prefix.h"
  17. #include "secext.h"
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, RxExtractServerName)
  20. #pragma alloc_text(PAGE, RxFindOrCreateConnections)
  21. #pragma alloc_text(PAGE, RxCreateNetRootCallBack)
  22. #pragma alloc_text(PAGE, RxConstructSrvCall)
  23. #pragma alloc_text(PAGE, RxConstructNetRoot)
  24. #pragma alloc_text(PAGE, RxConstructVirtualNetRoot)
  25. #pragma alloc_text(PAGE, RxFindOrConstructVirtualNetRoot)
  26. #endif
  27. //
  28. // The local trace mask for this part of the module
  29. //
  30. #define Dbg (DEBUG_TRACE_CONNECT)
  31. // Internal helper functions for establishing connections through mini redirectors
  32. VOID
  33. RxCreateNetRootCallBack (
  34. IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
  35. );
  36. VOID
  37. RxCreateSrvCallCallBack (
  38. IN PMRX_SRVCALL_CALLBACK_CONTEXT Context
  39. );
  40. VOID
  41. RxExtractServerName(
  42. IN PUNICODE_STRING FilePathName,
  43. OUT PUNICODE_STRING SrvCallName,
  44. OUT PUNICODE_STRING RestOfName
  45. )
  46. /*++
  47. Routine Description:
  48. This routine parses the input name into srv, netroot, and the
  49. rest. any of the output can be null
  50. Arguments:
  51. FilePathName -- the given file name
  52. xSrvCallName -- the srv call name
  53. xNetRootName -- the net root name
  54. RestOfName -- the remaining portion of the name
  55. --*/
  56. {
  57. ULONG length = FilePathName->Length;
  58. PWCH w = FilePathName->Buffer;
  59. PWCH wlimit = (PWCH)(((PCHAR)w)+length);
  60. PWCH wlow;
  61. UNICODE_STRING xRestOfName;
  62. PAGED_CODE();
  63. ASSERT(SrvCallName);
  64. SrvCallName->Buffer = wlow = w;
  65. for (;;) {
  66. if (w>=wlimit) break;
  67. if ( (*w == OBJ_NAME_PATH_SEPARATOR) && (w!=wlow) ) break;
  68. w++;
  69. }
  70. SrvCallName->Length = SrvCallName->MaximumLength
  71. = (USHORT)((PCHAR)w - (PCHAR)wlow);
  72. if (!RestOfName) RestOfName = &xRestOfName;
  73. RestOfName->Buffer = w;
  74. RestOfName->Length = RestOfName->MaximumLength
  75. = (USHORT)((PCHAR)wlimit - (PCHAR)w);
  76. RxDbgTrace( 0,Dbg,(" RxExtractServerName FilePath=%wZ\n",FilePathName));
  77. RxDbgTrace(0,Dbg,(" Srv=%wZ,Rest=%wZ\n",
  78. SrvCallName,RestOfName));
  79. return;
  80. }
  81. NTSTATUS
  82. RxFindOrCreateConnections (
  83. IN PRX_CONTEXT RxContext,
  84. IN PUNICODE_STRING CanonicalName,
  85. IN NET_ROOT_TYPE NetRootType,
  86. OUT PUNICODE_STRING LocalNetRootName,
  87. OUT PUNICODE_STRING FilePathName,
  88. IN OUT LOCK_HOLDING_STATE *pLockHoldingState,
  89. IN PRX_CONNECTION_ID RxConnectionId
  90. )
  91. /*++
  92. Routine Description:
  93. This routine handles the call down from the MUP to claim a name or from the
  94. create path. If we don't find the name in the netname table, we pass the name
  95. down to the minirdrs to be connected. in the few places where it matters, we use
  96. the majorcode to distinguish between in MUP and create cases. there are a million
  97. cases depending on what we find on the initial lookup.
  98. these are the cases:
  99. found nothing (1)
  100. found intransition srvcall (2)
  101. found stable/nongood srvcall (3)
  102. found good srvcall (4&0)
  103. found good netroot on good srvcall (0)
  104. found intransition netroot on good srvcall (5)
  105. found bad netroot on good srvcall (6)
  106. found good netroot on bad srvcall (3)
  107. found intransition netroot on bad srvcall (3)
  108. found bad netroot on bad srvcall (3)
  109. found good netroot on intransition srvcall (2)
  110. found intransition netroot on intransition srvcall (2)
  111. found bad netroot on intransition srvcall (2)
  112. (x) means that the code to handle that case has a marker
  113. like "case (x)". could be a comment....could be a debugout.
  114. Arguments:
  115. IN PRX_CONTEXT RxContext,
  116. IN PUNICODE_STRING CanonicalName,
  117. IN NET_ROOT_TYPE NetRootType,
  118. OUT PUNICODE_STRING LocalNetRootName,
  119. OUT PUNICODE_STRING FilePathName,
  120. IN OUT PLOCK_HOLDING_STATE LockHoldingState
  121. Return Value:
  122. RXSTATUS
  123. --*/
  124. {
  125. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  126. RxCaptureRequestPacket;
  127. RxCaptureParamBlock;
  128. UNICODE_STRING UnmatchedName;
  129. PVOID Container = NULL;
  130. PSRV_CALL SrvCall = NULL;
  131. PNET_ROOT NetRoot = NULL;
  132. PV_NET_ROOT VNetRoot = NULL;
  133. PRX_PREFIX_TABLE pRxNetNameTable
  134. = RxContext->RxDeviceObject->pRxNetNameTable;
  135. PAGED_CODE();
  136. RxDbgTrace(0, Dbg, ("RxFindOrCreateConnections -> %08lx\n", RxContext));
  137. // Parse the canonical name into the local net root name and file path name
  138. *FilePathName = *CanonicalName;
  139. LocalNetRootName->Length = 0;
  140. LocalNetRootName->MaximumLength = 0;
  141. LocalNetRootName->Buffer = CanonicalName->Buffer;
  142. if (FilePathName->Buffer[1] == L';') {
  143. PWCHAR pFilePathName = &FilePathName->Buffer[2];
  144. BOOLEAN SeparatorFound = FALSE;
  145. ULONG PathLength = 0;
  146. if (FilePathName->Length > sizeof(WCHAR) * 2) {
  147. PathLength = FilePathName->Length - sizeof(WCHAR) * 2;
  148. }
  149. while (PathLength > 0) {
  150. if (*pFilePathName == L'\\') {
  151. SeparatorFound = TRUE;
  152. break;
  153. }
  154. PathLength -= sizeof(WCHAR);
  155. pFilePathName++;
  156. }
  157. if (!SeparatorFound) {
  158. return STATUS_OBJECT_NAME_INVALID;
  159. }
  160. FilePathName->Buffer = pFilePathName;
  161. LocalNetRootName->Length =
  162. (USHORT)((PCHAR)pFilePathName - (PCHAR)CanonicalName->Buffer);
  163. LocalNetRootName->MaximumLength = LocalNetRootName->Length;
  164. FilePathName->Length -= LocalNetRootName->Length;
  165. }
  166. RxDbgTrace( 0, Dbg, ("RxFindOrCreateConnections Path = %wZ\n", FilePathName));
  167. try {
  168. UNICODE_STRING SrvCallName,NetRootName;
  169. RETRY_LOOKUP:
  170. ASSERT(*pLockHoldingState != LHS_LockNotHeld);
  171. if (Container != NULL) {
  172. // This is the subsequent pass of a lookup after waiting for the transition
  173. // to the stable state of a previous lookup.
  174. // Dereference the result of the earlier lookup.
  175. switch (NodeType(Container)) {
  176. case RDBSS_NTC_V_NETROOT:
  177. RxDereferenceVNetRoot((PV_NET_ROOT)Container,*pLockHoldingState);
  178. break;
  179. case RDBSS_NTC_SRVCALL:
  180. RxDereferenceSrvCall((PSRV_CALL)Container,*pLockHoldingState);
  181. break;
  182. case RDBSS_NTC_NETROOT:
  183. RxDereferenceNetRoot((PNET_ROOT)Container,*pLockHoldingState);
  184. break;
  185. default:
  186. DbgPrint("RxFindOrCreateConnections -- Invalid Container Type\n");
  187. break;
  188. }
  189. }
  190. Container = RxPrefixTableLookupName(
  191. pRxNetNameTable,
  192. FilePathName,
  193. &UnmatchedName,
  194. RxConnectionId );
  195. RxLog(("FOrCC1 %x %x %wZ \n",RxContext,Container,FilePathName));
  196. RxWmiLog(LOG,
  197. RxFindOrCreateConnections_1,
  198. LOGPTR(RxContext)
  199. LOGPTR(Container)
  200. LOGUSTR(*FilePathName));
  201. RETRY_AFTER_LOOKUP:
  202. NetRoot = NULL;
  203. SrvCall = NULL;
  204. VNetRoot = NULL;
  205. RxContext->Create.pVNetRoot = NULL;
  206. RxContext->Create.pNetRoot = NULL;
  207. RxContext->Create.pSrvCall = NULL;
  208. RxContext->Create.Type = NetRootType;
  209. if ( Container ) {
  210. if (NodeType(Container) == RDBSS_NTC_V_NETROOT) {
  211. VNetRoot = (PV_NET_ROOT)Container;
  212. NetRoot = (PNET_ROOT)VNetRoot->NetRoot;
  213. SrvCall = (PSRV_CALL)NetRoot->SrvCall;
  214. if (NetRoot->Condition == Condition_InTransition) {
  215. RxReleasePrefixTableLock(pRxNetNameTable);
  216. RxWaitForStableNetRoot(NetRoot,RxContext);
  217. RxAcquirePrefixTableLockExclusive(pRxNetNameTable,TRUE);
  218. *pLockHoldingState = LHS_ExclusiveLockHeld;
  219. //
  220. // Since we had to drop the table lock and reacquire it,
  221. // our NetRoot pointer may be stale. Look it up again before
  222. // using it.
  223. //
  224. // NOTE: The NetRoot is still referenced, so it is safe to
  225. // look at its condition.
  226. //
  227. if (NetRoot->Condition == Condition_Good) {
  228. goto RETRY_LOOKUP;
  229. }
  230. }
  231. if ((NetRoot->Condition == Condition_Good) &&
  232. (SrvCall->Condition == Condition_Good) &&
  233. (SrvCall->RxDeviceObject == RxContext->RxDeviceObject) ) {
  234. //case (0)...the good case...see comments below
  235. RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
  236. RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
  237. RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
  238. try_return ( Status = (STATUS_CONNECTION_ACTIVE) );
  239. } else {
  240. Status = VNetRoot->ConstructionStatus==STATUS_SUCCESS ?
  241. STATUS_BAD_NETWORK_PATH:
  242. VNetRoot->ConstructionStatus;
  243. RxDereferenceVNetRoot(VNetRoot,*pLockHoldingState);
  244. try_return ( Status );
  245. }
  246. } else {
  247. ASSERT ( NodeType(Container) == RDBSS_NTC_SRVCALL);
  248. SrvCall = (PSRV_CALL)Container;
  249. #if 0
  250. if ((NetRootType != NET_ROOT_MAILSLOT) &&
  251. (SrvCall->Flags & SRVCALL_FLAG_MAILSLOT_SERVER)) {
  252. RxDereferenceSrvCall(SrvCall,*pLockHoldingState);
  253. try_return(Status = (STATUS_BAD_DEVICE_TYPE));
  254. }
  255. #endif
  256. // The associated SRV_CALL is in the process of construction.
  257. // await the result.
  258. if (SrvCall->Condition == Condition_InTransition) {
  259. RxDbgTrace(0, Dbg, (" Case(3)\n", 0));
  260. RxReleasePrefixTableLock(pRxNetNameTable);
  261. RxWaitForStableSrvCall(SrvCall,RxContext);
  262. RxAcquirePrefixTableLockExclusive(pRxNetNameTable,TRUE);
  263. *pLockHoldingState = LHS_ExclusiveLockHeld;
  264. if (SrvCall->Condition == Condition_Good) {
  265. goto RETRY_LOOKUP;
  266. }
  267. }
  268. if (SrvCall->Condition != Condition_Good) {
  269. Status = SrvCall->Status == STATUS_SUCCESS ?
  270. STATUS_BAD_NETWORK_PATH:
  271. SrvCall->Status;
  272. //in changing this...remember precious servers.......
  273. RxDereferenceSrvCall(SrvCall,*pLockHoldingState);
  274. try_return(Status);
  275. }
  276. }
  277. }
  278. if ( (SrvCall != NULL)
  279. && (SrvCall->Condition == Condition_Good)
  280. && (SrvCall->RxDeviceObject != RxContext->RxDeviceObject) ) {
  281. RxDereferenceSrvCall(SrvCall,*pLockHoldingState);
  282. try_return(Status = (STATUS_BAD_NETWORK_NAME));
  283. }
  284. if (*pLockHoldingState == LHS_SharedLockHeld) {
  285. // Upgrade the lock to an exclusive lock
  286. if (!RxAcquirePrefixTableLockExclusive(pRxNetNameTable, FALSE) ) {
  287. RxReleasePrefixTableLock(pRxNetNameTable);
  288. RxAcquirePrefixTableLockExclusive(pRxNetNameTable,TRUE);
  289. *pLockHoldingState = LHS_ExclusiveLockHeld;
  290. goto RETRY_LOOKUP;
  291. } else {
  292. *pLockHoldingState = LHS_ExclusiveLockHeld;
  293. }
  294. }
  295. ASSERT(*pLockHoldingState == LHS_ExclusiveLockHeld);
  296. // A prefix table entry was found. Further construction is required
  297. // if either a SRV_CALL was found or a SRV_CALL/NET_ROOT/V_NET_ROOT
  298. // in a bad state was found.
  299. if (Container) {
  300. RxDbgTrace(0, Dbg, (" SrvCall=%08lx\n", SrvCall));
  301. ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) &&
  302. (SrvCall->Condition == Condition_Good));
  303. ASSERT((NetRoot == NULL) && VNetRoot == NULL);
  304. RxDbgTrace(0, Dbg, (" Case(4)\n", 0));
  305. ASSERT (SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
  306. SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(
  307. FilePathName,
  308. (PMRX_SRV_CALL)SrvCall,
  309. &NetRootName,
  310. NULL);
  311. NetRoot = RxCreateNetRoot(
  312. SrvCall,
  313. &NetRootName,
  314. 0,
  315. RxConnectionId);
  316. if (NetRoot == NULL) {
  317. Status = (STATUS_INSUFFICIENT_RESOURCES);
  318. try_return(Status);
  319. }
  320. NetRoot->Type = NetRootType;
  321. // Decrement the reference created by lookup. Since the newly created
  322. // netroot holds onto a reference it is safe to do so.
  323. RxDereferenceSrvCall(SrvCall,*pLockHoldingState);
  324. // Also create the associated default virtual net root
  325. VNetRoot = RxCreateVNetRoot(
  326. RxContext,
  327. NetRoot,
  328. CanonicalName,
  329. LocalNetRootName,
  330. FilePathName,
  331. RxConnectionId);
  332. if (VNetRoot == NULL) {
  333. RxFinalizeNetRoot(NetRoot,TRUE,TRUE);
  334. Status = (STATUS_INSUFFICIENT_RESOURCES);
  335. try_return(Status);
  336. }
  337. // Reference the VNetRoot
  338. RxReferenceVNetRoot(VNetRoot);
  339. NetRoot->Condition = Condition_InTransition;
  340. RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
  341. RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
  342. RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
  343. Status = RxConstructNetRoot(
  344. RxContext,
  345. SrvCall,
  346. NetRoot,
  347. VNetRoot,
  348. pLockHoldingState);
  349. if (Status == (STATUS_SUCCESS)) {
  350. ASSERT(*pLockHoldingState == LHS_ExclusiveLockHeld);
  351. if (!(capPARAMS->Parameters.Create.Options & FILE_CREATE_TREE_CONNECTION)) {
  352. // do not release the lock acquired by the callback routine ....
  353. RxExclusivePrefixTableLockToShared(pRxNetNameTable);
  354. *pLockHoldingState = LHS_SharedLockHeld;
  355. }
  356. } else {
  357. // Dereference the Virtual net root
  358. RxTransitionVNetRoot(VNetRoot, Condition_Bad);
  359. RxLog(("FOrCC %x %x Failed %x VNRc %d \n", RxContext, VNetRoot, Status, VNetRoot->Condition));
  360. RxWmiLog(LOG,
  361. RxFindOrCreateConnections_2,
  362. LOGPTR(RxContext)
  363. LOGPTR(VNetRoot)
  364. LOGULONG(Status)
  365. LOGULONG(VNetRoot->Condition));
  366. RxDereferenceVNetRoot(VNetRoot,*pLockHoldingState);
  367. RxContext->Create.pNetRoot = NULL;
  368. RxContext->Create.pVNetRoot = NULL;
  369. }
  370. try_return (Status);
  371. }
  372. // No prefix table entry was found. A new SRV_CALL instance needs to be
  373. // constructed.
  374. ASSERT(Container == NULL);
  375. RxExtractServerName(FilePathName,&SrvCallName,NULL);
  376. SrvCall = RxCreateSrvCall(RxContext,&SrvCallName,NULL,RxConnectionId);
  377. if (SrvCall == NULL) {
  378. Status = (STATUS_INSUFFICIENT_RESOURCES);
  379. try_return(Status);
  380. }
  381. RxReferenceSrvCall(SrvCall);
  382. RxContext->Create.Type = NetRootType;
  383. RxContext->Create.pSrvCall = NULL;
  384. RxContext->Create.pNetRoot = NULL;
  385. RxContext->Create.pVNetRoot = NULL;
  386. Status = RxConstructSrvCall(
  387. RxContext,
  388. SrvCall,
  389. pLockHoldingState);
  390. ASSERT(!(Status==(STATUS_SUCCESS)) ||
  391. RxIsPrefixTableLockAcquired(pRxNetNameTable));
  392. if (Status != STATUS_SUCCESS) {
  393. if (SrvCall != NULL) {
  394. RxAcquirePrefixTableLockExclusive( pRxNetNameTable, TRUE);
  395. RxDereferenceSrvCall(SrvCall,LHS_ExclusiveLockHeld);
  396. RxReleasePrefixTableLock( pRxNetNameTable );
  397. }
  398. try_return(Status);
  399. } else {
  400. Container = SrvCall;
  401. goto RETRY_AFTER_LOOKUP;
  402. }
  403. try_exit: NOTHING;
  404. } finally {
  405. if ((Status != (STATUS_SUCCESS)) &&
  406. (Status != (STATUS_CONNECTION_ACTIVE))) {
  407. if (*pLockHoldingState != LHS_LockNotHeld) {
  408. RxReleasePrefixTableLock( pRxNetNameTable );
  409. *pLockHoldingState = LHS_LockNotHeld;
  410. }
  411. }
  412. }
  413. ASSERT(!(Status==(STATUS_SUCCESS)) ||
  414. RxIsPrefixTableLockAcquired(pRxNetNameTable));
  415. return Status;
  416. }
  417. VOID
  418. RxCreateNetRootCallBack (
  419. IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
  420. )
  421. /*++
  422. Routine Description:
  423. This routine gets called when the minirdr has finished processing on
  424. a CreateNetRoot calldown. It's exact function depends on whether the context
  425. describes IRP_MJ_CREATE or an IRP_MJ_IOCTL.
  426. Arguments:
  427. NetRoot - describes the Net_Root.
  428. --*/
  429. {
  430. PAGED_CODE();
  431. RxDbgTrace(0, Dbg, ("RxCreateNetRootCallBack pCreateNetRootContext = %08lx\n",
  432. pCreateNetRootContext));
  433. KeSetEvent(&pCreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE );
  434. }
  435. NTSTATUS
  436. RxFinishSrvCallConstruction(
  437. IN OUT PMRX_SRVCALLDOWN_STRUCTURE pSrvCalldownStructure)
  438. /*++
  439. Routine Description:
  440. This routine completes the construction of the srv call instance on an
  441. asyhcnronous manner
  442. Arguments:
  443. SCCBC -- Call back structure
  444. --*/
  445. {
  446. PRX_CONTEXT RxContext;
  447. RX_BLOCK_CONDITION SrvCallCondition;
  448. NTSTATUS Status;
  449. PSRV_CALL pSrvCall;
  450. PRX_PREFIX_TABLE pRxNetNameTable;
  451. RxContext = pSrvCalldownStructure->RxContext;
  452. pRxNetNameTable = RxContext->RxDeviceObject->pRxNetNameTable;
  453. pSrvCall = (PSRV_CALL)pSrvCalldownStructure->SrvCall;
  454. if ( pSrvCalldownStructure->BestFinisher == NULL) {
  455. SrvCallCondition = Condition_Bad;
  456. Status = pSrvCalldownStructure->CallbackContexts[0].Status;
  457. } else {
  458. PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext;
  459. // Notify the Winner
  460. CallbackContext = &(pSrvCalldownStructure->CallbackContexts[pSrvCalldownStructure->BestFinisherOrdinal]);
  461. RxLog(("WINNER %x %wZ\n",CallbackContext,&pSrvCalldownStructure->BestFinisher->DeviceName));
  462. RxWmiLog(LOG,
  463. RxFinishSrvCallConstruction,
  464. LOGPTR(CallbackContext)
  465. LOGUSTR(pSrvCalldownStructure->BestFinisher->DeviceName));
  466. ASSERT(pSrvCall->RxDeviceObject == pSrvCalldownStructure->BestFinisher);
  467. MINIRDR_CALL_THROUGH(
  468. Status,
  469. pSrvCalldownStructure->BestFinisher->Dispatch,
  470. MRxSrvCallWinnerNotify,
  471. (
  472. (PMRX_SRV_CALL)pSrvCall,
  473. TRUE,
  474. CallbackContext->RecommunicateContext
  475. ));
  476. if (STATUS_SUCCESS != Status) {
  477. SrvCallCondition = Condition_Bad;
  478. } else {
  479. SrvCallCondition = Condition_Good;
  480. }
  481. }
  482. // Transition the SrvCall instance ...
  483. RxAcquirePrefixTableLockExclusive(pRxNetNameTable, TRUE);
  484. RxTransitionSrvCall(pSrvCall,SrvCallCondition);
  485. RxFreePool(pSrvCalldownStructure);
  486. if (FlagOn(
  487. RxContext->Flags,
  488. RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  489. RxReleasePrefixTableLock( pRxNetNameTable );
  490. // Resume the request that triggered the construction of the SrvCall ...
  491. if (BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_CANCELLED)) {
  492. Status = STATUS_CANCELLED;
  493. }
  494. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  495. RxpPrepareCreateContextForReuse(RxContext);
  496. }
  497. if (Status == STATUS_SUCCESS) {
  498. Status = RxContext->ResumeRoutine(RxContext);
  499. if (Status != STATUS_PENDING) {
  500. RxCompleteRequest(RxContext,Status);
  501. }
  502. } else {
  503. RxCaptureRequestPacket;
  504. RxCaptureParamBlock;
  505. RxContext->MajorFunction = capPARAMS->MajorFunction;
  506. if (RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
  507. if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL) {
  508. RxFreePool(RxContext->PrefixClaim.SuppliedPathName.Buffer);
  509. RxContext->PrefixClaim.SuppliedPathName.Buffer = NULL;
  510. }
  511. }
  512. capReqPacket->IoStatus.Status = Status;
  513. capReqPacket->IoStatus.Information = 0;
  514. RxCompleteRequest(RxContext,Status);
  515. }
  516. }
  517. RxDereferenceSrvCall(pSrvCall,LHS_LockNotHeld);
  518. return Status;
  519. }
  520. BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE;
  521. VOID
  522. RxFinishSrvCallConstructionDispatcher(
  523. PVOID Context)
  524. /*++
  525. Routine Description:
  526. This routine provides us with a throttling mechanism for controlling
  527. the number of threads that can be consumed by srv call construction in the
  528. thread pool. Currently this limit is set at 1.
  529. gets called when a minirdr has finished processing on
  530. --*/
  531. {
  532. KIRQL SavedIrql;
  533. BOOLEAN RemainingRequestsForProcessing;
  534. BOOLEAN ResumeRequestsOnDispatchError;
  535. ResumeRequestsOnDispatchError = (Context == NULL);
  536. for (;;) {
  537. PLIST_ENTRY pSrvCalldownListEntry;
  538. PMRX_SRVCALLDOWN_STRUCTURE pSrvCalldownStructure;
  539. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  540. pSrvCalldownListEntry = RemoveHeadList(
  541. &RxSrvCalldownList);
  542. if (pSrvCalldownListEntry != &RxSrvCalldownList) {
  543. RemainingRequestsForProcessing = TRUE;
  544. } else {
  545. RemainingRequestsForProcessing = FALSE;
  546. RxSrvCallConstructionDispatcherActive = FALSE;
  547. }
  548. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  549. if (!RemainingRequestsForProcessing) {
  550. break;
  551. }
  552. pSrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)
  553. CONTAINING_RECORD(
  554. pSrvCalldownListEntry,
  555. MRX_SRVCALLDOWN_STRUCTURE,
  556. SrvCalldownList);
  557. if (ResumeRequestsOnDispatchError) {
  558. pSrvCalldownStructure->BestFinisher = NULL;
  559. }
  560. RxFinishSrvCallConstruction(pSrvCalldownStructure);
  561. }
  562. }
  563. VOID
  564. RxCreateSrvCallCallBack (
  565. IN PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC
  566. )
  567. /*++
  568. Routine Description:
  569. This routine gets called when a minirdr has finished processing on
  570. a CreateSrvCall calldown. The minirdr will have set the status in the passed
  571. context to indicate success or failure. what we have to do is
  572. 1) decrease the number of outstanding requests and set the event
  573. if this is the last one.
  574. 2) determine whether this guy is the winner of the call.
  575. the minirdr must get the strucsupspinlock in order to call this routine; this routine
  576. must NOT be called if the minirdr's call was successfully canceled.
  577. Arguments:
  578. SCCBC -- Call back structure
  579. --*/
  580. {
  581. KIRQL SavedIrql;
  582. PMRX_SRVCALLDOWN_STRUCTURE pSrvCalldownStructure = (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->SrvCalldownStructure);
  583. PSRV_CALL pSrvCall = (PSRV_CALL)pSrvCalldownStructure->SrvCall;
  584. ULONG MiniRedirectorsRemaining;
  585. BOOLEAN Cancelled;
  586. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  587. RxDbgTrace(0, Dbg, (" RxCreateSrvCallCallBack SrvCall = %08lx\n",
  588. pSrvCall));
  589. if (SCCBC->Status == (STATUS_SUCCESS)) {
  590. pSrvCalldownStructure->BestFinisher = SCCBC->RxDeviceObject;
  591. pSrvCalldownStructure->BestFinisherOrdinal = SCCBC->CallbackContextOrdinal;
  592. }
  593. pSrvCalldownStructure->NumberRemaining -= 1;
  594. MiniRedirectorsRemaining = pSrvCalldownStructure->NumberRemaining;
  595. pSrvCall->Status = SCCBC->Status;
  596. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  597. if (MiniRedirectorsRemaining == 0) {
  598. if (!FlagOn(
  599. pSrvCalldownStructure->RxContext->Flags,
  600. RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  601. KeSetEvent(
  602. &pSrvCalldownStructure->FinishEvent,
  603. IO_NETWORK_INCREMENT,
  604. FALSE );
  605. } else if (FlagOn(
  606. pSrvCalldownStructure->RxContext->Flags,
  607. RX_CONTEXT_FLAG_CREATE_MAILSLOT)) {
  608. RxFinishSrvCallConstruction(pSrvCalldownStructure);
  609. } else {
  610. KIRQL SavedIrql;
  611. BOOLEAN DispatchRequest;
  612. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  613. InsertTailList(
  614. &RxSrvCalldownList,
  615. &pSrvCalldownStructure->SrvCalldownList);
  616. DispatchRequest = !RxSrvCallConstructionDispatcherActive;
  617. if (!RxSrvCallConstructionDispatcherActive) {
  618. RxSrvCallConstructionDispatcherActive = TRUE;
  619. }
  620. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  621. if (DispatchRequest) {
  622. NTSTATUS DispatchStatus;
  623. DispatchStatus = RxDispatchToWorkerThread(
  624. RxFileSystemDeviceObject,
  625. CriticalWorkQueue,
  626. RxFinishSrvCallConstructionDispatcher,
  627. &RxSrvCalldownList);
  628. if (DispatchStatus != STATUS_SUCCESS) {
  629. RxFinishSrvCallConstructionDispatcher(NULL);
  630. }
  631. }
  632. }
  633. }
  634. }
  635. NTSTATUS
  636. RxConstructSrvCall(
  637. PRX_CONTEXT RxContext,
  638. PSRV_CALL pSrvCall,
  639. LOCK_HOLDING_STATE *pLockHoldingState)
  640. /*++
  641. Routine Description:
  642. This routine constructs a srv call by invoking the registered mini redirectors
  643. Arguments:
  644. pSrvCall -- the server call whose construction is to be completed
  645. pLockHoldingState -- the prefix table lock holding status
  646. Return Value:
  647. the appropriate status value
  648. --*/
  649. {
  650. RxCaptureRequestPacket;
  651. NTSTATUS Status,WaitStatus;
  652. PMRX_SRVCALLDOWN_STRUCTURE pSrvCalldownStructure;
  653. RX_BLOCK_CONDITION SrvCallCondition;
  654. BOOLEAN SynchronousOperation;
  655. PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC;
  656. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
  657. PRX_PREFIX_TABLE pRxNetNameTable = RxDeviceObject->pRxNetNameTable;
  658. PAGED_CODE();
  659. ASSERT(*pLockHoldingState == LHS_ExclusiveLockHeld);
  660. SynchronousOperation = (!FlagOn(
  661. RxContext->Flags,
  662. RX_CONTEXT_FLAG_ASYNC_OPERATION));
  663. pSrvCalldownStructure = RxAllocatePoolWithTag(
  664. NonPagedPool,
  665. sizeof(MRX_SRVCALLDOWN_STRUCTURE) +
  666. (sizeof(MRX_SRVCALL_CALLBACK_CONTEXT) * 1), //one minirdr in this call
  667. 'CSxR' );
  668. if (pSrvCalldownStructure == NULL) {
  669. pSrvCall->Condition = Condition_Bad;
  670. pSrvCall->Context = NULL;
  671. RxReleasePrefixTableLock( pRxNetNameTable );
  672. *pLockHoldingState = LHS_LockNotHeld;
  673. return STATUS_INSUFFICIENT_RESOURCES;
  674. }
  675. RtlZeroMemory(pSrvCalldownStructure,
  676. sizeof(MRX_SRVCALLDOWN_STRUCTURE) +
  677. sizeof(MRX_SRVCALL_CALLBACK_CONTEXT) * 1);
  678. pSrvCall->Condition = Condition_InTransition;
  679. pSrvCall->Context = NULL;
  680. // Drop the prefix table lock before calling the mini redirectors.
  681. RxReleasePrefixTableLock( pRxNetNameTable );
  682. *pLockHoldingState = LHS_LockNotHeld;
  683. SCCBC = &(pSrvCalldownStructure->CallbackContexts[0]); //use the first and only context
  684. RxLog(("Calldwn %lx %wZ",SCCBC,&RxDeviceObject->DeviceName));
  685. RxWmiLog(LOG,
  686. RxConstructSrvCall,
  687. LOGPTR(SCCBC)
  688. LOGUSTR(RxDeviceObject->DeviceName));
  689. SCCBC->SrvCalldownStructure = pSrvCalldownStructure;
  690. SCCBC->CallbackContextOrdinal = 0;
  691. SCCBC->RxDeviceObject = RxDeviceObject;
  692. // This reference is taken away by the RxFinishSrvCallConstruction routine.
  693. // This reference enables us to deal with synchronous/asynchronous processing
  694. // of srv call construction requests in an identical manner.
  695. RxReferenceSrvCall(pSrvCall);
  696. if (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  697. RxPrePostIrp(RxContext,capReqPacket);
  698. } else {
  699. KeInitializeEvent(
  700. &pSrvCalldownStructure->FinishEvent,
  701. SynchronizationEvent,
  702. FALSE );
  703. }
  704. pSrvCalldownStructure->NumberToWait = 1;
  705. pSrvCalldownStructure->NumberRemaining = pSrvCalldownStructure->NumberToWait;
  706. pSrvCalldownStructure->SrvCall = (PMRX_SRV_CALL)pSrvCall;
  707. pSrvCalldownStructure->CallBack = RxCreateSrvCallCallBack;
  708. pSrvCalldownStructure->BestFinisher = NULL;
  709. pSrvCalldownStructure->RxContext = RxContext;
  710. SCCBC->Status = STATUS_BAD_NETWORK_PATH;
  711. InitializeListHead(&pSrvCalldownStructure->SrvCalldownList);
  712. MINIRDR_CALL_THROUGH(
  713. Status,
  714. RxDeviceObject->Dispatch,
  715. MRxCreateSrvCall,
  716. ((PMRX_SRV_CALL)pSrvCall,SCCBC),
  717. );
  718. ASSERT(Status == STATUS_PENDING);
  719. if (SynchronousOperation) {
  720. WaitStatus = KeWaitForSingleObject(
  721. &pSrvCalldownStructure->FinishEvent,
  722. Executive,
  723. KernelMode,
  724. FALSE,
  725. NULL);
  726. Status = RxFinishSrvCallConstruction(pSrvCalldownStructure);
  727. if (Status != STATUS_SUCCESS) {
  728. RxReleasePrefixTableLock( pRxNetNameTable );
  729. *pLockHoldingState = LHS_LockNotHeld;
  730. } else {
  731. ASSERT(RxIsPrefixTableLockAcquired(pRxNetNameTable));
  732. *pLockHoldingState = LHS_ExclusiveLockHeld;
  733. }
  734. } else {
  735. Status = STATUS_PENDING;
  736. }
  737. return Status;
  738. }
  739. NTSTATUS
  740. RxConstructNetRoot(
  741. PRX_CONTEXT RxContext,
  742. PSRV_CALL pSrvCall,
  743. PNET_ROOT pNetRoot,
  744. PV_NET_ROOT pVNetRoot,
  745. LOCK_HOLDING_STATE *pLockHoldingState
  746. )
  747. /*++
  748. Routine Description:
  749. This routine constructs a net root by invoking the registered mini redirectors
  750. Arguments:
  751. RxContext -- the RDBSS context
  752. pSrvCall -- the server call associated with the net root
  753. pNetRoot -- the net root instance to be constructed
  754. pVirtualNetRoot -- the virtual net root instance to be constructed
  755. pLockHoldingState -- the prefix table lock holding status
  756. Return Value:
  757. the appropriate status value
  758. --*/
  759. {
  760. NTSTATUS Status;
  761. PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
  762. RX_BLOCK_CONDITION NetRootCondition = Condition_Bad;
  763. RX_BLOCK_CONDITION VNetRootCondition = Condition_Bad;
  764. PRX_PREFIX_TABLE pRxNetNameTable
  765. = RxContext->RxDeviceObject->pRxNetNameTable;
  766. PAGED_CODE();
  767. ASSERT(*pLockHoldingState == LHS_ExclusiveLockHeld);
  768. pCreateNetRootContext = (PMRX_CREATENETROOT_CONTEXT)
  769. RxAllocatePoolWithTag( NonPagedPool,
  770. sizeof(MRX_CREATENETROOT_CONTEXT),
  771. 'CSxR' );
  772. if (pCreateNetRootContext == NULL) {
  773. return (STATUS_INSUFFICIENT_RESOURCES);
  774. }
  775. RxReleasePrefixTableLock( pRxNetNameTable );
  776. *pLockHoldingState = LHS_LockNotHeld;
  777. RtlZeroMemory(pCreateNetRootContext,sizeof(MRX_CREATENETROOT_CONTEXT));
  778. KeInitializeEvent( &pCreateNetRootContext->FinishEvent, SynchronizationEvent, FALSE );
  779. pCreateNetRootContext->Callback = RxCreateNetRootCallBack;
  780. pCreateNetRootContext->RxContext = RxContext;
  781. pCreateNetRootContext->pVNetRoot = pVNetRoot;
  782. MINIRDR_CALL_THROUGH(
  783. Status,
  784. pSrvCall->RxDeviceObject->Dispatch,
  785. MRxCreateVNetRoot,(pCreateNetRootContext)
  786. );
  787. ASSERT (Status == STATUS_PENDING);
  788. if (Status == STATUS_PENDING) {
  789. KeWaitForSingleObject(&pCreateNetRootContext->FinishEvent, Executive, KernelMode, FALSE, NULL);
  790. if ((pCreateNetRootContext->NetRootStatus == (STATUS_SUCCESS)) &&
  791. (pCreateNetRootContext->VirtualNetRootStatus == (STATUS_SUCCESS))) {
  792. RxDbgTrace(0, Dbg, ("Return to open, good netroot...%wZ\n",
  793. &pNetRoot->PrefixEntry.Prefix));
  794. NetRootCondition = Condition_Good;
  795. VNetRootCondition = Condition_Good;
  796. Status = (STATUS_SUCCESS);
  797. } else {
  798. if (pCreateNetRootContext->NetRootStatus == (STATUS_SUCCESS)) {
  799. NetRootCondition = Condition_Good;
  800. }
  801. RxDbgTrace(0, Dbg, ("Return to open, bad netroot...%wZ\n",
  802. &pNetRoot->PrefixEntry.Prefix));
  803. if (pCreateNetRootContext->VirtualNetRootStatus != (STATUS_SUCCESS)) {
  804. Status = pCreateNetRootContext->VirtualNetRootStatus;
  805. } else {
  806. Status = pCreateNetRootContext->NetRootStatus;
  807. }
  808. }
  809. }
  810. RxAcquirePrefixTableLockExclusive(pRxNetNameTable, TRUE);
  811. RxTransitionNetRoot(pNetRoot, NetRootCondition);
  812. RxTransitionVNetRoot(pVNetRoot,VNetRootCondition);
  813. *pLockHoldingState = LHS_ExclusiveLockHeld;
  814. if (pCreateNetRootContext->WorkQueueItem.List.Flink != NULL) {
  815. //DbgBreakPoint();
  816. }
  817. RxFreePool(pCreateNetRootContext);
  818. return Status;
  819. }
  820. NTSTATUS
  821. RxConstructVirtualNetRoot(
  822. PRX_CONTEXT RxContext,
  823. PUNICODE_STRING CanonicalName,
  824. NET_ROOT_TYPE NetRootType,
  825. PV_NET_ROOT *pVirtualNetRootPointer,
  826. LOCK_HOLDING_STATE *pLockHoldingState,
  827. PRX_CONNECTION_ID RxConnectionId)
  828. /*++
  829. Routine Description:
  830. This routine constructs a VNetRoot (View of a net root) by invoking the registered mini
  831. redirectors
  832. Arguments:
  833. RxContext -- the RDBSS context
  834. CanonicalName -- the canonical name associated with the VNetRoot
  835. NetRootType -- the type of the virtual net root
  836. pVirtualNetRoot -- placeholder for the virtual net root instance to be constructed
  837. pLockHoldingState -- the prefix table lock holding status
  838. RxConnectionId -- The ID used for multiplex control
  839. Return Value:
  840. the appropriate status value
  841. --*/
  842. {
  843. NTSTATUS Status;
  844. RX_BLOCK_CONDITION VNetRootCondition = Condition_Bad;
  845. UNICODE_STRING FilePath;
  846. UNICODE_STRING LocalNetRootName;
  847. PV_NET_ROOT pVirtualNetRoot = NULL;
  848. PAGED_CODE();
  849. RxDbgTrace(0, Dbg, ("RxConstructVirtualNetRoot -- Entry\n"));
  850. ASSERT(*pLockHoldingState != LHS_LockNotHeld);
  851. Status = RxFindOrCreateConnections(
  852. RxContext,
  853. CanonicalName,
  854. NetRootType,
  855. &LocalNetRootName,
  856. &FilePath,
  857. pLockHoldingState,
  858. RxConnectionId);
  859. if (Status == (STATUS_CONNECTION_ACTIVE)) {
  860. PV_NET_ROOT pActiveVNetRoot = (PV_NET_ROOT)(RxContext->Create.pVNetRoot);
  861. PNET_ROOT pNetRoot = (PNET_ROOT)pActiveVNetRoot->NetRoot;
  862. RxDbgTrace(0, Dbg, (" RxConstructVirtualNetRoot -- Creating new VNetRoot\n"));
  863. RxDbgTrace(0, Dbg, ("RxCreateTreeConnect netroot=%wZ\n", &pNetRoot->PrefixEntry.Prefix));
  864. // The NetRoot has been previously constructed. A subsequent VNetRoot
  865. // construction is required since the existing VNetRoot's do not satisfy
  866. // the given criterion ( currently smae Logon Id's).
  867. pVirtualNetRoot = RxCreateVNetRoot(
  868. RxContext,
  869. pNetRoot,
  870. CanonicalName,
  871. &LocalNetRootName,
  872. &FilePath,
  873. RxConnectionId);
  874. // The skeleton VNetRoot has been constructed. ( As part of this construction
  875. // the underlying NetRoot and SrvCall has been referenced).
  876. if (pVirtualNetRoot != NULL) {
  877. RxReferenceVNetRoot(pVirtualNetRoot);
  878. }
  879. // Dereference the VNetRoot returned as part of the lookup.
  880. RxDereferenceVNetRoot(pActiveVNetRoot,LHS_LockNotHeld);
  881. RxContext->Create.pVNetRoot = NULL;
  882. RxContext->Create.pNetRoot = NULL;
  883. RxContext->Create.pSrvCall = NULL;
  884. if (pVirtualNetRoot != NULL) {
  885. Status = RxConstructNetRoot(
  886. RxContext,
  887. (PSRV_CALL)pVirtualNetRoot->NetRoot->SrvCall,
  888. (PNET_ROOT)pVirtualNetRoot->NetRoot,
  889. pVirtualNetRoot,
  890. pLockHoldingState);
  891. VNetRootCondition = (Status == (STATUS_SUCCESS))
  892. ? Condition_Good
  893. : Condition_Bad;
  894. } else {
  895. Status = STATUS_INSUFFICIENT_RESOURCES;
  896. }
  897. } else if (Status == (STATUS_SUCCESS)) {
  898. *pLockHoldingState = LHS_ExclusiveLockHeld;
  899. VNetRootCondition = Condition_Good;
  900. pVirtualNetRoot = (PV_NET_ROOT)(RxContext->Create.pVNetRoot);
  901. } else {
  902. RxDbgTrace(0, Dbg, ("RxConstructVirtualNetRoot -- RxFindOrCreateConnections Status %lx\n",Status));
  903. }
  904. if ((pVirtualNetRoot != NULL) &&
  905. !StableCondition(pVirtualNetRoot->Condition)) {
  906. RxTransitionVNetRoot(pVirtualNetRoot,VNetRootCondition);
  907. }
  908. if (Status != (STATUS_SUCCESS)) {
  909. if (pVirtualNetRoot != NULL) {
  910. ASSERT(*pLockHoldingState != LHS_LockNotHeld);
  911. RxDereferenceVNetRoot(pVirtualNetRoot,*pLockHoldingState);
  912. pVirtualNetRoot = NULL;
  913. }
  914. if (*pLockHoldingState != LHS_LockNotHeld) {
  915. RxReleasePrefixTableLock(
  916. RxContext->RxDeviceObject->pRxNetNameTable);
  917. *pLockHoldingState = LHS_LockNotHeld;
  918. }
  919. }
  920. *pVirtualNetRootPointer = pVirtualNetRoot;
  921. RxDbgTrace(0, Dbg, ("RxConstructVirtualNetRoot -- Exit Status %lx\n",Status));
  922. return Status;
  923. }
  924. NTSTATUS
  925. RxCheckVNetRootCredentials(
  926. PRX_CONTEXT RxContext,
  927. PV_NET_ROOT pVNetRoot,
  928. LUID *pLogonId,
  929. PUNICODE_STRING pUserName,
  930. PUNICODE_STRING pUserDomainName,
  931. PUNICODE_STRING pPassword,
  932. ULONG Flags
  933. )
  934. {
  935. NTSTATUS Status;
  936. BOOLEAN UNCName;
  937. BOOLEAN TreeConnectFlagSpecified;
  938. PSecurityUserData pSecurityData = NULL;
  939. RxCaptureParamBlock;
  940. PAGED_CODE();
  941. Status = (STATUS_MORE_PROCESSING_REQUIRED);
  942. UNCName = BooleanFlagOn(RxContext->Create.Flags,RX_CONTEXT_CREATE_FLAG_UNC_NAME);
  943. TreeConnectFlagSpecified =
  944. BooleanFlagOn(capPARAMS->Parameters.Create.Options,FILE_CREATE_TREE_CONNECTION);
  945. // only for UNC names do we do the logic below
  946. if(RxContext->Create.Flags & RX_CONTEXT_CREATE_FLAG_UNC_NAME)
  947. {
  948. if ((pVNetRoot->Flags & VNETROOT_FLAG_CSCAGENT_INSTANCE) !=
  949. (Flags & VNETROOT_FLAG_CSCAGENT_INSTANCE))
  950. {
  951. // mismatched csc agent flags, not collapsing
  952. //DbgPrint("RxCheckVNetRootCredentials Not collapsing VNR %x \n", pVNetRoot);
  953. return Status;
  954. }
  955. }
  956. // The for loop is a scoping construct to join together the
  957. // multitiude of failure cases in comparing the EA parameters
  958. // with the original parameters supplied in the create request.
  959. for (;;) {
  960. if (RtlCompareMemory(&pVNetRoot->LogonId,pLogonId,sizeof(LUID)) == sizeof(LUID)) {
  961. PUNICODE_STRING TempUserName,TempUserDomainName;
  962. // If no EA parameters are specified by the user, the existing
  963. // V_NET_ROOT instance as used. This is the common case when
  964. // the user specifies the credentials for establishing a
  965. // persistent connection across processes and reuses them.
  966. if ((pUserName == NULL) &&
  967. (pUserDomainName == NULL) &&
  968. (pPassword == NULL)) {
  969. Status = STATUS_SUCCESS;
  970. break;
  971. }
  972. TempUserName = pVNetRoot->pUserName;
  973. TempUserDomainName = pVNetRoot->pUserDomainName;
  974. if (TempUserName == NULL ||
  975. TempUserDomainName == NULL) {
  976. Status = GetSecurityUserInfo(
  977. pLogonId,
  978. UNDERSTANDS_LONG_NAMES,
  979. &pSecurityData);
  980. if (NT_SUCCESS(Status)) {
  981. if (TempUserName == NULL) {
  982. TempUserName = &(pSecurityData->UserName);
  983. }
  984. if (TempUserDomainName == NULL) {
  985. TempUserDomainName = &(pSecurityData->LogonDomainName);
  986. }
  987. } else {
  988. break;
  989. }
  990. }
  991. // The logon ids match. The user has supplied EA parameters
  992. // which can either match with the existing credentials or
  993. // result in a conflict with the existing credentials. In all
  994. // such cases the outcome will either be a reuse of the
  995. // existing V_NET_ROOT instance or a refusal of the new connection
  996. // attempt.
  997. // The only exception to the above rule is in the case of
  998. // regular opens (FILE_CREATE_TREE_CONNECTION is not
  999. // specified for UNC names. In such cases the construction of a
  1000. // new V_NET_ROOT is initiated which will be torn down
  1001. // when the associated file is closed
  1002. if (UNCName && !TreeConnectFlagSpecified) {
  1003. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1004. } else {
  1005. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  1006. }
  1007. if (pUserName != NULL &&
  1008. TempUserName != NULL &&
  1009. !RtlEqualUnicodeString(TempUserName,pUserName,TRUE)) {
  1010. break;
  1011. }
  1012. if (pUserDomainName != NULL &&
  1013. !RtlEqualUnicodeString(TempUserDomainName,pUserDomainName,TRUE)) {
  1014. break;
  1015. }
  1016. if ((pVNetRoot->pPassword != NULL) &&
  1017. (pPassword != NULL)) {
  1018. if (!RtlEqualUnicodeString(
  1019. pVNetRoot->pPassword,
  1020. pPassword,
  1021. FALSE)) {
  1022. break;
  1023. }
  1024. }
  1025. // We use existing session if either the stored or new password is NULL.
  1026. // Later, a new security API will be created for verify the password based
  1027. // on the logon ID.
  1028. Status = STATUS_SUCCESS;
  1029. break;
  1030. } else {
  1031. break;
  1032. }
  1033. }
  1034. //ASSERT(Status != STATUS_NETWORK_CREDENTIAL_CONFLICT);
  1035. if (pSecurityData != NULL) {
  1036. LsaFreeReturnBuffer(pSecurityData);
  1037. }
  1038. return Status;
  1039. }
  1040. NTSTATUS
  1041. RxFindOrConstructVirtualNetRoot(
  1042. PRX_CONTEXT RxContext,
  1043. PUNICODE_STRING CanonicalName,
  1044. NET_ROOT_TYPE NetRootType,
  1045. PUNICODE_STRING RemainingName)
  1046. /*++
  1047. Routine Description:
  1048. This routine finds or constructs a VNetRoot (View of a net root)
  1049. Arguments:
  1050. RxContext -- the RDBSS context
  1051. CanonicalName -- the canonical name associated with the VNetRoot
  1052. NetRootType -- the type of the virtual net root
  1053. RemainingName -- the portion of the name that was not found in the prefix table
  1054. Return Value:
  1055. the appropriate status value
  1056. --*/
  1057. {
  1058. NTSTATUS Status;
  1059. LOCK_HOLDING_STATE LockHoldingState;
  1060. BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
  1061. BOOLEAN InFSD = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
  1062. BOOLEAN UNCName;
  1063. BOOLEAN TreeConnectFlagSpecified;
  1064. PVOID Container;
  1065. PV_NET_ROOT pVNetRoot;
  1066. PNET_ROOT pNetRoot;
  1067. PSRV_CALL pSrvCall;
  1068. PRX_PREFIX_TABLE pRxNetNameTable
  1069. = RxContext->RxDeviceObject->pRxNetNameTable;
  1070. ULONG Flags = 0;
  1071. RX_CONNECTION_ID sRxConnectionId;
  1072. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
  1073. RxCaptureParamBlock;
  1074. PAGED_CODE();
  1075. MINIRDR_CALL_THROUGH(
  1076. Status,
  1077. RxDeviceObject->Dispatch,
  1078. MRxGetConnectionId,
  1079. (RxContext,&sRxConnectionId)
  1080. );
  1081. if( Status == STATUS_NOT_IMPLEMENTED )
  1082. {
  1083. RtlZeroMemory( &sRxConnectionId, sizeof(RX_CONNECTION_ID) );
  1084. }
  1085. else if( !NT_SUCCESS(Status) )
  1086. {
  1087. DbgPrint( "MRXSMB: Failed to initialize Connection ID\n" );
  1088. ASSERT(FALSE);
  1089. RtlZeroMemory( &sRxConnectionId, sizeof(RX_CONNECTION_ID) );
  1090. }
  1091. Status = (STATUS_MORE_PROCESSING_REQUIRED);
  1092. UNCName = BooleanFlagOn(RxContext->Create.Flags,RX_CONTEXT_CREATE_FLAG_UNC_NAME);
  1093. TreeConnectFlagSpecified =
  1094. BooleanFlagOn(capPARAMS->Parameters.Create.Options,FILE_CREATE_TREE_CONNECTION);
  1095. //deleterxcontext stuff will deref wherever this points.......
  1096. RxContext->Create.NetNamePrefixEntry = NULL;
  1097. RxAcquirePrefixTableLockShared(pRxNetNameTable, TRUE);
  1098. LockHoldingState = LHS_SharedLockHeld;
  1099. for(;;) {
  1100. // This for loop actually serves as a simple scoping construct for executing
  1101. // the same piece of code twice, once with a shared lock and once with an
  1102. // exclusive lock. In the interests of maximal concurrency a shared lock is
  1103. // accquired for the first pass and subsequently upgraded. If the search
  1104. // succeeds with a shared lock the second pass is skipped.
  1105. Container = RxPrefixTableLookupName( pRxNetNameTable, CanonicalName, RemainingName, &sRxConnectionId );
  1106. if (Container != NULL ) {
  1107. if (NodeType(Container) == RDBSS_NTC_V_NETROOT) {
  1108. PV_NET_ROOT pTempVNetRoot;
  1109. ULONG SessionId;
  1110. pVNetRoot = (PV_NET_ROOT)Container;
  1111. pNetRoot = (PNET_ROOT)pVNetRoot->NetRoot;
  1112. // Determine if a virtual net root with the same logon id. already exists.
  1113. // If not a new virtual net root has to be constructed.
  1114. // traverse the list of virtual net roots associated with a net root.
  1115. // Note that the list of virtual net roots associated with a net root cannot be empty
  1116. // since the construction of the default virtual net root coincides with the creation
  1117. // of the net root.
  1118. if (((pNetRoot->Condition == Condition_Good) ||
  1119. (pNetRoot->Condition == Condition_InTransition)) &&
  1120. (pNetRoot->pSrvCall->RxDeviceObject == RxContext->RxDeviceObject)) {
  1121. LUID LogonId;
  1122. PUNICODE_STRING pUserName,pUserDomainName,pPassword;
  1123. // Extract the VNetRoot parameters from the IRP to map one of
  1124. // the existing VNetRoots if possible. The algorithm for
  1125. // determining this mapping is very simplistic. If no Ea
  1126. // parameters are specified a VNetRoot with a matching Logon
  1127. // id. is choosen. if Ea parameters are specified then a
  1128. // VNetRoot with identical parameters is choosen. The idea
  1129. // behind this simplistic algorithm is to let the mini redirectors
  1130. // determine the mapping policy and not prefer one mini
  1131. // redirectors policy over another.
  1132. Status = RxInitializeVNetRootParameters(
  1133. RxContext,
  1134. &LogonId,
  1135. &SessionId,
  1136. &pUserName,
  1137. &pUserDomainName,
  1138. &pPassword,
  1139. &Flags
  1140. );
  1141. #if 0
  1142. if (Flags & VNETROOT_FLAG_CSCAGENT_INSTANCE)
  1143. {
  1144. DbgPrint("RxFindOrConstructVirtualNetRoot AgentOpen %wZ\n", CanonicalName);
  1145. }
  1146. #endif
  1147. if (Status == STATUS_SUCCESS) {
  1148. pTempVNetRoot = pVNetRoot;
  1149. Status = RxCheckVNetRootCredentials(
  1150. RxContext,
  1151. pTempVNetRoot,
  1152. &LogonId,
  1153. pUserName,
  1154. pUserDomainName,
  1155. pPassword,
  1156. Flags
  1157. );
  1158. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1159. // The for loop iterates over the existing VNetRoots to locate
  1160. // an instance whose parameters match the supplied parameters.
  1161. // On exit from this loop pTempVNetRoot will either point to a
  1162. // valid instance or have a NULL value.
  1163. pTempVNetRoot = (PV_NET_ROOT)CONTAINING_RECORD(
  1164. pNetRoot->VirtualNetRoots.Flink,
  1165. V_NET_ROOT,
  1166. NetRootListEntry);
  1167. for (;;) {
  1168. Status = RxCheckVNetRootCredentials(
  1169. RxContext,
  1170. pTempVNetRoot,
  1171. &LogonId,
  1172. pUserName,
  1173. pUserDomainName,
  1174. pPassword,
  1175. Flags
  1176. );
  1177. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1178. if (pTempVNetRoot->NetRootListEntry.Flink == &pNetRoot->VirtualNetRoots) {
  1179. pTempVNetRoot = NULL;
  1180. break;
  1181. } else {
  1182. pTempVNetRoot = (PV_NET_ROOT)CONTAINING_RECORD(
  1183. pTempVNetRoot->NetRootListEntry.Flink,
  1184. V_NET_ROOT,
  1185. NetRootListEntry);
  1186. }
  1187. } else {
  1188. break;
  1189. }
  1190. }
  1191. }
  1192. if (Status != STATUS_SUCCESS) {
  1193. pTempVNetRoot = NULL;
  1194. }
  1195. RxUninitializeVNetRootParameters(pUserName,pUserDomainName,pPassword,&Flags);
  1196. }
  1197. } else {
  1198. Status = (STATUS_BAD_NETWORK_PATH);
  1199. pTempVNetRoot = NULL;
  1200. }
  1201. if ((Status == STATUS_MORE_PROCESSING_REQUIRED) ||
  1202. (Status == STATUS_SUCCESS)) {
  1203. if (pTempVNetRoot != pVNetRoot) {
  1204. RxDereferenceVNetRoot(pVNetRoot,LockHoldingState);
  1205. pVNetRoot = pTempVNetRoot;
  1206. if (pVNetRoot != NULL) {
  1207. RxReferenceVNetRoot(pVNetRoot);
  1208. }
  1209. }
  1210. } else {
  1211. if (pTempVNetRoot == NULL) {
  1212. RxDereferenceVNetRoot(pVNetRoot,LockHoldingState);
  1213. }
  1214. }
  1215. } else {
  1216. ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
  1217. RxDereferenceSrvCall((PSRV_CALL)Container,LockHoldingState);
  1218. }
  1219. }
  1220. if ((Status == (STATUS_MORE_PROCESSING_REQUIRED)) &&
  1221. (LockHoldingState == LHS_SharedLockHeld)) {
  1222. // Release the shared lock and acquire it in an exclusive mode.
  1223. // Upgrade the lock to an exclusive lock
  1224. if (!RxAcquirePrefixTableLockExclusive(pRxNetNameTable, FALSE) ) {
  1225. RxReleasePrefixTableLock(pRxNetNameTable);
  1226. RxAcquirePrefixTableLockExclusive(pRxNetNameTable,TRUE);
  1227. LockHoldingState = LHS_ExclusiveLockHeld;
  1228. } else {
  1229. // The lock was upgraded from a shared mode to an exclusive mode without
  1230. // losing it. Therefore there is no need to search the table again. The
  1231. // construction of the new V_NET_ROOT can proceed.
  1232. LockHoldingState = LHS_ExclusiveLockHeld;
  1233. break;
  1234. }
  1235. } else {
  1236. break;
  1237. }
  1238. }
  1239. // At this point either the lookup was successful ( with a shared/exclusive lock )
  1240. // or exclusive lock has been obtained.
  1241. // No virtual net root was found in the prefix table or the net root that was found is bad.
  1242. // The construction of a new virtual netroot needs to be undertaken.
  1243. if (Status == (STATUS_MORE_PROCESSING_REQUIRED)) {
  1244. ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
  1245. Status = RxConstructVirtualNetRoot(
  1246. RxContext,
  1247. CanonicalName,
  1248. NetRootType,
  1249. &pVNetRoot,
  1250. &LockHoldingState,
  1251. &sRxConnectionId);
  1252. ASSERT((Status != (STATUS_SUCCESS)) || (LockHoldingState != LHS_LockNotHeld));
  1253. if (Status == (STATUS_SUCCESS)) {
  1254. ASSERT(CanonicalName->Length >= pVNetRoot->PrefixEntry.Prefix.Length);
  1255. RemainingName->Buffer = (PWCH)((PCHAR)CanonicalName->Buffer +
  1256. pVNetRoot->PrefixEntry.Prefix.Length);
  1257. RemainingName->Length = CanonicalName->Length -
  1258. pVNetRoot->PrefixEntry.Prefix.Length;
  1259. RemainingName->MaximumLength = RemainingName->Length;
  1260. if (FlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
  1261. {
  1262. RxLog(("FOrCVNR CSC instance %x\n", pVNetRoot));
  1263. RxWmiLog(LOG,
  1264. RxFindOrConstructVirtualNetRoot,
  1265. LOGPTR(pVNetRoot));
  1266. // DbgPrint("FOrCVNR CSC instance %wZ\n", CanonicalName);
  1267. }
  1268. pVNetRoot->Flags |= Flags;
  1269. }
  1270. }
  1271. if (LockHoldingState != LHS_LockNotHeld) {
  1272. RxReleasePrefixTableLock(pRxNetNameTable);
  1273. }
  1274. if (Status == (STATUS_SUCCESS)) {
  1275. RxWaitForStableVNetRoot(pVNetRoot,RxContext);
  1276. if (pVNetRoot->Condition == Condition_Good) {
  1277. pNetRoot = (PNET_ROOT)pVNetRoot->NetRoot;
  1278. pSrvCall = (PSRV_CALL)pNetRoot->SrvCall;
  1279. RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)pVNetRoot;
  1280. RxContext->Create.pNetRoot = (PMRX_NET_ROOT)pNetRoot;
  1281. RxContext->Create.pSrvCall = (PMRX_SRV_CALL)pSrvCall;
  1282. } else {
  1283. RxDereferenceVNetRoot(pVNetRoot,LHS_LockNotHeld);
  1284. RxContext->Create.pVNetRoot = NULL;
  1285. Status = (STATUS_BAD_NETWORK_PATH);
  1286. }
  1287. }
  1288. return Status;
  1289. }