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.
1707 lines
57 KiB
1707 lines
57 KiB
// --------------------------------------------------------------------------
|
|
// Module Name: ThemeManagerAPIRequest.cpp
|
|
//
|
|
// Copyright (c) 2000, Microsoft Corporation
|
|
//
|
|
// This file contains a class that implements the work for the theme server.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// 2000-11-29 vtan moved to separate file
|
|
// --------------------------------------------------------------------------
|
|
|
|
#include "StandardHeader.h"
|
|
#include "ThemeManagerAPIRequest.h"
|
|
#include "ThemeManagerService.h"
|
|
|
|
#include <LPCThemes.h>
|
|
#include <uxthemep.h>
|
|
#include <UxThemeServer.h>
|
|
|
|
#include "RegistryResources.h"
|
|
#include "SingleThreadedExecution.h"
|
|
#include "StatusCode.h"
|
|
#include "TokenInformation.h"
|
|
|
|
#define STRSAFE_LIB
|
|
#include <strsafe.h>
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Static member variables.
|
|
//
|
|
// History: 2000-11-09 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
CDynamicCountedObjectArray* CThemeManagerAPIRequest::s_pSessionData = NULL;
|
|
CCriticalSection* CThemeManagerAPIRequest::s_pLock = NULL;
|
|
DWORD CThemeManagerAPIRequest::s_dwServerChangeNumber = 0;
|
|
const TCHAR CThemeManagerAPIRequest::s_szServerChangeNumberValue[] = TEXT("ServerChangeNumber");
|
|
|
|
#ifdef DEBUG
|
|
#define PROCESSLOADERWAIT DISPATCHSYNC_TIMEOUT * 10
|
|
#else
|
|
#define PROCESSLOADERWAIT DISPATCHSYNC_TIMEOUT
|
|
#endif DEBUG
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Forward decls
|
|
//
|
|
// History: 2002-02-26 scotthan created
|
|
// --------------------------------------------------------------------------
|
|
inline NTSTATUS _CheckTokenPrivilege( HANDLE hToken, DWORD dwPrivilege )
|
|
{
|
|
CTokenInformation tokenInformation(hToken);
|
|
return tokenInformation.UserHasPrivilege(dwPrivilege) ?
|
|
STATUS_SUCCESS : STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::CThemeManagerAPIRequest
|
|
//
|
|
// Arguments: pAPIDispatcher = CAPIDispatcher that calls this object.
|
|
// pAPIConnection = CAPIConnection for access change.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Constructor for the CThemeManagerAPIRequest class. It just passes the
|
|
// control to the super class.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
CThemeManagerAPIRequest::CThemeManagerAPIRequest (CAPIDispatcher* pAPIDispatcher) :
|
|
CAPIRequest(pAPIDispatcher),
|
|
_hToken(NULL),
|
|
_pSessionData(NULL)
|
|
|
|
{
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::CThemeManagerAPIRequest
|
|
//
|
|
// Arguments: pAPIDispatcher = CAPIDispatcher that calls this object.
|
|
// pAPIConnection = CAPIConnection for access change.
|
|
// portMessage = CPortMessage to copy construct.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Constructor for the CThemeManagerAPIRequest class. It just
|
|
// passes the control to the super class.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
CThemeManagerAPIRequest::CThemeManagerAPIRequest (
|
|
CAPIDispatcher* pAPIDispatcher, const CPortMessage& portMessage)
|
|
: CAPIRequest(pAPIDispatcher, portMessage),
|
|
_hToken(NULL),
|
|
_pSessionData(NULL)
|
|
|
|
{
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::~CThemeManagerAPIRequest
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Destructor for the CThemeManagerAPIRequest class.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
CThemeManagerAPIRequest::~CThemeManagerAPIRequest (void)
|
|
|
|
{
|
|
ASSERTMSG(_hToken == NULL, "Impersonation token not released in CThemeManagerAPIRequest::~CThemeManagerAPIRequest");
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute
|
|
//
|
|
// Arguments: pAPIDispatchSync - allows request execution access to various
|
|
// service notifications and events
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Execute implementation for theme manager API requests. This
|
|
// function dispatches requests based on the API request number.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// 2002-03-11 scotthan add API_THEMES_PROCESSLOADTHEME,
|
|
// API_THEMES_PROCESSASSIGNSECTION handlers
|
|
// 2002-03-24 scotthan add DispatchSync arg
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute (CAPIDispatchSync* pAPIDispatchSync)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
unsigned long ulAPINumber;
|
|
|
|
ulAPINumber = reinterpret_cast<API_THEMES*>(&_data)->apiGeneric.ulAPINumber & API_GENERIC_NUMBER_MASK;
|
|
|
|
// First try and get the client session data. If this fails then
|
|
// there's no object to execute the request on. Fail it.
|
|
// Exception to this is API_THEMES_SESSIONCREATE which creates one.
|
|
|
|
// Note: GetClientSessionData will store the session data in the
|
|
// _pSessionData member variable. While doing so it will increase
|
|
// reference count on this so that it doesn't get pulled from the
|
|
// array while the API request is being executed. The reference is
|
|
// released at the end of this function.
|
|
|
|
status = GetClientSessionData();
|
|
if (NT_SUCCESS(status) || (ulAPINumber == API_THEMES_SESSIONCREATE))
|
|
{
|
|
switch (ulAPINumber)
|
|
{
|
|
case API_THEMES_THEMEHOOKSON:
|
|
status = Execute_ThemeHooksOn();
|
|
break;
|
|
case API_THEMES_THEMEHOOKSOFF:
|
|
status = Execute_ThemeHooksOff();
|
|
break;
|
|
case API_THEMES_GETSTATUSFLAGS:
|
|
status = Execute_GetStatusFlags();
|
|
break;
|
|
case API_THEMES_GETCURRENTCHANGENUMBER:
|
|
status = Execute_GetCurrentChangeNumber();
|
|
break;
|
|
case API_THEMES_GETNEWCHANGENUMBER:
|
|
status = Execute_GetNewChangeNumber();
|
|
break;
|
|
case API_THEMES_SETGLOBALTHEME:
|
|
status = Execute_SetGlobalTheme();
|
|
break;
|
|
case API_THEMES_MARKSECTION:
|
|
status = Execute_MarkSection();
|
|
break;
|
|
case API_THEMES_GETGLOBALTHEME:
|
|
status = Execute_GetGlobalTheme();
|
|
break;
|
|
case API_THEMES_CHECKTHEMESIGNATURE:
|
|
status = Execute_CheckThemeSignature();
|
|
break;
|
|
case API_THEMES_LOADTHEME:
|
|
status = Execute_LoadTheme();
|
|
break;
|
|
case API_THEMES_PROCESSLOADTHEME:
|
|
status = Execute_ProcessLoadTheme(pAPIDispatchSync);
|
|
break;
|
|
case API_THEMES_PROCESSASSIGNSECTION:
|
|
status = Execute_ProcessAssignSection();
|
|
break;
|
|
case API_THEMES_USERLOGON:
|
|
status = Execute_UserLogon();
|
|
break;
|
|
case API_THEMES_USERLOGOFF:
|
|
status = Execute_UserLogoff();
|
|
break;
|
|
case API_THEMES_SESSIONCREATE:
|
|
status = Execute_SessionCreate();
|
|
break;
|
|
case API_THEMES_SESSIONDESTROY:
|
|
status = Execute_SessionDestroy();
|
|
break;
|
|
case API_THEMES_PING:
|
|
status = Execute_Ping();
|
|
break;
|
|
default:
|
|
DISPLAYMSG("Unknown API request in CThemeManagerAPIRequest::Execute");
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If the execution function needed to impersonate the client then
|
|
// revert here and release the token used.
|
|
|
|
if (_hToken != NULL)
|
|
{
|
|
if (RevertToSelf() == FALSE)
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
ReleaseHandle(_hToken);
|
|
}
|
|
|
|
// Release the _pSessionData object now. NULL it out to prevent
|
|
// accidentally using it after being released.
|
|
|
|
if (_pSessionData != NULL)
|
|
{
|
|
_pSessionData->Release();
|
|
_pSessionData = NULL;
|
|
}
|
|
|
|
// Return to caller.
|
|
|
|
TSTATUS(status);
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::SessionDestroy
|
|
//
|
|
// Arguments: dwSessionID = Session ID to destroy.
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: External entry point for session client (winlogon) watcher.
|
|
// When winlogon dies we clean up the session information for
|
|
// that session and release resources.
|
|
//
|
|
// History: 2000-12-09 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::SessionDestroy (DWORD dwSessionID)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
int iIndex;
|
|
CSingleThreadedExecution lock(*s_pLock);
|
|
|
|
iIndex = FindIndexSessionData(dwSessionID);
|
|
if (iIndex >= 0)
|
|
{
|
|
status = s_pSessionData->Remove(iIndex);
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::InitializeServerChangeNumber
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Initializes the static server change number. Every time the
|
|
// service starts up this number is incremented. If the number
|
|
// isn't present then 0 is used.
|
|
//
|
|
// History: 2000-12-09 vtan created
|
|
// 2000-12-09 vtan split from StaticInitialize
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::InitializeServerChangeNumber (void)
|
|
|
|
{
|
|
LONG lErrorCodeOpen, lErrorCodeRead;
|
|
DWORD dwServerChangeNumber;
|
|
CRegKey regKey;
|
|
|
|
dwServerChangeNumber = s_dwServerChangeNumber;
|
|
|
|
// Initialize the static member variable now in case of failure.
|
|
// We ignore failures because at GUI setup the key does NOT exist
|
|
// because the server dll hasn't been regsvr'd yet. After GUI setup
|
|
// this gets regsvr'd and the key exists and we are happy campers.
|
|
|
|
lErrorCodeOpen = regKey.Open(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ThemeManager"),
|
|
KEY_QUERY_VALUE | KEY_SET_VALUE);
|
|
if (ERROR_SUCCESS == lErrorCodeOpen)
|
|
{
|
|
lErrorCodeRead = regKey.GetDWORD(s_szServerChangeNumberValue, dwServerChangeNumber);
|
|
}
|
|
else
|
|
{
|
|
lErrorCodeRead = ERROR_FILE_NOT_FOUND;
|
|
}
|
|
dwServerChangeNumber = static_cast<WORD>(dwServerChangeNumber + 1);
|
|
if ((ERROR_SUCCESS == lErrorCodeOpen) && (ERROR_SUCCESS == lErrorCodeRead))
|
|
{
|
|
TW32(regKey.SetDWORD(s_szServerChangeNumberValue, dwServerChangeNumber));
|
|
}
|
|
s_dwServerChangeNumber = dwServerChangeNumber;
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::StaticInitialize
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Static initializer for the class.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::StaticInitialize (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = STATUS_SUCCESS;
|
|
if (s_pLock == NULL)
|
|
{
|
|
s_pLock = new CCriticalSection;
|
|
if (s_pLock != NULL)
|
|
{
|
|
status = s_pLock->Status();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
delete s_pLock;
|
|
s_pLock = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::StaticTerminate
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Static destructor for the class.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::StaticTerminate (void)
|
|
|
|
{
|
|
if (s_pLock != NULL)
|
|
{
|
|
delete s_pLock;
|
|
s_pLock = NULL;
|
|
}
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::ArrayInitialize
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Initializes (allocates) the session array.
|
|
//
|
|
// History: 2001-01-05 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::ArrayInitialize (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
CSingleThreadedExecution lock(*s_pLock);
|
|
|
|
status = STATUS_SUCCESS;
|
|
if (s_pSessionData == NULL)
|
|
{
|
|
s_pSessionData = new CDynamicCountedObjectArray;
|
|
if (s_pSessionData == NULL)
|
|
{
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::ArrayTerminate
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Releases all objects in the session array (removes the waits)
|
|
// and releases the session array object.
|
|
//
|
|
// History: 2001-01-05 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::ArrayTerminate (void)
|
|
|
|
{
|
|
CSingleThreadedExecution lock(*s_pLock);
|
|
|
|
if (s_pSessionData != NULL)
|
|
{
|
|
int i, iLimit;
|
|
|
|
iLimit = s_pSessionData->GetCount();
|
|
for (i = iLimit - 1; i >= 0; --i)
|
|
{
|
|
TSTATUS(static_cast<CThemeManagerSessionData*>(s_pSessionData->Get(i))->Cleanup());
|
|
TSTATUS(s_pSessionData->Remove(i));
|
|
}
|
|
delete s_pSessionData;
|
|
s_pSessionData = NULL;
|
|
}
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::ImpersonateClientIfRequired
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Impersonates the client if the client is NOT the SYSTEM.
|
|
// There's usually no point impersonating the system unless the
|
|
// token is actually a filtered token.
|
|
//
|
|
// History: 2000-10-19 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::ImpersonateClientIfRequired (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = OpenClientToken(_hToken);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
CTokenInformation tokenInformation(_hToken);
|
|
|
|
if (tokenInformation.IsUserTheSystem())
|
|
{
|
|
ReleaseHandle(_hToken);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else if (ImpersonateLoggedOnUser(_hToken) != FALSE)
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::ClientHasTcbPrivilege
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Returns whether the client has the SE_TCB_PRIVILEGE as a
|
|
// status code.
|
|
//
|
|
// History: 2000-11-09 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::ClientHasTcbPrivilege (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE hTokenClient;
|
|
|
|
if (OpenProcessToken(_pAPIDispatcher->GetClientProcess(),
|
|
TOKEN_QUERY,
|
|
&hTokenClient) != FALSE)
|
|
{
|
|
status = _CheckTokenPrivilege(hTokenClient, SE_TCB_PRIVILEGE);
|
|
|
|
TBOOL(CloseHandle(hTokenClient));
|
|
}
|
|
else
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::FindIndexSessionData
|
|
//
|
|
// Arguments: dwSessionID = Session ID to find.
|
|
//
|
|
// Returns: int
|
|
//
|
|
// Purpose: Iterates the session data array looking for the sessions that
|
|
// matches the given session.
|
|
//
|
|
// History: 2000-11-30 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
int CThemeManagerAPIRequest::FindIndexSessionData (DWORD dwSessionID)
|
|
|
|
{
|
|
int iIndex;
|
|
|
|
iIndex = -1;
|
|
if ((s_pLock != NULL) && (s_pSessionData != NULL))
|
|
{
|
|
int i, iLimit;
|
|
|
|
ASSERTMSG(s_pLock->IsOwned(), "s_pLock must be acquired in CThemeManagerAPIRequest::FindIndexSessionData");
|
|
iLimit = s_pSessionData->GetCount();
|
|
for (i = 0; (iIndex < 0) && (i < iLimit); ++i)
|
|
{
|
|
CThemeManagerSessionData *pSessionData;
|
|
|
|
pSessionData = static_cast<CThemeManagerSessionData*>(s_pSessionData->Get(i));
|
|
if ((pSessionData != NULL) && (pSessionData->EqualSessionID(dwSessionID)))
|
|
{
|
|
iIndex = i;
|
|
}
|
|
}
|
|
}
|
|
return(iIndex);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::GetClientSessionData
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Retrieves the session data associated with the client's
|
|
// session ID. This abstracts the information from uxtheme's
|
|
// loader code and just passes it an object it knows how to deal
|
|
// with.
|
|
//
|
|
// History: 2000-11-09 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::GetClientSessionData (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
int iIndex;
|
|
CSingleThreadedExecution lock(*s_pLock);
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
iIndex = FindIndexSessionData(_pAPIDispatcher->GetClientSessionID());
|
|
if (iIndex >= 0)
|
|
{
|
|
_pSessionData = static_cast<CThemeManagerSessionData*>(s_pSessionData->Get(iIndex));
|
|
if (_pSessionData != NULL)
|
|
{
|
|
_pSessionData->AddRef();
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_pSessionData = NULL;
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_ThemeHooksOn
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_THEMEHOOKSON.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_ThemeHooksOn (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ImpersonateClientIfRequired();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
API_THEMES_THEMEHOOKSON_OUT *pAPIOut;
|
|
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiThemeHooksOn.out;
|
|
pAPIOut->hr = ThemeHooksOn(_pSessionData->GetData());
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_ThemeHooksOff
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_THEMEHOOKSOFF.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_ThemeHooksOff (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ImpersonateClientIfRequired();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
API_THEMES_THEMEHOOKSOFF_OUT *pAPIOut;
|
|
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiThemeHooksOff.out;
|
|
pAPIOut->hr = ThemeHooksOff(_pSessionData->GetData());
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_GetStatusFlags
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_GETSTATUSFLAGS.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_GetStatusFlags (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ImpersonateClientIfRequired();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
DWORD dwFlags;
|
|
API_THEMES_GETSTATUSFLAGS_OUT *pAPIOut;
|
|
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiGetStatusFlags.out;
|
|
dwFlags = QTS_AVAILABLE;
|
|
if (AreThemeHooksActive(_pSessionData->GetData()))
|
|
{
|
|
dwFlags |= QTS_RUNNING;
|
|
}
|
|
pAPIOut->dwFlags = dwFlags;
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_GetCurrentChangeNumber
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_GETCURRENTCHANGENUMBER.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_GetCurrentChangeNumber (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ImpersonateClientIfRequired();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
API_THEMES_GETCURRENTCHANGENUMBER_OUT *pAPIOut;
|
|
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiGetCurrentChangeNumber.out;
|
|
pAPIOut->iChangeNumber = GetCurrentChangeNumber(_pSessionData->GetData());
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_GetNewChangeNumber
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_GETNEWCHANGENUMBER.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_GetNewChangeNumber (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ImpersonateClientIfRequired();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
API_THEMES_GETNEWCHANGENUMBER_OUT *pAPIOut;
|
|
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiGetNewChangeNumber.out;
|
|
pAPIOut->iChangeNumber = GetNewChangeNumber(_pSessionData->GetData());
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_SetGlobalTheme
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_SETGLOBALTHEME.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_SetGlobalTheme (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
// Note: we must not impersonate the user here, since we need write access to the section
|
|
|
|
HANDLE hSection;
|
|
API_THEMES_SETGLOBALTHEME_IN *pAPIIn;
|
|
API_THEMES_SETGLOBALTHEME_OUT *pAPIOut;
|
|
|
|
pAPIIn = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiSetGlobalTheme.in;
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiSetGlobalTheme.out;
|
|
if (pAPIIn->hSection != NULL)
|
|
{
|
|
if (DuplicateHandle(_pAPIDispatcher->GetClientProcess(),
|
|
pAPIIn->hSection,
|
|
GetCurrentProcess(),
|
|
&hSection,
|
|
FILE_MAP_ALL_ACCESS,
|
|
FALSE,
|
|
0) != FALSE)
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hSection = NULL;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
pAPIOut->hr = SetGlobalTheme(_pSessionData->GetData(), hSection);
|
|
if (hSection != NULL)
|
|
{
|
|
TBOOL(CloseHandle(hSection));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pAPIOut->hr = HRESULT_FROM_NT(status);
|
|
}
|
|
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_MarkSection
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_MARKSECTION.
|
|
//
|
|
// History: 2001-05-08 lmouton created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_MarkSection (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
// Note: we must not impersonate the user here, since we need write access to the section
|
|
|
|
HANDLE hSection;
|
|
DWORD dwAdd;
|
|
DWORD dwRemove;
|
|
API_THEMES_MARKSECTION_IN *pAPIIn;
|
|
API_THEMES_MARKSECTION_OUT *pAPIOut;
|
|
|
|
pAPIIn = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiMarkSection.in;
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiMarkSection.out;
|
|
dwAdd = pAPIIn->dwAdd;
|
|
dwRemove = pAPIIn->dwRemove;
|
|
|
|
if (pAPIIn->hSection != NULL)
|
|
{
|
|
if (DuplicateHandle(_pAPIDispatcher->GetClientProcess(),
|
|
pAPIIn->hSection,
|
|
GetCurrentProcess(),
|
|
&hSection,
|
|
FILE_MAP_ALL_ACCESS,
|
|
FALSE,
|
|
0) != FALSE)
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
DISPLAYMSG("Execute_MarkSection: Can't get a write handle");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hSection = NULL;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
if (hSection != NULL)
|
|
{
|
|
MarkSection(hSection, dwAdd, dwRemove);
|
|
TBOOL(CloseHandle(hSection));
|
|
}
|
|
}
|
|
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_GetGlobalTheme
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_GETGLOBALTHEME.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_GetGlobalTheme (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ImpersonateClientIfRequired();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hSection;
|
|
API_THEMES_GETGLOBALTHEME_OUT *pAPIOut;
|
|
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiGetGlobalTheme.out;
|
|
hr = GetGlobalTheme(_pSessionData->GetData(), &hSection);
|
|
if (SUCCEEDED(hr) && (hSection != NULL))
|
|
{
|
|
if (DuplicateHandle(GetCurrentProcess(),
|
|
hSection,
|
|
_pAPIDispatcher->GetClientProcess(),
|
|
&pAPIOut->hSection,
|
|
FILE_MAP_READ,
|
|
FALSE,
|
|
0) != FALSE)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwErrorCode;
|
|
|
|
dwErrorCode = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwErrorCode);
|
|
}
|
|
TBOOL(CloseHandle(hSection));
|
|
}
|
|
pAPIOut->hr = hr;
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// LOADTHEME_STRINGS + supporting functions
|
|
//
|
|
// Purpose: Manages and validates LoadTheme string parameters
|
|
//
|
|
// History: 2002-02-26 scotthan created
|
|
// --------------------------------------------------------------------------
|
|
typedef struct
|
|
{
|
|
LPWSTR pszFilename;
|
|
LPWSTR pszColor;
|
|
LPWSTR pszSize;
|
|
|
|
} LOADTHEME_STRINGS;
|
|
|
|
#define MAX_THEME_STRING MAX_PATH
|
|
|
|
// --------------------------------------------------------------------------
|
|
void _FreeThemeStrings( IN LOADTHEME_STRINGS* plts )
|
|
{
|
|
if( plts )
|
|
{
|
|
_FreeMappedClientString(plts->pszFilename);
|
|
_FreeMappedClientString(plts->pszColor);
|
|
_FreeMappedClientString(plts->pszSize);
|
|
delete plts;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
NTSTATUS _AllocAndMapThemeStrings(
|
|
IN HANDLE hProcessClient,
|
|
IN LPCWSTR pszFilenameIn,
|
|
IN UINT cchFilenameIn,
|
|
IN LPCWSTR pszColorIn,
|
|
IN UINT cchColorIn,
|
|
IN LPCWSTR pszSizeIn,
|
|
IN UINT cchSizeIn,
|
|
OUT LOADTHEME_STRINGS** pplts )
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERTMSG(pplts != NULL, "_AllocAndMapThemeStrings: NULL outbound parameter, LOADTHEME_STRINGS**.");
|
|
ASSERTMSG(hProcessClient != NULL, "_AllocAndMapThemeStrings: NULL process handle.");
|
|
|
|
// note: cchFileNameIn, cchColorIn, cchSizeIn are char counts that include the NULL terminus.
|
|
if( pszFilenameIn && pszColorIn && pszSizeIn &&
|
|
cchFilenameIn > 0 && cchColorIn > 0 && cchSizeIn > 0 &&
|
|
cchFilenameIn <= MAX_THEME_STRING && cchColorIn <= MAX_THEME_STRING && cchSizeIn <= MAX_THEME_STRING )
|
|
{
|
|
*pplts = NULL;
|
|
|
|
LOADTHEME_STRINGS *plts = new LOADTHEME_STRINGS;
|
|
|
|
if( plts != NULL )
|
|
{
|
|
ZeroMemory(plts, sizeof(*plts));
|
|
|
|
status = _AllocAndMapClientString(hProcessClient, pszFilenameIn, cchFilenameIn, MAX_THEME_STRING, &plts->pszFilename);
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
status = _AllocAndMapClientString(hProcessClient, pszColorIn, cchColorIn, MAX_THEME_STRING, &plts->pszColor);
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
status = _AllocAndMapClientString(hProcessClient, pszSizeIn, cchSizeIn, MAX_THEME_STRING, &plts->pszSize);
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
*pplts = plts;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !NT_SUCCESS(status) )
|
|
{
|
|
_FreeThemeStrings(plts);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_CheckThemeSignature
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_CHECKTHEMESIGNATURE.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_CheckThemeSignature (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ImpersonateClientIfRequired();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
API_THEMES_CHECKTHEMESIGNATURE_IN *pAPIIn;
|
|
API_THEMES_CHECKTHEMESIGNATURE_OUT *pAPIOut;
|
|
LPWSTR pszThemeFileName;
|
|
|
|
pAPIIn = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiCheckThemeSignature.in;
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiCheckThemeSignature.out;
|
|
|
|
status = _AllocAndMapClientString(_pAPIDispatcher->GetClientProcess(),
|
|
pAPIIn->pszName,
|
|
pAPIIn->cchName,
|
|
MAX_PATH,
|
|
&pszThemeFileName);
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
pAPIOut->hr = CheckThemeSignature(pszThemeFileName);
|
|
status = STATUS_SUCCESS;
|
|
|
|
_FreeMappedClientString(pszThemeFileName);
|
|
}
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_LoadTheme
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_LOADTHEME.
|
|
//
|
|
// History: 2000-10-10 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_LoadTheme (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
BOOL fTcb = NT_SUCCESS(ClientHasTcbPrivilege());
|
|
|
|
|
|
status = ImpersonateClientIfRequired();
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
HANDLE hProcessClient;
|
|
API_THEMES_LOADTHEME_IN *pAPIIn;
|
|
API_THEMES_LOADTHEME_OUT *pAPIOut;
|
|
LOADTHEME_STRINGS* plts;
|
|
|
|
hProcessClient = _pAPIDispatcher->GetClientProcess();
|
|
pAPIIn = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiLoadTheme.in;
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiLoadTheme.out;
|
|
|
|
status = _AllocAndMapThemeStrings( hProcessClient, pAPIIn->pszName, pAPIIn->cchName,
|
|
pAPIIn->pszColor, pAPIIn->cchColor,
|
|
pAPIIn->pszSize, pAPIIn->cchSize,
|
|
&plts );
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
HANDLE hSectionIn, hSectionOut;
|
|
|
|
if (DuplicateHandle(hProcessClient,
|
|
pAPIIn->hSection,
|
|
GetCurrentProcess(),
|
|
&hSectionIn,
|
|
FILE_MAP_ALL_ACCESS,
|
|
FALSE,
|
|
0) != FALSE)
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
|
|
// Only clients with TCB privilege can load a global theme section.
|
|
// We don't want stock object ownership here; let the client clean them up on failure.
|
|
DWORD dwLoadFlags = fTcb ? LTF_GLOBALPRIVILEGEDCLIENT : 0;
|
|
|
|
// Warning: this function will revert to self in order to create the section in system context.
|
|
// Impersonate the user again after it if needed
|
|
pAPIOut->hr = LoadTheme(_pSessionData->GetData(), hSectionIn, &hSectionOut,
|
|
plts->pszFilename, plts->pszColor, plts->pszSize, dwLoadFlags);
|
|
|
|
if (SUCCEEDED(pAPIOut->hr))
|
|
{
|
|
// Still running in the system context here
|
|
if (DuplicateHandle(GetCurrentProcess(),
|
|
hSectionOut,
|
|
hProcessClient,
|
|
&pAPIOut->hSection,
|
|
FILE_MAP_READ,
|
|
FALSE,
|
|
0) == FALSE)
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
TBOOL(CloseHandle(hSectionOut));
|
|
}
|
|
TBOOL(CloseHandle(hSectionIn));
|
|
}
|
|
else
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
|
|
_FreeThemeStrings(plts);
|
|
}
|
|
}
|
|
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_ProcessLoadTheme
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_PROCESSLOADTHEME.
|
|
//
|
|
// History: 2002-02-26 scotthan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_ProcessLoadTheme(
|
|
CAPIDispatchSync* pAPIDispatchSync)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
CLoaderProcess *pLoader = NULL;
|
|
API_THEMES_PROCESSLOADTHEME_IN *pAPIIn;
|
|
API_THEMES_PROCESSLOADTHEME_OUT *pAPIOut;
|
|
HANDLE hProcessClient;
|
|
HANDLE hLoaderProcess = NULL;
|
|
|
|
s_pLock->Acquire();
|
|
|
|
pAPIIn = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiProcessLoadTheme.in;
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiProcessLoadTheme.out;
|
|
hProcessClient = _pAPIDispatcher->GetClientProcess();
|
|
|
|
if( !CAPIDispatchSync::IsServiceStopping(pAPIDispatchSync) )
|
|
{
|
|
status = _pSessionData->GetLoaderProcess(&pLoader);
|
|
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
status =
|
|
// do we already have a loader?
|
|
status = pLoader->IsAlive() ? STATUS_ACCESS_DENIED : STATUS_SUCCESS;
|
|
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
status = ImpersonateClientIfRequired();
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
LOADTHEME_STRINGS* plts;
|
|
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
status = _AllocAndMapThemeStrings( hProcessClient,
|
|
pAPIIn->pszName, pAPIIn->cchName,
|
|
pAPIIn->pszColor, pAPIIn->cchColor,
|
|
pAPIIn->pszSize, pAPIIn->cchSize,
|
|
&plts );
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
HANDLE hTokenClient;
|
|
|
|
if( OpenProcessToken(hProcessClient,
|
|
TOKEN_ASSIGN_PRIMARY| TOKEN_DUPLICATE | TOKEN_QUERY,
|
|
&hTokenClient) )
|
|
{
|
|
// SECURITY: Launch process with client credentials to load the theme.
|
|
status = pLoader->Create(_pSessionData->GetData(), hTokenClient, NULL,
|
|
plts->pszFilename, plts->pszColor, plts->pszSize,
|
|
&hLoaderProcess);
|
|
CloseHandle(hTokenClient);
|
|
|
|
}
|
|
else
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
|
|
_FreeThemeStrings(plts);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // !CThemeManagerService::'()
|
|
{
|
|
status = STATUS_PORT_DISCONNECTED;
|
|
}
|
|
|
|
s_pLock->Release();
|
|
|
|
pAPIOut->hSection = NULL;
|
|
pAPIOut->hr = E_FAIL;
|
|
|
|
|
|
// If we launched a loader process, block until its finished
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
ASSERTMSG(hLoaderProcess != NULL, "CThemeManagerAPIRequest::Execute_ProcessLoadTheme - NULL loader process.");
|
|
|
|
HANDLE hStopEvent = CAPIDispatchSync::GetServiceStoppingEvent(pAPIDispatchSync);
|
|
ASSERTMSG(hStopEvent != NULL, "CThemeManagerAPIRequest::Execute_ProcessLoadTheme - NULL Stop event");
|
|
|
|
HANDLE rgHandles[2];
|
|
|
|
rgHandles[0] = hLoaderProcess;
|
|
rgHandles[1] = hStopEvent;
|
|
|
|
// paranoia: assign default status in case we fall out
|
|
status = STATUS_REQUEST_ABORTED;
|
|
|
|
DWORD dwWait = WaitForMultipleObjects(ARRAYSIZE(rgHandles), rgHandles, FALSE, PROCESSLOADERWAIT);
|
|
|
|
switch(dwWait)
|
|
{
|
|
case WAIT_OBJECT_0: // hLoaderProcess
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case WAIT_OBJECT_0+1: // hStopEvent
|
|
status = STATUS_PORT_DISCONNECTED;
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
status = STATUS_TIMEOUT;
|
|
DISPLAYMSG("Execute_ProcessLoadTheme - Timed out waiting for loader process.");
|
|
break;
|
|
}
|
|
|
|
// default the LPC return code to current status code
|
|
pAPIOut->hr = HRESULT_FROM_NT(status);
|
|
|
|
// By the time the process is finished, we'll have a theme memory section
|
|
// stored in the loader process object, transacted via API_THEMES_PROCESSASSIGNSECTION.
|
|
// Let's fetch it and hand it back to our caller.
|
|
|
|
s_pLock->Acquire();
|
|
|
|
NTSTATUS statusLoader = _pSessionData->GetLoaderProcess(&pLoader);
|
|
|
|
if( NT_SUCCESS(statusLoader) )
|
|
{
|
|
HANDLE hSectionOut = pLoader->GetSectionHandle(TRUE);
|
|
|
|
// did we unblock from the loader?
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
pAPIOut->hr = pLoader->GetHResult();
|
|
|
|
#ifdef DEBUG
|
|
if( SUCCEEDED(pAPIOut->hr) )
|
|
{
|
|
ASSERTMSG(hSectionOut != NULL, "CThemeManagerAPIRequest::Execute_ProcessLoadTheme - Success means valid section handle!");
|
|
}
|
|
#endif DEBUG
|
|
|
|
if( hSectionOut )
|
|
{
|
|
BOOL fDuped = DuplicateHandle(GetCurrentProcess(),
|
|
hSectionOut,
|
|
hProcessClient,
|
|
&pAPIOut->hSection,
|
|
FILE_MAP_READ,
|
|
FALSE,
|
|
0);
|
|
|
|
// Still running in the system context here
|
|
if( !fDuped )
|
|
{
|
|
// couldn't duplicate handle. This means we'll never clean stock objects.
|
|
ASSERTMSG(fDuped, "Failed to duplicate theme handle; leaking visual style stock objects");
|
|
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
pAPIOut->hr = HRESULT_FROM_NT(status);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERTMSG(pAPIOut->hr == HRESULT_FROM_NT(status),
|
|
"CThemeManagerAPIRequest::Execute_ProcessLoadTheme - failing to preserve proper status errror code.");
|
|
|
|
if( hSectionOut )
|
|
{
|
|
THR(ServiceClearStockObjects(_pSessionData->GetData(), hSectionOut));
|
|
pAPIOut->hSection = NULL;
|
|
}
|
|
}
|
|
|
|
if( hSectionOut )
|
|
{
|
|
CloseHandle(hSectionOut);
|
|
}
|
|
|
|
// prepare the loader object for the next request.
|
|
pLoader->Clear(_pSessionData->GetData(), TRUE);
|
|
}
|
|
else // NT_SUCCESS(_pSessionData->GetLoaderProcess).
|
|
{
|
|
status = statusLoader;
|
|
pAPIOut->hr = HRESULT_FROM_NT(status);
|
|
}
|
|
|
|
s_pLock->Release();
|
|
}
|
|
else
|
|
{
|
|
pAPIOut->hr = HRESULT_FROM_NT(status);
|
|
}
|
|
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_ProcessAssignSection
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_PROCESSASSIGNSECTION.
|
|
//
|
|
// History: 2002-02-26 scotthan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_ProcessAssignSection (void)
|
|
{
|
|
// Note: The following must be true for this part of the
|
|
// Load/ApplySecureTheme sequence to be truly secure:
|
|
//
|
|
// 1. There is a theme service worker thread handling API_THEMES_PROCESSLOADTHEME
|
|
// now. That handler launched a secure session loader process,
|
|
// 2. The API_THEMES_PROCESSLOADTHEME handler's thread is waiting for
|
|
// secure session loader process to terminate.
|
|
// 3. The only process that should be sending the API_THEMES_PROCESSASSIGNSECTION request
|
|
// is the same secure session loader process.
|
|
|
|
// _data is a hippo-union; store off in params to init out params
|
|
API_THEMES_PROCESSASSIGNSECTION_IN *pAPIIn;
|
|
|
|
pAPIIn = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiProcessAssignSection.in;
|
|
HRESULT hrClient = pAPIIn->hrLoad;
|
|
HANDLE hClientSection = pAPIIn->hSection;
|
|
|
|
// init out params
|
|
API_THEMES_PROCESSASSIGNSECTION_OUT *pAPIOut;
|
|
|
|
pAPIOut = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiProcessAssignSection.out;
|
|
pAPIOut->hr = E_FAIL;
|
|
|
|
// all of this takes place under the session data lock.
|
|
s_pLock->Acquire();
|
|
|
|
CLoaderProcess* pLoader = NULL;
|
|
NTSTATUS status = _pSessionData->GetLoaderProcess(&pLoader);
|
|
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
HANDLE hProcessClient = _pAPIDispatcher->GetClientProcess();
|
|
if( pLoader->IsProcessLoader(hProcessClient) )
|
|
{
|
|
// manage errors as nt status codes until the very end.
|
|
status = hrClient & ~FACILITY_NT_BIT;
|
|
|
|
// any work to do?
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
status = ImpersonateClientIfRequired();
|
|
|
|
if( NT_SUCCESS(status) )
|
|
{
|
|
HANDLE hSectionReadWrite = NULL;
|
|
// Map the incoming read-write section handle to
|
|
// theme service's address space
|
|
if (DuplicateHandle(hProcessClient,
|
|
hClientSection,
|
|
GetCurrentProcess(),
|
|
&hSectionReadWrite,
|
|
FILE_MAP_ALL_ACCESS,
|
|
FALSE,
|
|
0) != FALSE)
|
|
{
|
|
// Copy the incoming read-write section to a read-only section, update the theme change count
|
|
|
|
// Warning: this function will revert to self in order to create the
|
|
// section in the system context. Impersonate the user again after it if needed
|
|
|
|
HANDLE hSectionReadOnly = NULL;
|
|
status = pLoader->ValidateAndCopySection(_pSessionData->GetData(),
|
|
hSectionReadWrite,
|
|
&hSectionReadOnly);
|
|
|
|
// no longer don't need our dupe of the incoming, read-write section.
|
|
CloseHandle(hSectionReadWrite);
|
|
}
|
|
else // DuplicateHandle
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
pLoader->SetHResult(HRESULT_FROM_NT(status));
|
|
}
|
|
}
|
|
else // NT_SUCCESS(ImpersonateClientIfRequired)
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
pLoader->SetHResult(HRESULT_FROM_NT(status));
|
|
}
|
|
}
|
|
else // SUCCEEDED(hrClient)
|
|
{
|
|
pLoader->SetHResult(HRESULT_FROM_NT(status));
|
|
DISPLAYMSG("CThemeManagerAPIRequest::Execute_ProcessAssignSection: client failed section creation");
|
|
}
|
|
}
|
|
else // CLoaderProcess::IsProcessLoader
|
|
{
|
|
status = E_ACCESSDENIED;
|
|
DISPLAYMSG("CThemeManagerAPIRequest::Execute_ProcessAssignSection::IsProcessLoader failed");
|
|
}
|
|
}
|
|
|
|
pAPIOut->hr = HRESULT_FROM_NT(status);
|
|
|
|
s_pLock->Release();
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_UserLogon
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_USERLOGON. To call this API you must have
|
|
// the SE_TCB_PRIVILEGE in your token.
|
|
//
|
|
// History: 2000-10-12 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_UserLogon (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ClientHasTcbPrivilege();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
HANDLE hToken;
|
|
API_THEMES_USERLOGON_IN *pAPIIn;
|
|
|
|
pAPIIn = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiUserLogon.in;
|
|
if (DuplicateHandle(_pAPIDispatcher->GetClientProcess(),
|
|
pAPIIn->hToken,
|
|
GetCurrentProcess(),
|
|
&hToken,
|
|
0,
|
|
FALSE,
|
|
DUPLICATE_SAME_ACCESS) != FALSE)
|
|
{
|
|
status = _pSessionData->UserLogon(hToken);
|
|
TBOOL(CloseHandle(hToken));
|
|
}
|
|
else
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_UserLogoff
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_USERLOGOFF. To call this API you must have
|
|
// the SE_TCB_PRIVILEGE in your token.
|
|
//
|
|
// History: 2000-10-12 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_UserLogoff (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ClientHasTcbPrivilege();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = _pSessionData->UserLogoff();
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_SessionCreate
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_SESSIONCREATE. To call this API you must
|
|
// have the SE_TCB_PRIVILEGE in your token.
|
|
//
|
|
// History: 2000-11-09 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_SessionCreate (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ClientHasTcbPrivilege();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
HANDLE hProcessClient;
|
|
CThemeManagerSessionData *pSessionData;
|
|
|
|
ASSERTMSG(_pSessionData == NULL, "Session data already exists in CThemeManagerAPIRequest::Execute_SessionCreate");
|
|
if (DuplicateHandle(GetCurrentProcess(),
|
|
_pAPIDispatcher->GetClientProcess(),
|
|
GetCurrentProcess(),
|
|
&hProcessClient,
|
|
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE,
|
|
FALSE,
|
|
0) != FALSE)
|
|
{
|
|
DWORD dwSessionID;
|
|
|
|
dwSessionID = _pAPIDispatcher->GetClientSessionID();
|
|
pSessionData = new CThemeManagerSessionData(dwSessionID);
|
|
if (pSessionData != NULL)
|
|
{
|
|
API_THEMES_SESSIONCREATE_IN *pAPIIn;
|
|
|
|
pAPIIn = &reinterpret_cast<API_THEMES*>(&_data)->apiSpecific.apiSessionCreate.in;
|
|
status = pSessionData->Allocate(hProcessClient,
|
|
s_dwServerChangeNumber,
|
|
pAPIIn->pfnRegister,
|
|
pAPIIn->pfnUnregister,
|
|
pAPIIn->pfnClearStockObjects,
|
|
pAPIIn->dwStackSizeReserve,
|
|
pAPIIn->dwStackSizeCommit);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
int iIndex;
|
|
CSingleThreadedExecution lock(*s_pLock);
|
|
|
|
// Find the session data in the static array. If found
|
|
// then remove the entry (don't allow duplicates).
|
|
|
|
iIndex = FindIndexSessionData(dwSessionID);
|
|
if (iIndex >= 0)
|
|
{
|
|
status = s_pSessionData->Remove(iIndex);
|
|
}
|
|
|
|
// If the static array has been destroyed (the service has been
|
|
// stopped) then don't do anything - this is not an error.
|
|
|
|
if (NT_SUCCESS(status) && (s_pSessionData != NULL))
|
|
{
|
|
status = s_pSessionData->Add(pSessionData);
|
|
}
|
|
}
|
|
pSessionData->Release();
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
TBOOL(CloseHandle(hProcessClient));
|
|
}
|
|
else
|
|
{
|
|
status = CStatusCode::StatusCodeOfLastError();
|
|
}
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_SessionDestroy
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_SESSIONDESTROY. To call this API you must
|
|
// have the SE_TCB_PRIVILEGE in your token.
|
|
//
|
|
// History: 2000-11-09 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_SessionDestroy (void)
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = ClientHasTcbPrivilege();
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
int iIndex;
|
|
CSingleThreadedExecution lock(*s_pLock);
|
|
|
|
iIndex = FindIndexSessionData(_pAPIDispatcher->GetClientSessionID());
|
|
if (iIndex >= 0)
|
|
{
|
|
status = s_pSessionData->Remove(iIndex);
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CThemeManagerAPIRequest::Execute_Ping
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: NTSTATUS
|
|
//
|
|
// Purpose: Handles API_THEMES_PING. Tell the client we're alive.
|
|
//
|
|
// History: 2000-11-30 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
NTSTATUS CThemeManagerAPIRequest::Execute_Ping (void)
|
|
|
|
{
|
|
SetDataLength(sizeof(API_THEMES));
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|