xref: /reactos/base/system/services/driver.c (revision fc82f8e2)
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 */
330