Synchronize with trunk revision 59781.
[reactos.git] / drivers / sac / driver / data.c
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 = 0xFFFFFFFF;
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 return 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(1, "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(1, "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(1, "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