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
9 /* INCLUDES *******************************************************************/
13 /* GLOBALS ********************************************************************/
16 BOOLEAN CommandConsoleLaunchingEnabled
;
17 BOOLEAN GlobalDataInitialized
;
18 KMUTEX SACCMDEventInfoMutex
;
19 BOOLEAN IoctlSubmitted
;
22 HANDLE SACEventHandle
;
24 /* FUNCTIONS ******************************************************************/
28 WorkerProcessEvents(IN PSAC_DEVICE_EXTENSION DeviceExtension
)
30 /* Call the worker function */
31 ConMgrWorkerProcessEvents(DeviceExtension
);
36 WorkerThreadStartUp(IN PVOID Context
)
38 /* Call the worker function */
39 WorkerProcessEvents((PSAC_DEVICE_EXTENSION
)Context
);
44 BuildDeviceAcl(OUT PACL
* Dacl
)
47 return STATUS_NOT_IMPLEMENTED
;
52 CreateDeviceSecurityDescriptor(IN PDEVICE_OBJECT
*DeviceObject
)
55 PSECURITY_DESCRIPTOR SecurityDescriptor
;
56 BOOLEAN MemoryAllocated
= FALSE
;
58 PVOID ObjectSecurityDescriptor
= NULL
;
59 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC CreateDeviceSecurityDescriptor: Entering.\n");
61 /* Get the current SD of the device object */
62 Status
= ObGetObjectSecurity(*DeviceObject
, &SecurityDescriptor
, &MemoryAllocated
);
63 if (!NT_SUCCESS(Status
))
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
);
71 /* Build a DACL for it */
72 Status
= BuildDeviceAcl(&Dacl
);
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
;
86 /* Release the SD we queried */
87 ObReleaseObjectSecurity(SecurityDescriptor
, MemoryAllocated
);
89 /* Free anything else we may have allocated */
90 if (ObjectSecurityDescriptor
) ExFreePool(ObjectSecurityDescriptor
);
91 if (Dacl
) SacFreePool(Dacl
);
94 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status
);
102 UNICODE_STRING SymbolicLink
;
103 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC FreeGlobalData: Entering.\n");
105 /* Only free if we allocated */
106 if (GlobalDataInitialized
)
108 /* Close the SAC event if we had created one */
111 ZwClose(SACEventHandle
);
115 /* Destroy the cached messages */
116 TearDownGlobalMessageTable();
118 /* Delete the Win32 symbolic link */
119 RtlInitUnicodeString(&SymbolicLink
, L
"\\DosDevices\\SAC");
120 IoDeleteSymbolicLink(&SymbolicLink
);
122 /* Tear down connections */
125 /* Tear down channels */
128 /* Free the serial port buffer */
129 if (SerialPortBuffer
) SacFreePool(SerialPortBuffer
);
131 /* Free cached machine information */
132 FreeMachineInformation();
134 /* Cleanup the custom heap allocator */
135 FreeMemoryManagement();
137 /* We're back to a virgin state */
138 GlobalDataInitialized
= FALSE
;
142 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC FreeGlobalData: Exiting.\n");
147 FreeDeviceData(IN PDEVICE_OBJECT DeviceObject
)
149 PSAC_DEVICE_EXTENSION DeviceExtension
;
152 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC FreeDeviceData: Entering.\n");
154 /* Get the device extension and see how far we had gotten */
155 DeviceExtension
= (PSAC_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
156 if ((GlobalDataInitialized
) && (DeviceExtension
->Initialized
))
158 /* Attempt to rundown while holding the lock */
159 KeAcquireSpinLock(&DeviceExtension
->Lock
, &OldIrql
);
160 while (DeviceExtension
->RundownInProgress
)
162 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC FreeDeviceData: Waiting....\n");
164 /* Initiate and wait for rundown */
165 KeInitializeEvent(&DeviceExtension
->RundownEvent
, SynchronizationEvent
, 0);
166 KeReleaseSpinLock(&DeviceExtension
->Lock
, OldIrql
);
167 Status
= KeWaitForSingleObject(&DeviceExtension
->RundownEvent
,
172 ASSERT(Status
== STATUS_SUCCESS
);
174 /* Re-acquire the lock and check if rundown is done */
175 KeAcquireSpinLock(&DeviceExtension
->Lock
, &OldIrql
);
179 /* Now set the rundown flag while we cancel the timer */
180 DeviceExtension
->RundownInProgress
= TRUE
;
181 KeReleaseSpinLock(&DeviceExtension
->Lock
, OldIrql
);
184 KeCancelTimer(&DeviceExtension
->Timer
);
186 /* Reacquire the lock*/
187 KeAcquireSpinLock(&DeviceExtension
->Lock
, &OldIrql
);
188 DeviceExtension
->RundownInProgress
= FALSE
;
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
,
199 ASSERT(Status
== STATUS_SUCCESS
);
201 /* We no longer care about shutdown */
202 IoUnregisterShutdownNotification(DeviceObject
);
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");
213 InitializeDeviceData(IN PDEVICE_OBJECT DeviceObject
)
215 PSAC_DEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
219 LARGE_INTEGER DueTime
;
222 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Entering.\n");
224 /* If we already did this, bail out */
225 if (DeviceExtension
->Initialized
) goto SuccessExit
;
227 /* Setup the DO flags */
228 DeviceObject
->Flags
|= DO_DIRECT_IO
;
229 DeviceObject
->StackSize
= 16;
231 /* Setup the device extension */
232 DeviceExtension
->DeviceObject
= DeviceObject
;
233 DeviceExtension
->PriorityBoost
= IO_SERIAL_INCREMENT
;
234 DeviceExtension
->PriorityFail
= 0;
235 DeviceExtension
->RundownInProgress
= 0;
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
);
244 /* Attempt to enable HDL support */
246 Status
= HeadlessDispatch(HeadlessCmdEnableTerminal
,
251 if (!NT_SUCCESS(Status
))
253 /* Bail out if we couldn't even get this far */
254 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Exiting (1) with status FALSE\n");
258 /* Remember which process we started in */
259 DeviceExtension
->Process
= IoGetCurrentProcess();
261 /* Protect the device against non-admins */
262 Status
= CreateDeviceSecurityDescriptor(&DeviceExtension
->DeviceObject
);
263 if (!NT_SUCCESS(Status
))
265 /* Write down why we failed */
266 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Exiting (2) with status FALSE\n");
268 /* Disable the HDL terminal on failure */
270 Status
= HeadlessDispatch(HeadlessCmdEnableTerminal
,
275 if (!NT_SUCCESS(Status
)) SAC_DBG(SAC_DBG_INIT
, "Failed dispatch\n");
281 /* Create the worker thread */
282 Status
= PsCreateSystemThread(&DeviceExtension
->WorkerThreadHandle
,
289 if (!NT_SUCCESS(Status
))
291 /* Write down why we failed */
292 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Exiting (3) with status FALSE\n");
294 /* Disable the HDL terminal on failure */
296 Status
= HeadlessDispatch(HeadlessCmdEnableTerminal
,
301 if (!NT_SUCCESS(Status
)) SAC_DBG(SAC_DBG_INIT
, "Failed dispatch\n");
307 /* Set the priority of our thread to highest */
308 PriorityValue
= HIGH_PRIORITY
;
309 Status
= NtSetInformationThread(DeviceExtension
->WorkerThreadHandle
,
312 sizeof(PriorityValue
));
313 if (!NT_SUCCESS(Status
))
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
;
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
,
327 ASSERT(Status
== STATUS_SUCCESS
);
329 /* Disable the HDL terminal on failure */
331 Status
= HeadlessDispatch(HeadlessCmdEnableTerminal
,
336 if (!NT_SUCCESS(Status
)) SAC_DBG(SAC_DBG_INIT
, "Failed dispatch\n");
342 /* The first "packet" is the machine information in XML... */
343 Status
= TranslateMachineInformationXML(&Message
, NULL
);
344 if (NT_SUCCESS(Status
))
346 /* Go ahead and send it */
347 UTF8EncodeAndSend(L
"<?xml version=\"1.0\"?>\r\n");
348 UTF8EncodeAndSend(Message
);
350 /* Free the temporary buffer */
351 SacFreePool(Message
);
354 /* Finally, initialize the I/O Manager */
355 Status
= ConMgrInitialize();
356 if (!NT_SUCCESS(Status
)) return FALSE
;
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
;
364 /* Success path -- everything worked */
365 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Exiting with status TRUE\n");
371 InitializeGlobalData(IN PUNICODE_STRING RegistryPath
,
372 IN PDRIVER_OBJECT DriverObject
)
375 UNICODE_STRING LinkName
;
376 UNICODE_STRING DeviceName
;
377 UNICODE_STRING EventName
;
379 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Entering.\n");
381 /* If we already did this, bail out */
382 if (GlobalDataInitialized
) goto SuccessExit
;
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
;
390 /* Initialize the internal heap manager */
391 if (!InitializeMemoryManagement())
393 IoDeleteSymbolicLink(&LinkName
);
394 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Exiting with status FALSE\n");
398 /* Preload the messages in memory */
399 Status
= PreloadGlobalMessageTable(DriverObject
->DriverStart
);
400 if (!NT_SUCCESS(Status
))
402 IoDeleteSymbolicLink(&LinkName
);
403 SAC_DBG(SAC_DBG_INIT
, "unable to pre-load message table: %X\n", Status
);
407 /* Check if the administrator enabled this */
408 Status
= GetCommandConsoleLaunchingPermission(&CommandConsoleLaunchingEnabled
);
409 if (!NT_SUCCESS(Status
))
412 if (CommandConsoleLaunchingEnabled
)
414 /* Set the service start type to the correct value */
415 Status
= ImposeSacCmdServiceStartTypePolicy();
416 if (!NT_SUCCESS(Status
))
418 SAC_DBG(SAC_DBG_INIT
, "failed ImposeSacCmdServiceStartTypePolicy: %X\n", Status
);
422 /* We're going to keep going with the default */
423 SAC_DBG(SAC_DBG_INIT
, "failed GetCommandConsoleLaunchingPermission: %X\n", Status
);
426 /* Allocate the UTF-8 Conversion Buffer */
427 Utf8ConversionBuffer
= SacAllocatePool(Utf8ConversionBufferSize
, GLOBAL_BLOCK_TAG
);
428 if (!Utf8ConversionBuffer
)
430 /* Handle failure case */
431 TearDownGlobalMessageTable();
432 IoDeleteSymbolicLink(&LinkName
);
433 SAC_DBG(SAC_DBG_INIT
, "unable to allocate memory for UTF8 translation\n");
437 /* Initialize the channel manager */
438 Status
= ChanMgrInitialize();
439 if (!NT_SUCCESS(Status
))
441 /* Handle failure case */
442 SacFreePool(Utf8ConversionBuffer
);
443 TearDownGlobalMessageTable();
444 IoDeleteSymbolicLink(&LinkName
);
445 SAC_DBG(SAC_DBG_INIT
, "Failed to create SAC Channel\n");
449 /* Allocate the serial port buffer */
450 SerialPortBuffer
= SacAllocatePool(SAC_SERIAL_PORT_BUFFER_SIZE
, GLOBAL_BLOCK_TAG
);
451 if (!SerialPortBuffer
)
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");
462 RtlZeroMemory(SerialPortBuffer
, SAC_SERIAL_PORT_BUFFER_SIZE
);
464 /* Initialize command events. After this, driver data is good to go */
465 KeInitializeMutex(&SACCMDEventInfoMutex
, FALSE
);
466 InitializeCmdEventInfo();
467 GlobalDataInitialized
= TRUE
;
471 /* Create the SAC event */
472 RtlInitUnicodeString(&EventName
, L
"\\SACEvent");
473 SACEvent
= IoCreateSynchronizationEvent(&EventName
, &SACEventHandle
);
476 /* Handle failure case */
477 SacFreePool(Utf8ConversionBuffer
);
478 TearDownGlobalMessageTable();
479 IoDeleteSymbolicLink(&LinkName
);
480 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Exiting with event NULL\n");
484 /* Cache machine information */
485 InitializeMachineInformation();
488 Status
= RegisterBlueScreenMachineInformation();
489 if (!NT_SUCCESS(Status
))
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");
500 /* Success path -- everything worked */
501 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "Exiting with status TRUE\n");