diff --git a/base/services/rpcss/CMakeLists.txt b/base/services/rpcss/CMakeLists.txt index a7a31c5dfef..2ed8b49df35 100644 --- a/base/services/rpcss/CMakeLists.txt +++ b/base/services/rpcss/CMakeLists.txt @@ -8,6 +8,7 @@ list(APPEND SOURCE epmp.c irotp.c rpcss_main.c + setup.c precomp.h ${CMAKE_CURRENT_BINARY_DIR}/epm_s.c ${CMAKE_CURRENT_BINARY_DIR}/irot_s.c) diff --git a/base/services/rpcss/rpcss_main.c b/base/services/rpcss/rpcss_main.c index 885726dba18..c515fa1a111 100644 --- a/base/services/rpcss/rpcss_main.c +++ b/base/services/rpcss/rpcss_main.c @@ -118,6 +118,10 @@ static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_ } } +#ifdef __REACTOS__ +extern VOID DoRpcSsSetupConfiguration(VOID); +#endif + static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) { SERVICE_STATUS status; @@ -140,6 +144,10 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) status.dwWaitHint = 10000; SetServiceStatus( service_handle, &status ); +#ifdef __REACTOS__ + DoRpcSsSetupConfiguration(); +#endif + WaitForSingleObject( exit_event, INFINITE ); status.dwCurrentState = SERVICE_STOPPED; diff --git a/base/services/rpcss/setup.c b/base/services/rpcss/setup.c new file mode 100644 index 00000000000..e51831efc41 --- /dev/null +++ b/base/services/rpcss/setup.c @@ -0,0 +1,179 @@ +/* + * PROJECT: ReactOS RPC Subsystem Service + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: One-time service setup configuration. + * COPYRIGHT: Copyright 2018 Hermes Belusca-Maito + */ + +/* INCLUDES *****************************************************************/ + +/* PSDK/NDK Headers */ +#define WIN32_NO_STATUS +#include +#include +#include +#include + +#include +#include + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpcss); + +/* FUNCTIONS ****************************************************************/ + +static BOOL +SetupIsActive(VOID) +{ + LONG lResult; + HKEY hKey; + DWORD dwData = 0; + DWORD cbData = sizeof(dwData); + DWORD dwType = REG_NONE; + + lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_QUERY_VALUE, &hKey); + if (lResult != ERROR_SUCCESS) + return FALSE; + + lResult = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, + &dwType, (LPBYTE)&dwData, &cbData); + RegCloseKey(hKey); + + if ((lResult == ERROR_SUCCESS) && (dwType == REG_DWORD) && + (cbData == sizeof(dwData)) && (dwData == 1)) + { + return TRUE; + } + + return FALSE; +} + +static BOOL +RunningAsSYSTEM(VOID) +{ + /* S-1-5-18 -- Local System */ + static SID SystemSid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } }; + + BOOL bRet = FALSE; + PTOKEN_USER pTokenUser; + HANDLE hToken; + DWORD cbTokenBuffer = 0; + + /* Get the process token */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + return FALSE; + + /* Retrieve token's information */ + if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &cbTokenBuffer) && + GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + goto Quit; + } + + pTokenUser = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTokenBuffer); + if (!pTokenUser) + goto Quit; + + if (GetTokenInformation(hToken, TokenUser, pTokenUser, cbTokenBuffer, &cbTokenBuffer)) + { + /* Compare with SYSTEM SID */ + bRet = EqualSid(pTokenUser->User.Sid, &SystemSid); + } + + HeapFree(GetProcessHeap(), 0, pTokenUser); + +Quit: + CloseHandle(hToken); + return bRet; +} + +static VOID +RpcSsConfigureAsNetworkService(VOID) +{ + SC_HANDLE hSCManager, hService; + + /* Open the service controller */ + hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); + if (!hSCManager) + { + ERR("OpenSCManager() failed with error 0x%lx\n", GetLastError()); + return; + } + + /* Open the RPCSS service */ + hService = OpenServiceW(hSCManager, L"RPCSS", SERVICE_CHANGE_CONFIG); + if (!hService) + ERR("OpenService(\"RPCSS\") failed with error 0x%lx\n", GetLastError()); + if (hService) + { + /* Use the NetworkService account */ + if (!ChangeServiceConfigW(hService, + SERVICE_NO_CHANGE, + SERVICE_NO_CHANGE, + SERVICE_NO_CHANGE, + NULL, + NULL, + NULL, + NULL, + L"NT AUTHORITY\\NetworkService", + L"", + NULL)) + { + ERR("ChangeServiceConfig(\"RPCSS\") failed with error 0x%lx\n", GetLastError()); + } + + CloseServiceHandle(hService); + } + + CloseServiceHandle(hSCManager); +} + +static VOID +AddImpersonatePrivilege(VOID) +{ + /* S-1-5-6 -- "Service" group */ + static SID ServiceSid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_SERVICE_RID } }; + + NTSTATUS Status; + LSA_HANDLE PolicyHandle; + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + LSA_UNICODE_STRING RightString; + + ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); + Status = LsaOpenPolicy(NULL, &ObjectAttributes, + POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, + &PolicyHandle); + if (!NT_SUCCESS(Status)) + { + ERR("LsaOpenPolicy() failed with Status 0x%08lx\n", Status); + return; + } + + RtlInitUnicodeString(&RightString, L"SeImpersonatePrivilege"); + Status = LsaAddAccountRights(PolicyHandle, &ServiceSid, &RightString, 1); + if (!NT_SUCCESS(Status)) + { + ERR("LsaAddAccountRights(\"S-1-5-6\", \"%wZ\") failed with Status 0x%08lx\n", Status, &RightString); + } + + LsaClose(PolicyHandle); +} + +VOID DoRpcSsSetupConfiguration(VOID) +{ + /* + * On first run during the setup phase, the RPCSS service runs under + * the LocalSystem account. RPCSS then re-configures itself to run + * under the NetworkService account and adds the Impersonate privilege + * to the "Service" group. + * This is done in this way, because the NetworkService account does not + * initially exist when the setup phase is running and the RPCSS service + * is started, but this account is created later during the setup phase. + */ + if (SetupIsActive() && RunningAsSYSTEM()) + { + RpcSsConfigureAsNetworkService(); + AddImpersonatePrivilege(); + } +}