wnaspi32: Remove DECLSPEC_HIDDEN usage.
[wine.git] / programs / sc / tests / sc.c
blob57046905a4b0631d06eddd03a9ee7c75f2112e1b
1 /*
2 * Copyright 2022 Torge Matthies for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <windows.h>
20 #include <winsvc.h>
21 #include <stdio.h>
22 #include "wine/test.h"
24 #define lok ok_(__FILE__,line)
26 #define TEST_SERVICE_NAME "wine_test_svc"
27 #define TEST_SERVICE_NAME2 "wine_test_svc_2"
28 #define TEST_SERVICE_BINARY "c:\\windows\\system32\\cmd.exe"
29 #define TEST_SERVICE_BINARY_START_BOOT "\\SystemRoot\\system32\\cmd.exe"
30 #define TEST_SERVICE_BINARY_START_SYSTEM "\\??\\" TEST_SERVICE_BINARY
32 #define SC_EXIT_SUCCESS ERROR_SUCCESS
33 #define SC_EXIT_INVALID_PARAMETER ERROR_INVALID_PARAMETER
34 #define SC_EXIT_CIRCULAR_DEPENDENCY ERROR_CIRCULAR_DEPENDENCY
35 #define SC_EXIT_SERVICE_DOES_NOT_EXIST ERROR_SERVICE_DOES_NOT_EXIST
36 #define SC_EXIT_SERVICE_EXISTS ERROR_SERVICE_EXISTS
37 #define SC_EXIT_INVALID_COMMAND_LINE ERROR_INVALID_COMMAND_LINE
39 static HANDLE nul_file;
40 static SC_HANDLE scmgr;
42 /* Copied and modified from the reg.exe tests */
43 #define run_sc_exe(c,r) run_sc_exe_(__FILE__,__LINE__,c,r)
44 static BOOL run_sc_exe_(const char *file, unsigned line, const char *cmd, DWORD *rc)
46 STARTUPINFOA si = {sizeof(STARTUPINFOA)};
47 PROCESS_INFORMATION pi;
48 BOOL bret;
49 DWORD ret;
50 char cmdline[256];
52 si.dwFlags = STARTF_USESTDHANDLES;
53 si.hStdInput = nul_file;
54 si.hStdOutput = nul_file;
55 si.hStdError = nul_file;
57 strcpy(cmdline, cmd);
58 if (!CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
59 return FALSE;
61 ret = WaitForSingleObject(pi.hProcess, 10000);
62 if (ret == WAIT_TIMEOUT)
63 TerminateProcess(pi.hProcess, 1);
65 bret = GetExitCodeProcess(pi.hProcess, rc);
66 lok(bret, "GetExitCodeProcess failed: %ld\n", GetLastError());
68 CloseHandle(pi.hThread);
69 CloseHandle(pi.hProcess);
70 return bret;
73 #define BROKEN_CREATE 0x000000001UL
74 #define BROKEN_BINPATH 0x000000002UL
75 #define BROKEN_TYPE 0x000000004UL
76 #define BROKEN_START 0x000000008UL
77 #define BROKEN_ERROR 0x000000010UL
78 #define BROKEN_DEPEND 0x000000020UL
79 #define BROKEN_DISPLAY_NAME 0x000000040UL
80 #define BROKEN_DELAYED_AUTO_START 0x000000080UL
81 #define BROKEN_ALL ~0UL
83 #define SERVICE_DELAYED_AUTO_START (SERVICE_AUTO_START | 0x80000000)
85 #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)
86 static void check_service_definition_(const char *file, unsigned line, char const *name,
87 const char *binpath, DWORD type, DWORD start, DWORD error,
88 const char *depend, const char *display_name, DWORD broken)
90 SERVICE_DELAYED_AUTO_START_INFO delayed_auto_info = {0};
91 union {
92 char buffer[8192];
93 QUERY_SERVICE_CONFIGA config;
94 } cfg;
95 BOOL delayed_auto;
96 SC_HANDLE svc;
97 DWORD needed;
98 BOOL ret;
100 delayed_auto = !!(start & 0x80000000);
101 start &= ~0x80000000;
103 if (!scmgr)
104 return;
106 svc = OpenServiceA(scmgr, name, GENERIC_READ);
107 todo_wine_if(broken & BROKEN_CREATE)
108 lok(!!svc, "OpenServiceA failed: %ld\n", GetLastError());
109 if (!svc)
110 return;
112 ret = QueryServiceConfigA(svc, &cfg.config, sizeof(cfg.buffer), &needed);
113 lok(!!ret, "QueryServiceConfigA failed: %ld\n", GetLastError());
114 if (!ret)
115 goto done;
117 ret = QueryServiceConfig2A(svc, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (LPBYTE)&delayed_auto_info,
118 sizeof(delayed_auto_info), &needed);
119 todo_wine lok(!!ret, "QueryServiceConfig2A(SERVICE_CONFIG_DELAYED_AUTO_START_INFO) failed: %ld\n",
120 GetLastError());
122 #define check_str(a, b, msg) lok((a) && (b) && (a) != (b) && !strcmp((a), (b)), msg ": %s != %s\n", \
123 debugstr_a((a)), debugstr_a((b)))
124 #define check_dw(a, b, msg) lok((a) == (b), msg ": 0x%lx != 0x%lx\n", a, b)
126 todo_wine_if(broken & BROKEN_BINPATH)
127 check_str(cfg.config.lpBinaryPathName, binpath, "Wrong binary path");
128 todo_wine_if(broken & BROKEN_TYPE)
129 check_dw(cfg.config.dwServiceType, type, "Wrong service type");
130 todo_wine_if(broken & BROKEN_START)
131 check_dw(cfg.config.dwStartType, start, "Wrong start type");
132 todo_wine_if(broken & BROKEN_ERROR)
133 check_dw(cfg.config.dwErrorControl, error, "Wrong error control");
134 todo_wine_if(broken & BROKEN_DEPEND)
135 check_str(cfg.config.lpDependencies, depend, "Wrong dependencies");
136 todo_wine_if(broken & BROKEN_DISPLAY_NAME)
137 check_str(cfg.config.lpDisplayName, display_name, "Wrong display name");
138 todo_wine_if(broken & BROKEN_DELAYED_AUTO_START)
139 check_dw((DWORD)delayed_auto_info.fDelayedAutostart, (DWORD)delayed_auto, "Wrong delayed autostart value");
141 #undef check_dw
142 #undef check_str
144 done:
145 CloseServiceHandle(svc);
148 #define delete_service(n,e,b) delete_service_(__FILE__,__LINE__,n,e,b)
149 static void delete_service_(const char *file, unsigned line, const char *name, DWORD expected_status, BOOL broken)
151 char command[256];
152 BOOL bret;
153 DWORD r;
155 strcpy(command, "sc delete ");
156 strcat(command, name);
157 bret = run_sc_exe_(file, line, command, &r);
158 lok(bret, "run_sc_exe failed\n");
159 if (expected_status != SC_EXIT_SUCCESS && !strcmp(winetest_platform, "wine"))
160 expected_status = 1;
161 todo_wine_if(broken) lok(r == expected_status, "got exit code %ld, expected %ld\n", r, expected_status);
164 static void test_create_service(BOOL elevated)
166 static struct {
167 const char *param;
168 DWORD expected_start_type;
169 DWORD expected_service_type;
170 const char * expected_binary_path;
171 DWORD broken;
172 } start_types[] = {
173 { "boot type= kernel", SERVICE_BOOT_START, SERVICE_KERNEL_DRIVER, TEST_SERVICE_BINARY_START_BOOT,
174 BROKEN_BINPATH | BROKEN_DISPLAY_NAME },
175 { "system type= kernel", SERVICE_SYSTEM_START, SERVICE_KERNEL_DRIVER, TEST_SERVICE_BINARY_START_SYSTEM,
176 BROKEN_BINPATH | BROKEN_DISPLAY_NAME },
177 { "auto", SERVICE_AUTO_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY,
178 BROKEN_DISPLAY_NAME },
179 { "demand", SERVICE_DEMAND_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY,
180 BROKEN_DISPLAY_NAME },
181 { "disabled", SERVICE_DISABLED, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY,
182 BROKEN_DISPLAY_NAME },
183 { "delayed-auto", SERVICE_DELAYED_AUTO_START, SERVICE_WIN32_OWN_PROCESS, TEST_SERVICE_BINARY,
184 BROKEN_START | BROKEN_DISPLAY_NAME | BROKEN_DELAYED_AUTO_START }
186 static struct {
187 const char *param;
188 DWORD expected_error_control;
189 } error_severities[] = {
190 { "normal", SERVICE_ERROR_NORMAL },
191 { "severe", SERVICE_ERROR_SEVERE },
192 { "critical", SERVICE_ERROR_CRITICAL },
193 { "ignore", SERVICE_ERROR_IGNORE }
195 unsigned int i;
196 DWORD r;
198 if (!elevated)
200 win_skip("\"sc create\" tests need elevated permissions\n");
201 return;
204 #define check_exit_code(x) ok(r == (x), "got exit code %ld, expected %d\n", r, (x))
205 #define check_test_service(t,s,e,de,di,br) \
206 check_service_definition(TEST_SERVICE_NAME, TEST_SERVICE_BINARY, t, s, e, de, di ? di : TEST_SERVICE_NAME, br)
207 #define delete_test_service(x, y) \
208 delete_service(TEST_SERVICE_NAME, (x) ? SC_EXIT_SUCCESS : SC_EXIT_SERVICE_DOES_NOT_EXIST, (y))
209 #define check_test_service2(t,s,e,de,di,br) \
210 check_service_definition(TEST_SERVICE_NAME2, TEST_SERVICE_BINARY, t, s, e, de, di ? di : TEST_SERVICE_NAME2, br)
211 #define delete_test_service2(x, y) \
212 delete_service(TEST_SERVICE_NAME2, (x) ? SC_EXIT_SUCCESS : SC_EXIT_SERVICE_DOES_NOT_EXIST, (y))
214 /* too few parameters */
216 run_sc_exe("sc create", &r);
217 todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE);
218 delete_test_service(FALSE, FALSE);
220 run_sc_exe("sc create " TEST_SERVICE_NAME, &r);
221 todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE);
222 delete_test_service(FALSE, FALSE);
224 /* binpath= */
226 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\"", &r);
227 check_exit_code(SC_EXIT_SUCCESS);
228 check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL,
229 BROKEN_DISPLAY_NAME);
231 /* existing service */
233 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" start= auto", &r);
234 todo_wine check_exit_code(SC_EXIT_SERVICE_EXISTS);
235 check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL,
236 BROKEN_DISPLAY_NAME);
237 delete_test_service(TRUE, FALSE);
239 /* type= */
241 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" type= invalid", &r);
242 todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE);
243 delete_test_service(FALSE, TRUE);
245 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" type= own", &r);
246 check_exit_code(SC_EXIT_SUCCESS);
247 check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL,
248 BROKEN_DISPLAY_NAME);
249 delete_test_service(TRUE, FALSE);
251 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" type= interact", &r);
252 todo_wine check_exit_code(SC_EXIT_INVALID_PARAMETER);
253 delete_test_service(FALSE, TRUE);
255 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" type= interact type= own", &r);
256 check_exit_code(SC_EXIT_SUCCESS);
257 check_test_service(SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START,
258 SERVICE_ERROR_NORMAL, "", NULL, BROKEN_TYPE | BROKEN_DISPLAY_NAME);
259 delete_test_service(TRUE, FALSE);
261 /* start= */
263 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" start= invalid", &r);
264 todo_wine check_exit_code(SC_EXIT_INVALID_COMMAND_LINE);
265 delete_test_service(FALSE, TRUE);
267 for (i = 0; i < ARRAY_SIZE(start_types); i++)
269 char cmdline[256];
271 strcpy(cmdline, "sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" start= ");
272 strcat(cmdline, start_types[i].param);
273 run_sc_exe(cmdline, &r);
274 check_exit_code(SC_EXIT_SUCCESS);
275 check_service_definition(TEST_SERVICE_NAME, start_types[i].expected_binary_path,
276 start_types[i].expected_service_type, start_types[i].expected_start_type,
277 SERVICE_ERROR_NORMAL, "", TEST_SERVICE_NAME, start_types[i].broken);
278 delete_test_service(TRUE, FALSE);
281 /* error= */
283 for (i = 0; i < ARRAY_SIZE(error_severities); i++)
285 char cmdline[256];
287 strcpy(cmdline, "sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" error= ");
288 strcat(cmdline, error_severities[i].param);
289 run_sc_exe(cmdline, &r);
290 check_exit_code(SC_EXIT_SUCCESS);
291 check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,
292 error_severities[i].expected_error_control, "", NULL, BROKEN_DISPLAY_NAME);
293 delete_test_service(TRUE, FALSE);
296 /* tag= */
298 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" tag= yes", &r);
299 todo_wine check_exit_code(SC_EXIT_INVALID_PARAMETER);
300 delete_test_service(FALSE, TRUE);
302 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" tag= no", &r);
303 check_exit_code(SC_EXIT_SUCCESS);
304 check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "", NULL,
305 BROKEN_DISPLAY_NAME);
306 delete_test_service(TRUE, FALSE);
308 /* depend= */
310 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= \"" TEST_SERVICE_BINARY "\" depend= " TEST_SERVICE_NAME, &r);
311 todo_wine check_exit_code(SC_EXIT_CIRCULAR_DEPENDENCY);
312 delete_test_service(FALSE, TRUE);
314 run_sc_exe("sc create " TEST_SERVICE_NAME2 " binpath= \"" TEST_SERVICE_BINARY "\" depend= " TEST_SERVICE_NAME, &r);
315 check_exit_code(SC_EXIT_SUCCESS);
316 check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
317 TEST_SERVICE_NAME, NULL, BROKEN_DEPEND | BROKEN_DISPLAY_NAME);
318 delete_test_service2(TRUE, FALSE);
320 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= " TEST_SERVICE_BINARY, &r);
321 check_exit_code(SC_EXIT_SUCCESS);
322 run_sc_exe("sc create " TEST_SERVICE_NAME2 " binpath= \"" TEST_SERVICE_BINARY "\" depend= " TEST_SERVICE_NAME, &r);
323 check_exit_code(SC_EXIT_SUCCESS);
324 check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
325 TEST_SERVICE_NAME, NULL, BROKEN_DEPEND | BROKEN_DISPLAY_NAME);
326 delete_test_service2(TRUE, FALSE);
327 delete_test_service(TRUE, FALSE);
329 /* displayname= */
331 run_sc_exe("sc create " TEST_SERVICE_NAME " binpath= " TEST_SERVICE_BINARY
332 " displayname= \"Wine Test Service\"", &r);
333 check_exit_code(SC_EXIT_SUCCESS);
334 check_test_service(SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, "",
335 "Wine Test Service", 0);
336 delete_test_service(TRUE, FALSE);
338 /* without spaces */
340 run_sc_exe("sc create " TEST_SERVICE_NAME2 " binpath=\"" TEST_SERVICE_BINARY "\" type=own start=auto"
341 " error=normal tag=no depend=" TEST_SERVICE_NAME " displayname=\"Wine Test Service\"", &r);
342 ok(r == SC_EXIT_SUCCESS || broken(r == SC_EXIT_INVALID_COMMAND_LINE), "got exit code %ld, expected %d\n",
343 r, SC_EXIT_SUCCESS);
344 if (r == SC_EXIT_SUCCESS)
346 check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
347 TEST_SERVICE_NAME, "Wine Test Service", BROKEN_DEPEND);
348 delete_test_service2(TRUE, FALSE);
350 else
352 delete_test_service2(FALSE, FALSE);
355 /* case-insensitive */
357 run_sc_exe("SC CREATE " TEST_SERVICE_NAME2 " BINPATH= \"" TEST_SERVICE_BINARY "\" TYPE= OWN START= AUTO"
358 " ERROR= NORMAL TAG= NO DEPEND= " TEST_SERVICE_NAME " DISPLAYNAME= \"Wine Test Service\"", &r);
359 check_exit_code(SC_EXIT_SUCCESS);
360 check_test_service2(SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
361 TEST_SERVICE_NAME, "Wine Test Service", BROKEN_DEPEND);
362 delete_test_service2(TRUE, FALSE);
364 #undef delete_test_service2
365 #undef check_test_service2
366 #undef delete_test_service
367 #undef check_test_service
368 #undef check_exit_code
371 /* taken from winetest, only whitespace changes */
372 static int running_elevated(void)
374 HANDLE token;
375 TOKEN_ELEVATION elevation_info;
376 DWORD size;
378 /* Get the process token */
379 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
380 return -1;
382 /* Get the elevation info from the token */
383 if (!GetTokenInformation(token, TokenElevation, &elevation_info, sizeof(TOKEN_ELEVATION), &size))
385 CloseHandle(token);
386 return -1;
388 CloseHandle(token);
390 return elevation_info.TokenIsElevated;
394 START_TEST(sc)
396 SECURITY_ATTRIBUTES secattr = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
397 BOOL elevated = running_elevated();
399 nul_file = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE, 0, &secattr, OPEN_EXISTING,
400 FILE_ATTRIBUTE_NORMAL, NULL);
402 scmgr = OpenSCManagerA(NULL, NULL, GENERIC_READ);
403 ok(!!scmgr, "OpenSCManagerA failed: %ld\n", GetLastError());
405 test_create_service(elevated);
407 CloseServiceHandle(scmgr);
408 CloseHandle(nul_file);