Reactos
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
15ULONG SACDebug = 0;
16BOOLEAN CommandConsoleLaunchingEnabled;
17BOOLEAN GlobalDataInitialized;
18KMUTEX SACCMDEventInfoMutex;
19BOOLEAN IoctlSubmitted;
20ULONG ProcessingType;
21PKEVENT SACEvent;
22HANDLE SACEventHandle;
23
24/* FUNCTIONS ******************************************************************/
25
26VOID
27NTAPI
28WorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension)
29{
30 /* Call the worker function */
31 ConMgrWorkerProcessEvents(DeviceExtension);
32}
33
34VOID
35NTAPI
36WorkerThreadStartUp(IN PVOID Context)
37{
38 /* Call the worker function */
39 WorkerProcessEvents((PSAC_DEVICE_EXTENSION)Context);
40}
41
42NTSTATUS
43NTAPI
44BuildDeviceAcl(OUT PACL* Dacl)
45{
46 /* TODO */
47 return STATUS_NOT_IMPLEMENTED;
48}
49
50NTSTATUS
51NTAPI
52CreateDeviceSecurityDescriptor(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
85CleanupPath:
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
98VOID
99NTAPI
100FreeGlobalData(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
145VOID
146NTAPI
147FreeDeviceData(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);
210Exit:
211 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeDeviceData: Exiting.\n");
212}
213
214BOOLEAN
215NTAPI
216InitializeDeviceData(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
366SuccessExit:
367 /* Success path -- everything worked */
368 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n");
369 return TRUE;
370}
371
372BOOLEAN
373NTAPI
374InitializeGlobalData(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
502SuccessExit:
503 /* Success path -- everything worked */
504 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n");
505 return TRUE;
506}