xref: /reactos/drivers/sac/driver/data.c (revision 81db5e1d)
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         goto Exit;
159     }
160 
161     /* Attempt to rundown while holding the lock */
162     KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
163     while (DeviceExtension->RundownInProgress)
164     {
165         SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Waiting....\n");
166 
167         /* Initiate and wait for rundown */
168         KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, 0);
169         KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
170         Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent,
171                                        Executive,
172                                        KernelMode,
173                                        FALSE,
174                                        NULL);
175         ASSERT(Status == STATUS_SUCCESS);
176 
177         /* Re-acquire the lock and check if rundown is done */
178         KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
179     }
180 
181     /* Now set the rundown flag while we cancel the timer */
182     DeviceExtension->RundownInProgress = TRUE;
183     KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
184 
185     /* Cancel it */
186     KeCancelTimer(&DeviceExtension->Timer);
187 
188     /* Reacquire the lock*/
189     KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
190     DeviceExtension->RundownInProgress = FALSE;
191 
192     /* Now do the last rundown attempt, we should be the only ones here */
193     KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, 0);
194     KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
195     KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, 0);
196     Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent,
197                                    Executive,
198                                    KernelMode,
199                                    FALSE,
200                                    NULL);
201     ASSERT(Status == STATUS_SUCCESS);
202 
203     /* We no longer care about shutdown */
204     IoUnregisterShutdownNotification(DeviceObject);
205 
206     /* We are now fully uninitialized */
207     KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
208     DeviceExtension->Initialized = FALSE;
209     KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
210 Exit:
211     SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Exiting.\n");
212 }
213 
214 BOOLEAN
215 NTAPI
216 InitializeDeviceData(IN PDEVICE_OBJECT DeviceObject)
217 {
218     PSAC_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
219     BOOLEAN EnableData;
220     ULONG PriorityValue;
221     NTSTATUS Status;
222     LARGE_INTEGER DueTime;
223     PWCHAR Message;
224     PAGED_CODE();
225     SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n");
226 
227     /* If we already did this, bail out */
228     if (DeviceExtension->Initialized) goto SuccessExit;
229 
230     /* Setup the DO flags */
231     DeviceObject->Flags |= DO_DIRECT_IO;
232     DeviceObject->StackSize = 16;
233 
234     /* Setup the device extension */
235     DeviceExtension->DeviceObject = DeviceObject;
236     DeviceExtension->PriorityBoost = IO_SERIAL_INCREMENT;
237     DeviceExtension->PriorityFail = 0;
238     DeviceExtension->RundownInProgress = 0;
239 
240     /* Initialize locks, events, timers, DPCs, etc... */
241     KeInitializeTimer(&DeviceExtension->Timer);
242     KeInitializeDpc(&DeviceExtension->Dpc, TimerDpcRoutine, DeviceExtension);
243     KeInitializeSpinLock(&DeviceExtension->Lock);
244     KeInitializeEvent(&DeviceExtension->Event, SynchronizationEvent, FALSE);
245     InitializeListHead(&DeviceExtension->List);
246 
247     /* Attempt to enable HDL support */
248     EnableData = TRUE;
249     Status = HeadlessDispatch(HeadlessCmdEnableTerminal,
250                               &EnableData,
251                               sizeof(EnableData),
252                               NULL,
253                               NULL);
254     if (!NT_SUCCESS(Status))
255     {
256         /* Bail out if we couldn't even get this far */
257         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (1) with status FALSE\n");
258         return FALSE;
259     }
260 
261     /* Remember which process we started in */
262     DeviceExtension->Process = IoGetCurrentProcess();
263 
264     /* Protect the device against non-admins */
265     Status = CreateDeviceSecurityDescriptor(&DeviceExtension->DeviceObject);
266     if (!NT_SUCCESS(Status))
267     {
268         /* Write down why we failed */
269         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (2) with status FALSE\n");
270 
271         /* Disable the HDL terminal on failure */
272         EnableData = FALSE;
273         Status = HeadlessDispatch(HeadlessCmdEnableTerminal,
274                                   &EnableData,
275                                   sizeof(EnableData),
276                                   NULL,
277                                   NULL);
278         if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n");
279 
280         /* Bail out */
281         return FALSE;
282     }
283 
284     /* Create the worker thread */
285     Status = PsCreateSystemThread(&DeviceExtension->WorkerThreadHandle,
286                                   THREAD_ALL_ACCESS,
287                                   NULL,
288                                   NULL,
289                                   NULL,
290                                   WorkerThreadStartUp,
291                                   DeviceExtension);
292     if (!NT_SUCCESS(Status))
293     {
294         /* Write down why we failed */
295         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (3) with status FALSE\n");
296 
297         /* Disable the HDL terminal on failure */
298         EnableData = FALSE;
299         Status = HeadlessDispatch(HeadlessCmdEnableTerminal,
300                                   &EnableData,
301                                   sizeof(EnableData),
302                                   NULL,
303                                   NULL);
304         if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n");
305 
306         /* Bail out */
307         return FALSE;
308     }
309 
310     /* Set the priority of our thread to highest */
311     PriorityValue = HIGH_PRIORITY;
312     Status = NtSetInformationThread(DeviceExtension->WorkerThreadHandle,
313                                     ThreadPriority,
314                                     &PriorityValue,
315                                     sizeof(PriorityValue));
316     if (!NT_SUCCESS(Status))
317     {
318         /* For debugging, write down why we failed */
319         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (6) with status FALSE\n");
320         DeviceExtension->PriorityFail = TRUE;
321 
322         /* Initialize rundown and wait for the thread to do it */
323         KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, FALSE);
324         KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, FALSE);
325         Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent,
326                                        Executive,
327                                        KernelMode,
328                                        FALSE,
329                                        NULL);
330         ASSERT(Status == STATUS_SUCCESS);
331 
332         /* Disable the HDL terminal on failure */
333         EnableData = FALSE;
334         Status = HeadlessDispatch(HeadlessCmdEnableTerminal,
335                                   &EnableData,
336                                   sizeof(EnableData),
337                                   NULL,
338                                   NULL);
339         if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n");
340 
341         /* Bail out */
342         return FALSE;
343     }
344 
345     /* The first "packet" is the machine information in XML... */
346     Status = TranslateMachineInformationXML(&Message, NULL);
347     if (NT_SUCCESS(Status))
348     {
349         /* Go ahead and send it */
350         UTF8EncodeAndSend(L"<?xml version=\"1.0\"?>\r\n");
351         UTF8EncodeAndSend(Message);
352 
353         /* Free the temporary buffer */
354         SacFreePool(Message);
355     }
356 
357     /* Finally, initialize the I/O Manager */
358     Status = ConMgrInitialize();
359     if (!NT_SUCCESS(Status)) return FALSE;
360 
361     /* Set the timer. Once this is done, the device is initialized */
362     DueTime.QuadPart = -4000;
363     KeSetTimerEx(&DeviceExtension->Timer, DueTime, 4, &DeviceExtension->Dpc);
364     DeviceExtension->Initialized = TRUE;
365 
366 SuccessExit:
367     /* Success path -- everything worked */
368     SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n");
369     return TRUE;
370 }
371 
372 BOOLEAN
373 NTAPI
374 InitializeGlobalData(IN PUNICODE_STRING RegistryPath,
375                      IN PDRIVER_OBJECT DriverObject)
376 {
377     NTSTATUS Status;
378     UNICODE_STRING LinkName;
379     UNICODE_STRING DeviceName;
380     UNICODE_STRING EventName;
381     PAGED_CODE();
382     SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n");
383 
384     /* If we already did this, bail out */
385     if (GlobalDataInitialized) goto SuccessExit;
386 
387     /* Setup the symbolic link for Win32 support */
388     RtlInitUnicodeString(&LinkName, L"\\DosDevices\\SAC");
389     RtlInitUnicodeString(&DeviceName, L"\\Device\\SAC");
390     Status = IoCreateSymbolicLink(&LinkName, &DeviceName);
391     if (!NT_SUCCESS(Status)) return FALSE;
392 
393     /* Initialize the internal heap manager */
394     if (!InitializeMemoryManagement())
395     {
396         IoDeleteSymbolicLink(&LinkName);
397         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status FALSE\n");
398         return FALSE;
399     }
400 
401     /* Preload the messages in memory */
402     Status = PreloadGlobalMessageTable(DriverObject->DriverStart);
403     if (!NT_SUCCESS(Status))
404     {
405         IoDeleteSymbolicLink(&LinkName);
406         SAC_DBG(SAC_DBG_INIT, "unable to pre-load message table: %X\n", Status);
407         return FALSE;
408     }
409 
410     /* Check if the administrator enabled this */
411     Status = GetCommandConsoleLaunchingPermission(&CommandConsoleLaunchingEnabled);
412     if (!NT_SUCCESS(Status))
413     {
414         /* Is it enabled? */
415         if (CommandConsoleLaunchingEnabled)
416         {
417             /* Set the service start type to the correct value */
418             Status = ImposeSacCmdServiceStartTypePolicy();
419             if (!NT_SUCCESS(Status))
420             {
421                 SAC_DBG(SAC_DBG_INIT, "failed ImposeSacCmdServiceStartTypePolicy: %X\n", Status);
422             }
423         }
424 
425         /* We're going to keep going with the default */
426         SAC_DBG(SAC_DBG_INIT, "failed GetCommandConsoleLaunchingPermission: %X\n", Status);
427     }
428 
429     /* Allocate the UTF-8 Conversion Buffer */
430     Utf8ConversionBuffer = SacAllocatePool(Utf8ConversionBufferSize, GLOBAL_BLOCK_TAG);
431     if (!Utf8ConversionBuffer)
432     {
433         /* Handle failure case */
434         TearDownGlobalMessageTable();
435         IoDeleteSymbolicLink(&LinkName);
436         SAC_DBG(SAC_DBG_INIT, "unable to allocate memory for UTF8 translation\n");
437         return FALSE;
438     }
439 
440     /* Initialize the channel manager */
441     Status = ChanMgrInitialize();
442     if (!NT_SUCCESS(Status))
443     {
444         /* Handle failure case */
445         SacFreePool(Utf8ConversionBuffer);
446         TearDownGlobalMessageTable();
447         IoDeleteSymbolicLink(&LinkName);
448         SAC_DBG(SAC_DBG_INIT, "Failed to create SAC Channel\n");
449         return FALSE;
450     }
451 
452     /* Allocate the serial port buffer */
453     SerialPortBuffer = SacAllocatePool(SAC_SERIAL_PORT_BUFFER_SIZE, GLOBAL_BLOCK_TAG);
454     if (!SerialPortBuffer)
455     {
456         /* Handle failure case */
457         SacFreePool(Utf8ConversionBuffer);
458         TearDownGlobalMessageTable();
459         IoDeleteSymbolicLink(&LinkName);
460         SAC_DBG(SAC_DBG_INIT, "Failed to allocate Serial Port Buffer\n");
461         return FALSE;
462     }
463 
464     /* Zero it out */
465     RtlZeroMemory(SerialPortBuffer, SAC_SERIAL_PORT_BUFFER_SIZE);
466 
467     /* Initialize command events. After this, driver data is good to go */
468     KeInitializeMutex(&SACCMDEventInfoMutex, FALSE);
469     InitializeCmdEventInfo();
470     GlobalDataInitialized = TRUE;
471     ProcessingType = 0;
472     IoctlSubmitted = 0;
473 
474     /* Create the SAC event */
475     RtlInitUnicodeString(&EventName, L"\\SACEvent");
476     SACEvent = IoCreateSynchronizationEvent(&EventName, &SACEventHandle);
477     if (!SACEvent)
478     {
479         /* Handle failure case */
480         SacFreePool(Utf8ConversionBuffer);
481         TearDownGlobalMessageTable();
482         IoDeleteSymbolicLink(&LinkName);
483         SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with event NULL\n");
484         return FALSE;
485     }
486 
487     /* Cache machine information */
488     InitializeMachineInformation();
489 
490     /* Register it */
491     Status = RegisterBlueScreenMachineInformation();
492     if (!NT_SUCCESS(Status))
493     {
494         /* Handle failure case */
495         SacFreePool(Utf8ConversionBuffer);
496         TearDownGlobalMessageTable();
497         IoDeleteSymbolicLink(&LinkName);
498         SAC_DBG(SAC_DBG_INIT, "Failed to register blue screen machine info\n");
499         return FALSE;
500     }
501 
502 SuccessExit:
503     /* Success path -- everything worked */
504     SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n");
505     return TRUE;
506 }
507