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 | OBJ_KERNEL_HANDLE, 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) 431 goto Quit; 432 433 /* Allocate the buffer for the partial info structure and our integer data */ 434 ResultLength += sizeof(ULONG); 435 *Buffer = SacAllocatePool(ResultLength, GLOBAL_BLOCK_TAG); 436 if (!*Buffer) 437 { 438 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed allocation\n"); 439 goto Quit; 440 } 441 442 /* Now read the data */ 443 Status = ZwQueryValueKey(Handle, 444 &DestinationString, 445 KeyValuePartialInformation, 446 *Buffer, 447 ResultLength, 448 &ResultLength); 449 if (!NT_SUCCESS(Status)) 450 { 451 /* Free the buffer if we couldn't read the data */ 452 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwQueryValueKey: %X.\n", Status); 453 SacFreePool(*Buffer); 454 } 455 456 Quit: 457 /* Close the handle and exit */ 458 ZwClose(Handle); 459 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: Exiting.\n"); 460 return Status; 461 } 462 463 NTSTATUS 464 NTAPI 465 SetRegistryValue(IN PCWSTR KeyName, 466 IN PWCHAR ValueName, 467 IN ULONG Type, 468 IN PVOID Data, 469 IN ULONG DataSize) 470 { 471 NTSTATUS Status; 472 OBJECT_ATTRIBUTES ObjectAttributes; 473 UNICODE_STRING DestinationString; 474 HANDLE Handle; 475 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Entering.\n"); 476 CHECK_PARAMETER1(KeyName); 477 CHECK_PARAMETER2(ValueName); 478 CHECK_PARAMETER4(Data); 479 480 /* Open the specified key */ 481 RtlInitUnicodeString(&DestinationString, KeyName); 482 InitializeObjectAttributes(&ObjectAttributes, 483 &DestinationString, 484 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 485 NULL, 486 NULL); 487 Status = ZwOpenKey(&Handle, 488 KEY_WRITE | SYNCHRONIZE | KEY_READ, 489 &ObjectAttributes); 490 if (!NT_SUCCESS(Status)) 491 { 492 /* Bail out on failure */ 493 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwOpenKey: %X.\n", Status); 494 return Status; 495 } 496 497 /* Set the specified value */ 498 RtlInitUnicodeString(&DestinationString, ValueName); 499 Status = ZwSetValueKey(Handle, &DestinationString, 0, Type, Data, DataSize); 500 if (!NT_SUCCESS(Status)) 501 { 502 /* Print error on failure */ 503 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwSetValueKey: %X.\n", Status); 504 } 505 506 /* Close the handle and exit */ 507 ZwClose(Handle); 508 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n"); 509 return Status; 510 } 511 512 NTSTATUS 513 NTAPI 514 CopyRegistryValueData(IN PVOID* Buffer, 515 IN PKEY_VALUE_PARTIAL_INFORMATION PartialInfo) 516 { 517 NTSTATUS Status = STATUS_SUCCESS; 518 CHECK_PARAMETER1(Buffer); 519 CHECK_PARAMETER2(PartialInfo); 520 521 /* Allocate space for registry data */ 522 *Buffer = SacAllocatePool(PartialInfo->DataLength, GLOBAL_BLOCK_TAG); 523 if (*Buffer) 524 { 525 /* Copy the data into the buffer */ 526 RtlCopyMemory(*Buffer, PartialInfo->Data, PartialInfo->DataLength); 527 } 528 else 529 { 530 /* Set the correct error code */ 531 SAC_DBG(SAC_DBG_UTIL, "SAC CopyRegistryValueBuffer: Failed ALLOCATE.\n"); 532 Status = STATUS_NO_MEMORY; 533 } 534 535 /* Return the result */ 536 return Status; 537 } 538 539 NTSTATUS 540 NTAPI 541 TranslateMachineInformationXML(IN PWCHAR *Buffer, 542 IN PWCHAR ExtraData) 543 { 544 NTSTATUS Status; 545 SIZE_T Size; 546 PWCHAR p; 547 CHECK_PARAMETER1(Buffer); 548 549 /* Start by believing the world is beautiful */ 550 Status = STATUS_SUCCESS; 551 552 /* First, the header */ 553 Size = wcslen(L"<machine-info>\r\n"); 554 555 /* Do we have a machine name? */ 556 if (MachineInformation->MachineName) 557 { 558 /* Go and add it in */ 559 Size += wcslen(MachineInformation->MachineName); 560 Size += wcslen(L"<name>%s</name>\r\n"); 561 } 562 563 /* Do we have a GUID? */ 564 if (MachineInformation->MachineGuid) 565 { 566 /* Go and add it in */ 567 Size += wcslen(MachineInformation->MachineGuid); 568 Size += wcslen(L"<guid>%s</guid>\r\n"); 569 } 570 571 /* Do we know the processor? */ 572 if (MachineInformation->ProcessorArchitecture) 573 { 574 /* Go and add it in */ 575 Size += wcslen(MachineInformation->ProcessorArchitecture); 576 Size += wcslen(L"<processor-architecture>%s</processor-architecture>\r\n"); 577 } 578 579 /* Do we have the version? */ 580 if (MachineInformation->MajorVersion) 581 { 582 /* Go and add it in */ 583 Size += wcslen(MachineInformation->MajorVersion); 584 Size += wcslen(L"<os-version>%s</os-version>\r\n"); 585 } 586 587 /* Do we have the build? */ 588 if (MachineInformation->BuildNumber) 589 { 590 /* Go and add it in */ 591 Size += wcslen(MachineInformation->BuildNumber); 592 Size += wcslen(L"<os-build-number>%s</os-build-number>\r\n"); 593 } 594 595 /* Do we have the product type? */ 596 if (MachineInformation->ProductType) 597 { 598 /* Go and add it in */ 599 Size += wcslen(MachineInformation->ProductType); 600 Size += wcslen(L"<os-product>%s</os-product>\r\n"); 601 } 602 603 /* Do we have a service pack? */ 604 if (MachineInformation->ServicePack) 605 { 606 /* Go and add it in */ 607 Size += wcslen(MachineInformation->ServicePack); 608 Size += wcslen(L"<os-service-pack>%s</os-service-pack>\r\n"); 609 } 610 611 /* Anything else we need to know? Add it in too */ 612 if (ExtraData) Size += wcslen(ExtraData); 613 614 /* Finally, add the footer */ 615 Size += wcslen(L"</machine-info>\r\n"); 616 617 /* Convert to bytes and add a NULL */ 618 Size += sizeof(ANSI_NULL); 619 Size *= sizeof(WCHAR); 620 621 /* Allocate space for the buffer */ 622 p = SacAllocatePool(Size, GLOBAL_BLOCK_TAG); 623 *Buffer = p; 624 if (!p) return STATUS_NO_MEMORY; 625 626 wcscpy(p, L"<machine-info>\r\n"); 627 p += wcslen(L"<machine-info>\r\n"); 628 629 if (MachineInformation->MachineName) 630 { 631 p += swprintf(p, 632 L"<name>%s</name>\r\n", 633 MachineInformation->MachineName); 634 } 635 636 if (MachineInformation->MachineGuid) 637 { 638 p += swprintf(p, 639 L"<guid>%s</guid>\r\n", 640 MachineInformation->MachineGuid); 641 } 642 643 if (MachineInformation->ProcessorArchitecture) 644 { 645 p += swprintf(p, 646 L"<processor-architecture>%s</processor-architecture>\r\n", 647 MachineInformation->ProcessorArchitecture); 648 } 649 650 if (MachineInformation->MajorVersion) 651 { 652 p += swprintf(p, 653 L"<os-version>%s</os-version>\r\n", 654 MachineInformation->MajorVersion); 655 } 656 657 if (MachineInformation->BuildNumber) 658 { 659 p += swprintf(p, 660 L"<os-build-number>%s</os-build-number>\r\n", 661 MachineInformation->BuildNumber); 662 } 663 664 if (MachineInformation->ProductType) 665 { 666 p += swprintf(p, 667 L"<os-product>%s</os-product>\r\n", 668 MachineInformation->ProductType); 669 } 670 671 if (MachineInformation->ServicePack) 672 { 673 p += swprintf(p, 674 L"<os-service-pack>%s</os-service-pack>\r\n", 675 MachineInformation->ServicePack); 676 } 677 678 if (ExtraData) 679 { 680 wcscpy(p, ExtraData); 681 p += wcslen(ExtraData); 682 } 683 684 wcscpy(p, L"</machine-info>\r\n"); 685 SAC_DBG(SAC_DBG_ENTRY_EXIT, "MachineInformation: %S\n", *Buffer); 686 ASSERT((((ULONG)wcslen(*Buffer) + 1) * sizeof(WCHAR)) <= Size); 687 return Status; 688 } 689 690 VOID 691 NTAPI 692 InitializeMachineInformation(VOID) 693 { 694 NTSTATUS Status; 695 PWCHAR GuidString, MajorVersion, ServicePack, BuildNumber, MessageBuffer; 696 PWCHAR ProductType; 697 ULONG SuiteTypeMessage; 698 BOOLEAN SetupInProgress = FALSE; 699 GUID SystemGuid; 700 SIZE_T RealSize, Size, OutputSize; 701 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; 702 RTL_OSVERSIONINFOEXW VersionInformation; 703 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Entering.\n"); 704 705 /* Don't do anything if we already queried this */ 706 if (MachineInformation) 707 { 708 SAC_DBG(SAC_DBG_MACHINE, "SAC Initialize Machine Information:: MachineInformationBuffer already initialized.\n"); 709 return; 710 } 711 712 /* Allocate the machine information */ 713 MachineInformation = SacAllocatePool(sizeof(*MachineInformation), 714 GLOBAL_BLOCK_TAG); 715 if (!MachineInformation) 716 { 717 goto Fail; 718 } 719 720 /* Zero it out for now */ 721 RtlZeroMemory(MachineInformation, sizeof(*MachineInformation)); 722 723 /* Query OS version */ 724 RtlZeroMemory(&VersionInformation, sizeof(VersionInformation)); 725 VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation); 726 Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&VersionInformation); 727 if (!NT_SUCCESS(Status)) 728 { 729 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (2).\n"); 730 goto Fail; 731 } 732 733 /* Check if setup is in progress */ 734 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\Setup", 735 L"SystemSetupInProgress", 736 &PartialInfo); 737 if (NT_SUCCESS(Status)) 738 { 739 /* The key is there, is the value set? */ 740 if (*(PULONG)PartialInfo->Data) SetupInProgress = TRUE; 741 SacFreePool(PartialInfo); 742 if (SetupInProgress) 743 { 744 /* Yes, so we'll use a special hostname to identify this */ 745 MessageBuffer = GetMessage(SAC_UNINITIALIZED_MSG); 746 Size = wcslen(MessageBuffer); 747 ASSERT(Size > 0); 748 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL); 749 750 /* Make room for it and copy it in there */ 751 MachineInformation->MachineName = SacAllocatePool(RealSize, 752 GLOBAL_BLOCK_TAG); 753 if (MachineInformation->MachineName) 754 { 755 wcscpy(MachineInformation->MachineName, MessageBuffer); 756 } 757 } 758 } 759 760 /* If we are not in setup mode, or if we failed to check... */ 761 if (!SetupInProgress) 762 { 763 /* Query the computer name */ 764 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\" 765 L"CurrentControlSet\\Control\\" 766 L"ComputerName\\ComputerName", 767 L"ComputerName", 768 &PartialInfo); 769 if (!NT_SUCCESS(Status)) 770 { 771 /* It's not critical, but we won't have it */ 772 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get machine name.\n"); 773 } 774 else 775 { 776 /* We have the name, copy it from the registry */ 777 Status = CopyRegistryValueData((PVOID*)&MachineInformation-> 778 MachineName, 779 PartialInfo); 780 SacFreePool(PartialInfo); 781 if (!NT_SUCCESS(Status)) 782 { 783 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (20).\n"); 784 goto Fail; 785 } 786 } 787 } 788 789 /* Next step, try to get the machine GUID */ 790 RtlZeroMemory(&SystemGuid, sizeof(SystemGuid)); 791 OutputSize = sizeof(SystemGuid); 792 Status = HeadlessDispatch(HeadlessCmdQueryGUID, 793 NULL, 794 0, 795 &SystemGuid, 796 &OutputSize); 797 if (!NT_SUCCESS(Status)) 798 { 799 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get Machine GUID.\n"); 800 } 801 else 802 { 803 /* We have it -- make room for it */ 804 GuidString = SacAllocatePool(0x50, GLOBAL_BLOCK_TAG); 805 if (!GuidString) 806 { 807 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (31).\n"); 808 goto Fail; 809 } 810 811 /* Build the string with the GUID in it, and save the ppointer to it */ 812 swprintf(GuidString, 813 L"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 814 SystemGuid.Data1, 815 SystemGuid.Data2, 816 SystemGuid.Data3, 817 SystemGuid.Data4[0], 818 SystemGuid.Data4[1], 819 SystemGuid.Data4[2], 820 SystemGuid.Data4[3], 821 SystemGuid.Data4[4], 822 SystemGuid.Data4[5], 823 SystemGuid.Data4[6], 824 SystemGuid.Data4[7]); 825 MachineInformation->MachineGuid = GuidString; 826 } 827 828 /* Next, query the processor architecture */ 829 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\" 830 L"CurrentControlSet\\Control\\" 831 L"Session Manager\\Environment", 832 L"PROCESSOR_ARCHITECTURE", 833 &PartialInfo); 834 if (!NT_SUCCESS(Status)) 835 { 836 /* It's not critical, but we won't have it */ 837 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n"); 838 } 839 else 840 { 841 /* We have it! Copy the value from the registry */ 842 Status = CopyRegistryValueData((PVOID*)&MachineInformation-> 843 ProcessorArchitecture, 844 PartialInfo); 845 SacFreePool(PartialInfo); 846 if (!NT_SUCCESS(Status)) 847 { 848 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n"); 849 goto Fail; 850 } 851 } 852 853 /* Now allocate a buffer for the OS version number */ 854 MajorVersion = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG); 855 if (!MajorVersion) 856 { 857 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (50).\n"); 858 goto Fail; 859 } 860 861 /* Build the buffer and set a pointer to it */ 862 swprintf(MajorVersion, 863 L"%d.%d", 864 VersionInformation.dwMajorVersion, 865 VersionInformation.dwMinorVersion); 866 MachineInformation->MajorVersion = MajorVersion; 867 868 /* Now allocate a buffer for the OS build number */ 869 BuildNumber = SacAllocatePool(0xC, GLOBAL_BLOCK_TAG); 870 if (!BuildNumber) 871 { 872 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (60).\n"); 873 goto Fail; 874 } 875 876 /* Build the buffer and set a pointer to it */ 877 swprintf(BuildNumber, L"%d", VersionInformation.dwBuildNumber); 878 MachineInformation->BuildNumber = BuildNumber; 879 880 /* Now check what kind of SKU this is */ 881 if (ExVerifySuite(DataCenter)) 882 { 883 SuiteTypeMessage = SAC_DATACENTER_SUITE_MSG; 884 } 885 else if (ExVerifySuite(EmbeddedNT)) 886 { 887 SuiteTypeMessage = SAC_EMBEDDED_SUITE_MSG; 888 } 889 else if (ExVerifySuite(Enterprise)) 890 { 891 SuiteTypeMessage = SAC_ENTERPRISE_SUITE_MSG; 892 } 893 else 894 { 895 /* Unknown or perhaps a client SKU */ 896 SuiteTypeMessage = SAC_NO_SUITE_MSG; 897 } 898 899 /* Get the string that corresponds to the SKU type */ 900 MessageBuffer = GetMessage(SuiteTypeMessage); 901 if (!MessageBuffer) 902 { 903 /* We won't have it, but this isn't critical */ 904 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed to get product type.\n"); 905 } 906 else 907 { 908 /* Calculate the size we need to hold the string */ 909 Size = wcslen(MessageBuffer); 910 ASSERT(Size > 0); 911 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL); 912 913 /* Allocate a buffer for it */ 914 ProductType = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG); 915 if (!ProductType) 916 { 917 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed product type memory allocation.\n"); 918 goto Fail; 919 } 920 921 /* Copy the string and set the pointer */ 922 RtlCopyMemory(ProductType, MessageBuffer, RealSize); 923 MachineInformation->ProductType = ProductType; 924 } 925 926 /* Check if this is a SP version or RTM version */ 927 if (VersionInformation.wServicePackMajor) 928 { 929 /* This is a service pack, allocate a buffer for the version */ 930 ServicePack = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG); 931 if (ServicePack) 932 { 933 /* Build the buffer and set a pointer to it */ 934 swprintf(ServicePack, 935 L"%d.%d", 936 VersionInformation.wServicePackMajor, 937 VersionInformation.wServicePackMinor); 938 MachineInformation->ServicePack = ServicePack; 939 940 /* We've collected all the machine info and are done! */ 941 return; 942 } 943 944 /* This is the failure path */ 945 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n"); 946 } 947 else 948 { 949 /* Get a generic string that indicates there's no service pack */ 950 MessageBuffer = GetMessage(SAC_NO_DATA_MSG); 951 Size = wcslen(MessageBuffer); 952 ASSERT(Size > 0); 953 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL); 954 955 /* Allocate memory for the "no service pack" string */ 956 ServicePack = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG); 957 if (ServicePack) 958 { 959 /* Copy the buffer and set a pointer to it */ 960 RtlCopyMemory(ServicePack, MessageBuffer, RealSize); 961 MachineInformation->ServicePack = ServicePack; 962 963 /* We've collected all the machine info and are done! */ 964 return; 965 } 966 967 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n"); 968 } 969 970 Fail: 971 /* In the failure path, always cleanup the machine information buffer */ 972 if (MachineInformation) 973 { 974 SacFreePool(MachineInformation); 975 } 976 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Exiting with error.\n"); 977 } 978 979 NTSTATUS 980 NTAPI 981 GetCommandConsoleLaunchingPermission(OUT PBOOLEAN Permission) 982 { 983 NTSTATUS Status; 984 PKEY_VALUE_PARTIAL_INFORMATION Dummy; 985 986 /* Assume success and read the key */ 987 *Permission = TRUE; 988 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacdrv", 989 L"DisableCmdSessions", 990 &Dummy); 991 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 992 { 993 /* The default is success */ 994 Status = STATUS_SUCCESS; 995 } 996 else 997 { 998 /* Only if the key is present and set, do we disable permission */ 999 if (NT_SUCCESS(Status)) *Permission = FALSE; 1000 } 1001 1002 /* Return status */ 1003 return Status; 1004 } 1005 1006 NTSTATUS 1007 NTAPI 1008 ImposeSacCmdServiceStartTypePolicy(VOID) 1009 { 1010 NTSTATUS Status; 1011 PKEY_VALUE_PARTIAL_INFORMATION Buffer = NULL; 1012 PULONG Data; 1013 1014 /* Read the service start type*/ 1015 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr", 1016 L"Start", 1017 &Buffer); 1018 if (!NT_SUCCESS(Status)) return Status; 1019 1020 /* If there's no start type, fail, as this is unusual */ 1021 if (!Buffer) return STATUS_UNSUCCESSFUL; 1022 1023 /* Read the value */ 1024 Status = CopyRegistryValueData((PVOID*)&Data, Buffer); 1025 SacFreePool(Buffer); 1026 if (!NT_SUCCESS(Status)) return Status; 1027 1028 /* Check what the current start type is */ 1029 switch (*Data) 1030 { 1031 /* It's boot, system, or disabled */ 1032 case 1: 1033 case 2: 1034 case 4: 1035 /* Leave it as is */ 1036 return Status; 1037 1038 case 3: 1039 1040 /* It's set to automatic, set it to system instead */ 1041 *Data = 2; 1042 Status = SetRegistryValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr", 1043 L"Start", 1044 REG_DWORD, 1045 Data, 1046 sizeof(ULONG)); 1047 if (!NT_SUCCESS(Status)) 1048 { 1049 SAC_DBG(SAC_DBG_INIT, "SAC ImposeSacCmdServiceStartTypePolicy: Failed SetRegistryValue: %X\n", Status); 1050 } 1051 break; 1052 1053 default: 1054 ASSERT(FALSE); 1055 } 1056 1057 return Status; 1058 } 1059 1060 VOID 1061 NTAPI 1062 InitializeCmdEventInfo(VOID) 1063 { 1064 /* Check if we were already initialized */ 1065 if (HaveUserModeServiceCmdEventInfo) 1066 { 1067 /* Full state expected */ 1068 ASSERT(RequestSacCmdEventObjectBody); 1069 ASSERT(RequestSacCmdSuccessEventObjectBody); 1070 ASSERT(RequestSacCmdFailureEventObjectBody); 1071 1072 /* Dereference each wait object in turn */ 1073 if (RequestSacCmdEventObjectBody) 1074 { 1075 ObDereferenceObject(RequestSacCmdEventObjectBody); 1076 } 1077 1078 if (RequestSacCmdSuccessEventObjectBody) 1079 { 1080 ObDereferenceObject(RequestSacCmdSuccessEventObjectBody); 1081 } 1082 1083 if (RequestSacCmdFailureEventObjectBody) 1084 { 1085 ObDereferenceObject(RequestSacCmdFailureEventObjectBody); 1086 } 1087 } 1088 1089 /* Claer everything */ 1090 RequestSacCmdEventObjectBody = NULL; 1091 RequestSacCmdEventWaitObjectBody = NULL; 1092 RequestSacCmdSuccessEventObjectBody = NULL; 1093 RequestSacCmdSuccessEventWaitObjectBody = NULL; 1094 RequestSacCmdFailureEventObjectBody = NULL; 1095 RequestSacCmdFailureEventWaitObjectBody = NULL; 1096 ServiceProcessFileObject = NULL; 1097 1098 /* Reset state */ 1099 HaveUserModeServiceCmdEventInfo = FALSE; 1100 } 1101 1102 NTSTATUS 1103 NTAPI 1104 RegisterBlueScreenMachineInformation(VOID) 1105 { 1106 PWCHAR XmlBuffer; 1107 PHEADLESS_CMD_SET_BLUE_SCREEN_DATA BsBuffer; 1108 SIZE_T Length, HeaderLength, TotalLength; 1109 NTSTATUS Status; 1110 ULONG i; 1111 1112 /* Create the XML buffer and make sure it's OK */ 1113 Status = TranslateMachineInformationXML(&XmlBuffer, NULL); 1114 CHECK_PARAMETER_WITH_STATUS(NT_SUCCESS(Status), Status); 1115 CHECK_PARAMETER_WITH_STATUS(XmlBuffer, STATUS_UNSUCCESSFUL); 1116 1117 /* Compute the sizes and allocate a buffer for it */ 1118 Length = wcslen(XmlBuffer); 1119 HeaderLength = strlen("MACHINEINFO"); 1120 TotalLength = HeaderLength + 1121 Length + 1122 sizeof(*BsBuffer) + 1123 2 * sizeof(ANSI_NULL); 1124 BsBuffer = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG); 1125 CHECK_PARAMETER_WITH_STATUS(BsBuffer, STATUS_NO_MEMORY); 1126 1127 /* Copy the XML property name */ 1128 strcpy((PCHAR)BsBuffer->Data, "MACHINEINFO"); 1129 BsBuffer->ValueIndex = HeaderLength + sizeof(ANSI_NULL); 1130 1131 /* Copy the data and NULL-terminate it */ 1132 for (i = 0; i < Length; i++) 1133 { 1134 BsBuffer->Data[BsBuffer->ValueIndex + i] = XmlBuffer[i]; 1135 } 1136 BsBuffer->Data[BsBuffer->ValueIndex + i] = ANSI_NULL; 1137 1138 /* Let the OS save the buffer for later */ 1139 Status = HeadlessDispatch(HeadlessCmdSetBlueScreenData, 1140 BsBuffer, 1141 TotalLength, 1142 NULL, 1143 NULL); 1144 1145 /* Failure or not, we don't need this anymore */ 1146 SacFreePool(BsBuffer); 1147 SacFreePool(XmlBuffer); 1148 1149 /* Return the result */ 1150 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information: Exiting.\n"); 1151 return Status; 1152 } 1153 1154 VOID 1155 NTAPI 1156 FreeMachineInformation(VOID) 1157 { 1158 ASSERT(MachineInformation); 1159 1160 /* Free every cached string of machine information */ 1161 if (MachineInformation->MachineName) SacFreePool(MachineInformation); 1162 if (MachineInformation->MachineGuid) SacFreePool(MachineInformation->MachineGuid); 1163 if (MachineInformation->ProcessorArchitecture) SacFreePool(MachineInformation->ProcessorArchitecture); 1164 if (MachineInformation->MajorVersion) SacFreePool(MachineInformation->MajorVersion); 1165 if (MachineInformation->BuildNumber) SacFreePool(MachineInformation->BuildNumber); 1166 if (MachineInformation->ProductType) SacFreePool(MachineInformation->ProductType); 1167 if (MachineInformation->ServicePack) SacFreePool(MachineInformation->ServicePack); 1168 } 1169 1170 BOOLEAN 1171 NTAPI 1172 VerifyEventWaitable(IN HANDLE Handle, 1173 OUT PVOID *WaitObject, 1174 OUT PVOID *ActualWaitObject) 1175 { 1176 PVOID Object; 1177 NTSTATUS Status; 1178 POBJECT_TYPE ObjectType; 1179 1180 /* Reference the object */ 1181 Status = ObReferenceObjectByHandle(Handle, 1182 EVENT_ALL_ACCESS, 1183 NULL, 1184 KernelMode, 1185 &Object, 1186 NULL); 1187 *WaitObject = Object; 1188 if (!NT_SUCCESS(Status)) 1189 { 1190 SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: Unable to reference event object (%lx)\n", Status); 1191 return FALSE; 1192 } 1193 1194 /* Check if the object itself is NOT being used */ 1195 ObjectType = OBJECT_TO_OBJECT_HEADER(Object)->Type; 1196 if (ObjectType->TypeInfo.UseDefaultObject == FALSE) 1197 { 1198 /* Get the actual object that's being used for the wait */ 1199 *ActualWaitObject = (PVOID)((ULONG_PTR)Object + 1200 (ULONG_PTR)ObjectType->DefaultObject); 1201 return TRUE; 1202 } 1203 1204 /* Drop the reference we took */ 1205 SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: event object not waitable!\n"); 1206 ObDereferenceObject(*WaitObject); 1207 return FALSE; 1208 } 1209 1210 NTSTATUS 1211 NTAPI 1212 SerialBufferGetChar(OUT PCHAR Char) 1213 { 1214 /* Check if nothing's been produced yet */ 1215 if (SerialPortConsumerIndex == SerialPortProducerIndex) 1216 { 1217 return STATUS_NO_DATA_DETECTED; 1218 } 1219 1220 /* Consume the produced character and clear it*/ 1221 *Char = SerialPortBuffer[SerialPortConsumerIndex]; 1222 SerialPortBuffer[SerialPortConsumerIndex] = ANSI_NULL; 1223 1224 /* Advance the index and return success */ 1225 _InterlockedExchange(&SerialPortConsumerIndex, 1226 (SerialPortConsumerIndex + 1) & 1227 (SAC_SERIAL_PORT_BUFFER_SIZE - 1)); 1228 return STATUS_SUCCESS; 1229 } 1230 1231 ULONG 1232 NTAPI 1233 GetMessageLineCount(IN ULONG MessageIndex) 1234 { 1235 ULONG LineCount = 0; 1236 PWCHAR Buffer; 1237 1238 /* Get the message buffer */ 1239 Buffer = GetMessage(MessageIndex); 1240 if (Buffer) 1241 { 1242 /* Scan it looking for new lines, and increment the count each time */ 1243 while (*Buffer) if (*Buffer++ == L'\n') ++LineCount; 1244 } 1245 1246 /* Return the line count */ 1247 return LineCount; 1248 } 1249 1250 ULONG 1251 ConvertAnsiToUnicode( 1252 IN PWCHAR pwch, 1253 IN PCHAR pch, 1254 IN ULONG length 1255 ) 1256 { 1257 return STATUS_NOT_IMPLEMENTED; 1258 } 1259 1260 BOOLEAN 1261 IsCmdEventRegistrationProcess( 1262 IN PFILE_OBJECT FileObject 1263 ) 1264 { 1265 return FALSE; 1266 } 1267 1268 NTSTATUS 1269 InvokeUserModeService( 1270 VOID 1271 ) 1272 { 1273 return STATUS_NOT_IMPLEMENTED; 1274 } 1275 1276 NTSTATUS 1277 TranslateMachineInformationText( 1278 IN PWCHAR Buffer) 1279 { 1280 return STATUS_NOT_IMPLEMENTED; 1281 } 1282 1283 NTSTATUS 1284 CopyAndInsertStringAtInterval( 1285 IN PWCHAR SourceStr, 1286 IN ULONG Interval, 1287 IN PWCHAR InsertStr, 1288 OUT PWCHAR pDestStr 1289 ) 1290 { 1291 return STATUS_NOT_IMPLEMENTED; 1292 } 1293 1294 NTSTATUS 1295 RegisterSacCmdEvent( 1296 IN PVOID Object, 1297 IN PKEVENT SetupCmdEvent[] 1298 ) 1299 { 1300 return STATUS_NOT_IMPLEMENTED; 1301 } 1302 1303 NTSTATUS 1304 UnregisterSacCmdEvent( 1305 IN PFILE_OBJECT FileObject 1306 ) 1307 { 1308 return STATUS_NOT_IMPLEMENTED; 1309 } 1310