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