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