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;
|
|||
|
}
|
|||
|
|