1 /*
2  * PROJECT:     ReactOS kernel-mode tests
3  * LICENSE:     LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4  * PURPOSE:     Kernel-Mode Test Suite loader service control functions
5  * COPYRIGHT:   Copyright 2011-2018 Thomas Faber <thomas.faber@reactos.org>
6  *              Copyright 2017 Ged Murphy <gedmurphy@reactos.org>
7  */
8 
9 #include <kmt_test.h>
10 #include "kmtest.h"
11 
12 #include <assert.h>
13 
14 #define SERVICE_ACCESS (SERVICE_START | SERVICE_STOP | DELETE)
15 
16 /*
17  * This is an internal function not meant for use by the kmtests app,
18  * so we declare it here instead of kmtest.h
19  */
20 DWORD
21 KmtpCreateService(
22     IN PCWSTR ServiceName,
23     IN PCWSTR ServicePath,
24     IN PCWSTR DisplayName OPTIONAL,
25     IN DWORD ServiceType,
26     OUT SC_HANDLE *ServiceHandle);
27 
28 
29 static SC_HANDLE ScmHandle;
30 
31 /**
32  * @name KmtServiceInit
33  *
34  * Initialize service management routines (by opening the service control manager)
35  *
36  * @return Win32 error code
37  */
38 DWORD
39 KmtServiceInit(VOID)
40 {
41     DWORD Error = ERROR_SUCCESS;
42 
43     assert(!ScmHandle);
44 
45     ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
46     if (!ScmHandle)
47         error(Error);
48 
49     return Error;
50 }
51 
52 /**
53  * @name KmtServiceCleanup
54  *
55  * Clean up resources used by service management routines.
56  *
57  * @param IgnoreErrors
58  *        If TRUE, the function will never set ErrorLineAndFile, and always return ERROR_SUCCESS
59  *
60  * @return Win32 error code
61  */
62 DWORD
63 KmtServiceCleanup(
64     BOOLEAN IgnoreErrors)
65 {
66     DWORD Error = ERROR_SUCCESS;
67 
68     if (ScmHandle && !CloseServiceHandle(ScmHandle) && !IgnoreErrors)
69         error(Error);
70 
71     return Error;
72 }
73 
74 /**
75  * @name KmtCreateService
76  *
77  * Create the specified driver service and return a handle to it
78  *
79  * @param ServiceName
80  *        Name of the service to create
81  * @param ServicePath
82  *        File name of the driver, relative to the current directory
83  * @param DisplayName
84  *        Service display name
85  * @param ServiceHandle
86  *        Pointer to a variable to receive the handle to the service
87  *
88  * @return Win32 error code
89  */
90 DWORD
91 KmtCreateService(
92     IN PCWSTR ServiceName,
93     IN PCWSTR ServicePath,
94     IN PCWSTR DisplayName OPTIONAL,
95     OUT SC_HANDLE *ServiceHandle)
96 {
97     return KmtpCreateService(ServiceName,
98                              ServicePath,
99                              DisplayName,
100                              SERVICE_KERNEL_DRIVER,
101                              ServiceHandle);
102 }
103 
104 /**
105  * @name KmtStartService
106  *
107  * Start the specified driver service by handle or name (and return a handle to it)
108  *
109  * @param ServiceName
110  *        If *ServiceHandle is NULL, name of the service to start
111  * @param ServiceHandle
112  *        Pointer to a variable containing the service handle,
113  *        or NULL (in which case it will be filled with a handle to the service)
114  *
115  * @return Win32 error code
116  */
117 DWORD
118 KmtStartService(
119     IN PCWSTR ServiceName OPTIONAL,
120     IN OUT SC_HANDLE *ServiceHandle)
121 {
122     DWORD Error = ERROR_SUCCESS;
123 
124     assert(ServiceHandle);
125     assert(ServiceName || *ServiceHandle);
126 
127     if (!*ServiceHandle)
128         *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
129 
130     if (!*ServiceHandle)
131         error_goto(Error, cleanup);
132 
133     if (!StartService(*ServiceHandle, 0, NULL))
134         error_goto(Error, cleanup);
135 
136 cleanup:
137     return Error;
138 }
139 
140 /**
141  * @name KmtCreateAndStartService
142  *
143  * Create and start the specified driver service and return a handle to it
144  *
145  * @param ServiceName
146  *        Name of the service to create
147  * @param ServicePath
148  *        File name of the driver, relative to the current directory
149  * @param DisplayName
150  *        Service display name
151  * @param ServiceHandle
152  *        Pointer to a variable to receive the handle to the service
153  * @param RestartIfRunning
154  *        TRUE to stop and restart the service if it is already running
155  *
156  * @return Win32 error code
157  */
158 DWORD
159 KmtCreateAndStartService(
160     IN PCWSTR ServiceName,
161     IN PCWSTR ServicePath,
162     IN PCWSTR DisplayName OPTIONAL,
163     OUT SC_HANDLE *ServiceHandle,
164     IN BOOLEAN RestartIfRunning)
165 {
166     DWORD Error = ERROR_SUCCESS;
167 
168     assert(ServiceHandle);
169 
170     Error = KmtCreateService(ServiceName, ServicePath, DisplayName, ServiceHandle);
171 
172     if (Error && Error != ERROR_SERVICE_EXISTS)
173         goto cleanup;
174 
175     Error = KmtStartService(ServiceName, ServiceHandle);
176 
177     if (Error != ERROR_SERVICE_ALREADY_RUNNING)
178         goto cleanup;
179 
180     Error = ERROR_SUCCESS;
181 
182     if (!RestartIfRunning)
183         goto cleanup;
184 
185     Error = KmtStopService(ServiceName, ServiceHandle);
186     if (Error)
187         goto cleanup;
188 
189     Error = KmtStartService(ServiceName, ServiceHandle);
190     if (Error)
191         goto cleanup;
192 
193 cleanup:
194     assert(Error || *ServiceHandle);
195     return Error;
196 }
197 
198 /**
199  * @name KmtStopService
200  *
201  * Stop the specified driver service by handle or name (and return a handle to it)
202  *
203  * @param ServiceName
204  *        If *ServiceHandle is NULL, name of the service to stop
205  * @param ServiceHandle
206  *        Pointer to a variable containing the service handle,
207  *        or NULL (in which case it will be filled with a handle to the service)
208  *
209  * @return Win32 error code
210  */
211 DWORD
212 KmtStopService(
213     IN PCWSTR ServiceName OPTIONAL,
214     IN OUT SC_HANDLE *ServiceHandle)
215 {
216     DWORD Error = ERROR_SUCCESS;
217     SERVICE_STATUS ServiceStatus;
218 
219     assert(ServiceHandle);
220     assert(ServiceName || *ServiceHandle);
221 
222     if (!*ServiceHandle)
223         *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
224 
225     if (!*ServiceHandle)
226         error_goto(Error, cleanup);
227 
228     if (!ControlService(*ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus))
229         error_goto(Error, cleanup);
230 
231 cleanup:
232     return Error;
233 }
234 
235 /**
236  * @name KmtDeleteService
237  *
238  * Delete the specified driver service by handle or name (and return a handle to it)
239  *
240  * @param ServiceName
241  *        If *ServiceHandle is NULL, name of the service to delete
242  * @param ServiceHandle
243  *        Pointer to a variable containing the service handle.
244  *        Will be set to NULL on success
245  *
246  * @return Win32 error code
247  */
248 DWORD
249 KmtDeleteService(
250     IN PCWSTR ServiceName OPTIONAL,
251     IN OUT SC_HANDLE *ServiceHandle)
252 {
253     DWORD Error = ERROR_SUCCESS;
254 
255     assert(ServiceHandle);
256     assert(ServiceName || *ServiceHandle);
257 
258     if (!*ServiceHandle)
259         *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
260 
261     if (!*ServiceHandle)
262         error_goto(Error, cleanup);
263 
264     if (!DeleteService(*ServiceHandle))
265         error_goto(Error, cleanup);
266 
267     if (*ServiceHandle)
268         CloseServiceHandle(*ServiceHandle);
269 
270 cleanup:
271     return Error;
272 }
273 
274 /**
275  * @name KmtCloseService
276  *
277  * Close the specified driver service handle
278  *
279  * @param ServiceHandle
280  *        Pointer to a variable containing the service handle.
281  *        Will be set to NULL on success
282  *
283  * @return Win32 error code
284  */
285 DWORD KmtCloseService(
286     IN OUT SC_HANDLE *ServiceHandle)
287 {
288     DWORD Error = ERROR_SUCCESS;
289 
290     assert(ServiceHandle);
291 
292     if (*ServiceHandle && !CloseServiceHandle(*ServiceHandle))
293         error_goto(Error, cleanup);
294 
295     *ServiceHandle = NULL;
296 
297 cleanup:
298     return Error;
299 }
300 
301 
302 /*
303  * Private function, not meant for use in kmtests
304  * See KmtCreateService & KmtFltCreateService
305  */
306 DWORD
307 KmtpCreateService(
308     IN PCWSTR ServiceName,
309     IN PCWSTR ServicePath,
310     IN PCWSTR DisplayName OPTIONAL,
311     IN DWORD ServiceType,
312     OUT SC_HANDLE *ServiceHandle)
313 {
314     DWORD Error = ERROR_SUCCESS;
315     WCHAR DriverPath[MAX_PATH];
316     HRESULT result = S_OK;
317 
318     assert(ServiceHandle);
319     assert(ServiceName && ServicePath);
320 
321     if (!GetModuleFileName(NULL, DriverPath, sizeof DriverPath / sizeof DriverPath[0]))
322         error_goto(Error, cleanup);
323 
324     assert(wcsrchr(DriverPath, L'\\') != NULL);
325     wcsrchr(DriverPath, L'\\')[1] = L'\0';
326 
327     result = StringCbCat(DriverPath, sizeof DriverPath, ServicePath);
328     if (FAILED(result))
329         error_value_goto(Error, result, cleanup);
330 
331     if (GetFileAttributes(DriverPath) == INVALID_FILE_ATTRIBUTES)
332         error_goto(Error, cleanup);
333 
334     *ServiceHandle = CreateService(ScmHandle, ServiceName, DisplayName,
335                                    SERVICE_ACCESS, ServiceType, SERVICE_DEMAND_START,
336                                    SERVICE_ERROR_NORMAL, DriverPath, NULL, NULL, NULL, NULL, NULL);
337 
338     if (!*ServiceHandle)
339         error_goto(Error, cleanup);
340 
341 cleanup:
342     return Error;
343 }