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