1 /* 2 * PROJECT: ReactOS Service Control Manager 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/system/services/driver.c 5 * PURPOSE: Driver control interface 6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl 7 * 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include "services.h" 13 14 #include <ndk/iofuncs.h> 15 #include <ndk/setypes.h> 16 17 #define NDEBUG 18 #include <debug.h> 19 20 /* FUNCTIONS ****************************************************************/ 21 22 static 23 DWORD 24 ScmLoadDriver(PSERVICE lpService) 25 { 26 NTSTATUS Status = STATUS_SUCCESS; 27 BOOLEAN WasPrivilegeEnabled = FALSE; 28 PWSTR pszDriverPath; 29 UNICODE_STRING DriverPath; 30 31 /* Build the driver path */ 32 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ 33 pszDriverPath = HeapAlloc(GetProcessHeap(), 34 HEAP_ZERO_MEMORY, 35 (52 + wcslen(lpService->lpServiceName) + 1) * sizeof(WCHAR)); 36 if (pszDriverPath == NULL) 37 return ERROR_NOT_ENOUGH_MEMORY; 38 39 wcscpy(pszDriverPath, 40 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 41 wcscat(pszDriverPath, 42 lpService->lpServiceName); 43 44 RtlInitUnicodeString(&DriverPath, 45 pszDriverPath); 46 47 DPRINT(" Path: %wZ\n", &DriverPath); 48 49 /* Acquire driver-loading privilege */ 50 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 51 TRUE, 52 FALSE, 53 &WasPrivilegeEnabled); 54 if (!NT_SUCCESS(Status)) 55 { 56 /* We encountered a failure, exit properly */ 57 DPRINT1("SERVICES: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status); 58 goto done; 59 } 60 61 Status = NtLoadDriver(&DriverPath); 62 63 /* Release driver-loading privilege */ 64 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 65 WasPrivilegeEnabled, 66 FALSE, 67 &WasPrivilegeEnabled); 68 69 done: 70 HeapFree(GetProcessHeap(), 0, pszDriverPath); 71 return RtlNtStatusToDosError(Status); 72 } 73 74 75 static 76 DWORD 77 ScmUnloadDriver(PSERVICE lpService) 78 { 79 NTSTATUS Status = STATUS_SUCCESS; 80 BOOLEAN WasPrivilegeEnabled = FALSE; 81 PWSTR pszDriverPath; 82 UNICODE_STRING DriverPath; 83 DWORD dwError; 84 85 /* Build the driver path */ 86 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ 87 pszDriverPath = HeapAlloc(GetProcessHeap(), 88 HEAP_ZERO_MEMORY, 89 (52 + wcslen(lpService->lpServiceName) + 1) * sizeof(WCHAR)); 90 if (pszDriverPath == NULL) 91 return ERROR_NOT_ENOUGH_MEMORY; 92 93 wcscpy(pszDriverPath, 94 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 95 wcscat(pszDriverPath, 96 lpService->lpServiceName); 97 98 RtlInitUnicodeString(&DriverPath, 99 pszDriverPath); 100 101 DPRINT(" Path: %wZ\n", &DriverPath); 102 103 /* Acquire driver-unloading privilege */ 104 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 105 TRUE, 106 FALSE, 107 &WasPrivilegeEnabled); 108 if (!NT_SUCCESS(Status)) 109 { 110 /* We encountered a failure, exit properly */ 111 DPRINT1("SERVICES: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status); 112 dwError = RtlNtStatusToDosError(Status); 113 goto done; 114 } 115 116 Status = NtUnloadDriver(&DriverPath); 117 if (Status == STATUS_INVALID_DEVICE_REQUEST) 118 dwError = ERROR_INVALID_SERVICE_CONTROL; 119 else 120 dwError = RtlNtStatusToDosError(Status); 121 122 /* Release driver-unloading privilege */ 123 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 124 WasPrivilegeEnabled, 125 FALSE, 126 &WasPrivilegeEnabled); 127 128 done: 129 HeapFree(GetProcessHeap(), 0, pszDriverPath); 130 return dwError; 131 } 132 133 134 static 135 DWORD 136 ScmGetDriverStatus(PSERVICE lpService, 137 LPSERVICE_STATUS lpServiceStatus) 138 { 139 OBJECT_ATTRIBUTES ObjectAttributes; 140 UNICODE_STRING DirName; 141 HANDLE DirHandle; 142 NTSTATUS Status = STATUS_SUCCESS; 143 POBJECT_DIRECTORY_INFORMATION DirInfo; 144 ULONG BufferLength; 145 ULONG DataLength; 146 ULONG Index; 147 DWORD dwError = ERROR_SUCCESS; 148 BOOLEAN bFound = FALSE; 149 DWORD dwPreviousState; 150 151 DPRINT1("ScmGetDriverStatus() called\n"); 152 153 /* Zero output buffer if any */ 154 if (lpServiceStatus != NULL) 155 { 156 memset(lpServiceStatus, 0, sizeof(SERVICE_STATUS)); 157 } 158 159 /* Select the appropriate object directory based on driver type */ 160 if (lpService->Status.dwServiceType == SERVICE_KERNEL_DRIVER) 161 { 162 RtlInitUnicodeString(&DirName, L"\\Driver"); 163 } 164 else // if (lpService->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER) 165 { 166 ASSERT(lpService->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER); 167 RtlInitUnicodeString(&DirName, L"\\FileSystem"); 168 } 169 170 InitializeObjectAttributes(&ObjectAttributes, 171 &DirName, 172 0, 173 NULL, 174 NULL); 175 176 /* Open the object directory where loaded drivers are */ 177 Status = NtOpenDirectoryObject(&DirHandle, 178 DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 179 &ObjectAttributes); 180 if (!NT_SUCCESS(Status)) 181 { 182 DPRINT1("NtOpenDirectoryObject() failed!\n"); 183 return RtlNtStatusToDosError(Status); 184 } 185 186 /* Allocate a buffer big enough for querying the object */ 187 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) + 188 2 * MAX_PATH * sizeof(WCHAR); 189 DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(), 190 HEAP_ZERO_MEMORY, 191 BufferLength); 192 193 /* Now, start browsing entry by entry */ 194 Index = 0; 195 while (TRUE) 196 { 197 Status = NtQueryDirectoryObject(DirHandle, 198 DirInfo, 199 BufferLength, 200 TRUE, 201 FALSE, 202 &Index, 203 &DataLength); 204 /* End of enumeration, the driver was not found */ 205 if (Status == STATUS_NO_MORE_ENTRIES) 206 { 207 DPRINT("No more services\n"); 208 break; 209 } 210 211 /* Other error, fail */ 212 if (!NT_SUCCESS(Status)) 213 break; 214 215 DPRINT("Comparing: '%S' '%wZ'\n", lpService->lpServiceName, &DirInfo->Name); 216 217 /* Compare names to check whether it matches our driver */ 218 if (_wcsicmp(lpService->lpServiceName, DirInfo->Name.Buffer) == 0) 219 { 220 /* That's our driver, bail out! */ 221 DPRINT1("Found: '%S' '%wZ'\n", 222 lpService->lpServiceName, &DirInfo->Name); 223 bFound = TRUE; 224 225 break; 226 } 227 } 228 229 /* Release resources we don't need */ 230 HeapFree(GetProcessHeap(), 231 0, 232 DirInfo); 233 NtClose(DirHandle); 234 235 /* Only quit if there's a failure 236 * Not having found the driver is legit! 237 * It means the driver was registered as a service, but not loaded 238 * We have not to fail in that situation, but to return proper status 239 */ 240 if (!NT_SUCCESS(Status) && Status != STATUS_NO_MORE_ENTRIES) 241 { 242 DPRINT1("Status: %lx\n", Status); 243 return RtlNtStatusToDosError(Status); 244 } 245 246 /* Now, we have two cases: 247 * We found the driver: it means it's running 248 * We didn't find the driver: it wasn't running 249 */ 250 if (bFound) 251 { 252 /* Found, return it's running */ 253 254 dwPreviousState = lpService->Status.dwCurrentState; 255 256 /* It is running */ 257 lpService->Status.dwCurrentState = SERVICE_RUNNING; 258 259 if (dwPreviousState == SERVICE_STOPPED) 260 { 261 /* Make it run if it was stopped before */ 262 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; 263 lpService->Status.dwServiceSpecificExitCode = ERROR_SUCCESS; 264 lpService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; 265 lpService->Status.dwCheckPoint = 0; 266 lpService->Status.dwWaitHint = 0; 267 } 268 269 if (lpService->Status.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED) 270 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; 271 } 272 else 273 { 274 /* Not found, return it's stopped */ 275 276 if (lpService->Status.dwCurrentState == SERVICE_STOP_PENDING) 277 { 278 /* Stopped successfully */ 279 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; 280 lpService->Status.dwCurrentState = SERVICE_STOPPED; 281 lpService->Status.dwControlsAccepted = 0; 282 lpService->Status.dwCheckPoint = 0; 283 lpService->Status.dwWaitHint = 0; 284 } 285 else if (lpService->Status.dwCurrentState == SERVICE_STOPPED) 286 { 287 /* Don't change the current status */ 288 } 289 else 290 { 291 lpService->Status.dwWin32ExitCode = ERROR_GEN_FAILURE; 292 lpService->Status.dwCurrentState = SERVICE_STOPPED; 293 lpService->Status.dwControlsAccepted = 0; 294 lpService->Status.dwCheckPoint = 0; 295 lpService->Status.dwWaitHint = 0; 296 } 297 } 298 299 /* Copy service status if required */ 300 if (lpServiceStatus != NULL) 301 { 302 RtlCopyMemory(lpServiceStatus, 303 &lpService->Status, 304 sizeof(SERVICE_STATUS)); 305 } 306 307 DPRINT1("ScmGetDriverStatus() done (Error: %lu)\n", dwError); 308 309 return ERROR_SUCCESS; 310 } 311 312 313 DWORD 314 ScmStartDriver(PSERVICE pService) 315 { 316 DWORD dwError; 317 318 DPRINT("ScmStartDriver(%p)\n", pService); 319 320 dwError = ScmLoadDriver(pService); 321 if (dwError == ERROR_SUCCESS) 322 { 323 pService->Status.dwCurrentState = SERVICE_RUNNING; 324 pService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; 325 pService->Status.dwWin32ExitCode = ERROR_SUCCESS; 326 } 327 328 DPRINT("ScmStartDriver returns %lu\n", dwError); 329 330 return dwError; 331 } 332 333 334 DWORD 335 ScmControlDriver(PSERVICE lpService, 336 DWORD dwControl, 337 LPSERVICE_STATUS lpServiceStatus) 338 { 339 DWORD dwError; 340 341 DPRINT("ScmControlDriver() called\n"); 342 343 switch (dwControl) 344 { 345 case SERVICE_CONTROL_STOP: 346 /* Check the drivers status */ 347 dwError = ScmGetDriverStatus(lpService, 348 lpServiceStatus); 349 if (dwError != ERROR_SUCCESS) 350 goto done; 351 352 /* Fail, if it is not running */ 353 if (lpService->Status.dwCurrentState != SERVICE_RUNNING) 354 { 355 dwError = ERROR_INVALID_SERVICE_CONTROL; 356 goto done; 357 } 358 359 /* Unload the driver */ 360 dwError = ScmUnloadDriver(lpService); 361 if (dwError == ERROR_INVALID_SERVICE_CONTROL) 362 { 363 /* The driver cannot be stopped, mark it non-stoppable */ 364 lpService->Status.dwControlsAccepted = 0; 365 goto done; 366 } 367 368 /* Make the driver 'stop pending' */ 369 lpService->Status.dwCurrentState = SERVICE_STOP_PENDING; 370 371 /* Check the drivers status again */ 372 dwError = ScmGetDriverStatus(lpService, 373 lpServiceStatus); 374 break; 375 376 case SERVICE_CONTROL_INTERROGATE: 377 dwError = ScmGetDriverStatus(lpService, 378 lpServiceStatus); 379 break; 380 381 default: 382 dwError = ERROR_INVALID_SERVICE_CONTROL; 383 } 384 385 done: 386 DPRINT("ScmControlDriver() done (Erorr: %lu)\n", dwError); 387 388 return dwError; 389 } 390 391 /* EOF */ 392