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 * Copyright 2018 Serge Gautherie <reactos-git_serge_171003@gautherie.fr> 8 */ 9 10 #include <kmt_test.h> 11 #include "kmtest.h" 12 13 #include <assert.h> 14 15 #define SERVICE_ACCESS (SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP | DELETE) 16 17 /* 18 * This is an internal function not meant for use by the kmtests app, 19 * so we declare it here instead of kmtest.h 20 */ 21 DWORD 22 KmtpCreateService( 23 IN PCWSTR ServiceName, 24 IN PCWSTR ServicePath, 25 IN PCWSTR DisplayName OPTIONAL, 26 IN DWORD ServiceType, 27 OUT SC_HANDLE *ServiceHandle); 28 29 30 static SC_HANDLE ScmHandle; 31 32 /** 33 * @name KmtServiceInit 34 * 35 * Initialize service management routines (by opening the service control manager) 36 * 37 * @return Win32 error code 38 */ 39 DWORD 40 KmtServiceInit(VOID) 41 { 42 DWORD Error = ERROR_SUCCESS; 43 44 assert(!ScmHandle); 45 46 ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); 47 if (!ScmHandle) 48 error(Error); 49 50 return Error; 51 } 52 53 /** 54 * @name KmtServiceCleanup 55 * 56 * Clean up resources used by service management routines. 57 * 58 * @param IgnoreErrors 59 * If TRUE, the function will never set ErrorLineAndFile, and always return ERROR_SUCCESS 60 * 61 * @return Win32 error code 62 */ 63 DWORD 64 KmtServiceCleanup( 65 BOOLEAN IgnoreErrors) 66 { 67 DWORD Error = ERROR_SUCCESS; 68 69 if (ScmHandle && !CloseServiceHandle(ScmHandle) && !IgnoreErrors) 70 error(Error); 71 72 return Error; 73 } 74 75 /** 76 * @name KmtCreateService 77 * 78 * Create the specified driver service and return a handle to it 79 * 80 * @param ServiceName 81 * Name of the service to create 82 * @param ServicePath 83 * File name of the driver, relative to the current directory 84 * @param DisplayName 85 * Service display name 86 * @param ServiceHandle 87 * Pointer to a variable to receive the handle to the service 88 * 89 * @return Win32 error code 90 */ 91 DWORD 92 KmtCreateService( 93 IN PCWSTR ServiceName, 94 IN PCWSTR ServicePath, 95 IN PCWSTR DisplayName OPTIONAL, 96 OUT SC_HANDLE *ServiceHandle) 97 { 98 return KmtpCreateService(ServiceName, 99 ServicePath, 100 DisplayName, 101 SERVICE_KERNEL_DRIVER, 102 ServiceHandle); 103 } 104 105 /** 106 * @name KmtGetServiceStateAsString 107 * 108 * @param ServiceState 109 * Service state as a number 110 * 111 * @return Service state as a string 112 */ 113 static 114 PCSTR 115 KmtGetServiceStateAsString( 116 IN DWORD ServiceState) 117 { 118 switch(ServiceState) 119 { 120 case SERVICE_STOPPED: 121 return "STOPPED"; 122 case SERVICE_START_PENDING: 123 return "START_PENDING"; 124 case SERVICE_STOP_PENDING: 125 return "STOP_PENDING"; 126 case SERVICE_RUNNING: 127 return "RUNNING"; 128 case SERVICE_CONTINUE_PENDING: 129 return "CONTINUE_PENDING"; 130 case SERVICE_PAUSE_PENDING: 131 return "PAUSE_PENDING"; 132 case SERVICE_PAUSED: 133 return "PAUSED"; 134 default: 135 ok(FALSE, "Unknown service state = %lu\n", ServiceState); 136 return "(Unknown)"; 137 } 138 } 139 140 /** 141 * @name KmtEnsureServiceState 142 * 143 * @param ServiceName 144 * Name of the service to check, 145 * or NULL 146 * @param ServiceHandle 147 * Handle to the service 148 * @param ExpectedServiceState 149 * State which the service should be in 150 * 151 * @return Win32 error code 152 */ 153 static 154 DWORD 155 KmtEnsureServiceState( 156 IN PCWSTR ServiceName OPTIONAL, 157 IN SC_HANDLE ServiceHandle, 158 IN DWORD ExpectedServiceState) 159 { 160 DWORD Error = ERROR_SUCCESS; 161 SERVICE_STATUS ServiceStatus; 162 DWORD StartTime = GetTickCount(); 163 DWORD Timeout = 10 * 1000; 164 PCWSTR ServiceNameOut = ServiceName ? ServiceName : L"(handle only, no name)"; 165 166 assert(ServiceHandle); 167 assert(ExpectedServiceState); 168 169 if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) 170 error_goto(Error, cleanup); 171 172 while (ServiceStatus.dwCurrentState != ExpectedServiceState) 173 { 174 // NB: ServiceStatus.dwWaitHint and ServiceStatus.dwCheckPoint logic could be added, if need be. 175 176 Sleep(1 * 1000); 177 178 if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) 179 error_goto(Error, cleanup); 180 181 if (GetTickCount() - StartTime >= Timeout) 182 break; 183 } 184 185 if (ServiceStatus.dwCurrentState != ExpectedServiceState) 186 { 187 ok(FALSE, "Service = %ls, state = %lu %s (!= %lu %s), waitHint = %lu, checkPoint = %lu\n", 188 ServiceNameOut, 189 ServiceStatus.dwCurrentState, KmtGetServiceStateAsString(ServiceStatus.dwCurrentState), 190 ExpectedServiceState, KmtGetServiceStateAsString(ExpectedServiceState), 191 ServiceStatus.dwWaitHint, ServiceStatus.dwCheckPoint); 192 goto cleanup; 193 } 194 195 trace("Service = %ls, state = %lu %s\n", 196 ServiceNameOut, 197 ExpectedServiceState, KmtGetServiceStateAsString(ExpectedServiceState)); 198 199 cleanup: 200 return Error; 201 } 202 203 /** 204 * @name KmtStartService 205 * 206 * Start the specified driver service by handle or name (and return a handle to it) 207 * 208 * @param ServiceName 209 * If *ServiceHandle is NULL, name of the service to start 210 * @param ServiceHandle 211 * Pointer to a variable containing the service handle, 212 * or NULL (in which case it will be filled with a handle to the service) 213 * 214 * @return Win32 error code 215 */ 216 DWORD 217 KmtStartService( 218 IN PCWSTR ServiceName OPTIONAL, 219 IN OUT SC_HANDLE *ServiceHandle) 220 { 221 DWORD Error = ERROR_SUCCESS; 222 223 assert(ServiceHandle); 224 assert(ServiceName || *ServiceHandle); 225 226 if (!*ServiceHandle) 227 *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS); 228 229 if (!*ServiceHandle) 230 error_goto(Error, cleanup); 231 232 if (!StartService(*ServiceHandle, 0, NULL)) 233 error_goto(Error, cleanup); 234 235 Error = KmtEnsureServiceState(ServiceName, *ServiceHandle, SERVICE_RUNNING); 236 if (Error) 237 goto cleanup; 238 239 cleanup: 240 return Error; 241 } 242 243 /** 244 * @name KmtCreateAndStartService 245 * 246 * Create and start the specified driver service and return a handle to it 247 * 248 * @param ServiceName 249 * Name of the service to create 250 * @param ServicePath 251 * File name of the driver, relative to the current directory 252 * @param DisplayName 253 * Service display name 254 * @param ServiceHandle 255 * Pointer to a variable to receive the handle to the service 256 * @param RestartIfRunning 257 * TRUE to stop and restart the service if it is already running 258 * 259 * @return Win32 error code 260 */ 261 DWORD 262 KmtCreateAndStartService( 263 IN PCWSTR ServiceName, 264 IN PCWSTR ServicePath, 265 IN PCWSTR DisplayName OPTIONAL, 266 OUT SC_HANDLE *ServiceHandle, 267 IN BOOLEAN RestartIfRunning) 268 { 269 DWORD Error = ERROR_SUCCESS; 270 271 assert(ServiceHandle); 272 273 Error = KmtCreateService(ServiceName, ServicePath, DisplayName, ServiceHandle); 274 275 if (Error && Error != ERROR_SERVICE_EXISTS) 276 goto cleanup; 277 278 Error = KmtStartService(ServiceName, ServiceHandle); 279 280 if (Error != ERROR_SERVICE_ALREADY_RUNNING) 281 goto cleanup; 282 283 Error = ERROR_SUCCESS; 284 285 if (!RestartIfRunning) 286 goto cleanup; 287 288 Error = KmtStopService(ServiceName, ServiceHandle); 289 if (Error) 290 goto cleanup; 291 292 Error = KmtStartService(ServiceName, ServiceHandle); 293 if (Error) 294 goto cleanup; 295 296 cleanup: 297 assert(Error || *ServiceHandle); 298 return Error; 299 } 300 301 /** 302 * @name KmtStopService 303 * 304 * Stop the specified driver service by handle or name (and return a handle to it) 305 * 306 * @param ServiceName 307 * If *ServiceHandle is NULL, name of the service to stop 308 * @param ServiceHandle 309 * Pointer to a variable containing the service handle, 310 * or NULL (in which case it will be filled with a handle to the service) 311 * 312 * @return Win32 error code 313 */ 314 DWORD 315 KmtStopService( 316 IN PCWSTR ServiceName OPTIONAL, 317 IN OUT SC_HANDLE *ServiceHandle) 318 { 319 DWORD Error = ERROR_SUCCESS; 320 SERVICE_STATUS ServiceStatus; 321 322 assert(ServiceHandle); 323 assert(ServiceName || *ServiceHandle); 324 325 if (!*ServiceHandle) 326 *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS); 327 328 if (!*ServiceHandle) 329 error_goto(Error, cleanup); 330 331 if (!ControlService(*ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus)) 332 error_goto(Error, cleanup); 333 334 Error = KmtEnsureServiceState(ServiceName, *ServiceHandle, SERVICE_STOPPED); 335 if (Error) 336 goto cleanup; 337 338 cleanup: 339 return Error; 340 } 341 342 /** 343 * @name KmtDeleteService 344 * 345 * Delete the specified driver service by handle or name (and return a handle to it) 346 * 347 * @param ServiceName 348 * If *ServiceHandle is NULL, name of the service to delete 349 * @param ServiceHandle 350 * Pointer to a variable containing the service handle. 351 * Will be set to NULL on success 352 * 353 * @return Win32 error code 354 */ 355 DWORD 356 KmtDeleteService( 357 IN PCWSTR ServiceName OPTIONAL, 358 IN OUT SC_HANDLE *ServiceHandle) 359 { 360 DWORD Error = ERROR_SUCCESS; 361 362 assert(ServiceHandle); 363 assert(ServiceName || *ServiceHandle); 364 365 if (!*ServiceHandle) 366 *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS); 367 368 if (!*ServiceHandle) 369 error_goto(Error, cleanup); 370 371 if (!DeleteService(*ServiceHandle)) 372 error_goto(Error, cleanup); 373 374 if (*ServiceHandle) 375 CloseServiceHandle(*ServiceHandle); 376 377 cleanup: 378 return Error; 379 } 380 381 /** 382 * @name KmtCloseService 383 * 384 * Close the specified driver service handle 385 * 386 * @param ServiceHandle 387 * Pointer to a variable containing the service handle. 388 * Will be set to NULL on success 389 * 390 * @return Win32 error code 391 */ 392 DWORD KmtCloseService( 393 IN OUT SC_HANDLE *ServiceHandle) 394 { 395 DWORD Error = ERROR_SUCCESS; 396 397 assert(ServiceHandle); 398 399 if (*ServiceHandle && !CloseServiceHandle(*ServiceHandle)) 400 error_goto(Error, cleanup); 401 402 *ServiceHandle = NULL; 403 404 cleanup: 405 return Error; 406 } 407 408 409 /* 410 * Private function, not meant for use in kmtests 411 * See KmtCreateService & KmtFltCreateService 412 */ 413 DWORD 414 KmtpCreateService( 415 IN PCWSTR ServiceName, 416 IN PCWSTR ServicePath, 417 IN PCWSTR DisplayName OPTIONAL, 418 IN DWORD ServiceType, 419 OUT SC_HANDLE *ServiceHandle) 420 { 421 DWORD Error = ERROR_SUCCESS; 422 WCHAR DriverPath[MAX_PATH]; 423 HRESULT result = S_OK; 424 425 assert(ServiceHandle); 426 assert(ServiceName && ServicePath); 427 428 if (!GetModuleFileName(NULL, DriverPath, sizeof DriverPath / sizeof DriverPath[0])) 429 error_goto(Error, cleanup); 430 431 assert(wcsrchr(DriverPath, L'\\') != NULL); 432 wcsrchr(DriverPath, L'\\')[1] = L'\0'; 433 434 result = StringCbCat(DriverPath, sizeof DriverPath, ServicePath); 435 if (FAILED(result)) 436 error_value_goto(Error, result, cleanup); 437 438 if (GetFileAttributes(DriverPath) == INVALID_FILE_ATTRIBUTES) 439 error_goto(Error, cleanup); 440 441 *ServiceHandle = CreateService(ScmHandle, ServiceName, DisplayName, 442 SERVICE_ACCESS, ServiceType, SERVICE_DEMAND_START, 443 SERVICE_ERROR_NORMAL, DriverPath, NULL, NULL, NULL, NULL, NULL); 444 445 if (!*ServiceHandle) 446 error_goto(Error, cleanup); 447 448 cleanup: 449 return Error; 450 } 451