Source code of Windows XP (NT5)
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.

1825 lines
44 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. rmlogon.c
  5. Abstract:
  6. This module implements the kernel mode logon tracking performed by the
  7. reference monitor. Logon tracking is performed by keeping a count of
  8. how many tokens exist for each active logon in a system. When a logon
  9. session's reference count drops to zero, the LSA is notified so that
  10. authentication packages can clean up any related context data.
  11. Author:
  12. Jim Kelly (JimK) 21-April-1991
  13. Environment:
  14. Kernel mode only.
  15. Revision History:
  16. --*/
  17. //#define SEP_TRACK_LOGON_SESSION_REFS
  18. #include "pch.h"
  19. #pragma hdrstop
  20. #include "rmp.h"
  21. #include <bugcodes.h>
  22. #include <stdio.h>
  23. #include <zwapi.h>
  24. #ifdef ALLOC_DATA_PRAGMA
  25. #pragma data_seg("PAGEDATA")
  26. #endif
  27. SEP_LOGON_SESSION_TERMINATED_NOTIFICATION
  28. SeFileSystemNotifyRoutinesHead = {0};
  29. ////////////////////////////////////////////////////////////////////////////
  30. // //
  31. // Internally defined data types //
  32. // //
  33. ////////////////////////////////////////////////////////////////////////////
  34. typedef struct _SEP_FILE_SYSTEM_NOTIFY_CONTEXT {
  35. WORK_QUEUE_ITEM WorkItem;
  36. LUID LogonId;
  37. } SEP_FILE_SYSTEM_NOTIFY_CONTEXT, *PSEP_FILE_SYSTEM_NOTIFY_CONTEXT;
  38. ////////////////////////////////////////////////////////////////////////////
  39. // //
  40. // Internally defined routines //
  41. // //
  42. ////////////////////////////////////////////////////////////////////////////
  43. VOID
  44. SepInformLsaOfDeletedLogon(
  45. IN PLUID LogonId
  46. );
  47. VOID
  48. SepInformFileSystemsOfDeletedLogon(
  49. IN PLUID LogonId
  50. );
  51. VOID
  52. SepNotifyFileSystems(
  53. IN PVOID Context
  54. );
  55. NTSTATUS
  56. SepCleanupLUIDDeviceMapDirectory(
  57. PLUID pLogonId
  58. );
  59. NTSTATUS
  60. SeGetLogonIdDeviceMap(
  61. IN PLUID pLogonId,
  62. OUT PDEVICE_MAP* ppDevMap
  63. );
  64. //
  65. // declared in ntos\ob\obp.h
  66. // defined in ntos\ob\obdir.c
  67. // Used to dereference the LUID device map
  68. //
  69. VOID
  70. FASTCALL
  71. ObfDereferenceDeviceMap(
  72. IN PDEVICE_MAP DeviceMap
  73. );
  74. #ifdef ALLOC_PRAGMA
  75. #pragma alloc_text(PAGE,SepRmCreateLogonSessionWrkr)
  76. #pragma alloc_text(PAGE,SepRmDeleteLogonSessionWrkr)
  77. #pragma alloc_text(PAGE,SepReferenceLogonSession)
  78. #pragma alloc_text(PAGE,SepCleanupLUIDDeviceMapDirectory)
  79. #pragma alloc_text(PAGE,SepDeReferenceLogonSession)
  80. #pragma alloc_text(PAGE,SepCreateLogonSessionTrack)
  81. #pragma alloc_text(PAGE,SepDeleteLogonSessionTrack)
  82. #pragma alloc_text(PAGE,SepInformLsaOfDeletedLogon)
  83. #pragma alloc_text(PAGE,SeRegisterLogonSessionTerminatedRoutine)
  84. #pragma alloc_text(PAGE,SeUnregisterLogonSessionTerminatedRoutine)
  85. #pragma alloc_text(PAGE,SeMarkLogonSessionForTerminationNotification)
  86. #pragma alloc_text(PAGE,SepInformFileSystemsOfDeletedLogon)
  87. #pragma alloc_text(PAGE,SepNotifyFileSystems)
  88. #pragma alloc_text(PAGE,SeGetLogonIdDeviceMap)
  89. #if DBG || TOKEN_LEAK_MONITOR
  90. #pragma alloc_text(PAGE,SepAddTokenLogonSession)
  91. #pragma alloc_text(PAGE,SepRemoveTokenLogonSession)
  92. #endif
  93. #endif
  94. ////////////////////////////////////////////////////////////////////////////
  95. // //
  96. // Local macros //
  97. // //
  98. ////////////////////////////////////////////////////////////////////////////
  99. //
  100. // This macro is used to obtain an index into the logon session tracking
  101. // array given a logon session ID (a LUID).
  102. //
  103. #define SepLogonSessionIndex( PLogonId ) ( \
  104. (PLogonId)->LowPart & SEP_LOGON_TRACK_INDEX_MASK \
  105. )
  106. ////////////////////////////////////////////////////////////////////////////
  107. // //
  108. // Exported Services //
  109. // //
  110. ////////////////////////////////////////////////////////////////////////////
  111. VOID
  112. SepRmCreateLogonSessionWrkr(
  113. IN PRM_COMMAND_MESSAGE CommandMessage,
  114. OUT PRM_REPLY_MESSAGE ReplyMessage
  115. )
  116. /*++
  117. Routine Description:
  118. This function is the dispatch routine for the LSA --> RM
  119. "CreateLogonSession" call.
  120. The arguments passed to this routine are defined by the
  121. type SEP_RM_COMMAND_WORKER.
  122. Arguments:
  123. CommandMessage - Points to structure containing RM command message
  124. information consisting of an LPC PORT_MESSAGE structure followed
  125. by the command number (RmComponentTestCommand) and a command-specific
  126. body. The command-specific body of this parameter is a LUID of the
  127. logon session to be created.
  128. ReplyMessage - Pointer to structure containing LSA reply message
  129. information consisting of an LPC PORT_MESSAGE structure followed
  130. by the command ReturnedStatus field in which a status code from the
  131. command will be returned.
  132. Return Value:
  133. VOID
  134. --*/
  135. {
  136. NTSTATUS Status;
  137. LUID LogonId;
  138. PAGED_CODE();
  139. //
  140. // Check that command is expected type
  141. //
  142. ASSERT( CommandMessage->CommandNumber == RmCreateLogonSession );
  143. //
  144. // Typecast the command parameter to what we expect.
  145. //
  146. LogonId = *((LUID UNALIGNED *) CommandMessage->CommandParams);
  147. //
  148. // Try to create the logon session tracking record
  149. //
  150. Status = SepCreateLogonSessionTrack( &LogonId );
  151. //
  152. // Set the reply status
  153. //
  154. ReplyMessage->ReturnedStatus = Status;
  155. return;
  156. }
  157. VOID
  158. SepRmDeleteLogonSessionWrkr(
  159. IN PRM_COMMAND_MESSAGE CommandMessage,
  160. OUT PRM_REPLY_MESSAGE ReplyMessage
  161. )
  162. /*++
  163. Routine Description:
  164. This function is the dispatch routine for the LSA --> RM
  165. "DeleteLogonSession" call.
  166. The arguments passed to this routine are defined by the
  167. type SEP_RM_COMMAND_WORKER.
  168. Arguments:
  169. CommandMessage - Points to structure containing RM command message
  170. information consisting of an LPC PORT_MESSAGE structure followed
  171. by the command number (RmComponentTestCommand) and a command-specific
  172. body. The command-specific body of this parameter is a LUID of the
  173. logon session to be created.
  174. ReplyMessage - Pointer to structure containing LSA reply message
  175. information consisting of an LPC PORT_MESSAGE structure followed
  176. by the command ReturnedStatus field in which a status code from the
  177. command will be returned.
  178. Return Value:
  179. VOID
  180. --*/
  181. {
  182. NTSTATUS Status;
  183. LUID LogonId;
  184. PAGED_CODE();
  185. //
  186. // Check that command is expected type
  187. //
  188. ASSERT( CommandMessage->CommandNumber == RmDeleteLogonSession );
  189. //
  190. // Typecast the command parameter to what we expect.
  191. //
  192. LogonId = *((LUID UNALIGNED *) CommandMessage->CommandParams);
  193. //
  194. // Try to create the logon session tracking record
  195. //
  196. Status = SepDeleteLogonSessionTrack( &LogonId );
  197. //
  198. // Set the reply status
  199. //
  200. ReplyMessage->ReturnedStatus = Status;
  201. return;
  202. }
  203. NTSTATUS
  204. SepReferenceLogonSession(
  205. IN PLUID LogonId
  206. )
  207. /*++
  208. Routine Description:
  209. This routine increments the reference count of a logon session
  210. tracking record.
  211. Arguments:
  212. LogonId - Pointer to the logon session ID whose logon track is
  213. to be incremented.
  214. Return Value:
  215. STATUS_SUCCESS - The reference count was successfully incremented.
  216. STATUS_NO_SUCH_LOGON_SESSION - The specified logon session doesn't
  217. exist in the reference monitor's database.
  218. --*/
  219. {
  220. ULONG SessionArrayIndex;
  221. PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
  222. #ifdef SEP_TRACK_LOGON_SESSION_REFS
  223. ULONG Refs;
  224. #endif //SEP_TRACK_LOGON_SESSION_REFS
  225. PAGED_CODE();
  226. SessionArrayIndex = SepLogonSessionIndex( LogonId );
  227. Previous = &SepLogonSessions[ SessionArrayIndex ];
  228. //
  229. // Protect modification of reference monitor database
  230. //
  231. SepRmAcquireDbWriteLock();
  232. //
  233. // Now walk the list for our logon session array hash index.
  234. //
  235. Current = *Previous;
  236. while (Current != NULL) {
  237. //
  238. // If we found it, increment the reference count and return
  239. //
  240. if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
  241. #ifdef SEP_TRACK_LOGON_SESSION_REFS
  242. ULONG Refs;
  243. #endif //SEP_TRACK_LOGON_SESSION_REFS
  244. Current->ReferenceCount += 1;
  245. #ifdef SEP_TRACK_LOGON_SESSION_REFS
  246. Refs = Current->ReferenceCount;
  247. #endif //SEP_TRACK_LOGON_SESSION_REFS
  248. SepRmReleaseDbWriteLock();
  249. #ifdef SEP_TRACK_LOGON_SESSION_REFS
  250. DbgPrint("SE (rm): ++ logon session: (%d, %d) to %d by (%d, %d)\n",
  251. LogonId->HighPart, LogonId->LowPart, Refs,
  252. PsGetCurrentThread()->Cid.UniqueProcess,
  253. PsGetCurrentThread()->Cid.UniqueThread);
  254. #endif //SEP_TRACK_LOGON_SESSION_REFS
  255. return STATUS_SUCCESS;
  256. }
  257. Current = Current->Next;
  258. }
  259. SepRmReleaseDbWriteLock();
  260. //
  261. // Bad news, someone asked us to increment the reference count of
  262. // a logon session we didn't know existed. This might be a new
  263. // token being created, so return an error status and let the caller
  264. // decide if it warrants a bug check or not.
  265. //
  266. return STATUS_NO_SUCH_LOGON_SESSION;
  267. }
  268. NTSTATUS
  269. SepCleanupLUIDDeviceMapDirectory(
  270. PLUID pLogonId
  271. )
  272. /*++
  273. Routine Description:
  274. Make the contents of the (LUID's device map)'s directory object
  275. temporary so that their names go away.
  276. Arguments:
  277. pLogonId - Pointer to the logon session ID whose device is to be
  278. cleaned up
  279. Return Value:
  280. STATUS_SUCCESS - cleaned up the entire device map
  281. STATUS_INVALID_PARAMETER - pLogonId is a NULL pointer
  282. STATUS_NO_MEMORY - could not allocate memory to hold the handle
  283. buffer
  284. appropriate NTSTATUS code
  285. --*/
  286. {
  287. NTSTATUS Status;
  288. OBJECT_ATTRIBUTES Attributes;
  289. UNICODE_STRING UnicodeString;
  290. HANDLE LinkHandle;
  291. POBJECT_DIRECTORY_INFORMATION DirInfo = NULL;
  292. BOOLEAN RestartScan;
  293. WCHAR szString[64]; // \Sessions\0\DosDevices\x-x = 10+1+12+(8)+1+(8)+1 = 41
  294. ULONG Context = 0;
  295. ULONG ReturnedLength;
  296. HANDLE DosDevicesDirectory;
  297. HANDLE *HandleArray;
  298. ULONG Size = 100;
  299. ULONG i, Count = 0;
  300. ULONG dirInfoLength = 0;
  301. PAGED_CODE();
  302. if (pLogonId == NULL) {
  303. return( STATUS_INVALID_PARAMETER );
  304. }
  305. //
  306. // Open a handle to the directory object for the LUID device map
  307. // Get a kernel handle
  308. //
  309. _snwprintf( szString,
  310. sizeof(szString)/sizeof(WCHAR),
  311. L"\\Sessions\\0\\DosDevices\\%08x-%08x",
  312. pLogonId->HighPart,
  313. pLogonId->LowPart );
  314. RtlInitUnicodeString(&UnicodeString, szString);
  315. InitializeObjectAttributes(&Attributes,
  316. &UnicodeString,
  317. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  318. NULL,
  319. NULL);
  320. Status = ZwOpenDirectoryObject(&DosDevicesDirectory,
  321. DIRECTORY_QUERY,
  322. &Attributes);
  323. if (!NT_SUCCESS(Status)) {
  324. return Status;
  325. }
  326. Restart:
  327. //
  328. // Create an array of handles to close with each scan
  329. // of the directory
  330. //
  331. HandleArray = (HANDLE *)ExAllocatePoolWithTag(
  332. PagedPool,
  333. (Size * sizeof(HANDLE)),
  334. 'aHeS'
  335. );
  336. if (HandleArray == NULL) {
  337. ZwClose(DosDevicesDirectory);
  338. if (DirInfo != NULL) {
  339. ExFreePool(DirInfo);
  340. }
  341. return STATUS_NO_MEMORY;
  342. }
  343. RestartScan = TRUE;
  344. while (TRUE) {
  345. do {
  346. //
  347. // ZwQueryDirectoryObject returns one element at a time
  348. //
  349. Status = ZwQueryDirectoryObject( DosDevicesDirectory,
  350. (PVOID)DirInfo,
  351. dirInfoLength,
  352. TRUE,
  353. RestartScan,
  354. &Context,
  355. &ReturnedLength );
  356. if (Status == STATUS_BUFFER_TOO_SMALL) {
  357. dirInfoLength = ReturnedLength;
  358. if (DirInfo != NULL) {
  359. ExFreePool(DirInfo);
  360. }
  361. DirInfo = ExAllocatePoolWithTag( PagedPool, dirInfoLength, 'bDeS' );
  362. if (DirInfo == NULL) {
  363. Status = STATUS_INSUFFICIENT_RESOURCES;
  364. }
  365. }
  366. }while (Status == STATUS_BUFFER_TOO_SMALL);
  367. //
  368. // Check the status of the operation.
  369. //
  370. if (!NT_SUCCESS(Status)) {
  371. if (Status == STATUS_NO_MORE_ENTRIES) {
  372. Status = STATUS_SUCCESS;
  373. }
  374. break;
  375. }
  376. //
  377. // Check that the element is a symbolic link
  378. //
  379. if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink")) {
  380. //
  381. // check if the handle array is full
  382. //
  383. if ( Count >= Size ) {
  384. //
  385. // empty the handle array by closing all the handles
  386. // and free the handle array so that we can create
  387. // a bigger handle array
  388. // Need to restart the directory scan
  389. //
  390. for (i = 0; i < Count ; i++) {
  391. ZwClose (HandleArray[i]);
  392. }
  393. Size += 20;
  394. Count = 0;
  395. ExFreePool((PVOID)HandleArray);
  396. HandleArray = NULL;
  397. goto Restart;
  398. }
  399. InitializeObjectAttributes( &Attributes,
  400. &DirInfo->Name,
  401. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  402. DosDevicesDirectory,
  403. NULL);
  404. Status = ZwOpenSymbolicLinkObject( &LinkHandle,
  405. SYMBOLIC_LINK_ALL_ACCESS,
  406. &Attributes);
  407. if (NT_SUCCESS(Status)) {
  408. //
  409. // Make the object temporary so that its name goes away from
  410. // the Object Manager's namespace
  411. //
  412. Status = ZwMakeTemporaryObject( LinkHandle );
  413. if (NT_SUCCESS( Status )) {
  414. HandleArray[Count] = LinkHandle;
  415. Count++;
  416. }
  417. else {
  418. ZwClose( LinkHandle );
  419. }
  420. }
  421. }
  422. RestartScan = FALSE;
  423. }
  424. //
  425. // Close all the handles
  426. //
  427. for (i = 0; i < Count ; i++) {
  428. ZwClose (HandleArray[i]);
  429. }
  430. if (HandleArray != NULL) {
  431. ExFreePool((PVOID)HandleArray);
  432. }
  433. if (DirInfo != NULL) {
  434. ExFreePool(DirInfo);
  435. }
  436. if (DosDevicesDirectory != NULL) {
  437. ZwClose(DosDevicesDirectory);
  438. }
  439. return Status;
  440. }
  441. VOID
  442. SepDeReferenceLogonSession(
  443. IN PLUID LogonId
  444. )
  445. /*++
  446. Routine Description:
  447. This routine decrements the reference count of a logon session
  448. tracking record.
  449. If the reference count is decremented to zero, then there is no
  450. possibility for any more tokens to exist for the logon session.
  451. In this case, the LSA is notified that a logon session has
  452. terminated.
  453. Arguments:
  454. LogonId - Pointer to the logon session ID whose logon track is
  455. to be decremented.
  456. Return Value:
  457. None.
  458. --*/
  459. {
  460. ULONG SessionArrayIndex;
  461. PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
  462. PDEVICE_MAP pDeviceMap = NULL;
  463. #ifdef SEP_TRACK_LOGON_SESSION_REFS
  464. ULONG Refs;
  465. #endif //SEP_TRACK_LOGON_SESSION_REFS
  466. PAGED_CODE();
  467. SessionArrayIndex = SepLogonSessionIndex( LogonId );
  468. Previous = &SepLogonSessions[ SessionArrayIndex ];
  469. //
  470. // Protect modification of reference monitor database
  471. //
  472. SepRmAcquireDbWriteLock();
  473. //
  474. // Now walk the list for our logon session array hash index.
  475. //
  476. Current = *Previous;
  477. while (Current != NULL) {
  478. //
  479. // If we found it, decrement the reference count and return
  480. //
  481. if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
  482. Current->ReferenceCount -= 1;
  483. if (Current->ReferenceCount == 0) {
  484. //
  485. // Pull it from the list
  486. //
  487. *Previous = Current->Next;
  488. //
  489. // No longer need to protect our pointer to this
  490. // record.
  491. //
  492. SepRmReleaseDbWriteLock();
  493. //
  494. // If the Device Map exist for this LUID,
  495. // dereference the pointer to the Device Map
  496. //
  497. if (Current->pDeviceMap != NULL) {
  498. //
  499. // Dereference our reference on the device map
  500. // our reference should be the last reference,
  501. // thus the system will delete the device map
  502. // for the LUID
  503. //
  504. pDeviceMap = Current->pDeviceMap;
  505. Current->pDeviceMap = NULL;
  506. }
  507. //
  508. // Make all the contents of the LUID's device map temporary,
  509. // so that the names go away from the Object Manager's
  510. // namespace
  511. // Remove our reference on the LUID's device map
  512. //
  513. if (pDeviceMap != NULL) {
  514. SepCleanupLUIDDeviceMapDirectory( LogonId );
  515. ObfDereferenceDeviceMap( pDeviceMap );
  516. }
  517. //
  518. // Asynchronoously inform file systems that this logon session
  519. // is going away, if atleast one FS expressed interest in this
  520. // logon session.
  521. //
  522. if (Current->Flags & SEP_TERMINATION_NOTIFY) {
  523. SepInformFileSystemsOfDeletedLogon( LogonId );
  524. }
  525. //
  526. // Deallocate the logon session track record.
  527. //
  528. ExFreePool( (PVOID)Current );
  529. #ifdef SEP_TRACK_LOGON_SESSION_REFS
  530. DbgPrint("SE (rm): -- ** logon session: (%d, %d) to ZERO by (%d, %d)\n",
  531. LogonId->HighPart, LogonId->LowPart,
  532. PsGetCurrentThread()->Cid.UniqueProcess,
  533. PsGetCurrentThread()->Cid.UniqueThread);
  534. #endif //SEP_TRACK_LOGON_SESSION_REFS
  535. //
  536. // Inform the LSA about the deletion of this logon session.
  537. //
  538. SepInformLsaOfDeletedLogon( LogonId );
  539. return;
  540. }
  541. //
  542. // reference count was incremented, but not to zero.
  543. //
  544. #ifdef SEP_TRACK_LOGON_SESSION_REFS
  545. Refs = Current->ReferenceCount;
  546. #endif //SEP_TRACK_LOGON_SESSION_REFS
  547. SepRmReleaseDbWriteLock();
  548. #ifdef SEP_TRACK_LOGON_SESSION_REFS
  549. DbgPrint("SE (rm): -- logon session: (%d, %d) to %d by (%d, %d)\n",
  550. LogonId->HighPart, LogonId->LowPart, Refs,
  551. PsGetCurrentThread()->Cid.UniqueProcess,
  552. PsGetCurrentThread()->Cid.UniqueThread);
  553. #endif //SEP_TRACK_LOGON_SESSION_REFS
  554. return;
  555. }
  556. Previous = &Current->Next;
  557. Current = *Previous;
  558. }
  559. SepRmReleaseDbWriteLock();
  560. //
  561. // Bad news, someone asked us to decrement the reference count of
  562. // a logon session we didn't know existed.
  563. //
  564. KeBugCheckEx( DEREF_UNKNOWN_LOGON_SESSION, 0, 0, 0, 0 );
  565. return;
  566. }
  567. NTSTATUS
  568. SepCreateLogonSessionTrack(
  569. IN PLUID LogonId
  570. )
  571. /*++
  572. Routine Description:
  573. This routine creates a new logon session tracking record.
  574. This should only be called as a dispatch routine for a LSA->RM
  575. call (and once during system initialization).
  576. If the specified logon session already exists, then an error is returned.
  577. Arguments:
  578. LogonId - Pointer to the logon session ID for which a new logon track is
  579. to be created.
  580. Return Value:
  581. STATUS_SUCCESS - The logon session track was created successfully.
  582. STATUS_LOGON_SESSION_EXISTS - The logon session already exists.
  583. A new one has not been created.
  584. --*/
  585. {
  586. ULONG SessionArrayIndex;
  587. PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
  588. PSEP_LOGON_SESSION_REFERENCES LogonSessionTrack;
  589. PAGED_CODE();
  590. //
  591. // Make sure we can allocate a new logon session track record
  592. //
  593. LogonSessionTrack = (PSEP_LOGON_SESSION_REFERENCES)
  594. ExAllocatePoolWithTag(
  595. PagedPool,
  596. sizeof(SEP_LOGON_SESSION_REFERENCES),
  597. 'sLeS'
  598. );
  599. if (LogonSessionTrack == NULL) {
  600. return STATUS_INSUFFICIENT_RESOURCES;
  601. }
  602. RtlZeroMemory(LogonSessionTrack, sizeof(SEP_LOGON_SESSION_REFERENCES));
  603. LogonSessionTrack->LogonId = (*LogonId);
  604. LogonSessionTrack->ReferenceCount = 0;
  605. LogonSessionTrack->pDeviceMap = NULL;
  606. #if DBG || TOKEN_LEAK_MONITOR
  607. InitializeListHead(&LogonSessionTrack->TokenList);
  608. #endif
  609. SessionArrayIndex = SepLogonSessionIndex( LogonId );
  610. Previous = &SepLogonSessions[ SessionArrayIndex ];
  611. //
  612. // Protect modification of reference monitor database
  613. //
  614. SepRmAcquireDbWriteLock();
  615. //
  616. // Now walk the list for our logon session array hash index
  617. // looking for a duplicate logon session ID.
  618. //
  619. Current = *Previous;
  620. while (Current != NULL) {
  621. if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
  622. //
  623. // One already exists. Hmmm.
  624. //
  625. SepRmReleaseDbWriteLock();
  626. ExFreePool(LogonSessionTrack);
  627. return STATUS_LOGON_SESSION_EXISTS;
  628. }
  629. Current = Current->Next;
  630. }
  631. //
  632. // Reached the end of the list without finding a duplicate.
  633. // Add the new one.
  634. //
  635. LogonSessionTrack->Next = *Previous;
  636. *Previous = LogonSessionTrack;
  637. SepRmReleaseDbWriteLock();
  638. return STATUS_SUCCESS;
  639. }
  640. NTSTATUS
  641. SepDeleteLogonSessionTrack(
  642. IN PLUID LogonId
  643. )
  644. /*++
  645. Routine Description:
  646. This routine creates a new logon session tracking record.
  647. This should only be called as a dispatch routine for a LSA->RM
  648. call (and once during system initialization).
  649. If the specified logon session already exists, then an error is returned.
  650. Arguments:
  651. LogonId - Pointer to the logon session ID whose logon track is
  652. to be deleted.
  653. Return Value:
  654. STATUS_SUCCESS - The logon session track was deleted successfully.
  655. STATUS_BAD_LOGON_SESSION_STATE - The logon session has a non-zero
  656. reference count and can not be deleted.
  657. STATUS_NO_SUCH_LOGON_SESSION - The specified logon session does not
  658. exist.
  659. --*/
  660. {
  661. ULONG SessionArrayIndex;
  662. PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
  663. PDEVICE_MAP pDeviceMap = NULL;
  664. PAGED_CODE();
  665. SessionArrayIndex = SepLogonSessionIndex( LogonId );
  666. Previous = &SepLogonSessions[ SessionArrayIndex ];
  667. //
  668. // Protect modification of reference monitor database
  669. //
  670. SepRmAcquireDbWriteLock();
  671. //
  672. // Now walk the list for our logon session array hash index.
  673. //
  674. Current = *Previous;
  675. while (Current != NULL) {
  676. //
  677. // If we found it, make sure reference count is zero
  678. //
  679. if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
  680. if (Current->ReferenceCount == 0) {
  681. //
  682. // Pull it from the list
  683. //
  684. *Previous = Current->Next;
  685. //
  686. // If the Device Map exist for this LUID,
  687. // dereference the pointer to the Device Map
  688. //
  689. if (Current->pDeviceMap != NULL) {
  690. //
  691. // Dereference our reference on the device map
  692. // our reference should be the last reference,
  693. // thus the system will delete the device map
  694. // for the LUID
  695. //
  696. pDeviceMap = Current->pDeviceMap;
  697. Current->pDeviceMap = NULL;
  698. }
  699. //
  700. // No longer need to protect our pointer to this
  701. // record.
  702. //
  703. SepRmReleaseDbWriteLock();
  704. //
  705. // Make all the contents of the LUID's device map temporary,
  706. // so that the names go away from the Object Manager's
  707. // namespace
  708. // Remove our reference on the LUID's device map
  709. //
  710. if (pDeviceMap != NULL) {
  711. SepCleanupLUIDDeviceMapDirectory( LogonId );
  712. ObfDereferenceDeviceMap( pDeviceMap );
  713. }
  714. //
  715. // Deallocate the logon session track record.
  716. //
  717. ExFreePool( (PVOID)Current );
  718. return STATUS_SUCCESS;
  719. }
  720. //
  721. // reference count was not zero. This is not considered
  722. // a healthy situation. Return an error and let someone
  723. // else declare the bug check.
  724. //
  725. SepRmReleaseDbWriteLock();
  726. return STATUS_BAD_LOGON_SESSION_STATE;
  727. }
  728. Previous = &Current->Next;
  729. Current = *Previous;
  730. }
  731. SepRmReleaseDbWriteLock();
  732. //
  733. // Someone asked us to delete a logon session that isn't
  734. // in the database.
  735. //
  736. return STATUS_NO_SUCH_LOGON_SESSION;
  737. }
  738. VOID
  739. SepInformLsaOfDeletedLogon(
  740. IN PLUID LogonId
  741. )
  742. /*++
  743. Routine Description:
  744. This routine informs the LSA about the deletion of a logon session.
  745. Note that we can not be guaranteed that we are in a whole (or wholesome)
  746. thread, since we may be in the middle of process deletion and object
  747. rundown. Therefore, we must queue the work off to a worker thread which
  748. can then make an LPC call to the LSA.
  749. Arguments:
  750. LogonId - Pointer to the logon session ID which has been deleted.
  751. Return Value:
  752. None.
  753. --*/
  754. {
  755. PSEP_LSA_WORK_ITEM DeleteLogonItem;
  756. PAGED_CODE();
  757. //
  758. // Pass the LUID value along with the work queue item.
  759. // Note that the worker thread is responsible for freeing the WorkItem data
  760. // structure.
  761. //
  762. DeleteLogonItem = ExAllocatePoolWithTag( PagedPool, sizeof(SEP_LSA_WORK_ITEM), 'wLeS' );
  763. if (DeleteLogonItem == NULL) {
  764. //
  765. // I don't know what to do here... we loose track of a logon session,
  766. // but the system isn't really harmed in any way.
  767. //
  768. return;
  769. }
  770. DeleteLogonItem->CommandParams.LogonId = (*LogonId);
  771. DeleteLogonItem->CommandNumber = LsapLogonSessionDeletedCommand;
  772. DeleteLogonItem->CommandParamsLength = sizeof( LUID );
  773. DeleteLogonItem->ReplyBuffer = NULL;
  774. DeleteLogonItem->ReplyBufferLength = 0;
  775. DeleteLogonItem->CleanupFunction = NULL;
  776. DeleteLogonItem->CleanupParameter = 0;
  777. DeleteLogonItem->Tag = SepDeleteLogon;
  778. DeleteLogonItem->CommandParamsMemoryType = SepRmImmediateMemory;
  779. if (!SepQueueWorkItem( DeleteLogonItem, TRUE )) {
  780. ExFreePool( DeleteLogonItem );
  781. }
  782. return;
  783. }
  784. NTSTATUS
  785. SeRegisterLogonSessionTerminatedRoutine(
  786. IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine
  787. )
  788. /*++
  789. Routine Description:
  790. This routine is called by file systems that are interested in being
  791. notified when a logon session is being deleted.
  792. Arguments:
  793. CallbackRoutine - Address of routine to call back when a logon session
  794. is being deleted.
  795. Return Value:
  796. STATUS_SUCCESS - Successfully registered routine
  797. STATUS_INVALID_PARAMETER - CallbackRoutine is NULL
  798. STATUS_INSUFFICIENT_RESOURCE - Unable to allocate list entry.
  799. --*/
  800. {
  801. PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION NewCallback;
  802. PAGED_CODE();
  803. if (CallbackRoutine == NULL) {
  804. return( STATUS_INVALID_PARAMETER );
  805. }
  806. NewCallback = ExAllocatePoolWithTag(
  807. PagedPool | POOL_COLD_ALLOCATION,
  808. sizeof(SEP_LOGON_SESSION_TERMINATED_NOTIFICATION),
  809. 'SFeS');
  810. if (NewCallback == NULL) {
  811. return( STATUS_INSUFFICIENT_RESOURCES );
  812. }
  813. SepRmAcquireDbWriteLock();
  814. NewCallback->Next = SeFileSystemNotifyRoutinesHead.Next;
  815. NewCallback->CallbackRoutine = CallbackRoutine;
  816. SeFileSystemNotifyRoutinesHead.Next = NewCallback;
  817. SepRmReleaseDbWriteLock();
  818. return( STATUS_SUCCESS );
  819. }
  820. NTSTATUS
  821. SeUnregisterLogonSessionTerminatedRoutine(
  822. IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine
  823. )
  824. /*++
  825. Routine Description:
  826. This is the dual of SeRegisterLogonSessionTerminatedRoutine. A File System
  827. *MUST* call this before it is unloaded.
  828. Arguments:
  829. CallbackRoutine - Address of routine that was originally passed in to
  830. SeRegisterLogonSessionTerminatedRoutine.
  831. Return Value:
  832. STATUS_SUCCESS - Successfully removed callback routine
  833. STATUS_INVALID_PARAMETER - CallbackRoutine is NULL
  834. STATUS_NOT_FOUND - Didn't find and entry for CallbackRoutine
  835. --*/
  836. {
  837. NTSTATUS Status;
  838. PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION PreviousEntry;
  839. PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION NotifyEntry;
  840. PAGED_CODE();
  841. if (CallbackRoutine == NULL) {
  842. return( STATUS_INVALID_PARAMETER );
  843. }
  844. SepRmAcquireDbWriteLock();
  845. for (PreviousEntry = &SeFileSystemNotifyRoutinesHead,
  846. NotifyEntry = SeFileSystemNotifyRoutinesHead.Next;
  847. NotifyEntry != NULL;
  848. PreviousEntry = NotifyEntry,
  849. NotifyEntry = NotifyEntry->Next) {
  850. if (NotifyEntry->CallbackRoutine == CallbackRoutine)
  851. break;
  852. }
  853. if (NotifyEntry != NULL) {
  854. PreviousEntry->Next = NotifyEntry->Next;
  855. SepRmReleaseDbWriteLock();
  856. ExFreePool( NotifyEntry );
  857. Status = STATUS_SUCCESS;
  858. } else {
  859. SepRmReleaseDbWriteLock();
  860. Status = STATUS_NOT_FOUND;
  861. }
  862. return( Status );
  863. }
  864. NTSTATUS
  865. SeMarkLogonSessionForTerminationNotification(
  866. IN PLUID LogonId
  867. )
  868. /*++
  869. Routine Description:
  870. File systems that have registered for logon-termination notification
  871. can mark logon sessions they are interested in for callback by calling
  872. this routine.
  873. Arguments:
  874. LogonId - The logon id for which the file system should be notified
  875. when the logon session is terminated.
  876. Returns:
  877. Nothing.
  878. --*/
  879. {
  880. ULONG SessionArrayIndex;
  881. PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
  882. PAGED_CODE();
  883. SessionArrayIndex = SepLogonSessionIndex( LogonId );
  884. Previous = &SepLogonSessions[ SessionArrayIndex ];
  885. //
  886. // Protect modification of reference monitor database
  887. //
  888. SepRmAcquireDbWriteLock();
  889. //
  890. // Now walk the list for our logon session array hash index.
  891. //
  892. Current = *Previous;
  893. while (Current != NULL) {
  894. //
  895. // If we found it, decrement the reference count and return
  896. //
  897. if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
  898. Current->Flags |= SEP_TERMINATION_NOTIFY;
  899. break;
  900. }
  901. Current = Current->Next;
  902. }
  903. SepRmReleaseDbWriteLock();
  904. return( (Current != NULL) ? STATUS_SUCCESS : STATUS_NOT_FOUND );
  905. }
  906. VOID
  907. SepInformFileSystemsOfDeletedLogon(
  908. IN PLUID LogonId
  909. )
  910. /*++
  911. Routine Description:
  912. This routine informs interested file systems of a deleted logon.
  913. Note that we can not be guaranteed that we are in a whole (or wholesome)
  914. thread, since we may be in the middle of process deletion and object
  915. rundown. Therefore, we must queue the work off to a worker thread.
  916. Arguments:
  917. LogonId - Pointer to the logon session ID which has been deleted.
  918. Return Value:
  919. None.
  920. --*/
  921. {
  922. PSEP_FILE_SYSTEM_NOTIFY_CONTEXT FSNotifyContext;
  923. PAGED_CODE();
  924. FSNotifyContext = ExAllocatePoolWithTag(
  925. NonPagedPool,
  926. sizeof(SEP_FILE_SYSTEM_NOTIFY_CONTEXT),
  927. 'SFeS');
  928. if (FSNotifyContext == NULL) {
  929. //
  930. // I don't know what to do here... file systems will loose track of a
  931. // logon session, but the system isn't really harmed in any way.
  932. //
  933. return;
  934. }
  935. FSNotifyContext->LogonId = *LogonId;
  936. ExInitializeWorkItem( &FSNotifyContext->WorkItem,
  937. (PWORKER_THREAD_ROUTINE) SepNotifyFileSystems,
  938. (PVOID) FSNotifyContext);
  939. ExQueueWorkItem( &FSNotifyContext->WorkItem, DelayedWorkQueue );
  940. }
  941. VOID
  942. SepNotifyFileSystems(
  943. IN PVOID Context
  944. )
  945. {
  946. PSEP_FILE_SYSTEM_NOTIFY_CONTEXT FSNotifyContext =
  947. (PSEP_FILE_SYSTEM_NOTIFY_CONTEXT) Context;
  948. PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION NextCallback;
  949. PAGED_CODE();
  950. //
  951. // Protect modification of the list of FS callbacks.
  952. //
  953. SepRmAcquireDbReadLock();
  954. NextCallback = SeFileSystemNotifyRoutinesHead.Next;
  955. while (NextCallback != NULL) {
  956. NextCallback->CallbackRoutine( &FSNotifyContext->LogonId );
  957. NextCallback = NextCallback->Next;
  958. }
  959. SepRmReleaseDbReadLock();
  960. ExFreePool( FSNotifyContext );
  961. }
  962. NTSTATUS
  963. SeGetLogonIdDeviceMap(
  964. IN PLUID pLogonId,
  965. OUT PDEVICE_MAP* ppDevMap
  966. )
  967. /*++
  968. Routine Description:
  969. This routine is called by components that want a handle to the
  970. Device Map for the specified LUID
  971. Arguments:
  972. LogonID - LUID of the user
  973. Return Value:
  974. STATUS_SUCCESS - Successfully registered routine
  975. STATUS_INVALID_PARAMETER - invalid parameter
  976. STATUS_INSUFFICIENT_RESOURCE - Unable to allocate list entry.
  977. --*/
  978. {
  979. PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
  980. ULONG SessionArrayIndex;
  981. PAGED_CODE();
  982. if( pLogonId == NULL ) {
  983. return( STATUS_INVALID_PARAMETER );
  984. }
  985. if( ppDevMap == NULL ) {
  986. return( STATUS_INVALID_PARAMETER );
  987. }
  988. SessionArrayIndex = SepLogonSessionIndex( pLogonId );
  989. Previous = &SepLogonSessions[ SessionArrayIndex ];
  990. //
  991. // Protect modification of reference monitor database
  992. //
  993. SepRmAcquireDbWriteLock();
  994. //
  995. // Now walk the list for our logon session array hash index.
  996. //
  997. Current = *Previous;
  998. while (Current != NULL) {
  999. //
  1000. // If we found it, return a handle to the device map
  1001. //
  1002. if (RtlEqualLuid( pLogonId, &(Current->LogonId) )) {
  1003. NTSTATUS Status;
  1004. Status = STATUS_SUCCESS;
  1005. //
  1006. // Check if the Device Map does not exist for this LUID
  1007. //
  1008. if (Current->pDeviceMap == NULL) {
  1009. WCHAR szString[64]; // \Sessions\0\DosDevices\x-x = 10+1+12+(8)+1+(8)+1 = 41
  1010. OBJECT_ATTRIBUTES Obja;
  1011. UNICODE_STRING UnicodeString, SymLinkUnicodeString;
  1012. HANDLE hDevMap, hSymLink;
  1013. PDEVICE_MAP pDeviceMap = NULL;
  1014. //
  1015. // Drop the lock while we create the devmap
  1016. //
  1017. Current->ReferenceCount += 1;
  1018. SepRmReleaseDbWriteLock();
  1019. _snwprintf( szString,
  1020. sizeof(szString)/sizeof(WCHAR),
  1021. L"\\Sessions\\0\\DosDevices\\%08x-%08x",
  1022. pLogonId->HighPart,
  1023. pLogonId->LowPart );
  1024. RtlInitUnicodeString( &UnicodeString, szString );
  1025. //
  1026. // Device Map for LUID does not exist
  1027. // Create the Device Map for the LUID
  1028. //
  1029. InitializeObjectAttributes( &Obja,
  1030. &UnicodeString,
  1031. OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
  1032. NULL,
  1033. NULL );
  1034. Status = ZwCreateDirectoryObject( &hDevMap,
  1035. DIRECTORY_ALL_ACCESS,
  1036. &Obja );
  1037. if (NT_SUCCESS( Status )) {
  1038. //
  1039. // Set the DeviceMap for this directory object
  1040. //
  1041. Status = ObSetDirectoryDeviceMap( &pDeviceMap,
  1042. hDevMap );
  1043. if (NT_SUCCESS( Status )) {
  1044. //
  1045. // Create the Global SymLink to the global DosDevices
  1046. //
  1047. RtlInitUnicodeString( &SymLinkUnicodeString, L"Global" );
  1048. RtlInitUnicodeString( &UnicodeString, L"\\Global??" );
  1049. InitializeObjectAttributes(
  1050. &Obja,
  1051. &SymLinkUnicodeString,
  1052. OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
  1053. hDevMap,
  1054. NULL );
  1055. Status = ZwCreateSymbolicLinkObject( &hSymLink,
  1056. SYMBOLIC_LINK_ALL_ACCESS,
  1057. &Obja,
  1058. &UnicodeString );
  1059. if (NT_SUCCESS( Status )) {
  1060. ZwClose( hSymLink );
  1061. }
  1062. else {
  1063. ObfDereferenceDeviceMap(pDeviceMap);
  1064. }
  1065. }
  1066. ZwClose( hDevMap );
  1067. }
  1068. //
  1069. // Reaquire the lock and modify the LUID structures
  1070. //
  1071. SepRmAcquireDbWriteLock();
  1072. if (!NT_SUCCESS( Status )) {
  1073. *ppDevMap = NULL;
  1074. }
  1075. else {
  1076. if(Current->pDeviceMap == NULL) {
  1077. Current->pDeviceMap = pDeviceMap;
  1078. }
  1079. else {
  1080. ObfDereferenceDeviceMap(pDeviceMap);
  1081. }
  1082. *ppDevMap = Current->pDeviceMap;
  1083. }
  1084. //
  1085. // Remove the reference we just added
  1086. //
  1087. if(Current->ReferenceCount == 1) {
  1088. //
  1089. // Special case: the count will be decremented to zero, so
  1090. // the LUID should go away. We drop the lock and call the
  1091. // existing DeReference function to actually destroy the
  1092. // object.
  1093. //
  1094. SepRmReleaseDbWriteLock();
  1095. SepDeReferenceLogonSession(pLogonId);
  1096. return ( Status );
  1097. }
  1098. else {
  1099. Current->ReferenceCount -= 1;
  1100. }
  1101. }
  1102. else {
  1103. //
  1104. // Device Map for LUID already exist
  1105. // return the handle to the Device Map
  1106. //
  1107. *ppDevMap = Current->pDeviceMap;
  1108. }
  1109. SepRmReleaseDbWriteLock();
  1110. return ( Status );
  1111. }
  1112. Current = Current->Next;
  1113. }
  1114. SepRmReleaseDbWriteLock();
  1115. //
  1116. // Bad news, someone asked us for a device map of
  1117. // a logon session we didn't know existed. This might be a new
  1118. // token being created, so return an error status and let the caller
  1119. // decide if it warrants a bug check or not.
  1120. //
  1121. return STATUS_NO_SUCH_LOGON_SESSION;
  1122. }
  1123. #if DBG || TOKEN_LEAK_MONITOR
  1124. VOID
  1125. SepAddTokenLogonSession(
  1126. IN PTOKEN Token
  1127. )
  1128. /*++
  1129. Routine Description
  1130. Adds SEP_LOGON_SESSION_TOKEN to a reference monitor track.
  1131. Arguments
  1132. Token - token to add
  1133. Return Value
  1134. None
  1135. --*/
  1136. {
  1137. ULONG SessionArrayIndex;
  1138. PSEP_LOGON_SESSION_REFERENCES Current;
  1139. PSEP_LOGON_SESSION_TOKEN TokenTrack = NULL;
  1140. PLUID LogonId = &Token->AuthenticationId;
  1141. PAGED_CODE();
  1142. SessionArrayIndex = SepLogonSessionIndex( LogonId );
  1143. //
  1144. // Protect modification of reference monitor database
  1145. //
  1146. SepRmAcquireDbWriteLock();
  1147. Current = SepLogonSessions[ SessionArrayIndex ];
  1148. //
  1149. // Now walk the list for our logon session array hash index.
  1150. //
  1151. while (Current != NULL) {
  1152. //
  1153. // If we found it, increment the reference count and return
  1154. //
  1155. if (RtlEqualLuid( LogonId, &Current->LogonId )) {
  1156. //
  1157. // Stick the token address into the track. Find the last in the list of tokens
  1158. // for this session.
  1159. //
  1160. TokenTrack = ExAllocatePoolWithTag(PagedPool, sizeof(SEP_LOGON_SESSION_TOKEN), 'sLeS');
  1161. if (TokenTrack) {
  1162. RtlZeroMemory(TokenTrack, sizeof(SEP_LOGON_SESSION_TOKEN));
  1163. TokenTrack->Token = Token;
  1164. InsertTailList(&Current->TokenList, &TokenTrack->ListEntry);
  1165. }
  1166. SepRmReleaseDbWriteLock();
  1167. return;
  1168. }
  1169. Current = Current->Next;
  1170. }
  1171. ASSERT(FALSE && L"Failed to add logon session token track.");
  1172. SepRmReleaseDbWriteLock();
  1173. }
  1174. VOID
  1175. SepRemoveTokenLogonSession(
  1176. IN PTOKEN Token
  1177. )
  1178. /*++
  1179. Routine Description
  1180. Removes a SEP_LOGON_SESSION_TOKEN from a reference monitor logon track.
  1181. Arguments
  1182. Token - token to remove
  1183. Return Value
  1184. None.
  1185. --*/
  1186. {
  1187. ULONG SessionArrayIndex;
  1188. PSEP_LOGON_SESSION_REFERENCES Current;
  1189. PSEP_LOGON_SESSION_TOKEN TokenTrack = NULL;
  1190. PLUID LogonId = &Token->AuthenticationId;
  1191. PLIST_ENTRY ListEntry;
  1192. PAGED_CODE();
  1193. if (Token->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) {
  1194. return;
  1195. }
  1196. SessionArrayIndex = SepLogonSessionIndex( LogonId );
  1197. //
  1198. // Protect modification of reference monitor database
  1199. //
  1200. SepRmAcquireDbWriteLock();
  1201. Current = SepLogonSessions[ SessionArrayIndex ];
  1202. //
  1203. // Now walk the list for our logon session array hash index.
  1204. //
  1205. while (Current != NULL) {
  1206. if (RtlEqualLuid( LogonId, &Current->LogonId )) {
  1207. //
  1208. // Remove the token from the token list for this session.
  1209. //
  1210. ListEntry = Current->TokenList.Flink;
  1211. while (ListEntry != &Current->TokenList) {
  1212. TokenTrack = CONTAINING_RECORD (ListEntry, SEP_LOGON_SESSION_TOKEN, ListEntry);
  1213. if (TokenTrack->Token == Token) {
  1214. RemoveEntryList (ListEntry);
  1215. SepRmReleaseDbWriteLock();
  1216. ExFreePool(TokenTrack);
  1217. TokenTrack = NULL;
  1218. return;
  1219. }
  1220. ListEntry = ListEntry->Flink;
  1221. }
  1222. }
  1223. Current = Current->Next;
  1224. }
  1225. ASSERT(FALSE && L"Failed to delete logon session token track.");
  1226. SepRmReleaseDbWriteLock();
  1227. }
  1228. #endif