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 /* 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(SAC_DBG_ENTRY_EXIT, "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