windows-nt/Source/XPSP1/NT/com/mobile/sens/conn/senslogn/senslogn.cxx
2020-09-26 16:20:57 +08:00

1471 lines
32 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}