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.

4083 lines
136 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbcedb.c
  5. Abstract:
  6. This module implements all functions related to accessing the SMB connection engine
  7. database
  8. Revision History:
  9. Balan Sethu Raman [SethuR] 6-March-1995
  10. Notes:
  11. The construction of server, net root and session entries involve a certain
  12. amount of network traffic. Therefore, all these entities are constructed
  13. using a two phase protocol
  14. This continuation context is that of the RDBSS during construction of
  15. srv call and net root entries. For the session entries it is an SMB exchange
  16. that needs to be resumed.
  17. Two of the three primary data structures in the SMB mini redirector, i.e.,
  18. SMBCEDB_SERVER_ENTRY, SMBCEDB_SESSION_ENTRY and SMBCEDB_NET_ROOT_ENTRY have
  19. directcounterparts in the RDBSS (MRX_SRV_CALL, MRX_V_NET_ROOT and MRX_NET_ROOT)
  20. constitute the core of the SMB mini redirector connection engine. There exists
  21. a one to one mapping between the SERVER_ENTRY and the MRX_SRV_CALL, as well
  22. as NET_ROOT_ENTRY and MRX_NET_ROOT.
  23. The SMBCEDB_SESSION_ENTRY does not have a direct mapping to a wrapper data
  24. structue, It is a part of SMBCE_V_NET_ROOT_CONTEXT which is the data
  25. structure associated with a MRX_V_NET_ROOT instance.
  26. More than one tree connect to a server can use the same session on a USER level
  27. security share. Consequently mapping rules need to be established to manage this
  28. relationship. The SMB mini redirector implements the following rules ...
  29. 1) The first session with explicitly specified credentials will be
  30. treated as the default session for all subsequent requests to any given
  31. server unless credentials are explicitly specified for the new session.
  32. 2) If no session with explicitly specified credentials exist then a
  33. session with the same logon id. is choosen.
  34. 3) If no session with the same logon id. exists a new session is created.
  35. These rules are liable to change as we experiment with rules for establishing
  36. sessions with differing credentials to a given server. The problem is not with
  37. creating/manipulating these sessions but providing an adequate set of
  38. fallback rules for emulating the behaviour of the old redirector.
  39. These rules are implemented in SmbCeFindOrConstructSessionEntry.
  40. --*/
  41. #include "precomp.h"
  42. #pragma hdrstop
  43. #include "exsessup.h"
  44. #include "secext.h"
  45. #include "csc.h"
  46. #ifdef ALLOC_PRAGMA
  47. #pragma alloc_text(PAGE, SmbCeUpdateSrvCall)
  48. #pragma alloc_text(PAGE, SmbCeTearDownServerEntry)
  49. #pragma alloc_text(PAGE, SmbCeGetUserNameAndDomainName)
  50. #pragma alloc_text(PAGE, SmbCeTearDownSessionEntry)
  51. #pragma alloc_text(PAGE, SmbCeTearDownNetRootEntry)
  52. #pragma alloc_text(PAGE, SmbCeUpdateNetRoot)
  53. #pragma alloc_text(PAGE, SmbCeDbInit)
  54. #endif
  55. extern BOOLEAN MRxSmbSecuritySignaturesRequired;
  56. extern BOOLEAN MRxSmbSecuritySignaturesEnabled;
  57. extern BOOLEAN MRxSmbExtendedSignaturesEnabled;
  58. extern BOOLEAN MRxSmbExtendedSignaturesRequired;
  59. extern BOOLEAN Win9xSessionRestriction;
  60. RXDT_DefineCategory(SMBCEDB);
  61. #define Dbg (DEBUG_TRACE_SMBCEDB)
  62. // The flag mask to control reference count tracing.
  63. ULONG MRxSmbReferenceTracingValue = 0;
  64. PSMBCEDB_SERVER_ENTRY
  65. SmbCeFindServerEntry(
  66. PUNICODE_STRING pServerName,
  67. SMBCEDB_SERVER_TYPE ServerType,
  68. PRX_CONNECTION_ID RxConnectionId )
  69. /*++
  70. Routine Description:
  71. This routine searches the list of server entries and locates a matching
  72. entry
  73. Arguments:
  74. pServerName - the name of the server
  75. ServerType - the server type
  76. RxConnectionId - Used to control whether this will be multiplexed or not
  77. Notes:
  78. The SmbCeResource must be held on entry and its ownership state will remain
  79. unchanged on exit
  80. --*/
  81. {
  82. PSMBCEDB_SERVER_ENTRY pServerEntry;
  83. RX_CONNECTION_ID LocalId;
  84. ASSERT(SmbCeIsResourceOwned());
  85. if( !RxConnectionId )
  86. {
  87. RtlZeroMemory( &LocalId, sizeof(RX_CONNECTION_ID) );
  88. RxConnectionId = &LocalId;
  89. }
  90. pServerEntry = SmbCeGetFirstServerEntry();
  91. while (pServerEntry != NULL) {
  92. if ((RtlCompareUnicodeString(
  93. pServerName,
  94. &pServerEntry->Name,
  95. TRUE) == 0)) {
  96. // Check the connection ID
  97. if( RxEqualConnectionId( RxConnectionId, &pServerEntry->ConnectionId ) )
  98. {
  99. SmbCeReferenceServerEntry(pServerEntry);
  100. break;
  101. }
  102. else
  103. {
  104. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  105. }
  106. } else {
  107. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  108. }
  109. }
  110. return pServerEntry;
  111. }
  112. PSMBCEDB_SERVER_ENTRY
  113. SmbCeFindServerEntryNoId(
  114. PUNICODE_STRING pServerName,
  115. SMBCEDB_SERVER_TYPE ServerType)
  116. /*++
  117. Routine Description:
  118. This routine searches the list of server entries and locates a matching
  119. entry and ignores the ConnectionId
  120. Arguments:
  121. pServerName - the name of the server
  122. ServerType - the server type
  123. Notes:
  124. The SmbCeResource must be held on entry and its ownership state will remain
  125. unchanged on exit
  126. --*/
  127. {
  128. PSMBCEDB_SERVER_ENTRY pServerEntry;
  129. RX_CONNECTION_ID LocalId;
  130. ASSERT(SmbCeIsResourceOwned());
  131. RtlZeroMemory( &LocalId, sizeof(RX_CONNECTION_ID) );
  132. pServerEntry = SmbCeGetFirstServerEntry();
  133. while (pServerEntry != NULL) {
  134. if ((RtlCompareUnicodeString(
  135. pServerName,
  136. &pServerEntry->Name,
  137. TRUE) == 0)) {
  138. if( RxEqualConnectionId( &LocalId, &pServerEntry->ConnectionId ) )
  139. {
  140. SmbCeReferenceServerEntry(pServerEntry);
  141. break;
  142. }
  143. else
  144. {
  145. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  146. }
  147. } else {
  148. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  149. }
  150. }
  151. return pServerEntry;
  152. }
  153. PSMBCEDB_SERVER_ENTRY
  154. SmbCeFindDfsServerEntry(
  155. PUNICODE_STRING pServerName,
  156. SMBCEDB_SERVER_TYPE ServerType)
  157. /*++
  158. Routine Description:
  159. This routine searches the list of server entries and locates a matching
  160. entry
  161. Arguments:
  162. pServerName - the name of the server
  163. ServerType - the server type
  164. Notes:
  165. The SmbCeResource must be held on entry and its ownership state will remain
  166. unchanged on exit
  167. --*/
  168. {
  169. PSMBCEDB_SERVER_ENTRY pServerEntry;
  170. ASSERT(SmbCeIsResourceOwned());
  171. pServerEntry = SmbCeGetFirstServerEntry();
  172. while (pServerEntry != NULL) {
  173. if ((RtlCompareUnicodeString(
  174. pServerName,
  175. &pServerEntry->DfsRootName,
  176. TRUE) == 0)) {
  177. SmbCeReferenceServerEntry(pServerEntry);
  178. break;
  179. } else {
  180. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  181. }
  182. }
  183. return pServerEntry;
  184. }
  185. NTSTATUS
  186. SmbCeFindOrConstructServerEntry(
  187. PUNICODE_STRING pServerName,
  188. SMBCEDB_SERVER_TYPE ServerType,
  189. PSMBCEDB_SERVER_ENTRY *pServerEntryPtr,
  190. PBOOLEAN pNewServerEntry,
  191. PRX_CONNECTION_ID RxConnectionId )
  192. /*++
  193. Routine Description:
  194. This routine searches the list of server entries and locates a matching
  195. entry or constructs a new one with the given name
  196. Arguments:
  197. pServerName - the name of the server
  198. ServerType - the type of server
  199. pServerEntryPtr - placeholder for the server entry
  200. pNewServerEntry - set to TRUE if it is a newly created server entry
  201. Notes:
  202. The SmbCeResource must be held on entry and its ownership state will remain
  203. unchanged on exit
  204. --*/
  205. {
  206. NTSTATUS Status = STATUS_SUCCESS;
  207. BOOLEAN fNewServerEntry = FALSE;
  208. PSMBCEDB_SERVER_ENTRY pServerEntry;
  209. RX_CONNECTION_ID LocalId;
  210. ASSERT(SmbCeIsResourceOwned());
  211. if( !RxConnectionId )
  212. {
  213. RtlZeroMemory( &LocalId, sizeof(RX_CONNECTION_ID) );
  214. RxConnectionId = &LocalId;
  215. }
  216. pServerEntry = SmbCeFindServerEntry(
  217. pServerName,
  218. ServerType,
  219. RxConnectionId);
  220. if (pServerEntry == NULL) {
  221. // Create a server instance, initialize its state, add it to the list
  222. pServerEntry = (PSMBCEDB_SERVER_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_SERVER);
  223. if (pServerEntry != NULL) {
  224. pServerEntry->Name.Buffer = RxAllocatePoolWithTag(
  225. NonPagedPool,
  226. pServerName->Length,
  227. MRXSMB_SERVER_POOLTAG);
  228. if (pServerEntry->Name.Buffer == NULL) {
  229. SmbMmFreeObject(pServerEntry);
  230. pServerEntry = NULL;
  231. }
  232. }
  233. if (pServerEntry != NULL) {
  234. fNewServerEntry = TRUE;
  235. pServerEntry->Name.Length = pServerName->Length;
  236. pServerEntry->Name.MaximumLength = pServerEntry->Name.Length;
  237. RtlCopyMemory(
  238. pServerEntry->Name.Buffer,
  239. pServerName->Buffer,
  240. pServerEntry->Name.Length);
  241. SmbCeUpdateServerEntryState(
  242. pServerEntry,
  243. SMBCEDB_CONSTRUCTION_IN_PROGRESS);
  244. SmbCeSetServerType(
  245. pServerEntry,
  246. ServerType);
  247. pServerEntry->PreferredTransport = NULL;
  248. SmbCeReferenceServerEntry(pServerEntry);
  249. SmbCeAddServerEntry(pServerEntry);
  250. pServerEntry->Server.IsRemoteBootServer = FALSE;
  251. if (MRxSmbBootedRemotely &&
  252. (MRxSmbRemoteBootShare.Length > pServerEntry->Name.Length)) {
  253. UNICODE_STRING RemoteBootServer;
  254. RemoteBootServer.Length = pServerEntry->Name.Length;
  255. RemoteBootServer.MaximumLength = pServerEntry->Name.MaximumLength;
  256. RemoteBootServer.Buffer = MRxSmbRemoteBootShare.Buffer;
  257. if (RtlEqualUnicodeString(
  258. &pServerEntry->Name,
  259. &RemoteBootServer,
  260. TRUE)) {
  261. pServerEntry->Server.IsRemoteBootServer = TRUE;
  262. }
  263. }
  264. pServerEntry->Server.IsFakeDfsServerForOfflineUse = FALSE;
  265. pServerEntry->Server.IsPinnedOffline = FALSE;
  266. pServerEntry->Server.SecurityMode = SECURITY_MODE_USER_LEVEL;
  267. RtlCopyMemory( &pServerEntry->ConnectionId, RxConnectionId, sizeof(RX_CONNECTION_ID) );
  268. if (SmbCeContext.ServersWithExtendedSessTimeout.Length != 0) {
  269. PWSTR pSmbMRxServers = (PWSTR)SmbCeContext.ServersWithExtendedSessTimeout.Buffer;
  270. UNICODE_STRING SmbMRxServer, TargetServer;
  271. TargetServer.Length = pServerEntry->Name.Length - sizeof(WCHAR);
  272. TargetServer.MaximumLength = pServerEntry->Name.MaximumLength;
  273. TargetServer.Buffer = &pServerEntry->Name.Buffer[1];
  274. while (*pSmbMRxServers) {
  275. SmbMRxServer.Length = wcslen(pSmbMRxServers) * sizeof(WCHAR);
  276. if (SmbMRxServer.Length == TargetServer.Length) {
  277. SmbMRxServer.MaximumLength = SmbMRxServer.Length;
  278. SmbMRxServer.Buffer = pSmbMRxServers;
  279. if (RtlCompareUnicodeString(
  280. &SmbMRxServer,
  281. &TargetServer,
  282. TRUE) == 0) {
  283. pServerEntry->Server.ExtendedSessTimeout = TRUE;
  284. //DbgPrint("Extended SessTimeout %wZ\n",&pServerEntry->Name);
  285. break;
  286. }
  287. }
  288. pSmbMRxServers += (SmbMRxServer.Length / sizeof(WCHAR) + 1);
  289. }
  290. }
  291. SmbCeLog(("NewSrvEntry %lx %wZ\n",pServerEntry,&pServerEntry->Name));
  292. SmbLog(LOG,
  293. SmbCeFindOrConstructServerEntry_1,
  294. LOGPTR(pServerEntry)
  295. LOGUSTR(pServerEntry->Name));
  296. } else {
  297. RxDbgTrace(0, Dbg, ("SmbCeOpenServer : Server Entry Allocation failed\n"));
  298. Status = STATUS_INSUFFICIENT_RESOURCES;
  299. }
  300. } else {
  301. if (pServerEntry->PreferredTransport != NULL) {
  302. // reset the preferred transport created by previous owner
  303. SmbCeDereferenceTransport(pServerEntry->PreferredTransport);
  304. pServerEntry->PreferredTransport = NULL;
  305. }
  306. SmbCeLog(("CachedSrvEntry %lx %wZ\n",pServerEntry,&pServerEntry->Name));
  307. SmbLog(LOG,
  308. SmbCeFindOrConstructServerEntry_2,
  309. LOGPTR(pServerEntry)
  310. LOGUSTR(pServerEntry->Name));
  311. }
  312. *pServerEntryPtr = pServerEntry;
  313. *pNewServerEntry = fNewServerEntry;
  314. return Status;
  315. }
  316. VOID
  317. SmbCeCompleteSrvCallConstruction(
  318. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
  319. /*++
  320. Routine Description:
  321. This routine comlpletes the srvcall construtcion routine by invoking
  322. the callback routine to the wrapper.
  323. Arguments:
  324. pCallbackContext - the RDBSS context
  325. Notes:
  326. --*/
  327. {
  328. PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure;
  329. PMRX_SRV_CALL pSrvCall;
  330. PSMBCEDB_SERVER_ENTRY pServerEntry;
  331. BOOLEAN MustSucceed = FALSE;
  332. NTSTATUS Status;
  333. PAGED_CODE();
  334. SrvCalldownStructure =
  335. (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
  336. pSrvCall = SrvCalldownStructure->SrvCall;
  337. pServerEntry = (PSMBCEDB_SERVER_ENTRY)pCallbackContext->RecommunicateContext;
  338. if (pServerEntry != NULL) {
  339. if (!NT_SUCCESS(pCallbackContext->Status)) {
  340. if (pServerEntry->Server.IsRemoteBootServer ||
  341. pCallbackContext->Status == STATUS_RETRY) {
  342. MustSucceed = TRUE;
  343. }
  344. SmbCeDereferenceServerEntry(pServerEntry);
  345. } else {
  346. if (SmbCeGetServerType(pServerEntry) == SMBCEDB_MAILSLOT_SERVER) {
  347. pServerEntry->Header.State = SMBCEDB_ACTIVE;
  348. }
  349. }
  350. } else {
  351. if (pCallbackContext->Status == STATUS_SUCCESS) {
  352. pCallbackContext->Status = STATUS_INSUFFICIENT_RESOURCES;
  353. }
  354. }
  355. if (MustSucceed) {
  356. //DbgPrint("Build ServerEntry %X try again.\n",pCallbackContext->Status);
  357. // in case it is the remote boot server, if the server entry cannot be created for some
  358. // reason, i.e. transport is not ready and the cache is not filled, we need to create the
  359. // server entry again until it succeeds.
  360. Status = RxDispatchToWorkerThread(
  361. MRxSmbDeviceObject,
  362. CriticalWorkQueue,
  363. SmbCeCreateSrvCall,
  364. pCallbackContext);
  365. } else {
  366. SrvCalldownStructure->CallBack(pCallbackContext);
  367. }
  368. }
  369. NTSTATUS
  370. SmbCeInitializeServerEntry(
  371. PMRX_SRV_CALL pSrvCall,
  372. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext,
  373. BOOLEAN fDeferNetworkInitialization)
  374. /*++
  375. Routine Description:
  376. This routine opens/creates a server entry in the connection engine database
  377. Arguments:
  378. pSrvCall - the SrvCall instance
  379. pCallbackContext - the RDBSS context
  380. Return Value:
  381. STATUS_SUCCESS - the server call construction has been finalized.
  382. Other Status codes correspond to error situations.
  383. Notes:
  384. --*/
  385. {
  386. NTSTATUS Status = STATUS_SUCCESS;
  387. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  388. BOOLEAN MailSlotCreate = FALSE;
  389. PSMBCE_TRANSPORT PreferredTransport = NULL;
  390. BOOLEAN fNewServerEntry = FALSE;
  391. SMBCEDB_SERVER_TYPE ServerType = SMBCEDB_FILE_SERVER;
  392. UNICODE_STRING TransportName;
  393. RX_CONNECTION_ID sRxConnectionId;
  394. // RxProfile(SmbCe,SmbCeOpenServer);
  395. ASSERT(pSrvCall->Context == NULL);
  396. TransportName = pCallbackContext->SrvCalldownStructure->RxContext->Create.TransportName;
  397. Status = MRxSmbGetConnectionId( pCallbackContext->SrvCalldownStructure->RxContext, &sRxConnectionId );
  398. if( !NT_SUCCESS(Status) )
  399. {
  400. DbgPrint( "MRXSMB: GetConnectionId failed.\n" );
  401. ASSERT(FALSE);
  402. RtlZeroMemory( &sRxConnectionId, sizeof(RX_CONNECTION_ID) );
  403. }
  404. if (TransportName.Length > 0) {
  405. if ((PreferredTransport=SmbCeFindTransport(&TransportName)) == NULL) {
  406. ASSERT(pCallbackContext->RecommunicateContext == NULL);
  407. Status = STATUS_NETWORK_UNREACHABLE;
  408. goto FINALLY;
  409. }
  410. }
  411. MailSlotCreate = BooleanFlagOn(
  412. pCallbackContext->SrvCalldownStructure->RxContext->Flags,
  413. RX_CONTEXT_FLAG_CREATE_MAILSLOT);
  414. if (MailSlotCreate) {
  415. fDeferNetworkInitialization = FALSE;
  416. ServerType = SMBCEDB_MAILSLOT_SERVER;
  417. }
  418. SmbCeAcquireResource();
  419. Status = SmbCeFindOrConstructServerEntry(
  420. pSrvCall->pSrvCallName,
  421. ServerType,
  422. &pServerEntry,
  423. &fNewServerEntry,
  424. &sRxConnectionId);
  425. SmbCeReleaseResource();
  426. pCallbackContext->RecommunicateContext = pServerEntry;
  427. if (Status == STATUS_SUCCESS) {
  428. ASSERT(pServerEntry != NULL);
  429. InterlockedExchangePointer(
  430. &pServerEntry->pRdbssSrvCall,
  431. pSrvCall);
  432. Status = SmbCeUpdateSrvCall(pServerEntry);
  433. if(!SmbCeIsServerInDisconnectedMode(pServerEntry)) {
  434. if (Status == STATUS_SUCCESS) {
  435. if (PreferredTransport != NULL) {
  436. // Transfer the ownership of the preferred transport to the
  437. // server entry.
  438. pServerEntry->PreferredTransport = PreferredTransport;
  439. PreferredTransport = NULL;
  440. } else {
  441. pServerEntry->PreferredTransport = NULL;
  442. }
  443. if (fNewServerEntry) {
  444. pServerEntry->Header.State = SMBCEDB_INVALID;
  445. // Initialize the mailslot server parameters.
  446. pServerEntry->Server.Dialect = LANMAN21_DIALECT;
  447. // MaximumBufferSize will be set based on negotiate response
  448. pServerEntry->Server.MaximumBufferSize = 0xffff;
  449. Status = CscInitializeServerEntryDfsRoot(
  450. pCallbackContext->SrvCalldownStructure->RxContext,
  451. pServerEntry);
  452. }
  453. if (Status == STATUS_SUCCESS) {
  454. if (!fDeferNetworkInitialization &&
  455. !MailSlotCreate) {
  456. Status = SmbCeInitializeServerTransport(
  457. pServerEntry,
  458. SmbCeCompleteSrvCallConstruction,
  459. pCallbackContext);
  460. } else {
  461. Status = SmbCeInitializeServerMailSlotTransport(
  462. pServerEntry,
  463. SmbCeCompleteSrvCallConstruction,
  464. pCallbackContext);
  465. }
  466. }
  467. }
  468. }
  469. }
  470. FINALLY:
  471. if (Status != STATUS_PENDING) {
  472. pCallbackContext->Status = Status;
  473. SmbCeCompleteSrvCallConstruction(pCallbackContext);
  474. }
  475. if (PreferredTransport != NULL) {
  476. SmbCeDereferenceTransport(PreferredTransport);
  477. }
  478. return STATUS_PENDING;
  479. }
  480. NTSTATUS
  481. SmbCeUpdateSrvCall(
  482. PSMBCEDB_SERVER_ENTRY pServerEntry)
  483. /*++
  484. Routine Description:
  485. This routine initializes the wrapper data structure corresponding to a
  486. given server entry.
  487. Arguments:
  488. pServerEntry - the server entry
  489. Return Value:
  490. STATUS_SUCCESS if successful
  491. --*/
  492. {
  493. NTSTATUS Status = STATUS_SUCCESS;
  494. PMRX_SRV_CALL pSrvCall = pServerEntry->pRdbssSrvCall;
  495. PAGED_CODE();
  496. if (pSrvCall != NULL) {
  497. // Copy the domain name into the server entry
  498. Status = RxSetSrvCallDomainName(
  499. pSrvCall,
  500. &pServerEntry->DomainName);
  501. // Initialize the SrvCall flags based upon the capabilities of the remote
  502. // server. The only flags that the SMB mini redirector updates are the
  503. // SRVCALL_FLAG_DFS_AWARE and SRVCALL_FLAG_LWIO_AWARE
  504. if (pServerEntry->Server.Capabilities & CAP_DFS) {
  505. SetFlag(
  506. pSrvCall->Flags,
  507. SRVCALL_FLAG_DFS_AWARE_SERVER);
  508. }
  509. if (pServerEntry->Server.Capabilities & LWIO_CAPABILITY) {
  510. SetFlag(
  511. pSrvCall->Flags,
  512. SRVCALL_FLAG_LWIO_AWARE_SERVER);
  513. }
  514. if (pServerEntry->Server.IsLoopBack) {
  515. SetFlag(
  516. pSrvCall->Flags,
  517. SRVCALL_FLAG_LOOPBACK_SERVER);
  518. }
  519. }
  520. return Status;
  521. }
  522. BOOLEAN
  523. SmbCeAreServerEntriesAliased(
  524. PSMBCEDB_SERVER_ENTRY pServerEntry1,
  525. PSMBCEDB_SERVER_ENTRY pServerEntry2)
  526. /*++
  527. Routine Description:
  528. This routine is used to determine if two server entries are aliased. For uplevel
  529. servers (NT5 or greater) the server GUID can be used to determine if the two
  530. server entries are aliased. For downlevel servers it is determined by checking if
  531. they have the same IP address.
  532. Arguments:
  533. pServerEntry1 - the first server entry
  534. pServerEntry2 - the second server entry
  535. Return Value:
  536. TRUE if the two server entries are aliased and FALSE otherwise
  537. Notes:
  538. There are two interesting points to note ...
  539. 1) a server entry cannot be an alias of itself. The first test in the implementation.
  540. This semantic makes checking a server entry against a collection of entries easy.
  541. 2) the mechanism that we have for detecting aliases is not complete. There are cases
  542. (downlevel) when the two server entries are aliases of each other but we will conclude
  543. otherwise. This is because there is no foolproof way of establishing the absence of
  544. aliasing. The algorithm that is currently implemented detects the most important case
  545. of aliasing, i.e., DNS names and NETBIOS names to the same server on TCP.
  546. --*/
  547. {
  548. BOOLEAN ServerEntriesAliased = FALSE;
  549. if (pServerEntry1 != pServerEntry2) {
  550. if (BooleanFlagOn(
  551. pServerEntry1->Server.DialectFlags,
  552. DF_EXTENDED_SECURITY) &&
  553. BooleanFlagOn(
  554. pServerEntry2->Server.DialectFlags,
  555. DF_EXTENDED_SECURITY)) {
  556. if (RtlEqualMemory(
  557. &pServerEntry1->Server.NtServer.ServerGuid,
  558. &pServerEntry2->Server.NtServer.ServerGuid,
  559. sizeof(GUID))) {
  560. ServerEntriesAliased = TRUE;
  561. }
  562. } else {
  563. if ((pServerEntry1->Server.IpAddress == pServerEntry2->Server.IpAddress) &&
  564. (pServerEntry1->Server.IpAddress != 0)) {
  565. ServerEntriesAliased = TRUE;
  566. }
  567. }
  568. }
  569. return ServerEntriesAliased;
  570. }
  571. VOID
  572. SmbCeCompleteServerEntryInitialization(
  573. PSMBCEDB_SERVER_ENTRY pServerEntry,
  574. NTSTATUS Status)
  575. /*++
  576. Routine Description:
  577. This routine is invoked in the context of a worker thread to finalize the
  578. construction of a server entry
  579. Arguments:
  580. pServerEntry - the server entry to be finalized
  581. ServerState - the final state of the server
  582. --*/
  583. {
  584. NTSTATUS ServerStatus;
  585. SMBCEDB_OBJECT_STATE PreviousState;
  586. SMBCEDB_REQUESTS ReconnectRequests;
  587. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  588. KIRQL SavedIrql;
  589. RxDbgTrace( 0, Dbg, ("Server Entry Finalization\n"));
  590. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  591. InitializeListHead(&ReconnectRequests.ListHead);
  592. // Acquire the SMBCE resource
  593. SmbCeAcquireResource();
  594. SmbCeAcquireSpinLock();
  595. // The server status could have changed because of the transport disconnects
  596. // from the time the admin exchange was completed to the time the server
  597. // entry initialization complete routine is called. Update the state
  598. // accordingly.
  599. PreviousState = pServerEntry->Header.State;
  600. if (PreviousState == SMBCEDB_CONSTRUCTION_IN_PROGRESS) {
  601. pServerEntry->ServerStatus = Status;
  602. if (Status == STATUS_SUCCESS) {
  603. pServerEntry->Header.State = SMBCEDB_ACTIVE;
  604. } else {
  605. pServerEntry->Header.State = SMBCEDB_INVALID;
  606. }
  607. }
  608. ServerStatus = pServerEntry->ServerStatus;
  609. pServerEntry->NegotiateInProgress = FALSE;
  610. // Weed out all the reconnect requests so that they can be resumed
  611. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  612. while (pRequestEntry != NULL) {
  613. if (pRequestEntry->GenericRequest.Type == RECONNECT_REQUEST) {
  614. PSMBCEDB_REQUEST_ENTRY pTempRequestEntry;
  615. pTempRequestEntry = pRequestEntry;
  616. pRequestEntry = SmbCeGetNextRequestEntry(
  617. &pServerEntry->OutstandingRequests,
  618. pRequestEntry);
  619. SmbCeRemoveRequestEntryLite(
  620. &pServerEntry->OutstandingRequests,
  621. pTempRequestEntry);
  622. SmbCeAddRequestEntryLite(
  623. &ReconnectRequests,
  624. pTempRequestEntry);
  625. } else {
  626. pRequestEntry = SmbCeGetNextRequestEntry(
  627. &pServerEntry->OutstandingRequests,
  628. pRequestEntry);
  629. }
  630. }
  631. pServerEntry->Server.NumberOfVNetRootContextsForScavenging = 0;
  632. pServerEntry->Server.AliasedServers = FALSE;
  633. if ((Status == STATUS_SUCCESS) && (ServerStatus == STATUS_SUCCESS)) {
  634. // Walk through the list of currently active servers to establish the
  635. // session numbering. This traversal is required because of server
  636. // name aliasing that occurs when the different name formats are used
  637. // to access the server, i.e., dotted IP address, DNS name, NETBIOS name.
  638. // The disambiguation between different servers is done in one of two
  639. // ways. For uplevel servers ( NT5.0 or later ) the Server GUID is used.
  640. // For downlevel servers ( NT 4.0 or before ) the IP address is used
  641. // to distinguish the two. Note that there is one case that is not
  642. // covered by the current solution, the connection using a NETBIOS
  643. // name is established over some transport other than NetBt and this
  644. // is followed by establishing a connection establishment using the
  645. // DNS name over NetBt. In such cases this numbering scheme fails. In
  646. // some ways there is no complete solution for this once we start using
  647. // *SMBSERVER names as opposed to the NETBIOS name for connection
  648. // establishment with dotted IP address.
  649. PSMBCEDB_SERVER_ENTRY pTempServerEntry;
  650. pTempServerEntry = SmbCeGetFirstServerEntry();
  651. while (pTempServerEntry != NULL) {
  652. if (pTempServerEntry->Header.State == SMBCEDB_ACTIVE) {
  653. if (SmbCeAreServerEntriesAliased(
  654. pServerEntry,
  655. pTempServerEntry)) {
  656. pServerEntry->Server.AliasedServers = TRUE;
  657. pTempServerEntry->Server.AliasedServers = TRUE;
  658. }
  659. }
  660. pTempServerEntry = SmbCeGetNextServerEntry(pTempServerEntry);
  661. }
  662. }
  663. SmbCeReleaseSpinLock();
  664. if ((Status == STATUS_SUCCESS) &&
  665. (ServerStatus == STATUS_SUCCESS) &&
  666. (PreviousState == SMBCEDB_CONSTRUCTION_IN_PROGRESS)) {
  667. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  668. SESSION_TYPE SessionType;
  669. InterlockedIncrement(&pServerEntry->Server.Version);
  670. pServerEntry->Server.NumberOfSrvOpens = 0;
  671. ASSERT(pServerEntry->pMidAtlas == NULL);
  672. // Initialize the MID Atlas
  673. pServerEntry->pMidAtlas = FsRtlCreateMidAtlas(
  674. pServerEntry->Server.MaximumRequests,
  675. pServerEntry->Server.MaximumRequests);
  676. if (pServerEntry->pMidAtlas == NULL) {
  677. pServerEntry->ServerStatus = RX_MAP_STATUS(INSUFFICIENT_RESOURCES);
  678. }
  679. if (MRxSmbSecuritySignaturesEnabled &&
  680. pServerEntry->Server.SecuritySignaturesEnabled) {
  681. pServerEntry->SecuritySignaturesEnabled = TRUE;
  682. } else {
  683. pServerEntry->SecuritySignaturesEnabled = FALSE;
  684. }
  685. // The sessions that have been created but whose initialization has been
  686. // deferred will have the session types set incorrectly. This is because
  687. // there is no previous knowledge of the session type required for deferred
  688. // servers.
  689. if (pServerEntry->Server.DialectFlags & DF_EXTENDED_SECURITY) {
  690. SessionType = EXTENDED_NT_SESSION;
  691. } else {
  692. SessionType = LANMAN_SESSION;
  693. }
  694. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  695. while (pSessionEntry != NULL) {
  696. if (!FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
  697. pSessionEntry->Session.Type = SessionType;
  698. } else {
  699. pSessionEntry->Session.Type = LANMAN_SESSION;
  700. }
  701. pSessionEntry = SmbCeGetNextSessionEntry(
  702. pServerEntry,
  703. pSessionEntry);
  704. }
  705. MRxSmbCheckForLoopBack(pServerEntry);
  706. }
  707. // Release the resource for the server entry
  708. SmbCeReleaseResource();
  709. // Resume all the outstanding reconnect requests that were held up because an earlier
  710. // reconnect request was under way.
  711. // Iterate over the list of pending requests and resume all of them
  712. SmbCeResumeOutstandingRequests(&ReconnectRequests,ServerStatus);
  713. }
  714. VOID
  715. SmbCepDereferenceServerEntry(
  716. PSMBCEDB_SERVER_ENTRY pServerEntry)
  717. /*++
  718. Routine Description:
  719. This routine dereferences a server entry instance
  720. Arguments:
  721. pServerEntry - the server entry to be dereferenced
  722. --*/
  723. {
  724. if (pServerEntry != NULL) {
  725. BOOLEAN fTearDownEntry = FALSE;
  726. LONG FinalRefCount;
  727. ASSERT((pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER) &&
  728. (pServerEntry->Header.SwizzleCount > 0));
  729. SmbCeAcquireResource();
  730. SmbCeAcquireSpinLock();
  731. /* if this is a work item request then clear the flag */
  732. /* WorkerRoutine is set to NULL just before work items are called */
  733. if((pServerEntry->WorkQueueItemForDisconnect.WorkerRoutine == NULL) &&
  734. pServerEntry->DisconnectWorkItemOutstanding == TRUE) {
  735. pServerEntry->DisconnectWorkItemOutstanding = FALSE;
  736. }
  737. FinalRefCount = InterlockedDecrement(&pServerEntry->Header.SwizzleCount);
  738. fTearDownEntry = (FinalRefCount == 0);
  739. if (fTearDownEntry) {
  740. // This is to ensure that the routines for traversing the server
  741. // entry list, i.e., probing servers do not colide with the teardown.
  742. if (pServerEntry->Header.SwizzleCount == 0) {
  743. pServerEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION;
  744. SmbCeRemoveServerEntryLite(pServerEntry);
  745. if (SmbCeGetFirstServerEntry() == NULL &&
  746. SmbCeStartStopContext.pServerEntryTearDownEvent != NULL) {
  747. KeSetEvent(SmbCeStartStopContext.pServerEntryTearDownEvent,0,FALSE);
  748. }
  749. } else {
  750. fTearDownEntry = FALSE;
  751. }
  752. }
  753. SmbCeReleaseSpinLock();
  754. SmbCeReleaseResource();
  755. if (fTearDownEntry) {
  756. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  757. SmbCeTearDownServerEntry(pServerEntry);
  758. } else {
  759. InitializeListHead(&pServerEntry->WorkQueueItem.List);
  760. RxPostToWorkerThread(
  761. MRxSmbDeviceObject,
  762. CriticalWorkQueue,
  763. &pServerEntry->WorkQueueItem,
  764. SmbCeTearDownServerEntry,
  765. pServerEntry);
  766. }
  767. }
  768. }
  769. }
  770. VOID
  771. SmbCeTearDownServerEntry(
  772. PSMBCEDB_SERVER_ENTRY pServerEntry)
  773. /*++
  774. Routine Description:
  775. This routine tears down a server entry instance
  776. Arguments:
  777. pServerEntry - the server entry to be dereferenced
  778. --*/
  779. {
  780. NTSTATUS Status = STATUS_SUCCESS;
  781. PAGED_CODE();
  782. SmbCeLog(("TearSrvEntry %lx %wZ\n",pServerEntry,&pServerEntry->Name));
  783. SmbLog(LOG,
  784. SmbCeTearDownServerEntry,
  785. LOGPTR(pServerEntry)
  786. LOGUSTR(pServerEntry->Name));
  787. ASSERT(pServerEntry->Header.State == SMBCEDB_MARKED_FOR_DELETION);
  788. if (pServerEntry->pMidAtlas != NULL) {
  789. FsRtlDestroyMidAtlas(pServerEntry->pMidAtlas,NULL);
  790. pServerEntry->pMidAtlas = NULL;
  791. }
  792. if (pServerEntry->pTransport != NULL ||
  793. pServerEntry->pMailSlotTransport != NULL) {
  794. Status = SmbCeUninitializeServerTransport(pServerEntry,NULL,NULL);
  795. ASSERT(Status == STATUS_SUCCESS);
  796. }
  797. if (pServerEntry->Server.NtServer.pSecurityBlob != NULL) {
  798. RxFreePool(pServerEntry->Server.NtServer.pSecurityBlob);
  799. }
  800. if (pServerEntry->Name.Buffer != NULL) {
  801. RxFreePool(pServerEntry->Name.Buffer);
  802. }
  803. if (pServerEntry->DomainName.Buffer != NULL) {
  804. RxFreePool(pServerEntry->DomainName.Buffer);
  805. }
  806. if (pServerEntry->DfsRootName.Buffer != NULL) {
  807. RxFreePool(pServerEntry->DfsRootName.Buffer);
  808. }
  809. if (pServerEntry->DnsName.Buffer != NULL) {
  810. RxFreePool(pServerEntry->DnsName.Buffer);
  811. }
  812. if (pServerEntry->PreferredTransport != NULL) {
  813. SmbCeDereferenceTransport(pServerEntry->PreferredTransport);
  814. }
  815. SmbMmFreeObject(pServerEntry);
  816. }
  817. NTSTATUS
  818. SmbCeFindOrConstructSessionEntry(
  819. PMRX_V_NET_ROOT pVNetRoot,
  820. PSMBCEDB_SESSION_ENTRY *pSessionEntryPtr)
  821. /*++
  822. Routine Description:
  823. This routine opens/creates a session for a given user in the connection engine database
  824. Arguments:
  825. pVNetRoot - the RDBSS Virtual net root instance
  826. Return Value:
  827. STATUS_SUCCESS - if successful
  828. Other Status codes correspond to error situations.
  829. Notes:
  830. This routine assumes that the necesary concurreny control mechanism has already
  831. been taken.
  832. On Entry the connection engine resource must have been acquired exclusive and
  833. ownership remains invariant on exit.
  834. In case of UPN, we should pass a NULL string instead of NULL as domain name.
  835. --*/
  836. {
  837. NTSTATUS Status = STATUS_SUCCESS;
  838. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  839. PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL;
  840. BOOLEAN fSessionEntryFound = FALSE;
  841. PUNICODE_STRING UserName;
  842. PUNICODE_STRING Password;
  843. PUNICODE_STRING UserDomainName;
  844. DWORD SessionType;
  845. LUID AnonymousLogonID = ANONYMOUS_LOGON_LUID;
  846. #define SessionTypeDefault 1
  847. #define SessionTypeUser 2
  848. #define SessionTypeNull 3
  849. #define SessionTypeRemoteBoot 4
  850. ASSERT(SmbCeIsResourceOwned());
  851. UserName = pVNetRoot->pUserName;
  852. Password = pVNetRoot->pPassword;
  853. UserDomainName = pVNetRoot->pUserDomainName;
  854. //
  855. // If this is a remote boot client, and we're connecting to the boot share,
  856. // we always use the machine account, not the user account. This is
  857. // necessary in order to get security (ACL checking) to behave correctly.
  858. //
  859. SessionType = SessionTypeDefault;
  860. if ( MRxSmbBootedRemotely ) {
  861. //DbgPrint( "FindOrConstructSessionEntry: root %wZ\n", pVNetRoot->pNetRoot->pNetRootName );
  862. //DbgBreakPoint();
  863. if ( RtlCompareUnicodeString(
  864. pVNetRoot->pNetRoot->pNetRootName,
  865. &MRxSmbRemoteBootShare,
  866. TRUE
  867. ) == 0 ) {
  868. SessionType = SessionTypeRemoteBoot;
  869. //DbgPrint( " Original user/password/domain: %wZ/%wZ/%wZ\n", UserName, Password, UserDomainName );
  870. UserName = &MRxSmbRemoteBootMachineName;
  871. Password = &MRxSmbRemoteBootMachinePassword;
  872. UserDomainName = &MRxSmbRemoteBootMachineDomain;
  873. //DbgPrint( " Machine user/password/domain: %wZ/%wZ/%wZ\n", UserName, Password, UserDomainName );
  874. }
  875. }
  876. if (SessionType != SessionTypeRemoteBoot) {
  877. if ((UserName != NULL) &&
  878. (UserName->Length == 0) &&
  879. (Password != NULL) &&
  880. (Password->Length == 0) &&
  881. (UserDomainName != NULL) &&
  882. (UserDomainName->Length == 0)) {
  883. SessionType = SessionTypeNull;
  884. } else if ((UserName != NULL) ||
  885. ((Password != NULL) &&
  886. (Password->Length > 0))) {
  887. SessionType = SessionTypeUser;
  888. }
  889. }
  890. *pSessionEntryPtr = NULL;
  891. // Reference the server handle
  892. pServerEntry = SmbCeReferenceAssociatedServerEntry(pVNetRoot->pNetRoot->pSrvCall);
  893. if (pServerEntry != NULL) {
  894. if (SessionType != SessionTypeUser &&
  895. pServerEntry->Server.SecurityMode != SECURITY_MODE_SHARE_LEVEL) {
  896. SmbCeAcquireSpinLock();
  897. // Rule No. 1
  898. // 1) The first session with explicitly specified credentials will be treated as the
  899. // default session for all subsequent requests to any given server.
  900. if (SessionType == SessionTypeDefault) {
  901. pSessionEntry = SmbCeGetDefaultSessionEntry(
  902. pServerEntry,
  903. pVNetRoot->SessionId,
  904. &pVNetRoot->LogonId);
  905. while (pSessionEntry != NULL &&
  906. FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION)) {
  907. SmbCeRemoveDefaultSessionEntry(pSessionEntry);
  908. pSessionEntry = SmbCeGetDefaultSessionEntry(
  909. pServerEntry,
  910. pVNetRoot->SessionId,
  911. &pVNetRoot->LogonId);
  912. }
  913. }
  914. if (pSessionEntry == NULL) {
  915. // Enumerate the sessions to detect if a session satisfying rule 2 exists
  916. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  917. while (pSessionEntry != NULL) {
  918. if (!FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION)) {
  919. if (SessionType == SessionTypeDefault) {
  920. //
  921. // Rule No. 2
  922. // 2) If no session with explicitly specified credentials exist then a
  923. // session with the same logon id. is choosen.
  924. //
  925. if (RtlEqualLuid(
  926. &pSessionEntry->Session.LogonId,
  927. &pVNetRoot->LogonId)) {
  928. break;
  929. }
  930. } else if (SessionType == SessionTypeNull) {
  931. if (FlagOn(
  932. pSessionEntry->Session.Flags,
  933. SMBCE_SESSION_FLAGS_NULL_CREDENTIALS)) {
  934. break;
  935. }
  936. } else {
  937. ASSERT(SessionType == SessionTypeRemoteBoot);
  938. if (FlagOn(
  939. pSessionEntry->Session.Flags,
  940. SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION)) {
  941. break;
  942. }
  943. }
  944. }
  945. pSessionEntry = SmbCeGetNextSessionEntry(pServerEntry,pSessionEntry);
  946. }
  947. }
  948. if (pSessionEntry != NULL) {
  949. SmbCeReferenceSessionEntry(pSessionEntry);
  950. }
  951. SmbCeReleaseSpinLock();
  952. } else {
  953. BOOLEAN SessionEntryFound = FALSE;
  954. SmbCeAcquireSpinLock();
  955. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  956. if (pSessionEntry != NULL) {
  957. SmbCeReferenceSessionEntry(pSessionEntry);
  958. }
  959. SmbCeReleaseSpinLock();
  960. while ((pSessionEntry != NULL) && !SessionEntryFound) {
  961. if (!FlagOn(pSessionEntry->Session.Flags,
  962. SMBCE_SESSION_FLAGS_NULL_CREDENTIALS |
  963. SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION |
  964. SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION)) {
  965. PSecurityUserData pSecurityData = NULL;
  966. if (pServerEntry->Server.SecurityMode != SECURITY_MODE_SHARE_LEVEL) {
  967. for (;;) {
  968. PSMBCE_SESSION pSession = &pSessionEntry->Session;
  969. PUNICODE_STRING TempUserName,TempUserDomainName;
  970. // For each existing session check to determine if the credentials
  971. // supplied match the credentials used to construct the session.
  972. if( pSession->SessionId != pVNetRoot->SessionId ) {
  973. break;
  974. }
  975. if (!RtlEqualLuid(
  976. &pSessionEntry->Session.LogonId,
  977. &pVNetRoot->LogonId)) {
  978. break;
  979. }
  980. TempUserName = pSession->pUserName;
  981. TempUserDomainName = pSession->pUserDomainName;
  982. if (TempUserName == NULL ||
  983. TempUserDomainName == NULL) {
  984. Status = GetSecurityUserInfo(
  985. &pVNetRoot->LogonId,
  986. UNDERSTANDS_LONG_NAMES,
  987. &pSecurityData);
  988. if (NT_SUCCESS(Status)) {
  989. if (TempUserName == NULL) {
  990. TempUserName = &(pSecurityData->UserName);
  991. }
  992. if (TempUserDomainName == NULL) {
  993. TempUserDomainName = &(pSecurityData->LogonDomainName);
  994. }
  995. } else {
  996. break;
  997. }
  998. }
  999. if (UserName != NULL &&
  1000. !RtlEqualUnicodeString(UserName,TempUserName,TRUE)) {
  1001. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  1002. break;
  1003. }
  1004. if (UserDomainName != NULL &&
  1005. !RtlEqualUnicodeString(UserDomainName,TempUserDomainName,TRUE)) {
  1006. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  1007. break;
  1008. }
  1009. if ((Password != NULL) &&
  1010. (pSession->pPassword != NULL)) {
  1011. if (!RtlEqualUnicodeString(
  1012. Password,
  1013. pSession->pPassword,
  1014. FALSE)) {
  1015. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  1016. break;
  1017. }
  1018. }
  1019. SessionEntryFound = TRUE;
  1020. // We use existing session if either the stored or new password is NULL.
  1021. // Later, a new security API will be created for verify the password
  1022. // based on the logon ID.
  1023. // An entry that matches the credentials supplied has been found. use it.
  1024. break;
  1025. }
  1026. //ASSERT(Status != STATUS_NETWORK_CREDENTIAL_CONFLICT);
  1027. if (pSecurityData != NULL) {
  1028. LsaFreeReturnBuffer(pSecurityData);
  1029. pSecurityData = NULL;
  1030. }
  1031. } else {
  1032. if (RtlEqualLuid(
  1033. &pSessionEntry->Session.LogonId,
  1034. &pVNetRoot->LogonId)) {
  1035. // For share level security, each share will have a different session
  1036. if (pSessionEntry->pNetRootName != NULL) {
  1037. if (RtlEqualUnicodeString(
  1038. pVNetRoot->pNetRoot->pNetRootName,
  1039. pSessionEntry->pNetRootName,
  1040. FALSE)) {
  1041. SessionEntryFound = TRUE;
  1042. }
  1043. }
  1044. }
  1045. }
  1046. }
  1047. if (!SessionEntryFound) {
  1048. if (Status == STATUS_SUCCESS) {
  1049. PSMBCEDB_SESSION_ENTRY pNextSessionEntry;
  1050. SmbCeAcquireSpinLock();
  1051. pNextSessionEntry = SmbCeGetNextSessionEntry(
  1052. pServerEntry,
  1053. pSessionEntry);
  1054. if (pNextSessionEntry != NULL) {
  1055. SmbCeReferenceSessionEntry(pNextSessionEntry);
  1056. }
  1057. SmbCeReleaseSpinLock();
  1058. SmbCeDereferenceSessionEntry(pSessionEntry);
  1059. pSessionEntry = pNextSessionEntry;
  1060. } else {
  1061. // An error situation was encountered. Terminate the iteration.
  1062. // Typically a set of conflicting credentials have been presented
  1063. SmbCeDereferenceSessionEntry(pSessionEntry);
  1064. pSessionEntry = NULL;
  1065. }
  1066. } else {
  1067. if (RtlEqualLuid(&pSessionEntry->Session.LogonId,&AnonymousLogonID) &&
  1068. (Password != NULL || UserName != NULL || UserDomainName != NULL)) {
  1069. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  1070. }
  1071. }
  1072. }
  1073. }
  1074. if (Win9xSessionRestriction &&
  1075. (pSessionEntry == NULL) &&
  1076. (Status == STATUS_SUCCESS) &&
  1077. FlagOn(pServerEntry->Server.DialectFlags,DF_W95)) {
  1078. PSMBCEDB_SESSION_ENTRY TempSessionEntry;
  1079. TempSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  1080. while (TempSessionEntry != NULL) {
  1081. if (!FlagOn(TempSessionEntry->Session.Flags,
  1082. SMBCE_SESSION_FLAGS_NULL_CREDENTIALS)) {
  1083. Status = STATUS_LOGIN_WKSTA_RESTRICTION;
  1084. break;
  1085. }
  1086. TempSessionEntry = SmbCeGetNextSessionEntry(pServerEntry,TempSessionEntry);
  1087. }
  1088. }
  1089. if ((pSessionEntry == NULL) && (Status == STATUS_SUCCESS)) {
  1090. // Rule No. 3
  1091. // 3) If no session with the same logon id. exists a new session is created.
  1092. //
  1093. // Allocate a new session entry
  1094. // This is the point at which a many to mapping between session entries and
  1095. // V_NET_ROOT's in the RDBSS is being established. From this point it is
  1096. // true that the session entry can outlive the associated V_NET_ROOT entry.
  1097. // Therefore copies of the parameters used in the session setup need be made.
  1098. PSMBCE_SESSION pSession = &pSessionEntry->Session;
  1099. PUNICODE_STRING pPassword,pUserName,pUserDomainName,pNetRootName;
  1100. if (Password != NULL) {
  1101. pPassword = (PUNICODE_STRING)
  1102. RxAllocatePoolWithTag(
  1103. NonPagedPool,
  1104. sizeof(UNICODE_STRING) + Password->Length,
  1105. MRXSMB_SESSION_POOLTAG);
  1106. if (pPassword != NULL) {
  1107. pPassword->Buffer = (PWCHAR)((PCHAR)pPassword + sizeof(UNICODE_STRING));
  1108. pPassword->Length = Password->Length;
  1109. pPassword->MaximumLength = pPassword->Length;
  1110. RtlCopyMemory(
  1111. pPassword->Buffer,
  1112. Password->Buffer,
  1113. pPassword->Length);
  1114. } else {
  1115. Status = STATUS_INSUFFICIENT_RESOURCES;
  1116. }
  1117. } else {
  1118. pPassword = NULL;
  1119. }
  1120. if ((UserName != NULL) &&
  1121. (Status == RX_MAP_STATUS(SUCCESS))) {
  1122. pUserName = (PUNICODE_STRING)
  1123. RxAllocatePoolWithTag(
  1124. NonPagedPool,
  1125. sizeof(UNICODE_STRING) + UserName->Length,
  1126. MRXSMB_SESSION_POOLTAG);
  1127. if (pUserName != NULL) {
  1128. pUserName->Buffer = (PWCHAR)((PCHAR)pUserName + sizeof(UNICODE_STRING));
  1129. pUserName->Length = UserName->Length;
  1130. pUserName->MaximumLength = pUserName->Length;
  1131. RtlCopyMemory(
  1132. pUserName->Buffer,
  1133. UserName->Buffer,
  1134. pUserName->Length);
  1135. } else {
  1136. Status = STATUS_INSUFFICIENT_RESOURCES;
  1137. }
  1138. } else {
  1139. pUserName = NULL;
  1140. }
  1141. if ((UserDomainName != NULL) &&
  1142. (Status == RX_MAP_STATUS(SUCCESS))) {
  1143. pUserDomainName = (PUNICODE_STRING)
  1144. RxAllocatePoolWithTag(
  1145. NonPagedPool,
  1146. sizeof(UNICODE_STRING) + UserDomainName->Length + sizeof(WCHAR),
  1147. MRXSMB_SESSION_POOLTAG);
  1148. if (pUserDomainName != NULL) {
  1149. pUserDomainName->Buffer = (PWCHAR)((PCHAR)pUserDomainName + sizeof(UNICODE_STRING));
  1150. pUserDomainName->Length = UserDomainName->Length;
  1151. pUserDomainName->MaximumLength = pUserDomainName->Length;
  1152. // in case of UPN name, domain name will be a NULL string
  1153. *pUserDomainName->Buffer = 0;
  1154. if (UserDomainName->Length > 0) {
  1155. RtlCopyMemory(
  1156. pUserDomainName->Buffer,
  1157. UserDomainName->Buffer,
  1158. pUserDomainName->Length);
  1159. }
  1160. } else {
  1161. Status = STATUS_INSUFFICIENT_RESOURCES;
  1162. }
  1163. } else {
  1164. pUserDomainName = NULL;
  1165. }
  1166. if (pServerEntry->Server.SecurityMode == SECURITY_MODE_SHARE_LEVEL) {
  1167. pNetRootName = (PUNICODE_STRING)RxAllocatePoolWithTag(
  1168. NonPagedPool,
  1169. sizeof(UNICODE_STRING) +
  1170. pVNetRoot->pNetRoot->pNetRootName->Length,
  1171. MRXSMB_SESSION_POOLTAG);
  1172. if (pNetRootName != NULL) {
  1173. pNetRootName->Buffer = (PWCHAR)((PCHAR)pNetRootName + sizeof(UNICODE_STRING));
  1174. pNetRootName->Length = pVNetRoot->pNetRoot->pNetRootName->Length;
  1175. pNetRootName->MaximumLength = pNetRootName->Length;
  1176. if (pNetRootName->Length > 0) {
  1177. RtlCopyMemory(
  1178. pNetRootName->Buffer,
  1179. pVNetRoot->pNetRoot->pNetRootName->Buffer,
  1180. pNetRootName->Length);
  1181. }
  1182. } else {
  1183. Status = STATUS_INSUFFICIENT_RESOURCES;
  1184. }
  1185. } else {
  1186. pNetRootName = NULL;
  1187. }
  1188. if (Status == STATUS_SUCCESS) {
  1189. pSessionEntry = SmbMmAllocateSessionEntry(
  1190. pServerEntry,
  1191. (BOOLEAN)(SessionType == SessionTypeRemoteBoot));
  1192. if (pSessionEntry != NULL) {
  1193. PSMBCE_SESSION pSession = & pSessionEntry->Session;
  1194. SmbCeLog(("NewSessEntry %lx\n",pSessionEntry));
  1195. SmbLog(LOG,
  1196. SmbCeFindOrConstructSessionEntry_1,
  1197. LOGPTR(pSessionEntry));
  1198. pSessionEntry->Header.State = SMBCEDB_INVALID;
  1199. pSessionEntry->pServerEntry = pServerEntry;
  1200. pSessionEntry->pNetRootName = pNetRootName;
  1201. if (pServerEntry->Server.SecurityMode == SECURITY_MODE_SHARE_LEVEL) {
  1202. pSessionEntry->Session.UserId = (SMB_USER_ID)SMBCE_SHARE_LEVEL_SERVER_USERID;
  1203. }
  1204. pSession->Flags = 0;
  1205. if ( SessionType == SessionTypeRemoteBoot ) {
  1206. pSession->Flags = SMBCE_SESSION_FLAGS_REMOTE_BOOT_SESSION;
  1207. }
  1208. if ( SessionType == SessionTypeNull ) {
  1209. pSession->Flags |= SMBCE_SESSION_FLAGS_NULL_CREDENTIALS;
  1210. }
  1211. pSession->LogonId = pVNetRoot->LogonId;
  1212. pSession->pUserName = pUserName;
  1213. pSession->pPassword = pPassword;
  1214. pSession->pUserDomainName = pUserDomainName;
  1215. pSession->SessionId = pVNetRoot->SessionId;
  1216. SmbCeReferenceSessionEntry(pSessionEntry);
  1217. SmbCeAddSessionEntry(pServerEntry,pSessionEntry);
  1218. } else {
  1219. Status = STATUS_INSUFFICIENT_RESOURCES;
  1220. }
  1221. }
  1222. if (Status != STATUS_SUCCESS) {
  1223. if (pUserName != NULL) {
  1224. RxFreePool(pUserName);
  1225. }
  1226. if (pPassword != NULL) {
  1227. RxFreePool(pPassword);
  1228. }
  1229. if (pUserDomainName != NULL) {
  1230. RxFreePool(pUserDomainName);
  1231. }
  1232. if (pNetRootName != NULL) {
  1233. RxFreePool(pNetRootName);
  1234. }
  1235. }
  1236. } else {
  1237. if (Status == STATUS_SUCCESS) {
  1238. SmbCeLog(("CachedSessEntry %lx\n",pSessionEntry));
  1239. SmbLog(LOG,
  1240. SmbCeFindOrConstructSessionEntry_2,
  1241. LOGPTR(pSessionEntry));
  1242. }
  1243. }
  1244. if (Status == STATUS_SUCCESS) {
  1245. *pSessionEntryPtr = pSessionEntry;
  1246. }
  1247. SmbCeDereferenceServerEntry(pServerEntry);
  1248. } else {
  1249. Status = STATUS_INVALID_PARAMETER;
  1250. }
  1251. return Status;
  1252. }
  1253. VOID
  1254. SmbCeCompleteSessionEntryInitialization(
  1255. PVOID pContext,
  1256. NTSTATUS Status,
  1257. BOOLEAN SecuritySignatureReturned)
  1258. /*++
  1259. Routine Description:
  1260. This routine is invoked in the context of a worker thread to finalize the
  1261. construction of a session entry
  1262. Arguments:
  1263. pContext - the session entry to be activated
  1264. Notes:
  1265. PRE_CONDITION: The session entry must have been referenced to ensure that
  1266. even it has been finalized it will not be deleted.
  1267. --*/
  1268. {
  1269. PSMBCEDB_SESSION_ENTRY pSessionEntry = (PSMBCEDB_SESSION_ENTRY)pContext;
  1270. PSMBCE_SESSION pSession = &pSessionEntry->Session;
  1271. PSMBCEDB_SERVER_ENTRY pServerEntry = pSessionEntry->pServerEntry;
  1272. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  1273. SMBCEDB_REQUESTS Requests;
  1274. SMBCEDB_REQUESTS SecuritySignatureSyncRequests;
  1275. RxDbgTrace( 0, Dbg, ("Session Entry Finalization\n"));
  1276. ASSERT(pSessionEntry->Header.ObjectType == SMBCEDB_OT_SESSION);
  1277. // Acquire the SMBCE resource
  1278. SmbCeAcquireResource();
  1279. // reset the constructor exchange field since the construction is complete
  1280. pSessionEntry->pExchange = NULL;
  1281. //
  1282. SmbCeUnblockSerializedSessionSetupRequests(pSessionEntry);
  1283. // Create a temporary copy of the list that can be traversed after releasing the
  1284. // resource.
  1285. SmbCeTransferRequests(&Requests,&pSessionEntry->Requests);
  1286. SmbCeTransferRequests(&SecuritySignatureSyncRequests,&pServerEntry->SecuritySignatureSyncRequests);
  1287. pServerEntry->ExtSessionSetupInProgress = FALSE;
  1288. if (Status == STATUS_SUCCESS) {
  1289. SmbCeUpdateSessionEntryState(
  1290. pSessionEntry,
  1291. SMBCEDB_ACTIVE);
  1292. if ((pSession->pPassword != NULL || pSession->pUserName != NULL) &&
  1293. !BooleanFlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_NULL_CREDENTIALS)) {
  1294. if (pSessionEntry->DefaultSessionLink.Flink == NULL ) {
  1295. ASSERT( pSessionEntry->DefaultSessionLink.Blink == NULL );
  1296. InsertHeadList(&pServerEntry->Sessions.DefaultSessionList,
  1297. &pSessionEntry->DefaultSessionLink );
  1298. }
  1299. }
  1300. if (SecuritySignatureReturned &&
  1301. pServerEntry->SecuritySignaturesEnabled == TRUE &&
  1302. pServerEntry->SecuritySignaturesActive == FALSE) {
  1303. if (pSession->Type == EXTENDED_NT_SESSION) {
  1304. SmbInitializeSmbSecuritySignature(&pServerEntry->Server,
  1305. NULL,
  1306. pSession->UserSessionKey,
  1307. pSession->SessionKeyLength);
  1308. if( MRxSmbExtendedSignaturesEnabled )
  1309. {
  1310. pSession->SessionKeyState = SmbSessionKeyAuthenticating;
  1311. ClearFlag( pSession->Flags, SMBCE_SESSION_FLAGS_SESSION_KEY_HASHED );
  1312. }
  1313. else
  1314. {
  1315. pSession->SessionKeyState = SmbSessionKeyAvailible;
  1316. }
  1317. //DbgPrint("MRXSMB: Security Signature is active to W2K server %wZ\n", &pServerEntry->Name);
  1318. } else {
  1319. //DbgPrint("MRXSMB: Security Signature is active to NT4 server %wZ\n", &pServerEntry->Name);
  1320. pSession->SessionKeyState = SmbSessionKeyAvailible;
  1321. }
  1322. // turn on the security signature on the client side
  1323. pServerEntry->SecuritySignaturesActive = TRUE;
  1324. pServerEntry->Server.SmbSecuritySignatureIndex = 2;
  1325. }
  1326. else
  1327. {
  1328. pSession->SessionKeyState = SmbSessionKeyAvailible;
  1329. }
  1330. } else {
  1331. SmbCeUpdateSessionEntryState(
  1332. pSessionEntry,
  1333. SMBCEDB_INVALID);
  1334. }
  1335. pSessionEntry->SessionRecoverInProgress = FALSE;
  1336. pSessionEntry->SessionRecoveryInitiated = FALSE;
  1337. RxLog( ( "Completed session initialization %lx",pSessionEntry ) );
  1338. // Release the resource for the session entry
  1339. SmbCeReleaseResource();
  1340. if (!IsListEmpty(&Requests.ListHead)) {
  1341. // Iterate over the list of pending requests and resume all of them
  1342. SmbCeResumeOutstandingRequests(&Requests,Status);
  1343. }
  1344. if (!IsListEmpty(&SecuritySignatureSyncRequests.ListHead)) {
  1345. SmbCeResumeOutstandingRequests(&SecuritySignatureSyncRequests,STATUS_SUCCESS);
  1346. }
  1347. SmbCeDereferenceSessionEntry(pSessionEntry);
  1348. }
  1349. NTSTATUS
  1350. SmbCeGetUserNameAndDomainName(
  1351. PSMBCEDB_SESSION_ENTRY pSessionEntry,
  1352. PUNICODE_STRING pUserName,
  1353. PUNICODE_STRING pUserDomainName)
  1354. /*++
  1355. Routine Description:
  1356. This routine returns the user name and domain name associated with a session
  1357. in a caller allocated buffer.
  1358. Arguments:
  1359. pSessionEntry - the session entry to be dereferenced
  1360. pUserName - the User name
  1361. pUserDomainName - the user domain name
  1362. Return Value:
  1363. STATUS_SUCCESS if successful
  1364. --*/
  1365. {
  1366. NTSTATUS Status;
  1367. PSMBCE_SESSION pSession;
  1368. PUNICODE_STRING pSessionUserName,pSessionDomainName;
  1369. PSecurityUserData pSecurityData;
  1370. PAGED_CODE();
  1371. ASSERT(pSessionEntry != NULL);
  1372. pSession = &pSessionEntry->Session;
  1373. if ((pUserName == NULL) ||
  1374. (pUserDomainName == NULL) ||
  1375. (pUserName->MaximumLength < (UNLEN * sizeof(WCHAR))) ||
  1376. (pUserDomainName->MaximumLength < (DNLEN * sizeof(WCHAR)))) {
  1377. return STATUS_INVALID_PARAMETER;
  1378. }
  1379. Status = STATUS_SUCCESS;
  1380. pSecurityData = NULL;
  1381. pSessionUserName = pSession->pUserName;
  1382. pSessionDomainName = pSession->pUserDomainName;
  1383. try {
  1384. if (pSessionUserName == NULL ||
  1385. pSessionDomainName == NULL) {
  1386. Status = GetSecurityUserInfo(
  1387. &pSession->LogonId,
  1388. UNDERSTANDS_LONG_NAMES,
  1389. &pSecurityData);
  1390. if (NT_SUCCESS(Status)) {
  1391. if (pSessionUserName == NULL) {
  1392. pSessionUserName = &(pSecurityData->UserName);
  1393. }
  1394. if (pSessionDomainName == NULL) {
  1395. pSessionDomainName = &(pSecurityData->LogonDomainName);
  1396. }
  1397. }
  1398. }
  1399. if (NT_SUCCESS(Status)) {
  1400. if (pSessionUserName->Length > pUserName->MaximumLength ||
  1401. pSessionDomainName->Length > pUserDomainName->MaximumLength) {
  1402. Status = STATUS_BUFFER_OVERFLOW;
  1403. }
  1404. pUserName->Length = pSessionUserName->Length;
  1405. RtlCopyMemory(
  1406. pUserName->Buffer,
  1407. pSessionUserName->Buffer,
  1408. pUserName->Length);
  1409. pUserDomainName->Length = pSessionDomainName->Length;
  1410. if (pUserDomainName->Length > 0) {
  1411. RtlCopyMemory(
  1412. pUserDomainName->Buffer,
  1413. pSessionDomainName->Buffer,
  1414. pUserDomainName->Length);
  1415. }
  1416. }
  1417. } finally {
  1418. if (pSecurityData != NULL) {
  1419. LsaFreeReturnBuffer(pSecurityData);
  1420. }
  1421. }
  1422. return Status;
  1423. }
  1424. VOID
  1425. SmbCepDereferenceSessionEntry(
  1426. PSMBCEDB_SESSION_ENTRY pSessionEntry)
  1427. /*++
  1428. Routine Description:
  1429. This routine dereferences a session entry instance
  1430. Arguments:
  1431. pSessionEntry - the session entry to be dereferenced
  1432. --*/
  1433. {
  1434. if (pSessionEntry != NULL) {
  1435. BOOLEAN fTearDownEntry;
  1436. BOOLEAN fLogOffRequired;
  1437. LONG FinalRefCount;
  1438. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1439. ASSERT((pSessionEntry->Header.ObjectType == SMBCEDB_OT_SESSION) &&
  1440. (pSessionEntry->Header.SwizzleCount > 0));
  1441. pServerEntry = pSessionEntry->pServerEntry;
  1442. SmbCeAcquireResource();
  1443. FinalRefCount = InterlockedDecrement(&pSessionEntry->Header.SwizzleCount);
  1444. fTearDownEntry = (FinalRefCount == 0);
  1445. if (fTearDownEntry) {
  1446. // A logoff smb needs to be sent if the user id associated with
  1447. // the session is not zero. Note that we cannot rely on the state
  1448. // of the session to indicate this since extended session setups
  1449. // cna be terminated midway through the construction
  1450. SmbCeReferenceServerEntry(pServerEntry);
  1451. if (pSessionEntry->Header.SwizzleCount == 0) {
  1452. if (!FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) {
  1453. SmbCeRemoveSessionEntry(pServerEntry,pSessionEntry);
  1454. }
  1455. SmbCeRemoveDefaultSessionEntry(pSessionEntry);
  1456. if ((pSessionEntry->Session.UserId != (SMB_USER_ID)(SMBCE_SHARE_LEVEL_SERVER_USERID)) &&
  1457. (pSessionEntry->Session.UserId != 0) &&
  1458. (pSessionEntry->Header.State == SMBCEDB_ACTIVE) &&
  1459. !FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) {
  1460. SmbCeReferenceServerEntry(pServerEntry);
  1461. SmbCeReferenceSessionEntry(pSessionEntry);
  1462. fLogOffRequired = TRUE;
  1463. } else {
  1464. fLogOffRequired = FALSE;
  1465. }
  1466. pSessionEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION;
  1467. pSessionEntry->Session.Flags |= SMBCE_SESSION_FLAGS_LOGGED_OFF;
  1468. fTearDownEntry = TRUE;
  1469. } else {
  1470. fTearDownEntry = FALSE;
  1471. }
  1472. SmbCeDereferenceServerEntry(pServerEntry);
  1473. }
  1474. SmbCeReleaseResource();
  1475. if (fTearDownEntry) {
  1476. if (fLogOffRequired) {
  1477. SmbCeLogOff(pServerEntry,pSessionEntry);
  1478. SmbCeDereferenceServerEntry(pServerEntry);
  1479. } else {
  1480. SmbCeTearDownSessionEntry(pSessionEntry);
  1481. }
  1482. }
  1483. }
  1484. }
  1485. NTSTATUS
  1486. MRxSmbLogonSessionTerminationHandler(
  1487. PLUID pLogonId)
  1488. /*++
  1489. Routine Description:
  1490. This routine issues a log off command to the server on all the sessions
  1491. for the given logon id.
  1492. Arguments:
  1493. pLogonId - the logon id of the logon session that was terminated
  1494. --*/
  1495. {
  1496. #if 0
  1497. PSMBCEDB_SERVER_ENTRY pServerEntry,pNextServerEntry;
  1498. PSMBCEDB_SESSION_ENTRY pSessionEntry,pNextSessionEntry;
  1499. SmbCeAcquireResource();
  1500. pServerEntry = SmbCeGetFirstServerEntry();
  1501. while (pServerEntry != NULL) {
  1502. ASSERT(SmbCeIsResourceOwned());
  1503. SmbCeReferenceServerEntry(pServerEntry);
  1504. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  1505. while (pSessionEntry != NULL) {
  1506. if (RtlEqualLuid(
  1507. &pSessionEntry->Session.LogonId,
  1508. pLogonId)) {
  1509. if ((pSessionEntry->Session.UserId != (SMB_USER_ID)(SMBCE_SHARE_LEVEL_SERVER_USERID)) &&
  1510. (pSessionEntry->Session.UserId != 0) &&
  1511. !FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) {
  1512. SmbCeRemoveSessionEntry(pServerEntry,pSessionEntry);
  1513. SmbCeRemoveDefaultSessionEntry(pSessionEntry);
  1514. pSessionEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION;
  1515. pSessionEntry->Session.Flags |= SMBCE_SESSION_FLAGS_LOGGED_OFF;
  1516. SmbCeReferenceSessionEntry(pSessionEntry);
  1517. SmbCeReleaseResource();
  1518. if (pSessionEntry->Header.State == SMBCEDB_ACTIVE) {
  1519. SmbCeLogOff(pServerEntry,pSessionEntry);
  1520. } else {
  1521. SmbCeDereferenceSessionEntry(pSessionEntry);
  1522. }
  1523. SmbCeAcquireResource();
  1524. pNextSessionEntry = SmbCeGetNextSessionEntry(pServerEntry,pSessionEntry);
  1525. SmbCeDereferenceSessionEntry(pSessionEntry);
  1526. pSessionEntry = pNextSessionEntry;
  1527. }
  1528. } else {
  1529. pSessionEntry = SmbCeGetNextSessionEntry(pServerEntry,pSessionEntry);
  1530. }
  1531. }
  1532. pNextServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1533. SmbCeDereferenceServerEntry(pServerEntry);
  1534. pServerEntry = pNextServerEntry;
  1535. }
  1536. SmbCeReleaseResource();
  1537. #endif
  1538. return STATUS_SUCCESS;
  1539. }
  1540. VOID
  1541. SmbCeTearDownSessionEntry(
  1542. PSMBCEDB_SESSION_ENTRY pSessionEntry)
  1543. /*++
  1544. Routine Description:
  1545. This routine tears down a session entry instance
  1546. Arguments:
  1547. pSessionEntry - the session entry to be dereferenced
  1548. --*/
  1549. {
  1550. PAGED_CODE();
  1551. ASSERT((pSessionEntry->Header.SwizzleCount == 0) &&
  1552. (pSessionEntry->Header.State == SMBCEDB_MARKED_FOR_DELETION));
  1553. ASSERT(IsListEmpty(&pSessionEntry->SerializationList));
  1554. SmbCeLog(("TearSessEntry %lx\n",pSessionEntry));
  1555. SmbLog(LOG,
  1556. SmbCeTearDownSessionEntry,
  1557. LOGPTR(pSessionEntry));
  1558. if (pSessionEntry->Session.pUserName != NULL) {
  1559. RxFreePool(pSessionEntry->Session.pUserName);
  1560. }
  1561. if (pSessionEntry->Session.pPassword != NULL) {
  1562. RtlSecureZeroMemory(pSessionEntry->Session.pPassword->Buffer,pSessionEntry->Session.pPassword->Length);
  1563. RxFreePool(pSessionEntry->Session.pPassword);
  1564. }
  1565. if (pSessionEntry->Session.pUserDomainName != NULL) {
  1566. RxFreePool(pSessionEntry->Session.pUserDomainName);
  1567. }
  1568. if (pSessionEntry->Session.TargetInfoMarshalled != NULL) {
  1569. RxFreePool(pSessionEntry->Session.TargetInfoMarshalled);
  1570. }
  1571. if (pSessionEntry->pNetRootName != NULL) {
  1572. RxFreePool(pSessionEntry->pNetRootName);
  1573. }
  1574. UninitializeSecurityContextsForSession(&pSessionEntry->Session);
  1575. SmbMmFreeSessionEntry(pSessionEntry);
  1576. }
  1577. PSMBCEDB_NET_ROOT_ENTRY
  1578. SmbCeFindNetRootEntry(
  1579. PSMBCEDB_SERVER_ENTRY pServerEntry,
  1580. PUNICODE_STRING pServerShare
  1581. )
  1582. {
  1583. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
  1584. ASSERT(SmbCeIsResourceOwned());
  1585. pNetRootEntry = SmbCeGetFirstNetRootEntry(pServerEntry);
  1586. while (pNetRootEntry != NULL) {
  1587. if (RtlCompareUnicodeString(
  1588. pServerShare,
  1589. &pNetRootEntry->Name,
  1590. TRUE) == 0) {
  1591. break;
  1592. }
  1593. pNetRootEntry = SmbCeGetNextNetRootEntry(pServerEntry,pNetRootEntry);
  1594. }
  1595. return pNetRootEntry;
  1596. }
  1597. NTSTATUS
  1598. SmbCeFindOrConstructNetRootEntry(
  1599. IN PMRX_NET_ROOT pNetRoot,
  1600. OUT PSMBCEDB_NET_ROOT_ENTRY *pNetRootEntryPtr)
  1601. /*++
  1602. Routine Description:
  1603. This routine opens/creates a net root entry in the connection engine database
  1604. Arguments:
  1605. pNetRoot -- the RDBSS net root instance
  1606. pNetRootEntryPtr -- Initialized to the SMBCEDB_NET_ROOT_ENTRY instance if
  1607. successful
  1608. Return Value:
  1609. STATUS_SUCCESS - the construction of the net root instance has been finalized
  1610. Other Status codes correspond to error situations.
  1611. Notes:
  1612. This routine assumes that the necesary concurreny control mechanism has already
  1613. been taken.
  1614. On Entry the connection engine resource must have been acquired exclusive and
  1615. ownership remains invariant on exit.
  1616. --*/
  1617. {
  1618. NTSTATUS Status = STATUS_SUCCESS;
  1619. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  1620. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
  1621. PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL;
  1622. SMB_USER_ID UserId = 0;
  1623. ASSERT(SmbCeIsResourceOwned());
  1624. *pNetRootEntryPtr = NULL;
  1625. pServerEntry = SmbCeReferenceAssociatedServerEntry(pNetRoot->pSrvCall);
  1626. if (pServerEntry != NULL) {
  1627. // Check if any of the SMBCEDB_NET_ROOT_ENTRY associated with the server
  1628. // can be used. An existing entry is reusable if the names match
  1629. pNetRootEntry = SmbCeGetFirstNetRootEntry(pServerEntry);
  1630. while (pNetRootEntry != NULL) {
  1631. if (RtlCompareUnicodeString(
  1632. pNetRoot->pNetRootName,
  1633. &pNetRootEntry->Name,
  1634. TRUE) == 0) {
  1635. SmbCeLog(("CachedNREntry %lx\n",pNetRootEntry));
  1636. SmbLog(LOG,
  1637. SmbCeFindOrConstructNetRootEntry_1,
  1638. LOGPTR(pNetRootEntry));
  1639. break;
  1640. }
  1641. pNetRootEntry = SmbCeGetNextNetRootEntry(pServerEntry,pNetRootEntry);
  1642. }
  1643. if (pNetRootEntry != NULL) {
  1644. SmbCeReferenceNetRootEntry(pNetRootEntry);
  1645. } else {
  1646. pNetRootEntry = (PSMBCEDB_NET_ROOT_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_NETROOT);
  1647. if (pNetRootEntry != NULL) {
  1648. Status = MRxSmbCscInitializeNetRootEntry(pNetRootEntry);
  1649. if (Status != STATUS_SUCCESS) {
  1650. SmbMmFreeObject(pNetRootEntry);
  1651. } else {
  1652. pNetRootEntry->Name.Buffer = RxAllocatePoolWithTag(
  1653. PagedPool | POOL_COLD_ALLOCATION,
  1654. pNetRoot->pNetRootName->Length,
  1655. MRXSMB_NETROOT_POOLTAG);
  1656. if (pNetRootEntry->Name.Buffer != NULL) {
  1657. SmbCeLog(("NewNetREntry %lx\n",pNetRootEntry));
  1658. SmbLog(LOG,
  1659. SmbCeFindOrConstructNetRootEntry_2,
  1660. LOGPTR(pNetRootEntry));
  1661. pNetRootEntry->Name.Length = pNetRoot->pNetRootName->Length;
  1662. pNetRootEntry->Name.MaximumLength = pNetRootEntry->Name.Length;
  1663. RtlCopyMemory(
  1664. pNetRootEntry->Name.Buffer,
  1665. pNetRoot->pNetRootName->Buffer,
  1666. pNetRootEntry->Name.Length);
  1667. pNetRootEntry->pServerEntry = pServerEntry;
  1668. pNetRootEntry->NetRoot.UserId = UserId;
  1669. pNetRootEntry->NetRoot.NetRootType = pNetRoot->Type;
  1670. InitializeListHead(&pNetRootEntry->NetRoot.ClusterSizeSerializationQueue);
  1671. pNetRootEntry->Header.State = SMBCEDB_ACTIVE;
  1672. // Init the NetRoot Name Caches.
  1673. //
  1674. // The get file attributes name cache tracks the file attributes response
  1675. // from the last GFA sent to the server for a given file.
  1676. // NB: There is no struct defined for the extension to the GFA name
  1677. // cache since the extension is only an SMBPSE_FILEINFO_BUNDLE.
  1678. //
  1679. RxNameCacheInitialize(
  1680. &pNetRootEntry->NameCacheCtlGFABasic,
  1681. sizeof(FILE_BASIC_INFORMATION),
  1682. NAME_CACHE_NETROOT_MAX_ENTRIES);
  1683. RxNameCacheInitialize(
  1684. &pNetRootEntry->NameCacheCtlGFAStandard,
  1685. sizeof(FILE_STANDARD_INFORMATION),
  1686. NAME_CACHE_NETROOT_MAX_ENTRIES);
  1687. RxNameCacheInitialize(
  1688. &pNetRootEntry->NameCacheCtlGFAInternal,
  1689. sizeof(FILE_INTERNAL_INFORMATION),
  1690. NAME_CACHE_NETROOT_MAX_ENTRIES);
  1691. //
  1692. // The file not found name cache just tracks opens on files where the
  1693. // response was file not found.
  1694. //
  1695. RxNameCacheInitialize(
  1696. &pNetRootEntry->NameCacheCtlFNF,
  1697. 0,
  1698. NAME_CACHE_NETROOT_MAX_ENTRIES);
  1699. RxNameCacheInitialize(
  1700. &pNetRootEntry->NameCacheCtlPartialDir,
  1701. sizeof (FULL_DIR_CACHE),
  1702. NAME_CACHE_NETROOT_MAX_ENTRIES);
  1703. SmbCeReferenceNetRootEntry(pNetRootEntry);
  1704. SmbCeAddNetRootEntry(pServerEntry,pNetRootEntry);
  1705. if ( RtlCompareUnicodeString(
  1706. pNetRoot->pNetRootName,
  1707. &MRxSmbRemoteBootShare,
  1708. TRUE
  1709. ) == 0 ) {
  1710. pNetRootEntry->IsRemoteBoot = TRUE;
  1711. }
  1712. } else {
  1713. SmbMmFreeObject(pNetRootEntry);
  1714. Status = STATUS_INSUFFICIENT_RESOURCES;
  1715. }
  1716. }
  1717. } else {
  1718. Status = STATUS_INSUFFICIENT_RESOURCES;
  1719. }
  1720. }
  1721. if (Status == STATUS_SUCCESS) {
  1722. ASSERT(pNetRootEntry != NULL);
  1723. *pNetRootEntryPtr = pNetRootEntry;
  1724. }
  1725. SmbCeDereferenceServerEntry(pServerEntry);
  1726. } else {
  1727. Status = STATUS_INVALID_PARAMETER;
  1728. }
  1729. return Status;
  1730. }
  1731. VOID
  1732. SmbCepDereferenceNetRootEntry(
  1733. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry,
  1734. PVOID FileName,
  1735. ULONG FileLine)
  1736. /*++
  1737. Routine Description:
  1738. This routine dereferences a net root entry instance
  1739. Arguments:
  1740. pNetRootEntry - the NEt Root entry to be dereferenced
  1741. Notes:
  1742. Disconnects are not required for mailslot servers. They need to be
  1743. sent to File servers only.
  1744. --*/
  1745. {
  1746. if (pNetRootEntry != NULL) {
  1747. LONG FinalRefCount;
  1748. BOOLEAN fTearDownEntry;
  1749. BOOLEAN fDisconnectRequired;
  1750. ASSERT((pNetRootEntry->Header.ObjectType == SMBCEDB_OT_NETROOT) &&
  1751. (pNetRootEntry->Header.SwizzleCount > 0));
  1752. SmbCeAcquireResource();
  1753. FinalRefCount = InterlockedDecrement(&pNetRootEntry->Header.SwizzleCount);
  1754. fTearDownEntry = (FinalRefCount == 0);
  1755. if (fTearDownEntry) {
  1756. if (pNetRootEntry->Header.SwizzleCount == 0) {
  1757. PSMBCEDB_SERVER_ENTRY pServerEntry = pNetRootEntry->pServerEntry;
  1758. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
  1759. SmbCeRemoveNetRootEntryLite(pNetRootEntry->pServerEntry,pNetRootEntry);
  1760. pNetRootEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION;
  1761. fTearDownEntry = TRUE;
  1762. pVNetRootContext = SmbCeGetFirstVNetRootContext(&pServerEntry->VNetRootContexts);
  1763. while (pVNetRootContext != NULL) {
  1764. ASSERT(pVNetRootContext->pNetRootEntry != pNetRootEntry);
  1765. pVNetRootContext = SmbCeGetNextVNetRootContext(
  1766. &pServerEntry->VNetRootContexts,
  1767. pVNetRootContext);
  1768. }
  1769. } else {
  1770. fTearDownEntry = FALSE;
  1771. }
  1772. }
  1773. SmbCeReleaseResource();
  1774. if (fTearDownEntry) {
  1775. SmbCeTearDownNetRootEntry(pNetRootEntry);
  1776. }
  1777. }
  1778. }
  1779. VOID
  1780. SmbCeTearDownNetRootEntry(
  1781. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry)
  1782. /*++
  1783. Routine Description:
  1784. This routine tears down a net root entry instance
  1785. Arguments:
  1786. pNetRootEntry - the NEt Root entry to be dereferenced
  1787. --*/
  1788. {
  1789. PAGED_CODE();
  1790. ASSERT((pNetRootEntry->Header.SwizzleCount == 0) &&
  1791. (pNetRootEntry->Header.State == SMBCEDB_MARKED_FOR_DELETION));
  1792. SmbCeLog(("TearNetREntry %lx\n",pNetRootEntry));
  1793. SmbLog(LOG,
  1794. SmbCeTearDownNetRootEntry,
  1795. LOGPTR(pNetRootEntry));
  1796. MRxSmbCscUninitializeNetRootEntry(pNetRootEntry);
  1797. //
  1798. // Free storage associated with all entries in the name caches.
  1799. //
  1800. RxNameCacheFinalize(&pNetRootEntry->NameCacheCtlGFABasic);
  1801. RxNameCacheFinalize(&pNetRootEntry->NameCacheCtlGFAStandard);
  1802. RxNameCacheFinalize(&pNetRootEntry->NameCacheCtlGFAInternal);
  1803. RxNameCacheFinalize(&pNetRootEntry->NameCacheCtlFNF);
  1804. RxNameCacheFinalize(&pNetRootEntry->NameCacheCtlPartialDir);
  1805. if (pNetRootEntry->Name.Buffer != NULL) {
  1806. RxFreePool(pNetRootEntry->Name.Buffer);
  1807. pNetRootEntry->Name.Buffer = NULL;
  1808. }
  1809. if (pNetRootEntry->VolumeInfo != NULL) {
  1810. RxFreePool(pNetRootEntry->VolumeInfo);
  1811. pNetRootEntry->VolumeInfo = NULL;
  1812. }
  1813. SmbMmFreeObject(pNetRootEntry);
  1814. }
  1815. NTSTATUS
  1816. SmbCeUpdateNetRoot(
  1817. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry,
  1818. PMRX_NET_ROOT pNetRoot)
  1819. /*++
  1820. Routine Description:
  1821. This routine initializes the wrapper data structure corresponding to a
  1822. given net root entry.
  1823. Arguments:
  1824. pNetRootEntry - the server entry
  1825. Return Value:
  1826. STATUS_SUCCESS if successful
  1827. --*/
  1828. {
  1829. PAGED_CODE();
  1830. if (pNetRootEntry->NetRoot.NetRootType != NET_ROOT_WILD) {
  1831. pNetRoot->Type = pNetRootEntry->NetRoot.NetRootType;
  1832. }
  1833. switch (pNetRoot->Type) {
  1834. case NET_ROOT_DISK:
  1835. {
  1836. pNetRoot->DeviceType = RxDeviceType(DISK);
  1837. RxInitializeNetRootThrottlingParameters(
  1838. &pNetRoot->DiskParameters.LockThrottlingParameters,
  1839. MRxSmbConfiguration.LockIncrement,
  1840. MRxSmbConfiguration.MaximumLock);
  1841. }
  1842. break;
  1843. case NET_ROOT_PIPE:
  1844. {
  1845. pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
  1846. RxInitializeNetRootThrottlingParameters(
  1847. &pNetRoot->NamedPipeParameters.PipeReadThrottlingParameters,
  1848. MRxSmbConfiguration.PipeIncrement,
  1849. MRxSmbConfiguration.PipeMaximum);
  1850. }
  1851. break;
  1852. case NET_ROOT_COMM:
  1853. pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
  1854. break;
  1855. case NET_ROOT_PRINT:
  1856. pNetRoot->DeviceType = RxDeviceType(PRINTER);
  1857. break;
  1858. case NET_ROOT_MAILSLOT:
  1859. pNetRoot->DeviceType = RxDeviceType(MAILSLOT);
  1860. break;
  1861. case NET_ROOT_WILD:
  1862. break;
  1863. default:
  1864. ASSERT(!"Valid Net Root Type");
  1865. }
  1866. if (pNetRootEntry->NetRoot.DfsAware) {
  1867. SetFlag(pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT);
  1868. } else {
  1869. ClearFlag(pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT);
  1870. }
  1871. return STATUS_SUCCESS;
  1872. }
  1873. NTSTATUS
  1874. SmbCeProbeServers(
  1875. PVOID pContext)
  1876. /*++
  1877. Routine Description:
  1878. This routine probes all the remote servers on which no activity has been
  1879. detected in the recent past.
  1880. Notes:
  1881. The current implementation of walking through the list of all servers to
  1882. initiate echo processing will not scale very well for gateway servers. A
  1883. different mechanism needs to be implemented.
  1884. --*/
  1885. {
  1886. LIST_ENTRY DiscardedServersList;
  1887. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1888. PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT pEchoProbeContext;
  1889. PSMBCEDB_SERVER_ENTRY pPreviousServerEntry = NULL;
  1890. pEchoProbeContext = (PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT)pContext;
  1891. InitializeListHead(&DiscardedServersList);
  1892. SmbCeAcquireSpinLock();
  1893. pServerEntry = SmbCeGetFirstServerEntry();
  1894. while (pServerEntry != NULL) {
  1895. BOOLEAN TearDownTransport = FALSE;
  1896. if ((SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER) &&
  1897. ((pServerEntry->Header.State == SMBCEDB_ACTIVE) ||
  1898. (pServerEntry->Header.State == SMBCEDB_CONSTRUCTION_IN_PROGRESS))) {
  1899. // The additional reference is required to keep this server entry
  1900. // as a place marker in the list of server entries.
  1901. // This will be released on resumption of the processinf further
  1902. // down in this routine
  1903. InterlockedIncrement(&pServerEntry->Header.SwizzleCount);
  1904. SmbCeReleaseSpinLock();
  1905. if (pPreviousServerEntry != NULL) {
  1906. SmbCeDereferenceServerEntry(pPreviousServerEntry);
  1907. }
  1908. // For loop back servers we forego the expired exchange detection
  1909. // mechanism. Since the I/O is directed to the same machine this
  1910. // indicates a problem with the local system.
  1911. TearDownTransport = SmbCeDetectExpiredExchanges(pServerEntry);
  1912. if (!TearDownTransport) {
  1913. if ((pServerEntry->Server.SmbsReceivedSinceLastStrobe == 0) &&
  1914. (pServerEntry->pMidAtlas != NULL) &&
  1915. (pServerEntry->pMidAtlas->NumberOfMidsInUse > 0)) {
  1916. if (pServerEntry->Server.EchoProbeState == ECHO_PROBE_IDLE) {
  1917. NTSTATUS Status;
  1918. LARGE_INTEGER CurrentTime,ExpiryTimeInTicks;
  1919. KeQueryTickCount( &CurrentTime );
  1920. ExpiryTimeInTicks.QuadPart = (1000 * 1000 * 10) / KeQueryTimeIncrement();
  1921. ExpiryTimeInTicks.QuadPart = MRxSmbConfiguration.SessionTimeoutInterval * ExpiryTimeInTicks.QuadPart;
  1922. pServerEntry->Server.EchoExpiryTime.QuadPart = CurrentTime.QuadPart +
  1923. ExpiryTimeInTicks.QuadPart;
  1924. InterlockedExchange(
  1925. &pServerEntry->Server.EchoProbeState,
  1926. ECHO_PROBE_AWAITING_RESPONSE);
  1927. Status = SmbCeSendEchoProbe(
  1928. pServerEntry,
  1929. pEchoProbeContext);
  1930. RxDbgTrace(0,Dbg,("Sending ECHO SMB %lx Status %lx\n",pServerEntry,Status));
  1931. TearDownTransport = ((Status != STATUS_SUCCESS) &&
  1932. (Status != STATUS_PENDING));
  1933. if( TearDownTransport )
  1934. {
  1935. RxLogRetail(( "Echo failed %x (%x)\n", pServerEntry, Status ));
  1936. }
  1937. } else if (pServerEntry->Server.EchoProbeState == ECHO_PROBE_AWAITING_RESPONSE) {
  1938. // Compare the current time with the time at which the echo probe
  1939. // was sent. If the interval is greater than the response time then
  1940. // it can be deemed that the echo response is not forthcoming and
  1941. // the tear down can be initiated.
  1942. LARGE_INTEGER CurrentTime;
  1943. KeQueryTickCount( &CurrentTime );
  1944. if ((pServerEntry->Server.EchoExpiryTime.QuadPart != 0) &&
  1945. (pServerEntry->Server.EchoExpiryTime.QuadPart < CurrentTime.QuadPart)) {
  1946. RxLogRetail(( "Echo failed %x (timeout)\n", pServerEntry ));
  1947. TearDownTransport = TRUE;
  1948. }
  1949. }
  1950. if (TearDownTransport) {
  1951. RxLog(("Echo Problem for srvr%lx \n",pServerEntry));
  1952. SmbLog(LOG,
  1953. SmbCeProbeServers,
  1954. LOGPTR(pServerEntry)
  1955. LOGUSTR(pServerEntry->Name));
  1956. }
  1957. } else {
  1958. InterlockedExchange(&pServerEntry->Server.SmbsReceivedSinceLastStrobe,0);
  1959. }
  1960. }
  1961. if (TearDownTransport) {
  1962. InterlockedIncrement(&MRxSmbStatistics.HungSessions);
  1963. SmbCeTransportDisconnectIndicated(pServerEntry);
  1964. }
  1965. // reacquire the spin lock to traverse the list.
  1966. SmbCeAcquireSpinLock();
  1967. pPreviousServerEntry = pServerEntry;
  1968. pServerEntry = SmbCeGetNextServerEntry(pPreviousServerEntry);
  1969. } else {
  1970. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1971. }
  1972. }
  1973. SmbCeReleaseSpinLock();
  1974. if (pPreviousServerEntry != NULL) {
  1975. SmbCeDereferenceServerEntry(pPreviousServerEntry);
  1976. }
  1977. return STATUS_SUCCESS;
  1978. }
  1979. VOID
  1980. SmbCeTransportDisconnectIndicated(
  1981. PSMBCEDB_SERVER_ENTRY pServerEntry)
  1982. /*++
  1983. Routine Description:
  1984. This routine invalidates a server entry on notification from the underlying transport
  1985. Arguments:
  1986. pServerEntry - the server entry to be dereferenced
  1987. Notes:
  1988. The server entry and the associated net roots and sessions are marked as invalid. A
  1989. reconnect is facilitated on other requests as and when required. In addition all
  1990. pending requests are resumed with the appropriate error indication.
  1991. --*/
  1992. {
  1993. NTSTATUS Status;
  1994. BOOLEAN ShouldResumeRequests = FALSE;
  1995. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  1996. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  1997. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  1998. RxDbgTrace(0,
  1999. Dbg,
  2000. ("SmbCeDbTransportDisconnectIndicated for %lx -- Entry\n",pServerEntry));
  2001. // Acquire the database resource (DPC Level)
  2002. SmbCeAcquireSpinLock();
  2003. if (!pServerEntry->ResumeRequestsInProgress) {
  2004. ShouldResumeRequests = TRUE;
  2005. pServerEntry->ResumeRequestsInProgress = TRUE;
  2006. pServerEntry->ServerStatus = STATUS_CONNECTION_DISCONNECTED;
  2007. pServerEntry->Header.State = SMBCEDB_DESTRUCTION_IN_PROGRESS;
  2008. pServerEntry->SecuritySignaturesActive = FALSE;
  2009. SmbCeReferenceServerEntry(pServerEntry);
  2010. // Increment the associated version count so as to invalidate all existing Fids
  2011. InterlockedIncrement(&pServerEntry->Server.Version);
  2012. }
  2013. // release the database resource (DPC Level)
  2014. SmbCeReleaseSpinLock();
  2015. SmbLog(LOG,
  2016. SmbCeTransportDisconnectIndicated,
  2017. LOGPTR(pServerEntry)
  2018. LOGUSTR(pServerEntry->Name));
  2019. if (ShouldResumeRequests) {
  2020. InitializeListHead(&pServerEntry->WorkQueueItemForResume.List);
  2021. RxPostToWorkerThread(
  2022. MRxSmbDeviceObject,
  2023. CriticalWorkQueue,
  2024. &pServerEntry->WorkQueueItemForResume,
  2025. SmbCeResumeAllOutstandingRequestsOnError,
  2026. pServerEntry);
  2027. }
  2028. RxDbgTrace(0,
  2029. Dbg,
  2030. ("SmbCeTransportDisconnectIndicated -- Exit\n"));
  2031. }
  2032. VOID
  2033. SmbCeHandleTransportInvalidation(
  2034. IN PSMBCE_TRANSPORT pTransport)
  2035. /*++
  2036. Routine Description:
  2037. This routine invalidates all servers using a particular transport. This is different from
  2038. a disconnect indication in which one server is invalidated. In this case a transport is being
  2039. removed/invalidated locally and all servers using that transport must be invalidated
  2040. Arguments:
  2041. pTransport - the transport being invalidated
  2042. --*/
  2043. {
  2044. PSMBCEDB_SERVER_ENTRY pServerEntry;
  2045. SmbCeAcquireSpinLock();
  2046. pServerEntry = SmbCeGetFirstServerEntry();
  2047. while (pServerEntry != NULL) {
  2048. if ((pServerEntry->pTransport != NULL) &&
  2049. (pServerEntry->pTransport->pTransport == pTransport)) {
  2050. pServerEntry->Header.State = SMBCEDB_DESTRUCTION_IN_PROGRESS;
  2051. // The invalidation needs to hold onto an extra reference to avoid
  2052. // race conditions which could lead to premature destruction of
  2053. // this server entry.
  2054. SmbCeReferenceServerEntry(pServerEntry);
  2055. }
  2056. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  2057. }
  2058. SmbCeReleaseSpinLock();
  2059. SmbCeAcquireResource();
  2060. pServerEntry = SmbCeGetFirstServerEntry();
  2061. while (pServerEntry != NULL) {
  2062. PSMBCEDB_SERVER_ENTRY pPrevServerEntry;
  2063. BOOLEAN fDereferencePrevServerEntry = FALSE;
  2064. if ((pServerEntry->pTransport != NULL) &&
  2065. (pServerEntry->pTransport->pTransport == pTransport)) {
  2066. SmbCeReleaseResource();
  2067. SmbCeTransportDisconnectIndicated(pServerEntry);
  2068. SmbCeReferenceServerEntry(pServerEntry);
  2069. // the reference count of Server Entry will be taken away while the transport
  2070. // is torn down, which prevents the server tranports being torn down again at
  2071. // time the server entry being freed.
  2072. SmbCeUninitializeServerTransport(pServerEntry,
  2073. SmbCeCompleteUninitializeServerTransport,
  2074. pServerEntry);
  2075. SmbCeAcquireResource();
  2076. if (pServerEntry->PreferredTransport != NULL) {
  2077. SmbCeDereferenceTransport(pServerEntry->PreferredTransport);
  2078. pServerEntry->PreferredTransport = NULL;
  2079. }
  2080. fDereferencePrevServerEntry = TRUE;
  2081. }
  2082. pPrevServerEntry = pServerEntry;
  2083. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  2084. if (fDereferencePrevServerEntry) {
  2085. SmbCeDereferenceServerEntry(pPrevServerEntry);
  2086. }
  2087. }
  2088. SmbCeReleaseResource();
  2089. }
  2090. NTSTATUS
  2091. SmbCeHoldExchangeForSessionRecovery(
  2092. IN PSMB_EXCHANGE pExchange,
  2093. PSMBCE_RELEASE_ROUTINE pRoutine
  2094. )
  2095. /*++
  2096. Routine Description:
  2097. This routine adds the exchange to a list which will resume when session recoovery
  2098. completes..
  2099. Arguments:
  2100. OrdinaryExchange
  2101. Return Value:
  2102. NTSTATUS - The return status for the operation
  2103. Notes:
  2104. IRQL < DISPATCH_LEVEL
  2105. This routine takes an extra reference on the exchange so that it will not be finalized.
  2106. When the exchange is 'released', the extra reference will be removed.
  2107. (see SmbCeResumeOutstandingRequests)
  2108. --*/
  2109. {
  2110. PSMBCEDB_SERVER_ENTRY pServerEntry;
  2111. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  2112. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  2113. SMBCEDB_REQUESTS SecuritySignatureSyncRequests;
  2114. NTSTATUS Status = STATUS_SUCCESS;
  2115. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  2116. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  2117. InitializeListHead( &SecuritySignatureSyncRequests.ListHead );
  2118. SmbCeAcquireResource();
  2119. //
  2120. // If we are recovering from an expired session, we add the request to a list hanging on the server.
  2121. //
  2122. if( pSessionEntry->SessionRecoveryInitiated ) {
  2123. pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
  2124. if (pRequestEntry != NULL) {
  2125. pRequestEntry->HoldRequest.Type = HOLD_REQUEST;
  2126. pRequestEntry->HoldRequest.pExchange = pExchange;
  2127. pRequestEntry->HoldRequest.ReleaseRoutine = pRoutine;
  2128. SmbCeAddRequestEntry(&pServerEntry->SecuritySignatureSyncRequests,pRequestEntry);
  2129. RxLog( ( "Held exchange %x", pExchange ) );
  2130. Status = STATUS_PENDING;
  2131. } else {
  2132. Status = STATUS_INSUFFICIENT_RESOURCES;
  2133. }
  2134. } else {
  2135. //
  2136. // Release the resource and initiate session recovery.
  2137. //
  2138. pSessionEntry->SessionRecoveryInitiated = TRUE;
  2139. SmbCeReleaseResource();
  2140. Status = SmbCeReconnect( SmbCeGetExchangeVNetRoot( pExchange ) );
  2141. ASSERT(Status != STATUS_PENDING);
  2142. SmbCeAcquireResource();
  2143. pSessionEntry->SessionRecoveryInitiated = FALSE;
  2144. if( !NT_SUCCESS( Status ) ) {
  2145. SmbCeTransferRequests(&SecuritySignatureSyncRequests,&pServerEntry->SecuritySignatureSyncRequests);
  2146. }
  2147. }
  2148. SmbCeReleaseResource();
  2149. //
  2150. // If we were unable to reconnect successfully, we must make sure that any requests
  2151. // added to the list are resumed.
  2152. //
  2153. if (!IsListEmpty(&SecuritySignatureSyncRequests.ListHead)) {
  2154. SmbCeResumeOutstandingRequests(&SecuritySignatureSyncRequests,Status);
  2155. }
  2156. return Status;
  2157. }
  2158. VOID
  2159. SmbCeResumeOutstandingRequests(
  2160. PSMBCEDB_REQUESTS pRequests,
  2161. NTSTATUS RequestStatus)
  2162. /*++
  2163. Routine Description:
  2164. This routine resumes the outstanding requests with the appropriate status
  2165. Arguments:
  2166. pRequests - the list of requests
  2167. RequestStatus - the resumption status ..
  2168. Notes:
  2169. As a side effect the list of requests is torn down.
  2170. --*/
  2171. {
  2172. NTSTATUS Status;
  2173. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  2174. PSMB_EXCHANGE pExchange;
  2175. // Resume all the outstanding reconnect requests that were held up because an earlier
  2176. // reconnect request was under way.
  2177. // Iterate over the list of pending requests and resume all of them
  2178. pRequestEntry = SmbCeGetFirstRequestEntry(pRequests);
  2179. while (pRequestEntry != NULL) {
  2180. pExchange = pRequestEntry->GenericRequest.pExchange;
  2181. switch(pRequestEntry->GenericRequest.Type) {
  2182. case HOLD_REQUEST:
  2183. RxLog( ( "Releasing held exchange %x", pExchange ) );
  2184. pRequestEntry->HoldRequest.ReleaseRoutine( pExchange, pExchange->RxContext );
  2185. break;
  2186. default:
  2187. RxDbgTrace(0, Dbg, ("Resuming outstanding reconnect request exchange %lx \n",pExchange));
  2188. pExchange->Status = RequestStatus;
  2189. SmbCeDecrementPendingLocalOperations(pExchange);
  2190. // Resume the exchange.
  2191. if (pRequestEntry->Request.pExchange->pSmbCeSynchronizationEvent == NULL) {
  2192. if (RequestStatus == STATUS_SUCCESS) {
  2193. Status = SmbCeResumeExchange(pExchange);
  2194. } else {
  2195. // Invoke the error handler
  2196. RxDbgTrace( 0, Dbg, ("Resuming exchange%lx with error\n",pRequestEntry->Request.pExchange));
  2197. SmbCeFinalizeExchange(pExchange);
  2198. }
  2199. } else {
  2200. KeSetEvent(
  2201. pRequestEntry->Request.pExchange->pSmbCeSynchronizationEvent,
  2202. 0,
  2203. FALSE);
  2204. }
  2205. }
  2206. // Delete the request entry
  2207. SmbCeRemoveRequestEntryLite(pRequests,pRequestEntry);
  2208. // Tear down the continuation entry
  2209. SmbCeTearDownRequestEntry(pRequestEntry);
  2210. // Skip to the next one.
  2211. pRequestEntry = SmbCeGetFirstRequestEntry(pRequests);
  2212. }
  2213. }
  2214. VOID
  2215. SmbCeResumeAllOutstandingRequestsOnError(
  2216. PSMBCEDB_SERVER_ENTRY pServerEntry)
  2217. /*++
  2218. Routine Description:
  2219. This routine handles the resumption of all outstanding requests on an error
  2220. Arguments:
  2221. pServerEntry - the Server entry which is being classified as disconnected
  2222. Notes:
  2223. This routine requires the caller to have obtained a reference on the corresponding
  2224. server entry. This is required because invocation of this routine can be posted
  2225. which implies that a reference is required to avoid premature destruction of
  2226. the associated server entry.
  2227. --*/
  2228. {
  2229. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  2230. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  2231. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  2232. SMBCEDB_REQUESTS Requests;
  2233. SMBCEDB_REQUESTS MidRequests;
  2234. SMBCEDB_REQUESTS SecuritySignatureSyncRequests;
  2235. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  2236. PMID_ATLAS pMidAtlas;
  2237. PSMB_EXCHANGE pNegotiateExchange = NULL;
  2238. LIST_ENTRY ExpiredExchanges;
  2239. //DbgPrint("SmbCeResumeAllOutstandingRequestsOnError: Invoked \n");
  2240. InitializeListHead(&ExpiredExchanges);
  2241. InitializeListHead(&Requests.ListHead);
  2242. SmbCeAcquireResource();
  2243. SmbCeAcquireSpinLock();
  2244. if (pServerEntry->Header.State != SMBCEDB_DESTRUCTION_IN_PROGRESS) {
  2245. SmbCeReleaseSpinLock();
  2246. SmbCeReleaseResource();
  2247. SmbCeDereferenceServerEntry(pServerEntry);
  2248. return;
  2249. }
  2250. if (pServerEntry->pNegotiateExchange != NULL) {
  2251. if (pServerEntry->pNegotiateExchange->ReceivePendingOperations > 0) {
  2252. pNegotiateExchange = SmbResetServerEntryNegotiateExchange(pServerEntry);
  2253. }
  2254. }
  2255. // Create a temporary copy of the list that can be traversed after releasing the
  2256. // resource.
  2257. // Copy all the MID assignment requests pending.
  2258. SmbCeTransferRequests(&MidRequests,&pServerEntry->MidAssignmentRequests);
  2259. // Weed out all the reconnect requests so that they can be resumed
  2260. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  2261. while (pRequestEntry != NULL) {
  2262. if (pRequestEntry->GenericRequest.Type == RECONNECT_REQUEST) {
  2263. PSMBCEDB_REQUEST_ENTRY pTempRequestEntry;
  2264. pTempRequestEntry = pRequestEntry;
  2265. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  2266. SmbCeRemoveRequestEntryLite(&pServerEntry->OutstandingRequests,pTempRequestEntry);
  2267. SmbCeAddRequestEntryLite(&Requests,pTempRequestEntry);
  2268. } else {
  2269. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  2270. }
  2271. }
  2272. // The exchanges that have valid MID's assigned to them fall into two categories
  2273. // Those that have a ReceivePendingOperation count of > 0 and those that have
  2274. // a ReceievePendingOperation count of zero. For all the exchanges that belong
  2275. // to the first category the finalize ( quiescent state ) routine must be invoked
  2276. // since no receives will be forthcoming. For those exchanges that are in the
  2277. // second category it is sufficient to mark the MID as being invalid. The
  2278. // finalization( quiescent state ) routine is going to be called on completion
  2279. // of other opertaions in this case.
  2280. pMidAtlas = pServerEntry->pMidAtlas;
  2281. if (pMidAtlas != NULL) {
  2282. PVOID pContext;
  2283. USHORT MidsProcessed = 0;
  2284. USHORT NumberOfMidsInUse;
  2285. USHORT MaximumNumberOfMids;
  2286. USHORT NextMid = 0;
  2287. MaximumNumberOfMids = FsRtlGetMaximumNumberOfMids(pMidAtlas);
  2288. NumberOfMidsInUse = FsRtlGetNumberOfMidsInUse(pMidAtlas);
  2289. while ((NumberOfMidsInUse > MidsProcessed) &&
  2290. (NextMid < MaximumNumberOfMids)) {
  2291. pContext = FsRtlMapMidToContext(pMidAtlas,NextMid);
  2292. if (pContext != NULL) {
  2293. PSMB_EXCHANGE pExchange = (PSMB_EXCHANGE)pContext;
  2294. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_MID_VALID;
  2295. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  2296. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  2297. if ((pExchange->ReceivePendingOperations > 0) &&
  2298. ((pExchange->LocalPendingOperations > 0) ||
  2299. (pExchange->CopyDataPendingOperations > 0) ||
  2300. (pExchange->SendCompletePendingOperations > 0))) {
  2301. // There are other pending operations. By merely setting the
  2302. // pending receive operations to zero, the finalization of
  2303. // the exchange is ensured.
  2304. pExchange->ReceivePendingOperations = 0;
  2305. }
  2306. if (pExchange->ReceivePendingOperations == 0) {
  2307. FsRtlMapAndDissociateMidFromContext(pMidAtlas,NextMid,&pContext);
  2308. }
  2309. MidsProcessed++;
  2310. }
  2311. NextMid++;
  2312. }
  2313. }
  2314. // Transfer all the active exchanges to expired exchanges. This will prevent these
  2315. // exchanges from being considered for time outs again.
  2316. if (!IsListEmpty(&pServerEntry->ActiveExchanges)) {
  2317. pServerEntry->ExpiredExchanges.Blink->Flink = pServerEntry->ActiveExchanges.Flink;
  2318. pServerEntry->ActiveExchanges.Flink->Blink = pServerEntry->ExpiredExchanges.Blink;
  2319. pServerEntry->ExpiredExchanges.Blink = pServerEntry->ActiveExchanges.Blink;
  2320. pServerEntry->ActiveExchanges.Blink->Flink = &pServerEntry->ExpiredExchanges;
  2321. InitializeListHead(&pServerEntry->ActiveExchanges);
  2322. }
  2323. // Splice together all the requests that are awaiting the completion of the
  2324. // session/netroot construction.
  2325. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  2326. while (pSessionEntry != NULL) {
  2327. if (pSessionEntry->Header.State == SMBCEDB_ACTIVE) {
  2328. pSessionEntry->Header.State = SMBCEDB_INVALID;
  2329. }
  2330. if (!IsListEmpty(&pSessionEntry->Requests.ListHead)) {
  2331. Requests.ListHead.Blink->Flink = pSessionEntry->Requests.ListHead.Flink;
  2332. pSessionEntry->Requests.ListHead.Flink->Blink = Requests.ListHead.Blink;
  2333. Requests.ListHead.Blink = pSessionEntry->Requests.ListHead.Blink;
  2334. pSessionEntry->Requests.ListHead.Blink->Flink = &Requests.ListHead;
  2335. SmbCeInitializeRequests(&pSessionEntry->Requests);
  2336. }
  2337. pSessionEntry = SmbCeGetNextSessionEntry(pServerEntry,pSessionEntry);
  2338. }
  2339. pNetRootEntry = SmbCeGetFirstNetRootEntry(pServerEntry);
  2340. while (pNetRootEntry != NULL) {
  2341. if (pNetRootEntry->Header.State == SMBCEDB_ACTIVE) {
  2342. pNetRootEntry->Header.State = SMBCEDB_INVALID;
  2343. }
  2344. if (!IsListEmpty(&pNetRootEntry->Requests.ListHead)) {
  2345. Requests.ListHead.Blink->Flink = pNetRootEntry->Requests.ListHead.Flink;
  2346. pNetRootEntry->Requests.ListHead.Flink->Blink = Requests.ListHead.Blink;
  2347. Requests.ListHead.Blink = pNetRootEntry->Requests.ListHead.Blink;
  2348. pNetRootEntry->Requests.ListHead.Blink->Flink = &Requests.ListHead;
  2349. SmbCeInitializeRequests(&pNetRootEntry->Requests);
  2350. }
  2351. pNetRootEntry = SmbCeGetNextNetRootEntry(pServerEntry,pNetRootEntry);
  2352. }
  2353. pVNetRootContext = SmbCeGetFirstVNetRootContext(&pServerEntry->VNetRootContexts);
  2354. while (pVNetRootContext != NULL) {
  2355. pVNetRootContext->Header.State = SMBCEDB_INVALID;
  2356. ClearFlag(
  2357. pVNetRootContext->Flags,
  2358. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  2359. pVNetRootContext->TreeId = 0;
  2360. if (!IsListEmpty(&pVNetRootContext->Requests.ListHead)) {
  2361. Requests.ListHead.Blink->Flink = pVNetRootContext->Requests.ListHead.Flink;
  2362. pVNetRootContext->Requests.ListHead.Flink->Blink = Requests.ListHead.Blink;
  2363. Requests.ListHead.Blink = pVNetRootContext->Requests.ListHead.Blink;
  2364. pVNetRootContext->Requests.ListHead.Blink->Flink = &Requests.ListHead;
  2365. SmbCeInitializeRequests(&pVNetRootContext->Requests);
  2366. }
  2367. pVNetRootContext = SmbCeGetNextVNetRootContext(
  2368. &pServerEntry->VNetRootContexts,
  2369. pVNetRootContext);
  2370. }
  2371. pVNetRootContext = SmbCeGetFirstVNetRootContext(&MRxSmbScavengerServiceContext.VNetRootContexts);
  2372. while (pVNetRootContext != NULL &&
  2373. pVNetRootContext->pServerEntry == pServerEntry) {
  2374. // prevent the VNetRootContexts on the scavenger list from being reused
  2375. pVNetRootContext->Header.State = SMBCEDB_INVALID;
  2376. ClearFlag(
  2377. pVNetRootContext->Flags,
  2378. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  2379. pVNetRootContext->TreeId = 0;
  2380. pVNetRootContext = SmbCeGetNextVNetRootContext(
  2381. &MRxSmbScavengerServiceContext.VNetRootContexts,
  2382. pVNetRootContext);
  2383. }
  2384. pServerEntry->pMidAtlas = NULL;
  2385. if (pServerEntry->NegotiateInProgress) {
  2386. pServerEntry->Header.State = SMBCEDB_CONSTRUCTION_IN_PROGRESS;
  2387. } else {
  2388. pServerEntry->Header.State = SMBCEDB_INVALID;
  2389. }
  2390. pServerEntry->ResumeRequestsInProgress = FALSE;
  2391. //
  2392. // Remove all entries from the SecuritySignatureSyncRequests to a private list.
  2393. //
  2394. SmbCeTransferRequests(&SecuritySignatureSyncRequests,&pServerEntry->SecuritySignatureSyncRequests);
  2395. SmbCeReleaseSpinLock();
  2396. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  2397. SmbCeInitiateDisconnect(pServerEntry);
  2398. }
  2399. SmbCeReleaseResource();
  2400. //DbgPrint("SmbCeResumeAllOutstandingRequestsOnError: Processing outsanding request \n");
  2401. SmbCeResumeOutstandingRequests(&Requests,STATUS_CONNECTION_DISCONNECTED);
  2402. //DbgPrint("SmbCeResumeAllOutstandingRequestsOnError: Processing MID request \n");
  2403. SmbCeResumeDiscardedMidAssignmentRequests(
  2404. &MidRequests,
  2405. STATUS_CONNECTION_DISCONNECTED);
  2406. //
  2407. // Resume all the security signature sync requests...
  2408. //
  2409. if (!IsListEmpty(&SecuritySignatureSyncRequests.ListHead)) {
  2410. SmbCeResumeOutstandingRequests(&SecuritySignatureSyncRequests,STATUS_SUCCESS);
  2411. }
  2412. // Resume all the outstanding requests with the error indication
  2413. // The FsRtlDestroyMidAtlas destroys the Mid atlas and at the same
  2414. // time invokes the specified routine on each valid context.
  2415. if (pMidAtlas != NULL) {
  2416. FsRtlDestroyMidAtlas(pMidAtlas,SmbCeFinalizeExchangeOnDisconnect);
  2417. }
  2418. if (pNegotiateExchange != NULL) {
  2419. pNegotiateExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  2420. pNegotiateExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  2421. pNegotiateExchange->ReceivePendingOperations = 0;
  2422. SmbCeDecrementPendingLocalOperationsAndFinalize(pNegotiateExchange);
  2423. }
  2424. // The remaining ECHO exchanges on the expired exchanges list in the server entry
  2425. // needs to be finalized as well.
  2426. SmbCeAcquireResource();
  2427. SmbCeAcquireSpinLock();
  2428. if (!IsListEmpty(&pServerEntry->ExpiredExchanges)) {
  2429. PLIST_ENTRY pListEntry;
  2430. PSMB_EXCHANGE pExchange;
  2431. pListEntry = pServerEntry->ExpiredExchanges.Flink;
  2432. while (pListEntry != &pServerEntry->ExpiredExchanges) {
  2433. PLIST_ENTRY pNextListEntry = pListEntry->Flink;
  2434. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  2435. if ((pExchange->Mid == SMBCE_ECHO_PROBE_MID) &&
  2436. !FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED) &&
  2437. ((pExchange->ReceivePendingOperations > 0) ||
  2438. (pExchange->LocalPendingOperations > 0) ||
  2439. (pExchange->CopyDataPendingOperations > 0) ||
  2440. (pExchange->SendCompletePendingOperations > 0))) {
  2441. RemoveEntryList(&pExchange->ExchangeList);
  2442. InsertTailList(&ExpiredExchanges,&pExchange->ExchangeList);
  2443. InterlockedIncrement(&pExchange->LocalPendingOperations);
  2444. }
  2445. pListEntry = pNextListEntry;
  2446. }
  2447. }
  2448. SmbCeReleaseSpinLock();
  2449. SmbCeReleaseResource();
  2450. while (!IsListEmpty(&ExpiredExchanges)) {
  2451. PLIST_ENTRY pListEntry;
  2452. PSMB_EXCHANGE pExchange;
  2453. pListEntry = ExpiredExchanges.Flink;
  2454. RemoveHeadList(&ExpiredExchanges);
  2455. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  2456. InitializeListHead(&pExchange->ExchangeList);
  2457. RxLog(("Finalizing scavenged exchange %lx Type %ld\n",pExchange,pExchange->Type));
  2458. SmbLog(LOG,
  2459. SmbCeResumeAllOutstandingRequestsOnError,
  2460. LOGPTR(pExchange)
  2461. LOGUCHAR(pExchange->Type));
  2462. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  2463. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  2464. pExchange->ReceivePendingOperations = 0;
  2465. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  2466. }
  2467. //DbgPrint("SmbCeResumeAllOutstandingRequestsOnError: Exit \n");
  2468. SmbCeDereferenceServerEntry(pServerEntry);
  2469. }
  2470. VOID
  2471. SmbCeFinalizeAllExchangesForNetRoot(
  2472. PMRX_NET_ROOT pNetRoot)
  2473. /*++
  2474. Routine Description:
  2475. This routine handles the resumption of all outstanding requests on a forced
  2476. finalization of a connection
  2477. Arguments:
  2478. pNetRoot - the NetRoot which is being fianlized forcibly
  2479. Notes:
  2480. --*/
  2481. {
  2482. PMRX_SRV_CALL pSrvCall;
  2483. PSMBCEDB_SERVER_ENTRY pServerEntry;
  2484. SMBCEDB_REQUESTS Requests;
  2485. LIST_ENTRY ExpiredExchanges;
  2486. PSMB_EXCHANGE pExchange;
  2487. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  2488. PLIST_ENTRY pListEntry;
  2489. pSrvCall = pNetRoot->pSrvCall;
  2490. pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall);
  2491. InitializeListHead(&Requests.ListHead);
  2492. InitializeListHead(&ExpiredExchanges);
  2493. SmbCeAcquireSpinLock();
  2494. // Walk through the list of active exchanges, and the pending requests to
  2495. // weed out the exchanges for the given VNET_ROOT.
  2496. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  2497. while (pRequestEntry != NULL) {
  2498. pExchange = pRequestEntry->GenericRequest.pExchange;
  2499. if ((pRequestEntry->GenericRequest.Type == RECONNECT_REQUEST) &&
  2500. (pExchange->SmbCeContext.pVNetRoot != NULL) &&
  2501. (pExchange->SmbCeContext.pVNetRoot->pNetRoot == pNetRoot)) {
  2502. PSMBCEDB_REQUEST_ENTRY pTempRequestEntry;
  2503. pTempRequestEntry = pRequestEntry;
  2504. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  2505. SmbCeRemoveRequestEntryLite(&pServerEntry->OutstandingRequests,pTempRequestEntry);
  2506. SmbCeAddRequestEntryLite(&Requests,pTempRequestEntry);
  2507. } else {
  2508. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  2509. }
  2510. }
  2511. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->MidAssignmentRequests);
  2512. while (pRequestEntry != NULL) {
  2513. pExchange = pRequestEntry->GenericRequest.pExchange;
  2514. ASSERT(pRequestEntry->GenericRequest.Type == ACQUIRE_MID_REQUEST);
  2515. if ((pRequestEntry->GenericRequest.Type == ACQUIRE_MID_REQUEST) &&
  2516. (pExchange->SmbCeContext.pVNetRoot != NULL) &&
  2517. (pExchange->SmbCeContext.pVNetRoot->pNetRoot == pNetRoot)) {
  2518. PSMBCEDB_REQUEST_ENTRY pTempRequestEntry;
  2519. pTempRequestEntry = pRequestEntry;
  2520. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->MidAssignmentRequests,pRequestEntry);
  2521. SmbCeRemoveRequestEntryLite(&pServerEntry->MidAssignmentRequests,pTempRequestEntry);
  2522. // Signal the waiter for resumption
  2523. pTempRequestEntry->MidRequest.pResumptionContext->Status = STATUS_CONNECTION_DISCONNECTED;
  2524. SmbCeResume(pTempRequestEntry->MidRequest.pResumptionContext);
  2525. SmbCeTearDownRequestEntry(pTempRequestEntry);
  2526. } else {
  2527. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->MidAssignmentRequests,pRequestEntry);
  2528. }
  2529. }
  2530. pListEntry = pServerEntry->ActiveExchanges.Flink;
  2531. while (pListEntry != &pServerEntry->ActiveExchanges) {
  2532. PLIST_ENTRY pNextListEntry = pListEntry->Flink;
  2533. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  2534. if ((pExchange->SmbCeContext.pVNetRoot != NULL) &&
  2535. (pExchange->SmbCeContext.pVNetRoot->pNetRoot == pNetRoot)) {
  2536. if (!FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED)) {
  2537. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) {
  2538. NTSTATUS LocalStatus;
  2539. LocalStatus = SmbCepDiscardMidAssociatedWithExchange(
  2540. pExchange);
  2541. ASSERT(LocalStatus == STATUS_SUCCESS);
  2542. }
  2543. if ((pExchange->ReceivePendingOperations > 0) ||
  2544. (pExchange->LocalPendingOperations > 0) ||
  2545. (pExchange->CopyDataPendingOperations > 0) ||
  2546. (pExchange->SendCompletePendingOperations > 0)) {
  2547. RemoveEntryList(&pExchange->ExchangeList);
  2548. InsertTailList(&ExpiredExchanges,&pExchange->ExchangeList);
  2549. InterlockedIncrement(&pExchange->LocalPendingOperations);
  2550. }
  2551. }
  2552. }
  2553. pListEntry = pNextListEntry;
  2554. }
  2555. SmbCeReleaseSpinLock();
  2556. while (!IsListEmpty(&ExpiredExchanges)) {
  2557. PLIST_ENTRY pListEntry;
  2558. PSMB_EXCHANGE pExchange;
  2559. pListEntry = ExpiredExchanges.Flink;
  2560. RemoveHeadList(&ExpiredExchanges);
  2561. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  2562. InitializeListHead(&pExchange->ExchangeList);
  2563. RxLog(("Finalizing scavenged exchange %lx Type %ld\n",pExchange,pExchange->Type));
  2564. SmbLog(LOG,
  2565. SmbCeFinalizeAllExchangesForNetRoot,
  2566. LOGPTR(pExchange)
  2567. LOGUCHAR(pExchange->Type));
  2568. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  2569. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  2570. pExchange->ReceivePendingOperations = 0;
  2571. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  2572. }
  2573. SmbCeResumeOutstandingRequests(&Requests,STATUS_CONNECTION_DISCONNECTED);
  2574. }
  2575. VOID
  2576. SmbCeTearDownRequestEntry(
  2577. PSMBCEDB_REQUEST_ENTRY pRequestEntry)
  2578. /*++
  2579. Routine Description:
  2580. This routine tears down a request entry
  2581. Arguments:
  2582. pRequestEntry - the request entry to be torn down
  2583. Notes:
  2584. --*/
  2585. {
  2586. SmbMmFreeObject(pRequestEntry);
  2587. }
  2588. //
  2589. // The connection engine database initializtion/tear down routines
  2590. //
  2591. extern NTSTATUS
  2592. SmbMmInit();
  2593. extern VOID
  2594. SmbMmTearDown();
  2595. KIRQL s_SmbCeDbSpinLockSavedIrql;
  2596. KSPIN_LOCK s_SmbCeDbSpinLock;
  2597. ERESOURCE s_SmbCeDbResource;
  2598. ERESOURCE s_SmbSecuritySignatureResource;
  2599. SMBCEDB_SERVERS s_DbServers;
  2600. BOOLEAN s_SmbCeDbSpinLockAcquired;
  2601. NTSTATUS
  2602. SmbCeDbInit()
  2603. /*++
  2604. Routine Description:
  2605. This routine initializes the SMBCe database
  2606. Notes:
  2607. --*/
  2608. {
  2609. NTSTATUS Status;
  2610. PAGED_CODE();
  2611. // Initialize the lists associated with various database entities
  2612. InitializeListHead(&s_DbServers.ListHead);
  2613. // Initialize the resource associated with the database.
  2614. KeInitializeSpinLock(&s_SmbCeDbSpinLock );
  2615. ExInitializeResource(&s_SmbCeDbResource);
  2616. ExInitializeResource(&s_SmbSecuritySignatureResource);
  2617. s_SmbCeDbSpinLockAcquired = FALSE;
  2618. MRxSmbInitializeSmbCe();
  2619. // Initialize the memory management data structures.
  2620. Status = SmbMmInit();
  2621. return Status;
  2622. }
  2623. VOID
  2624. SmbCeDbTearDown()
  2625. /*++
  2626. Routine Description:
  2627. This routine tears down the SMB connection engine database
  2628. Notes:
  2629. --*/
  2630. {
  2631. // Walk through the list of servers and tear them down.
  2632. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  2633. KEVENT ServerEntryTearDownEvent;
  2634. BOOLEAN NeedToWait = FALSE;
  2635. KeInitializeEvent(
  2636. &ServerEntryTearDownEvent,
  2637. NotificationEvent,
  2638. FALSE);
  2639. SmbCeStartStopContext.pServerEntryTearDownEvent = &ServerEntryTearDownEvent;
  2640. // The CSC code obtains references on all the servers that are operating in
  2641. // disconnected mode. Force it to release the references since we are shutting
  2642. // down.
  2643. CscTransitionServerToOnline(0);
  2644. SmbCeAcquireResource();
  2645. SmbCeAcquireSpinLock();
  2646. pServerEntry = SmbCeGetFirstServerEntry();
  2647. if (pServerEntry != NULL) {
  2648. SmbCeReferenceServerEntry(pServerEntry);
  2649. NeedToWait = TRUE;
  2650. }
  2651. while (pServerEntry != NULL) {
  2652. PSMBCEDB_SERVER_ENTRY pTempServerEntry;
  2653. pTempServerEntry = pServerEntry;
  2654. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  2655. if (pServerEntry != NULL) {
  2656. SmbCeReferenceServerEntry(pServerEntry);
  2657. }
  2658. SmbCeReleaseSpinLock();
  2659. SmbCeReleaseResource();
  2660. pTempServerEntry->Header.State = SMBCEDB_DESTRUCTION_IN_PROGRESS;
  2661. pTempServerEntry->ServerStatus = RX_MAP_STATUS(REDIRECTOR_PAUSED);
  2662. SmbCeResumeAllOutstandingRequestsOnError(pTempServerEntry);
  2663. SmbCeAcquireResource();
  2664. SmbCeAcquireSpinLock();
  2665. }
  2666. SmbCeReleaseSpinLock();
  2667. SmbCeReleaseResource();
  2668. MRxSmbUninitializeTransport();
  2669. MRxSmbTearDownSmbCe();
  2670. if (NeedToWait) {
  2671. KeWaitForSingleObject(
  2672. &ServerEntryTearDownEvent,
  2673. Executive,
  2674. KernelMode,
  2675. FALSE,
  2676. NULL);
  2677. }
  2678. // Tear down the connection engine memory management data structures.
  2679. SmbMmTearDown();
  2680. }
  2681. NTSTATUS
  2682. FindServerEntryFromCompleteUNCPath(
  2683. USHORT *lpuServerShareName,
  2684. PSMBCEDB_SERVER_ENTRY *ppServerEntry
  2685. )
  2686. /*++
  2687. Routine Description:
  2688. Given a UNC path of the form \\server\share, this routine looks up the redir
  2689. in-memory data structures to locate such s SMBCEDB_SERVER_ENTRY for the server
  2690. Arguments:
  2691. lpuServerShareName \\server\share
  2692. ppServerEntry Contains the server entry if successful
  2693. Notes:
  2694. The server entry is refcounted, hence the caller must dereference it after use by
  2695. calling SmbCeDereferenceServerEntry
  2696. --*/
  2697. {
  2698. UNICODE_STRING unistrServerName;
  2699. USHORT *lpuT = lpuServerShareName;
  2700. DWORD dwlenServerShare, dwlenServer=0;
  2701. if ((*lpuT++ != (USHORT)'\\') || (*lpuT++ != (USHORT)'\\'))
  2702. {
  2703. return STATUS_INVALID_PARAMETER;
  2704. }
  2705. for (dwlenServerShare = 1; *lpuT; lpuT++, dwlenServerShare++)
  2706. {
  2707. if (*lpuT == (USHORT)'\\')
  2708. {
  2709. if (dwlenServer)
  2710. {
  2711. break;
  2712. }
  2713. else
  2714. {
  2715. dwlenServer = dwlenServerShare; // length of the \server part
  2716. }
  2717. }
  2718. }
  2719. unistrServerName.Length = unistrServerName.MaximumLength = (USHORT)(dwlenServer * sizeof(USHORT));
  2720. unistrServerName.Buffer = lpuServerShareName+1;
  2721. SmbCeAcquireResource();
  2722. try
  2723. {
  2724. *ppServerEntry = SmbCeFindServerEntry(&unistrServerName, SMBCEDB_FILE_SERVER, NULL);
  2725. if (!*ppServerEntry)
  2726. {
  2727. *ppServerEntry = SmbCeFindDfsServerEntry(&unistrServerName, SMBCEDB_FILE_SERVER);
  2728. }
  2729. }
  2730. except(EXCEPTION_EXECUTE_HANDLER)
  2731. {
  2732. SmbCeReleaseResource();
  2733. return STATUS_UNSUCCESSFUL;
  2734. }
  2735. SmbCeReleaseResource();
  2736. if (*ppServerEntry)
  2737. {
  2738. return STATUS_SUCCESS;
  2739. }
  2740. return STATUS_UNSUCCESSFUL;
  2741. }
  2742. NTSTATUS
  2743. FindNetRootEntryFromCompleteUNCPath(
  2744. USHORT *lpuServerShareName,
  2745. PSMBCEDB_NET_ROOT_ENTRY *ppNetRootEntry
  2746. )
  2747. /*++
  2748. Routine Description:
  2749. Given a UNC path of the form \\server\share, this routine looks up the redir
  2750. in-memory data structures to locate such a NETROOT
  2751. Arguments:
  2752. lpuServerShareName \\server\share
  2753. ppNetRootEntry Contains the netroot entry if successful.
  2754. Notes:
  2755. The netroot entry is refcounted, hence the caller must dereference it after use by
  2756. calling SmbCeDereferenceNetRootEntry
  2757. --*/
  2758. {
  2759. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  2760. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
  2761. UNICODE_STRING unistrServerName, unistrServerShare;
  2762. USHORT *lpuT = lpuServerShareName, *lpuDfsShare=NULL, *lpuSav;
  2763. DWORD dwlenServerShare, dwlenServer=0;
  2764. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2765. if ((*lpuT++ != (USHORT)'\\') || (*lpuT++ != (USHORT)'\\'))
  2766. {
  2767. return STATUS_INVALID_PARAMETER;
  2768. }
  2769. for (dwlenServerShare = 1; *lpuT; lpuT++, dwlenServerShare++)
  2770. {
  2771. if (*lpuT == (USHORT)'\\')
  2772. {
  2773. if (dwlenServer)
  2774. {
  2775. break;
  2776. }
  2777. else
  2778. {
  2779. dwlenServer = dwlenServerShare; // length of the \server part
  2780. }
  2781. }
  2782. }
  2783. ASSERT((dwlenServerShare>dwlenServer));
  2784. unistrServerName.Length = unistrServerName.MaximumLength = (USHORT)(dwlenServer * sizeof(USHORT));
  2785. unistrServerName.Buffer = lpuServerShareName+1;
  2786. unistrServerShare.Length = unistrServerShare.MaximumLength = (USHORT)(dwlenServerShare * sizeof(USHORT));
  2787. unistrServerShare.Buffer = lpuServerShareName+1;
  2788. SmbCeAcquireResource();
  2789. try
  2790. {
  2791. // lookup in standard places
  2792. pServerEntry = SmbCeFindServerEntry(&unistrServerName, SMBCEDB_FILE_SERVER, NULL);
  2793. if (pServerEntry)
  2794. {
  2795. pNetRootEntry = SmbCeFindNetRootEntry(pServerEntry, &unistrServerShare);
  2796. SmbCeDereferenceServerEntry(pServerEntry);
  2797. if (pNetRootEntry)
  2798. {
  2799. goto bailout;
  2800. }
  2801. }
  2802. // now look to see if a DFS alternate has this share
  2803. pServerEntry = SmbCeGetFirstServerEntry();
  2804. while (pServerEntry != NULL) {
  2805. DWORD dwAllocationSize = 0;
  2806. if ((RtlCompareUnicodeString(
  2807. &unistrServerName,
  2808. &pServerEntry->DfsRootName,
  2809. TRUE) == 0)) {
  2810. dwAllocationSize = pServerEntry->Name.MaximumLength+
  2811. (dwlenServerShare-dwlenServer+2) * sizeof(USHORT);
  2812. lpuDfsShare = RxAllocatePoolWithTag(
  2813. NonPagedPool,
  2814. dwAllocationSize,
  2815. MRXSMB_SESSION_POOLTAG);
  2816. if (!lpuDfsShare)
  2817. {
  2818. Status = STATUS_INSUFFICIENT_RESOURCES;
  2819. goto bailout;
  2820. }
  2821. ASSERT(dwAllocationSize > pServerEntry->Name.MaximumLength);
  2822. unistrServerShare.Length = (USHORT)(pServerEntry->Name.Length + (dwlenServerShare-dwlenServer) * sizeof(USHORT));
  2823. unistrServerShare.MaximumLength = (USHORT)(pServerEntry->Name.MaximumLength+
  2824. (dwlenServerShare-dwlenServer+2) * sizeof(USHORT));
  2825. memcpy(lpuDfsShare, pServerEntry->Name.Buffer, pServerEntry->Name.Length);
  2826. memcpy(&lpuDfsShare[pServerEntry->Name.Length/sizeof(USHORT)],
  2827. &(unistrServerShare.Buffer[dwlenServer]),
  2828. (dwlenServerShare-dwlenServer) * sizeof(USHORT));
  2829. lpuSav = unistrServerShare.Buffer;
  2830. unistrServerShare.Buffer = lpuDfsShare;
  2831. pNetRootEntry = SmbCeFindNetRootEntry(pServerEntry, &unistrServerShare);
  2832. unistrServerShare.Buffer = lpuSav;
  2833. RxFreePool(lpuDfsShare);
  2834. // stop if we found it
  2835. if (pNetRootEntry)
  2836. {
  2837. break;
  2838. }
  2839. }
  2840. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  2841. }
  2842. }
  2843. except(EXCEPTION_EXECUTE_HANDLER)
  2844. {
  2845. goto bailout;
  2846. }
  2847. bailout:
  2848. if (pNetRootEntry)
  2849. {
  2850. SmbCeReferenceNetRootEntry(pNetRootEntry);
  2851. *ppNetRootEntry = pNetRootEntry;
  2852. Status = STATUS_SUCCESS;
  2853. }
  2854. SmbCeReleaseResource();
  2855. return Status;
  2856. }
  2857. NTSTATUS
  2858. MRxSmbCscCachingBitsFromCompleteUNCPath(
  2859. PWSTR lpServerShare,
  2860. ULONG *lpulBits
  2861. )
  2862. /*++
  2863. Routine Description:
  2864. Given a UNC path of the form \\server\share, this routine checks to see whether
  2865. such a NETROOT exists, and if so, it gets the SMB flags for that entry
  2866. Arguments:
  2867. lpuServerShareName \\server\share
  2868. lpulBits SMB bits
  2869. Notes:
  2870. --*/
  2871. {
  2872. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry=NULL;
  2873. NTSTATUS Status;
  2874. if ((Status = FindNetRootEntryFromCompleteUNCPath(lpServerShare, &pNetRootEntry)) == STATUS_SUCCESS)
  2875. {
  2876. // convert these bits to those defined in csc\inc\shdcom.h
  2877. *lpulBits = (pNetRootEntry->NetRoot.CscFlags << 4);
  2878. SmbCeDereferenceNetRootEntry(pNetRootEntry);
  2879. }
  2880. return Status;
  2881. }
  2882. NTSTATUS
  2883. MRxSmbCscServerStateFromCompleteUNCPath(
  2884. PWSTR lpServerShare,
  2885. BOOL *lpfOnline,
  2886. BOOL *lpfPinnedOffline
  2887. )
  2888. {
  2889. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  2890. NTSTATUS Status;
  2891. if ((Status = FindServerEntryFromCompleteUNCPath(lpServerShare, &pServerEntry)) == STATUS_SUCCESS)
  2892. {
  2893. *lpfOnline = (pServerEntry->Server.CscState == ServerCscShadowing);
  2894. *lpfPinnedOffline = (pServerEntry->Server.IsPinnedOffline == TRUE);
  2895. SmbCeDereferenceServerEntry(pServerEntry);
  2896. }
  2897. return Status;
  2898. }
  2899. NTSTATUS
  2900. MRxSmbCscIsLoopbackServer(
  2901. PWSTR lpServerShare,
  2902. BOOL *lpfIsLoopBack)
  2903. {
  2904. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  2905. NTSTATUS Status;
  2906. if ((Status = FindServerEntryFromCompleteUNCPath(lpServerShare, &pServerEntry)) == STATUS_SUCCESS)
  2907. {
  2908. *lpfIsLoopBack = pServerEntry->Server.IsLoopBack;
  2909. SmbCeDereferenceServerEntry(pServerEntry);
  2910. }
  2911. return Status;
  2912. }
  2913. PSMBCEDB_SESSION_ENTRY
  2914. SmbCeGetDefaultSessionEntry(
  2915. PSMBCEDB_SERVER_ENTRY pServerEntry,
  2916. ULONG SessionId,
  2917. PLUID pLogonId
  2918. )
  2919. /*++
  2920. Routine Description:
  2921. This routine returns the session entry from the default sessions list.
  2922. Arguments:
  2923. pServerEntry - Server entry
  2924. SessionId - Hydra session Id.
  2925. pLogonId - the logon id.
  2926. Notes:
  2927. This is called with the SmbCe spinlock held.
  2928. --*/
  2929. {
  2930. PLIST_ENTRY pListEntry;
  2931. PSMBCEDB_SESSION_ENTRY pSession;
  2932. PSMBCEDB_SESSION_ENTRY pReturnSession = NULL;
  2933. ASSERT( pServerEntry != NULL );
  2934. pListEntry = pServerEntry->Sessions.DefaultSessionList.Flink;
  2935. while( pListEntry != &pServerEntry->Sessions.DefaultSessionList ) {
  2936. pSession = CONTAINING_RECORD( pListEntry, SMBCEDB_SESSION_ENTRY, DefaultSessionLink );
  2937. if( pSession->Session.SessionId == SessionId ) {
  2938. if (RtlEqualLuid(
  2939. &pSession->Session.LogonId,
  2940. pLogonId)) {
  2941. pReturnSession = pSession;
  2942. break;
  2943. }
  2944. }
  2945. pListEntry = pListEntry->Flink;
  2946. }
  2947. return( pReturnSession );
  2948. }
  2949. VOID
  2950. SmbCeRemoveDefaultSessionEntry(
  2951. PSMBCEDB_SESSION_ENTRY pDefaultSessionEntry
  2952. )
  2953. /*++
  2954. Routine Description:
  2955. This routine removes the session entry from the default sessions list.
  2956. Arguments:
  2957. pServerEntry - Server entry
  2958. SessionId - Hydra session Id.
  2959. pLogonId - the logon id.
  2960. Notes:
  2961. This is called with the SmbCe spinlock held.
  2962. --*/
  2963. {
  2964. if( pDefaultSessionEntry &&
  2965. pDefaultSessionEntry->DefaultSessionLink.Flink ) {
  2966. RemoveEntryList( &pDefaultSessionEntry->DefaultSessionLink );
  2967. pDefaultSessionEntry->DefaultSessionLink.Flink = NULL;
  2968. pDefaultSessionEntry->DefaultSessionLink.Blink = NULL;
  2969. }
  2970. }
  2971. VOID
  2972. MRxSmbTrackRefCount(
  2973. PVOID pInstance,
  2974. PCHAR FileName,
  2975. ULONG Line)
  2976. {
  2977. LONG State = ((PSMBCE_OBJECT_HEADER)pInstance)->State;
  2978. LONG RefCount = ((PSMBCE_OBJECT_HEADER)pInstance)->SwizzleCount;
  2979. SMBCEDB_OBJECT_TYPE ObjectType = ((PSMBCE_OBJECT_HEADER)pInstance)->ObjectType;
  2980. switch (ObjectType) {
  2981. case SMBCEDB_OT_SERVER :
  2982. if (MRXSMB_REF_TRACING_ON(MRXSMB_REF_TRACE_SERVER_ENTRY)) {
  2983. if (MRxSmbReferenceTracingValue & MRXSMB_LOG_REF_TRACKING) {
  2984. RxLog((" Ref ServerEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName));
  2985. }
  2986. if (MRxSmbReferenceTracingValue & MRXSMB_PRINT_REF_TRACKING) {
  2987. DbgPrint(" Ref ServerEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName);
  2988. }
  2989. }
  2990. SmbLog(SERVER,MRxSmbRefServerEntry,LOGPTR(pInstance)LOGULONG(State)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
  2991. break;
  2992. case SMBCEDB_OT_NETROOT :
  2993. if (MRXSMB_REF_TRACING_ON(MRXSMB_REF_TRACE_NETROOT_ENTRY)) {
  2994. if (MRxSmbReferenceTracingValue & MRXSMB_LOG_REF_TRACKING) {
  2995. RxLog((" Ref NetRootEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName));
  2996. }
  2997. if (MRxSmbReferenceTracingValue & MRXSMB_PRINT_REF_TRACKING) {
  2998. DbgPrint(" Ref NetRootEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName);
  2999. }
  3000. }
  3001. SmbLog(NETROOT,MRxSmbRefNetRootEntry,LOGPTR(pInstance)LOGULONG(State)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
  3002. break;
  3003. case SMBCEDB_OT_SESSION :
  3004. if (MRXSMB_REF_TRACING_ON(MRXSMB_REF_TRACE_SESSION_ENTRY)) {
  3005. if (MRxSmbReferenceTracingValue & MRXSMB_LOG_REF_TRACKING) {
  3006. RxLog((" Ref SessionEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName));
  3007. }
  3008. if (MRxSmbReferenceTracingValue & MRXSMB_PRINT_REF_TRACKING) {
  3009. DbgPrint(" Ref SessionEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName);
  3010. }
  3011. }
  3012. SmbLog(SESSION,MRxSmbRefSessionEntry,LOGPTR(pInstance)LOGULONG(State)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
  3013. break;
  3014. case SMBCEDB_OT_VNETROOTCONTEXT :
  3015. if (MRXSMB_REF_TRACING_ON(MRXSMB_REF_TRACE_VNETROOT_CONTEXT)) {
  3016. if (MRxSmbReferenceTracingValue & MRXSMB_LOG_REF_TRACKING) {
  3017. RxLog((" Ref VNetRootConext %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName));
  3018. }
  3019. if (MRxSmbReferenceTracingValue & MRXSMB_PRINT_REF_TRACKING) {
  3020. DbgPrint(" Ref VNetRootContext %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName);
  3021. }
  3022. }
  3023. SmbLog(VNETROOT,MRxSmbRefVNetRootContext,LOGPTR(pInstance)LOGULONG(State)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
  3024. break;
  3025. }
  3026. }
  3027. VOID
  3028. MRxSmbTrackDerefCount(
  3029. PVOID pInstance,
  3030. PCHAR FileName,
  3031. ULONG Line)
  3032. {
  3033. LONG State = ((PSMBCE_OBJECT_HEADER)pInstance)->State;
  3034. LONG RefCount = ((PSMBCE_OBJECT_HEADER)pInstance)->SwizzleCount;
  3035. SMBCEDB_OBJECT_TYPE ObjectType = ((PSMBCE_OBJECT_HEADER)pInstance)->ObjectType;
  3036. switch (ObjectType) {
  3037. case SMBCEDB_OT_SERVER :
  3038. if (MRXSMB_REF_TRACING_ON(MRXSMB_REF_TRACE_SERVER_ENTRY)) {
  3039. if (MRxSmbReferenceTracingValue & MRXSMB_LOG_REF_TRACKING) {
  3040. RxLog(("Deref ServerEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName));
  3041. }
  3042. if (MRxSmbReferenceTracingValue & MRXSMB_PRINT_REF_TRACKING) {
  3043. DbgPrint("Deref ServerEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName);
  3044. }
  3045. }
  3046. SmbLog(SERVER,MRxSmbDerefServerEntry,LOGPTR(pInstance)LOGULONG(State)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
  3047. break;
  3048. case SMBCEDB_OT_NETROOT :
  3049. if (MRXSMB_REF_TRACING_ON(MRXSMB_REF_TRACE_NETROOT_ENTRY)) {
  3050. if (MRxSmbReferenceTracingValue & MRXSMB_LOG_REF_TRACKING) {
  3051. RxLog(("Deref NetRootEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName));
  3052. }
  3053. if (MRxSmbReferenceTracingValue & MRXSMB_PRINT_REF_TRACKING) {
  3054. DbgPrint("Deref NetRootEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName);
  3055. }
  3056. }
  3057. SmbLog(NETROOT,MRxSmbDerefNetRootEntry,LOGPTR(pInstance)LOGULONG(State)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
  3058. break;
  3059. case SMBCEDB_OT_SESSION :
  3060. if (MRXSMB_REF_TRACING_ON(MRXSMB_REF_TRACE_SESSION_ENTRY)) {
  3061. if (MRxSmbReferenceTracingValue & MRXSMB_LOG_REF_TRACKING) {
  3062. RxLog(("Deref SessionEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName));
  3063. }
  3064. if (MRxSmbReferenceTracingValue & MRXSMB_PRINT_REF_TRACKING) {
  3065. DbgPrint("Deref SessionEntry %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName);
  3066. }
  3067. }
  3068. SmbLog(SESSION,MRxSmbDerefSessionEntry,LOGPTR(pInstance)LOGULONG(State)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
  3069. break;
  3070. case SMBCEDB_OT_VNETROOTCONTEXT :
  3071. if (MRXSMB_REF_TRACING_ON(MRXSMB_REF_TRACE_VNETROOT_CONTEXT)) {
  3072. if (MRxSmbReferenceTracingValue & MRXSMB_LOG_REF_TRACKING) {
  3073. RxLog(("Deref VNetRootConext %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName));
  3074. }
  3075. if (MRxSmbReferenceTracingValue & MRXSMB_PRINT_REF_TRACKING) {
  3076. DbgPrint("Deref VNetRootContext %lx %d %d %ld %s\n",pInstance,State,RefCount,Line,FileName);
  3077. }
  3078. }
  3079. SmbLog(VNETROOT,MRxSmbDerefVNetRootContext,LOGPTR(pInstance)LOGULONG(State)LOGULONG(RefCount)LOGULONG(Line)LOGARSTR(FileName));
  3080. break;
  3081. }
  3082. }