- Synchronize up to trunk's revision r57864.
[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 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS ****************************************************************/
18
19 static DWORD EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege)
20 {
21 DWORD dwRet = ERROR_SUCCESS;
22 HANDLE hToken = NULL;
23
24 if (OpenProcessToken(GetCurrentProcess(),
25 TOKEN_ADJUST_PRIVILEGES,
26 &hToken))
27 {
28 TOKEN_PRIVILEGES tp;
29
30 tp.PrivilegeCount = 1;
31 tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0);
32
33 if (LookupPrivilegeValueW(NULL,
34 lpszPrivilegeName,
35 &tp.Privileges[0].Luid))
36 {
37 if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
38 {
39 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
40 dwRet = ERROR_NOT_ALL_ASSIGNED;
41 }
42 else
43 {
44 dwRet = GetLastError();
45 }
46 }
47 else
48 {
49 dwRet = GetLastError();
50 }
51
52 CloseHandle(hToken);
53 }
54 else
55 {
56 dwRet = GetLastError();
57 }
58
59 return dwRet;
60 }
61
62
63 DWORD
64 ScmLoadDriver(PSERVICE lpService)
65 {
66 PWSTR pszDriverPath;
67 UNICODE_STRING DriverPath;
68 NTSTATUS Status;
69 DWORD dwError = ERROR_SUCCESS;
70
71 /* Build the driver path */
72 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
73 pszDriverPath = HeapAlloc(GetProcessHeap(),
74 HEAP_ZERO_MEMORY,
75 (52 + wcslen(lpService->lpServiceName) + 1) * sizeof(WCHAR));
76 if (pszDriverPath == NULL)
77 return ERROR_NOT_ENOUGH_MEMORY;
78
79 wcscpy(pszDriverPath,
80 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
81 wcscat(pszDriverPath,
82 lpService->lpServiceName);
83
84 RtlInitUnicodeString(&DriverPath,
85 pszDriverPath);
86
87 DPRINT(" Path: %wZ\n", &DriverPath);
88
89 /* Acquire driver-loading privilege */
90 dwError = EnablePrivilege(SE_LOAD_DRIVER_NAME, TRUE);
91 if (dwError != ERROR_SUCCESS)
92 {
93 /* We encountered a failure, exit properly */
94 DPRINT1("SERVICES: Cannot acquire driver-loading privilege, error = %lu\n", dwError);
95 goto done;
96 }
97
98 Status = NtLoadDriver(&DriverPath);
99
100 /* Release driver-loading privilege */
101 EnablePrivilege(SE_LOAD_DRIVER_NAME, FALSE);
102
103 if (!NT_SUCCESS(Status))
104 {
105 dwError = RtlNtStatusToDosError(Status);
106 }
107
108 done:
109 HeapFree(GetProcessHeap(), 0, pszDriverPath);
110
111 return dwError;
112 }
113
114
115 DWORD
116 ScmUnloadDriver(PSERVICE lpService)
117 {
118 PWSTR pszDriverPath;
119 UNICODE_STRING DriverPath;
120 NTSTATUS Status;
121 DWORD dwError = ERROR_SUCCESS;
122
123 /* Build the driver path */
124 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
125 pszDriverPath = HeapAlloc(GetProcessHeap(),
126 HEAP_ZERO_MEMORY,
127 (52 + wcslen(lpService->lpServiceName) + 1) * sizeof(WCHAR));
128 if (pszDriverPath == NULL)
129 return ERROR_NOT_ENOUGH_MEMORY;
130
131 wcscpy(pszDriverPath,
132 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
133 wcscat(pszDriverPath,
134 lpService->lpServiceName);
135
136 RtlInitUnicodeString(&DriverPath,
137 pszDriverPath);
138
139 /* Acquire driver-unloading privilege */
140 dwError = EnablePrivilege(SE_LOAD_DRIVER_NAME, TRUE);
141 if (dwError != ERROR_SUCCESS)
142 {
143 /* We encountered a failure, exit properly */
144 DPRINT1("SERVICES: Cannot acquire driver-unloading privilege, error = %lu\n", dwError);
145 goto done;
146 }
147
148 Status = NtUnloadDriver(&DriverPath);
149
150 /* Release driver-unloading privilege */
151 EnablePrivilege(SE_LOAD_DRIVER_NAME, FALSE);
152
153 if (!NT_SUCCESS(Status))
154 {
155 dwError = RtlNtStatusToDosError(Status);
156 }
157
158 done:
159 HeapFree(GetProcessHeap(), 0, pszDriverPath);
160
161 return dwError;
162 }
163
164
165 DWORD
166 ScmGetDriverStatus(PSERVICE lpService,
167 LPSERVICE_STATUS lpServiceStatus)
168 {
169 OBJECT_ATTRIBUTES ObjectAttributes;
170 UNICODE_STRING DirName;
171 HANDLE DirHandle;
172 NTSTATUS Status = STATUS_SUCCESS;
173 POBJECT_DIRECTORY_INFORMATION DirInfo;
174 ULONG BufferLength;
175 ULONG DataLength;
176 ULONG Index;
177 DWORD dwError = ERROR_SUCCESS;
178 BOOLEAN bFound = FALSE;
179
180 DPRINT1("ScmGetDriverStatus() called\n");
181
182 memset(lpServiceStatus, 0, sizeof(SERVICE_STATUS));
183
184 if (lpService->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
185 {
186 RtlInitUnicodeString(&DirName,
187 L"\\Driver");
188 }
189 else
190 {
191 RtlInitUnicodeString(&DirName,
192 L"\\FileSystem");
193 }
194
195 InitializeObjectAttributes(&ObjectAttributes,
196 &DirName,
197 0,
198 NULL,
199 NULL);
200
201 Status = NtOpenDirectoryObject(&DirHandle,
202 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
203 &ObjectAttributes);
204 if (!NT_SUCCESS(Status))
205 {
206 DPRINT1("NtOpenDirectoryObject() failed!\n");
207 return RtlNtStatusToDosError(Status);
208 }
209
210 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
211 2 * MAX_PATH * sizeof(WCHAR);
212 DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
213 HEAP_ZERO_MEMORY,
214 BufferLength);
215
216 Index = 0;
217 while (TRUE)
218 {
219 Status = NtQueryDirectoryObject(DirHandle,
220 DirInfo,
221 BufferLength,
222 TRUE,
223 FALSE,
224 &Index,
225 &DataLength);
226 if (Status == STATUS_NO_MORE_ENTRIES)
227 {
228 DPRINT("No more services\n");
229 break;
230 }
231
232 if (!NT_SUCCESS(Status))
233 break;
234
235 DPRINT("Comparing: '%S' '%wZ'\n", lpService->lpServiceName, &DirInfo->Name);
236
237 if (_wcsicmp(lpService->lpServiceName, DirInfo->Name.Buffer) == 0)
238 {
239 DPRINT1("Found: '%S' '%wZ'\n",
240 lpService->lpServiceName, &DirInfo->Name);
241 bFound = TRUE;
242
243 break;
244 }
245 }
246
247 HeapFree(GetProcessHeap(),
248 0,
249 DirInfo);
250 NtClose(DirHandle);
251
252 if (!NT_SUCCESS(Status))
253 {
254 DPRINT1("Status: %lx\n", Status);
255 return RtlNtStatusToDosError(Status);
256 }
257
258 if ((bFound == TRUE) &&
259 (lpService->Status.dwCurrentState != SERVICE_STOP_PENDING))
260 {
261 if (lpService->Status.dwCurrentState == SERVICE_STOPPED)
262 {
263 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
264 lpService->Status.dwServiceSpecificExitCode = ERROR_SUCCESS;
265 lpService->Status.dwCheckPoint = 0;
266 lpService->Status.dwWaitHint = 0;
267 lpService->Status.dwControlsAccepted = 0;
268 }
269 else
270 {
271 lpService->Status.dwCurrentState = SERVICE_RUNNING;
272 lpService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
273
274 if (lpService->Status.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED)
275 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
276 }
277 }
278 else
279 {
280 lpService->Status.dwCurrentState = SERVICE_STOPPED;
281 lpService->Status.dwControlsAccepted = 0;
282 lpService->Status.dwCheckPoint = 0;
283 lpService->Status.dwWaitHint = 0;
284
285 if (lpService->Status.dwCurrentState == SERVICE_STOP_PENDING)
286 lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
287 else
288 lpService->Status.dwWin32ExitCode = ERROR_GEN_FAILURE;
289 }
290
291 if (lpServiceStatus != NULL)
292 {
293 memcpy(lpServiceStatus,
294 &lpService->Status,
295 sizeof(SERVICE_STATUS));
296 }
297
298 DPRINT1("ScmGetDriverStatus() done (Error: %lu)\n", dwError);
299
300 return ERROR_SUCCESS;
301 }
302
303
304 DWORD
305 ScmControlDriver(PSERVICE lpService,
306 DWORD dwControl,
307 LPSERVICE_STATUS lpServiceStatus)
308 {
309 DWORD dwError;
310
311 DPRINT("ScmControlDriver() called\n");
312
313 switch (dwControl)
314 {
315 case SERVICE_CONTROL_STOP:
316 if (lpService->Status.dwCurrentState != SERVICE_RUNNING)
317 {
318 dwError = ERROR_INVALID_SERVICE_CONTROL;
319 goto done;
320 }
321
322 dwError = ScmUnloadDriver(lpService);
323 if (dwError == ERROR_SUCCESS)
324 {
325 lpService->Status.dwControlsAccepted = 0;
326 lpService->Status.dwCurrentState = SERVICE_STOPPED;
327 }
328 break;
329
330 case SERVICE_CONTROL_INTERROGATE:
331 dwError = ScmGetDriverStatus(lpService,
332 lpServiceStatus);
333 break;
334
335 default:
336 dwError = ERROR_INVALID_SERVICE_CONTROL;
337 }
338
339 done:;
340 DPRINT("ScmControlDriver() done (Erorr: %lu)\n", dwError);
341
342 return dwError;
343 }
344
345 /* EOF */