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.
1823 lines
46 KiB
1823 lines
46 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rmlogon.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the kernel mode logon tracking performed by the
|
|
reference monitor. Logon tracking is performed by keeping a count of
|
|
how many tokens exist for each active logon in a system. When a logon
|
|
session's reference count drops to zero, the LSA is notified so that
|
|
authentication packages can clean up any related context data.
|
|
|
|
|
|
Author:
|
|
|
|
Jim Kelly (JimK) 21-April-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//#define SEP_TRACK_LOGON_SESSION_REFS
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "rmp.h"
|
|
#include <bugcodes.h>
|
|
#include <stdio.h>
|
|
#include <zwapi.h>
|
|
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma data_seg("PAGEDATA")
|
|
#endif
|
|
|
|
SEP_LOGON_SESSION_TERMINATED_NOTIFICATION
|
|
SeFileSystemNotifyRoutinesHead = {0};
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Internally defined data types //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct _SEP_FILE_SYSTEM_NOTIFY_CONTEXT {
|
|
WORK_QUEUE_ITEM WorkItem;
|
|
LUID LogonId;
|
|
} SEP_FILE_SYSTEM_NOTIFY_CONTEXT, *PSEP_FILE_SYSTEM_NOTIFY_CONTEXT;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Internally defined routines //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
VOID
|
|
SepInformLsaOfDeletedLogon(
|
|
IN PLUID LogonId
|
|
);
|
|
|
|
VOID
|
|
SepInformFileSystemsOfDeletedLogon(
|
|
IN PLUID LogonId
|
|
);
|
|
|
|
VOID
|
|
SepNotifyFileSystems(
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
SepCleanupLUIDDeviceMapDirectory(
|
|
PLUID pLogonId
|
|
);
|
|
|
|
NTSTATUS
|
|
SeGetLogonIdDeviceMap(
|
|
IN PLUID pLogonId,
|
|
OUT PDEVICE_MAP* ppDevMap
|
|
);
|
|
|
|
//
|
|
// declared in ntos\ob\obp.h
|
|
// defined in ntos\ob\obdir.c
|
|
// Used to dereference the LUID device map
|
|
//
|
|
VOID
|
|
FASTCALL
|
|
ObfDereferenceDeviceMap(
|
|
IN PDEVICE_MAP DeviceMap
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,SepRmCreateLogonSessionWrkr)
|
|
#pragma alloc_text(PAGE,SepRmDeleteLogonSessionWrkr)
|
|
#pragma alloc_text(PAGE,SepReferenceLogonSession)
|
|
#pragma alloc_text(PAGE,SepCleanupLUIDDeviceMapDirectory)
|
|
#pragma alloc_text(PAGE,SepDeReferenceLogonSession)
|
|
#pragma alloc_text(PAGE,SepCreateLogonSessionTrack)
|
|
#pragma alloc_text(PAGE,SepDeleteLogonSessionTrack)
|
|
#pragma alloc_text(PAGE,SepInformLsaOfDeletedLogon)
|
|
#pragma alloc_text(PAGE,SeRegisterLogonSessionTerminatedRoutine)
|
|
#pragma alloc_text(PAGE,SeUnregisterLogonSessionTerminatedRoutine)
|
|
#pragma alloc_text(PAGE,SeMarkLogonSessionForTerminationNotification)
|
|
#pragma alloc_text(PAGE,SepInformFileSystemsOfDeletedLogon)
|
|
#pragma alloc_text(PAGE,SepNotifyFileSystems)
|
|
#pragma alloc_text(PAGE,SeGetLogonIdDeviceMap)
|
|
#if DBG || TOKEN_LEAK_MONITOR
|
|
#pragma alloc_text(PAGE,SepAddTokenLogonSession)
|
|
#pragma alloc_text(PAGE,SepRemoveTokenLogonSession)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Local macros //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//
|
|
// This macro is used to obtain an index into the logon session tracking
|
|
// array given a logon session ID (a LUID).
|
|
//
|
|
|
|
#define SepLogonSessionIndex( PLogonId ) ( \
|
|
(PLogonId)->LowPart & SEP_LOGON_TRACK_INDEX_MASK \
|
|
)
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Exported Services //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
SepRmCreateLogonSessionWrkr(
|
|
IN PRM_COMMAND_MESSAGE CommandMessage,
|
|
OUT PRM_REPLY_MESSAGE ReplyMessage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the dispatch routine for the LSA --> RM
|
|
"CreateLogonSession" call.
|
|
|
|
The arguments passed to this routine are defined by the
|
|
type SEP_RM_COMMAND_WORKER.
|
|
|
|
|
|
Arguments:
|
|
|
|
CommandMessage - Points to structure containing RM command message
|
|
information consisting of an LPC PORT_MESSAGE structure followed
|
|
by the command number (RmComponentTestCommand) and a command-specific
|
|
body. The command-specific body of this parameter is a LUID of the
|
|
logon session to be created.
|
|
|
|
ReplyMessage - Pointer to structure containing LSA reply message
|
|
information consisting of an LPC PORT_MESSAGE structure followed
|
|
by the command ReturnedStatus field in which a status code from the
|
|
command will be returned.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
LUID LogonId;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Check that command is expected type
|
|
//
|
|
|
|
ASSERT( CommandMessage->CommandNumber == RmCreateLogonSession );
|
|
|
|
|
|
//
|
|
// Typecast the command parameter to what we expect.
|
|
//
|
|
|
|
LogonId = *((LUID UNALIGNED *) CommandMessage->CommandParams);
|
|
|
|
|
|
|
|
//
|
|
// Try to create the logon session tracking record
|
|
//
|
|
|
|
Status = SepCreateLogonSessionTrack( &LogonId );
|
|
|
|
|
|
|
|
//
|
|
// Set the reply status
|
|
//
|
|
|
|
ReplyMessage->ReturnedStatus = Status;
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SepRmDeleteLogonSessionWrkr(
|
|
IN PRM_COMMAND_MESSAGE CommandMessage,
|
|
OUT PRM_REPLY_MESSAGE ReplyMessage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the dispatch routine for the LSA --> RM
|
|
"DeleteLogonSession" call.
|
|
|
|
The arguments passed to this routine are defined by the
|
|
type SEP_RM_COMMAND_WORKER.
|
|
|
|
|
|
Arguments:
|
|
|
|
CommandMessage - Points to structure containing RM command message
|
|
information consisting of an LPC PORT_MESSAGE structure followed
|
|
by the command number (RmComponentTestCommand) and a command-specific
|
|
body. The command-specific body of this parameter is a LUID of the
|
|
logon session to be created.
|
|
|
|
ReplyMessage - Pointer to structure containing LSA reply message
|
|
information consisting of an LPC PORT_MESSAGE structure followed
|
|
by the command ReturnedStatus field in which a status code from the
|
|
command will be returned.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
LUID LogonId;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Check that command is expected type
|
|
//
|
|
|
|
ASSERT( CommandMessage->CommandNumber == RmDeleteLogonSession );
|
|
|
|
|
|
//
|
|
// Typecast the command parameter to what we expect.
|
|
//
|
|
|
|
LogonId = *((LUID UNALIGNED *) CommandMessage->CommandParams);
|
|
|
|
|
|
|
|
//
|
|
// Try to create the logon session tracking record
|
|
//
|
|
|
|
Status = SepDeleteLogonSessionTrack( &LogonId );
|
|
|
|
|
|
|
|
//
|
|
// Set the reply status
|
|
//
|
|
|
|
ReplyMessage->ReturnedStatus = Status;
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SepReferenceLogonSession(
|
|
IN PLUID LogonId,
|
|
OUT PSEP_LOGON_SESSION_REFERENCES *ReturnSession
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine increments the reference count of a logon session
|
|
tracking record.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
LogonId - Pointer to the logon session ID whose logon track is
|
|
to be incremented.
|
|
|
|
ReturnSession - The found session is returned here on success.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The reference count was successfully incremented.
|
|
|
|
STATUS_NO_SUCH_LOGON_SESSION - The specified logon session doesn't
|
|
exist in the reference monitor's database.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG SessionArrayIndex;
|
|
PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
|
|
ULONG Refs;
|
|
|
|
PAGED_CODE();
|
|
|
|
SessionArrayIndex = SepLogonSessionIndex( LogonId );
|
|
|
|
Previous = &SepLogonSessions[ SessionArrayIndex ];
|
|
|
|
//
|
|
// Protect modification of reference monitor database
|
|
//
|
|
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
|
|
//
|
|
// Now walk the list for our logon session array hash index.
|
|
//
|
|
|
|
Current = *Previous;
|
|
|
|
while (Current != NULL) {
|
|
|
|
//
|
|
// If we found it, increment the reference count and return
|
|
//
|
|
|
|
if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
|
|
|
|
Refs = InterlockedIncrement (&Current->ReferenceCount);
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
#ifdef SEP_TRACK_LOGON_SESSION_REFS
|
|
DbgPrint("SE (rm): ++ logon session: (%d, %d) to %d by (%d, %d)\n",
|
|
LogonId->HighPart, LogonId->LowPart, Refs,
|
|
PsGetCurrentThread()->Cid.UniqueProcess,
|
|
PsGetCurrentThread()->Cid.UniqueThread);
|
|
|
|
#endif //SEP_TRACK_LOGON_SESSION_REFS
|
|
|
|
*ReturnSession = Current;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
Current = Current->Next;
|
|
}
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
//
|
|
// Bad news, someone asked us to increment the reference count of
|
|
// a logon session we didn't know existed. This might be a new
|
|
// token being created, so return an error status and let the caller
|
|
// decide if it warrants a bug check or not.
|
|
//
|
|
|
|
|
|
return STATUS_NO_SUCH_LOGON_SESSION;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SepCleanupLUIDDeviceMapDirectory(
|
|
PLUID pLogonId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Make the contents of the (LUID's device map)'s directory object
|
|
temporary so that their names go away.
|
|
|
|
|
|
Arguments:
|
|
|
|
pLogonId - Pointer to the logon session ID whose device is to be
|
|
cleaned up
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - cleaned up the entire device map
|
|
|
|
STATUS_INVALID_PARAMETER - pLogonId is a NULL pointer
|
|
|
|
STATUS_NO_MEMORY - could not allocate memory to hold the handle
|
|
buffer
|
|
|
|
appropriate NTSTATUS code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES Attributes;
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE LinkHandle;
|
|
POBJECT_DIRECTORY_INFORMATION DirInfo = NULL;
|
|
BOOLEAN RestartScan;
|
|
WCHAR szString[64]; // \Sessions\0\DosDevices\x-x = 10+1+12+(8)+1+(8)+1 = 41
|
|
ULONG Context = 0;
|
|
ULONG ReturnedLength;
|
|
HANDLE DosDevicesDirectory;
|
|
HANDLE *HandleArray;
|
|
ULONG Size = 100;
|
|
ULONG i, Count = 0;
|
|
ULONG dirInfoLength = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (pLogonId == NULL) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// Open a handle to the directory object for the LUID device map
|
|
// Get a kernel handle
|
|
//
|
|
|
|
_snwprintf( szString,
|
|
(sizeof(szString)/sizeof(WCHAR)) - 1,
|
|
L"\\Sessions\\0\\DosDevices\\%08x-%08x",
|
|
pLogonId->HighPart,
|
|
pLogonId->LowPart );
|
|
|
|
RtlInitUnicodeString(&UnicodeString, szString);
|
|
|
|
InitializeObjectAttributes(&Attributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = ZwOpenDirectoryObject(&DosDevicesDirectory,
|
|
DIRECTORY_QUERY,
|
|
&Attributes);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Restart:
|
|
|
|
//
|
|
// Create an array of handles to close with each scan
|
|
// of the directory
|
|
//
|
|
HandleArray = (HANDLE *)ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
(Size * sizeof(HANDLE)),
|
|
'aHeS'
|
|
);
|
|
|
|
if (HandleArray == NULL) {
|
|
|
|
ZwClose(DosDevicesDirectory);
|
|
if (DirInfo != NULL) {
|
|
ExFreePool(DirInfo);
|
|
}
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
RestartScan = TRUE;
|
|
|
|
while (TRUE) {
|
|
|
|
do {
|
|
//
|
|
// ZwQueryDirectoryObject returns one element at a time
|
|
//
|
|
Status = ZwQueryDirectoryObject( DosDevicesDirectory,
|
|
(PVOID)DirInfo,
|
|
dirInfoLength,
|
|
TRUE,
|
|
RestartScan,
|
|
&Context,
|
|
&ReturnedLength );
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
dirInfoLength = ReturnedLength;
|
|
if (DirInfo != NULL) {
|
|
ExFreePool(DirInfo);
|
|
}
|
|
DirInfo = ExAllocatePoolWithTag( PagedPool, dirInfoLength, 'bDeS' );
|
|
if (DirInfo == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}while (Status == STATUS_BUFFER_TOO_SMALL);
|
|
|
|
//
|
|
// Check the status of the operation.
|
|
//
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
if (Status == STATUS_NO_MORE_ENTRIES) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check that the element is a symbolic link
|
|
//
|
|
if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink")) {
|
|
|
|
//
|
|
// check if the handle array is full
|
|
//
|
|
if ( Count >= Size ) {
|
|
|
|
//
|
|
// empty the handle array by closing all the handles
|
|
// and free the handle array so that we can create
|
|
// a bigger handle array
|
|
// Need to restart the directory scan
|
|
//
|
|
for (i = 0; i < Count ; i++) {
|
|
ZwClose (HandleArray[i]);
|
|
}
|
|
Size += 20;
|
|
Count = 0;
|
|
ExFreePool((PVOID)HandleArray);
|
|
HandleArray = NULL;
|
|
goto Restart;
|
|
|
|
}
|
|
|
|
InitializeObjectAttributes( &Attributes,
|
|
&DirInfo->Name,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
DosDevicesDirectory,
|
|
NULL);
|
|
|
|
Status = ZwOpenSymbolicLinkObject( &LinkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&Attributes);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Make the object temporary so that its name goes away from
|
|
// the Object Manager's namespace
|
|
//
|
|
Status = ZwMakeTemporaryObject( LinkHandle );
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
HandleArray[Count] = LinkHandle;
|
|
Count++;
|
|
}
|
|
else {
|
|
ZwClose( LinkHandle );
|
|
}
|
|
}
|
|
|
|
}
|
|
RestartScan = FALSE;
|
|
}
|
|
|
|
//
|
|
// Close all the handles
|
|
//
|
|
for (i = 0; i < Count ; i++) {
|
|
|
|
ZwClose (HandleArray[i]);
|
|
|
|
}
|
|
|
|
if (HandleArray != NULL) {
|
|
ExFreePool((PVOID)HandleArray);
|
|
}
|
|
|
|
if (DirInfo != NULL) {
|
|
ExFreePool(DirInfo);
|
|
}
|
|
|
|
if (DosDevicesDirectory != NULL) {
|
|
ZwClose(DosDevicesDirectory);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SepDeReferenceLogonSession(
|
|
IN PLUID LogonId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decrements the reference count of a logon session
|
|
tracking record.
|
|
|
|
If the reference count is decremented to zero, then there is no
|
|
possibility for any more tokens to exist for the logon session.
|
|
In this case, the LSA is notified that a logon session has
|
|
terminated.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
LogonId - Pointer to the logon session ID whose logon track is
|
|
to be decremented.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG SessionArrayIndex;
|
|
PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
|
|
PDEVICE_MAP pDeviceMap = NULL;
|
|
ULONG Refs;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
SessionArrayIndex = SepLogonSessionIndex( LogonId );
|
|
|
|
Previous = &SepLogonSessions[ SessionArrayIndex ];
|
|
|
|
//
|
|
// Protect modification of reference monitor database
|
|
//
|
|
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
|
|
//
|
|
// Now walk the list for our logon session array hash index.
|
|
//
|
|
|
|
Current = *Previous;
|
|
|
|
while (Current != NULL) {
|
|
|
|
//
|
|
// If we found it, decrement the reference count and return
|
|
//
|
|
|
|
if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
|
|
Refs = InterlockedDecrement (&Current->ReferenceCount);
|
|
if (Refs == 0) {
|
|
|
|
//
|
|
// Pull it from the list
|
|
//
|
|
|
|
*Previous = Current->Next;
|
|
|
|
//
|
|
// No longer need to protect our pointer to this
|
|
// record.
|
|
//
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
//
|
|
// If the Device Map exist for this LUID,
|
|
// dereference the pointer to the Device Map
|
|
//
|
|
if (Current->pDeviceMap != NULL) {
|
|
|
|
//
|
|
// Dereference our reference on the device map
|
|
// our reference should be the last reference,
|
|
// thus the system will delete the device map
|
|
// for the LUID
|
|
//
|
|
pDeviceMap = Current->pDeviceMap;
|
|
Current->pDeviceMap = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Make all the contents of the LUID's device map temporary,
|
|
// so that the names go away from the Object Manager's
|
|
// namespace
|
|
// Remove our reference on the LUID's device map
|
|
//
|
|
if (pDeviceMap != NULL) {
|
|
SepCleanupLUIDDeviceMapDirectory( LogonId );
|
|
ObfDereferenceDeviceMap( pDeviceMap );
|
|
}
|
|
|
|
//
|
|
// Asynchronoously inform file systems that this logon session
|
|
// is going away, if at least one FS expressed interest in this
|
|
// logon session.
|
|
//
|
|
|
|
if (Current->Flags & SEP_TERMINATION_NOTIFY) {
|
|
SepInformFileSystemsOfDeletedLogon( LogonId );
|
|
}
|
|
|
|
//
|
|
// Deallocate the logon session track record.
|
|
//
|
|
|
|
ExFreePool( (PVOID)Current );
|
|
|
|
|
|
#ifdef SEP_TRACK_LOGON_SESSION_REFS
|
|
DbgPrint("SE (rm): -- ** logon session: (%d, %d) to ZERO by (%d, %d)\n",
|
|
LogonId->HighPart, LogonId->LowPart,
|
|
PsGetCurrentThread()->Cid.UniqueProcess,
|
|
PsGetCurrentThread()->Cid.UniqueThread);
|
|
|
|
#endif //SEP_TRACK_LOGON_SESSION_REFS
|
|
|
|
//
|
|
// Inform the LSA about the deletion of this logon session.
|
|
//
|
|
|
|
SepInformLsaOfDeletedLogon( LogonId );
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// reference count was decremented, but not to zero.
|
|
//
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
#ifdef SEP_TRACK_LOGON_SESSION_REFS
|
|
DbgPrint("SE (rm): -- logon session: (%d, %d) to %d by (%d, %d)\n",
|
|
LogonId->HighPart, LogonId->LowPart, Refs,
|
|
PsGetCurrentThread()->Cid.UniqueProcess,
|
|
PsGetCurrentThread()->Cid.UniqueThread);
|
|
#endif //SEP_TRACK_LOGON_SESSION_REFS
|
|
|
|
return;
|
|
}
|
|
|
|
Previous = &Current->Next;
|
|
Current = *Previous;
|
|
}
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
//
|
|
// Bad news, someone asked us to decrement the reference count of
|
|
// a logon session we didn't know existed.
|
|
//
|
|
|
|
KeBugCheckEx( DEREF_UNKNOWN_LOGON_SESSION, 0, 0, 0, 0 );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SepCreateLogonSessionTrack(
|
|
IN PLUID LogonId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a new logon session tracking record.
|
|
|
|
This should only be called as a dispatch routine for a LSA->RM
|
|
call (and once during system initialization).
|
|
|
|
If the specified logon session already exists, then an error is returned.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
LogonId - Pointer to the logon session ID for which a new logon track is
|
|
to be created.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The logon session track was created successfully.
|
|
|
|
STATUS_LOGON_SESSION_EXISTS - The logon session already exists.
|
|
A new one has not been created.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG SessionArrayIndex;
|
|
PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
|
|
PSEP_LOGON_SESSION_REFERENCES LogonSessionTrack;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
#if DBG || TOKEN_LEAK_MONITOR
|
|
if (SepTokenLeakTracking) {
|
|
DbgPrint("\nLOGON : 0x%x 0x%x\n\n", LogonId->HighPart, LogonId->LowPart);
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Make sure we can allocate a new logon session track record
|
|
//
|
|
|
|
LogonSessionTrack = (PSEP_LOGON_SESSION_REFERENCES)
|
|
ExAllocatePoolWithTag(
|
|
PagedPool,
|
|
sizeof(SEP_LOGON_SESSION_REFERENCES),
|
|
'sLeS'
|
|
);
|
|
|
|
if (LogonSessionTrack == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(LogonSessionTrack, sizeof(SEP_LOGON_SESSION_REFERENCES));
|
|
LogonSessionTrack->LogonId = (*LogonId);
|
|
LogonSessionTrack->ReferenceCount = 0;
|
|
LogonSessionTrack->pDeviceMap = NULL;
|
|
|
|
#if DBG || TOKEN_LEAK_MONITOR
|
|
InitializeListHead(&LogonSessionTrack->TokenList);
|
|
#endif
|
|
|
|
|
|
SessionArrayIndex = SepLogonSessionIndex( LogonId );
|
|
|
|
Previous = &SepLogonSessions[ SessionArrayIndex ];
|
|
|
|
//
|
|
// Protect modification of reference monitor database
|
|
//
|
|
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
|
|
//
|
|
// Now walk the list for our logon session array hash index
|
|
// looking for a duplicate logon session ID.
|
|
//
|
|
|
|
Current = *Previous;
|
|
|
|
while (Current != NULL) {
|
|
|
|
if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
|
|
|
|
//
|
|
// One already exists. Hmmm.
|
|
//
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
ExFreePool(LogonSessionTrack);
|
|
return STATUS_LOGON_SESSION_EXISTS;
|
|
|
|
}
|
|
|
|
Current = Current->Next;
|
|
}
|
|
|
|
|
|
//
|
|
// Reached the end of the list without finding a duplicate.
|
|
// Add the new one.
|
|
//
|
|
|
|
LogonSessionTrack->Next = *Previous;
|
|
*Previous = LogonSessionTrack;
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SepDeleteLogonSessionTrack(
|
|
IN PLUID LogonId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a new logon session tracking record.
|
|
|
|
This should only be called as a dispatch routine for a LSA->RM
|
|
call (and once during system initialization).
|
|
|
|
If the specified logon session already exists, then an error is returned.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
LogonId - Pointer to the logon session ID whose logon track is
|
|
to be deleted.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The logon session track was deleted successfully.
|
|
|
|
STATUS_BAD_LOGON_SESSION_STATE - The logon session has a non-zero
|
|
reference count and can not be deleted.
|
|
|
|
STATUS_NO_SUCH_LOGON_SESSION - The specified logon session does not
|
|
exist.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG SessionArrayIndex;
|
|
PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
|
|
PDEVICE_MAP pDeviceMap = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
SessionArrayIndex = SepLogonSessionIndex( LogonId );
|
|
|
|
Previous = &SepLogonSessions[ SessionArrayIndex ];
|
|
|
|
//
|
|
// Protect modification of reference monitor database
|
|
//
|
|
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
|
|
//
|
|
// Now walk the list for our logon session array hash index.
|
|
//
|
|
|
|
Current = *Previous;
|
|
|
|
while (Current != NULL) {
|
|
|
|
//
|
|
// If we found it, make sure reference count is zero
|
|
//
|
|
|
|
if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
|
|
|
|
if (Current->ReferenceCount == 0) {
|
|
|
|
//
|
|
// Pull it from the list
|
|
//
|
|
|
|
*Previous = Current->Next;
|
|
|
|
//
|
|
// If the Device Map exist for this LUID,
|
|
// dereference the pointer to the Device Map
|
|
//
|
|
if (Current->pDeviceMap != NULL) {
|
|
|
|
//
|
|
// Dereference our reference on the device map
|
|
// our reference should be the last reference,
|
|
// thus the system will delete the device map
|
|
// for the LUID
|
|
//
|
|
pDeviceMap = Current->pDeviceMap;
|
|
Current->pDeviceMap = NULL;
|
|
}
|
|
|
|
//
|
|
// No longer need to protect our pointer to this
|
|
// record.
|
|
//
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
//
|
|
// Make all the contents of the LUID's device map temporary,
|
|
// so that the names go away from the Object Manager's
|
|
// namespace
|
|
// Remove our reference on the LUID's device map
|
|
//
|
|
if (pDeviceMap != NULL) {
|
|
SepCleanupLUIDDeviceMapDirectory( LogonId );
|
|
ObfDereferenceDeviceMap( pDeviceMap );
|
|
}
|
|
|
|
//
|
|
// Deallocate the logon session track record.
|
|
//
|
|
|
|
ExFreePool( (PVOID)Current );
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// reference count was not zero. This is not considered
|
|
// a healthy situation. Return an error and let someone
|
|
// else declare the bug check.
|
|
//
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
return STATUS_BAD_LOGON_SESSION_STATE;
|
|
}
|
|
|
|
Previous = &Current->Next;
|
|
Current = *Previous;
|
|
}
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
//
|
|
// Someone asked us to delete a logon session that isn't
|
|
// in the database.
|
|
//
|
|
|
|
return STATUS_NO_SUCH_LOGON_SESSION;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SepInformLsaOfDeletedLogon(
|
|
IN PLUID LogonId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine informs the LSA about the deletion of a logon session.
|
|
|
|
Note that we can not be guaranteed that we are in a whole (or wholesome)
|
|
thread, since we may be in the middle of process deletion and object
|
|
rundown. Therefore, we must queue the work off to a worker thread which
|
|
can then make an LPC call to the LSA.
|
|
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
LogonId - Pointer to the logon session ID which has been deleted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSEP_LSA_WORK_ITEM DeleteLogonItem;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Pass the LUID value along with the work queue item.
|
|
// Note that the worker thread is responsible for freeing the WorkItem data
|
|
// structure.
|
|
//
|
|
|
|
DeleteLogonItem = ExAllocatePoolWithTag( PagedPool, sizeof(SEP_LSA_WORK_ITEM), 'wLeS' );
|
|
if (DeleteLogonItem == NULL) {
|
|
|
|
//
|
|
// I don't know what to do here... we loose track of a logon session,
|
|
// but the system isn't really harmed in any way.
|
|
//
|
|
|
|
ASSERT("Failed to allocate DeleteLogonItem." && FALSE);
|
|
return;
|
|
|
|
}
|
|
|
|
DeleteLogonItem->CommandParams.LogonId = (*LogonId);
|
|
DeleteLogonItem->CommandNumber = LsapLogonSessionDeletedCommand;
|
|
DeleteLogonItem->CommandParamsLength = sizeof( LUID );
|
|
DeleteLogonItem->ReplyBuffer = NULL;
|
|
DeleteLogonItem->ReplyBufferLength = 0;
|
|
DeleteLogonItem->CleanupFunction = NULL;
|
|
DeleteLogonItem->CleanupParameter = 0;
|
|
DeleteLogonItem->Tag = SepDeleteLogon;
|
|
DeleteLogonItem->CommandParamsMemoryType = SepRmImmediateMemory;
|
|
|
|
if (!SepQueueWorkItem( DeleteLogonItem, TRUE )) {
|
|
|
|
ExFreePool( DeleteLogonItem );
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SeRegisterLogonSessionTerminatedRoutine(
|
|
IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by file systems that are interested in being
|
|
notified when a logon session is being deleted.
|
|
|
|
Arguments:
|
|
|
|
CallbackRoutine - Address of routine to call back when a logon session
|
|
is being deleted.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Successfully registered routine
|
|
|
|
STATUS_INVALID_PARAMETER - CallbackRoutine is NULL
|
|
|
|
STATUS_INSUFFICIENT_RESOURCE - Unable to allocate list entry.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION NewCallback;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (CallbackRoutine == NULL) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
NewCallback = ExAllocatePoolWithTag(
|
|
PagedPool | POOL_COLD_ALLOCATION,
|
|
sizeof(SEP_LOGON_SESSION_TERMINATED_NOTIFICATION),
|
|
'SFeS');
|
|
|
|
if (NewCallback == NULL) {
|
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
|
}
|
|
|
|
SepRmAcquireDbWriteLock(SEP_HARDCODED_LOCK_INDEX);
|
|
|
|
NewCallback->Next = SeFileSystemNotifyRoutinesHead.Next;
|
|
|
|
NewCallback->CallbackRoutine = CallbackRoutine;
|
|
|
|
SeFileSystemNotifyRoutinesHead.Next = NewCallback;
|
|
|
|
SepRmReleaseDbWriteLock(SEP_HARDCODED_LOCK_INDEX);
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SeUnregisterLogonSessionTerminatedRoutine(
|
|
IN PSE_LOGON_SESSION_TERMINATED_ROUTINE CallbackRoutine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the dual of SeRegisterLogonSessionTerminatedRoutine. A File System
|
|
*MUST* call this before it is unloaded.
|
|
|
|
Arguments:
|
|
|
|
CallbackRoutine - Address of routine that was originally passed in to
|
|
SeRegisterLogonSessionTerminatedRoutine.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Successfully removed callback routine
|
|
|
|
STATUS_INVALID_PARAMETER - CallbackRoutine is NULL
|
|
|
|
STATUS_NOT_FOUND - Didn't find and entry for CallbackRoutine
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION PreviousEntry;
|
|
PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION NotifyEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (CallbackRoutine == NULL) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
SepRmAcquireDbWriteLock(SEP_HARDCODED_LOCK_INDEX);
|
|
|
|
for (PreviousEntry = &SeFileSystemNotifyRoutinesHead,
|
|
NotifyEntry = SeFileSystemNotifyRoutinesHead.Next;
|
|
NotifyEntry != NULL;
|
|
PreviousEntry = NotifyEntry,
|
|
NotifyEntry = NotifyEntry->Next) {
|
|
|
|
if (NotifyEntry->CallbackRoutine == CallbackRoutine)
|
|
break;
|
|
|
|
}
|
|
|
|
if (NotifyEntry != NULL) {
|
|
|
|
PreviousEntry->Next = NotifyEntry->Next;
|
|
|
|
SepRmReleaseDbWriteLock(SEP_HARDCODED_LOCK_INDEX);
|
|
|
|
ExFreePool( NotifyEntry );
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
SepRmReleaseDbWriteLock(SEP_HARDCODED_LOCK_INDEX);
|
|
|
|
Status = STATUS_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SeMarkLogonSessionForTerminationNotification(
|
|
IN PLUID LogonId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
File systems that have registered for logon-termination notification
|
|
can mark logon sessions they are interested in for callback by calling
|
|
this routine.
|
|
|
|
Arguments:
|
|
|
|
LogonId - The logon id for which the file system should be notified
|
|
when the logon session is terminated.
|
|
|
|
Returns:
|
|
|
|
Nothing.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG SessionArrayIndex;
|
|
PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
|
|
|
|
PAGED_CODE();
|
|
|
|
SessionArrayIndex = SepLogonSessionIndex( LogonId );
|
|
|
|
Previous = &SepLogonSessions[ SessionArrayIndex ];
|
|
|
|
//
|
|
// Protect modification of reference monitor database
|
|
//
|
|
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
|
|
//
|
|
// Now walk the list for our logon session array hash index.
|
|
//
|
|
|
|
Current = *Previous;
|
|
|
|
while (Current != NULL) {
|
|
|
|
//
|
|
// If we found it, decrement the reference count and return
|
|
//
|
|
|
|
if (RtlEqualLuid( LogonId, &Current->LogonId) ) {
|
|
Current->Flags |= SEP_TERMINATION_NOTIFY;
|
|
break;
|
|
}
|
|
|
|
Current = Current->Next;
|
|
}
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
return( (Current != NULL) ? STATUS_SUCCESS : STATUS_NOT_FOUND );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SepInformFileSystemsOfDeletedLogon(
|
|
IN PLUID LogonId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine informs interested file systems of a deleted logon.
|
|
|
|
Note that we can not be guaranteed that we are in a whole (or wholesome)
|
|
thread, since we may be in the middle of process deletion and object
|
|
rundown. Therefore, we must queue the work off to a worker thread.
|
|
|
|
|
|
Arguments:
|
|
|
|
LogonId - Pointer to the logon session ID which has been deleted.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSEP_FILE_SYSTEM_NOTIFY_CONTEXT FSNotifyContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
FSNotifyContext = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(SEP_FILE_SYSTEM_NOTIFY_CONTEXT),
|
|
'SFeS');
|
|
|
|
if (FSNotifyContext == NULL) {
|
|
|
|
//
|
|
// I don't know what to do here... file systems will loose track of a
|
|
// logon session, but the system isn't really harmed in any way.
|
|
//
|
|
|
|
ASSERT("Failed to allocate FSNotifyContext." && FALSE);
|
|
return;
|
|
|
|
}
|
|
|
|
FSNotifyContext->LogonId = *LogonId;
|
|
|
|
ExInitializeWorkItem( &FSNotifyContext->WorkItem,
|
|
(PWORKER_THREAD_ROUTINE) SepNotifyFileSystems,
|
|
(PVOID) FSNotifyContext);
|
|
|
|
ExQueueWorkItem( &FSNotifyContext->WorkItem, DelayedWorkQueue );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SepNotifyFileSystems(
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PSEP_FILE_SYSTEM_NOTIFY_CONTEXT FSNotifyContext =
|
|
(PSEP_FILE_SYSTEM_NOTIFY_CONTEXT) Context;
|
|
|
|
PSEP_LOGON_SESSION_TERMINATED_NOTIFICATION NextCallback;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Protect modification of the list of FS callbacks.
|
|
//
|
|
|
|
SepRmAcquireDbReadLock(SEP_HARDCODED_LOCK_INDEX);
|
|
|
|
NextCallback = SeFileSystemNotifyRoutinesHead.Next;
|
|
|
|
while (NextCallback != NULL) {
|
|
|
|
NextCallback->CallbackRoutine( &FSNotifyContext->LogonId );
|
|
|
|
NextCallback = NextCallback->Next;
|
|
}
|
|
|
|
SepRmReleaseDbReadLock(SEP_HARDCODED_LOCK_INDEX);
|
|
|
|
ExFreePool( FSNotifyContext );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SeGetLogonIdDeviceMap(
|
|
IN PLUID pLogonId,
|
|
OUT PDEVICE_MAP* ppDevMap
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by components that want a handle to the
|
|
Device Map for the specified LUID
|
|
|
|
Arguments:
|
|
|
|
LogonID - LUID of the user
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Successfully registered routine
|
|
|
|
STATUS_INVALID_PARAMETER - invalid parameter
|
|
|
|
STATUS_INSUFFICIENT_RESOURCE - Unable to allocate list entry.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PSEP_LOGON_SESSION_REFERENCES *Previous, Current;
|
|
ULONG SessionArrayIndex;
|
|
LONG OldValue;
|
|
|
|
PAGED_CODE();
|
|
|
|
if( pLogonId == NULL ) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
if( ppDevMap == NULL ) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
SessionArrayIndex = SepLogonSessionIndex( pLogonId );
|
|
|
|
Previous = &SepLogonSessions[ SessionArrayIndex ];
|
|
|
|
//
|
|
// Protect modification of reference monitor database
|
|
//
|
|
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
//
|
|
// Now walk the list for our logon session array hash index.
|
|
//
|
|
|
|
Current = *Previous;
|
|
|
|
while (Current != NULL) {
|
|
|
|
//
|
|
// If we found it, return a handle to the device map
|
|
//
|
|
|
|
if (RtlEqualLuid( pLogonId, &(Current->LogonId) )) {
|
|
|
|
NTSTATUS Status;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Check if the Device Map does not exist for this LUID
|
|
//
|
|
if (Current->pDeviceMap == NULL) {
|
|
|
|
WCHAR szString[64]; // \Sessions\0\DosDevices\x-x = 10+1+12+(8)+1+(8)+1 = 41
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING UnicodeString, SymLinkUnicodeString;
|
|
HANDLE hDevMap, hSymLink;
|
|
PDEVICE_MAP pDeviceMap = NULL;
|
|
|
|
//
|
|
// Drop the lock while we create the devmap
|
|
//
|
|
InterlockedIncrement (&Current->ReferenceCount);
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
_snwprintf( szString,
|
|
(sizeof(szString)/sizeof(WCHAR)) - 1,
|
|
L"\\Sessions\\0\\DosDevices\\%08x-%08x",
|
|
pLogonId->HighPart,
|
|
pLogonId->LowPart );
|
|
|
|
RtlInitUnicodeString( &UnicodeString, szString );
|
|
|
|
//
|
|
// Device Map for LUID does not exist
|
|
// Create the Device Map for the LUID
|
|
//
|
|
InitializeObjectAttributes( &Obja,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL );
|
|
|
|
Status = ZwCreateDirectoryObject( &hDevMap,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&Obja );
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
//
|
|
// Set the DeviceMap for this directory object
|
|
//
|
|
Status = ObSetDirectoryDeviceMap( &pDeviceMap,
|
|
hDevMap );
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
//
|
|
// Create the Global SymLink to the global DosDevices
|
|
//
|
|
RtlInitUnicodeString( &SymLinkUnicodeString, L"Global" );
|
|
|
|
RtlInitUnicodeString( &UnicodeString, L"\\Global??" );
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&SymLinkUnicodeString,
|
|
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
|
|
hDevMap,
|
|
NULL );
|
|
|
|
Status = ZwCreateSymbolicLinkObject( &hSymLink,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&Obja,
|
|
&UnicodeString );
|
|
if (NT_SUCCESS( Status )) {
|
|
ZwClose( hSymLink );
|
|
}
|
|
else {
|
|
ObfDereferenceDeviceMap(pDeviceMap);
|
|
}
|
|
}
|
|
|
|
ZwClose( hDevMap );
|
|
}
|
|
|
|
//
|
|
// Reaquire the lock and modify the LUID structures
|
|
//
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
*ppDevMap = NULL;
|
|
}
|
|
else {
|
|
if(Current->pDeviceMap == NULL) {
|
|
Current->pDeviceMap = pDeviceMap;
|
|
}
|
|
else {
|
|
ObfDereferenceDeviceMap(pDeviceMap);
|
|
}
|
|
*ppDevMap = Current->pDeviceMap;
|
|
}
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
//
|
|
// Remove the reference we just added
|
|
//
|
|
|
|
SepDeReferenceLogonSessionDirect(Current);
|
|
|
|
return Status;
|
|
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Device Map for LUID already exist
|
|
// return the handle to the Device Map
|
|
//
|
|
|
|
*ppDevMap = Current->pDeviceMap;
|
|
}
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
return ( Status );
|
|
}
|
|
|
|
Current = Current->Next;
|
|
}
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
//
|
|
// Bad news, someone asked us for a device map of
|
|
// a logon session we didn't know existed. This might be a new
|
|
// token being created, so return an error status and let the caller
|
|
// decide if it warrants a bug check or not.
|
|
//
|
|
|
|
return STATUS_NO_SUCH_LOGON_SESSION;
|
|
}
|
|
|
|
#if DBG || TOKEN_LEAK_MONITOR
|
|
|
|
VOID
|
|
SepAddTokenLogonSession(
|
|
IN PTOKEN Token
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Adds SEP_LOGON_SESSION_TOKEN to a reference monitor track.
|
|
|
|
Arguments
|
|
|
|
Token - token to add
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG SessionArrayIndex;
|
|
PSEP_LOGON_SESSION_REFERENCES Current;
|
|
PSEP_LOGON_SESSION_TOKEN TokenTrack = NULL;
|
|
PLUID LogonId = &Token->AuthenticationId;
|
|
|
|
PAGED_CODE();
|
|
|
|
SessionArrayIndex = SepLogonSessionIndex( LogonId );
|
|
|
|
//
|
|
// Protect modification of reference monitor database
|
|
//
|
|
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
Current = SepLogonSessions[ SessionArrayIndex ];
|
|
|
|
//
|
|
// Now walk the list for our logon session array hash index.
|
|
//
|
|
|
|
while (Current != NULL) {
|
|
|
|
//
|
|
// If we found it, increment the reference count and return
|
|
//
|
|
|
|
if (RtlEqualLuid( LogonId, &Current->LogonId )) {
|
|
|
|
//
|
|
// Stick the token address into the track. Find the last in the list of tokens
|
|
// for this session.
|
|
//
|
|
|
|
TokenTrack = ExAllocatePoolWithTag(PagedPool, sizeof(SEP_LOGON_SESSION_TOKEN), 'sLeS');
|
|
|
|
if (TokenTrack) {
|
|
RtlZeroMemory(TokenTrack, sizeof(SEP_LOGON_SESSION_TOKEN));
|
|
TokenTrack->Token = Token;
|
|
InsertTailList(&Current->TokenList, &TokenTrack->ListEntry);
|
|
}
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
return;
|
|
}
|
|
|
|
Current = Current->Next;
|
|
}
|
|
|
|
ASSERT(FALSE && L"Failed to add logon session token track.");
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex );
|
|
}
|
|
|
|
VOID
|
|
SepRemoveTokenLogonSession(
|
|
IN PTOKEN Token
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Removes a SEP_LOGON_SESSION_TOKEN from a reference monitor logon track.
|
|
|
|
Arguments
|
|
|
|
Token - token to remove
|
|
|
|
Return Value
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG SessionArrayIndex;
|
|
PSEP_LOGON_SESSION_REFERENCES Current;
|
|
PSEP_LOGON_SESSION_TOKEN TokenTrack = NULL;
|
|
PLUID LogonId = &Token->AuthenticationId;
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Token->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) {
|
|
return;
|
|
}
|
|
|
|
SessionArrayIndex = SepLogonSessionIndex( LogonId );
|
|
|
|
//
|
|
// Protect modification of reference monitor database
|
|
//
|
|
|
|
SepRmAcquireDbWriteLock(SessionArrayIndex);
|
|
|
|
Current = SepLogonSessions[ SessionArrayIndex ];
|
|
|
|
//
|
|
// Now walk the list for our logon session array hash index.
|
|
//
|
|
|
|
while (Current != NULL) {
|
|
|
|
if (RtlEqualLuid( LogonId, &Current->LogonId )) {
|
|
|
|
//
|
|
// Remove the token from the token list for this session.
|
|
//
|
|
|
|
ListEntry = Current->TokenList.Flink;
|
|
|
|
while (ListEntry != &Current->TokenList) {
|
|
TokenTrack = CONTAINING_RECORD (ListEntry, SEP_LOGON_SESSION_TOKEN, ListEntry);
|
|
if (TokenTrack->Token == Token) {
|
|
RemoveEntryList (ListEntry);
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
|
|
ExFreePool(TokenTrack);
|
|
TokenTrack = NULL;
|
|
return;
|
|
}
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
}
|
|
|
|
Current = Current->Next;
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrint("Failed to delete logon session token track.");
|
|
#endif
|
|
|
|
SepRmReleaseDbWriteLock(SessionArrayIndex);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma data_seg()
|
|
#endif
|
|
|
|
|