Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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