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.

2990 lines
96 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 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. Notes:
  9. The construction of server, net root and session entries involve a certain
  10. amount of network traffic. Therefore, all these entities are constructed
  11. using a two phase protocol
  12. This continuation context is that of the RDBSS during construction of
  13. srv call and net root entries. For the session entries it is an SMB exchange
  14. that needs to be resumed.
  15. Two of the three primary data structures in the SMB mini redirector, i.e.,
  16. SMBCEDB_SERVER_ENTRY, SMBCEDB_SESSION_ENTRY and SMBCEDB_NET_ROOT_ENTRY have
  17. directcounterparts in the RDBSS (MRX_SRV_CALL, MRX_V_NET_ROOT and MRX_NET_ROOT)
  18. constitute the core of the SMB mini redirector connection engine. There exists
  19. a one to one mapping between the SERVER_ENTRY and the MRX_SRV_CALL, as well
  20. as NET_ROOT_ENTRY and MRX_NET_ROOT.
  21. The SMBCEDB_SESSION_ENTRY does not have a direct mapping to a wrapper data
  22. structue, It is a part of SMBCE_V_NET_ROOT_CONTEXT which is the data
  23. structure associated with a MRX_V_NET_ROOT instance.
  24. More than one tree connect to a server can use the same session on a USER level
  25. security share. Consequently mapping rules need to be established to manage this
  26. relationship. The SMB mini redirector implements the following rules ...
  27. 1) The first session with explicitly specified credentials will be
  28. treated as the default session for all subsequent requests to any given
  29. server unless credentials are explicitly specified for the new session.
  30. 2) If no session with explicitly specified credentials exist then a
  31. session with the same logon id. is choosen.
  32. 3) If no session with the same logon id. exists a new session is created.
  33. These rules are liable to change as we experiment with rules for establishing
  34. sessions with differing credentials to a given server. The problem is not with
  35. creating/manipulating these sessions but providing an adequate set of
  36. fallback rules for emulating the behaviour of the old redirector.
  37. These rules are implemented in SmbCeFindOrConstructSessionEntry.
  38. --*/
  39. #include "precomp.h"
  40. #pragma hdrstop
  41. #ifdef ALLOC_PRAGMA
  42. #pragma alloc_text(PAGE, SmbCeUpdateSrvCall)
  43. #pragma alloc_text(PAGE, SmbCeTearDownServerEntry)
  44. #pragma alloc_text(PAGE, SmbCeCompleteSessionEntryInitialization)
  45. #pragma alloc_text(PAGE, SmbCeGetUserNameAndDomainName)
  46. #pragma alloc_text(PAGE, SmbCeTearDownSessionEntry)
  47. #pragma alloc_text(PAGE, SmbCeTearDownNetRootEntry)
  48. #pragma alloc_text(PAGE, SmbCeUpdateNetRoot)
  49. #pragma alloc_text(PAGE, SmbCeDbInit)
  50. #endif
  51. RXDT_DefineCategory(SMBCEDB);
  52. #define Dbg (DEBUG_TRACE_SMBCEDB)
  53. // The flag mask to control reference count tracing.
  54. ULONG MRxSmbReferenceTracingValue = 0;
  55. PSMBCEDB_SERVER_ENTRY
  56. SmbCeFindServerEntry(
  57. PUNICODE_STRING pServerName,
  58. SMBCEDB_SERVER_TYPE ServerType)
  59. /*++
  60. Routine Description:
  61. This routine searches the list of server entries and locates a matching
  62. entry
  63. Arguments:
  64. pServerName - the name of the server
  65. ServerType - the server type
  66. Notes:
  67. The SmbCeResource must be held on entry and its ownership state will remain
  68. unchanged on exit
  69. --*/
  70. {
  71. PSMBCEDB_SERVER_ENTRY pServerEntry;
  72. ASSERT(SmbCeIsResourceOwned());
  73. pServerEntry = SmbCeGetFirstServerEntry();
  74. while (pServerEntry != NULL) {
  75. if ((RtlCompareUnicodeString(
  76. pServerName,
  77. &pServerEntry->Name,
  78. TRUE) == 0)) {
  79. SmbCeReferenceServerEntry(pServerEntry);
  80. break;
  81. } else {
  82. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  83. }
  84. }
  85. return pServerEntry;
  86. }
  87. NTSTATUS
  88. SmbCeFindOrConstructServerEntry(
  89. PUNICODE_STRING pServerName,
  90. SMBCEDB_SERVER_TYPE ServerType,
  91. PSMBCEDB_SERVER_ENTRY *pServerEntryPtr,
  92. PBOOLEAN pNewServerEntry)
  93. /*++
  94. Routine Description:
  95. This routine searches the list of server entries and locates a matching
  96. entry or constructs a new one with the given name
  97. Arguments:
  98. pServerName - the name of the server
  99. ServerType - the type of server
  100. pServerEntryPtr - placeholder for the server entry
  101. pNewServerEntry - set to TRUE if it is a newly created server entry
  102. Notes:
  103. The SmbCeResource must be held on entry and its ownership state will remain
  104. unchanged on exit
  105. --*/
  106. {
  107. NTSTATUS Status = STATUS_SUCCESS;
  108. BOOLEAN fNewServerEntry = FALSE;
  109. PSMBCEDB_SERVER_ENTRY pServerEntry;
  110. ASSERT(SmbCeIsResourceOwned());
  111. pServerEntry = SmbCeFindServerEntry(
  112. pServerName,
  113. ServerType);
  114. if (pServerEntry == NULL) {
  115. // Create a server instance, initialize its state, add it to the list
  116. pServerEntry = (PSMBCEDB_SERVER_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_SERVER);
  117. if (pServerEntry != NULL) {
  118. pServerEntry->Name.Buffer = RxAllocatePoolWithTag(
  119. NonPagedPool,
  120. pServerName->Length,
  121. MRXSMB_SERVER_POOLTAG);
  122. if (pServerEntry->Name.Buffer == NULL) {
  123. SmbMmFreeObject(pServerEntry);
  124. pServerEntry = NULL;
  125. }
  126. }
  127. if (pServerEntry != NULL) {
  128. fNewServerEntry = TRUE;
  129. pServerEntry->Name.Length = pServerName->Length;
  130. pServerEntry->Name.MaximumLength = pServerEntry->Name.Length;
  131. RtlCopyMemory(
  132. pServerEntry->Name.Buffer,
  133. pServerName->Buffer,
  134. pServerEntry->Name.Length);
  135. SmbCeUpdateServerEntryState(
  136. pServerEntry,
  137. SMBCEDB_CONSTRUCTION_IN_PROGRESS);
  138. SmbCeSetServerType(
  139. pServerEntry,
  140. ServerType);
  141. pServerEntry->PreferredTransport = NULL;
  142. SmbCeReferenceServerEntry(pServerEntry);
  143. SmbCeAddServerEntry(pServerEntry);
  144. SmbCeLog(("NewSrvEntry %lx %wZ\n",pServerEntry,&pServerEntry->Name));
  145. } else {
  146. RxDbgTrace(0, Dbg, ("SmbCeOpenServer : Server Entry Allocation failed\n"));
  147. Status = STATUS_INSUFFICIENT_RESOURCES;
  148. }
  149. } else {
  150. if (pServerEntry->PreferredTransport != NULL) {
  151. // reset the preferred transport created by previous owner
  152. SmbCeDereferenceTransport(pServerEntry->PreferredTransport);
  153. pServerEntry->PreferredTransport = NULL;
  154. }
  155. SmbCeLog(("CachedSrvEntry %lx %wZ\n",pServerEntry,&pServerEntry->Name));
  156. }
  157. *pServerEntryPtr = pServerEntry;
  158. *pNewServerEntry = fNewServerEntry;
  159. return Status;
  160. }
  161. VOID
  162. SmbCeCompleteSrvCallConstruction(
  163. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext)
  164. /*++
  165. Routine Description:
  166. This routine comlpletes the srvcall construtcion routine by invoking
  167. the callback routine to the wrapper.
  168. Arguments:
  169. pCallbackContext - the RDBSS context
  170. Notes:
  171. --*/
  172. {
  173. PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure;
  174. PMRX_SRV_CALL pSrvCall;
  175. PSMBCEDB_SERVER_ENTRY pServerEntry;
  176. BOOLEAN MustSucceed = FALSE;
  177. NTSTATUS Status;
  178. PAGED_CODE();
  179. SrvCalldownStructure =
  180. (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);
  181. pSrvCall = SrvCalldownStructure->SrvCall;
  182. pServerEntry = (PSMBCEDB_SERVER_ENTRY)pCallbackContext->RecommunicateContext;
  183. if (pServerEntry != NULL) {
  184. if (!NT_SUCCESS(pCallbackContext->Status)) {
  185. if (pCallbackContext->Status == STATUS_RETRY) {
  186. MustSucceed = TRUE;
  187. }
  188. SmbCeDereferenceServerEntry(pServerEntry);
  189. }
  190. } else {
  191. pCallbackContext->Status = STATUS_INSUFFICIENT_RESOURCES;
  192. }
  193. if (MustSucceed) {
  194. //DbgPrint("Build ServerEntry %X try again.\n",pCallbackContext->Status);
  195. // Transport is not ready and the cache is not filled, we need to create the
  196. // server entry again until it succeeds.
  197. Status = RxDispatchToWorkerThread(
  198. MRxSmbDeviceObject,
  199. CriticalWorkQueue,
  200. SmbCeCreateSrvCall,
  201. pCallbackContext);
  202. } else {
  203. SrvCalldownStructure->CallBack(pCallbackContext);
  204. }
  205. }
  206. NTSTATUS
  207. SmbCeInitializeServerEntry(
  208. PMRX_SRV_CALL pSrvCall,
  209. PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext,
  210. BOOLEAN fDeferNetworkInitialization)
  211. /*++
  212. Routine Description:
  213. This routine opens/creates a server entry in the connection engine database
  214. Arguments:
  215. pSrvCall - the SrvCall instance
  216. pCallbackContext - the RDBSS context
  217. Return Value:
  218. STATUS_SUCCESS - the server call construction has been finalized.
  219. Other Status codes correspond to error situations.
  220. Notes:
  221. --*/
  222. {
  223. NTSTATUS Status = STATUS_SUCCESS;
  224. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  225. PSMBCE_TRANSPORT PreferredTransport = NULL;
  226. BOOLEAN fNewServerEntry = FALSE;
  227. SMBCEDB_SERVER_TYPE ServerType = SMBCEDB_FILE_SERVER;
  228. UNICODE_STRING TransportName;
  229. // RxProfile(SmbCe,SmbCeOpenServer);
  230. ASSERT(pSrvCall->Context == NULL);
  231. TransportName = pCallbackContext->SrvCalldownStructure->RxContext->Create.TransportName;
  232. if (TransportName.Length > 0) {
  233. if ((PreferredTransport=SmbCeFindTransport(&TransportName)) == NULL) {
  234. ASSERT(pCallbackContext->RecommunicateContext == NULL);
  235. Status = STATUS_NETWORK_UNREACHABLE;
  236. goto FINALLY;
  237. }
  238. }
  239. SmbCeAcquireResource();
  240. Status = SmbCeFindOrConstructServerEntry(
  241. pSrvCall->pSrvCallName,
  242. ServerType,
  243. &pServerEntry,
  244. &fNewServerEntry);
  245. SmbCeReleaseResource();
  246. pCallbackContext->RecommunicateContext = pServerEntry;
  247. if (Status == STATUS_SUCCESS) {
  248. ASSERT(pServerEntry != NULL);
  249. InterlockedExchangePointer(
  250. &pServerEntry->pRdbssSrvCall,
  251. pSrvCall);
  252. Status = SmbCeUpdateSrvCall(pServerEntry);
  253. if (Status == STATUS_SUCCESS) {
  254. if (PreferredTransport != NULL) {
  255. // Transfer the ownership of the preferred transport to the
  256. // server entry.
  257. pServerEntry->PreferredTransport = PreferredTransport;
  258. PreferredTransport = NULL;
  259. } else {
  260. pServerEntry->PreferredTransport = NULL;
  261. }
  262. if (fNewServerEntry) {
  263. pServerEntry->Header.State = SMBCEDB_INVALID;
  264. pServerEntry->Server.Dialect = LANMAN21_DIALECT;
  265. pServerEntry->Server.MaximumBufferSize = 0xffff;
  266. }
  267. if (!fDeferNetworkInitialization) {
  268. Status = SmbCeInitializeServerTransport(
  269. pServerEntry,
  270. SmbCeCompleteSrvCallConstruction,
  271. pCallbackContext);
  272. }
  273. }
  274. }
  275. FINALLY:
  276. if (Status != STATUS_PENDING) {
  277. pCallbackContext->Status = Status;
  278. SmbCeCompleteSrvCallConstruction(pCallbackContext);
  279. }
  280. if (PreferredTransport != NULL) {
  281. SmbCeDereferenceTransport(PreferredTransport);
  282. }
  283. return STATUS_PENDING;
  284. }
  285. NTSTATUS
  286. SmbCeUpdateSrvCall(
  287. PSMBCEDB_SERVER_ENTRY pServerEntry)
  288. /*++
  289. Routine Description:
  290. This routine initializes the wrapper data structure corresponding to a
  291. given server entry.
  292. Arguments:
  293. pServerEntry - the server entry
  294. Return Value:
  295. STATUS_SUCCESS if successful
  296. --*/
  297. {
  298. NTSTATUS Status = STATUS_SUCCESS;
  299. PMRX_SRV_CALL pSrvCall = pServerEntry->pRdbssSrvCall;
  300. PAGED_CODE();
  301. if (pSrvCall != NULL) {
  302. // Copy the domain name into the server entry
  303. Status = RxSetSrvCallDomainName(
  304. pSrvCall,
  305. &pServerEntry->DomainName);
  306. // Initialize the SrvCall flags based upon the capabilities of the remote
  307. // server. The only flag that the SMB mini redirector updates is the
  308. // SRVCALL_FLAG_DFS_AWARE
  309. if (pServerEntry->Server.Capabilities & CAP_DFS) {
  310. SetFlag(
  311. pSrvCall->Flags,
  312. SRVCALL_FLAG_DFS_AWARE_SERVER);
  313. }
  314. }
  315. return Status;
  316. }
  317. VOID
  318. SmbCeCompleteServerEntryInitialization(
  319. PSMBCEDB_SERVER_ENTRY pServerEntry,
  320. NTSTATUS Status)
  321. /*++
  322. Routine Description:
  323. This routine is invoked in the context of a worker thread to finalize the
  324. construction of a server entry
  325. Arguments:
  326. pServerEntry - the server entry to be finalized
  327. ServerState - the final state of the server
  328. --*/
  329. {
  330. NTSTATUS ServerStatus;
  331. SMBCEDB_OBJECT_STATE PreviousState;
  332. SMBCEDB_REQUESTS ReconnectRequests;
  333. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  334. KIRQL SavedIrql;
  335. RxDbgTrace( 0, Dbg, ("Server Entry Finalization\n"));
  336. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  337. InitializeListHead(&ReconnectRequests.ListHead);
  338. // Acquire the SMBCE resource
  339. SmbCeAcquireResource();
  340. SmbCeAcquireSpinLock();
  341. // The server status could have changed because of the transport disconnects
  342. // from the time the admin exchange was completed to the time the server
  343. // entry initialization complete routine is called. Update the state
  344. // accordingly.
  345. PreviousState = pServerEntry->Header.State;
  346. if (PreviousState == SMBCEDB_CONSTRUCTION_IN_PROGRESS) {
  347. pServerEntry->ServerStatus = Status;
  348. if (Status == STATUS_SUCCESS) {
  349. pServerEntry->Header.State = SMBCEDB_ACTIVE;
  350. } else {
  351. pServerEntry->Header.State = SMBCEDB_INVALID;
  352. }
  353. }
  354. ServerStatus = pServerEntry->ServerStatus;
  355. pServerEntry->NegotiateInProgress = FALSE;
  356. // Weed out all the reconnect requests so that they can be resumed
  357. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  358. while (pRequestEntry != NULL) {
  359. if (pRequestEntry->GenericRequest.Type == RECONNECT_REQUEST) {
  360. PSMBCEDB_REQUEST_ENTRY pTempRequestEntry;
  361. pTempRequestEntry = pRequestEntry;
  362. pRequestEntry = SmbCeGetNextRequestEntry(
  363. &pServerEntry->OutstandingRequests,
  364. pRequestEntry);
  365. SmbCeRemoveRequestEntryLite(
  366. &pServerEntry->OutstandingRequests,
  367. pTempRequestEntry);
  368. SmbCeAddRequestEntryLite(
  369. &ReconnectRequests,
  370. pTempRequestEntry);
  371. } else {
  372. pRequestEntry = SmbCeGetNextRequestEntry(
  373. &pServerEntry->OutstandingRequests,
  374. pRequestEntry);
  375. }
  376. }
  377. pServerEntry->Server.NumberOfVNetRootContextsForScavenging = 0;
  378. SmbCeReleaseSpinLock();
  379. if ((Status == STATUS_SUCCESS) &&
  380. (ServerStatus == STATUS_SUCCESS) &&
  381. (PreviousState == SMBCEDB_CONSTRUCTION_IN_PROGRESS)) {
  382. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  383. SESSION_TYPE SessionType;
  384. InterlockedIncrement(&pServerEntry->Server.Version);
  385. pServerEntry->Server.NumberOfSrvOpens = 0;
  386. ASSERT(pServerEntry->pMidAtlas == NULL);
  387. // Initialize the MID Atlas
  388. pServerEntry->pMidAtlas = FsRtlCreateMidAtlas(
  389. pServerEntry->Server.MaximumRequests,
  390. pServerEntry->Server.MaximumRequests);
  391. if (pServerEntry->pMidAtlas == NULL) {
  392. pServerEntry->ServerStatus = STATUS_INSUFFICIENT_RESOURCES;
  393. }
  394. // The sessions that have been created but whose initialization has been
  395. // deferred will have the session types set incorrectly. This is because
  396. // there is no previous knowledge of the session type required for deferred
  397. // servers.
  398. SessionType = LANMAN_SESSION;
  399. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  400. while (pSessionEntry != NULL) {
  401. pSessionEntry->Session.Type = SessionType;
  402. pSessionEntry = SmbCeGetNextSessionEntry(
  403. pServerEntry,
  404. pSessionEntry);
  405. }
  406. }
  407. // Release the resource for the server entry
  408. SmbCeReleaseResource();
  409. // Resume all the outstanding reconnect requests that were held up because an earlier
  410. // reconnect request was under way.
  411. // Iterate over the list of pending requests and resume all of them
  412. SmbCeResumeOutstandingRequests(&ReconnectRequests,ServerStatus);
  413. }
  414. VOID
  415. SmbCepDereferenceServerEntry(
  416. PSMBCEDB_SERVER_ENTRY pServerEntry)
  417. /*++
  418. Routine Description:
  419. This routine dereferences a server entry instance
  420. Arguments:
  421. pServerEntry - the server entry to be dereferenced
  422. --*/
  423. {
  424. if (pServerEntry != NULL) {
  425. BOOLEAN fTearDownEntry = FALSE;
  426. LONG FinalRefCount;
  427. ASSERT((pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER) &&
  428. (pServerEntry->Header.SwizzleCount > 0));
  429. MRXSMB_PRINT_REF_COUNT(SERVER_ENTRY,pServerEntry->Header.SwizzleCount);
  430. SmbCeAcquireResource();
  431. SmbCeAcquireSpinLock();
  432. FinalRefCount = InterlockedDecrement(&pServerEntry->Header.SwizzleCount);
  433. fTearDownEntry = (FinalRefCount == 0);
  434. if (fTearDownEntry) {
  435. // This is to ensure that the routines for traversing the server
  436. // entry list, i.e., probing servers do not colide with the teardown.
  437. if (pServerEntry->Header.SwizzleCount == 0) {
  438. pServerEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION;
  439. SmbCeRemoveServerEntryLite(pServerEntry);
  440. if (SmbCeGetFirstServerEntry() == NULL &&
  441. SmbCeStartStopContext.pServerEntryTearDownEvent != NULL) {
  442. KeSetEvent(SmbCeStartStopContext.pServerEntryTearDownEvent,0,FALSE);
  443. }
  444. } else {
  445. fTearDownEntry = FALSE;
  446. }
  447. }
  448. SmbCeReleaseSpinLock();
  449. SmbCeReleaseResource();
  450. if (fTearDownEntry) {
  451. SmbCeTearDownServerEntry(pServerEntry);
  452. }
  453. }
  454. }
  455. VOID
  456. SmbCeTearDownServerEntry(
  457. PSMBCEDB_SERVER_ENTRY pServerEntry)
  458. /*++
  459. Routine Description:
  460. This routine tears down a server entry instance
  461. Arguments:
  462. pServerEntry - the server entry to be dereferenced
  463. --*/
  464. {
  465. NTSTATUS Status = STATUS_SUCCESS;
  466. PAGED_CODE();
  467. ASSERT(pServerEntry->Header.State == SMBCEDB_MARKED_FOR_DELETION);
  468. SmbCeLog(("TearSrvEntry %lx %wZ\n",pServerEntry,&pServerEntry->Name));
  469. if (pServerEntry->pMidAtlas != NULL) {
  470. FsRtlDestroyMidAtlas(pServerEntry->pMidAtlas,NULL);
  471. pServerEntry->pMidAtlas = NULL;
  472. }
  473. if (pServerEntry->pTransport != NULL) {
  474. Status = SmbCeUninitializeServerTransport(pServerEntry,NULL,NULL);
  475. }
  476. if (pServerEntry->Name.Buffer != NULL) {
  477. RxFreePool(pServerEntry->Name.Buffer);
  478. }
  479. if (pServerEntry->DomainName.Buffer != NULL) {
  480. RxFreePool(pServerEntry->DomainName.Buffer);
  481. }
  482. if (pServerEntry->DfsRootName.Buffer != NULL) {
  483. RxFreePool(pServerEntry->DfsRootName.Buffer);
  484. }
  485. if (pServerEntry->PreferredTransport != NULL) {
  486. SmbCeDereferenceTransport(pServerEntry->PreferredTransport);
  487. }
  488. if (Status == STATUS_SUCCESS) {
  489. SmbMmFreeObject(pServerEntry);
  490. } else {
  491. ASSERT(FALSE);
  492. }
  493. }
  494. NTSTATUS
  495. SmbCeFindOrConstructSessionEntry(
  496. PMRX_V_NET_ROOT pVNetRoot,
  497. PSMBCEDB_SESSION_ENTRY *pSessionEntryPtr)
  498. /*++
  499. Routine Description:
  500. This routine opens/creates a session for a given user in the connection engine database
  501. Arguments:
  502. pVNetRoot - the RDBSS Virtual net root instance
  503. Return Value:
  504. STATUS_SUCCESS - if successful
  505. Other Status codes correspond to error situations.
  506. Notes:
  507. This routine assumes that the necesary concurreny control mechanism has already
  508. been taken.
  509. On Entry the connection engine resource must have been acquired exclusive and
  510. ownership remains invariant on exit.
  511. In case of UPN, we should pass a NULL string instead of NULL as domain name.
  512. --*/
  513. {
  514. NTSTATUS Status = STATUS_SUCCESS;
  515. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  516. PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL;
  517. BOOLEAN fSessionEntryFound = FALSE;
  518. PUNICODE_STRING UserName;
  519. PUNICODE_STRING Password;
  520. PUNICODE_STRING UserDomainName;
  521. DWORD SessionType;
  522. LUID AnonymousLogonID = ANONYMOUS_LOGON_LUID;
  523. #define SessionTypeDefault 1
  524. #define SessionTypeUser 2
  525. #define SessionTypeNull 3
  526. ASSERT(SmbCeIsResourceOwned());
  527. UserName = pVNetRoot->pUserName;
  528. Password = pVNetRoot->pPassword;
  529. UserDomainName = pVNetRoot->pUserDomainName;
  530. SessionType = SessionTypeDefault;
  531. if ((UserName != NULL) &&
  532. (UserName->Length == 0) &&
  533. (Password != NULL) &&
  534. (Password->Length == 0) &&
  535. (UserDomainName != NULL) &&
  536. (UserDomainName->Length == 0)) {
  537. SessionType = SessionTypeNull;
  538. } else if ((UserName != NULL) ||
  539. ((Password != NULL) &&
  540. (Password->Length > 0))) {
  541. SessionType = SessionTypeUser;
  542. }
  543. *pSessionEntryPtr = NULL;
  544. // Reference the server handle
  545. pServerEntry = SmbCeReferenceAssociatedServerEntry(pVNetRoot->pNetRoot->pSrvCall);
  546. if (pServerEntry != NULL) {
  547. if (SessionType != SessionTypeUser) {
  548. SmbCeAcquireSpinLock();
  549. // Rule No. 1
  550. // 1) The first session with explicitly specified credentials will be treated as the
  551. // default session for all subsequent requests to any given server.
  552. if (SessionType == SessionTypeDefault) {
  553. pSessionEntry = SmbCeGetDefaultSessionEntry(
  554. pServerEntry,
  555. pVNetRoot->SessionId,
  556. &pVNetRoot->LogonId);
  557. while (pSessionEntry != NULL &&
  558. FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION)) {
  559. SmbCeRemoveDefaultSessionEntry(pSessionEntry);
  560. pSessionEntry = SmbCeGetDefaultSessionEntry(
  561. pServerEntry,
  562. pVNetRoot->SessionId,
  563. &pVNetRoot->LogonId);
  564. }
  565. }
  566. if (pSessionEntry == NULL) {
  567. // Enumerate the sessions to detect if a session satisfying rule 2 exists
  568. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  569. while (pSessionEntry != NULL) {
  570. if (!FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION)) {
  571. if (SessionType == SessionTypeDefault) {
  572. //
  573. // Rule No. 2
  574. // 2) If no session with explicitly specified credentials exist then a
  575. // session with the same logon id. is choosen.
  576. //
  577. if (RtlEqualLuid(
  578. &pSessionEntry->Session.LogonId,
  579. &pVNetRoot->LogonId)) {
  580. break;
  581. }
  582. } else if (SessionType == SessionTypeNull) {
  583. if (FlagOn(
  584. pSessionEntry->Session.Flags,
  585. SMBCE_SESSION_FLAGS_NULL_CREDENTIALS)) {
  586. break;
  587. }
  588. }
  589. }
  590. pSessionEntry = SmbCeGetNextSessionEntry(pServerEntry,pSessionEntry);
  591. }
  592. }
  593. if (pSessionEntry != NULL) {
  594. SmbCeReferenceSessionEntry(pSessionEntry);
  595. }
  596. SmbCeReleaseSpinLock();
  597. } else {
  598. BOOLEAN SessionEntryFound = FALSE;
  599. SmbCeAcquireSpinLock();
  600. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  601. if (pSessionEntry != NULL) {
  602. SmbCeReferenceSessionEntry(pSessionEntry);
  603. }
  604. SmbCeReleaseSpinLock();
  605. while ((pSessionEntry != NULL) && !SessionEntryFound) {
  606. if (!FlagOn(pSessionEntry->Session.Flags,
  607. SMBCE_SESSION_FLAGS_NULL_CREDENTIALS |
  608. SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION)) {
  609. PSecurityUserData pSecurityData = NULL;
  610. for (;;) {
  611. PSMBCE_SESSION pSession = &pSessionEntry->Session;
  612. PUNICODE_STRING TempUserName,TempUserDomainName;
  613. // For each existing session check to determine if the credentials
  614. // supplied match the credentials used to construct the session.
  615. if( pSession->SessionId != pVNetRoot->SessionId ) {
  616. break;
  617. }
  618. if (!RtlEqualLuid(
  619. &pSessionEntry->Session.LogonId,
  620. &pVNetRoot->LogonId)) {
  621. break;
  622. }
  623. TempUserName = pSession->pUserName;
  624. TempUserDomainName = pSession->pUserDomainName;
  625. if (TempUserName == NULL ||
  626. TempUserDomainName == NULL) {
  627. Status = GetSecurityUserInfo(
  628. &pVNetRoot->LogonId,
  629. UNDERSTANDS_LONG_NAMES,
  630. &pSecurityData);
  631. if (NT_SUCCESS(Status)) {
  632. if (TempUserName == NULL) {
  633. TempUserName = &(pSecurityData->UserName);
  634. }
  635. if (TempUserDomainName == NULL) {
  636. TempUserDomainName = &(pSecurityData->LogonDomainName);
  637. }
  638. } else {
  639. break;
  640. }
  641. }
  642. if (UserName != NULL &&
  643. !RtlEqualUnicodeString(UserName,TempUserName,TRUE)) {
  644. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  645. break;
  646. }
  647. if (UserDomainName != NULL &&
  648. !RtlEqualUnicodeString(UserDomainName,TempUserDomainName,TRUE)) {
  649. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  650. break;
  651. }
  652. if ((Password != NULL) &&
  653. (pSession->pPassword != NULL)) {
  654. if (!RtlEqualUnicodeString(
  655. Password,
  656. pSession->pPassword,
  657. FALSE)) {
  658. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  659. break;
  660. }
  661. }
  662. // We use existing session if either the stored or new password is NULL.
  663. // Later, a new security API will be created for verify the password
  664. // based on the logon ID.
  665. // An entry that matches the credentials supplied has been found. use it.
  666. SessionEntryFound = TRUE;
  667. break;
  668. }
  669. //ASSERT(Status != STATUS_NETWORK_CREDENTIAL_CONFLICT);
  670. if (pSecurityData != NULL) {
  671. LsaFreeReturnBuffer(pSecurityData);
  672. }
  673. }
  674. if (pServerEntry->Server.SecurityMode == SECURITY_MODE_SHARE_LEVEL &&
  675. (Status == STATUS_NETWORK_CREDENTIAL_CONFLICT ||
  676. Status == STATUS_LOGON_FAILURE)) {
  677. Status = STATUS_SUCCESS;
  678. }
  679. if (!SessionEntryFound) {
  680. if (Status == STATUS_SUCCESS) {
  681. PSMBCEDB_SESSION_ENTRY pNextSessionEntry;
  682. SmbCeAcquireSpinLock();
  683. pNextSessionEntry = SmbCeGetNextSessionEntry(
  684. pServerEntry,
  685. pSessionEntry);
  686. if (pNextSessionEntry != NULL) {
  687. SmbCeReferenceSessionEntry(pNextSessionEntry);
  688. }
  689. SmbCeReleaseSpinLock();
  690. SmbCeDereferenceSessionEntry(pSessionEntry);
  691. pSessionEntry = pNextSessionEntry;
  692. } else {
  693. // An error situation was encountered. Terminate the iteration.
  694. // Typically a set of conflicting credentials have been presented
  695. SmbCeDereferenceSessionEntry(pSessionEntry);
  696. pSessionEntry = NULL;
  697. }
  698. } else {
  699. if (RtlEqualLuid(&pSessionEntry->Session.LogonId,&AnonymousLogonID) &&
  700. (Password != NULL || UserName != NULL || UserDomainName != NULL)) {
  701. Status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  702. }
  703. }
  704. }
  705. }
  706. if ((pSessionEntry == NULL) && (Status == STATUS_SUCCESS)) {
  707. // Rule No. 3
  708. // 3) If no session with the same logon id. exists a new session is created.
  709. //
  710. // Allocate a new session entry
  711. // This is the point at which a many to mapping between session entries and
  712. // V_NET_ROOT's in the RDBSS is being established. From this point it is
  713. // true that the session entry can outlive the associated V_NET_ROOT entry.
  714. // Therefore copies of the parameters used in the session setup need be made.
  715. PSMBCE_SESSION pSession = &pSessionEntry->Session;
  716. PUNICODE_STRING pPassword,pUserName,pUserDomainName;
  717. if (Password != NULL) {
  718. pPassword = (PUNICODE_STRING)
  719. RxAllocatePoolWithTag(
  720. NonPagedPool,
  721. sizeof(UNICODE_STRING) + Password->Length,
  722. MRXSMB_SESSION_POOLTAG);
  723. if (pPassword != NULL) {
  724. pPassword->Buffer = (PWCHAR)((PCHAR)pPassword + sizeof(UNICODE_STRING));
  725. pPassword->Length = Password->Length;
  726. pPassword->MaximumLength = pPassword->Length;
  727. RtlCopyMemory(
  728. pPassword->Buffer,
  729. Password->Buffer,
  730. pPassword->Length);
  731. } else {
  732. Status = STATUS_INSUFFICIENT_RESOURCES;
  733. }
  734. } else {
  735. pPassword = NULL;
  736. }
  737. if ((UserName != NULL) &&
  738. (Status == STATUS_SUCCESS)) {
  739. pUserName = (PUNICODE_STRING)
  740. RxAllocatePoolWithTag(
  741. NonPagedPool,
  742. sizeof(UNICODE_STRING) + UserName->Length,
  743. MRXSMB_SESSION_POOLTAG);
  744. if (pUserName != NULL) {
  745. pUserName->Buffer = (PWCHAR)((PCHAR)pUserName + sizeof(UNICODE_STRING));
  746. pUserName->Length = UserName->Length;
  747. pUserName->MaximumLength = pUserName->Length;
  748. RtlCopyMemory(
  749. pUserName->Buffer,
  750. UserName->Buffer,
  751. pUserName->Length);
  752. } else {
  753. Status = STATUS_INSUFFICIENT_RESOURCES;
  754. }
  755. } else {
  756. pUserName = NULL;
  757. }
  758. if ((UserDomainName != NULL) &&
  759. (Status == STATUS_SUCCESS)) {
  760. pUserDomainName = (PUNICODE_STRING)
  761. RxAllocatePoolWithTag(
  762. NonPagedPool,
  763. sizeof(UNICODE_STRING) + UserDomainName->Length + sizeof(WCHAR),
  764. MRXSMB_SESSION_POOLTAG);
  765. if (pUserDomainName != NULL) {
  766. pUserDomainName->Buffer = (PWCHAR)((PCHAR)pUserDomainName + sizeof(UNICODE_STRING));
  767. pUserDomainName->Length = UserDomainName->Length;
  768. pUserDomainName->MaximumLength = pUserDomainName->Length;
  769. // in case of UPN name, domain name will be a NULL string
  770. *pUserDomainName->Buffer = 0;
  771. if (UserDomainName->Length > 0) {
  772. RtlCopyMemory(
  773. pUserDomainName->Buffer,
  774. UserDomainName->Buffer,
  775. pUserDomainName->Length);
  776. }
  777. } else {
  778. Status = STATUS_INSUFFICIENT_RESOURCES;
  779. }
  780. } else {
  781. pUserDomainName = NULL;
  782. }
  783. if (Status == STATUS_SUCCESS) {
  784. pSessionEntry = SmbMmAllocateSessionEntry(pServerEntry);
  785. if (pSessionEntry != NULL) {
  786. SmbCeLog(("NewSessEntry %lx\n",pSessionEntry));
  787. pSession = & pSessionEntry->Session;
  788. pSessionEntry->Header.State = SMBCEDB_INVALID;
  789. pSessionEntry->pServerEntry = pServerEntry;
  790. if (pServerEntry->Server.SecurityMode == SECURITY_MODE_SHARE_LEVEL) {
  791. pSessionEntry->Session.UserId = (SMB_USER_ID)SMBCE_SHARE_LEVEL_SERVER_USERID;
  792. }
  793. pSession->Flags = 0;
  794. if ( SessionType == SessionTypeNull ) {
  795. pSession->Flags |= SMBCE_SESSION_FLAGS_NULL_CREDENTIALS;
  796. }
  797. pSession->LogonId = pVNetRoot->LogonId;
  798. pSession->pUserName = pUserName;
  799. pSession->pPassword = pPassword;
  800. pSession->pUserDomainName = pUserDomainName;
  801. pSession->SessionId = pVNetRoot->SessionId;
  802. SmbCeReferenceSessionEntry(pSessionEntry);
  803. SmbCeAddSessionEntry(pServerEntry,pSessionEntry);
  804. } else {
  805. Status = STATUS_INSUFFICIENT_RESOURCES;
  806. }
  807. }
  808. if (Status != STATUS_SUCCESS) {
  809. if (pUserName != NULL) {
  810. RxFreePool(pUserName);
  811. }
  812. if (pPassword != NULL) {
  813. RxFreePool(pPassword);
  814. }
  815. if (pUserDomainName != NULL) {
  816. RxFreePool(pUserDomainName);
  817. }
  818. }
  819. } else {
  820. if (Status == STATUS_SUCCESS) {
  821. SmbCeLog(("CachedSessEntry %lx\n",pSessionEntry));
  822. }
  823. }
  824. if (Status == STATUS_SUCCESS) {
  825. *pSessionEntryPtr = pSessionEntry;
  826. }
  827. SmbCeDereferenceServerEntry(pServerEntry);
  828. } else {
  829. Status = STATUS_INVALID_PARAMETER;
  830. }
  831. return Status;
  832. }
  833. VOID
  834. SmbCeCompleteSessionEntryInitialization(
  835. PVOID pContext,
  836. NTSTATUS Status)
  837. /*++
  838. Routine Description:
  839. This routine is invoked in the context of a worker thread to finalize the
  840. construction of a session entry
  841. Arguments:
  842. pContext - the session entry to be activated
  843. Notes:
  844. PRE_CONDITION: The session entry must have been referenced to ensure that
  845. even it has been finalized it will not be deleted.
  846. --*/
  847. {
  848. PSMBCEDB_SESSION_ENTRY pSessionEntry = (PSMBCEDB_SESSION_ENTRY)pContext;
  849. PSMBCE_SESSION pSession = &pSessionEntry->Session;
  850. PSMBCEDB_SERVER_ENTRY pServerEntry = pSessionEntry->pServerEntry;
  851. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  852. SMBCEDB_REQUESTS Requests;
  853. PAGED_CODE();
  854. RxDbgTrace( 0, Dbg, ("Session Entry Finalization\n"));
  855. ASSERT(pSessionEntry->Header.ObjectType == SMBCEDB_OT_SESSION);
  856. // Acquire the SMBCE resource
  857. SmbCeAcquireResource();
  858. // reset the constructor exchange field since the construction is complete
  859. pSessionEntry->pExchange = NULL;
  860. // Create a temporary copy of the list that can be traversed after releasing the
  861. // resource.
  862. SmbCeTransferRequests(&Requests,&pSessionEntry->Requests);
  863. if (Status == STATUS_SUCCESS) {
  864. SmbCeUpdateSessionEntryState(
  865. pSessionEntry,
  866. SMBCEDB_ACTIVE);
  867. if ((pSession->pPassword != NULL || pSession->pUserName != NULL) &&
  868. !BooleanFlagOn(pSession->Flags,SMBCE_SESSION_FLAGS_NULL_CREDENTIALS)) {
  869. if (pSessionEntry->DefaultSessionLink.Flink == NULL ) {
  870. ASSERT( pSessionEntry->DefaultSessionLink.Blink == NULL );
  871. InsertHeadList(&pServerEntry->Sessions.DefaultSessionList,
  872. &pSessionEntry->DefaultSessionLink );
  873. }
  874. }
  875. } else {
  876. Status = STATUS_BAD_LOGON_SESSION_STATE;
  877. SmbCeUpdateSessionEntryState(
  878. pSessionEntry,
  879. SMBCEDB_INVALID);
  880. }
  881. // Release the resource for the session entry
  882. SmbCeReleaseResource();
  883. if (!IsListEmpty(&Requests.ListHead)) {
  884. // Iterate over the list of pending requests and resume all of them
  885. SmbCeResumeOutstandingRequests(&Requests,Status);
  886. }
  887. SmbCeDereferenceSessionEntry(pSessionEntry);
  888. }
  889. NTSTATUS
  890. SmbCeGetUserNameAndDomainName(
  891. PSMBCEDB_SESSION_ENTRY pSessionEntry,
  892. PUNICODE_STRING pUserName,
  893. PUNICODE_STRING pUserDomainName)
  894. /*++
  895. Routine Description:
  896. This routine returns the user name and domain name associated with a session
  897. in a caller allocated buffer.
  898. Arguments:
  899. pSessionEntry - the session entry to be dereferenced
  900. pUserName - the User name
  901. pUserDomainName - the user domain name
  902. Return Value:
  903. STATUS_SUCCESS if successful
  904. --*/
  905. {
  906. NTSTATUS Status;
  907. PSMBCE_SESSION pSession;
  908. PUNICODE_STRING pSessionUserName,pSessionDomainName;
  909. PSecurityUserData pSecurityData;
  910. PAGED_CODE();
  911. ASSERT(pSessionEntry != NULL);
  912. pSession = &pSessionEntry->Session;
  913. if ((pUserName == NULL) ||
  914. (pUserDomainName == NULL) ||
  915. (pUserName->MaximumLength < (UNLEN * sizeof(WCHAR))) ||
  916. (pUserDomainName->MaximumLength < (DNLEN * sizeof(WCHAR)))) {
  917. return STATUS_INVALID_PARAMETER;
  918. }
  919. Status = STATUS_SUCCESS;
  920. pSecurityData = NULL;
  921. pSessionUserName = pSession->pUserName;
  922. pSessionDomainName = pSession->pUserDomainName;
  923. try {
  924. if (pSessionUserName == NULL ||
  925. pSessionDomainName == NULL) {
  926. Status = GetSecurityUserInfo(
  927. &pSession->LogonId,
  928. UNDERSTANDS_LONG_NAMES,
  929. &pSecurityData);
  930. if (NT_SUCCESS(Status)) {
  931. if (pSessionUserName == NULL) {
  932. pSessionUserName = &(pSecurityData->UserName);
  933. }
  934. if (pSessionDomainName == NULL) {
  935. pSessionDomainName = &(pSecurityData->LogonDomainName);
  936. }
  937. }
  938. }
  939. if (NT_SUCCESS(Status)) {
  940. ASSERT(pSessionUserName->Length <= pUserName->MaximumLength);
  941. ASSERT(pSessionDomainName->Length <= pUserDomainName->MaximumLength);
  942. pUserName->Length = pSessionUserName->Length;
  943. RtlCopyMemory(
  944. pUserName->Buffer,
  945. pSessionUserName->Buffer,
  946. pUserName->Length);
  947. pUserDomainName->Length = pSessionDomainName->Length;
  948. if (pUserDomainName->Length > 0) {
  949. RtlCopyMemory(
  950. pUserDomainName->Buffer,
  951. pSessionDomainName->Buffer,
  952. pUserDomainName->Length);
  953. }
  954. }
  955. } finally {
  956. if (pSecurityData != NULL) {
  957. LsaFreeReturnBuffer(pSecurityData);
  958. }
  959. }
  960. return Status;
  961. }
  962. VOID
  963. SmbCepDereferenceSessionEntry(
  964. PSMBCEDB_SESSION_ENTRY pSessionEntry)
  965. /*++
  966. Routine Description:
  967. This routine dereferences a session entry instance
  968. Arguments:
  969. pSessionEntry - the session entry to be dereferenced
  970. --*/
  971. {
  972. if (pSessionEntry != NULL) {
  973. BOOLEAN fTearDownEntry;
  974. BOOLEAN fLogOffRequired;
  975. LONG FinalRefCount;
  976. PSMBCEDB_SERVER_ENTRY pServerEntry;
  977. ASSERT((pSessionEntry->Header.ObjectType == SMBCEDB_OT_SESSION) &&
  978. (pSessionEntry->Header.SwizzleCount > 0));
  979. MRXSMB_PRINT_REF_COUNT(SESSION_ENTRY,pSessionEntry->Header.SwizzleCount);
  980. pServerEntry = pSessionEntry->pServerEntry;
  981. SmbCeAcquireResource();
  982. FinalRefCount = InterlockedDecrement(&pSessionEntry->Header.SwizzleCount);
  983. fTearDownEntry = (FinalRefCount == 0);
  984. if (fTearDownEntry) {
  985. // A logoff smb needs to be sent if the user id associated with
  986. // the session is not zero. Note that we cannot rely on the state
  987. // of the session to indicate this.
  988. SmbCeReferenceServerEntry(pServerEntry);
  989. if (pSessionEntry->Header.SwizzleCount == 0) {
  990. if (!FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) {
  991. SmbCeRemoveSessionEntry(pServerEntry,pSessionEntry);
  992. InterlockedDecrement(
  993. &pServerEntry->Server.NumberOfActiveSessions);
  994. }
  995. SmbCeRemoveDefaultSessionEntry(pSessionEntry);
  996. if ((pSessionEntry->Session.UserId != (SMB_USER_ID)(SMBCE_SHARE_LEVEL_SERVER_USERID)) &&
  997. (pSessionEntry->Session.UserId != 0) &&
  998. !FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) {
  999. SmbCeReferenceServerEntry(pServerEntry);
  1000. SmbCeReferenceSessionEntry(pSessionEntry);
  1001. fLogOffRequired = TRUE;
  1002. } else {
  1003. fLogOffRequired = FALSE;
  1004. pSessionEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION;
  1005. }
  1006. pSessionEntry->Session.Flags |= SMBCE_SESSION_FLAGS_LOGGED_OFF;
  1007. fTearDownEntry = TRUE;
  1008. } else {
  1009. fTearDownEntry = FALSE;
  1010. }
  1011. SmbCeDereferenceServerEntry(pServerEntry);
  1012. }
  1013. SmbCeReleaseResource();
  1014. if (fTearDownEntry) {
  1015. if (fLogOffRequired) {
  1016. SmbCeLogOff(pServerEntry,pSessionEntry);
  1017. SmbCeDereferenceServerEntry(pServerEntry);
  1018. } else {
  1019. SmbCeTearDownSessionEntry(pSessionEntry);
  1020. }
  1021. }
  1022. }
  1023. }
  1024. VOID
  1025. SmbCeTearDownSessionEntry(
  1026. PSMBCEDB_SESSION_ENTRY pSessionEntry)
  1027. /*++
  1028. Routine Description:
  1029. This routine tears down a session entry instance
  1030. Arguments:
  1031. pSessionEntry - the session entry to be dereferenced
  1032. --*/
  1033. {
  1034. PAGED_CODE();
  1035. ASSERT((pSessionEntry->Header.SwizzleCount == 0) &&
  1036. (pSessionEntry->Header.State == SMBCEDB_MARKED_FOR_DELETION));
  1037. ASSERT(IsListEmpty(&pSessionEntry->SerializationList));
  1038. SmbCeLog(("TearSessEntry %lx\n",pSessionEntry));
  1039. if (pSessionEntry->Session.pUserName != NULL) {
  1040. RxFreePool(pSessionEntry->Session.pUserName);
  1041. }
  1042. if (pSessionEntry->Session.pPassword != NULL) {
  1043. RxFreePool(pSessionEntry->Session.pPassword);
  1044. }
  1045. if (pSessionEntry->Session.pUserDomainName != NULL) {
  1046. RxFreePool(pSessionEntry->Session.pUserDomainName);
  1047. }
  1048. UninitializeSecurityContextsForSession(&pSessionEntry->Session);
  1049. SmbMmFreeSessionEntry(pSessionEntry);
  1050. }
  1051. PSMBCEDB_NET_ROOT_ENTRY
  1052. SmbCeFindNetRootEntry(
  1053. PSMBCEDB_SERVER_ENTRY pServerEntry,
  1054. PUNICODE_STRING pServerShare
  1055. )
  1056. {
  1057. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
  1058. ASSERT(SmbCeIsResourceOwned());
  1059. pNetRootEntry = SmbCeGetFirstNetRootEntry(pServerEntry);
  1060. while (pNetRootEntry != NULL) {
  1061. if (RtlCompareUnicodeString(
  1062. pServerShare,
  1063. &pNetRootEntry->Name,
  1064. TRUE) == 0) {
  1065. break;
  1066. }
  1067. pNetRootEntry = SmbCeGetNextNetRootEntry(pServerEntry,pNetRootEntry);
  1068. }
  1069. return pNetRootEntry;
  1070. }
  1071. NTSTATUS
  1072. SmbCeFindOrConstructNetRootEntry(
  1073. IN PMRX_NET_ROOT pNetRoot,
  1074. OUT PSMBCEDB_NET_ROOT_ENTRY *pNetRootEntryPtr)
  1075. /*++
  1076. Routine Description:
  1077. This routine opens/creates a net root entry in the connection engine database
  1078. Arguments:
  1079. pNetRoot -- the RDBSS net root instance
  1080. pNetRootEntryPtr -- Initialized to the SMBCEDB_NET_ROOT_ENTRY instance if
  1081. successful
  1082. Return Value:
  1083. STATUS_SUCCESS - the construction of the net root instance has been finalized
  1084. Other Status codes correspond to error situations.
  1085. Notes:
  1086. This routine assumes that the necesary concurreny control mechanism has already
  1087. been taken.
  1088. On Entry the connection engine resource must have been acquired exclusive and
  1089. ownership remains invariant on exit.
  1090. --*/
  1091. {
  1092. NTSTATUS Status = STATUS_SUCCESS;
  1093. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  1094. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
  1095. PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL;
  1096. SMB_USER_ID UserId = 0;
  1097. ASSERT(SmbCeIsResourceOwned());
  1098. *pNetRootEntryPtr = NULL;
  1099. pServerEntry = SmbCeReferenceAssociatedServerEntry(pNetRoot->pSrvCall);
  1100. if (pServerEntry != NULL) {
  1101. // Check if any of the SMBCEDB_NET_ROOT_ENTRY associated with the server
  1102. // can be used. An existing entry is reusable if the names match
  1103. pNetRootEntry = SmbCeGetFirstNetRootEntry(pServerEntry);
  1104. while (pNetRootEntry != NULL) {
  1105. if (RtlCompareUnicodeString(
  1106. pNetRoot->pNetRootName,
  1107. &pNetRootEntry->Name,
  1108. TRUE) == 0) {
  1109. SmbCeLog(("CachedNREntry %lx\n",pNetRootEntry));
  1110. break;
  1111. }
  1112. pNetRootEntry = SmbCeGetNextNetRootEntry(pServerEntry,pNetRootEntry);
  1113. }
  1114. if (pNetRootEntry != NULL) {
  1115. SmbCeReferenceNetRootEntry(pNetRootEntry);
  1116. } else {
  1117. pNetRootEntry = (PSMBCEDB_NET_ROOT_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_NETROOT);
  1118. if (pNetRootEntry != NULL) {
  1119. pNetRootEntry->Name.Buffer = RxAllocatePoolWithTag(
  1120. PagedPool,
  1121. pNetRoot->pNetRootName->Length,
  1122. MRXSMB_NETROOT_POOLTAG);
  1123. if (pNetRootEntry->Name.Buffer != NULL) {
  1124. SmbCeLog(("NewNetREntry %lx\n",pNetRootEntry));
  1125. pNetRootEntry->Name.Length = pNetRoot->pNetRootName->Length;
  1126. pNetRootEntry->Name.MaximumLength = pNetRootEntry->Name.Length;
  1127. RtlCopyMemory(
  1128. pNetRootEntry->Name.Buffer,
  1129. pNetRoot->pNetRootName->Buffer,
  1130. pNetRootEntry->Name.Length);
  1131. pNetRootEntry->pServerEntry = pServerEntry;
  1132. pNetRootEntry->NetRoot.UserId = UserId;
  1133. pNetRootEntry->NetRoot.NetRootType = pNetRoot->Type;
  1134. InitializeListHead(&pNetRootEntry->NetRoot.ClusterSizeSerializationQueue);
  1135. pNetRootEntry->Header.State = SMBCEDB_ACTIVE;
  1136. SmbCeReferenceNetRootEntry(pNetRootEntry);
  1137. SmbCeAddNetRootEntry(pServerEntry,pNetRootEntry);
  1138. } else {
  1139. SmbMmFreeObject(pNetRootEntry);
  1140. Status = STATUS_INSUFFICIENT_RESOURCES;
  1141. }
  1142. } else {
  1143. Status = STATUS_INSUFFICIENT_RESOURCES;
  1144. }
  1145. }
  1146. if (Status == STATUS_SUCCESS) {
  1147. ASSERT(pNetRootEntry != NULL);
  1148. *pNetRootEntryPtr = pNetRootEntry;
  1149. }
  1150. SmbCeDereferenceServerEntry(pServerEntry);
  1151. } else {
  1152. Status = STATUS_INVALID_PARAMETER;
  1153. }
  1154. return Status;
  1155. }
  1156. VOID
  1157. SmbCepDereferenceNetRootEntry(
  1158. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry,
  1159. PVOID FileName,
  1160. ULONG FileLine)
  1161. /*++
  1162. Routine Description:
  1163. This routine dereferences a net root entry instance
  1164. Arguments:
  1165. pNetRootEntry - the NEt Root entry to be dereferenced
  1166. --*/
  1167. {
  1168. if (pNetRootEntry != NULL) {
  1169. LONG FinalRefCount;
  1170. BOOLEAN fTearDownEntry;
  1171. BOOLEAN fDisconnectRequired;
  1172. ASSERT((pNetRootEntry->Header.ObjectType == SMBCEDB_OT_NETROOT) &&
  1173. (pNetRootEntry->Header.SwizzleCount > 0));
  1174. MRXSMB_PRINT_REF_COUNT(NETROOT_ENTRY,pNetRootEntry->Header.SwizzleCount);
  1175. SmbCeAcquireResource();
  1176. FinalRefCount = InterlockedDecrement(&pNetRootEntry->Header.SwizzleCount);
  1177. fTearDownEntry = (FinalRefCount == 0);
  1178. if (fTearDownEntry) {
  1179. if (pNetRootEntry->Header.SwizzleCount == 0) {
  1180. PSMBCEDB_SERVER_ENTRY pServerEntry = pNetRootEntry->pServerEntry;
  1181. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
  1182. SmbCeRemoveNetRootEntryLite(pNetRootEntry->pServerEntry,pNetRootEntry);
  1183. pNetRootEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION;
  1184. fTearDownEntry = TRUE;
  1185. pVNetRootContext = SmbCeGetFirstVNetRootContext(&pServerEntry->VNetRootContexts);
  1186. while (pVNetRootContext != NULL) {
  1187. ASSERT(pVNetRootContext->pNetRootEntry != pNetRootEntry);
  1188. pVNetRootContext = SmbCeGetNextVNetRootContext(
  1189. &pServerEntry->VNetRootContexts,
  1190. pVNetRootContext);
  1191. }
  1192. } else {
  1193. fTearDownEntry = FALSE;
  1194. }
  1195. }
  1196. SmbReferenceRecord(&pNetRootEntry->ReferenceRecord[0],FileName,FileLine);
  1197. SmbCeReleaseResource();
  1198. if (fTearDownEntry) {
  1199. SmbCeTearDownNetRootEntry(pNetRootEntry);
  1200. }
  1201. }
  1202. }
  1203. VOID
  1204. SmbCeTearDownNetRootEntry(
  1205. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry)
  1206. /*++
  1207. Routine Description:
  1208. This routine tears down a net root entry instance
  1209. Arguments:
  1210. pNetRootEntry - the NEt Root entry to be dereferenced
  1211. --*/
  1212. {
  1213. PAGED_CODE();
  1214. ASSERT((pNetRootEntry->Header.SwizzleCount == 0) &&
  1215. (pNetRootEntry->Header.State == SMBCEDB_MARKED_FOR_DELETION));
  1216. SmbCeLog(("TearNetREntry %lx\n",pNetRootEntry));
  1217. if (pNetRootEntry->Name.Buffer != NULL) {
  1218. RxFreePool(pNetRootEntry->Name.Buffer);
  1219. pNetRootEntry->Name.Buffer = NULL;
  1220. }
  1221. SmbMmFreeObject(pNetRootEntry);
  1222. }
  1223. NTSTATUS
  1224. SmbCeUpdateNetRoot(
  1225. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry,
  1226. PMRX_NET_ROOT pNetRoot)
  1227. /*++
  1228. Routine Description:
  1229. This routine initializes the wrapper data structure corresponding to a
  1230. given net root entry.
  1231. Arguments:
  1232. pNetRootEntry - the server entry
  1233. Return Value:
  1234. STATUS_SUCCESS if successful
  1235. --*/
  1236. {
  1237. PAGED_CODE();
  1238. pNetRoot->Type = pNetRootEntry->NetRoot.NetRootType;
  1239. switch (pNetRoot->Type) {
  1240. case NET_ROOT_DISK:
  1241. {
  1242. pNetRoot->DeviceType = RxDeviceType(DISK);
  1243. RxInitializeNetRootThrottlingParameters(
  1244. &pNetRoot->DiskParameters.LockThrottlingParameters,
  1245. MRxSmbConfiguration.LockIncrement,
  1246. MRxSmbConfiguration.MaximumLock);
  1247. }
  1248. break;
  1249. case NET_ROOT_PIPE:
  1250. pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE);
  1251. break;
  1252. case NET_ROOT_COMM:
  1253. pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT);
  1254. break;
  1255. case NET_ROOT_PRINT:
  1256. pNetRoot->DeviceType = RxDeviceType(PRINTER);
  1257. break;
  1258. case NET_ROOT_MAILSLOT:
  1259. pNetRoot->DeviceType = RxDeviceType(MAILSLOT);
  1260. break;
  1261. case NET_ROOT_WILD:
  1262. break;
  1263. default:
  1264. ASSERT(!"Valid Net Root Type");
  1265. }
  1266. if (pNetRootEntry->NetRoot.DfsAware) {
  1267. SetFlag(pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT);
  1268. } else {
  1269. ClearFlag(pNetRoot->Flags,NETROOT_FLAG_DFS_AWARE_NETROOT);
  1270. }
  1271. return STATUS_SUCCESS;
  1272. }
  1273. NTSTATUS
  1274. SmbCeProbeServers(
  1275. PVOID pContext)
  1276. /*++
  1277. Routine Description:
  1278. This routine probes all the remote servers on which no activity has been
  1279. detected in the recent past.
  1280. Notes:
  1281. The current implementation of walking through the list of all servers to
  1282. initiate echo processing will not scale very well for gateway servers. A
  1283. different mechanism needs to be implemented.
  1284. --*/
  1285. {
  1286. LIST_ENTRY DiscardedServersList;
  1287. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1288. PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT pEchoProbeContext;
  1289. PSMBCEDB_SERVER_ENTRY pPreviousServerEntry = NULL;
  1290. pEchoProbeContext = (PMRXSMB_ECHO_PROBE_SERVICE_CONTEXT)pContext;
  1291. InitializeListHead(&DiscardedServersList);
  1292. SmbCeAcquireSpinLock();
  1293. pServerEntry = SmbCeGetFirstServerEntry();
  1294. while (pServerEntry != NULL) {
  1295. BOOLEAN TearDownTransport = FALSE;
  1296. if ((SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER) &&
  1297. ((pServerEntry->Header.State == SMBCEDB_ACTIVE) ||
  1298. (pServerEntry->Header.State == SMBCEDB_CONSTRUCTION_IN_PROGRESS))) {
  1299. // The additional reference is required to keep this server entry
  1300. // as a place marker in the list of server entries.
  1301. // This will be released on resumption of the processinf further
  1302. // down in this routine
  1303. InterlockedIncrement(&pServerEntry->Header.SwizzleCount);
  1304. SmbCeReleaseSpinLock();
  1305. if (pPreviousServerEntry != NULL) {
  1306. SmbCeDereferenceServerEntry(pPreviousServerEntry);
  1307. }
  1308. // For loop back servers we forego the expired exchange detection
  1309. // mechanism. Since the I/O is directed to the same machine this
  1310. // indicates a problem with the local system.
  1311. if (!pServerEntry->Server.IsLoopBack) {
  1312. TearDownTransport = SmbCeDetectExpiredExchanges(pServerEntry);
  1313. }
  1314. if (!TearDownTransport) {
  1315. if ((pServerEntry->Server.SmbsReceivedSinceLastStrobe == 0) &&
  1316. (pServerEntry->pMidAtlas != NULL) &&
  1317. (pServerEntry->pMidAtlas->NumberOfMidsInUse > 0)) {
  1318. if (pServerEntry->Server.EchoProbeState == ECHO_PROBE_IDLE) {
  1319. NTSTATUS Status;
  1320. LARGE_INTEGER CurrentTime,ExpiryTimeInTicks;
  1321. KeQueryTickCount( &CurrentTime );
  1322. ExpiryTimeInTicks.QuadPart = (1000 * 1000 * 10) / KeQueryTimeIncrement();
  1323. ExpiryTimeInTicks.QuadPart = MRxSmbConfiguration.SessionTimeoutInterval * ExpiryTimeInTicks.QuadPart;
  1324. pServerEntry->Server.EchoExpiryTime.QuadPart = CurrentTime.QuadPart +
  1325. ExpiryTimeInTicks.QuadPart;
  1326. InterlockedExchange(
  1327. &pServerEntry->Server.EchoProbeState,
  1328. ECHO_PROBE_AWAITING_RESPONSE);
  1329. Status = SmbCeSendEchoProbe(
  1330. pServerEntry,
  1331. pEchoProbeContext);
  1332. RxDbgTrace(0,Dbg,("Sending ECHO SMB %lx Status %lx\n",pServerEntry,Status));
  1333. TearDownTransport = ((Status != STATUS_SUCCESS) &&
  1334. (Status != STATUS_PENDING));
  1335. } else if (pServerEntry->Server.EchoProbeState == ECHO_PROBE_AWAITING_RESPONSE) {
  1336. // Compare the current time with the time at which the echo probe
  1337. // was sent. If the interval is greater than the response time then
  1338. // it can be deemed that the echo response is not forthcoming and
  1339. // the tear down can be initiated.
  1340. LARGE_INTEGER CurrentTime;
  1341. KeQueryTickCount( &CurrentTime );
  1342. if ((pServerEntry->Server.EchoExpiryTime.QuadPart != 0) &&
  1343. (pServerEntry->Server.EchoExpiryTime.QuadPart < CurrentTime.QuadPart)) {
  1344. TearDownTransport = TRUE;
  1345. }
  1346. }
  1347. if (TearDownTransport) {
  1348. RxLog(("Echo Problem for srvr%lx \n",pServerEntry));
  1349. }
  1350. } else {
  1351. InterlockedExchange(&pServerEntry->Server.SmbsReceivedSinceLastStrobe,0);
  1352. }
  1353. }
  1354. if (TearDownTransport) {
  1355. InterlockedIncrement(&MRxSmbStatistics.HungSessions);
  1356. SmbCeTransportDisconnectIndicated(pServerEntry);
  1357. }
  1358. // reacquire the spin lock to traverse the list.
  1359. SmbCeAcquireSpinLock();
  1360. pPreviousServerEntry = pServerEntry;
  1361. pServerEntry = SmbCeGetNextServerEntry(pPreviousServerEntry);
  1362. } else {
  1363. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1364. }
  1365. }
  1366. SmbCeReleaseSpinLock();
  1367. if (pPreviousServerEntry != NULL) {
  1368. SmbCeDereferenceServerEntry(pPreviousServerEntry);
  1369. }
  1370. return STATUS_SUCCESS;
  1371. }
  1372. VOID
  1373. SmbCeTransportDisconnectIndicated(
  1374. PSMBCEDB_SERVER_ENTRY pServerEntry)
  1375. /*++
  1376. Routine Description:
  1377. This routine invalidates a server entry on notification from the underlying transport
  1378. Arguments:
  1379. pServerEntry - the server entry to be dereferenced
  1380. Notes:
  1381. The server entry and the associated net roots and sessions are marked as invalid. A
  1382. reconnect is facilitated on other requests as and when required. In addition all
  1383. pending requests are resumed with the appropriate error indication.
  1384. --*/
  1385. {
  1386. NTSTATUS Status;
  1387. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  1388. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  1389. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  1390. RxDbgTrace(0,
  1391. Dbg,
  1392. ("SmbCeDbTransportDisconnectIndicated for %lx -- Entry\n",pServerEntry));
  1393. // Acquire the database resource (DPC Level)
  1394. SmbCeAcquireSpinLock();
  1395. // Increment the associated version count so as to invalidate all existing Fids
  1396. InterlockedIncrement(&pServerEntry->Server.Version);
  1397. pServerEntry->ServerStatus = STATUS_CONNECTION_DISCONNECTED;
  1398. pServerEntry->Header.State = SMBCEDB_DESTRUCTION_IN_PROGRESS;
  1399. // Mark all the associated sessions as being invalid.
  1400. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  1401. while (pSessionEntry != NULL) {
  1402. if (pSessionEntry->Header.State == SMBCEDB_ACTIVE) {
  1403. pSessionEntry->Header.State = SMBCEDB_INVALID;
  1404. }
  1405. pSessionEntry = SmbCeGetNextSessionEntry(pServerEntry,pSessionEntry);
  1406. }
  1407. // Mark all the associated net roots as being invalid
  1408. pNetRootEntry = SmbCeGetFirstNetRootEntry(pServerEntry);
  1409. while (pNetRootEntry != NULL) {
  1410. if (pNetRootEntry->Header.State == SMBCEDB_ACTIVE) {
  1411. pNetRootEntry->Header.State = SMBCEDB_INVALID;
  1412. }
  1413. pNetRootEntry = SmbCeGetNextNetRootEntry(pServerEntry,pNetRootEntry);
  1414. }
  1415. pVNetRootContext = SmbCeGetFirstVNetRootContext(&pServerEntry->VNetRootContexts);
  1416. while (pVNetRootContext != NULL) {
  1417. pVNetRootContext->Header.State = SMBCEDB_INVALID;
  1418. ClearFlag(
  1419. pVNetRootContext->Flags,
  1420. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  1421. pVNetRootContext->TreeId = 0;
  1422. pVNetRootContext = SmbCeGetNextVNetRootContext(
  1423. &pServerEntry->VNetRootContexts,
  1424. pVNetRootContext);
  1425. }
  1426. SmbCeReferenceServerEntry(pServerEntry);
  1427. // release the database resource (DPC Level)
  1428. SmbCeReleaseSpinLock();
  1429. Status = RxDispatchToWorkerThread(
  1430. MRxSmbDeviceObject,
  1431. CriticalWorkQueue,
  1432. SmbCeResumeAllOutstandingRequestsOnError,
  1433. pServerEntry);
  1434. if (Status != STATUS_SUCCESS) {
  1435. RxLog(("SmbCe Xport Disc.Error %lx\n", pServerEntry));
  1436. }
  1437. RxDbgTrace(0,
  1438. Dbg,
  1439. ("SmbCeTransportDisconnectIndicated -- Exit\n"));
  1440. }
  1441. VOID
  1442. SmbCeHandleTransportInvalidation(
  1443. IN PSMBCE_TRANSPORT pTransport)
  1444. /*++
  1445. Routine Description:
  1446. This routine invalidates all servers using a particular transport. This is different from
  1447. a disconnect indication in which one server is invalidated. In this case a transport is being
  1448. removed/invalidated locally and all servers using that transport must be invalidated
  1449. Arguments:
  1450. pTransport - the transport being invalidated
  1451. --*/
  1452. {
  1453. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1454. SmbCeAcquireSpinLock();
  1455. pServerEntry = SmbCeGetFirstServerEntry();
  1456. while (pServerEntry != NULL) {
  1457. if ((pServerEntry->pTransport != NULL) &&
  1458. (pServerEntry->pTransport->pTransport == pTransport)) {
  1459. pServerEntry->Header.State = SMBCEDB_DESTRUCTION_IN_PROGRESS;
  1460. // The invalidation needs to hold onto an extra reference to avoid
  1461. // race conditions which could lead to premature destruction of
  1462. // this server entry.
  1463. SmbCeReferenceServerEntry(pServerEntry);
  1464. }
  1465. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1466. }
  1467. SmbCeReleaseSpinLock();
  1468. SmbCeAcquireResource();
  1469. pServerEntry = SmbCeGetFirstServerEntry();
  1470. while (pServerEntry != NULL) {
  1471. PSMBCEDB_SERVER_ENTRY pPrevServerEntry;
  1472. BOOLEAN fDereferencePrevServerEntry = FALSE;
  1473. if ((pServerEntry->pTransport != NULL) &&
  1474. (pServerEntry->pTransport->pTransport == pTransport)) {
  1475. SmbCeReleaseResource();
  1476. SmbCeTransportDisconnectIndicated(pServerEntry);
  1477. SmbCeReferenceServerEntry(pServerEntry);
  1478. // the reference count of Server Entry will be taken away while the transport
  1479. // is torn down, which prevents the server tranports being torn down again at
  1480. // time the server entry being freed.
  1481. SmbCeUninitializeServerTransport(pServerEntry,
  1482. SmbCeCompleteUninitializeServerTransport,
  1483. pServerEntry);
  1484. SmbCeAcquireResource();
  1485. if (pServerEntry->PreferredTransport != NULL) {
  1486. SmbCeDereferenceTransport(pServerEntry->PreferredTransport);
  1487. pServerEntry->PreferredTransport = NULL;
  1488. }
  1489. fDereferencePrevServerEntry = TRUE;
  1490. }
  1491. pPrevServerEntry = pServerEntry;
  1492. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1493. if (fDereferencePrevServerEntry) {
  1494. SmbCeDereferenceServerEntry(pPrevServerEntry);
  1495. }
  1496. }
  1497. SmbCeReleaseResource();
  1498. }
  1499. VOID
  1500. SmbCeResumeOutstandingRequests(
  1501. PSMBCEDB_REQUESTS pRequests,
  1502. NTSTATUS RequestStatus)
  1503. /*++
  1504. Routine Description:
  1505. This routine resumes the outstanding requests with the appropriate status
  1506. Arguments:
  1507. pRequests - the list of requests
  1508. RequestStatus - the resumption status ..
  1509. Notes:
  1510. As a side effect the list of requests is torn down.
  1511. --*/
  1512. {
  1513. NTSTATUS Status;
  1514. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  1515. // Resume all the outstanding reconnect requests that were held up because an earlier
  1516. // reconnect request was under way.
  1517. // Iterate over the list of pending requests and resume all of them
  1518. pRequestEntry = SmbCeGetFirstRequestEntry(pRequests);
  1519. while (pRequestEntry != NULL) {
  1520. PSMB_EXCHANGE pExchange = pRequestEntry->ReconnectRequest.pExchange;
  1521. RxDbgTrace(0, Dbg, ("Resuming outstanding reconnect request exchange %lx \n",pExchange));
  1522. pExchange->Status = RequestStatus;
  1523. SmbCeDecrementPendingLocalOperations(pExchange);
  1524. // Resume the exchange.
  1525. if (pRequestEntry->Request.pExchange->pSmbCeSynchronizationEvent == NULL) {
  1526. if (RequestStatus == STATUS_SUCCESS) {
  1527. Status = SmbCeResumeExchange(pExchange);
  1528. } else {
  1529. // Invoke the error handler
  1530. RxDbgTrace( 0, Dbg, ("Resuming exchange%lx with error\n",pRequestEntry->Request.pExchange));
  1531. SmbCeFinalizeExchange(pExchange);
  1532. }
  1533. } else {
  1534. KeSetEvent(
  1535. pRequestEntry->Request.pExchange->pSmbCeSynchronizationEvent,
  1536. 0,
  1537. FALSE);
  1538. }
  1539. // Delete the request entry
  1540. SmbCeRemoveRequestEntryLite(pRequests,pRequestEntry);
  1541. // Tear down the continuation entry
  1542. SmbCeTearDownRequestEntry(pRequestEntry);
  1543. // Skip to the next one.
  1544. pRequestEntry = SmbCeGetFirstRequestEntry(pRequests);
  1545. }
  1546. }
  1547. VOID
  1548. SmbCeResumeAllOutstandingRequestsOnError(
  1549. PSMBCEDB_SERVER_ENTRY pServerEntry)
  1550. /*++
  1551. Routine Description:
  1552. This routine handles the resumption of all outstanding requests on an error
  1553. Arguments:
  1554. pServerEntry - the Server entry which is being classified as disconnected
  1555. Notes:
  1556. This routine requires the caller to have obtained a reference on the corresponding
  1557. server entry. This is required because invocation of this routine can be posted
  1558. which implies that a reference is required to avoid premature destruction of
  1559. the associated server entry.
  1560. --*/
  1561. {
  1562. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  1563. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  1564. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  1565. SMBCEDB_REQUESTS Requests;
  1566. SMBCEDB_REQUESTS MidRequests;
  1567. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  1568. PMID_ATLAS pMidAtlas;
  1569. PSMB_EXCHANGE pNegotiateExchange = NULL;
  1570. LIST_ENTRY ExpiredExchanges;
  1571. //DbgPrint("SmbCeResumeAllOutstandingRequestsOnError: Invoked \n");
  1572. InitializeListHead(&ExpiredExchanges);
  1573. InitializeListHead(&Requests.ListHead);
  1574. SmbCeAcquireResource();
  1575. SmbCeAcquireSpinLock();
  1576. if (pServerEntry->Header.State != SMBCEDB_DESTRUCTION_IN_PROGRESS) {
  1577. SmbCeReleaseSpinLock();
  1578. SmbCeReleaseResource();
  1579. SmbCeDereferenceServerEntry(pServerEntry);
  1580. return;
  1581. }
  1582. if (pServerEntry->pNegotiateExchange != NULL) {
  1583. if (pServerEntry->pNegotiateExchange->ReceivePendingOperations > 0) {
  1584. pNegotiateExchange = SmbResetServerEntryNegotiateExchange(pServerEntry);
  1585. }
  1586. }
  1587. // Create a temporary copy of the list that can be traversed after releasing the
  1588. // resource.
  1589. // Copy all the MID assignment requests pending.
  1590. SmbCeTransferRequests(&MidRequests,&pServerEntry->MidAssignmentRequests);
  1591. // Weed out all the reconnect requests so that they can be resumed
  1592. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  1593. while (pRequestEntry != NULL) {
  1594. if (pRequestEntry->GenericRequest.Type == RECONNECT_REQUEST) {
  1595. PSMBCEDB_REQUEST_ENTRY pTempRequestEntry;
  1596. pTempRequestEntry = pRequestEntry;
  1597. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  1598. SmbCeRemoveRequestEntryLite(&pServerEntry->OutstandingRequests,pTempRequestEntry);
  1599. SmbCeAddRequestEntryLite(&Requests,pTempRequestEntry);
  1600. } else {
  1601. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  1602. }
  1603. }
  1604. // The exchanges that have valid MID's assigned to them fall into two categories
  1605. // Those that have a ReceivePendingOperation count of > 0 and those that have
  1606. // a ReceievePendingOperation count of zero. For all the exchanges that belong
  1607. // to the first category the finalize ( quiescent state ) routine must be invoked
  1608. // since no receives will be forthcoming. For those exchanges that are in the
  1609. // second category it is sufficient to mark the MID as being invalid. The
  1610. // finalization( quiescent state ) routine is going to be called on completion
  1611. // of other opertaions in this case.
  1612. pMidAtlas = pServerEntry->pMidAtlas;
  1613. if (pMidAtlas != NULL) {
  1614. PVOID pContext;
  1615. USHORT MidsProcessed = 0;
  1616. USHORT NumberOfMidsInUse;
  1617. USHORT MaximumNumberOfMids;
  1618. USHORT NextMid = 0;
  1619. MaximumNumberOfMids = FsRtlGetMaximumNumberOfMids(pMidAtlas);
  1620. NumberOfMidsInUse = FsRtlGetNumberOfMidsInUse(pMidAtlas);
  1621. while ((NumberOfMidsInUse > MidsProcessed) &&
  1622. (NextMid < MaximumNumberOfMids)) {
  1623. pContext = FsRtlMapMidToContext(pMidAtlas,NextMid);
  1624. if (pContext != NULL) {
  1625. PSMB_EXCHANGE pExchange = (PSMB_EXCHANGE)pContext;
  1626. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_MID_VALID;
  1627. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  1628. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  1629. if ((pExchange->ReceivePendingOperations > 0) &&
  1630. ((pExchange->LocalPendingOperations > 0) ||
  1631. (pExchange->CopyDataPendingOperations > 0) ||
  1632. (pExchange->SendCompletePendingOperations > 0))) {
  1633. // There are other pending operations. By merely setting the
  1634. // pending receive operations to zero, the finalization of
  1635. // the exchange is ensured.
  1636. pExchange->ReceivePendingOperations = 0;
  1637. }
  1638. if (pExchange->ReceivePendingOperations == 0) {
  1639. FsRtlMapAndDissociateMidFromContext(pMidAtlas,NextMid,&pContext);
  1640. }
  1641. MidsProcessed++;
  1642. }
  1643. NextMid++;
  1644. }
  1645. }
  1646. // Transfer all the active exchanges to expired exchanges. This will prevent these
  1647. // exchanges from being considered for time outs again.
  1648. if (!IsListEmpty(&pServerEntry->ActiveExchanges)) {
  1649. pServerEntry->ExpiredExchanges.Blink->Flink = pServerEntry->ActiveExchanges.Flink;
  1650. pServerEntry->ActiveExchanges.Flink->Blink = pServerEntry->ExpiredExchanges.Blink;
  1651. pServerEntry->ExpiredExchanges.Blink = pServerEntry->ActiveExchanges.Blink;
  1652. pServerEntry->ActiveExchanges.Blink->Flink = &pServerEntry->ExpiredExchanges;
  1653. InitializeListHead(&pServerEntry->ActiveExchanges);
  1654. }
  1655. // Splice together all the requests that are awaiting the completion of the
  1656. // session/netroot construction.
  1657. pSessionEntry = SmbCeGetFirstSessionEntry(pServerEntry);
  1658. while (pSessionEntry != NULL) {
  1659. if (pSessionEntry->Header.State == SMBCEDB_ACTIVE) {
  1660. pSessionEntry->Header.State = SMBCEDB_INVALID;
  1661. }
  1662. if (!IsListEmpty(&pSessionEntry->Requests.ListHead)) {
  1663. Requests.ListHead.Blink->Flink = pSessionEntry->Requests.ListHead.Flink;
  1664. pSessionEntry->Requests.ListHead.Flink->Blink = Requests.ListHead.Blink;
  1665. Requests.ListHead.Blink = pSessionEntry->Requests.ListHead.Blink;
  1666. pSessionEntry->Requests.ListHead.Blink->Flink = &Requests.ListHead;
  1667. SmbCeInitializeRequests(&pSessionEntry->Requests);
  1668. }
  1669. pSessionEntry = SmbCeGetNextSessionEntry(pServerEntry,pSessionEntry);
  1670. }
  1671. pNetRootEntry = SmbCeGetFirstNetRootEntry(pServerEntry);
  1672. while (pNetRootEntry != NULL) {
  1673. if (pNetRootEntry->Header.State == SMBCEDB_ACTIVE) {
  1674. pNetRootEntry->Header.State = SMBCEDB_INVALID;
  1675. }
  1676. if (!IsListEmpty(&pNetRootEntry->Requests.ListHead)) {
  1677. Requests.ListHead.Blink->Flink = pNetRootEntry->Requests.ListHead.Flink;
  1678. pNetRootEntry->Requests.ListHead.Flink->Blink = Requests.ListHead.Blink;
  1679. Requests.ListHead.Blink = pNetRootEntry->Requests.ListHead.Blink;
  1680. pNetRootEntry->Requests.ListHead.Blink->Flink = &Requests.ListHead;
  1681. SmbCeInitializeRequests(&pNetRootEntry->Requests);
  1682. }
  1683. pNetRootEntry = SmbCeGetNextNetRootEntry(pServerEntry,pNetRootEntry);
  1684. }
  1685. pVNetRootContext = SmbCeGetFirstVNetRootContext(&pServerEntry->VNetRootContexts);
  1686. while (pVNetRootContext != NULL) {
  1687. pVNetRootContext->Header.State = SMBCEDB_INVALID;
  1688. ClearFlag(
  1689. pVNetRootContext->Flags,
  1690. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  1691. pVNetRootContext->TreeId = 0;
  1692. if (!IsListEmpty(&pVNetRootContext->Requests.ListHead)) {
  1693. Requests.ListHead.Blink->Flink = pVNetRootContext->Requests.ListHead.Flink;
  1694. pVNetRootContext->Requests.ListHead.Flink->Blink = Requests.ListHead.Blink;
  1695. Requests.ListHead.Blink = pVNetRootContext->Requests.ListHead.Blink;
  1696. pVNetRootContext->Requests.ListHead.Blink->Flink = &Requests.ListHead;
  1697. SmbCeInitializeRequests(&pVNetRootContext->Requests);
  1698. }
  1699. pVNetRootContext = SmbCeGetNextVNetRootContext(
  1700. &pServerEntry->VNetRootContexts,
  1701. pVNetRootContext);
  1702. }
  1703. pVNetRootContext = SmbCeGetFirstVNetRootContext(&MRxSmbScavengerServiceContext.VNetRootContexts);
  1704. while (pVNetRootContext != NULL &&
  1705. pVNetRootContext->pServerEntry == pServerEntry) {
  1706. // prevent the VNetRootContexts on the scavenger list from being reused
  1707. pVNetRootContext->Header.State = SMBCEDB_INVALID;
  1708. ClearFlag(
  1709. pVNetRootContext->Flags,
  1710. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID);
  1711. pVNetRootContext->TreeId = 0;
  1712. pVNetRootContext = SmbCeGetNextVNetRootContext(
  1713. &MRxSmbScavengerServiceContext.VNetRootContexts,
  1714. pVNetRootContext);
  1715. }
  1716. pServerEntry->pMidAtlas = NULL;
  1717. if (pServerEntry->NegotiateInProgress) {
  1718. pServerEntry->Header.State = SMBCEDB_CONSTRUCTION_IN_PROGRESS;
  1719. } else {
  1720. pServerEntry->Header.State = SMBCEDB_INVALID;
  1721. }
  1722. SmbCeReleaseSpinLock();
  1723. if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
  1724. SmbCeInitiateDisconnect(pServerEntry);
  1725. }
  1726. SmbCeReleaseResource();
  1727. //DbgPrint("SmbCeResumeAllOutstandingRequestsOnError: Processing outsanding request \n");
  1728. SmbCeResumeOutstandingRequests(&Requests,STATUS_CONNECTION_DISCONNECTED);
  1729. //DbgPrint("SmbCeResumeAllOutstandingRequestsOnError: Processing MID request \n");
  1730. SmbCeResumeDiscardedMidAssignmentRequests(
  1731. &MidRequests,
  1732. STATUS_CONNECTION_DISCONNECTED);
  1733. // Resume all the outstanding requests with the error indication
  1734. // The FsRtlDestroyMidAtlas destroys the Mid atlas and at the same
  1735. // time invokes the specified routine on each valid context.
  1736. if (pMidAtlas != NULL) {
  1737. FsRtlDestroyMidAtlas(pMidAtlas,SmbCeFinalizeExchangeOnDisconnect);
  1738. }
  1739. if (pNegotiateExchange != NULL) {
  1740. pNegotiateExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  1741. pNegotiateExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  1742. pNegotiateExchange->ReceivePendingOperations = 0;
  1743. SmbCeDecrementPendingLocalOperationsAndFinalize(pNegotiateExchange);
  1744. }
  1745. // The remaining ECHO exchanges on the expired exchanges list in the server entry
  1746. // needs to be finalized as well.
  1747. SmbCeAcquireResource();
  1748. SmbCeAcquireSpinLock();
  1749. if (!IsListEmpty(&pServerEntry->ExpiredExchanges)) {
  1750. PLIST_ENTRY pListEntry;
  1751. PSMB_EXCHANGE pExchange;
  1752. pListEntry = pServerEntry->ExpiredExchanges.Flink;
  1753. while (pListEntry != &pServerEntry->ExpiredExchanges) {
  1754. PLIST_ENTRY pNextListEntry = pListEntry->Flink;
  1755. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  1756. if ((pExchange->Mid == SMBCE_ECHO_PROBE_MID) &&
  1757. !FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED) &&
  1758. ((pExchange->ReceivePendingOperations > 0) ||
  1759. (pExchange->LocalPendingOperations > 0) ||
  1760. (pExchange->CopyDataPendingOperations > 0) ||
  1761. (pExchange->SendCompletePendingOperations > 0))) {
  1762. RemoveEntryList(&pExchange->ExchangeList);
  1763. InsertTailList(&ExpiredExchanges,&pExchange->ExchangeList);
  1764. InterlockedIncrement(&pExchange->LocalPendingOperations);
  1765. }
  1766. pListEntry = pNextListEntry;
  1767. }
  1768. }
  1769. SmbCeReleaseSpinLock();
  1770. SmbCeReleaseResource();
  1771. while (!IsListEmpty(&ExpiredExchanges)) {
  1772. PLIST_ENTRY pListEntry;
  1773. PSMB_EXCHANGE pExchange;
  1774. pListEntry = ExpiredExchanges.Flink;
  1775. RemoveHeadList(&ExpiredExchanges);
  1776. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  1777. InitializeListHead(&pExchange->ExchangeList);
  1778. RxLog(("Finalizing scavenged exchange %lx Type %ld\n",pExchange,pExchange->Type));
  1779. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  1780. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  1781. pExchange->ReceivePendingOperations = 0;
  1782. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  1783. }
  1784. //DbgPrint("SmbCeResumeAllOutstandingRequestsOnError: Exit \n");
  1785. SmbCeDereferenceServerEntry(pServerEntry);
  1786. }
  1787. VOID
  1788. SmbCeFinalizeAllExchangesForNetRoot(
  1789. PMRX_NET_ROOT pNetRoot)
  1790. /*++
  1791. Routine Description:
  1792. This routine handles the resumption of all outstanding requests on a forced
  1793. finalization of a connection
  1794. Arguments:
  1795. pNetRoot - the NetRoot which is being fianlized forcibly
  1796. Notes:
  1797. --*/
  1798. {
  1799. PMRX_SRV_CALL pSrvCall;
  1800. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1801. SMBCEDB_REQUESTS Requests;
  1802. LIST_ENTRY ExpiredExchanges;
  1803. PSMB_EXCHANGE pExchange;
  1804. PSMBCEDB_REQUEST_ENTRY pRequestEntry;
  1805. PLIST_ENTRY pListEntry;
  1806. pSrvCall = pNetRoot->pSrvCall;
  1807. pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall);
  1808. InitializeListHead(&Requests.ListHead);
  1809. InitializeListHead(&ExpiredExchanges);
  1810. SmbCeAcquireSpinLock();
  1811. // Walk through the list of active exchanges, and the pending requests to
  1812. // weed out the exchanges for the given VNET_ROOT.
  1813. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->OutstandingRequests);
  1814. while (pRequestEntry != NULL) {
  1815. pExchange = pRequestEntry->GenericRequest.pExchange;
  1816. if ((pRequestEntry->GenericRequest.Type == RECONNECT_REQUEST) &&
  1817. (pExchange->SmbCeContext.pVNetRoot != NULL) &&
  1818. (pExchange->SmbCeContext.pVNetRoot->pNetRoot == pNetRoot)) {
  1819. PSMBCEDB_REQUEST_ENTRY pTempRequestEntry;
  1820. pTempRequestEntry = pRequestEntry;
  1821. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  1822. SmbCeRemoveRequestEntryLite(&pServerEntry->OutstandingRequests,pTempRequestEntry);
  1823. SmbCeAddRequestEntryLite(&Requests,pTempRequestEntry);
  1824. } else {
  1825. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->OutstandingRequests,pRequestEntry);
  1826. }
  1827. }
  1828. pRequestEntry = SmbCeGetFirstRequestEntry(&pServerEntry->MidAssignmentRequests);
  1829. while (pRequestEntry != NULL) {
  1830. pExchange = pRequestEntry->GenericRequest.pExchange;
  1831. ASSERT(pRequestEntry->GenericRequest.Type == ACQUIRE_MID_REQUEST);
  1832. if ((pRequestEntry->GenericRequest.Type == ACQUIRE_MID_REQUEST) &&
  1833. (pExchange->SmbCeContext.pVNetRoot != NULL) &&
  1834. (pExchange->SmbCeContext.pVNetRoot->pNetRoot == pNetRoot)) {
  1835. PSMBCEDB_REQUEST_ENTRY pTempRequestEntry;
  1836. pTempRequestEntry = pRequestEntry;
  1837. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->MidAssignmentRequests,pRequestEntry);
  1838. SmbCeRemoveRequestEntryLite(&pServerEntry->MidAssignmentRequests,pTempRequestEntry);
  1839. // Signal the waiter for resumption
  1840. pTempRequestEntry->MidRequest.pResumptionContext->Status = STATUS_CONNECTION_DISCONNECTED;
  1841. SmbCeResume(pTempRequestEntry->MidRequest.pResumptionContext);
  1842. SmbCeTearDownRequestEntry(pTempRequestEntry);
  1843. } else {
  1844. pRequestEntry = SmbCeGetNextRequestEntry(&pServerEntry->MidAssignmentRequests,pRequestEntry);
  1845. }
  1846. }
  1847. pListEntry = pServerEntry->ActiveExchanges.Flink;
  1848. while (pListEntry != &pServerEntry->ActiveExchanges) {
  1849. PLIST_ENTRY pNextListEntry = pListEntry->Flink;
  1850. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  1851. if ((pExchange->SmbCeContext.pVNetRoot != NULL) &&
  1852. (pExchange->SmbCeContext.pVNetRoot->pNetRoot == pNetRoot)) {
  1853. if (!FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_FINALIZED)) {
  1854. if (pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID) {
  1855. NTSTATUS LocalStatus;
  1856. LocalStatus = SmbCepDiscardMidAssociatedWithExchange(
  1857. pExchange);
  1858. ASSERT(LocalStatus == STATUS_SUCCESS);
  1859. }
  1860. if ((pExchange->ReceivePendingOperations > 0) ||
  1861. (pExchange->LocalPendingOperations > 0) ||
  1862. (pExchange->CopyDataPendingOperations > 0) ||
  1863. (pExchange->SendCompletePendingOperations > 0)) {
  1864. RemoveEntryList(&pExchange->ExchangeList);
  1865. InsertTailList(&ExpiredExchanges,&pExchange->ExchangeList);
  1866. InterlockedIncrement(&pExchange->LocalPendingOperations);
  1867. }
  1868. }
  1869. }
  1870. pListEntry = pNextListEntry;
  1871. }
  1872. SmbCeReleaseSpinLock();
  1873. while (!IsListEmpty(&ExpiredExchanges)) {
  1874. pListEntry = ExpiredExchanges.Flink;
  1875. RemoveHeadList(&ExpiredExchanges);
  1876. pExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  1877. InitializeListHead(&pExchange->ExchangeList);
  1878. RxLog(("Finalizing scavenged exchange %lx Type %ld\n",pExchange,pExchange->Type));
  1879. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  1880. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  1881. pExchange->ReceivePendingOperations = 0;
  1882. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  1883. }
  1884. SmbCeResumeOutstandingRequests(&Requests,STATUS_CONNECTION_DISCONNECTED);
  1885. }
  1886. VOID
  1887. SmbCeTearDownRequestEntry(
  1888. PSMBCEDB_REQUEST_ENTRY pRequestEntry)
  1889. /*++
  1890. Routine Description:
  1891. This routine tears down a request entry
  1892. Arguments:
  1893. pRequestEntry - the request entry to be torn down
  1894. Notes:
  1895. --*/
  1896. {
  1897. SmbMmFreeObject(pRequestEntry);
  1898. }
  1899. //
  1900. // The connection engine database initializtion/tear down routines
  1901. //
  1902. extern NTSTATUS
  1903. SmbMmInit();
  1904. extern VOID
  1905. SmbMmTearDown();
  1906. KIRQL s_SmbCeDbSpinLockSavedIrql;
  1907. KSPIN_LOCK s_SmbCeDbSpinLock;
  1908. ERESOURCE s_SmbCeDbResource;
  1909. SMBCEDB_SERVERS s_DbServers;
  1910. BOOLEAN s_SmbCeDbSpinLockAcquired;
  1911. NTSTATUS
  1912. SmbCeDbInit()
  1913. /*++
  1914. Routine Description:
  1915. This routine initializes the SMBCe database
  1916. Notes:
  1917. --*/
  1918. {
  1919. NTSTATUS Status;
  1920. PAGED_CODE();
  1921. // Initialize the lists associated with various database entities
  1922. InitializeListHead(&s_DbServers.ListHead);
  1923. // Initialize the resource associated with the database.
  1924. KeInitializeSpinLock(&s_SmbCeDbSpinLock );
  1925. //ExInitializeResource(&s_SmbCeDbResource);
  1926. s_SmbCeDbSpinLockAcquired = FALSE;
  1927. MRxSmbInitializeSmbCe();
  1928. // Initialize the memory management data structures.
  1929. Status = SmbMmInit();
  1930. return Status;
  1931. }
  1932. VOID
  1933. SmbCeDbTearDown()
  1934. /*++
  1935. Routine Description:
  1936. This routine tears down the SMB connection engine database
  1937. Notes:
  1938. --*/
  1939. {
  1940. // Walk through the list of servers and tear them down.
  1941. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  1942. KEVENT ServerEntryTearDownEvent;
  1943. BOOLEAN NeedToWait = FALSE;
  1944. KeInitializeEvent(
  1945. &ServerEntryTearDownEvent,
  1946. NotificationEvent,
  1947. FALSE);
  1948. SmbCeStartStopContext.pServerEntryTearDownEvent = &ServerEntryTearDownEvent;
  1949. SmbCeAcquireResource();
  1950. SmbCeAcquireSpinLock();
  1951. pServerEntry = SmbCeGetFirstServerEntry();
  1952. if (pServerEntry != NULL) {
  1953. SmbCeReferenceServerEntry(pServerEntry);
  1954. NeedToWait = TRUE;
  1955. }
  1956. while (pServerEntry != NULL) {
  1957. PSMBCEDB_SERVER_ENTRY pTempServerEntry;
  1958. pTempServerEntry = pServerEntry;
  1959. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  1960. if (pServerEntry != NULL) {
  1961. SmbCeReferenceServerEntry(pServerEntry);
  1962. }
  1963. SmbCeReleaseSpinLock();
  1964. SmbCeReleaseResource();
  1965. pTempServerEntry->Header.State = SMBCEDB_DESTRUCTION_IN_PROGRESS;
  1966. pTempServerEntry->ServerStatus = STATUS_REDIRECTOR_PAUSED;
  1967. SmbCeResumeAllOutstandingRequestsOnError(pTempServerEntry);
  1968. SmbCeAcquireResource();
  1969. SmbCeAcquireSpinLock();
  1970. }
  1971. SmbCeReleaseSpinLock();
  1972. SmbCeReleaseResource();
  1973. MRxSmbTearDownSmbCe();
  1974. if (NeedToWait) {
  1975. KeWaitForSingleObject(
  1976. &ServerEntryTearDownEvent,
  1977. Executive,
  1978. KernelMode,
  1979. FALSE,
  1980. NULL);
  1981. }
  1982. // Tear down the connection engine memory management data structures.
  1983. SmbMmTearDown();
  1984. }
  1985. NTSTATUS
  1986. FindServerEntryFromCompleteUNCPath(
  1987. USHORT *lpuServerShareName,
  1988. PSMBCEDB_SERVER_ENTRY *ppServerEntry
  1989. )
  1990. /*++
  1991. Routine Description:
  1992. Given a UNC path of the form \\server\share, this routine looks up the redir
  1993. in-memory data structures to locate such s SMBCEDB_SERVER_ENTRY for the server
  1994. Arguments:
  1995. lpuServerShareName \\server\share
  1996. ppServerEntry Contains the server entry if successful
  1997. Notes:
  1998. The server entry is refcounted, hence the caller must dereference it after use by
  1999. calling SmbCeDereferenceServerEntry
  2000. --*/
  2001. {
  2002. UNICODE_STRING unistrServerName;
  2003. USHORT *lpuT = lpuServerShareName;
  2004. DWORD dwlenServerShare, dwlenServer=0;
  2005. if ((*lpuT++ != (USHORT)'\\') || (*lpuT++ != (USHORT)'\\'))
  2006. {
  2007. return STATUS_INVALID_PARAMETER;
  2008. }
  2009. for (dwlenServerShare = 1; *lpuT; lpuT++, dwlenServerShare++)
  2010. {
  2011. if (*lpuT == (USHORT)'\\')
  2012. {
  2013. if (dwlenServer)
  2014. {
  2015. break;
  2016. }
  2017. else
  2018. {
  2019. dwlenServer = dwlenServerShare; // length of the \server part
  2020. }
  2021. }
  2022. }
  2023. unistrServerName.Length = unistrServerName.MaximumLength = (USHORT)(dwlenServer * sizeof(USHORT));
  2024. unistrServerName.Buffer = lpuServerShareName+1;
  2025. SmbCeAcquireResource();
  2026. *ppServerEntry = SmbCeFindServerEntry(&unistrServerName, SMBCEDB_FILE_SERVER);
  2027. SmbCeReleaseResource();
  2028. if (*ppServerEntry)
  2029. {
  2030. return STATUS_SUCCESS;
  2031. }
  2032. return STATUS_UNSUCCESSFUL;
  2033. }
  2034. NTSTATUS
  2035. FindNetRootEntryFromCompleteUNCPath(
  2036. USHORT *lpuServerShareName,
  2037. PSMBCEDB_NET_ROOT_ENTRY *ppNetRootEntry
  2038. )
  2039. /*++
  2040. Routine Description:
  2041. Given a UNC path of the form \\server\share, this routine looks up the redir
  2042. in-memory data structures to locate such a NETROOT
  2043. Arguments:
  2044. lpuServerShareName \\server\share
  2045. ppNetRootEntry Contains the netroot entry if successful.
  2046. Notes:
  2047. The netroot entry is refcounted, hence the caller must dereference it after use by
  2048. calling SmbCeDereferenceNetRootEntry
  2049. --*/
  2050. {
  2051. PSMBCEDB_SERVER_ENTRY pServerEntry = NULL;
  2052. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL;
  2053. UNICODE_STRING unistrServerName, unistrServerShare;
  2054. USHORT *lpuT = lpuServerShareName, *lpuDfsShare=NULL, *lpuSav;
  2055. DWORD dwlenServerShare, dwlenServer=0;
  2056. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2057. if ((*lpuT++ != (USHORT)'\\') || (*lpuT++ != (USHORT)'\\'))
  2058. {
  2059. return STATUS_INVALID_PARAMETER;
  2060. }
  2061. for (dwlenServerShare = 1; *lpuT; lpuT++, dwlenServerShare++)
  2062. {
  2063. if (*lpuT == (USHORT)'\\')
  2064. {
  2065. if (dwlenServer)
  2066. {
  2067. break;
  2068. }
  2069. else
  2070. {
  2071. dwlenServer = dwlenServerShare; // length of the \server part
  2072. }
  2073. }
  2074. }
  2075. ASSERT((dwlenServerShare>dwlenServer));
  2076. unistrServerName.Length = unistrServerName.MaximumLength = (USHORT)(dwlenServer * sizeof(USHORT));
  2077. unistrServerName.Buffer = lpuServerShareName+1;
  2078. unistrServerShare.Length = unistrServerShare.MaximumLength = (USHORT)(dwlenServerShare * sizeof(USHORT));
  2079. unistrServerShare.Buffer = lpuServerShareName+1;
  2080. SmbCeAcquireResource();
  2081. // lookup in standard places
  2082. pServerEntry = SmbCeFindServerEntry(&unistrServerName, SMBCEDB_FILE_SERVER);
  2083. if (pServerEntry)
  2084. {
  2085. pNetRootEntry = SmbCeFindNetRootEntry(pServerEntry, &unistrServerShare);
  2086. SmbCeDereferenceServerEntry(pServerEntry);
  2087. if (pNetRootEntry)
  2088. {
  2089. goto bailout;
  2090. }
  2091. }
  2092. // now look to see if a DFS alternate has this share
  2093. pServerEntry = SmbCeGetFirstServerEntry();
  2094. while (pServerEntry != NULL) {
  2095. DWORD dwAllocationSize = 0;
  2096. if ((RtlCompareUnicodeString(
  2097. &unistrServerName,
  2098. &pServerEntry->DfsRootName,
  2099. TRUE) == 0)) {
  2100. dwAllocationSize = pServerEntry->Name.MaximumLength+
  2101. (dwlenServerShare-dwlenServer+2) * sizeof(USHORT);
  2102. lpuDfsShare = RxAllocatePoolWithTag(
  2103. NonPagedPool,
  2104. dwAllocationSize,
  2105. MRXSMB_SESSION_POOLTAG);
  2106. if (!lpuDfsShare)
  2107. {
  2108. Status = STATUS_INSUFFICIENT_RESOURCES;
  2109. goto bailout;
  2110. }
  2111. ASSERT(dwAllocationSize > pServerEntry->Name.MaximumLength);
  2112. unistrServerShare.Length = (USHORT)(pServerEntry->Name.Length + (dwlenServerShare-dwlenServer) * sizeof(USHORT));
  2113. unistrServerShare.MaximumLength = (USHORT)(pServerEntry->Name.MaximumLength+
  2114. (dwlenServerShare-dwlenServer+2) * sizeof(USHORT));
  2115. memcpy(lpuDfsShare, pServerEntry->Name.Buffer, pServerEntry->Name.Length);
  2116. memcpy(&lpuDfsShare[pServerEntry->Name.Length/sizeof(USHORT)],
  2117. &(unistrServerShare.Buffer[dwlenServer]),
  2118. (dwlenServerShare-dwlenServer) * sizeof(USHORT));
  2119. lpuSav = unistrServerShare.Buffer;
  2120. unistrServerShare.Buffer = lpuDfsShare;
  2121. pNetRootEntry = SmbCeFindNetRootEntry(pServerEntry, &unistrServerShare);
  2122. unistrServerShare.Buffer = lpuSav;
  2123. RxFreePool(lpuDfsShare);
  2124. // stop if we found it
  2125. if (pNetRootEntry)
  2126. {
  2127. break;
  2128. }
  2129. }
  2130. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  2131. }
  2132. bailout:
  2133. if (pNetRootEntry)
  2134. {
  2135. SmbCeReferenceNetRootEntry(pNetRootEntry);
  2136. *ppNetRootEntry = pNetRootEntry;
  2137. Status = STATUS_SUCCESS;
  2138. }
  2139. SmbCeReleaseResource();
  2140. return Status;
  2141. }
  2142. PSMBCEDB_SESSION_ENTRY
  2143. SmbCeGetDefaultSessionEntry(
  2144. PSMBCEDB_SERVER_ENTRY pServerEntry,
  2145. ULONG SessionId,
  2146. PLUID pLogonId
  2147. )
  2148. /*++
  2149. Routine Description:
  2150. This routine returns the session entry from the default sessions list.
  2151. Arguments:
  2152. pServerEntry - Server entry
  2153. SessionId - Hydra session Id.
  2154. pLogonId - the logon id.
  2155. Notes:
  2156. This is called with the SmbCe spinlock held.
  2157. --*/
  2158. {
  2159. PLIST_ENTRY pListEntry;
  2160. PSMBCEDB_SESSION_ENTRY pSession;
  2161. PSMBCEDB_SESSION_ENTRY pReturnSession = NULL;
  2162. ASSERT( pServerEntry != NULL );
  2163. pListEntry = pServerEntry->Sessions.DefaultSessionList.Flink;
  2164. while( pListEntry != &pServerEntry->Sessions.DefaultSessionList ) {
  2165. pSession = CONTAINING_RECORD( pListEntry, SMBCEDB_SESSION_ENTRY, DefaultSessionLink );
  2166. if( pSession->Session.SessionId == SessionId ) {
  2167. if (!RtlEqualLuid(
  2168. &pSession->Session.LogonId,
  2169. pLogonId)) {
  2170. pReturnSession = pSession;
  2171. break;
  2172. }
  2173. }
  2174. pListEntry = pListEntry->Flink;
  2175. }
  2176. return( pReturnSession );
  2177. }
  2178. VOID
  2179. SmbCeRemoveDefaultSessionEntry(
  2180. PSMBCEDB_SESSION_ENTRY pDefaultSessionEntry
  2181. )
  2182. /*++
  2183. Routine Description:
  2184. This routine removes the session entry from the default sessions list.
  2185. Arguments:
  2186. pServerEntry - Server entry
  2187. SessionId - Hydra session Id.
  2188. pLogonId - the logon id.
  2189. Notes:
  2190. This is called with the SmbCe spinlock held.
  2191. --*/
  2192. {
  2193. if( pDefaultSessionEntry &&
  2194. pDefaultSessionEntry->DefaultSessionLink.Flink ) {
  2195. RemoveEntryList( &pDefaultSessionEntry->DefaultSessionLink );
  2196. pDefaultSessionEntry->DefaultSessionLink.Flink = NULL;
  2197. pDefaultSessionEntry->DefaultSessionLink.Blink = NULL;
  2198. }
  2199. }
  2200.