ReactOS  0.4.13-dev-651-g5dbc677
driver.c
Go to the documentation of this file.
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
25 {
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(),
35  (52 + wcslen(lpService->lpServiceName) + 1) * sizeof(WCHAR));
36  if (pszDriverPath == NULL)
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 */
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 */
65  WasPrivilegeEnabled,
66  FALSE,
67  &WasPrivilegeEnabled);
68 
69 done:
70  HeapFree(GetProcessHeap(), 0, pszDriverPath);
72 }
73 
74 
75 static
76 DWORD
78 {
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(),
89  (52 + wcslen(lpService->lpServiceName) + 1) * sizeof(WCHAR));
90  if (pszDriverPath == NULL)
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 */
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);
119  else
120  dwError = RtlNtStatusToDosError(Status);
121 
122  /* Release driver-unloading 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
137  LPSERVICE_STATUS lpServiceStatus)
138 {
141  HANDLE DirHandle;
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  {
167  RtlInitUnicodeString(&DirName, L"\\FileSystem");
168  }
169 
171  &DirName,
172  0,
173  NULL,
174  NULL);
175 
176  /* Open the object directory where loaded drivers are */
177  Status = NtOpenDirectoryObject(&DirHandle,
180  if (!NT_SUCCESS(Status))
181  {
182  DPRINT1("NtOpenDirectoryObject() failed!\n");
184  }
185 
186  /* Allocate a buffer big enough for querying the object */
188  2 * MAX_PATH * sizeof(WCHAR);
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 */
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 */
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  */
241  {
242  DPRINT1("Status: %lx\n", 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 */
258 
259  if (dwPreviousState == SERVICE_STOPPED)
260  {
261  /* Make it run if it was stopped before */
262  lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
265  lpService->Status.dwCheckPoint = 0;
266  lpService->Status.dwWaitHint = 0;
267  }
268 
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;
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  {
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
315 {
316  DWORD dwError;
317 
318  DPRINT("ScmStartDriver(%p)\n", pService);
319 
320  dwError = ScmLoadDriver(pService);
321  if (dwError == ERROR_SUCCESS)
322  {
326  }
327 
328  DPRINT("ScmStartDriver returns %lu\n", dwError);
329 
330  return dwError;
331 }
332 
333 
334 DWORD
336  DWORD dwControl,
337  LPSERVICE_STATUS lpServiceStatus)
338 {
339  DWORD dwError;
340 
341  DPRINT("ScmControlDriver() called\n");
342 
343  switch (dwControl)
344  {
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  {
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' */
370 
371  /* Check the drivers status again */
372  dwError = ScmGetDriverStatus(lpService,
373  lpServiceStatus);
374  break;
375 
377  dwError = ScmGetDriverStatus(lpService,
378  lpServiceStatus);
379  break;
380 
381  default:
383  }
384 
385 done:
386  DPRINT("ScmControlDriver() done (Erorr: %lu)\n", dwError);
387 
388  return dwError;
389 }
390 
391 /* EOF */
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
SERVICE_STATUS Status
Definition: services.h:69
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
DWORD ScmControlDriver(PSERVICE lpService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus)
Definition: driver.c:335
#define STATUS_NO_MORE_ENTRIES
Definition: ntstatus.h:193
#define ERROR_SUCCESS
Definition: deptool.c:10
DWORD dwCurrentState
Definition: winsvc.h:100
uint16_t * PWSTR
Definition: typedefs.h:54
NTSTATUS NTAPI NtOpenDirectoryObject(OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: obdir.c:401
LONG NTSTATUS
Definition: precomp.h:26
#define SE_LOAD_DRIVER_PRIVILEGE
Definition: security.c:664
#define SERVICE_ACCEPT_STOP
Definition: winsvc.h:28
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
NTSYSAPI NTSTATUS NTAPI RtlAdjustPrivilege(_In_ ULONG Privilege, _In_ BOOLEAN NewValue, _In_ BOOLEAN ForThread, _Out_ PBOOLEAN OldValue)
DWORD dwServiceSpecificExitCode
Definition: winsvc.h:103
DWORD ScmStartDriver(PSERVICE pService)
Definition: driver.c:314
NTSTATUS NTAPI NtQueryDirectoryObject(IN HANDLE DirectoryHandle, OUT PVOID Buffer, IN ULONG BufferLength, IN BOOLEAN ReturnSingleEntry, IN BOOLEAN RestartScan, IN OUT PULONG Context, OUT PULONG ReturnLength OPTIONAL)
Definition: obdir.c:498
#define ERROR_SERVICE_NEVER_STARTED
Definition: winerror.h:628
static DWORD ScmUnloadDriver(PSERVICE lpService)
Definition: driver.c:77
DWORD dwCheckPoint
Definition: winsvc.h:104
#define SERVICE_STOPPED
Definition: winsvc.h:21
_In_ ULONG BufferLength
Definition: usbdlib.h:225
#define SERVICE_RUNNING
Definition: winsvc.h:24
#define ERROR_INVALID_SERVICE_CONTROL
Definition: winerror.h:603
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
#define SERVICE_CONTROL_INTERROGATE
Definition: winsvc.h:39
#define SERVICE_FILE_SYSTEM_DRIVER
Definition: cmtypes.h:952
#define DIRECTORY_TRAVERSE
Definition: nt_native.h:1255
static DWORD ScmLoadDriver(PSERVICE lpService)
Definition: driver.c:24
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
DWORD dwWaitHint
Definition: winsvc.h:105
#define MAX_PATH
Definition: compat.h:26
static const UCHAR Index[8]
Definition: usbohci.c:18
DWORD dwWin32ExitCode
Definition: winsvc.h:102
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD dwServiceType
Definition: winsvc.h:99
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
NTSTATUS NTAPI NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
Definition: driver.c:2147
static const WCHAR L[]
Definition: oid.c:1250
static DWORD ScmGetDriverStatus(PSERVICE lpService, LPSERVICE_STATUS lpServiceStatus)
Definition: driver.c:136
LPWSTR lpServiceName
Definition: services.h:61
struct _OBJECT_DIRECTORY_INFORMATION OBJECT_DIRECTORY_INFORMATION
Status
Definition: gdiplustypes.h:24
NTSYSAPI ULONG WINAPI RtlNtStatusToDosError(NTSTATUS)
DWORD dwControlsAccepted
Definition: winsvc.h:101
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
#define DPRINT1
Definition: precomp.h:8
unsigned int ULONG
Definition: retypes.h:1
#define DIRECTORY_QUERY
Definition: nt_native.h:1254
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
_In_ PFCB _In_ PCD_NAME DirName
Definition: cdprocs.h:741
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define SERVICE_CONTROL_STOP
Definition: winsvc.h:36
#define ERROR_GEN_FAILURE
Definition: winerror.h:134
_Must_inspect_result_ _Out_writes_to_ DataLength PHIDP_DATA _Inout_ PULONG DataLength
Definition: hidpi.h:333
return STATUS_SUCCESS
Definition: btrfs.c:2777
#define memset(x, y, z)
Definition: compat.h:39
NTSTATUS NTAPI NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
Definition: driver.c:2090
#define SERVICE_STOP_PENDING
Definition: winsvc.h:23
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:394
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define SERVICE_KERNEL_DRIVER
Definition: cmtypes.h:951