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 
15 static SERVICE_STATUS_HANDLE status_handle;
16 
17 static void
18 report_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 
55 static 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 
67 static void WINAPI
68 service_main(DWORD dwArgc, LPWSTR* lpszArgv)
69 {
70     // SERVICE_STATUS_HANDLE status_handle;
71     LPWSTR lpEnvironment, lpEnvStr;
72     DWORD dwSize;
73 
74     UNREFERENCED_PARAMETER(dwArgc);
75     UNREFERENCED_PARAMETER(lpszArgv);
76 
77     /* Register our service for control (lpszArgv[0] holds the service name) */
78     status_handle = RegisterServiceCtrlHandlerW(lpszArgv[0], service_handler);
79     service_ok(status_handle != NULL, "RegisterServiceCtrlHandler failed: %lu\n", GetLastError());
80     if (!status_handle)
81         return;
82 
83     /* Report SERVICE_RUNNING status */
84     report_service_status(SERVICE_RUNNING, NO_ERROR, 4000);
85 
86     /* Display our current environment for informative purposes */
87     lpEnvironment = GetEnvironmentStringsW();
88     lpEnvStr = lpEnvironment;
89     while (*lpEnvStr)
90     {
91         service_trace("%S\n", lpEnvStr);
92         lpEnvStr += wcslen(lpEnvStr) + 1;
93     }
94     FreeEnvironmentStringsW(lpEnvironment);
95 
96     /* Check the presence of the user-related environment variables */
97     dwSize = GetEnvironmentVariableW(L"ALLUSERSPROFILE", NULL, 0);
98     service_ok(dwSize != 0, "ALLUSERSPROFILE envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError());
99     dwSize = GetEnvironmentVariableW(L"USERPROFILE", NULL, 0);
100     service_ok(dwSize != 0, "USERPROFILE envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError());
101 #if 0 // May not always exist
102     dwSize = GetEnvironmentVariableW(L"USERNAME", NULL, 0);
103     service_ok(dwSize != 0, "USERNAME envvar not found, or GetEnvironmentVariableW failed: %lu\n", GetLastError());
104 #endif
105 
106     /* Work is done */
107     report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
108 }
109 
110 static BOOL start_service(PCSTR service_nameA, PCWSTR service_nameW)
111 {
112     BOOL res;
113 
114     SERVICE_TABLE_ENTRYW servtbl[] =
115     {
116         { (PWSTR)service_nameW, service_main },
117         { NULL, NULL }
118     };
119 
120     res = StartServiceCtrlDispatcherW(servtbl);
121     service_ok(res, "StartServiceCtrlDispatcherW failed: %lu\n", GetLastError());
122     return res;
123 }
124 
125 
126 /*** Tester part of the test ***/
127 
128 static void
129 my_test_server(PCSTR service_nameA,
130                PCWSTR service_nameW,
131                void *param)
132 {
133     BOOL res;
134     SC_HANDLE hSC = NULL;
135     SC_HANDLE hService = NULL;
136     SERVICE_STATUS ServiceStatus;
137 
138     /* Open the SCM */
139     hSC = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
140     if (!hSC)
141     {
142         skip("OpenSCManagerW failed with error %lu!\n", GetLastError());
143         return;
144     }
145 
146     /* First create ourselves as a service running in the default LocalSystem account */
147     hService = register_service_exW(hSC, L"ServiceEnv", service_nameW, NULL,
148                                     SERVICE_ALL_ACCESS,
149                                     SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
150                                     SERVICE_DEMAND_START,
151                                     SERVICE_ERROR_IGNORE,
152                                     NULL, NULL, NULL,
153                                     NULL, NULL);
154     if (!hService)
155     {
156         skip("CreateServiceW failed with error %lu!\n", GetLastError());
157         goto Cleanup;
158     }
159 
160     /* Start it */
161     if (!StartServiceW(hService, 0, NULL))
162     {
163         skip("StartServiceW failed with error %lu!\n", GetLastError());
164         goto Cleanup;
165     }
166 
167     /* Wait for the service to stop by itself */
168     do
169     {
170         Sleep(100);
171         ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
172         res = QueryServiceStatus(hService, &ServiceStatus);
173     } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED);
174     ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
175     ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState);
176 
177     /* Be sure the service is really stopped */
178     res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
179     if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
180         ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING &&
181         GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
182     {
183         skip("ControlService failed with error %lu!\n", GetLastError());
184         goto Cleanup;
185     }
186 
187 #if 0
188     trace("Service stopped. Going to restart it...\n");
189 
190     /* Now change the service configuration to make it start under the NetworkService account */
191     if (!ChangeServiceConfigW(hService,
192                               SERVICE_NO_CHANGE,
193                               SERVICE_NO_CHANGE,
194                               SERVICE_NO_CHANGE,
195                               NULL, NULL, NULL, NULL,
196                               L"NT AUTHORITY\\NetworkService", L"",
197                               NULL))
198     {
199         skip("ChangeServiceConfigW failed with error %lu!\n", GetLastError());
200         goto Cleanup;
201     }
202 
203     /* Start it */
204     if (!StartServiceW(hService, 0, NULL))
205     {
206         skip("StartServiceW failed with error %lu!\n", GetLastError());
207         goto Cleanup;
208     }
209 
210     /* Wait for the service to stop by itself */
211     do
212     {
213         Sleep(100);
214         ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
215         res = QueryServiceStatus(hService, &ServiceStatus);
216     } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED);
217     ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
218     ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, "ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState);
219 
220     /* Be sure the service is really stopped */
221     res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
222     if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
223         ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING &&
224         GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
225     {
226         skip("ControlService failed with error %lu!\n", GetLastError());
227         goto Cleanup;
228     }
229 #endif
230 
231 Cleanup:
232     if (hService)
233     {
234         res = DeleteService(hService);
235         ok(res, "DeleteService failed: %lu\n", GetLastError());
236         CloseServiceHandle(hService);
237     }
238 
239     if (hSC)
240         CloseServiceHandle(hSC);
241 }
242 
243 START_TEST(ServiceEnv)
244 {
245     int argc;
246     char** argv;
247 
248     /* Check whether this test is started as a separated service process */
249     argc = winetest_get_mainargs(&argv);
250     if (argc >= 3)
251     {
252         service_process(start_service, argc, argv);
253         return;
254     }
255 
256     /* We are started as the real test */
257     test_runner(my_test_server, NULL);
258     // trace("Returned from test_runner\n");
259 }
260