1 /* 2 * PROJECT: ReactOS Drivers 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/sac/driver/util.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 #include <ndk/rtlfuncs.h> 14 15 /* GLOBALS ********************************************************************/ 16 17 PCHAR Utf8ConversionBuffer; 18 ULONG Utf8ConversionBufferSize = PAGE_SIZE; 19 20 PSAC_MACHINE_INFO MachineInformation; 21 22 PVOID RequestSacCmdEventObjectBody; 23 PKEVENT RequestSacCmdEventWaitObjectBody; 24 PVOID RequestSacCmdSuccessEventObjectBody; 25 PKEVENT RequestSacCmdSuccessEventWaitObjectBody; 26 PVOID RequestSacCmdFailureEventObjectBody; 27 PKEVENT RequestSacCmdFailureEventWaitObjectBody; 28 PFILE_OBJECT ServiceProcessFileObject; 29 BOOLEAN HaveUserModeServiceCmdEventInfo; 30 31 PSAC_MESSAGE_ENTRY GlobalMessageTable; 32 ULONG GlobalMessageTableCount; 33 34 LONG SerialPortConsumerIndex, SerialPortProducerIndex; 35 PCHAR SerialPortBuffer; 36 37 /* FUNCTIONS ******************************************************************/ 38 39 BOOLEAN 40 NTAPI 41 SacTranslateUtf8ToUnicode(IN CHAR Utf8Char, 42 IN PCHAR Utf8Buffer, 43 OUT PWCHAR Utf8Value) 44 { 45 ULONG i; 46 47 /* Find out how many valid characters we have in the buffer */ 48 i = 0; 49 while (Utf8Buffer[i++] && (i < 3)); 50 51 /* If we have at least 3, shift everything by a byte */ 52 if (i >= 3) 53 { 54 /* The last input character goes at the end */ 55 Utf8Buffer[0] = Utf8Buffer[1]; 56 Utf8Buffer[1] = Utf8Buffer[2]; 57 Utf8Buffer[2] = Utf8Char; 58 } 59 else 60 { 61 /* We don't have more than 3 characters, place the input at the index */ 62 Utf8Buffer[i] = Utf8Char; 63 } 64 65 /* Print to debugger */ 66 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SacTranslateUtf8ToUnicode - About to decode the UTF8 buffer.\n"); 67 SAC_DBG(SAC_DBG_ENTRY_EXIT, " UTF8[0]: 0x%02lx UTF8[1]: 0x%02lx UTF8[2]: 0x%02lx\n", 68 Utf8Buffer[0], 69 Utf8Buffer[1], 70 Utf8Buffer[2]); 71 72 /* Is this a simple ANSI character? */ 73 if (!(Utf8Char & 0x80)) 74 { 75 /* Return it as Unicode, nothing left to do */ 76 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SACDRV: SacTranslateUTf8ToUnicode - Case1\n"); 77 *Utf8Value = (WCHAR)Utf8Char; 78 Utf8Buffer[0] = Utf8Buffer[1]; 79 Utf8Buffer[1] = Utf8Buffer[2]; 80 Utf8Buffer[2] = UNICODE_NULL; 81 return TRUE; 82 } 83 84 /* Anything else is not yet supported */ 85 ASSERT(FALSE); 86 return FALSE; 87 } 88 89 BOOLEAN 90 NTAPI 91 SacTranslateUnicodeToUtf8(IN PWCHAR SourceBuffer, 92 IN ULONG SourceBufferLength, 93 OUT PCHAR DestinationBuffer, 94 IN ULONG DestinationBufferSize, 95 OUT PULONG UTF8Count, 96 OUT PULONG ProcessedCount) 97 { 98 *UTF8Count = 0; 99 *ProcessedCount = 0; 100 101 while ((*SourceBuffer) && 102 (*UTF8Count < DestinationBufferSize) && 103 (*ProcessedCount < SourceBufferLength)) 104 { 105 if (*SourceBuffer & 0xFF80) 106 { 107 if (*SourceBuffer & 0xF800) 108 { 109 if ((*UTF8Count + 3) >= DestinationBufferSize) break; 110 DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 12) & 0xF) | 0xE0; 111 ++*UTF8Count; 112 DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 6) & 0x3F) | 0x80; 113 } 114 else 115 { 116 if ((*UTF8Count + 2) >= DestinationBufferSize) break; 117 DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 6) & 31) | 0xC0; 118 } 119 ++*UTF8Count; 120 DestinationBuffer[*UTF8Count] = (*SourceBuffer & 0x3F) | 0x80; 121 } 122 else 123 { 124 DestinationBuffer[*UTF8Count] = (*SourceBuffer & 0x7F); 125 } 126 127 ++*UTF8Count; 128 ++*ProcessedCount; 129 ++SourceBuffer; 130 } 131 132 ASSERT(*ProcessedCount <= SourceBufferLength); 133 ASSERT(*UTF8Count <= DestinationBufferSize); 134 return TRUE; 135 } 136 137 PWCHAR 138 NTAPI 139 GetMessage(IN ULONG MessageIndex) 140 { 141 PSAC_MESSAGE_ENTRY MessageEntry; 142 ULONG i; 143 PWCHAR MessageData = NULL; 144 145 /* Loop all cached messages */ 146 for (i = 0; i < GlobalMessageTableCount; i++) 147 { 148 /* Check if this one matches the index */ 149 MessageEntry = &GlobalMessageTable[i]; 150 if (MessageEntry->Index == MessageIndex) 151 { 152 /* It does, return the buffer */ 153 MessageData = MessageEntry->Buffer; 154 break; 155 } 156 } 157 158 /* We should always find it */ 159 if (!MessageData) ASSERT(FALSE); 160 return MessageData; 161 } 162 163 NTSTATUS 164 NTAPI 165 UTF8EncodeAndSend(IN PWCHAR String) 166 { 167 ULONG ProcessedCount, Utf8Count, i; 168 NTSTATUS Status = STATUS_SUCCESS; 169 170 /* Call the translator routine */ 171 if (SacTranslateUnicodeToUtf8(String, 172 wcslen(String), 173 Utf8ConversionBuffer, 174 Utf8ConversionBufferSize, 175 &Utf8Count, 176 &ProcessedCount)) 177 { 178 /* Loop every character */ 179 for (i = 0; i < Utf8Count; i++) 180 { 181 /* Send it to the terminal */ 182 Status = HeadlessDispatch(HeadlessCmdPutData, 183 &Utf8ConversionBuffer[i], 184 sizeof(Utf8ConversionBuffer[i]), 185 NULL, 186 NULL); 187 if (!NT_SUCCESS(Status)) break; 188 } 189 } 190 else 191 { 192 /* Conversion failed */ 193 Status = STATUS_UNSUCCESSFUL; 194 } 195 196 /* All done */ 197 return Status; 198 } 199 200 VOID 201 NTAPI 202 SacFormatMessage(IN PWCHAR FormattedString, 203 IN PWCHAR MessageString, 204 IN ULONG MessageSize) 205 { 206 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Entering.\n"); 207 208 /* Check if any of the parameters are NULL or zero */ 209 if (!(MessageString) || !(FormattedString) || !(MessageSize)) 210 { 211 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Exiting with invalid parameters.\n"); 212 return; 213 } 214 215 /* Keep going as long as there's still characters */ 216 while ((MessageString[0]) && (MessageSize)) 217 { 218 /* Is it a non-formatting character? */ 219 if (MessageString[0] != L'%') 220 { 221 /* Just write it back into the buffer and keep going */ 222 *FormattedString++ = MessageString[0]; 223 MessageString++; 224 } 225 else 226 { 227 /* Go over the format characters we recognize */ 228 switch (MessageString[1]) 229 { 230 case L'0': 231 *FormattedString = UNICODE_NULL; 232 return; 233 234 case L'%': 235 *FormattedString++ = L'%'; 236 break; 237 238 case L'\\': 239 *FormattedString++ = L'\r'; 240 *FormattedString++ = L'\n'; 241 break; 242 243 case L'r': 244 *FormattedString++ = L'\r'; 245 break; 246 247 case L'b': 248 *FormattedString++ = L' '; 249 break; 250 251 case L'.': 252 *FormattedString++ = L'.'; 253 break; 254 255 case L'!': 256 *FormattedString++ = L'!'; 257 break; 258 259 default: 260 /* Only move forward one character */ 261 MessageString--; 262 break; 263 } 264 265 /* Move forward two characters */ 266 MessageString += 2; 267 } 268 269 /* Move to the next character*/ 270 MessageSize--; 271 } 272 273 /* All done */ 274 *FormattedString = UNICODE_NULL; 275 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Exiting.\n"); 276 } 277 278 NTSTATUS 279 NTAPI 280 PreloadGlobalMessageTable(IN PVOID ImageBase) 281 { 282 NTSTATUS Status, Status2; 283 ULONG MessageId, TotalLength, TextSize, i; 284 PWCHAR StringBuffer; 285 PMESSAGE_RESOURCE_ENTRY MessageEntry; 286 PAGED_CODE(); 287 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC PreloadGlobalMessageTable: Entering.\n"); 288 289 /* Nothing to do if we already have a table */ 290 Status = STATUS_SUCCESS; 291 if (GlobalMessageTable) goto Exit; 292 293 /* Loop through up to 200 messages */ 294 TotalLength = 0; 295 for (MessageId = 1; MessageId != SAC_MAX_MESSAGES; MessageId++) 296 { 297 /* Find this message ID in the string table*/ 298 Status2 = RtlFindMessage(ImageBase, 299 11, 300 LANG_NEUTRAL, 301 MessageId, 302 &MessageEntry); 303 if (NT_SUCCESS(Status2)) 304 { 305 /* Make sure it's Unicode */ 306 ASSERT(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE); 307 308 /* Remove the space taken up by the OS header, and add our own */ 309 TotalLength += MessageEntry->Length - 310 FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text) + 311 sizeof(SAC_MESSAGE_ENTRY); 312 313 /* One more in the table */ 314 GlobalMessageTableCount++; 315 } 316 } 317 318 /* We should've found at least one message... */ 319 if (!TotalLength) 320 { 321 /* Bail out otherwise */ 322 SAC_DBG(SAC_DBG_INIT, "SAC PreloadGlobalMessageTable: No Messages.\n"); 323 Status = STATUS_INVALID_PARAMETER; 324 goto Exit; 325 } 326 327 /* Allocate space for the buffers and headers */ 328 GlobalMessageTable = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG); 329 if (!GlobalMessageTable) 330 { 331 /* Bail out if we couldn't allocate it */ 332 Status = STATUS_NO_MEMORY; 333 goto Exit; 334 } 335 336 /* All the buffers are going to be at the end of the table */ 337 StringBuffer = (PWCHAR)(&GlobalMessageTable[GlobalMessageTableCount]); 338 339 /* Now loop over our entries again */ 340 for (i = 0, MessageId = 1; MessageId != SAC_MAX_MESSAGES; MessageId++) 341 { 342 /* Make sure the message is still there...! */ 343 Status2 = RtlFindMessage(ImageBase, 344 11, 345 LANG_NEUTRAL, 346 MessageId, 347 &MessageEntry); 348 if (NT_SUCCESS(Status2)) 349 { 350 /* Write the entry in the message table*/ 351 GlobalMessageTable[i].Index = MessageId; 352 GlobalMessageTable[i].Buffer = StringBuffer; 353 354 /* The structure includes the size of the header, elide it */ 355 TextSize = MessageEntry->Length - 356 FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text); 357 358 /* Format the message into the entry. It should be same or smaller */ 359 SacFormatMessage(StringBuffer, (PWCHAR)MessageEntry->Text, TextSize); 360 ASSERT((ULONG)(wcslen(StringBuffer)*sizeof(WCHAR)) <= TextSize); 361 362 /* Move to the next buffer space */ 363 StringBuffer += (TextSize / sizeof(WCHAR)); 364 365 /* Move to the next entry, make sure the status is full success */ 366 i++; 367 Status = STATUS_SUCCESS; 368 } 369 } 370 371 Exit: 372 /* All done, return the status code */ 373 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Exiting with status 0x%0x\n", Status); 374 return Status; 375 } 376 377 NTSTATUS 378 NTAPI 379 TearDownGlobalMessageTable(VOID) 380 { 381 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Entering.\n"); 382 383 /* Free the table if one existed */ 384 if (GlobalMessageTable) SacFreePool(GlobalMessageTable); 385 386 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Exiting\n"); 387 return STATUS_SUCCESS; 388 } 389 390 NTSTATUS 391 NTAPI 392 GetRegistryValueBuffer(IN PCWSTR KeyName, 393 IN PWCHAR ValueName, 394 IN PKEY_VALUE_PARTIAL_INFORMATION* Buffer) 395 { 396 NTSTATUS Status; 397 OBJECT_ATTRIBUTES ObjectAttributes; 398 UNICODE_STRING DestinationString; 399 HANDLE Handle; 400 ULONG ResultLength = 0; 401 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: Entering.\n"); 402 CHECK_PARAMETER1(KeyName); 403 CHECK_PARAMETER2(ValueName); 404 405 /* Open the specified key */ 406 RtlInitUnicodeString(&DestinationString, KeyName); 407 InitializeObjectAttributes(&ObjectAttributes, 408 &DestinationString, 409 OBJ_CASE_INSENSITIVE, 410 NULL, 411 NULL); 412 Status = ZwOpenKey(&Handle, 413 KEY_WRITE | SYNCHRONIZE | KEY_READ, 414 &ObjectAttributes); 415 if (!NT_SUCCESS(Status)) 416 { 417 /* Bail out on failure */ 418 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwOpenKey: %X.\n", Status); 419 return Status; 420 } 421 422 /* Query the size of the key */ 423 RtlInitUnicodeString(&DestinationString, ValueName); 424 Status = ZwQueryValueKey(Handle, 425 &DestinationString, 426 KeyValuePartialInformation, 427 NULL, 428 0, 429 &ResultLength); 430 if (!ResultLength) return Status; 431 432 /* Allocate the buffer for the partial info structure and our integer data */ 433 ResultLength += sizeof(ULONG); 434 *Buffer = SacAllocatePool(ResultLength, GLOBAL_BLOCK_TAG); 435 if (!*Buffer) 436 { 437 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed allocation\n"); 438 return Status; 439 } 440 441 /* Now read the data */ 442 Status = ZwQueryValueKey(Handle, 443 &DestinationString, 444 KeyValuePartialInformation, 445 *Buffer, 446 ResultLength, 447 &ResultLength); 448 if (!NT_SUCCESS(Status)) 449 { 450 /* Free the buffer if we couldn't read the data */ 451 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwQueryValueKey: %X.\n", Status); 452 SacFreePool(*Buffer); 453 } 454 455 /* Return the result */ 456 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n"); 457 return Status; 458 } 459 460 NTSTATUS 461 NTAPI 462 SetRegistryValue(IN PCWSTR KeyName, 463 IN PWCHAR ValueName, 464 IN ULONG Type, 465 IN PVOID Data, 466 IN ULONG DataSize) 467 { 468 NTSTATUS Status; 469 OBJECT_ATTRIBUTES ObjectAttributes; 470 UNICODE_STRING DestinationString; 471 HANDLE Handle; 472 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Entering.\n"); 473 CHECK_PARAMETER1(KeyName); 474 CHECK_PARAMETER2(ValueName); 475 CHECK_PARAMETER4(Data); 476 477 /* Open the specified key */ 478 RtlInitUnicodeString(&DestinationString, KeyName); 479 InitializeObjectAttributes(&ObjectAttributes, 480 &DestinationString, 481 OBJ_CASE_INSENSITIVE, 482 NULL, 483 NULL); 484 Status = ZwOpenKey(&Handle, 485 KEY_WRITE | SYNCHRONIZE | KEY_READ, 486 &ObjectAttributes); 487 if (!NT_SUCCESS(Status)) 488 { 489 /* Bail out on failure */ 490 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwOpenKey: %X.\n", Status); 491 return Status; 492 } 493 494 /* Set the specified value */ 495 RtlInitUnicodeString(&DestinationString, ValueName); 496 Status = ZwSetValueKey(Handle, &DestinationString, 0, Type, Data, DataSize); 497 if (!NT_SUCCESS(Status)) 498 { 499 /* Print error on failure */ 500 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwSetValueKey: %X.\n", Status); 501 } 502 503 /* Close the handle and exit */ 504 NtClose(Handle); 505 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n"); 506 return Status; 507 } 508 509 NTSTATUS 510 NTAPI 511 CopyRegistryValueData(IN PVOID* Buffer, 512 IN PKEY_VALUE_PARTIAL_INFORMATION PartialInfo) 513 { 514 NTSTATUS Status = STATUS_SUCCESS; 515 CHECK_PARAMETER1(Buffer); 516 CHECK_PARAMETER2(PartialInfo); 517 518 /* Allocate space for registry data */ 519 *Buffer = SacAllocatePool(PartialInfo->DataLength, GLOBAL_BLOCK_TAG); 520 if (*Buffer) 521 { 522 /* Copy the data into the buffer */ 523 RtlCopyMemory(*Buffer, PartialInfo->Data, PartialInfo->DataLength); 524 } 525 else 526 { 527 /* Set the correct error code */ 528 SAC_DBG(SAC_DBG_UTIL, "SAC CopyRegistryValueBuffer: Failed ALLOCATE.\n"); 529 Status = STATUS_NO_MEMORY; 530 } 531 532 /* Return the result */ 533 return Status; 534 } 535 536 NTSTATUS 537 NTAPI 538 TranslateMachineInformationXML(IN PWCHAR *Buffer, 539 IN PWCHAR ExtraData) 540 { 541 NTSTATUS Status; 542 SIZE_T Size; 543 PWCHAR p; 544 CHECK_PARAMETER1(Buffer); 545 546 /* Start by believing the world is beautiful */ 547 Status = STATUS_SUCCESS; 548 549 /* First, the header */ 550 Size = wcslen(L"<machine-info>\r\n"); 551 552 /* Do we have a machine name? */ 553 if (MachineInformation->MachineName) 554 { 555 /* Go and add it in */ 556 Size += wcslen(MachineInformation->MachineName); 557 Size += wcslen(L"<name>%s</name>\r\n"); 558 } 559 560 /* Do we have a GUID? */ 561 if (MachineInformation->MachineGuid) 562 { 563 /* Go and add it in */ 564 Size += wcslen(MachineInformation->MachineGuid); 565 Size += wcslen(L"<guid>%s</guid>\r\n"); 566 } 567 568 /* Do we know the processor? */ 569 if (MachineInformation->ProcessorArchitecture) 570 { 571 /* Go and add it in */ 572 Size += wcslen(MachineInformation->ProcessorArchitecture); 573 Size += wcslen(L"<processor-architecture>%s</processor-architecture>\r\n"); 574 } 575 576 /* Do we have the version? */ 577 if (MachineInformation->MajorVersion) 578 { 579 /* Go and add it in */ 580 Size += wcslen(MachineInformation->MajorVersion); 581 Size += wcslen(L"<os-version>%s</os-version>\r\n"); 582 } 583 584 /* Do we have the build? */ 585 if (MachineInformation->BuildNumber) 586 { 587 /* Go and add it in */ 588 Size += wcslen(MachineInformation->BuildNumber); 589 Size += wcslen(L"<os-build-number>%s</os-build-number>\r\n"); 590 } 591 592 /* Do we have the product type? */ 593 if (MachineInformation->ProductType) 594 { 595 /* Go and add it in */ 596 Size += wcslen(MachineInformation->ProductType); 597 Size += wcslen(L"<os-product>%s</os-product>\r\n"); 598 } 599 600 /* Do we have a service pack? */ 601 if (MachineInformation->ServicePack) 602 { 603 /* Go and add it in */ 604 Size += wcslen(MachineInformation->ServicePack); 605 Size += wcslen(L"<os-service-pack>%s</os-service-pack>\r\n"); 606 } 607 608 /* Anything else we need to know? Add it in too */ 609 if (ExtraData) Size += wcslen(ExtraData); 610 611 /* Finally, add the footer */ 612 Size += wcslen(L"</machine-info>\r\n"); 613 614 /* Convert to bytes and add a NULL */ 615 Size += sizeof(ANSI_NULL); 616 Size *= sizeof(WCHAR); 617 618 /* Allocate space for the buffer */ 619 p = SacAllocatePool(Size, GLOBAL_BLOCK_TAG); 620 *Buffer = p; 621 if (!p) return STATUS_NO_MEMORY; 622 623 wcscpy(p, L"<machine-info>\r\n"); 624 p += wcslen(L"<machine-info>\r\n"); 625 626 if (MachineInformation->MachineName) 627 { 628 p += swprintf(p, 629 L"<name>%s</name>\r\n", 630 MachineInformation->MachineName); 631 } 632 633 if (MachineInformation->MachineGuid) 634 { 635 p += swprintf(p, 636 L"<guid>%s</guid>\r\n", 637 MachineInformation->MachineGuid); 638 } 639 640 if (MachineInformation->ProcessorArchitecture) 641 { 642 p += swprintf(p, 643 L"<processor-architecture>%s</processor-architecture>\r\n", 644 MachineInformation->ProcessorArchitecture); 645 } 646 647 if (MachineInformation->MajorVersion) 648 { 649 p += swprintf(p, 650 L"<os-version>%s</os-version>\r\n", 651 MachineInformation->MajorVersion); 652 } 653 654 if (MachineInformation->BuildNumber) 655 { 656 p += swprintf(p, 657 L"<os-build-number>%s</os-build-number>\r\n", 658 MachineInformation->BuildNumber); 659 } 660 661 if (MachineInformation->ProductType) 662 { 663 p += swprintf(p, 664 L"<os-product>%s</os-product>\r\n", 665 MachineInformation->ProductType); 666 } 667 668 if (MachineInformation->ServicePack) 669 { 670 p += swprintf(p, 671 L"<os-service-pack>%s</os-service-pack>\r\n", 672 MachineInformation->ServicePack); 673 } 674 675 if (ExtraData) 676 { 677 wcscpy(p, ExtraData); 678 p += wcslen(ExtraData); 679 } 680 681 wcscpy(p, L"</machine-info>\r\n"); 682 SAC_DBG(SAC_DBG_ENTRY_EXIT, "MachineInformation: %S\n", *Buffer); 683 ASSERT((((ULONG)wcslen(*Buffer) + 1) * sizeof(WCHAR)) <= Size); 684 return Status; 685 } 686 687 VOID 688 NTAPI 689 InitializeMachineInformation(VOID) 690 { 691 NTSTATUS Status; 692 PWCHAR GuidString, MajorVersion, ServicePack, BuildNumber, MessageBuffer; 693 PWCHAR ProductType; 694 ULONG SuiteTypeMessage; 695 BOOLEAN SetupInProgress = FALSE; 696 GUID SystemGuid; 697 SIZE_T RealSize, Size, OutputSize; 698 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; 699 RTL_OSVERSIONINFOEXW VersionInformation; 700 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Entering.\n"); 701 702 /* Don't do anything if we already queried this */ 703 if (MachineInformation) 704 { 705 SAC_DBG(SAC_DBG_MACHINE, "SAC Initialize Machine Information:: MachineInformationBuffer already initialized.\n"); 706 return; 707 } 708 709 /* Allocate the machine information */ 710 MachineInformation = SacAllocatePool(sizeof(*MachineInformation), 711 GLOBAL_BLOCK_TAG); 712 if (!MachineInformation) 713 { 714 goto Fail; 715 } 716 717 /* Zero it out for now */ 718 RtlZeroMemory(MachineInformation, sizeof(*MachineInformation)); 719 720 /* Query OS version */ 721 RtlZeroMemory(&VersionInformation, sizeof(VersionInformation)); 722 VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation); 723 Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&VersionInformation); 724 if (!NT_SUCCESS(Status)) 725 { 726 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (2).\n"); 727 goto Fail; 728 } 729 730 /* Check if setup is in progress */ 731 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\Setup", 732 L"SystemSetupInProgress", 733 &PartialInfo); 734 if (NT_SUCCESS(Status)) 735 { 736 /* The key is there, is the value set? */ 737 if (*(PULONG)PartialInfo->Data) SetupInProgress = TRUE; 738 SacFreePool(PartialInfo); 739 if (SetupInProgress) 740 { 741 /* Yes, so we'll use a special hostname to identify this */ 742 MessageBuffer = GetMessage(SAC_UNINITIALIZED_MSG); 743 Size = wcslen(MessageBuffer); 744 ASSERT(Size > 0); 745 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL); 746 747 /* Make room for it and copy it in there */ 748 MachineInformation->MachineName = SacAllocatePool(RealSize, 749 GLOBAL_BLOCK_TAG); 750 if (MachineInformation->MachineName) 751 { 752 wcscpy(MachineInformation->MachineName, MessageBuffer); 753 } 754 } 755 } 756 757 /* If we are not in setup mode, or if we failed to check... */ 758 if (!SetupInProgress) 759 { 760 /* Query the computer name */ 761 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\" 762 L"CurrentControlSet\\Control\\" 763 L"ComputerName\\ComputerName", 764 L"ComputerName", 765 &PartialInfo); 766 if (!NT_SUCCESS(Status)) 767 { 768 /* It's not critical, but we won't have it */ 769 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get machine name.\n"); 770 } 771 else 772 { 773 /* We have the name, copy it from the registry */ 774 Status = CopyRegistryValueData((PVOID*)&MachineInformation-> 775 MachineName, 776 PartialInfo); 777 SacFreePool(PartialInfo); 778 if (!NT_SUCCESS(Status)) 779 { 780 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (20).\n"); 781 goto Fail; 782 } 783 } 784 } 785 786 /* Next step, try to get the machine GUID */ 787 RtlZeroMemory(&SystemGuid, sizeof(SystemGuid)); 788 OutputSize = sizeof(SystemGuid); 789 Status = HeadlessDispatch(HeadlessCmdQueryGUID, 790 NULL, 791 0, 792 &SystemGuid, 793 &OutputSize); 794 if (!NT_SUCCESS(Status)) 795 { 796 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get Machine GUID.\n"); 797 } 798 else 799 { 800 /* We have it -- make room for it */ 801 GuidString = SacAllocatePool(0x50, GLOBAL_BLOCK_TAG); 802 if (!GuidString) 803 { 804 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (31).\n"); 805 goto Fail; 806 } 807 808 /* Build the string with the GUID in it, and save the ppointer to it */ 809 swprintf(GuidString, 810 L"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 811 SystemGuid.Data1, 812 SystemGuid.Data2, 813 SystemGuid.Data3, 814 SystemGuid.Data4[0], 815 SystemGuid.Data4[1], 816 SystemGuid.Data4[2], 817 SystemGuid.Data4[3], 818 SystemGuid.Data4[4], 819 SystemGuid.Data4[5], 820 SystemGuid.Data4[6], 821 SystemGuid.Data4[7]); 822 MachineInformation->MachineGuid = GuidString; 823 } 824 825 /* Next, query the processor architecture */ 826 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\" 827 L"CurrentControlSet\\Control\\" 828 L"Session Manager\\Environment", 829 L"PROCESSOR_ARCHITECTURE", 830 &PartialInfo); 831 if (!NT_SUCCESS(Status)) 832 { 833 /* It's not critical, but we won't have it */ 834 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n"); 835 } 836 else 837 { 838 /* We have it! Copy the value from the registry */ 839 Status = CopyRegistryValueData((PVOID*)&MachineInformation-> 840 ProcessorArchitecture, 841 PartialInfo); 842 SacFreePool(PartialInfo); 843 if (!NT_SUCCESS(Status)) 844 { 845 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n"); 846 goto Fail; 847 } 848 } 849 850 /* Now allocate a buffer for the OS version number */ 851 MajorVersion = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG); 852 if (!MajorVersion) 853 { 854 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (50).\n"); 855 goto Fail; 856 } 857 858 /* Build the buffer and set a pointer to it */ 859 swprintf(MajorVersion, 860 L"%d.%d", 861 VersionInformation.dwMajorVersion, 862 VersionInformation.dwMinorVersion); 863 MachineInformation->MajorVersion = MajorVersion; 864 865 /* Now allocate a buffer for the OS build number */ 866 BuildNumber = SacAllocatePool(0xC, GLOBAL_BLOCK_TAG); 867 if (!BuildNumber) 868 { 869 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (60).\n"); 870 goto Fail; 871 } 872 873 /* Build the buffer and set a pointer to it */ 874 swprintf(BuildNumber, L"%d", VersionInformation.dwBuildNumber); 875 MachineInformation->BuildNumber = BuildNumber; 876 877 /* Now check what kind of SKU this is */ 878 if (ExVerifySuite(DataCenter)) 879 { 880 SuiteTypeMessage = SAC_DATACENTER_SUITE_MSG; 881 } 882 else if (ExVerifySuite(EmbeddedNT)) 883 { 884 SuiteTypeMessage = SAC_EMBEDDED_SUITE_MSG; 885 } 886 else if (ExVerifySuite(Enterprise)) 887 { 888 SuiteTypeMessage = SAC_ENTERPRISE_SUITE_MSG; 889 } 890 else 891 { 892 /* Unknown or perhaps a client SKU */ 893 SuiteTypeMessage = SAC_NO_SUITE_MSG; 894 } 895 896 /* Get the string that corresponds to the SKU type */ 897 MessageBuffer = GetMessage(SuiteTypeMessage); 898 if (!MessageBuffer) 899 { 900 /* We won't have it, but this isn't critical */ 901 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed to get product type.\n"); 902 } 903 else 904 { 905 /* Calculate the size we need to hold the string */ 906 Size = wcslen(MessageBuffer); 907 ASSERT(Size > 0); 908 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL); 909 910 /* Allocate a buffer for it */ 911 ProductType = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG); 912 if (!ProductType) 913 { 914 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed product type memory allocation.\n"); 915 goto Fail; 916 } 917 918 /* Copy the string and set the pointer */ 919 RtlCopyMemory(ProductType, MessageBuffer, RealSize); 920 MachineInformation->ProductType = ProductType; 921 } 922 923 /* Check if this is a SP version or RTM version */ 924 if (VersionInformation.wServicePackMajor) 925 { 926 /* This is a service pack, allocate a buffer for the version */ 927 ServicePack = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG); 928 if (ServicePack) 929 { 930 /* Build the buffer and set a pointer to it */ 931 swprintf(ServicePack, 932 L"%d.%d", 933 VersionInformation.wServicePackMajor, 934 VersionInformation.wServicePackMinor); 935 MachineInformation->ServicePack = ServicePack; 936 937 /* We've collected all the machine info and are done! */ 938 return; 939 } 940 941 /* This is the failure path */ 942 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n"); 943 } 944 else 945 { 946 /* Get a generic string that indicates there's no service pack */ 947 MessageBuffer = GetMessage(SAC_NO_DATA_MSG); 948 Size = wcslen(MessageBuffer); 949 ASSERT(Size > 0); 950 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL); 951 952 /* Allocate memory for the "no service pack" string */ 953 ServicePack = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG); 954 if (ServicePack) 955 { 956 /* Copy the buffer and set a pointer to it */ 957 RtlCopyMemory(ServicePack, MessageBuffer, RealSize); 958 MachineInformation->ServicePack = ServicePack; 959 960 /* We've collected all the machine info and are done! */ 961 return; 962 } 963 964 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n"); 965 } 966 967 Fail: 968 /* In the failure path, always cleanup the machine information buffer */ 969 if (MachineInformation) 970 { 971 SacFreePool(MachineInformation); 972 } 973 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Exiting with error.\n"); 974 } 975 976 NTSTATUS 977 NTAPI 978 GetCommandConsoleLaunchingPermission(OUT PBOOLEAN Permission) 979 { 980 NTSTATUS Status; 981 PKEY_VALUE_PARTIAL_INFORMATION Dummy; 982 983 /* Assume success and read the key */ 984 *Permission = TRUE; 985 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacdrv", 986 L"DisableCmdSessions", 987 &Dummy); 988 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 989 { 990 /* The default is success */ 991 Status = STATUS_SUCCESS; 992 } 993 else 994 { 995 /* Only if the key is present and set, do we disable permission */ 996 if (NT_SUCCESS(Status)) *Permission = FALSE; 997 } 998 999 /* Return status */ 1000 return Status; 1001 } 1002 1003 NTSTATUS 1004 NTAPI 1005 ImposeSacCmdServiceStartTypePolicy(VOID) 1006 { 1007 NTSTATUS Status; 1008 PKEY_VALUE_PARTIAL_INFORMATION Buffer = NULL; 1009 PULONG Data; 1010 1011 /* Read the service start type*/ 1012 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr", 1013 L"Start", 1014 &Buffer); 1015 if (!NT_SUCCESS(Status)) return Status; 1016 1017 /* If there's no start type, fail, as this is unusual */ 1018 if (!Buffer) return STATUS_UNSUCCESSFUL; 1019 1020 /* Read the value */ 1021 Status = CopyRegistryValueData((PVOID*)&Data, Buffer); 1022 SacFreePool(Buffer); 1023 if (!NT_SUCCESS(Status)) return Status; 1024 1025 /* Check what the current start type is */ 1026 switch (*Data) 1027 { 1028 /* It's boot, system, or disabled */ 1029 case 1: 1030 case 2: 1031 case 4: 1032 /* Leave it as is */ 1033 return Status; 1034 1035 case 3: 1036 1037 /* It's set to automatic, set it to system instead */ 1038 *Data = 2; 1039 Status = SetRegistryValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr", 1040 L"Start", 1041 REG_DWORD, 1042 Data, 1043 sizeof(ULONG)); 1044 if (!NT_SUCCESS(Status)) 1045 { 1046 SAC_DBG(SAC_DBG_INIT, "SAC ImposeSacCmdServiceStartTypePolicy: Failed SetRegistryValue: %X\n", Status); 1047 } 1048 break; 1049 1050 default: 1051 ASSERT(FALSE); 1052 } 1053 1054 return Status; 1055 } 1056 1057 VOID 1058 NTAPI 1059 InitializeCmdEventInfo(VOID) 1060 { 1061 /* Check if we were already initialized */ 1062 if (HaveUserModeServiceCmdEventInfo) 1063 { 1064 /* Full state expected */ 1065 ASSERT(RequestSacCmdEventObjectBody); 1066 ASSERT(RequestSacCmdSuccessEventObjectBody); 1067 ASSERT(RequestSacCmdFailureEventObjectBody); 1068 1069 /* Dereference each wait object in turn */ 1070 if (RequestSacCmdEventObjectBody) 1071 { 1072 ObDereferenceObject(RequestSacCmdEventObjectBody); 1073 } 1074 1075 if (RequestSacCmdSuccessEventObjectBody) 1076 { 1077 ObDereferenceObject(RequestSacCmdSuccessEventObjectBody); 1078 } 1079 1080 if (RequestSacCmdFailureEventObjectBody) 1081 { 1082 ObDereferenceObject(RequestSacCmdFailureEventObjectBody); 1083 } 1084 } 1085 1086 /* Claer everything */ 1087 RequestSacCmdEventObjectBody = NULL; 1088 RequestSacCmdEventWaitObjectBody = NULL; 1089 RequestSacCmdSuccessEventObjectBody = NULL; 1090 RequestSacCmdSuccessEventWaitObjectBody = NULL; 1091 RequestSacCmdFailureEventObjectBody = NULL; 1092 RequestSacCmdFailureEventWaitObjectBody = NULL; 1093 ServiceProcessFileObject = NULL; 1094 1095 /* Reset state */ 1096 HaveUserModeServiceCmdEventInfo = FALSE; 1097 } 1098 1099 NTSTATUS 1100 NTAPI 1101 RegisterBlueScreenMachineInformation(VOID) 1102 { 1103 PWCHAR XmlBuffer; 1104 PHEADLESS_CMD_SET_BLUE_SCREEN_DATA BsBuffer; 1105 SIZE_T Length, HeaderLength, TotalLength; 1106 NTSTATUS Status; 1107 ULONG i; 1108 1109 /* Create the XML buffer and make sure it's OK */ 1110 Status = TranslateMachineInformationXML(&XmlBuffer, NULL); 1111 CHECK_PARAMETER_WITH_STATUS(NT_SUCCESS(Status), Status); 1112 CHECK_PARAMETER_WITH_STATUS(XmlBuffer, STATUS_UNSUCCESSFUL); 1113 1114 /* Compute the sizes and allocate a buffer for it */ 1115 Length = wcslen(XmlBuffer); 1116 HeaderLength = strlen("MACHINEINFO"); 1117 TotalLength = HeaderLength + 1118 Length + 1119 sizeof(*BsBuffer) + 1120 2 * sizeof(ANSI_NULL); 1121 BsBuffer = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG); 1122 CHECK_PARAMETER_WITH_STATUS(BsBuffer, STATUS_NO_MEMORY); 1123 1124 /* Copy the XML property name */ 1125 strcpy((PCHAR)BsBuffer->Data, "MACHINEINFO"); 1126 BsBuffer->ValueIndex = HeaderLength + sizeof(ANSI_NULL); 1127 1128 /* Copy the data and NULL-terminate it */ 1129 for (i = 0; i < Length; i++) 1130 { 1131 BsBuffer->Data[BsBuffer->ValueIndex + i] = XmlBuffer[i]; 1132 } 1133 BsBuffer->Data[BsBuffer->ValueIndex + i] = ANSI_NULL; 1134 1135 /* Let the OS save the buffer for later */ 1136 Status = HeadlessDispatch(HeadlessCmdSetBlueScreenData, 1137 BsBuffer, 1138 TotalLength, 1139 NULL, 1140 NULL); 1141 1142 /* Failure or not, we don't need this anymore */ 1143 SacFreePool(BsBuffer); 1144 SacFreePool(XmlBuffer); 1145 1146 /* Return the result */ 1147 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information: Exiting.\n"); 1148 return Status; 1149 } 1150 1151 VOID 1152 NTAPI 1153 FreeMachineInformation(VOID) 1154 { 1155 ASSERT(MachineInformation); 1156 1157 /* Free every cached string of machine information */ 1158 if (MachineInformation->MachineName) SacFreePool(MachineInformation); 1159 if (MachineInformation->MachineGuid) SacFreePool(MachineInformation->MachineGuid); 1160 if (MachineInformation->ProcessorArchitecture) SacFreePool(MachineInformation->ProcessorArchitecture); 1161 if (MachineInformation->MajorVersion) SacFreePool(MachineInformation->MajorVersion); 1162 if (MachineInformation->BuildNumber) SacFreePool(MachineInformation->BuildNumber); 1163 if (MachineInformation->ProductType) SacFreePool(MachineInformation->ProductType); 1164 if (MachineInformation->ServicePack) SacFreePool(MachineInformation->ServicePack); 1165 } 1166 1167 BOOLEAN 1168 NTAPI 1169 VerifyEventWaitable(IN HANDLE Handle, 1170 OUT PVOID *WaitObject, 1171 OUT PVOID *ActualWaitObject) 1172 { 1173 PVOID Object; 1174 NTSTATUS Status; 1175 POBJECT_TYPE ObjectType; 1176 1177 /* Reference the object */ 1178 Status = ObReferenceObjectByHandle(Handle, 1179 EVENT_ALL_ACCESS, 1180 NULL, 1181 KernelMode, 1182 &Object, 1183 NULL); 1184 *WaitObject = Object; 1185 if (!NT_SUCCESS(Status)) 1186 { 1187 SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: Unable to reference event object (%lx)\n", Status); 1188 return FALSE; 1189 } 1190 1191 /* Check if the object itself is NOT being used */ 1192 ObjectType = OBJECT_TO_OBJECT_HEADER(Object)->Type; 1193 if (ObjectType->TypeInfo.UseDefaultObject == FALSE) 1194 { 1195 /* Get the actual object that's being used for the wait */ 1196 *ActualWaitObject = (PVOID)((ULONG_PTR)Object + 1197 (ULONG_PTR)ObjectType->DefaultObject); 1198 return TRUE; 1199 } 1200 1201 /* Drop the reference we took */ 1202 SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: event object not waitable!\n"); 1203 ObDereferenceObject(*WaitObject); 1204 return FALSE; 1205 } 1206 1207 NTSTATUS 1208 NTAPI 1209 SerialBufferGetChar(OUT PCHAR Char) 1210 { 1211 /* Check if nothing's been produced yet */ 1212 if (SerialPortConsumerIndex == SerialPortProducerIndex) 1213 { 1214 return STATUS_NO_DATA_DETECTED; 1215 } 1216 1217 /* Consume the produced character and clear it*/ 1218 *Char = SerialPortBuffer[SerialPortConsumerIndex]; 1219 SerialPortBuffer[SerialPortConsumerIndex] = ANSI_NULL; 1220 1221 /* Advance the index and return success */ 1222 _InterlockedExchange(&SerialPortConsumerIndex, 1223 (SerialPortConsumerIndex + 1) & 1224 (SAC_SERIAL_PORT_BUFFER_SIZE - 1)); 1225 return STATUS_SUCCESS; 1226 } 1227 1228 ULONG 1229 NTAPI 1230 GetMessageLineCount(IN ULONG MessageIndex) 1231 { 1232 ULONG LineCount = 0; 1233 PWCHAR Buffer; 1234 1235 /* Get the message buffer */ 1236 Buffer = GetMessage(MessageIndex); 1237 if (Buffer) 1238 { 1239 /* Scan it looking for new lines, and increment the count each time */ 1240 while (*Buffer) if (*Buffer++ == L'\n') ++LineCount; 1241 } 1242 1243 /* Return the line count */ 1244 return LineCount; 1245 } 1246 1247 ULONG 1248 ConvertAnsiToUnicode( 1249 IN PWCHAR pwch, 1250 IN PCHAR pch, 1251 IN ULONG length 1252 ) 1253 { 1254 return STATUS_NOT_IMPLEMENTED; 1255 } 1256 1257 BOOLEAN 1258 IsCmdEventRegistrationProcess( 1259 IN PFILE_OBJECT FileObject 1260 ) 1261 { 1262 return FALSE; 1263 } 1264 1265 NTSTATUS 1266 InvokeUserModeService( 1267 VOID 1268 ) 1269 { 1270 return STATUS_NOT_IMPLEMENTED; 1271 } 1272 1273 NTSTATUS 1274 TranslateMachineInformationText( 1275 IN PWCHAR Buffer) 1276 { 1277 return STATUS_NOT_IMPLEMENTED; 1278 } 1279 1280 NTSTATUS 1281 CopyAndInsertStringAtInterval( 1282 IN PWCHAR SourceStr, 1283 IN ULONG Interval, 1284 IN PWCHAR InsertStr, 1285 OUT PWCHAR pDestStr 1286 ) 1287 { 1288 return STATUS_NOT_IMPLEMENTED; 1289 } 1290 1291 NTSTATUS 1292 RegisterSacCmdEvent( 1293 IN PVOID Object, 1294 IN PKEVENT SetupCmdEvent[] 1295 ) 1296 { 1297 return STATUS_NOT_IMPLEMENTED; 1298 } 1299 1300 NTSTATUS 1301 UnregisterSacCmdEvent( 1302 IN PFILE_OBJECT FileObject 1303 ) 1304 { 1305 return STATUS_NOT_IMPLEMENTED; 1306 } 1307