Sync with trunk r63430.
[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 memset(lpServiceStatus, 0, sizeof(SERVICE_STATUS));
144
145 if (lpService->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
146 {
147 RtlInitUnicodeString(&DirName, L"\\Driver");
148 }
149 else // if (lpService->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
150 {
151 ASSERT(lpService->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER);
152 RtlInitUnicodeString(&DirName, L"\\FileSystem");
153 }
154
155 InitializeObjectAttributes(&ObjectAttributes,
156 &DirName,
157 0,
158 NULL,
159 NULL);
160
161 Status = NtOpenDirectoryObject(&DirHandle,
162 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
163 &ObjectAttributes);
164 if (!NT_SUCCESS(Status))
165 {
166 DPRINT1("NtOpenDirectoryObject() failed!\n");
167 return RtlNtStatusToDosError(Status);
168 }
169
170 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
171 2 * MAX_PATH * sizeof(WCHAR);
172 DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
173 HEAP_ZERO_MEMORY,
174 BufferLength);
175
176 Index = 0;
177 while (TRUE)
178 {
179 Status = NtQueryDirectoryObject(DirHandle,
180 DirInfo,
181 BufferLength,
182 TRUE,
183 FALSE,
184 &Index,
185 &DataLength);
186 if (Status == STATUS_NO_MORE_ENTRIES)
187 {
188 DPRINT("No more services\n");
189 break;
190 }
191
192 if (!NT_SUCCESS(Status))
193 break;
194
195 DPRINT("Comparing: '%S' '%wZ'\n", lpService->lpServiceName, &DirInfo->Name);
196
197 if (_wcsicmp(lpService->lpServiceName, DirInfo->Name.Buffer) == 0)
198 {
199 DPRINT1("Found: '%S' '%wZ'\n",
200 lpService->lpServiceName, &DirInfo->Name);
201 bFound = TRUE;
202
203 break;
204 }
205 }
206
207 HeapFree(GetProcessHeap(),
208 0,
209 DirInfo);
210 NtClose(DirHandle);
211
212 if (!NT_SUCCESS(Status))
213 {
214 DPRINT1("Status: %lx\n", Status);
215 return RtlNtStatusToDosError(Status);
216 }
217
218 if ((bFound == TRUE) &&
219 (lpService->Status.dwCurrentState != SERVICE_STOP_PENDING))
220 {
221 if (lpService->Status.dwCurrentState == SERVICE_STOPPED)
222 {
223 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
224 lpService->Status.dwServiceSpecificExitCode = ERROR_SUCCESS;
225 lpService->Status.dwCheckPoint = 0;
226 lpService->Status.dwWaitHint = 0;
227 lpService->Status.dwControlsAccepted = 0;
228 }
229 else
230 {
231 lpService->Status.dwCurrentState = SERVICE_RUNNING;
232 lpService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
233
234 if (lpService->Status.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED)
235 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
236 }
237 }
238 else
239 {
240 lpService->Status.dwCurrentState = SERVICE_STOPPED;
241 lpService->Status.dwControlsAccepted = 0;
242 lpService->Status.dwCheckPoint = 0;
243 lpService->Status.dwWaitHint = 0;
244
245 if (lpService->Status.dwCurrentState == SERVICE_STOP_PENDING)
246 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
247 else
248 lpService->Status.dwWin32ExitCode = ERROR_GEN_FAILURE;
249 }
250
251 if (lpServiceStatus != NULL)
252 {
253 memcpy(lpServiceStatus,
254 &lpService->Status,
255 sizeof(SERVICE_STATUS));
256 }
257
258 DPRINT1("ScmGetDriverStatus() done (Error: %lu)\n", dwError);
259
260 return ERROR_SUCCESS;
261 }
262
263
264 DWORD
265 ScmControlDriver(PSERVICE lpService,
266 DWORD dwControl,
267 LPSERVICE_STATUS lpServiceStatus)
268 {
269 DWORD dwError;
270
271 DPRINT("ScmControlDriver() called\n");
272
273 switch (dwControl)
274 {
275 case SERVICE_CONTROL_STOP:
276 if (lpService->Status.dwCurrentState != SERVICE_RUNNING)
277 {
278 dwError = ERROR_INVALID_SERVICE_CONTROL;
279 goto done;
280 }
281
282 dwError = ScmUnloadDriver(lpService);
283 if (dwError == ERROR_SUCCESS)
284 {
285 lpService->Status.dwControlsAccepted = 0;
286 lpService->Status.dwCurrentState = SERVICE_STOPPED;
287 }
288 break;
289
290 case SERVICE_CONTROL_INTERROGATE:
291 dwError = ScmGetDriverStatus(lpService,
292 lpServiceStatus);
293 break;
294
295 default:
296 dwError = ERROR_INVALID_SERVICE_CONTROL;
297 }
298
299 done:;
300 DPRINT("ScmControlDriver() done (Erorr: %lu)\n", dwError);
301
302 return dwError;
303 }
304
305 /* EOF */