xref: /reactos/drivers/sac/driver/data.c (revision c2c66aff)
1 /*
2  * PROJECT:     ReactOS Drivers
3  * LICENSE:     BSD - See COPYING.ARM in the top level directory
4  * FILE:        drivers/sac/driver/data.c
5  * PURPOSE:     Driver for the Server Administration Console (SAC) for EMS
6  * PROGRAMMERS: ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "sacdrv.h"
12 
13 /* GLOBALS ********************************************************************/
14 
15 ULONG SACDebug = 0;
16 BOOLEAN CommandConsoleLaunchingEnabled;
17 BOOLEAN GlobalDataInitialized;
18 KMUTEX SACCMDEventInfoMutex;
19 BOOLEAN IoctlSubmitted;
20 ULONG ProcessingType;
21 PKEVENT SACEvent;
22 HANDLE SACEventHandle;
23 
24 /* FUNCTIONS ******************************************************************/
25 
26 VOID
27 NTAPI
28 WorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension)
29 {
30     /* Call the worker function */
31     ConMgrWorkerProcessEvents(DeviceExtension);
32 }
33 
34 VOID
35 NTAPI
36 WorkerThreadStartUp(IN PVOID Context)
37 {
38     /* Call the worker function */
39     WorkerProcessEvents((PSAC_DEVICE_EXTENSION)Context);
40 }
41 
42 NTSTATUS
43 NTAPI
44 BuildDeviceAcl(OUT PACL* Dacl)
45 {
46     /* TODO */
47     return STATUS_NOT_IMPLEMENTED;
48 }
49 
50 NTSTATUS
51 NTAPI
52 CreateDeviceSecurityDescriptor(IN PDEVICE_OBJECT *DeviceObject)
53 {
54     NTSTATUS Status;
55     PSECURITY_DESCRIPTOR SecurityDescriptor;
56     BOOLEAN MemoryAllocated = FALSE;
57     PACL Dacl = NULL;
58     PVOID ObjectSecurityDescriptor = NULL;
59     SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Entering.\n");
60 
61     /* Get the current SD of the device object */
62     Status = ObGetObjectSecurity(*DeviceObject, &SecurityDescriptor, &MemoryAllocated);
63     if (!NT_SUCCESS(Status))
64     {
65         SAC_DBG(SAC_DBG_INIT, "SAC: Unable to get security descriptor, error: %x\n", Status);
66         NT_ASSERT(MemoryAllocated == FALSE);
67         SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status);
68         return Status;
69     }
70 
71     /* Build a DACL for it */
72     Status = BuildDeviceAcl(&Dacl);
73     if (Status >= 0)
74     {
75         ASSERT(FALSE);
76     }
77     else
78     {
79         SAC_DBG(SAC_DBG_INIT, "SAC CreateDeviceSecurityDescriptor : Unable to create Raw ACL, error : %x\n", Status);
80         /* FIXME: Temporary hack */
81         Status = STATUS_SUCCESS;
82         goto CleanupPath;
83     }
84 
85 CleanupPath:
86     /* Release the SD we queried */
87     ObReleaseObjectSecurity(SecurityDescriptor, MemoryAllocated);
88 
89     /* Free anything else we may have allocated */
90     if (ObjectSecurityDescriptor) ExFreePool(ObjectSecurityDescriptor);
91     if (Dacl) SacFreePool(Dacl);
92 
93     /* All done */
94     SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status);
95     return Status;
96 }
97 
98 VOID
99 NTAPI
100 FreeGlobalData(VOID)
101 {
102     UNICODE_STRING SymbolicLink;
103     SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeGlobalData: Entering.\n");
104 
105     /* Only free if we allocated */
106     if (GlobalDataInitialized)
107     {
108         /* Close the SAC event if we had created one */
109         if (SACEvent)
110         {
111             ZwClose(SACEventHandle);
112             SACEvent = NULL;
113         }
114 
115         /* Destroy the cached messages */
116         TearDownGlobalMessageTable();
117 
118         /* Delete the Win32 symbolic link */
119         RtlInitUnicodeString(&SymbolicLink, L"\\DosDevices\\SAC");
120         IoDeleteSymbolicLink(&SymbolicLink);
121 
122         /* Tear down connections */
123         ConMgrShutdown();
124 
125         /* Tear down channels */
126         ChanMgrShutdown();
127 
128         /* Free the serial port buffer */
129         if (SerialPortBuffer) SacFreePool(SerialPortBuffer);
130 
131         /* Free cached machine information */
132         FreeMachineInformation();
133 
134         /* Cleanup the custom heap allocator */
135         FreeMemoryManagement();
136 
137         /* We're back to a virgin state */
138         GlobalDataInitialized = FALSE;
139     }
140 
141     /* All done */
142     SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeGlobalData: Exiting.\n");
143 }
144 
145 VOID
146 NTAPI
147 FreeDeviceData(IN PDEVICE_OBJECT DeviceObject)
148 {
149     PSAC_DEVICE_EXTENSION DeviceExtension;
150     NTSTATUS Status;
151     KIRQL OldIrql;
152     SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Entering.\n");
153 
154     /* Get the device extension and see how far we had gotten */
155     DeviceExtension = (PSAC_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
156     if ((GlobalDataInitialized) && (DeviceExtension->Initialized))
157     {
158         /* Attempt to rundown while holding the lock */
159         KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
160         while (DeviceExtension->RundownInProgress)
161         {
162             SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Waiting....\n");
163 
164             /* Initiate and wait for rundown */
165             KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, 0);
166             KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
167             Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent,
168                                            Executive,
169                                            KernelMode,
170                                            FALSE,
171                                            NULL);
172             ASSERT(Status == STATUS_SUCCESS);
173 
174             /* Re-acquire the lock and check if rundown is done */
175             KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
176         }
177     }
178 
179     /* Now set the rundown flag while we cancel the timer */
180     DeviceExtension->RundownInProgress = TRUE;
181     KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
182 
183     /* Cancel it */
184     KeCancelTimer(&DeviceExtension->Timer);
185 
186     /* Reacquire the lock*/
187     KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
188     DeviceExtension->RundownInProgress = FALSE;
189 
190     /* Now do the last rundown attempt, we should be the only ones here */
191     KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, 0);
192     KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
193     KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, 0);
194     Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent,
195                                    Executive,
196                                    KernelMode,
197                                    FALSE,
198                                    NULL);
199     ASSERT(Status == STATUS_SUCCESS);
200 
201     /* We no longer care about shutdown */
202     IoUnregisterShutdownNotification(DeviceObject);
203 
204     /* We are now fully uninitialized */
205     KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
206     DeviceExtension->Initialized = FALSE;
207     KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
208     SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Exiting.\n");
209 }
210 
211 BOOLEAN
212 NTAPI
213 InitializeDeviceData(IN PDEVICE_OBJECT DeviceObject)
214 {
215     PSAC_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
216     BOOLEAN EnableData;
217     ULONG PriorityValue;
218     NTSTATUS Status;
219     LARGE_INTEGER DueTime;
220     PWCHAR Message;
221     PAGED_CODE();
222     SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n");
223 
224     /* If we already did this, bail out */
225     if (DeviceExtension->Initialized) goto SuccessExit;
226 
227     /* Setup the DO flags */
228     DeviceObject->Flags |= DO_DIRECT_IO;
229     DeviceObject->StackSize = 16;
230 
231     /* Setup the device extension */
232     DeviceExtension->DeviceObject = DeviceObject;
233     DeviceExtension->PriorityBoost = IO_SERIAL_INCREMENT;
234     DeviceExtension->PriorityFail = 0;
235     DeviceExtension->RundownInProgress = 0;
236 
237     /* Initialize locks, events, timers, DPCs, etc... */
238     KeInitializeTimer(&DeviceExtension->Timer);
239     KeInitializeDpc(&DeviceExtension->Dpc, TimerDpcRoutine, DeviceExtension);
240     KeInitializeSpinLock(&DeviceExtension->Lock);
241     KeInitializeEvent(&DeviceExtension->Event, SynchronizationEvent, FALSE);
242     InitializeListHead(&DeviceExtension->List);
243 
244     /* Attempt to enable HDL support */
245     EnableData = TRUE;
246     Status = HeadlessDispatch(HeadlessCmdEnableTerminal,
247                               &EnableData,
248                               sizeof(EnableData),
249                               NULL,
250                               0);
251     if (!NT_SUCCESS(Status))
252     {
253         /* Bail out if we couldn't even get this far */
254         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (1) with status FALSE\n");
255         return FALSE;
256     }
257 
258     /* Remember which process we started in */
259     DeviceExtension->Process = IoGetCurrentProcess();
260 
261     /* Protect the device against non-admins */
262     Status = CreateDeviceSecurityDescriptor(&DeviceExtension->DeviceObject);
263     if (!NT_SUCCESS(Status))
264     {
265         /* Write down why we failed */
266         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (2) with status FALSE\n");
267 
268         /* Disable the HDL terminal on failure */
269         EnableData = FALSE;
270         Status = HeadlessDispatch(HeadlessCmdEnableTerminal,
271                                   &EnableData,
272                                   sizeof(EnableData),
273                                   NULL,
274                                   NULL);
275         if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n");
276 
277         /* Bail out */
278         return FALSE;
279     }
280 
281     /* Create the worker thread */
282     Status = PsCreateSystemThread(&DeviceExtension->WorkerThreadHandle,
283                                   THREAD_ALL_ACCESS,
284                                   NULL,
285                                   NULL,
286                                   NULL,
287                                   WorkerThreadStartUp,
288                                   DeviceExtension);
289     if (!NT_SUCCESS(Status))
290     {
291         /* Write down why we failed */
292         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (3) with status FALSE\n");
293 
294         /* Disable the HDL terminal on failure */
295         EnableData = FALSE;
296         Status = HeadlessDispatch(HeadlessCmdEnableTerminal,
297                                   &EnableData,
298                                   sizeof(EnableData),
299                                   NULL,
300                                   NULL);
301         if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n");
302 
303         /* Bail out */
304         return FALSE;
305     }
306 
307     /* Set the priority of our thread to highest */
308     PriorityValue = HIGH_PRIORITY;
309     Status = NtSetInformationThread(DeviceExtension->WorkerThreadHandle,
310                                     ThreadPriority,
311                                     &PriorityValue,
312                                     sizeof(PriorityValue));
313     if (!NT_SUCCESS(Status))
314     {
315         /* For debugging, write down why we failed */
316         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (6) with status FALSE\n");
317         DeviceExtension->PriorityFail = TRUE;
318 
319         /* Initialize rundown and wait for the thread to do it */
320         KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, FALSE);
321         KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, FALSE);
322         Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent,
323                                        Executive,
324                                        KernelMode,
325                                        FALSE,
326                                        NULL);
327         ASSERT(Status == STATUS_SUCCESS);
328 
329         /* Disable the HDL terminal on failure */
330         EnableData = FALSE;
331         Status = HeadlessDispatch(HeadlessCmdEnableTerminal,
332                                   &EnableData,
333                                   sizeof(EnableData),
334                                   NULL,
335                                   0);
336         if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n");
337 
338         /* Bail out */
339         return FALSE;
340     }
341 
342     /* The first "packet" is the machine information in XML... */
343     Status = TranslateMachineInformationXML(&Message, NULL);
344     if (NT_SUCCESS(Status))
345     {
346         /* Go ahead and send it */
347         UTF8EncodeAndSend(L"<?xml version=\"1.0\"?>\r\n");
348         UTF8EncodeAndSend(Message);
349 
350         /* Free the temporary buffer */
351         SacFreePool(Message);
352     }
353 
354     /* Finally, initialize the I/O Manager */
355     Status = ConMgrInitialize();
356     if (!NT_SUCCESS(Status)) return FALSE;
357 
358     /* Set the timer. Once this is done, the device is initialized */
359     DueTime.QuadPart = -4000;
360     KeSetTimerEx(&DeviceExtension->Timer, DueTime, 4, &DeviceExtension->Dpc);
361     DeviceExtension->Initialized = TRUE;
362 
363 SuccessExit:
364     /* Success path -- everything worked */
365     SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n");
366     return TRUE;
367 }
368 
369 BOOLEAN
370 NTAPI
371 InitializeGlobalData(IN PUNICODE_STRING RegistryPath,
372                      IN PDRIVER_OBJECT DriverObject)
373 {
374     NTSTATUS Status;
375     UNICODE_STRING LinkName;
376     UNICODE_STRING DeviceName;
377     UNICODE_STRING EventName;
378     PAGED_CODE();
379     SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n");
380 
381     /* If we already did this, bail out */
382     if (GlobalDataInitialized) goto SuccessExit;
383 
384     /* Setup the symbolic link for Win32 support */
385     RtlInitUnicodeString(&LinkName, L"\\DosDevices\\SAC");
386     RtlInitUnicodeString(&DeviceName, L"\\Device\\SAC");
387     Status = IoCreateSymbolicLink(&LinkName, &DeviceName);
388     if (!NT_SUCCESS(Status)) return FALSE;
389 
390     /* Initialize the internal heap manager */
391     if (!InitializeMemoryManagement())
392     {
393         IoDeleteSymbolicLink(&LinkName);
394         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status FALSE\n");
395         return FALSE;
396     }
397 
398     /* Preload the messages in memory */
399     Status = PreloadGlobalMessageTable(DriverObject->DriverStart);
400     if (!NT_SUCCESS(Status))
401     {
402         IoDeleteSymbolicLink(&LinkName);
403         SAC_DBG(SAC_DBG_INIT, "unable to pre-load message table: %X\n", Status);
404         return FALSE;
405     }
406 
407     /* Check if the administrator enabled this */
408     Status = GetCommandConsoleLaunchingPermission(&CommandConsoleLaunchingEnabled);
409     if (!NT_SUCCESS(Status))
410     {
411         /* Is it enabled? */
412         if (CommandConsoleLaunchingEnabled)
413         {
414             /* Set the service start type to the correct value */
415             Status = ImposeSacCmdServiceStartTypePolicy();
416             if (!NT_SUCCESS(Status))
417             {
418                 SAC_DBG(SAC_DBG_INIT, "failed ImposeSacCmdServiceStartTypePolicy: %X\n", Status);
419             }
420         }
421 
422         /* We're going to keep going with the default */
423         SAC_DBG(SAC_DBG_INIT, "failed GetCommandConsoleLaunchingPermission: %X\n", Status);
424     }
425 
426     /* Allocate the UTF-8 Conversion Buffer */
427     Utf8ConversionBuffer = SacAllocatePool(Utf8ConversionBufferSize, GLOBAL_BLOCK_TAG);
428     if (!Utf8ConversionBuffer)
429     {
430         /* Handle failure case */
431         TearDownGlobalMessageTable();
432         IoDeleteSymbolicLink(&LinkName);
433         SAC_DBG(SAC_DBG_INIT, "unable to allocate memory for UTF8 translation\n");
434         return FALSE;
435     }
436 
437     /* Initialize the channel manager */
438     Status = ChanMgrInitialize();
439     if (!NT_SUCCESS(Status))
440     {
441         /* Handle failure case */
442         SacFreePool(Utf8ConversionBuffer);
443         TearDownGlobalMessageTable();
444         IoDeleteSymbolicLink(&LinkName);
445         SAC_DBG(SAC_DBG_INIT, "Failed to create SAC Channel\n");
446         return FALSE;
447     }
448 
449     /* Allocate the serial port buffer */
450     SerialPortBuffer = SacAllocatePool(SAC_SERIAL_PORT_BUFFER_SIZE, GLOBAL_BLOCK_TAG);
451     if (!SerialPortBuffer)
452     {
453         /* Handle failure case */
454         SacFreePool(Utf8ConversionBuffer);
455         TearDownGlobalMessageTable();
456         IoDeleteSymbolicLink(&LinkName);
457         SAC_DBG(SAC_DBG_INIT, "Failed to allocate Serial Port Buffer\n");
458         return FALSE;
459     }
460 
461     /* Zero it out */
462     RtlZeroMemory(SerialPortBuffer, SAC_SERIAL_PORT_BUFFER_SIZE);
463 
464     /* Initialize command events. After this, driver data is good to go */
465     KeInitializeMutex(&SACCMDEventInfoMutex, FALSE);
466     InitializeCmdEventInfo();
467     GlobalDataInitialized = TRUE;
468     ProcessingType = 0;
469     IoctlSubmitted = 0;
470 
471     /* Create the SAC event */
472     RtlInitUnicodeString(&EventName, L"\\SACEvent");
473     SACEvent = IoCreateSynchronizationEvent(&EventName, &SACEventHandle);
474     if (!SACEvent)
475     {
476         /* Handle failure case */
477         SacFreePool(Utf8ConversionBuffer);
478         TearDownGlobalMessageTable();
479         IoDeleteSymbolicLink(&LinkName);
480         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with event NULL\n");
481         return FALSE;
482     }
483 
484     /* Cache machine information */
485     InitializeMachineInformation();
486 
487     /* Register it */
488     Status = RegisterBlueScreenMachineInformation();
489     if (!NT_SUCCESS(Status))
490     {
491         /* Handle failure case */
492         SacFreePool(Utf8ConversionBuffer);
493         TearDownGlobalMessageTable();
494         IoDeleteSymbolicLink(&LinkName);
495         SAC_DBG(SAC_DBG_INIT, "Failed to register blue screen machine info\n");
496         return FALSE;
497     }
498 
499 SuccessExit:
500     /* Success path -- everything worked */
501     SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n");
502     return TRUE;
503 }
504