windows-nt/Source/XPSP1/NT/shell/services/themesrv/thememanagerservice.cpp

273 lines
8.7 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// --------------------------------------------------------------------------
// Module Name: ThemeManagerService.cpp
//
// Copyright (c) 2000, Microsoft Corporation
//
// This file contains a class that implements the theme server service
// specifics.
//
// History: 2000-11-29 vtan created
// --------------------------------------------------------------------------
#include "StandardHeader.h"
#include "ThemeManagerService.h"
#include <lpcthemes.h>
#include <winsta.h>
#include "Access.h"
#include "StatusCode.h"
const TCHAR CThemeManagerService::s_szName[] = TEXT("Themes");
// --------------------------------------------------------------------------
// CThemeManagerService::CThemeManagerService
//
// Arguments: pAPIConnection = CAPIConnection passed to base class.
// pServerAPI = CServerAPI passed to base class.
//
// Returns: <none>
//
// Purpose: Constructor for CThemeManagerService.
//
// History: 2000-11-29 vtan created
// --------------------------------------------------------------------------
CThemeManagerService::CThemeManagerService (CAPIConnection *pAPIConnection, CServerAPI *pServerAPI) :
CService(pAPIConnection, pServerAPI, GetName())
{
}
// --------------------------------------------------------------------------
// CThemeManagerService::~CThemeManagerService
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Destructor for CThemeManagerService.
//
// History: 2000-11-29 vtan created
// --------------------------------------------------------------------------
CThemeManagerService::~CThemeManagerService (void)
{
}
// --------------------------------------------------------------------------
// CThemeManagerService::Signal
//
// Arguments: <none>
//
// Returns: NTSTATUS
//
// Purpose: Used to signal that the service is coming up. Winlogon (via
// msgina) is listening for this event in its own session. This
// function queues a request to execute the real work done on a
// worker thread to prevent blocking the main service thread. If
// this is not possible then execute the signal inline.
//
// History: 2000-11-29 vtan created
// --------------------------------------------------------------------------
NTSTATUS CThemeManagerService::Signal (void)
{
if (QueueUserWorkItem(SignalSessionEvents, NULL, WT_EXECUTEDEFAULT) == FALSE)
{
(DWORD)SignalSessionEvents(NULL);
}
return(STATUS_SUCCESS);
}
// --------------------------------------------------------------------------
// CThemeManagerService::GetName
//
// Arguments: <none>
//
// Returns: const TCHAR*
//
// Purpose: Returns the name of the service (ThemeService).
//
// History: 2000-11-29 vtan created
// --------------------------------------------------------------------------
const TCHAR* CThemeManagerService::GetName (void)
{
return(s_szName);
}
// --------------------------------------------------------------------------
// CThemeManagerService::OpenStartEvent
//
// Arguments: <none>
//
// Returns: HANDLE
//
// Purpose: Opens or creates the theme service recovery event. This allows
// a process that has registered for the event to be signaled
// when the theme server is demand started. Currently only
// winlogon listens for this event and is required so that it can
// reestablish a server connection and re-create the session data
// which holds the hooks for theming.
//
// History: 2000-11-29 vtan created
// --------------------------------------------------------------------------
HANDLE CThemeManagerService::OpenStartEvent (DWORD dwSessionID, DWORD dwDesiredAccess)
{
HANDLE hEvent;
NTSTATUS status;
UNICODE_STRING eventName;
OBJECT_ATTRIBUTES objectAttributes;
WCHAR szEventName[64];
if (dwSessionID == 0)
{
wsprintfW(szEventName, L"\\BaseNamedObjects\\%s", THEMES_START_EVENT_NAME);
}
else
{
wsprintfW(szEventName, L"\\Sessions\\%d\\BaseNamedObjects\\%s", dwSessionID, THEMES_START_EVENT_NAME);
}
RtlInitUnicodeString(&eventName, szEventName);
InitializeObjectAttributes(&objectAttributes,
&eventName,
0,
NULL,
NULL);
status = NtOpenEvent(&hEvent, dwDesiredAccess, &objectAttributes);
if (!NT_SUCCESS(status))
{
// Build a security descriptor for the event that allows:
// S-1-5-18 NT AUTHORITY\SYSTEM EVENT_ALL_ACCESS
// S-1-5-32-544 <local administrators> SYNCHRONIZE | READ_CONTROL
// S-1-1-0 <everyone> SYNCHRONIZE
static SID_IDENTIFIER_AUTHORITY s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
static SID_IDENTIFIER_AUTHORITY s_SecurityWorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
{
{
&s_SecurityNTAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
EVENT_ALL_ACCESS
},
{
&s_SecurityNTAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
SYNCHRONIZE | READ_CONTROL
},
{
&s_SecurityWorldAuthority,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
SYNCHRONIZE
},
};
PSECURITY_DESCRIPTOR pSecurityDescriptor;
// Build a security descriptor that allows the described access above.
pSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
InitializeObjectAttributes(&objectAttributes,
&eventName,
0,
NULL,
pSecurityDescriptor);
status = NtCreateEvent(&hEvent,
EVENT_ALL_ACCESS,
&objectAttributes,
NotificationEvent,
FALSE);
ReleaseMemory(pSecurityDescriptor);
if (!NT_SUCCESS(status))
{
hEvent = NULL;
SetLastError(CStatusCode::ErrorCodeOfStatusCode(status));
}
}
return(hEvent);
}
// --------------------------------------------------------------------------
// CThemeManagerService::SignalSessionEvents
//
// Arguments: <none>
//
// Returns: HANDLE
//
// Purpose: Opens or creates the theme service recovery event. This allows
// a process that has registered for the event to be signaled
// when the theme server is demand started.
//
// History: 2000-11-29 vtan created
// --------------------------------------------------------------------------
DWORD WINAPI CThemeManagerService::SignalSessionEvents (void *pParameter)
{
UNREFERENCED_PARAMETER(pParameter);
HANDLE hEvent;
HANDLE hServer;
// First try and use terminal server to enumerate the sessions available.
hServer = WinStationOpenServerW(reinterpret_cast<WCHAR*>(SERVERNAME_CURRENT));
if (hServer != NULL)
{
ULONG ulEntries;
PLOGONID pLogonIDs;
if (WinStationEnumerate(hServer, &pLogonIDs, &ulEntries))
{
ULONG ul;
PLOGONID pLogonID;
for (ul = 0, pLogonID = pLogonIDs; ul < ulEntries; ++ul, ++pLogonID)
{
if ((pLogonID->State == State_Active) || (pLogonID->State == State_Connected) || (pLogonID->State == State_Disconnected))
{
hEvent = OpenStartEvent(pLogonID->SessionId, EVENT_MODIFY_STATE);
if (hEvent != NULL)
{
TBOOL(SetEvent(hEvent));
TBOOL(CloseHandle(hEvent));
}
}
}
(BOOLEAN)WinStationFreeMemory(pLogonIDs);
}
(BOOLEAN)WinStationCloseServer(hServer);
}
else
{
// If terminal services is not available then assume session 0 only.
hEvent = OpenStartEvent(0, EVENT_MODIFY_STATE);
if (hEvent != NULL)
{
TBOOL(SetEvent(hEvent));
TBOOL(CloseHandle(hEvent));
}
}
return(0);
}