123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- /*
- * Copyright 2022 Torge Matthies for CodeWeavers
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
- #include <windows.h>
- #include <winsvc.h>
- #include <stdio.h>
- #include "wine/test.h"
- #define lok ok_(__FILE__,line)
- #define TEST_SERVICE_NAME "wine_test_svc"
- #define TEST_SERVICE_NAME2 "wine_test_svc_2"
- #define TEST_SERVICE_BINARY "c:\\windows\\system32\\cmd.exe"
- #define TEST_SERVICE_BINARY_START_BOOT "\\SystemRoot\\system32\\cmd.exe"
- #define TEST_SERVICE_BINARY_START_SYSTEM "\\??\\" TEST_SERVICE_BINARY
- #define SC_EXIT_SUCCESS ERROR_SUCCESS
- #define SC_EXIT_INVALID_PARAMETER ERROR_INVALID_PARAMETER
- #define SC_EXIT_CIRCULAR_DEPENDENCY ERROR_CIRCULAR_DEPENDENCY
- #define SC_EXIT_SERVICE_DOES_NOT_EXIST ERROR_SERVICE_DOES_NOT_EXIST
- #define SC_EXIT_SERVICE_EXISTS ERROR_SERVICE_EXISTS
- #define SC_EXIT_INVALID_COMMAND_LINE ERROR_INVALID_COMMAND_LINE
- static HANDLE nul_file;
- static SC_HANDLE scmgr;
- /* Copied and modified from the reg.exe tests */
- #define run_sc_exe(c,r) run_sc_exe_(__FILE__,__LINE__,c,r)
- static BOOL run_sc_exe_(const char *file, unsigned line, const char *cmd, DWORD *rc)
- {
- STARTUPINFOA si = {sizeof(STARTUPINFOA)};
- PROCESS_INFORMATION pi;
- BOOL bret;
- DWORD ret;
- char cmdline[256];
- si.dwFlags = STARTF_USESTDHANDLES;
- si.hStdInput = nul_file;
- si.hStdOutput = nul_file;
- si.hStdError = nul_file;
- strcpy(cmdline, cmd);
- if (!CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
- return FALSE;
- ret = WaitForSingleObject(pi.hProcess, 10000);
- if (ret == WAIT_TIMEOUT)
- TerminateProcess(pi.hProcess, 1);
- bret = GetExitCodeProcess(pi.hProcess, rc);
- lok(bret, "GetExitCodeProcess failed: %ld\n", GetLastError());
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
- return bret;
- }
- #define BROKEN_CREATE 0x000000001UL
- #define BROKEN_BINPATH 0x000000002UL
- #define BROKEN_TYPE 0x000000004UL
- #define BROKEN_START 0x000000008UL
- #define BROKEN_ERROR 0x000000010UL
- #define BROKEN_DEPEND 0x000000020UL
- #define BROKEN_DISPLAY_NAME 0x000000040UL
- #define BROKEN_DELAYED_AUTO_START 0x000000080UL
- #define BROKEN_ALL ~0UL
- #define SERVICE_DELAYED_AUTO_START (SERVICE_AUTO_START | 0x80000000)
- #define check_service_definition(n,bi,t,s,e,de,di,br) check_service_definition_(__FILE__,__LINE__,n,bi,t,s,e,de,di,br)
- static void check_service_definition_(const char *file, unsigned line, char const *name,
- const char *binpath, DWORD type, DWORD start, DWORD error,
- const char *depend, const char *display_name, DWORD broken)
- {
- SERVICE_DELAYED_AUTO_START_INFO delayed_auto_info = {0};
- union {
- char buffer[8192];
- QUERY_SERVICE_CONFIGA config;
- } cfg;
- BOOL delayed_auto;
- SC_HANDLE svc;
- DWORD needed;
- BOOL ret;
- delayed_auto = !!(start & 0x80000000);
- start &= ~0x80000000;
- if (!scmgr)
- return;
- svc = OpenServiceA(scmgr, name, GENERIC_READ);
- todo_wine_if(broken & BROKEN_CREATE)
- lok(!!svc, "OpenServiceA failed: %ld\n", GetLastError());
- if (!svc)
- return;
- ret = QueryServiceConfigA(svc, &cfg.config, sizeof(cfg.buffer), &needed);
- lok(!!ret, "QueryServiceConfigA failed: %ld\n", GetLastError());
- if (!ret)
- goto done;
- ret = QueryServiceConfig2A(svc, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (LPBYTE)&delayed_auto_info,
- sizeof(delayed_auto_info), &needed);
- todo_wine lok(!!ret, "QueryServiceConfig2A(SERVICE_CONFIG_DELAYED_AUTO_START_INFO) failed: %ld\n",
- GetLastError());
- #define check_str(a, b, msg) lok((a) && (b) && (a) != (b) && !strcmp((a), (b)), msg ": %s != %s\n", \
- debugstr_a((a)), debugstr_a((b)))
- #define check_dw(a, b, msg) lok((a) == (b), msg ": 0x%lx != 0x%lx\n", a, b)
- todo_wine_if(broken & BROKEN_BINPATH)
- check_str(cfg.config.lpBinaryPathName, binpath, "Wrong binary path");
- todo_wine_if(broken & BROKEN_TYPE)
- check_dw(cfg.config.dwServiceType, type, "Wrong service type");
- todo_wine_if(broken & BROKEN_START)
- check_dw(cfg.config.dwStartType, start, "Wrong start type");
- todo_wine_if(broken & BROKEN_ERROR)
- check_dw(cfg.config.dwErrorControl, error, "Wrong error control");
- todo_wine_if(broken & BROKEN_DEPEND)
- check_str(cfg.config.lpDependencies, depend, "Wrong dependencies");
- todo_wine_if(broken & BROKEN_DISPLAY_NAME)
- check_str(cfg.config.lpDisplayName, display_name, "Wrong display name");
- todo_wine_if(broken & BROKEN_DELAYED_AUTO_START)
- check_dw((DWORD)delayed_auto_info.fDelayedAutostart, (DWORD)delayed_auto, "Wrong delayed autostart value");
- #undef check_dw
- #undef check_str
- done:
- CloseServiceHandle(svc);
- }
- #define delete_service(n,e,b) delete_service_(__FILE__,__LINE__,n,e,b)
- static void delete_service_(const char *file, unsigned line, const char *name, DWORD expected_status, BOOL broken)
- {
- char command[256];
- BOOL bret;
- DWORD r;
- strcpy(command, "sc delete ");
- strcat(command, name);
- bret = run_sc_exe_(file, line, command, &r);
- lok(bret, "run_sc_exe failed\n");
- if (expected_status != SC_EXIT_SUCCESS && !strcmp(winetest_platform, "wine"))
- expected_status = 1;
- todo_wine_if(broken) lok(r == expected_status, "got exit code %ld, expected %ld\n", r, expected_status);
- }
- static void test_create_service(BOOL elevated)
- {
- static struct {
- const char *param;
- DWORD expected_start_type;
- DWORD expected_service_type;
- const char * expected_binary_path;
- DWORD broken;
- } start_types[] = {
- { "boot type= kernel", SERVICE_BOOT_START, SERVICE_KERNEL_DRIVER, TEST_SERVICE_BINARY_START_BOOT,
- BROKEN_BINPATH | BROKEN_DISPLAY_NAME },
- { "system type= kernel", SERVICE_SYSTEM_START, SERVICE_KERNEL_DRIVER, TEST_SERVICE_BINARY_START_SYSTEM,
- BROKEN_BINPATH | BROKEN_DISPLAY_NAME },
- { "auto", SERVICE_AUTO_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY,
- BROKEN_DISPLAY_NAME },
- { "demand", SERVICE_DEMAND_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY,
- BROKEN_DISPLAY_NAME },
- { "disabled", SERVICE_DISABLED, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY,
- BROKEN_DISPLAY_NAME },
- { "delayed-auto", SERVICE_DELAYED_AUTO_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY,
- BROKEN_START | BROKEN_DISPLAY_NAME | BROKEN_DELAYED_AUTO_START }
- };
- static struct {
- const char *param;
- DWORD expected_error_control;
- } error_severities[] = {
- { "normal", SERVICE_ERROR_NORMAL },
- { "severe", SERVICE_ERROR_SEVERE },
- { "critical", SERVICE_ERROR_CRITICAL },
- { "ignore", SERVICE_ERROR_IGNORE }
- };
- unsigned int i;
- DWORD r;
- if (!elevated)
- {
- win_skip("\"sc create\" tests need elevated permissions\n");
- return;
- }
- #define check_exit_code(x) ok(r == (x), "got exit code %ld, expected %d\n", r, (x))
- #define check_test_service(t,s,e,de,di,br) \
- check_service_definition(TEST_SERVICE_NAME, TEST_SERVICE_BINARY, t, s, e, de, di ? di : TEST_SERVICE_NAME, br)
- #define delete_test_service(x, y) \
- delete_service(TEST_SERVICE_NAME, (x) ? SC_EXIT_SUCCESS : SC_EXIT_SERVICE_DOES_NOT_EXIST, (y))
- #define check_test_service2(t,s,e,de,di,br) \
- check_service_definition(TEST_SERVICE_NAME2, TEST_SERVICE_BINARY, t, s, e, de, di ? di : TEST_SERVICE_NAME2, br)
- #define delete_test_service2(x, y) \
- delete_service(TEST_SERVICE_NAME2, (x) ? SC_EXIT_SUCCESS : SC_EXIT_SERVICE_DOES_NOT_EXIST, (y))
- /* too few parameters */
- run_sc_exe("sc create", &r);
- todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE);
- delete_test_service(FALSE, FALSE);
- run_sc_exe("sc create " TEST_SERVICE_NAME, &r);
- todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE);
- delete_test_service(FALSE, FALSE);
- /* binpath= */
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\"", &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL,
- BROKEN_DISPLAY_NAME);
- /* existing service */
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" start= auto", &r);
- todo_wine check_exit_code(SC_EXIT_SERVICE_EXISTS);
- check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL,
- BROKEN_DISPLAY_NAME);
- delete_test_service(TRUE, FALSE);
- /* type= */
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" type= invalid", &r);
- todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE);
- delete_test_service(FALSE, TRUE);
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" type= own", &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL,
- BROKEN_DISPLAY_NAME);
- delete_test_service(TRUE, FALSE);
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" type= interact", &r);
- todo_wine check_exit_code(SC_EXIT_INVALID_PARAMETER);
- delete_test_service(FALSE, TRUE);
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" type= interact type= own", &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service(SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START,
- SERVICE_ERROR_NORMAL, "", NULL, BROKEN_TYPE | BROKEN_DISPLAY_NAME);
- delete_test_service(TRUE, FALSE);
- /* start= */
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" start= invalid", &r);
- todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE);
- delete_test_service(FALSE, TRUE);
- for (i = 0; i < ARRAY_SIZE(start_types); i++)
- {
- char cmdline[256];
- strcpy(cmdline, "sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" start= ");
- strcat(cmdline, start_types[i].param);
- run_sc_exe(cmdline, &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_service_definition(TEST_SERVICE_NAME, start_types[i].expected_binary_path,
- start_types[i].expected_service_type, start_types[i].expected_start_type,
- SERVICE_ERROR_NORMAL, "", TEST_SERVICE_NAME, start_types[i].broken);
- delete_test_service(TRUE, FALSE);
- }
- /* error= */
- for (i = 0; i < ARRAY_SIZE(error_severities); i++)
- {
- char cmdline[256];
- strcpy(cmdline, "sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" error= ");
- strcat(cmdline, error_severities[i].param);
- run_sc_exe(cmdline, &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,
- error_severities[i].expected_error_control, "", NULL, BROKEN_DISPLAY_NAME);
- delete_test_service(TRUE, FALSE);
- }
- /* tag= */
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" tag= yes", &r);
- todo_wine check_exit_code(SC_EXIT_INVALID_PARAMETER);
- delete_test_service(FALSE, TRUE);
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" tag= no", &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL,
- BROKEN_DISPLAY_NAME);
- delete_test_service(TRUE, FALSE);
- /* depend= */
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" depend= " TEST_SERVICE_NAME, &r);
- todo_wine check_exit_code(SC_EXIT_CIRCULAR_DEPENDENCY);
- delete_test_service(FALSE, TRUE);
- run_sc_exe("sc create " TEST_SERVICE_NAME2 " binpath= \"" TEST_SERVICE_BINARY "\" depend= " TEST_SERVICE_NAME, &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
- TEST_SERVICE_NAME, NULL, BROKEN_DEPEND | BROKEN_DISPLAY_NAME);
- delete_test_service2(TRUE, FALSE);
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= " TEST_SERVICE_BINARY, &r);
- check_exit_code(SC_EXIT_SUCCESS);
- run_sc_exe("sc create " TEST_SERVICE_NAME2 " binpath= \"" TEST_SERVICE_BINARY "\" depend= " TEST_SERVICE_NAME, &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
- TEST_SERVICE_NAME, NULL, BROKEN_DEPEND | BROKEN_DISPLAY_NAME);
- delete_test_service2(TRUE, FALSE);
- delete_test_service(TRUE, FALSE);
- /* displayname= */
- run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= " TEST_SERVICE_BINARY
- " displayname= \"Wine Test Service\"", &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "",
- "Wine Test Service", 0);
- delete_test_service(TRUE, FALSE);
- /* without spaces */
- run_sc_exe("sc create " TEST_SERVICE_NAME2 " binpath=\"" TEST_SERVICE_BINARY "\" type=own start=auto"
- " error=normal tag=no depend=" TEST_SERVICE_NAME " displayname=\"Wine Test Service\"", &r);
- ok(r == SC_EXIT_SUCCESS || broken(r == SC_EXIT_INVALID_COMMAND_LINE), "got exit code %ld, expected %d\n",
- r, SC_EXIT_SUCCESS);
- if (r == SC_EXIT_SUCCESS)
- {
- check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
- TEST_SERVICE_NAME, "Wine Test Service", BROKEN_DEPEND);
- delete_test_service2(TRUE, FALSE);
- }
- else
- {
- delete_test_service2(FALSE, FALSE);
- }
- /* case-insensitive */
- run_sc_exe("SC CREATE " TEST_SERVICE_NAME2 " BINPATH= \"" TEST_SERVICE_BINARY "\" TYPE= OWN START= AUTO"
- " ERROR= NORMAL TAG= NO DEPEND= " TEST_SERVICE_NAME " DISPLAYNAME= \"Wine Test Service\"", &r);
- check_exit_code(SC_EXIT_SUCCESS);
- check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
- TEST_SERVICE_NAME, "Wine Test Service", BROKEN_DEPEND);
- delete_test_service2(TRUE, FALSE);
- #undef delete_test_service2
- #undef check_test_service2
- #undef delete_test_service
- #undef check_test_service
- #undef check_exit_code
- }
- /* taken from winetest, only whitespace changes */
- static int running_elevated(void)
- {
- HANDLE token;
- TOKEN_ELEVATION elevation_info;
- DWORD size;
- /* Get the process token */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
- return -1;
- /* Get the elevation info from the token */
- if (!GetTokenInformation(token, TokenElevation, &elevation_info, sizeof(TOKEN_ELEVATION), &size))
- {
- CloseHandle(token);
- return -1;
- }
- CloseHandle(token);
- return elevation_info.TokenIsElevated;
- }
- START_TEST(sc)
- {
- SECURITY_ATTRIBUTES secattr = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
- BOOL elevated = running_elevated();
- nul_file = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE, 0, &secattr, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
- scmgr = OpenSCManagerA(NULL, NULL, GENERIC_READ);
- ok(!!scmgr, "OpenSCManagerA failed: %ld\n", GetLastError());
- test_create_service(elevated);
- CloseServiceHandle(scmgr);
- CloseHandle(nul_file);
- }
|