Reactos
1/*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for service process environment block
5 * PROGRAMMER: Hermes Belusca-Maito
6 */
7
8#include "precomp.h"
9
10#include "svchlp.h"
11
12
13/*** Service part of the test ***/
14
15static SERVICE_STATUS_HANDLE status_handle;
16
17static void
18report_service_status(DWORD dwCurrentState,
19 DWORD dwWin32ExitCode,
20 DWORD dwWaitHint)
21{
22 BOOL res;
23 SERVICE_STATUS status;
24
25 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
26 status.dwCurrentState = dwCurrentState;
27 status.dwWin32ExitCode = dwWin32ExitCode;
28 status.dwWaitHint = dwWaitHint;
29
30 status.dwServiceSpecificExitCode = 0;
31 status.dwCheckPoint = 0;
32
33 if ( (dwCurrentState == SERVICE_START_PENDING) ||
34 (dwCurrentState == SERVICE_STOP_PENDING) ||
35 (dwCurrentState == SERVICE_STOPPED) )
36 {
37 status.dwControlsAccepted = 0;
38 }
39 else
40 {
41 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
42 }
43
44#if 0
45 if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) )
46 status.dwCheckPoint = 0;
47 else
48 status.dwCheckPoint = dwCheckPoint++;
49#endif
50
51 res = SetServiceStatus(status_handle, &status);
52 service_ok(res, "SetServiceStatus(%d) failed: %lu\n", dwCurrentState, GetLastError());
53}
54
55static VOID WINAPI service_handler(DWORD ctrl)
56{
57 switch(ctrl)
58 {
59 case SERVICE_CONTROL_STOP:
60 case SERVICE_CONTROL_SHUTDOWN:
61 report_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
62 default:
63 report_service_status(SERVICE_RUNNING, NO_ERROR, 0);
64 }
65}
66
67static void WINAPI
68service_main(DWORD dwArgc, LPWSTR* lpszArgv)
69{
70 // SERVICE_STATUS_HANDLE status_handle;
71 LPWSTR lpEnvironment, lpEnvStr;
72 DWORD dwSize;
73 PTEB Teb;
74
75 UNREFERENCED_PARAMETER(dwArgc);
76 UNREFERENCED_PARAMETER(lpszArgv);
77
78 /* Register our service for control (lpszArgv[0] holds the service name) */
79 status_handle = RegisterServiceCtrlHandlerW(lpszArgv[0], service_handler);
80 service_ok(status_handle != NULL, "RegisterServiceCtrlHandler failed: %lu\n", GetLastError());
81 if (!status_handle)
82 return;
83
84 /* Report SERVICE_RUNNING status */
85 report_service_status(SERVICE_RUNNING, NO_ERROR, 4000);
86
87 /* Display our current environment for informative purposes */
88 lpEnvironment = GetEnvironmentStringsW();
89 lpEnvStr = lpEnvironment;
90 while (*lpEnvStr)
91 {
92 service_trace("%S\n", lpEnvStr);
93 lpEnvStr += wcslen(lpEnvStr) + 1;
94 }
95 FreeEnvironmentStringsW(lpEnvironment);
96
97 /* Check the presence of the user-related environment variables */
98 dwSize = GetEnvironmentVariableW(L"ALLUSERSPROFILE", NULL, 0);
99 service_ok(dwSize != 0, "ALLUSERSPROFILE envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError());
100 dwSize = GetEnvironmentVariableW(L"USERPROFILE", NULL, 0);
101 service_ok(dwSize != 0, "USERPROFILE envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError());
102#if 0 // May not always exist
103 dwSize = GetEnvironmentVariableW(L"USERNAME", NULL, 0);
104 service_ok(dwSize != 0, "USERNAME envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError());
105#endif
106
107 Teb = NtCurrentTeb();
108 service_ok(Teb->SubProcessTag != 0, "SubProcessTag is not defined!\n");
109 if (Teb->SubProcessTag != 0)
110 {
111 ULONG (NTAPI *_I_QueryTagInformation)(PVOID, DWORD, PVOID) = (PVOID)GetProcAddress(GetModuleHandle("advapi32.dll"), "I_QueryTagInformation");
112 if (_I_QueryTagInformation != NULL)
113 {
114 /* IN/OUT parameter structure for I_QueryTagInformation() function
115 * See: https://wj32.org/wp/2010/03/30/howto-use-i_querytaginformation/
116 * See: https://github.com/processhacker/processhacker/blob/master/phnt/include/subprocesstag.h
117 */
118 struct
119 {
120 ULONG ProcessId;
121 PVOID ServiceTag;
122 ULONG TagType;
123 PWSTR Buffer;
124 } ServiceQuery;
125
126 /* Set our input parameters */
127 ServiceQuery.ProcessId = GetCurrentProcessId();
128 ServiceQuery.ServiceTag = Teb->SubProcessTag;
129 ServiceQuery.TagType = 0;
130 ServiceQuery.Buffer = NULL;
131 /* Call ADVAPI32 to query the correctness of our tag */
132 _I_QueryTagInformation(NULL, 1, &ServiceQuery);
133
134 /* If buffer is not NULL, call succeed */
135 if (ServiceQuery.Buffer != NULL)
136 {
137 /* It should match our service name */
138 service_ok(wcscmp(lpszArgv[0], ServiceQuery.Buffer) == 0, "Mismatching info: %S - %S\n", lpszArgv[0], ServiceQuery.Buffer);
139 service_ok(ServiceQuery.TagType == 1, "Invalid tag type: %x\n", ServiceQuery.TagType);
140 LocalFree(ServiceQuery.Buffer);
141 }
142 }
143 }
144
145 /* Work is done */
146 report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
147}
148
149static BOOL start_service(PCSTR service_nameA, PCWSTR service_nameW)
150{
151 BOOL res;
152
153 SERVICE_TABLE_ENTRYW servtbl[] =
154 {
155 { (PWSTR)service_nameW, service_main },
156 { NULL, NULL }
157 };
158
159 res = StartServiceCtrlDispatcherW(servtbl);
160 service_ok(res, "StartServiceCtrlDispatcherW failed: %lu\n", GetLastError());
161 return res;
162}
163
164
165/*** Tester part of the test ***/
166
167static void
168my_test_server(PCSTR service_nameA,
169 PCWSTR service_nameW,
170 void *param)
171{
172 BOOL res;
173 SC_HANDLE hSC = NULL;
174 SC_HANDLE hService = NULL;
175 SERVICE_STATUS ServiceStatus;
176
177 /* Open the SCM */
178 hSC = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
179 if (!hSC)
180 {
181 skip("OpenSCManagerW failed with error %lu!\n", GetLastError());
182 return;
183 }
184
185 /* First create ourselves as a service running in the default LocalSystem account */
186 hService = register_service_exW(hSC, L"ServiceEnv", service_nameW, NULL,
187 SERVICE_ALL_ACCESS,
188 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
189 SERVICE_DEMAND_START,
190 SERVICE_ERROR_IGNORE,
191 NULL, NULL, NULL,
192 NULL, NULL);
193 if (!hService)
194 {
195 skip("CreateServiceW failed with error %lu!\n", GetLastError());
196 goto Cleanup;
197 }
198
199 /* Start it */
200 if (!StartServiceW(hService, 0, NULL))
201 {
202 skip("StartServiceW failed with error %lu!\n", GetLastError());
203 goto Cleanup;
204 }
205
206 /* Wait for the service to stop by itself */
207 do
208 {
209 Sleep(100);
210 ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
211 res = QueryServiceStatus(hService, &ServiceStatus);
212 } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED);
213 ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
214 ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState);
215
216 /* Be sure the service is really stopped */
217 res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
218 if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
219 ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING &&
220 GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
221 {
222 skip("ControlService failed with error %lu!\n", GetLastError());
223 goto Cleanup;
224 }
225
226#if 0
227 trace("Service stopped. Going to restart it...\n");
228
229 /* Now change the service configuration to make it start under the NetworkService account */
230 if (!ChangeServiceConfigW(hService,
231 SERVICE_NO_CHANGE,
232 SERVICE_NO_CHANGE,
233 SERVICE_NO_CHANGE,
234 NULL, NULL, NULL, NULL,
235 L"NT AUTHORITY\\NetworkService", L"",
236 NULL))
237 {
238 skip("ChangeServiceConfigW failed with error %lu!\n", GetLastError());
239 goto Cleanup;
240 }
241
242 /* Start it */
243 if (!StartServiceW(hService, 0, NULL))
244 {
245 skip("StartServiceW failed with error %lu!\n", GetLastError());
246 goto Cleanup;
247 }
248
249 /* Wait for the service to stop by itself */
250 do
251 {
252 Sleep(100);
253 ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
254 res = QueryServiceStatus(hService, &ServiceStatus);
255 } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED);
256 ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
257 ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState);
258
259 /* Be sure the service is really stopped */
260 res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
261 if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
262 ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING &&
263 GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
264 {
265 skip("ControlService failed with error %lu!\n", GetLastError());
266 goto Cleanup;
267 }
268#endif
269
270Cleanup:
271 if (hService)
272 {
273 res = DeleteService(hService);
274 ok(res, "DeleteService failed: %lu\n", GetLastError());
275 CloseServiceHandle(hService);
276 }
277
278 if (hSC)
279 CloseServiceHandle(hSC);
280}
281
282START_TEST(ServiceEnv)
283{
284 int argc;
285 char** argv;
286 PTEB Teb;
287
288 /* Check whether this test is started as a separated service process */
289 argc = winetest_get_mainargs(&argv);
290 if (argc >= 3)
291 {
292 service_process(start_service, argc, argv);
293 return;
294 }
295
296 Teb = NtCurrentTeb();
297 ok(Teb->SubProcessTag == 0, "SubProcessTag is defined: %p\n", Teb->SubProcessTag);
298
299 /* We are started as the real test */
300 test_runner(my_test_server, NULL);
301 // trace("Returned from test_runner\n");
302}