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.

741 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. svcsess.c
  5. Abstract:
  6. This module contains routines for supporting the session APIs in the
  7. server service, SrvNetSessionDel, SrvNetSessionEnum and
  8. SrvNetSessionGetInfo.
  9. Author:
  10. David Treadwell (davidtr) 31-Jan-1991
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "svcsess.tmh"
  15. #pragma hdrstop
  16. #define BugCheckFileId SRV_FILE_SVCSESS
  17. //
  18. // defined in scavengr.c
  19. //
  20. VOID
  21. UpdateSessionLastUseTime(
  22. IN PLARGE_INTEGER CurrentTime
  23. );
  24. //
  25. // Forward declarations.
  26. //
  27. VOID
  28. FillSessionInfoBuffer (
  29. IN PSERVER_REQUEST_PACKET Srp,
  30. IN PVOID Block,
  31. IN OUT PVOID *FixedStructure,
  32. IN LPWSTR *EndOfVariableData
  33. );
  34. BOOLEAN
  35. FilterSessions (
  36. IN PSERVER_REQUEST_PACKET Srp,
  37. IN PVOID Block
  38. );
  39. ULONG
  40. SizeSessions (
  41. IN PSERVER_REQUEST_PACKET Srp,
  42. IN PVOID Block
  43. );
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text( PAGE, SrvNetSessionDel )
  46. #pragma alloc_text( PAGE, SrvNetSessionEnum )
  47. #pragma alloc_text( PAGE, FillSessionInfoBuffer )
  48. #pragma alloc_text( PAGE, FilterSessions )
  49. #pragma alloc_text( PAGE, SizeSessions )
  50. #endif
  51. //
  52. // Macros to determine the size a session would take up at one of the
  53. // levels of session information.
  54. //
  55. #define FIXED_SIZE_OF_SESSION(level) \
  56. ( (level) == 0 ? sizeof(SESSION_INFO_0) : \
  57. (level) == 1 ? sizeof(SESSION_INFO_1) : \
  58. (level) == 2 ? sizeof(SESSION_INFO_2) : \
  59. (level) == 10 ? sizeof(SESSION_INFO_10) : \
  60. sizeof(SESSION_INFO_502) )
  61. NTSTATUS
  62. SrvNetSessionDel (
  63. IN PSERVER_REQUEST_PACKET Srp,
  64. IN PVOID Buffer,
  65. IN ULONG BufferLength
  66. )
  67. /*++
  68. Routine Description:
  69. This routine processes the NetSessionEnum API in the server FSP.
  70. It must run in the FSP because in order to close the session it must
  71. use the endpoint handle to force the TDI connection closed.
  72. Either the client name or user name must be specified, and it is
  73. legal to specify both. If only the computer name is specified, then
  74. the VC gets closed. If only the user name is specified, then all
  75. that users sessions are closed. If both are specified, then the
  76. particular user session is closed.
  77. Arguments:
  78. Srp - a pointer to the server request packet that contains all
  79. the information necessary to satisfy the request. This includes:
  80. INPUT:
  81. Name1 - name of the client computer whose session we should
  82. delete.
  83. Name2 - name of the user whose session we should delete.
  84. OUTPUT:
  85. None.
  86. Buffer - unused.
  87. BufferLength - unused.
  88. Return Value:
  89. NTSTATUS - result of operation to return to the server service.
  90. --*/
  91. {
  92. BOOLEAN foundSession = FALSE;
  93. PSESSION session;
  94. PAGED_CODE( );
  95. Buffer, BufferLength;
  96. //
  97. // Walk the ordered list, finding matching entries.
  98. //
  99. session = SrvFindEntryInOrderedList(
  100. &SrvSessionList,
  101. (PFILTER_ROUTINE)FilterSessions,
  102. Srp,
  103. (ULONG)-1,
  104. FALSE,
  105. NULL );
  106. while ( session != NULL ) {
  107. foundSession = TRUE;
  108. //
  109. // If a computer name was specified but not a user name, then
  110. // we're supposed to blow away the VC. Close the connection.
  111. //
  112. if ( Srp->Name1.Buffer != NULL && Srp->Name2.Buffer == NULL ) {
  113. #if SRVDBG29
  114. UpdateConnectionHistory( "SDL1", session->Connection->Endpoint, session->Connection );
  115. #endif
  116. session->Connection->DisconnectReason = DisconnectSessionDeleted;
  117. SrvCloseConnection( session->Connection, FALSE );
  118. } else {
  119. //
  120. // We want to close a user on the connection. Close that
  121. // session, then if there are no longer any sessions on the
  122. // connection, close the connection.
  123. //
  124. // Increment the count of sessions that have been logged off
  125. // normally.
  126. //
  127. SrvStatistics.SessionsLoggedOff++;
  128. SrvCloseSession( session );
  129. if ( session->Connection->CurrentNumberOfSessions == 0 ) {
  130. #if SRVDBG29
  131. UpdateConnectionHistory( "SDL2", session->Connection->Endpoint, session->Connection );
  132. #endif
  133. session->Connection->DisconnectReason = DisconnectSessionDeleted;
  134. SrvCloseConnection( session->Connection, FALSE );
  135. }
  136. }
  137. //
  138. // Find the next session that matches. This will dereference the
  139. // current session.
  140. //
  141. do {
  142. session =
  143. SrvFindNextEntryInOrderedList( &SrvSessionList, session );
  144. } while ( (session != NULL) && !FilterSessions( Srp, session ) );
  145. }
  146. if ( foundSession ) {
  147. return STATUS_SUCCESS;
  148. }
  149. Srp->ErrorCode = NERR_ClientNameNotFound;
  150. return STATUS_SUCCESS;
  151. } // SrvNetSessionDel
  152. NTSTATUS
  153. SrvNetSessionEnum (
  154. IN PSERVER_REQUEST_PACKET Srp,
  155. IN PVOID Buffer,
  156. IN ULONG BufferLength
  157. )
  158. /*++
  159. Routine Description:
  160. This routine processes the NetSessionEnum API in the server.
  161. Arguments:
  162. Srp - a pointer to the server request packet that contains all
  163. the information necessary to satisfy the request. This includes:
  164. INPUT:
  165. Level - level of information to return, 0, 1, or 2.
  166. Name1 - a client machine name to filter on, if any.
  167. Name2 - a user name to filter on, if any.
  168. OUTPUT:
  169. Parameters.Get.EntriesRead - the number of entries that fit in
  170. the output buffer.
  171. Parameters.Get.TotalEntries - the total number of entries that
  172. would be returned with a large enough buffer.
  173. Parameters.Get.TotalBytesNeeded - the buffer size that would be
  174. required to hold all the entries.
  175. Buffer - a pointer to the buffer for results.
  176. BufferLength - the length of this buffer.
  177. Return Value:
  178. NTSTATUS - result of operation to return to the server service.
  179. --*/
  180. {
  181. LARGE_INTEGER currentTime;
  182. PAGED_CODE( );
  183. //
  184. // See if we need to update the session last use time
  185. //
  186. KeQuerySystemTime( &currentTime );
  187. UpdateSessionLastUseTime( &currentTime );
  188. return SrvEnumApiHandler(
  189. Srp,
  190. Buffer,
  191. BufferLength,
  192. &SrvSessionList,
  193. FilterSessions,
  194. SizeSessions,
  195. FillSessionInfoBuffer
  196. );
  197. } // SrvNetSessionEnum
  198. VOID
  199. FillSessionInfoBuffer (
  200. IN PSERVER_REQUEST_PACKET Srp,
  201. IN PVOID Block,
  202. IN OUT PVOID *FixedStructure,
  203. IN LPWSTR *EndOfVariableData
  204. )
  205. /*++
  206. Routine Description:
  207. This routine puts a single fixed file structure and associated
  208. variable data, into a buffer. Fixed data goes at the beginning of
  209. the buffer, variable data at the end.
  210. *** This routine assumes that ALL the data, both fixed and variable,
  211. will fit.
  212. Arguments:
  213. Srp - a pointer to the SRP for the operation. Only the Level
  214. field is used.
  215. Block - the Session from which to get information.
  216. FixedStructure - where the in the buffer to place the fixed structure.
  217. This pointer is updated to point to the next available
  218. position for a fixed structure.
  219. EndOfVariableData - the last position on the buffer that variable
  220. data for this structure can occupy. The actual variable data
  221. is written before this position as long as it won't overwrite
  222. fixed structures. It is would overwrite fixed structures, it
  223. is not written.
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. PSESSION_INFO_502 sesi502 = *FixedStructure;
  229. PSESSION_INFO_2 sesi2 = *FixedStructure;
  230. PSESSION_INFO_10 sesi10 = *FixedStructure;
  231. PSESSION session = Block;
  232. UNICODE_STRING machineNameString;
  233. UNICODE_STRING userName;
  234. PPAGED_CONNECTION pagedConnection;
  235. LARGE_INTEGER currentTime;
  236. ULONG currentSecondsSince1980;
  237. ULONG startTimeInSecondsSince1980;
  238. ULONG secondsAlive;
  239. ULONG lastUseTimeInSecondsSince1980;
  240. ULONG secondsIdle;
  241. PAGED_CODE();
  242. //
  243. // Get the current time and use this to determine how long the
  244. // connection has been alive and how long it has been idle.
  245. //
  246. KeQuerySystemTime( &currentTime );
  247. RtlTimeToSecondsSince1980(
  248. &currentTime,
  249. &currentSecondsSince1980
  250. );
  251. RtlTimeToSecondsSince1980(
  252. &session->StartTime,
  253. &startTimeInSecondsSince1980
  254. );
  255. RtlTimeToSecondsSince1980(
  256. &session->LastUseTime,
  257. &lastUseTimeInSecondsSince1980
  258. );
  259. secondsAlive = currentSecondsSince1980 - startTimeInSecondsSince1980;
  260. secondsIdle = currentSecondsSince1980 - lastUseTimeInSecondsSince1980;
  261. //
  262. // Update FixedStructure to point to the next structure location.
  263. //
  264. *FixedStructure = (PCHAR)*FixedStructure +
  265. FIXED_SIZE_OF_SESSION( Srp->Level );
  266. ASSERT( (ULONG_PTR)*EndOfVariableData >= (ULONG_PTR)*FixedStructure );
  267. //
  268. // We'll return a machine name that does not contain the leading
  269. // backslashes.
  270. //
  271. pagedConnection = session->Connection->PagedConnection;
  272. machineNameString.Buffer = session->Connection->ClientMachineName;
  273. machineNameString.Length =
  274. (USHORT)( session->Connection->ClientMachineNameString.Length -
  275. (sizeof(WCHAR) * 2) );
  276. //
  277. // Case on the level to fill in the fixed structure appropriately.
  278. // We fill in actual pointers in the output structure. This is
  279. // possible because we are in the server FSD, hence the server
  280. // service's process and address space.
  281. //
  282. // *** Using the switch statement in this fashion relies on the fact
  283. // that the first fields on the different session structures are
  284. // identical (with the exception of level 10, which is handled
  285. // separately).
  286. //
  287. switch( Srp->Level ) {
  288. case 502:
  289. //
  290. // Copy the transport string to the output buffer.
  291. //
  292. SrvCopyUnicodeStringToBuffer(
  293. &session->Connection->Endpoint->TransportName,
  294. *FixedStructure,
  295. EndOfVariableData,
  296. &sesi502->sesi502_transport
  297. );
  298. // *** lack of break is intentional!
  299. case 2:
  300. //
  301. // Copy the client type string to the output buffer.
  302. //
  303. SrvCopyUnicodeStringToBuffer(
  304. session->Connection->ClientOSType.Buffer != NULL ?
  305. &session->Connection->ClientOSType :
  306. &SrvClientTypes[session->Connection->SmbDialect],
  307. *FixedStructure,
  308. EndOfVariableData,
  309. &sesi2->sesi2_cltype_name
  310. );
  311. // *** lack of break is intentional!
  312. case 1:
  313. //
  314. // Copy the user name to the output buffer.
  315. //
  316. SrvGetUserAndDomainName( session, &userName, NULL );
  317. SrvCopyUnicodeStringToBuffer(
  318. &userName,
  319. *FixedStructure,
  320. EndOfVariableData,
  321. &sesi2->sesi2_username
  322. );
  323. if( userName.Buffer ) {
  324. SrvReleaseUserAndDomainName( session, &userName, NULL );
  325. }
  326. //
  327. // Set up other fields.
  328. //
  329. //
  330. // Return the number of files open over this session, taking care
  331. // not to count those in the RFCB cache (since the RFCB cache should
  332. // be transparent to users and administrators.
  333. //
  334. sesi2->sesi2_num_opens = session->CurrentFileOpenCount;
  335. if( sesi2->sesi2_num_opens > 0 ) {
  336. ULONG count = SrvCountCachedRfcbsForUid( session->Connection, session->Uid );
  337. if( sesi2->sesi2_num_opens > count ) {
  338. sesi2->sesi2_num_opens -= count;
  339. } else {
  340. sesi2->sesi2_num_opens = 0;
  341. }
  342. }
  343. sesi2->sesi2_time = secondsAlive;
  344. sesi2->sesi2_idle_time = secondsIdle;
  345. //
  346. // Set up the user flags.
  347. //
  348. sesi2->sesi2_user_flags = 0;
  349. if ( session->GuestLogon ) {
  350. sesi2->sesi2_user_flags |= SESS_GUEST;
  351. }
  352. if ( !session->EncryptedLogon ) {
  353. sesi2->sesi2_user_flags |= SESS_NOENCRYPTION;
  354. }
  355. // *** lack of break is intentional!
  356. case 0:
  357. //
  358. // Set up the client machine name in the output buffer.
  359. //
  360. SrvCopyUnicodeStringToBuffer(
  361. &machineNameString,
  362. *FixedStructure,
  363. EndOfVariableData,
  364. &sesi2->sesi2_cname
  365. );
  366. break;
  367. case 10:
  368. //
  369. // Set up the client machine name and user name in the output
  370. // buffer.
  371. //
  372. SrvCopyUnicodeStringToBuffer(
  373. &machineNameString,
  374. *FixedStructure,
  375. EndOfVariableData,
  376. &sesi10->sesi10_cname
  377. );
  378. SrvGetUserAndDomainName( session, &userName, NULL );
  379. SrvCopyUnicodeStringToBuffer(
  380. &userName,
  381. *FixedStructure,
  382. EndOfVariableData,
  383. &sesi10->sesi10_username
  384. );
  385. if( userName.Buffer ) {
  386. SrvReleaseUserAndDomainName( session, &userName, NULL );
  387. }
  388. //
  389. // Set up other fields.
  390. //
  391. sesi10->sesi10_time = secondsAlive;
  392. sesi10->sesi10_idle_time = secondsIdle;
  393. break;
  394. default:
  395. //
  396. // This should never happen. The server service should have
  397. // checked for an invalid level.
  398. //
  399. INTERNAL_ERROR(
  400. ERROR_LEVEL_UNEXPECTED,
  401. "FillSessionInfoBuffer: invalid level number: %ld",
  402. Srp->Level,
  403. NULL
  404. );
  405. SrvLogInvalidSmb( NULL );
  406. }
  407. return;
  408. } // FillSessionInfoBuffer
  409. BOOLEAN
  410. FilterSessions (
  411. IN PSERVER_REQUEST_PACKET Srp,
  412. IN PVOID Block
  413. )
  414. /*++
  415. Routine Description:
  416. This routine is intended to be called by SrvEnumApiHandler to check
  417. whether a particular session should be returned.
  418. Arguments:
  419. Srp - a pointer to the SRP for the operation. Name1 is the client
  420. name, Name2 is the user name.
  421. Block - a pointer to the session to check.
  422. Return Value:
  423. TRUE if the block should be placed in the output buffer, FALSE
  424. if it should be passed over.
  425. --*/
  426. {
  427. PSESSION session = Block;
  428. UNICODE_STRING userName;
  429. PAGED_CODE( );
  430. //
  431. // If there was a client name passed in the NetSessionEnum API,
  432. // check whether it matches the client name on the connection
  433. // corresponding to the session.
  434. //
  435. if ( Srp->Name1.Length > 0 ) {
  436. if ( !RtlEqualUnicodeString(
  437. &Srp->Name1,
  438. &session->Connection->ClientMachineNameString,
  439. TRUE ) ) {
  440. return FALSE;
  441. }
  442. }
  443. //
  444. // If there was a user name passed in the NetSessionEnum API,
  445. // check whether it matches the user name on the session.
  446. //
  447. if ( Srp->Name2.Length > 0 ) {
  448. SrvGetUserAndDomainName( session, &userName, NULL );
  449. if( userName.Buffer == NULL ) {
  450. return FALSE;
  451. }
  452. if ( !RtlEqualUnicodeString(
  453. &Srp->Name2,
  454. &userName,
  455. TRUE ) ) {
  456. SrvReleaseUserAndDomainName( session, &userName, NULL );
  457. return FALSE;
  458. }
  459. SrvReleaseUserAndDomainName( session, &userName, NULL );
  460. }
  461. //
  462. // The session passed both tests. Put it in the output buffer.
  463. //
  464. return TRUE;
  465. } // FilterSessions
  466. ULONG
  467. SizeSessions (
  468. IN PSERVER_REQUEST_PACKET Srp,
  469. IN PVOID Block
  470. )
  471. /*++
  472. Routine Description:
  473. This routine returns the size the passed-in session would take up
  474. in an API output buffer.
  475. Arguments:
  476. Srp - a pointer to the SRP for the operation. Only the level
  477. parameter is used.
  478. Block - a pointer to the session to size.
  479. Return Value:
  480. ULONG - The number of bytes the session would take up in the output
  481. buffer.
  482. --*/
  483. {
  484. PSESSION session = Block;
  485. PCONNECTION connection = session->Connection;
  486. ULONG size;
  487. UNICODE_STRING userName;
  488. PAGED_CODE( );
  489. size = SrvLengthOfStringInApiBuffer(
  490. &connection->ClientMachineNameString
  491. );
  492. if ( Srp->Level > 0 ) {
  493. SrvGetUserAndDomainName( session, &userName, NULL );
  494. if( userName.Buffer != NULL ) {
  495. size += SrvLengthOfStringInApiBuffer(&userName);
  496. SrvReleaseUserAndDomainName( session, &userName, NULL );
  497. }
  498. }
  499. switch ( Srp->Level ) {
  500. case 0:
  501. size += sizeof(SESSION_INFO_0);
  502. break;
  503. case 1:
  504. size += sizeof(SESSION_INFO_1);
  505. break;
  506. case 2:
  507. size += sizeof( SESSION_INFO_2 );
  508. if( connection->ClientOSType.Buffer != NULL ) {
  509. size += SrvLengthOfStringInApiBuffer( &connection->ClientOSType );
  510. } else {
  511. size += SrvLengthOfStringInApiBuffer( &SrvClientTypes[ connection->SmbDialect ] );
  512. }
  513. break;
  514. case 10:
  515. size += sizeof(SESSION_INFO_10);
  516. break;
  517. case 502:
  518. size += sizeof(SESSION_INFO_502) +
  519. SrvLengthOfStringInApiBuffer(
  520. &connection->Endpoint->TransportName
  521. );
  522. if( connection->ClientOSType.Buffer != NULL ) {
  523. size += SrvLengthOfStringInApiBuffer( &connection->ClientOSType );
  524. } else {
  525. size += SrvLengthOfStringInApiBuffer( &SrvClientTypes[ connection->SmbDialect ] );
  526. }
  527. break;
  528. }
  529. return size;
  530. } // SizeSessions