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.

602 lines
14 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. blksess.c
  5. Abstract:
  6. This module implements routines for managing session blocks.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 4-Oct-1989
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "blksess.tmh"
  13. #pragma hdrstop
  14. #define BugCheckFileId SRV_FILE_BLKSESS
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvAllocateSession )
  17. #pragma alloc_text( PAGE, SrvCheckAndReferenceSession )
  18. #pragma alloc_text( PAGE, SrvCloseSession )
  19. #pragma alloc_text( PAGE, SrvCloseSessionsOnConnection )
  20. #pragma alloc_text( PAGE, SrvDereferenceSession )
  21. #pragma alloc_text( PAGE, SrvFreeSession )
  22. #endif
  23. VOID
  24. SrvAllocateSession (
  25. OUT PSESSION *Session,
  26. IN PUNICODE_STRING UserName OPTIONAL,
  27. IN PUNICODE_STRING Domain OPTIONAL
  28. )
  29. /*++
  30. Routine Description:
  31. This function allocates a Session Block from the FSP heap.
  32. Arguments:
  33. Session - Returns a pointer to the session block, or NULL if
  34. no heap space was available.
  35. Return Value:
  36. None.
  37. --*/
  38. {
  39. ULONG blockLength;
  40. PNONPAGED_HEADER header;
  41. PSESSION session;
  42. PWCH buffer;
  43. PAGED_CODE( );
  44. blockLength = sizeof(SESSION);
  45. if( ARGUMENT_PRESENT( UserName ) ) {
  46. blockLength += UserName->Length;
  47. }
  48. if( ARGUMENT_PRESENT( Domain ) ) {
  49. blockLength += Domain->Length;
  50. }
  51. //
  52. // Attempt to allocate from the heap.
  53. //
  54. session = ALLOCATE_HEAP( blockLength, BlockTypeSession );
  55. *Session = session;
  56. if ( session == NULL ) {
  57. INTERNAL_ERROR(
  58. ERROR_LEVEL_EXPECTED,
  59. "SrvAllocateSession: Unable to allocate %d bytes from heap",
  60. blockLength,
  61. NULL
  62. );
  63. return;
  64. }
  65. IF_DEBUG(HEAP) {
  66. SrvPrint1( "SrvAllocateSession: Allocated session at %p\n", session );
  67. }
  68. //
  69. // Allocate the nonpaged header.
  70. //
  71. header = ALLOCATE_NONPAGED_POOL(
  72. sizeof(NONPAGED_HEADER),
  73. BlockTypeNonpagedHeader
  74. );
  75. if ( header == NULL ) {
  76. INTERNAL_ERROR(
  77. ERROR_LEVEL_EXPECTED,
  78. "SrvAllocateSession: Unable to allocate %d bytes from pool.",
  79. sizeof( NONPAGED_HEADER ),
  80. NULL
  81. );
  82. FREE_HEAP( session );
  83. *Session = NULL;
  84. return;
  85. }
  86. header->Type = BlockTypeSession;
  87. header->PagedBlock = session;
  88. RtlZeroMemory( session, blockLength );
  89. session->NonpagedHeader = header;
  90. SET_BLOCK_TYPE_STATE_SIZE( session, BlockTypeSession, BlockStateActive, blockLength );
  91. session->SecurityContext = NULL;
  92. header->ReferenceCount = 2; // allow for Active status and caller's pointer
  93. //
  94. // Initialize times for autologoff.
  95. //
  96. KeQuerySystemTime( &session->StartTime );
  97. session->LastUseTime.QuadPart = session->StartTime.QuadPart;
  98. buffer = (PWCH)( session + 1 );
  99. //
  100. // Initialize the user name.
  101. //
  102. if( ARGUMENT_PRESENT( UserName ) ) {
  103. session->NtUserName.Length = UserName->Length;
  104. session->NtUserName.MaximumLength = UserName->Length;
  105. session->NtUserName.Buffer = buffer;
  106. buffer += UserName->Length / sizeof( WCHAR );
  107. if( UserName->Length != 0 ) {
  108. RtlCopyUnicodeString( &session->NtUserName, UserName );
  109. }
  110. }
  111. //
  112. // Initialize the domain name.
  113. //
  114. if( ARGUMENT_PRESENT( Domain ) ) {
  115. session->NtUserDomain.Length = Domain->Length;
  116. session->NtUserDomain.MaximumLength = Domain->Length;
  117. session->NtUserDomain.Buffer = buffer;
  118. if( Domain->Buffer != NULL ) {
  119. RtlCopyUnicodeString( &session->NtUserDomain, Domain );
  120. }
  121. }
  122. #if SRVDBG2
  123. session->BlockHeader.ReferenceCount = 2; // for INITIALIZE_REFERENCE_HISTORY
  124. #endif
  125. INITIALIZE_REFERENCE_HISTORY( session );
  126. INCREMENT_DEBUG_STAT( SrvDbgStatistics.SessionInfo.Allocations );
  127. return;
  128. } // SrvAllocateSession
  129. BOOLEAN SRVFASTCALL
  130. SrvCheckAndReferenceSession (
  131. PSESSION Session
  132. )
  133. /*++
  134. Routine Description:
  135. This function atomically verifies that a session is active and
  136. increments the reference count on the session if it is.
  137. Arguments:
  138. Session - Address of session
  139. Return Value:
  140. BOOLEAN - Returns TRUE if the session is active, FALSE otherwise.
  141. --*/
  142. {
  143. PAGED_CODE( );
  144. if( Session->LogonSequenceInProgress == FALSE ) {
  145. //
  146. // Acquire the lock that guards the session's state field.
  147. //
  148. ACQUIRE_LOCK( &Session->Connection->Lock );
  149. //
  150. // If the session is active, reference it and return TRUE.
  151. //
  152. if ( GET_BLOCK_STATE(Session) == BlockStateActive ) {
  153. SrvReferenceSession( Session );
  154. RELEASE_LOCK( &Session->Connection->Lock );
  155. return TRUE;
  156. }
  157. //
  158. // The session isn't active. Return FALSE.
  159. //
  160. RELEASE_LOCK( &Session->Connection->Lock );
  161. }
  162. return FALSE;
  163. } // SrvCheckAndReferenceSession
  164. VOID
  165. SrvCloseSession (
  166. PSESSION Session
  167. )
  168. /*++
  169. Routine Description:
  170. This routine does the core of a logoff (disconnect session). It
  171. sets the state of the session to Closing, closes open files and
  172. pending transactions, and dereferences the session block.
  173. Arguments:
  174. Session - Supplies a pointer to the session block that is to be
  175. closed.
  176. Return Value:
  177. None.
  178. --*/
  179. {
  180. PCONNECTION connection = Session->Connection;
  181. PPAGED_CONNECTION pagedConnection = connection->PagedConnection;
  182. PAGED_CODE( );
  183. ACQUIRE_LOCK( &connection->Lock );
  184. if ( GET_BLOCK_STATE(Session) == BlockStateActive ) {
  185. IF_DEBUG(BLOCK1) SrvPrint1( "Closing session at %p\n", Session );
  186. SET_BLOCK_STATE( Session, BlockStateClosing );
  187. //
  188. // Free the session table entry.
  189. //
  190. // *** This must be done here, not in SrvDereferenceSession!
  191. // This routine can be called from SrvSmbSessionSetupAndX
  192. // when it needs to free up session table entry 0 for
  193. // IMMEDIATE reuse.
  194. //
  195. SrvRemoveEntryTable(
  196. &pagedConnection->SessionTable,
  197. UID_INDEX( Session->Uid )
  198. );
  199. connection->CurrentNumberOfSessions--;
  200. RELEASE_LOCK( &connection->Lock );
  201. //
  202. // Disconnect the tree connects from this session
  203. //
  204. SrvDisconnectTreeConnectsFromSession( connection, Session );
  205. //
  206. // Close all open files.
  207. //
  208. SrvCloseRfcbsOnSessionOrPid( Session, NULL );
  209. //
  210. // Close all pending transactions.
  211. //
  212. SrvCloseTransactionsOnSession( Session );
  213. //
  214. // Close all DOS searches on this session.
  215. //
  216. SrvCloseSearches(
  217. connection,
  218. (PSEARCH_FILTER_ROUTINE)SrvSearchOnSession,
  219. (PVOID) Session,
  220. NULL
  221. );
  222. //
  223. // Close all cached directories on this session.
  224. //
  225. SrvCloseCachedDirectoryEntries( connection );
  226. //
  227. // Dereference the session (to indicate that it's no longer
  228. // open).
  229. //
  230. SrvDereferenceSession( Session );
  231. INCREMENT_DEBUG_STAT( SrvDbgStatistics.SessionInfo.Closes );
  232. } else {
  233. RELEASE_LOCK( &connection->Lock );
  234. }
  235. return;
  236. } // SrvCloseSession
  237. VOID
  238. SrvCloseSessionsOnConnection (
  239. IN PCONNECTION Connection,
  240. IN PUNICODE_STRING UserName OPTIONAL
  241. )
  242. /*++
  243. Routine Description:
  244. This function closes sessions on a connection. It walks the
  245. connection's list of sessions, calling SrvCloseSession as
  246. appropriate.
  247. Arguments:
  248. Connection - Supplies a pointer to a Connection Block
  249. UserName - if specified, only sessions with the given user name
  250. are closed.
  251. Return Value:
  252. None.
  253. --*/
  254. {
  255. PTABLE_HEADER tableHeader;
  256. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  257. LONG i;
  258. UNICODE_STRING userName;
  259. NTSTATUS status;
  260. PAGED_CODE( );
  261. //
  262. // Close all active sessions. (This also causes all open files
  263. // and pending transactions to be closed.)
  264. //
  265. // *** In order to prevent the session from being deallocated
  266. // between when we find it in the table and the call to
  267. // SrvCloseSession, we reference the session. It is not
  268. // legal to hold the connection lock while calling
  269. // SrvCloseSession, so simply holding the lock while we walk
  270. // the list is not legal.
  271. tableHeader = &pagedConnection->SessionTable;
  272. ACQUIRE_LOCK( &Connection->Lock );
  273. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  274. PSESSION session = (PSESSION)tableHeader->Table[i].Owner;
  275. if( session == NULL || GET_BLOCK_STATE( session ) != BlockStateActive ) {
  276. //
  277. // This session either doesn't exist, or is already going away
  278. //
  279. continue;
  280. }
  281. if( UserName != NULL ) {
  282. //
  283. // Get the user name for this session. We don't care about the
  284. // domain name.
  285. //
  286. status = SrvGetUserAndDomainName( session, &userName, NULL );
  287. if( !NT_SUCCESS( status ) ) {
  288. //
  289. // We can't figure out the name for the user for this session.
  290. // We probably shouldn't just blow it away, so let's just keep
  291. // going.
  292. //
  293. continue;
  294. }
  295. if( RtlCompareUnicodeString( &userName, UserName, TRUE ) != 0 ) {
  296. //
  297. // This is not the user we're interested in. Skip it.
  298. //
  299. SrvReleaseUserAndDomainName( session, &userName, NULL );
  300. continue;
  301. }
  302. SrvReleaseUserAndDomainName( session, &userName, NULL );
  303. }
  304. SrvReferenceSession( session );
  305. RELEASE_LOCK( &Connection->Lock );
  306. SrvStatistics.SessionsErroredOut++;
  307. SrvCloseSession( session );
  308. SrvDereferenceSession( session );
  309. ACQUIRE_LOCK( &Connection->Lock );
  310. }
  311. RELEASE_LOCK( &Connection->Lock );
  312. } // SrvCloseSessionsOnConnection
  313. VOID SRVFASTCALL
  314. SrvDereferenceSession (
  315. IN PSESSION Session
  316. )
  317. /*++
  318. Routine Description:
  319. This function decrements the reference count on a session. If the
  320. reference count goes to zero, the session block is deleted.
  321. Since this routine may call SrvDereferenceConnection, the caller
  322. must be careful if he holds the connection lock that he also
  323. holds a referenced pointer to the connection.
  324. Arguments:
  325. Session - Address of session
  326. Return Value:
  327. None.
  328. --*/
  329. {
  330. PCONNECTION connection;
  331. LONG result;
  332. PAGED_CODE( );
  333. //
  334. // Enter a critical section and decrement the reference count on the
  335. // block.
  336. //
  337. connection = Session->Connection;
  338. IF_DEBUG(REFCNT) {
  339. SrvPrint2( "Dereferencing session %p; old refcnt %lx\n",
  340. Session, Session->NonpagedHeader->ReferenceCount );
  341. }
  342. ASSERT( GET_BLOCK_TYPE( Session ) == BlockTypeSession );
  343. ASSERT( Session->NonpagedHeader->ReferenceCount > 0 );
  344. UPDATE_REFERENCE_HISTORY( Session, TRUE );
  345. result = InterlockedDecrement(
  346. &Session->NonpagedHeader->ReferenceCount
  347. );
  348. if ( result == 0 ) {
  349. //
  350. // The new reference count is 0, meaning that it's time to
  351. // delete this block.
  352. //
  353. // Remove the session from the global list of sessions.
  354. //
  355. SrvRemoveEntryOrderedList( &SrvSessionList, Session );
  356. //
  357. // Dereference the connection.
  358. //
  359. SrvDereferenceConnection( connection );
  360. DEBUG Session->Connection = NULL;
  361. //
  362. // Free the session block.
  363. //
  364. SrvFreeSession( Session );
  365. }
  366. return;
  367. } // SrvDereferenceSession
  368. VOID
  369. SrvFreeSession (
  370. IN PSESSION Session
  371. )
  372. /*++
  373. Routine Description:
  374. This function returns a Session Block to the FSP heap.
  375. Arguments:
  376. Session - Address of session
  377. Return Value:
  378. None.
  379. --*/
  380. {
  381. KAPC_STATE ApcState;
  382. PEPROCESS process;
  383. PAGED_CODE( );
  384. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Session, BlockTypeGarbage, BlockStateDead, -1 );
  385. DEBUG Session->NonpagedHeader->ReferenceCount = -1;
  386. TERMINATE_REFERENCE_HISTORY( Session );
  387. //
  388. // Ensure we are in the system process
  389. //
  390. process = IoGetCurrentProcess();
  391. if ( process != SrvServerProcess ) {
  392. KeStackAttachProcess( SrvServerProcess, &ApcState );
  393. }
  394. //
  395. // Tell the License Server
  396. //
  397. SrvXsLSOperation( Session, XACTSRV_MESSAGE_LSRELEASE );
  398. //
  399. // Close the logon token
  400. //
  401. SrvFreeSecurityContexts( Session );
  402. //
  403. // Get back to where we were
  404. //
  405. if( process != SrvServerProcess ) {
  406. KeUnstackDetachProcess( &ApcState );
  407. }
  408. //
  409. // Deallocate the session's memory.
  410. //
  411. DEALLOCATE_NONPAGED_POOL( Session->NonpagedHeader );
  412. FREE_HEAP( Session );
  413. IF_DEBUG(HEAP) {
  414. SrvPrint1( "SrvFreeSession: Freed session block at %p\n", Session );
  415. }
  416. INCREMENT_DEBUG_STAT( SrvDbgStatistics.SessionInfo.Frees );
  417. return;
  418. } // SrvFreeSession