// -------------------------------------------------------------------------- // 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" #define STRSAFE_LIB #include #include "ThemeManagerService.h" #include #include #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: // // Purpose: Constructor for CThemeManagerService. // // History: 2000-11-29 vtan created // -------------------------------------------------------------------------- CThemeManagerService::CThemeManagerService (CAPIConnection *pAPIConnection, CServerAPI *pServerAPI) : CService(pAPIConnection, pServerAPI, GetName()) { } // -------------------------------------------------------------------------- // CThemeManagerService::~CThemeManagerService // // Arguments: // // Returns: // // Purpose: Destructor for CThemeManagerService. // // History: 2000-11-29 vtan created // -------------------------------------------------------------------------- CThemeManagerService::~CThemeManagerService (void) { } // -------------------------------------------------------------------------- // CThemeManagerService::SignalStartStop // // Arguments: BOOL fStart // // Returns: NTSTATUS // // Purpose: Used to signal that the service is starting or stopping. // In the case of serivce start, 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 // 2002-03-11 scotthan renamed to 'SignalStartStop' from 'Signal', // added boolean arg, add call to base class // implementation. // -------------------------------------------------------------------------- NTSTATUS CThemeManagerService::SignalStartStop (BOOL fStart) { if( fStart ) { if (QueueUserWorkItem(SignalSessionEvents, NULL, WT_EXECUTEDEFAULT) == FALSE) { (DWORD)SignalSessionEvents(NULL); } } return CService::SignalStartStop(fStart); } // -------------------------------------------------------------------------- // CThemeManagerService::GetName // // Arguments: // // 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: // // 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) { StringCchPrintfW(szEventName, ARRAYSIZE(szEventName), L"\\BaseNamedObjects\\%s", THEMES_START_EVENT_NAME); } else { StringCchPrintfW(szEventName, ARRAYSIZE(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 SYNCHRONIZE | READ_CONTROL // S-1-1-0 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 }, { // Review: Is synchronize for Everyone really necessary? &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: // // 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(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); }