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 DWORD 23 ScmLoadDriver(PSERVICE lpService) 24 { 25 NTSTATUS Status = STATUS_SUCCESS; 26 BOOLEAN WasPrivilegeEnabled = FALSE; 27 PWSTR pszDriverPath; 28 UNICODE_STRING DriverPath; 29 30 /* Build the driver path */ 31 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ 32 pszDriverPath = HeapAlloc(GetProcessHeap(), 33 HEAP_ZERO_MEMORY, 34 (52 + wcslen(lpService->lpServiceName) + 1) * sizeof(WCHAR)); 35 if (pszDriverPath == NULL) 36 return ERROR_NOT_ENOUGH_MEMORY; 37 38 wcscpy(pszDriverPath, 39 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 40 wcscat(pszDriverPath, 41 lpService->lpServiceName); 42 43 RtlInitUnicodeString(&DriverPath, 44 pszDriverPath); 45 46 DPRINT(" Path: %wZ\n", &DriverPath); 47 48 /* Acquire driver-loading privilege */ 49 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 50 TRUE, 51 FALSE, 52 &WasPrivilegeEnabled); 53 if (!NT_SUCCESS(Status)) 54 { 55 /* We encountered a failure, exit properly */ 56 DPRINT1("SERVICES: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status); 57 goto done; 58 } 59 60 Status = NtLoadDriver(&DriverPath); 61 62 /* Release driver-loading privilege */ 63 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 64 WasPrivilegeEnabled, 65 FALSE, 66 &WasPrivilegeEnabled); 67 68 done: 69 HeapFree(GetProcessHeap(), 0, pszDriverPath); 70 return RtlNtStatusToDosError(Status); 71 } 72 73 74 DWORD 75 ScmUnloadDriver(PSERVICE lpService) 76 { 77 NTSTATUS Status = STATUS_SUCCESS; 78 BOOLEAN WasPrivilegeEnabled = FALSE; 79 PWSTR pszDriverPath; 80 UNICODE_STRING DriverPath; 81 82 /* Build the driver path */ 83 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */ 84 pszDriverPath = HeapAlloc(GetProcessHeap(), 85 HEAP_ZERO_MEMORY, 86 (52 + wcslen(lpService->lpServiceName) + 1) * sizeof(WCHAR)); 87 if (pszDriverPath == NULL) 88 return ERROR_NOT_ENOUGH_MEMORY; 89 90 wcscpy(pszDriverPath, 91 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 92 wcscat(pszDriverPath, 93 lpService->lpServiceName); 94 95 RtlInitUnicodeString(&DriverPath, 96 pszDriverPath); 97 98 DPRINT(" Path: %wZ\n", &DriverPath); 99 100 /* Acquire driver-unloading privilege */ 101 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 102 TRUE, 103 FALSE, 104 &WasPrivilegeEnabled); 105 if (!NT_SUCCESS(Status)) 106 { 107 /* We encountered a failure, exit properly */ 108 DPRINT1("SERVICES: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status); 109 goto done; 110 } 111 112 Status = NtUnloadDriver(&DriverPath); 113 114 /* Release driver-unloading privilege */ 115 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, 116 WasPrivilegeEnabled, 117 FALSE, 118 &WasPrivilegeEnabled); 119 120 done: 121 HeapFree(GetProcessHeap(), 0, pszDriverPath); 122 return RtlNtStatusToDosError(Status); 123 } 124 125 126 DWORD 127 ScmGetDriverStatus(PSERVICE lpService, 128 LPSERVICE_STATUS lpServiceStatus) 129 { 130 OBJECT_ATTRIBUTES ObjectAttributes; 131 UNICODE_STRING DirName; 132 HANDLE DirHandle; 133 NTSTATUS Status = STATUS_SUCCESS; 134 POBJECT_DIRECTORY_INFORMATION DirInfo; 135 ULONG BufferLength; 136 ULONG DataLength; 137 ULONG Index; 138 DWORD dwError = ERROR_SUCCESS; 139 BOOLEAN bFound = FALSE; 140 141 DPRINT1("ScmGetDriverStatus() called\n"); 142 143 /* Zero output buffer if any */ 144 if (lpServiceStatus != NULL) 145 { 146 memset(lpServiceStatus, 0, sizeof(SERVICE_STATUS)); 147 } 148 149 /* Select the appropriate object directory based on driver type */ 150 if (lpService->Status.dwServiceType == SERVICE_KERNEL_DRIVER) 151 { 152 RtlInitUnicodeString(&DirName, L"\\Driver"); 153 } 154 else // if (lpService->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER) 155 { 156 ASSERT(lpService->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER); 157 RtlInitUnicodeString(&DirName, L"\\FileSystem"); 158 } 159 160 InitializeObjectAttributes(&ObjectAttributes, 161 &DirName, 162 0, 163 NULL, 164 NULL); 165 166 /* Open the object directory where loaded drivers are */ 167 Status = NtOpenDirectoryObject(&DirHandle, 168 DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 169 &ObjectAttributes); 170 if (!NT_SUCCESS(Status)) 171 { 172 DPRINT1("NtOpenDirectoryObject() failed!\n"); 173 return RtlNtStatusToDosError(Status); 174 } 175 176 /* Allocate a buffer big enough for querying the object */ 177 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) + 178 2 * MAX_PATH * sizeof(WCHAR); 179 DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(), 180 HEAP_ZERO_MEMORY, 181 BufferLength); 182 183 /* Now, start browsing entry by entry */ 184 Index = 0; 185 while (TRUE) 186 { 187 Status = NtQueryDirectoryObject(DirHandle, 188 DirInfo, 189 BufferLength, 190 TRUE, 191 FALSE, 192 &Index, 193 &DataLength); 194 /* End of enumeration, the driver was not found */ 195 if (Status == STATUS_NO_MORE_ENTRIES) 196 { 197 DPRINT("No more services\n"); 198 break; 199 } 200 201 /* Other error, fail */ 202 if (!NT_SUCCESS(Status)) 203 break; 204 205 DPRINT("Comparing: '%S' '%wZ'\n", lpService->lpServiceName, &DirInfo->Name); 206 207 /* Compare names to check whether it matches our driver */ 208 if (_wcsicmp(lpService->lpServiceName, DirInfo->Name.Buffer) == 0) 209 { 210 /* That's our driver, bail out! */ 211 DPRINT1("Found: '%S' '%wZ'\n", 212 lpService->lpServiceName, &DirInfo->Name); 213 bFound = TRUE; 214 215 break; 216 } 217 } 218 219 /* Release resources we don't need */ 220 HeapFree(GetProcessHeap(), 221 0, 222 DirInfo); 223 NtClose(DirHandle); 224 225 /* Only quit if there's a failure 226 * Not having found the driver is legit! 227 * It means the driver was registered as a service, but not loaded 228 * We have not to fail in that situation, but to return proper status 229 */ 230 if (!NT_SUCCESS(Status) && Status != STATUS_NO_MORE_ENTRIES) 231 { 232 DPRINT1("Status: %lx\n", Status); 233 return RtlNtStatusToDosError(Status); 234 } 235 236 /* Now, we have two cases: 237 * We found the driver: it means it's running 238 * We didn't find the driver: it wasn't running 239 */ 240 if ((bFound != FALSE) && 241 (lpService->Status.dwCurrentState != SERVICE_STOP_PENDING)) 242 { 243 if (lpService->Status.dwCurrentState == SERVICE_STOPPED) 244 { 245 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; 246 lpService->Status.dwServiceSpecificExitCode = ERROR_SUCCESS; 247 lpService->Status.dwCheckPoint = 0; 248 lpService->Status.dwWaitHint = 0; 249 lpService->Status.dwControlsAccepted = 0; 250 } 251 else 252 { 253 lpService->Status.dwCurrentState = SERVICE_RUNNING; 254 lpService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; 255 256 if (lpService->Status.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED) 257 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; 258 } 259 } 260 /* Not found, return it's stopped */ 261 else 262 { 263 lpService->Status.dwCurrentState = SERVICE_STOPPED; 264 lpService->Status.dwControlsAccepted = 0; 265 lpService->Status.dwCheckPoint = 0; 266 lpService->Status.dwWaitHint = 0; 267 268 if (lpService->Status.dwCurrentState == SERVICE_STOP_PENDING) 269 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS; 270 else 271 lpService->Status.dwWin32ExitCode = ERROR_GEN_FAILURE; 272 } 273 274 /* Copy service status if required */ 275 if (lpServiceStatus != NULL) 276 { 277 memcpy(lpServiceStatus, 278 &lpService->Status, 279 sizeof(SERVICE_STATUS)); 280 } 281 282 DPRINT1("ScmGetDriverStatus() done (Error: %lu)\n", dwError); 283 284 return ERROR_SUCCESS; 285 } 286 287 288 DWORD 289 ScmControlDriver(PSERVICE lpService, 290 DWORD dwControl, 291 LPSERVICE_STATUS lpServiceStatus) 292 { 293 DWORD dwError; 294 295 DPRINT("ScmControlDriver() called\n"); 296 297 switch (dwControl) 298 { 299 case SERVICE_CONTROL_STOP: 300 if (lpService->Status.dwCurrentState != SERVICE_RUNNING) 301 { 302 dwError = ERROR_INVALID_SERVICE_CONTROL; 303 goto done; 304 } 305 306 dwError = ScmUnloadDriver(lpService); 307 if (dwError == ERROR_SUCCESS) 308 { 309 lpService->Status.dwControlsAccepted = 0; 310 lpService->Status.dwCurrentState = SERVICE_STOPPED; 311 } 312 break; 313 314 case SERVICE_CONTROL_INTERROGATE: 315 dwError = ScmGetDriverStatus(lpService, 316 lpServiceStatus); 317 break; 318 319 default: 320 dwError = ERROR_INVALID_SERVICE_CONTROL; 321 } 322 323 done:; 324 DPRINT("ScmControlDriver() done (Erorr: %lu)\n", dwError); 325 326 return dwError; 327 } 328 329 /* EOF */ 330