|
|
/*++
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 "irnotify.h"
#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 NOTIFY_IR_LOGONUSER "OnUserLogon"
#define NOTIFY_IR_LOGOFFUSER "OnUserLogoff"
#define NOTIFY_IR_INIT "InitializeDll"
#define SENS_SERVICE SENS_STRING("SENS")
#define EVENTSYSTEM_DLL SENS_STRING("ES.DLL")
#define IR_DLL SENS_STRING("IRNOTIFY.DLL")
#define SENS_STARTED_EVENT SENS_STRING("SENS Started Event")
//
// Globals
//
PWLX_NOTIFICATION_INFO gpStartShellInfo; HANDLE ghSensStartedEvent; MUTEX * SetupMutex; BOOL gbIsTokenCodeInitialized;
// For GetCurrentUserToken
PSID LocalSystemSid; USER_LOGON_TABLE * ActiveUserList;
// For IR notification of logon/logoff
RPC_BINDING_HANDLE g_hIrxfer;
//
// Some useful Macros
//
#ifdef DETAIL_DEBUG
#define DUMP_INFO(_EventType_) \
\ char buf[512]; \ 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 - %s\n", UnicodeToAnsi(pInfo->UserName, buf))); \ LogMessage((" Domain - %s\n", UnicodeToAnsi(pInfo->Domain, buf))); \ LogMessage((" WinStation - %s\n", UnicodeToAnsi(pInfo->WindowStation, buf))); \ 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"));
//
// Functions
//
PCHAR UnicodeToAnsi( PWSTR in, PCHAR out ) { PCHAR pSave = out;
if (in == NULL) { return "<NULL>"; }
if (*in == (WCHAR)'\0') { return "<Null String>"; }
while( *out++ = (CHAR)*in++) ;
return pSave; }
#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) * On non-Hydra NT: always returns FALSE * * ENTRY: * nothing * * EXIT: * nothing * ****************************************************************************/
typedef BOOL (__stdcall * PFNPROCESSIDTOSESSIONID)(DWORD, PDWORD); #define PFN_FIRSTTIME (PFNPROCESSIDTOSESSIONID(-1))
BOOL IsRemoteSession(VOID) { static PFNPROCESSIDTOSESSIONID s_pfn = PFN_FIRSTTIME; static BOOL bCachedIsRemoteSession = FALSE;
DWORD dwSessionId;
if (PFN_FIRSTTIME == s_pfn) { HINSTANCE hinst = GetModuleHandle(L"KERNEL32.DLL");
if (hinst) { s_pfn = (PFNPROCESSIDTOSESSIONID)GetProcAddress(hinst, "ProcessIdToSessionId"); } else { s_pfn = NULL; } }
if (s_pfn && s_pfn(GetCurrentProcessId(), &dwSessionId)) { bCachedIsRemoteSession = (dwSessionId != 0); }
// we set s_pfn = NULL to guarntee we only ever call ProcessIdToSessionId
// once, and after that we just use the bCachedIsRemoteSession value
s_pfn = NULL;
return bCachedIsRemoteSession; }
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 IR, 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()));
// Notify IR
LogMessage((SENSLOGN "[%d] Notifying IR...\n", GetTickCount())); OnUserLogoff( pTempInfo ); LogMessage((SENSLOGN "[%d] OnUserLogoff() succeeded, notified IR.\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 a SID representing the Local System account.
//
SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY;
status = RtlAllocateAndInitializeSid( &Authority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &LocalSystemSid ); if (!NT_SUCCESS(status)) { return RtlNtStatusToDosError(status); }
//
// Create the table of logged-in users.
//
ActiveUserList = new USER_LOGON_TABLE( &status ); if (!ActiveUserList || status) { delete ActiveUserList; return ERROR_NOT_ENOUGH_MEMORY; }
SetupMutex = new MUTEX( &status ); if (!SetupMutex || status) { delete SetupMutex; 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.
--*/ { unsigned i; DWORD status;
SetupMutex->Enter();
//
// Register the interface for GetCurrentUserToken().
//
status = RpcServerRegisterAuthInfo( NULL, RPC_C_AUTHN_WINNT, NULL, NULL ); if (status) { SetupMutex->Leave(); return FALSE; }
status = RpcServerUseAllProtseqsIf( RPC_C_PROTSEQ_MAX_REQS_DEFAULT, _GetUserToken_ServerIfHandle, NULL ); if (status) { SetupMutex->Leave(); return FALSE; }
//
// We expect another part of the process has already called RpcServerListen.
//
status = RpcServerRegisterIfEx( _GetUserToken_ServerIfHandle, NULL, NULL, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, AllowLocalSystem ); if (status) { SetupMutex->Leave(); return FALSE; }
if (!IsRemoteSession()) { //
// Make a handle to the Infrared Monitor app.
//
RPC_BINDING_HANDLE hServer; status = RpcBindingFromStringBinding(L"ncalrpc:[,security=impersonation dynamic false]", &hServer); if (status) { SetupMutex->Leave(); return FALSE; }
RPC_SECURITY_QOS RpcSecQos;
RpcSecQos.Version= RPC_C_SECURITY_QOS_VERSION_1; RpcSecQos.ImpersonationType= RPC_C_IMP_LEVEL_IMPERSONATE; RpcSecQos.IdentityTracking= RPC_C_QOS_IDENTITY_DYNAMIC; RpcSecQos.Capabilities= RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
status= RpcBindingSetAuthInfoEx(hServer, L"NT Authority\\System", RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_WINNT, NULL, RPC_C_AUTHZ_NONE, (RPC_SECURITY_QOS *)&RpcSecQos); if (RPC_S_OK != status) { RpcBindingFree(&hServer); SetupMutex->Leave(); return FALSE; }
g_hIrxfer = hServer; }
SetupMutex->Leave(); return TRUE; }
DWORD WINAPI SensStartShellEvent( LPVOID lpvParam ) /*++
Routine Description:
Hook to trap the StartShell Event. We treat this as Logon and notify various components (IR, 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;
dwLastError = 0; bRetVal = TRUE;
DUMP_INFO("StartShell");
//
// Allocate space for the parameters
//
pTempInfo = (PWLX_NOTIFICATION_INFO) lpvParam; gpStartShellInfo = (PWLX_NOTIFICATION_INFO) new char[(sizeof(WLX_NOTIFICATION_INFO))]; if (gpStartShellInfo == NULL) { dwLastError = GetLastError(); LogMessage((SENSLOGN "SensStartShellEvent(): new() failed - %x.\n", dwLastError)); return dwLastError; } memcpy(gpStartShellInfo, pTempInfo, sizeof(WLX_NOTIFICATION_INFO));
// String in WLX_NOTIFICATION_INFO are Unicode
gpStartShellInfo->UserName = (PWSTR) new WCHAR[(wcslen(pTempInfo->UserName) + 1)]; gpStartShellInfo->Domain = (PWSTR) new WCHAR[(wcslen(pTempInfo->Domain) + 1)]; gpStartShellInfo->WindowStation = (PWSTR) new WCHAR[(wcslen(pTempInfo->WindowStation) + 1)]; if ( (gpStartShellInfo->UserName == NULL) || (gpStartShellInfo->Domain == NULL) || (gpStartShellInfo->WindowStation == NULL)) { dwLastError = GetLastError(); LogMessage((SENSLOGN "SensStartShellEvent(): new() of strings failed - %x.\n", dwLastError)); delete gpStartShellInfo->UserName; delete gpStartShellInfo->Domain; delete gpStartShellInfo->WindowStation; delete gpStartShellInfo; gpStartShellInfo = NULL; return dwLastError; }
//
// Copy the parameters
//
wcscpy(gpStartShellInfo->UserName, pTempInfo->UserName); wcscpy(gpStartShellInfo->Domain, pTempInfo->Domain); wcscpy(gpStartShellInfo->WindowStation, pTempInfo->WindowStation);
//
// Create a thread to wait on the StartShell event
//
bRetVal = SensQueueUserWorkItem( (LPTHREAD_START_ROUTINE) SensWaitToStartRoutine, gpStartShellInfo, // Winlogon event info
SENS_LONG_ITEM // Flags
); if (FALSE == bRetVal) { dwLastError = GetLastError(); LogMessage((SENSLOGN "SensStartShellEvent(): SensQueueUserWorkItem() failed with %x.\n", dwLastError));
// Cleanup
delete gpStartShellInfo->UserName; delete gpStartShellInfo->Domain; delete gpStartShellInfo->WindowStation; delete gpStartShellInfo; gpStartShellInfo = NULL; }
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));
// Notify IR
LogMessage((SENSLOGN "[%d] Notifying IR...\n", GetTickCount())); OnUserLogon( pTempInfo ); LogMessage((SENSLOGN "[%d] OnUserLogon succeeded.\n", GetTickCount()));
// 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
delete pTempInfo->UserName; delete pTempInfo->Domain; delete pTempInfo->WindowStation; delete pTempInfo; gpStartShellInfo = NULL;
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; }
void OnUserLogon( WLX_NOTIFICATION_INFO * User ) { DWORD status = 0;
if (FALSE == gbIsTokenCodeInitialized) { return; }
if (IsRemoteSession()) { return; }
if (!ImpersonateLoggedOnUser( User->hToken )) { return; }
UserLoggedOn( g_hIrxfer, &status );
RevertToSelf(); }
void OnUserLogoff( WLX_NOTIFICATION_INFO * User ) { DWORD status;
if (FALSE == gbIsTokenCodeInitialized) { return; }
if (IsRemoteSession()) { return; }
if (!ImpersonateLoggedOnUser( User->hToken )) { return; }
UserLoggedOff( g_hIrxfer, &status );
RevertToSelf(); }
#define MAX_WINDOWSTATION_NAME_LENGTH 1000
DWORD _SecpGetCurrentUserToken( handle_t Binding, wchar_t WindowStation[], unsigned long ProcessId, unsigned long * pToken, unsigned long DesiredAccess ) { HANDLE LocalToken; HANDLE RemoteToken; HANDLE RemoteProcess;
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; }
//
// 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(); }
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;
WCHAR * Buffer = new WCHAR[ 1+wcslen(User->UserName) + 1+wcslen(User->Domain) + 1+wcslen(User->WindowStation) ]; 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);
wcscpy(Entry->Info.UserName, User->UserName); wcscpy(Entry->Info.Domain, User->Domain); wcscpy(Entry->Info.WindowStation, 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 ) { if (RpcImpersonateClient(Context)) { return ERROR_ACCESS_DENIED; }
//
// Clone the user's token so we can launch apps on the desktop.
//
HANDLE ImpersonationToken;
if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, // use process token for access check
&ImpersonationToken )) { return GetLastError(); }
//
// Get the SID from the token.
//
DWORD SizeNeeded = 0; TOKEN_USER * TokenData = NULL;
// Get the size first.
if (!GetTokenInformation( ImpersonationToken, TokenUser, 0, 0, &SizeNeeded )) { DWORD dwLastError = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != dwLastError) { CloseHandle( ImpersonationToken ); return dwLastError; } }
__try { TokenData = (TOKEN_USER *) _alloca( SizeNeeded ); } __except(EXCEPTION_EXECUTE_HANDLER) { // Nothing
}
if (!TokenData) { CloseHandle( ImpersonationToken ); return ERROR_NOT_ENOUGH_MEMORY; }
if (!GetTokenInformation( ImpersonationToken, TokenUser, TokenData, SizeNeeded, &SizeNeeded )) { CloseHandle( ImpersonationToken ); return GetLastError(); }
CloseHandle(ImpersonationToken);
if (!RtlEqualSid( TokenData->User.Sid, LocalSystemSid )) { return ERROR_ACCESS_DENIED; }
return 0; }
|