From: Hermès Bélusca-Maïto Date: Mon, 5 Dec 2016 16:36:06 +0000 (+0000) Subject: [ADVAPI32_APITEST]: Test for a (correctly initialized) service process environment... X-Git-Tag: ReactOS-0.4.4-FOSDEM2017~104 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=aadba539ce244e41607f9e8eae311208ab934384 [ADVAPI32_APITEST]: Test for a (correctly initialized) service process environment block, that should contain both ALLUSERSPROFILE and USERPROFILE environment variables. CORE-12414 svn path=/trunk/; revision=73431 --- diff --git a/rostests/apitests/advapi32/CMakeLists.txt b/rostests/apitests/advapi32/CMakeLists.txt index 5ef604958d7..b01d4ccd2ea 100644 --- a/rostests/apitests/advapi32/CMakeLists.txt +++ b/rostests/apitests/advapi32/CMakeLists.txt @@ -14,6 +14,7 @@ list(APPEND SOURCE RtlEncryptMemory.c SaferIdentifyLevel.c ServiceArgs.c + ServiceEnv.c svchlp.c testlist.c) diff --git a/rostests/apitests/advapi32/ServiceEnv.c b/rostests/apitests/advapi32/ServiceEnv.c new file mode 100644 index 00000000000..883b61e1647 --- /dev/null +++ b/rostests/apitests/advapi32/ServiceEnv.c @@ -0,0 +1,259 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Test for StartService functionality + * PROGRAMMER: Hermès BÉLUSCA - MAÏTO + */ + +#include +#include +#include "svchlp.h" + + +/*** Service part of the test ***/ + +static SERVICE_STATUS_HANDLE status_handle; + +static void +report_service_status(DWORD dwCurrentState, + DWORD dwWin32ExitCode, + DWORD dwWaitHint) +{ + BOOL res; + SERVICE_STATUS status; + + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + status.dwCurrentState = dwCurrentState; + status.dwWin32ExitCode = dwWin32ExitCode; + status.dwWaitHint = dwWaitHint; + + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + + if ( (dwCurrentState == SERVICE_START_PENDING) || + (dwCurrentState == SERVICE_STOP_PENDING) || + (dwCurrentState == SERVICE_STOPPED) ) + { + status.dwControlsAccepted = 0; + } + else + { + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + } + +#if 0 + if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) ) + status.dwCheckPoint = 0; + else + status.dwCheckPoint = dwCheckPoint++; +#endif + + res = SetServiceStatus(status_handle, &status); + service_ok(res, "SetServiceStatus(%d) failed: %lu\n", dwCurrentState, GetLastError()); +} + +static VOID WINAPI service_handler(DWORD ctrl) +{ + switch(ctrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + report_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0); + default: + report_service_status(SERVICE_RUNNING, NO_ERROR, 0); + } +} + +static void WINAPI +service_main(DWORD dwArgc, LPWSTR* lpszArgv) +{ + // SERVICE_STATUS_HANDLE status_handle; + LPWSTR lpEnvironment, lpEnvStr; + DWORD dwSize; + + UNREFERENCED_PARAMETER(dwArgc); + UNREFERENCED_PARAMETER(lpszArgv); + + /* Register our service for control (lpszArgv[0] holds the service name) */ + status_handle = RegisterServiceCtrlHandlerW(lpszArgv[0], service_handler); + service_ok(status_handle != NULL, "RegisterServiceCtrlHandler failed: %lu\n", GetLastError()); + if (!status_handle) + return; + + /* Report SERVICE_RUNNING status */ + report_service_status(SERVICE_RUNNING, NO_ERROR, 4000); + + /* Display our current environment for informative purposes */ + lpEnvironment = GetEnvironmentStringsW(); + lpEnvStr = lpEnvironment; + while (*lpEnvStr) + { + service_trace("%S\n", lpEnvStr); + lpEnvStr += wcslen(lpEnvStr) + 1; + } + FreeEnvironmentStringsW(lpEnvironment); + + /* Check the presence of the user-related environment variables */ + dwSize = GetEnvironmentVariableW(L"ALLUSERSPROFILE", NULL, 0); + service_ok(dwSize != 0, "ALLUSERSPROFILE envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError()); + dwSize = GetEnvironmentVariableW(L"USERPROFILE", NULL, 0); + service_ok(dwSize != 0, "USERPROFILE envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError()); +#if 0 // May not always exist + dwSize = GetEnvironmentVariableW(L"USERNAME", NULL, 0); + service_ok(dwSize != 0, "USERNAME envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError()); +#endif + + /* Work is done */ + report_service_status(SERVICE_STOPPED, NO_ERROR, 0); +} + +static BOOL start_service(PCSTR service_nameA, PCWSTR service_nameW) +{ + BOOL res; + + SERVICE_TABLE_ENTRYW servtbl[] = + { + { (PWSTR)service_nameW, service_main }, + { NULL, NULL } + }; + + res = StartServiceCtrlDispatcherW(servtbl); + service_ok(res, "StartServiceCtrlDispatcherW failed: %lu\n", GetLastError()); + return res; +} + + +/*** Tester part of the test ***/ + +static void +my_test_server(PCSTR service_nameA, + PCWSTR service_nameW, + void *param) +{ + BOOL res; + SC_HANDLE hSC = NULL; + SC_HANDLE hService = NULL; + SERVICE_STATUS ServiceStatus; + + /* Open the SCM */ + hSC = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!hSC) + { + skip("OpenSCManagerW failed with error %lu!\n", GetLastError()); + return; + } + + /* First create ourselves as a service running in the default LocalSystem account */ + hService = register_service_exW(hSC, L"ServiceEnv", service_nameW, NULL, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, + SERVICE_DEMAND_START, + SERVICE_ERROR_IGNORE, + NULL, NULL, NULL, + NULL, NULL); + if (!hService) + { + skip("CreateServiceW failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + + /* Start it */ + if (!StartServiceW(hService, 0, NULL)) + { + skip("StartServiceW failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + + /* Wait for the service to stop by itself */ + do + { + Sleep(100); + ZeroMemory(&ServiceStatus, sizeof(ServiceStatus)); + res = QueryServiceStatus(hService, &ServiceStatus); + } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED); + ok(res, "QueryServiceStatus failed: %lu\n", GetLastError()); + ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState); + + /* Be sure the service is really stopped */ + res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); + if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED && + ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && + GetLastError() != ERROR_SERVICE_NOT_ACTIVE) + { + skip("ControlService failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + +#if 0 + trace("Service stopped. Going to restart it...\n"); + + /* Now change the service configuration to make it start under 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)) + { + skip("ChangeServiceConfigW failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + + /* Start it */ + if (!StartServiceW(hService, 0, NULL)) + { + skip("StartServiceW failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + + /* Wait for the service to stop by itself */ + do + { + Sleep(100); + ZeroMemory(&ServiceStatus, sizeof(ServiceStatus)); + res = QueryServiceStatus(hService, &ServiceStatus); + } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED); + ok(res, "QueryServiceStatus failed: %lu\n", GetLastError()); + ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState); + + /* Be sure the service is really stopped */ + res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); + if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED && + ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && + GetLastError() != ERROR_SERVICE_NOT_ACTIVE) + { + skip("ControlService failed with error %lu!\n", GetLastError()); + goto Cleanup; + } +#endif + +Cleanup: + if (hService) + { + res = DeleteService(hService); + ok(res, "DeleteService failed: %lu\n", GetLastError()); + CloseServiceHandle(hService); + } + + if (hSC) + CloseServiceHandle(hSC); +} + +START_TEST(ServiceEnv) +{ + int argc; + char** argv; + + /* Check whether this test is started as a separated service process */ + argc = winetest_get_mainargs(&argv); + if (argc >= 3) + { + service_process(start_service, argc, argv); + return; + } + + /* We are started as the real test */ + test_runner(my_test_server, NULL); + // trace("Returned from test_runner\n"); +} diff --git a/rostests/apitests/advapi32/testlist.c b/rostests/apitests/advapi32/testlist.c index 41815bbdbad..a34bf766065 100644 --- a/rostests/apitests/advapi32/testlist.c +++ b/rostests/apitests/advapi32/testlist.c @@ -17,6 +17,7 @@ extern void func_RegQueryValueExW(void); extern void func_RtlEncryptMemory(void); extern void func_SaferIdentifyLevel(void); extern void func_ServiceArgs(void); +extern void func_ServiceEnv(void); const struct test winetest_testlist[] = { @@ -34,6 +35,7 @@ const struct test winetest_testlist[] = { "RtlEncryptMemory", func_RtlEncryptMemory }, { "SaferIdentifyLevel", func_SaferIdentifyLevel }, { "ServiceArgs", func_ServiceArgs }, + { "ServiceEnv", func_ServiceEnv }, { 0, 0 } };