1471 lines
32 KiB
C++
1471 lines
32 KiB
C++
/*++
|
||
|
||
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;
|
||
}
|
||
|