[SERVICES] Fix querying the status of a registered but not started driver.
[reactos.git] / base / system / services / driver.c
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 */