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