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.
 
 
 
 
 
 

1251 lines
29 KiB

/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
senslogn.cxx
Abstract:
This file contains the implementation of a Stub DLL to notify SENS of
events generated by Winlogon.
Author:
Gopal Parupudi <GopalP>
Notes:
a. This DLL notifies the following components:
o EventSystem (contact DMcCrady)
o IR service (contact JRoberts)
o SENS service (contact GopalP)
b. This DLL also maintains tokens of the currently logged on user. This
is used by COM for activation.
Revision History:
GopalP 12/7/1997 Start.
--*/
#include <common.hxx>
#include <stdio.h>
#include <windows.h>
#include <malloc.h>
#include <winwlx.h>
#include <sensapip.h>
#include <rpc.h>
#include "mutex.hxx"
#include "usertok.h"
#include "senslogn.hxx"
#include "onestop.cxx"
//
// Constants
//
#define NOTIFY_LCE_STARTSHELL 0x00000003
#define NOTIFY_LCE_LOGOFF 0x00000004
#define SENS_START_WAIT_TIMEOUT 180*1000 // 3 minutes
#define NOTIFY_LCE_LOGONUSER "NotifyLogonUser"
#define NOTIFY_LCE_LOGOFFUSER "NotifyLogoffUser"
#define SENS_SERVICE SENS_STRING("SENS")
#define EVENTSYSTEM_DLL SENS_STRING("ES.DLL")
//
// Globals
//
HANDLE ghSensStartedEvent;
BOOL gbIsTokenCodeInitialized;
// For GetCurrentUserToken
USER_LOGON_TABLE * ActiveUserList;
//
// Some useful Macros
//
#ifdef DETAIL_DEBUG
#define DUMP_INFO(_EventType_) \
\
PWLX_NOTIFICATION_INFO pInfo = (PWLX_NOTIFICATION_INFO) lpvParam; \
\
LogMessage(("------------------------------------------------------\n")); \
LogMessage((SENSLOGN " Received a %s Event.\n", _EventType_)); \
LogMessage((" Size - %d\n", pInfo->Size)); \
LogMessage((" Flags - 0x%x\n", pInfo->Flags)); \
LogMessage((" UserName - %ws\n", pInfo->UserName)); \
LogMessage((" Domain - %ws\n", pInfo->Domain)); \
LogMessage((" WinStation - %ws\n", pInfo->WindowStation)); \
LogMessage((" hToken - 0x%x\n", pInfo->hToken)); \
LogMessage((" hDesktop - 0x%x\n", pInfo->hDesktop)); \
LogMessage((" pCallback - 0x%x\n", pInfo->pStatusCallback)); \
LogMessage((" dwSessionId - 0x%x\n", NtCurrentPeb()->SessionId)); \
LogMessage(("------------------------------------------------------\n"));
#else // ! DETAIL_DEBUG
#define DUMP_INFO(_EventType_)
#endif // DETAIL_DEBUG
#define FIRE_EVENT(_EventType_) \
{ \
\
SENS_NOTIFY_WINLOGON Data; \
\
Data.eType = _EventType_; \
Data.Info.Size = sizeof(SENS_NOTIFY_WINLOGON); \
Data.Info.Flags = ((PWLX_NOTIFICATION_INFO)lpvParam)->Flags; \
Data.Info.UserName = ((PWLX_NOTIFICATION_INFO)lpvParam)->UserName; \
Data.Info.Domain = ((PWLX_NOTIFICATION_INFO)lpvParam)->Domain; \
Data.Info.WindowStation = ((PWLX_NOTIFICATION_INFO)lpvParam)->WindowStation; \
Data.Info.hToken = HandleToUlong(((PWLX_NOTIFICATION_INFO)lpvParam)->hToken); \
Data.Info.hDesktop = HandleToUlong(((PWLX_NOTIFICATION_INFO)lpvParam)->hDesktop); \
Data.Info.dwSessionId = NtCurrentPeb()->SessionId; \
\
status = SensNotifyWinlogonEvent(&Data); \
\
if (status) {SensPrintToDebugger(SENS_DBG, (SENSLOGN "SensNotifyWinlogonEvent(0x%x) returned %d\n", _EventType_, status));} \
}
/*****************************************************************************
*
* IsRemoteSession
*
* On a Terminal Server: returns TRUE if current Session is the not the physical
* console , FALSE if it is the console session (SessionId == 0)
*
* ENTRY:
* nothing
*
* EXIT:
* nothing
*
****************************************************************************/
BOOL
IsRemoteSession(VOID)
{
DWORD dwSessionId;
if (ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId))
{
return (dwSessionId != 0);
}
return FALSE;
}
DWORD WINAPI
SensLogonEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Logon Event. In addition, we do the following:
a. Populate our token table with the current token.
b. Initialize The token RPC interface, if necessary.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
PWLX_NOTIFICATION_INFO pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
DUMP_INFO("Logon");
ActiveUserList->Add( pTempInfo );
FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOGON);
return status;
}
DWORD WINAPI
SensLogoffEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Logoff Event. We notify various components
(like OneStop, EventSystem, SENS) of the Logoff event.
Arguments:
lpvParam - Winlogon notification info.
Notes:
a. The system logoff will block till this call returns. Be very
careful in adding code here.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DWORD dwError;
HRESULT hr;
PWLX_NOTIFICATION_INFO pTempInfo;
hr = S_OK;
dwError = 0x0;
pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
LogMessage((SENSLOGN "[%d] Entered Logoff.\n", GetTickCount()));
DUMP_INFO("Logoff");
// Try to fire SENS Event
LogMessage((SENSLOGN "[%d] Notifying SENS...\n", GetTickCount()));
FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOGOFF);
LogMessage((SENSLOGN "[%d] SensNotifyWinlogonEvent(LOGOFF) succeeded.\n", GetTickCount()));
// Start OneStop if necessary, except on Restart.
if ( ((pTempInfo->Flags & EWX_REBOOT) == 0)
&& (IsAutoSyncEnabled(pTempInfo->hToken, AUTOSYNC_ON_LOGOFF)))
{
//
// NOTE: If SENS ever becomes demandstarted on NT5, there are a couple
// of things that can be done:
// o Call StartSensIfNecessary() here. (OR)
// o Make Sens APIs call StartSensIfNecessary().
//
LogMessage((SENSLOGN "[%d] Notifying OneStop...\n", GetTickCount()));
hr = SensNotifyOneStop(pTempInfo->hToken, SYNC_MANAGER_LOGOFF, TRUE);
LogMessage((SENSLOGN "[%d] SensNotifyOneStop() returned 0x%x\n", GetTickCount(), hr));
}
// Notify EventSystem
LogMessage((SENSLOGN "[%d] Notifying EventSystem...\n", GetTickCount()));
hr = SensNotifyEventSystem(NOTIFY_LCE_LOGOFF, lpvParam);
LogMessage((SENSLOGN "[%d] SensNotifyEventSystem() returned 0x%x\n", GetTickCount(), hr));
//
// Remove token handle from the list at the end so that COM activation
// works till SENS gets done with event firings.
//
ActiveUserList->Remove( pTempInfo );
LogMessage((SENSLOGN "Removed current user's token!\n"));
return status;
}
DWORD WINAPI
SensStartupEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Startup Event. Do some token management related
initialization.
Arguments:
lpvParam - Winlogon notification info.
Notes:
a. This occurs very early in the bootup sequence. At this time,
SENS service hasn't yet started up.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DWORD dwLastError;
status = 0x0;
gbIsTokenCodeInitialized = FALSE;
//
// Create the table of logged-in users.
//
ActiveUserList = new USER_LOGON_TABLE( &status );
if (!ActiveUserList || status)
{
delete ActiveUserList;
return ERROR_NOT_ENOUGH_MEMORY;
}
InitializeNotifyInterface();
//
// We are ready to use Token Code.
//
gbIsTokenCodeInitialized = TRUE;
LogMessage((SENSLOGN "**** Token code initialized successfully ****\n"));
//
// Create an Event to indicate the starting of SENS.
//
ghSensStartedEvent = CreateEvent(
NULL, // Specific Security Attributes
TRUE, // Event is ManualReset
FALSE, // Initial state is not Signalled
SENS_STARTED_EVENT
);
if (ghSensStartedEvent == NULL)
{
dwLastError = GetLastError();
LogMessage((SENSLOGN "SensStartupEvent() - CreateEvent() failed - %x.\n",
dwLastError));
}
else
{
LogMessage((SENSLOGN "SensStartedEvent created successfully\n"));
}
DUMP_INFO("Startup");
return status;
}
BOOLEAN
InitializeNotifyInterface(
void
)
/*++
Routine Description:
Initialize RPC interface for accepting calls to GetCurrentUserToken() API.
Arguments:
None.
Return Value:
TRUE, if successful
FALSE, otherwise.
--*/
{
RPC_STATUS status;
if (!IsRemoteSession())
{
status = RpcServerRegisterIfEx(
_GetUserToken_ServerIfHandle,
NULL,
NULL,
0,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
AllowLocalSystem
);
if (RPC_S_OK != status)
{
return FALSE;
}
}
return TRUE;
}
DWORD WINAPI
SensStartShellEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the StartShell Event. We treat this as Logon and notify
various components (OneStop, SENS, EventSystem) of Logon.
Arguments:
lpvParam - Winlogon notification info.
Notes:
a. When this function is called by Winlogon, the shell has begun starting.
There is no guarantee that shell has started completely and is up and
running.
b. We create a thread to do bulk of the work and allow the function
to return.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
BOOL bRetVal;
DWORD status;
DWORD dwLastError;
PWLX_NOTIFICATION_INFO pTempInfo;
PWLX_NOTIFICATION_INFO pDuplicateInfo;
dwLastError = 0;
bRetVal = TRUE;
DUMP_INFO("StartShell");
// Duplicate the parts of the notification info so we can process this
// event on another thread.
pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
SIZE_T sizeUserName = wcslen(pTempInfo->UserName) + 1;
SIZE_T sizeDomain = wcslen(pTempInfo->Domain) + 1;
SIZE_T sizeWinsta = wcslen(pTempInfo->WindowStation) + 1;
//
// Allocate space for the notification block
//
pDuplicateInfo = new WLX_NOTIFICATION_INFO;
if (pDuplicateInfo == NULL)
{
dwLastError = GetLastError();
LogMessage((SENSLOGN "SensStartShellEvent(): new() failed - %x.\n", dwLastError));
return dwLastError;
}
//
// Copy simple types, safely initialize everything in case of failure.
//
pDuplicateInfo->Size = sizeof(WLX_NOTIFICATION_INFO);
pDuplicateInfo->Flags = pTempInfo->Flags;
pDuplicateInfo->hToken = NULL; // duplicated below, closed on error
pDuplicateInfo->hDesktop = NULL; // not duplicated, unused
pDuplicateInfo->pStatusCallback = NULL;
// Allocate space for the string parameters.
pDuplicateInfo->UserName = (PWSTR) new WCHAR[sizeUserName];
pDuplicateInfo->Domain = (PWSTR) new WCHAR[sizeDomain];
pDuplicateInfo->WindowStation = (PWSTR) new WCHAR[sizeWinsta];
if ( (pDuplicateInfo->UserName == NULL)
|| (pDuplicateInfo->Domain == NULL)
|| (pDuplicateInfo->WindowStation == NULL))
{
dwLastError = GetLastError();
LogMessage((SENSLOGN "SensStartShellEvent(): new() of strings failed - %x.\n", dwLastError));
goto Cleanup;
}
//
// Deep copy the parameters
//
StringCchCopy(pDuplicateInfo->UserName, sizeUserName, pTempInfo->UserName);
StringCchCopy(pDuplicateInfo->Domain, sizeDomain, pTempInfo->Domain);
StringCchCopy(pDuplicateInfo->WindowStation, sizeWinsta, pTempInfo->WindowStation);
if ( !DuplicateHandle(GetCurrentProcess(),
pTempInfo->hToken,
GetCurrentProcess(),
&pDuplicateInfo->hToken,
0, // ignored, same access flag set
FALSE,
DUPLICATE_SAME_ACCESS))
{
dwLastError = GetLastError();
LogMessage((SENSLOGN "SensStartShellEvent(): failed to duplicate users token - %x\n", dwLastError));
goto Cleanup;
}
//
// Create a thread to wait on the StartShell event
//
bRetVal = SensQueueUserWorkItem(
(LPTHREAD_START_ROUTINE) SensWaitToStartRoutine,
pDuplicateInfo, // Winlogon event info
SENS_LONG_ITEM // Flags
);
if (FALSE == bRetVal)
{
dwLastError = GetLastError();
LogMessage((SENSLOGN "SensStartShellEvent(): SensQueueUserWorkItem() failed with %x.\n",
dwLastError));
}
// Success - SensWaitToStartRoutine now owns pDuplicateInfo
return 0;
Cleanup:
// All branches here occur after the parameter block is copied and initalized
ASSERT(pDuplicateInfo);
if (pDuplicateInfo->hToken)
{
CloseHandle(pDuplicateInfo->hToken);
}
delete pDuplicateInfo->UserName;
delete pDuplicateInfo->Domain;
delete pDuplicateInfo->WindowStation;
delete pDuplicateInfo;
return dwLastError;
}
DWORD WINAPI
SensPostShellEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Post Shell Event.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DUMP_INFO("Post Shell");
FIRE_EVENT(SENS_NOTIFY_WINLOGON_POSTSHELL);
return status;
}
DWORD WINAPI
SensDisconnectEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Session Disconnect Event.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DUMP_INFO("Session Disconnect");
FIRE_EVENT(SENS_NOTIFY_WINLOGON_SESSION_DISCONNECT);
return status;
}
DWORD WINAPI
SensReconnectEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Session Reconnect Event.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DUMP_INFO("Session Reconnect");
FIRE_EVENT(SENS_NOTIFY_WINLOGON_SESSION_RECONNECT);
return status;
}
DWORD WINAPI
SensShutdownEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Shutdown Event. Do some cleanup.
Arguments:
lpvParam - Winlogon notification info.
Notes:
a. It is guaranteed that COM activation will not work when this event
is received.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
status = ERROR_SUCCESS;
DUMP_INFO("Shutdown");
return status;
}
DWORD WINAPI
SensLockEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Display Lock Event.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DUMP_INFO("Display Lock");
FIRE_EVENT(SENS_NOTIFY_WINLOGON_LOCK);
return status;
}
DWORD WINAPI
SensUnlockEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Display unlock Event.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DUMP_INFO("Display Unlock");
FIRE_EVENT(SENS_NOTIFY_WINLOGON_UNLOCK);
return status;
}
DWORD WINAPI
SensStartScreenSaverEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the ScreenSaver Start Event.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DUMP_INFO("StartScreenSaver");
FIRE_EVENT(SENS_NOTIFY_WINLOGON_STARTSCREENSAVER);
return status;
}
DWORD WINAPI
SensStopScreenSaverEvent(
LPVOID lpvParam
)
/*++
Routine Description:
Hook to trap the Screen Saver Stop Event.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
RPC status from SensNotifyWinlogonEvent()
--*/
{
DWORD status;
DUMP_INFO("StopScreenSaver");
FIRE_EVENT(SENS_NOTIFY_WINLOGON_STOPSCREENSAVER);
return status;
}
DWORD WINAPI
SensWaitToStartRoutine(
LPVOID lpvParam
)
/*++
Routine Description:
This routine implements the work item that is queued when the StartShell
event is received.
Arguments:
lpvParam - Winlogon notification info.
Return Value:
ERROR_SUCCESS, always
--*/
{
DWORD dwError;
DWORD dwWaitStatus;
DWORD status;
HRESULT hr;
PWLX_NOTIFICATION_INFO pTempInfo;
dwError = ERROR_SUCCESS;
dwWaitStatus = 0x0;
pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam;
// Give SENS a chance to start if it has not already stated.
// Give up after a short time in case sens is has been set to manual start
// We could check the service configuration but the thread as already been
// created so we save won't very much.
ASSERT(ghSensStartedEvent);
dwError = WaitForSingleObject(ghSensStartedEvent, 20*1000);
if (dwError != STATUS_WAIT_0)
{
LogMessage((SENSLOGN "[%d] Wait for sens start event timed out...\n", GetTickCount()));
}
// Notify EventSystem
LogMessage((SENSLOGN "[%d] Notifying EventSystem...\n", GetTickCount()));
hr = SensNotifyEventSystem(NOTIFY_LCE_STARTSHELL, lpvParam);
LogMessage((SENSLOGN "[%d] SensNotifyEventSystem() returned 0x%x\n", GetTickCount(), hr));
// Try to fire SENS Event
LogMessage((SENSLOGN "[%d] Notifying SENS...\n", GetTickCount()));
FIRE_EVENT(SENS_NOTIFY_WINLOGON_STARTSHELL);
LogMessage((SENSLOGN "[%d] SensNotifyWinlogonEvent(STARTSHELL) succeeded.\n", GetTickCount()));
// Cleanup
CloseHandle(pTempInfo->hToken);
delete pTempInfo->UserName;
delete pTempInfo->Domain;
delete pTempInfo->WindowStation;
delete pTempInfo;
return ERROR_SUCCESS;
}
HRESULT
SensNotifyEventSystem(
DWORD dwEvent,
LPVOID lpvParam
)
/*++
Routine Description:
This routine notifies EventSystem of the Logon/Logoff events.
Arguments:
dwEvent - Tells if the event is Logon or Logoff.
lpvParam - Winlogon notification info.
Notes:
a. EventSystem's notify routine has been observed sometimes to take
a long time causing Logoff to take longer time to complete.
Return Value:
HRESULT from EventSystem's Notify routine.
--*/
{
HRESULT hr;
hr = S_OK;
PWLX_NOTIFICATION_INFO pTempInfo = (PWLX_NOTIFICATION_INFO)lpvParam;
//
// Notify the COM+ Event System that a user has just logged on.
// Per-user subscriptions will be activated.
//
typedef HRESULT (__stdcall *LPFN_NOTIFICATION)(HANDLE);
HMODULE hDLL;
LPFN_NOTIFICATION lpfnNotify = NULL;
hDLL = (HMODULE) LoadLibrary(EVENTSYSTEM_DLL);
if (hDLL == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
if (dwEvent == NOTIFY_LCE_STARTSHELL)
{
lpfnNotify = (LPFN_NOTIFICATION) GetProcAddress(hDLL, NOTIFY_LCE_LOGONUSER);
}
else
if (dwEvent == NOTIFY_LCE_LOGOFF)
{
lpfnNotify = (LPFN_NOTIFICATION) GetProcAddress(hDLL, NOTIFY_LCE_LOGOFFUSER);
}
hr = (lpfnNotify == NULL) ? HRESULT_FROM_WIN32(GetLastError()) : (*lpfnNotify)(pTempInfo->hToken);
FreeLibrary(hDLL);
}
return hr;
}
#define MAX_WINDOWSTATION_NAME_LENGTH 1000
DWORD
_SecpGetCurrentUserToken(
handle_t Binding,
wchar_t WindowStation[],
unsigned long * pToken,
unsigned long DesiredAccess
)
/*++
Routine Description:
RPC server manager routine. This is the only method in the GetUserToken
interface.
The interface registered a callback function to verify that the caller is
both non-remote and is local system.
Arguments:
Binding - RPC server binding
WindowStation - window station retrive the token from
pToken - Upon return this is the handle ID of the duplicated token in the
callers process
DesiredAccess - Access mask passed directly to the DuplicateHandle() call.
Return Value:
WIN32 ERROR value or 0
--*/
{
HANDLE LocalToken;
HANDLE RemoteToken;
HANDLE RemoteProcess;
unsigned long ProcessId;
if (FALSE == gbIsTokenCodeInitialized)
{
return ERROR_OUTOFMEMORY;
}
//
// Validate arguments. The only one that can cause us harm is the window station.
//
if (IsBadStringPtr( WindowStation, MAX_WINDOWSTATION_NAME_LENGTH))
{
return ERROR_ACCESS_DENIED;
}
if (I_RpcBindingInqLocalClientPID(0, &ProcessId))
{
return ERROR_ACCESS_DENIED;
}
//
// Clone the token into the requested process.
//
LocalToken = ActiveUserList->CurrentUserTokenFromWindowStation( WindowStation );
if (!LocalToken)
{
LogMessage((SENSLOGN "GetCurrentUserToken(): User not logged on!\n"));
return ERROR_NOT_LOGGED_ON;
}
RemoteProcess = OpenProcess(
PROCESS_DUP_HANDLE,
FALSE, // not inheritable
ProcessId
);
if (!RemoteProcess)
{
LogMessage((SENSLOGN "GetCurrentUserToken(): OpenProcess() failed!\n"));
return GetLastError();
}
// Only way to verify that the client process has not exited while waiting for
// the response. (this is to avoid duplicating the handle into another process).
//
// This is done after the OpenProcess() call to keep the PID from being reused before
// we could open the process.
if (RPC_S_OK != RpcImpersonateClient(0))
{
CloseHandle(RemoteProcess);
return ERROR_ACCESS_DENIED;
}
// We have already validated that the caller is local system in the interface callback.
RpcRevertToSelf();
if (!DuplicateHandle(
GetCurrentProcess(),
LocalToken,
RemoteProcess,
&RemoteToken,
DesiredAccess,
FALSE, // not inheritable
0 // no funny options
))
{
LogMessage((SENSLOGN "GetCurrentUserToken(): DuplicateHandle() failed!\n"));
CloseHandle( RemoteProcess );
return GetLastError();
}
CloseHandle( RemoteProcess );
*pToken = HandleToUlong(RemoteToken);
LogMessage((SENSLOGN "GetCurrentUserToken(): Succeeded. Returning 0x%x.\n", *pToken));
return ERROR_SUCCESS;
}
BOOL
USER_LOGON_TABLE::Add(
WLX_NOTIFICATION_INFO * User
)
{
USER_INFO_NODE * Entry;
if (FALSE == gbIsTokenCodeInitialized)
{
return FALSE;
}
CLAIM_MUTEX Lock( Mutex );
Entry = FindInactiveEntry();
if (!Entry)
{
Entry = new USER_INFO_NODE;
if (!Entry)
{
return FALSE;
}
Entry->fActive = FALSE;
InsertTailList( &List, &Entry->Links );
}
Entry->Info.Size = sizeof(WLX_NOTIFICATION_INFO);
Entry->Info.Flags = User->Flags;
Entry->Info.hToken = User->hToken;
SIZE_T sizeUserName = wcslen(User->UserName) + 1;
SIZE_T sizeDomain = wcslen(User->Domain) + 1;
SIZE_T sizeWinsta = wcslen(User->WindowStation) + 1;
WCHAR * Buffer = new WCHAR[sizeUserName + sizeDomain + sizeWinsta];
if (!Buffer)
{
Entry->Info.UserName = 0;
Entry->Info.Domain = 0;
Entry->Info.WindowStation = 0;
return FALSE;
}
//
// This must match the code in Remove().
//
Entry->Info.UserName = Buffer;
Entry->Info.Domain = Entry->Info.UserName+1+wcslen(User->UserName);
Entry->Info.WindowStation = Entry->Info.Domain +1+wcslen(User->Domain);
StringCchCopy(Entry->Info.UserName, sizeUserName, User->UserName);
StringCchCopy(Entry->Info.Domain, sizeDomain, User->Domain);
StringCchCopy(Entry->Info.WindowStation, sizeWinsta, User->WindowStation);
Entry->fActive = TRUE;
return TRUE;
}
BOOL
USER_LOGON_TABLE::Remove(
WLX_NOTIFICATION_INFO * User
)
{
if (FALSE == gbIsTokenCodeInitialized)
{
return FALSE;
}
USER_INFO_NODE * Entry = FromWindowStation( User->WindowStation );
if (Entry)
{
//
// This must match the code in Add().
//
delete Entry->Info.UserName;
Entry->fActive = FALSE;
Mutex.Leave();
return TRUE;
}
Mutex.Leave();
return FALSE;
}
HANDLE
USER_LOGON_TABLE::CurrentUserTokenFromWindowStation(
wchar_t WindowStation[]
)
{
HANDLE Token = NULL;
USER_INFO_NODE * Node = FromWindowStation(WindowStation);
if (Node)
{
Token = Node->Info.hToken;
}
Mutex.Leave();
return Token;
}
USER_INFO_NODE *
USER_LOGON_TABLE::FromWindowStation(
wchar_t WindowStation[]
)
/*++
Note that the mutex is held on exit, to avoid race conditions.
--*/
{
USER_INFO_NODE * Node;
LIST_ENTRY * Link;
Mutex.Enter();
for (Link = List.Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links);
Link != &List;
Link = Link->Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links))
{
if (Node->fActive && 0 == wcscmp(Node->Info.WindowStation, WindowStation))
{
return Node;
}
}
return 0;
}
USER_INFO_NODE *
USER_LOGON_TABLE::FindInactiveEntry(
void
)
{
USER_INFO_NODE * Node;
LIST_ENTRY * Link;
for (Link = List.Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links);
Link != &List;
Link = Link->Flink, Node = CONTAINING_RECORD(Link, USER_INFO_NODE, Links))
{
if (!Node->fActive)
{
return Node;
}
}
return 0;
}
RPC_STATUS RPC_ENTRY
AllowLocalSystem (
IN RPC_IF_HANDLE InterfaceUuid,
IN void *Context
)
{
unsigned fLocal = FALSE;
if (RPC_S_OK != I_RpcBindingIsClientLocal(NULL, &fLocal))
{
return ERROR_ACCESS_DENIED;
}
if (!fLocal)
{
return ERROR_ACCESS_DENIED;
}
if (!IsRpcCallerLocalSystem())
{
return ERROR_ACCESS_DENIED;
}
return RPC_S_OK;
}