#include "cmdcons.h" #pragma hdrstop #include #include #include #include static BOOL firstTime = TRUE; static CONST PWSTR gszSoftwareHiveName = L"software"; static CONST PWSTR gszSoftwareHiveKey= L"\\registry\\machine\\xSOFTWARE"; static CONST PWSTR gszSAMHiveName = L"sam"; static CONST PWSTR gszSAMHiveKey = L"\\registry\\machine\\security"; static CONST PWSTR gszSystemHiveName = L"system"; static CONST PWSTR gszSystemHiveKey = L"\\registry\\machine\\xSYSTEM"; static CONST PWSTR gszSecurityHiveName = L"security"; static CONST PWSTR gszSecurityHiveKey = L"\\registry\\machine\\xSECURITY"; LIST_ENTRY NtInstalls; ULONG InstallCount; LIST_ENTRY NtInstallsFullScan; ULONG InstallCountFullScan; PNT_INSTALLATION SelectedInstall; LARGE_INTEGER glBias; #define IS_VALID_INSTALL(x) (((x) > 0) && ((x) <= InstallCount)) typedef struct _KEY_CHECK_STRUCT { WCHAR *szKeyName; BOOLEAN bControlSet; } KEY_CHECK_STRUCT; // // forward declarations // BOOLEAN LoginRequired( VOID ); BOOLEAN RcOpenHive( PWSTR szHiveName, PWSTR szHiveKey ); BOOLEAN RcCloseHive( PWSTR szHiveKey ); BOOLEAN RcIsValidSystemHive( VOID ); BOOLEAN IsSetCommandEnabled( VOID ); BOOLEAN RcDetermineCorrectControlKey( OUT PULONG pCorrectKey ); LARGE_INTEGER RcGetTimeZoneBias( VOID ); VOID RcDestroyList( PLIST_ENTRY ListHead ) { PLIST_ENTRY Entry = ListHead->Flink; if(Entry != NULL) { while(Entry != ListHead) { PLIST_ENTRY Next = Entry->Flink; SpMemFree(Entry); Entry = Next; } } InitializeListHead(ListHead); } BOOL RcLogonDiskRegionEnum( IN PPARTITIONED_DISK Disk, IN PDISK_REGION Region, IN ULONG_PTR UseArcNames ) { WCHAR buf[MAX_PATH]; OBJECT_ATTRIBUTES Obja; HANDLE DirectoryHandle; NTSTATUS Status; UNICODE_STRING UnicodeString; IO_STATUS_BLOCK IoStatusBlock; PFILE_BOTH_DIR_INFORMATION DirectoryInfo; struct SEARCH_BUFFER { FILE_BOTH_DIR_INFORMATION DirInfo; WCHAR Names[MAX_PATH]; } Buffer; UNICODE_STRING FileName; LPWSTR s; PNT_INSTALLATION NtInstall; swprintf( buf, L"\\??\\%c:\\", Region->DriveLetter ); INIT_OBJA( &Obja, &UnicodeString, buf ); Status = ZwOpenFile( &DirectoryHandle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ); if (!NT_SUCCESS(Status)) { return TRUE; } DirectoryInfo = &Buffer.DirInfo; RtlInitUnicodeString( &FileName, L"*" ); while (NT_SUCCESS(Status)) { Status = ZwQueryDirectoryFile( DirectoryHandle, NULL, NULL, NULL, &IoStatusBlock, DirectoryInfo, sizeof(Buffer), FileBothDirectoryInformation, TRUE, &FileName, FALSE ); if (NT_SUCCESS(Status) && DirectoryInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { swprintf( buf, L"\\??\\%c:\\", Region->DriveLetter ); wcsncat( buf, DirectoryInfo->FileName, DirectoryInfo->FileNameLength/sizeof(WCHAR) ); wcscat( buf, L"\\system32\\config" ); if (SpFileExists(buf, TRUE)) { swprintf( buf, L"\\??\\%c:\\", Region->DriveLetter ); wcsncat( buf, DirectoryInfo->FileName, DirectoryInfo->FileNameLength/sizeof(WCHAR) ); wcscat( buf, L"\\system32\\drivers" ); if (SpFileExists(buf, TRUE)) { NtInstall = (PNT_INSTALLATION) SpMemAlloc( sizeof(NT_INSTALLATION) ); if (NtInstall) { RtlZeroMemory( NtInstall, sizeof(NT_INSTALLATION) ); NtInstall->InstallNumber = ++InstallCount; NtInstall->DriveLetter = Region->DriveLetter; NtInstall->Region = Region; wcsncpy( NtInstall->Path, DirectoryInfo->FileName, DirectoryInfo->FileNameLength/sizeof(WCHAR) ); InsertTailList( &NtInstalls, &NtInstall->ListEntry ); } } } } } ZwClose( DirectoryHandle ); return TRUE; } BOOLEAN RcScanForNTInstallEnum( IN PCWSTR DirName, IN PFILE_BOTH_DIR_INFORMATION FileInfo, OUT PULONG ret, IN PVOID Pointer ) /*++ Routine Description: NOTE: this routine os of type: ENUMFILESPROC (spmisc.h) This routine determines if the directory which is currently being enumerated is an NT install directory Arguments: DirName - IN: the directory in which the file to enumerate exists FileInfo - IN: file attributes for the file to enumerate ret - OUT: return status of this procedure Pointer - IN: contains persistent recursion data Return Value: A linked list of SP_DISCOVERED_NT_INSTALLS, where each structure refers to a discovered installation of Windows --*/ { PWSTR FileName; PWSTR FullPath; PWSTR PartialPathName; BOOLEAN IsNtInstall; PRC_SCAN_RECURSION_DATA RecursionData; // // Ignore non-directories // if(! (FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { return TRUE; // continue processing } // // Build the full file or dir path // // // We have to make a copy of the directory name, because the info struct // we get isn't NULL-terminated. // wcsncpy( TemporaryBuffer, FileInfo->FileName, FileInfo->FileNameLength ); (TemporaryBuffer)[FileInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL; FileName = SpDupStringW(TemporaryBuffer); wcscpy(TemporaryBuffer,DirName); SpConcatenatePaths(TemporaryBuffer,FileName); FullPath = SpDupStringW(TemporaryBuffer); SpMemFree(FileName); // // Get the recursion data // RecursionData = (PRC_SCAN_RECURSION_DATA)Pointer; // // get the directory component beyond the root directory // PartialPathName = FullPath + RecursionData->RootDirLength; ASSERT(PartialPathName < (FullPath + wcslen(FullPath))); // // Test if the directory is an NT install // IsNtInstall = SpIsNtInDirectory(RecursionData->NtPartitionRegion, PartialPathName ); // // if we found an NT install, then add it to our linked list // if(IsNtInstall) { PNT_INSTALLATION NtInstall; NtInstall = (PNT_INSTALLATION) SpMemAlloc( sizeof(NT_INSTALLATION) ); if (NtInstall) { RtlZeroMemory( NtInstall, sizeof(NT_INSTALLATION) ); NtInstall->InstallNumber = ++InstallCountFullScan; NtInstall->DriveLetter = RecursionData->NtPartitionRegion->DriveLetter; NtInstall->Region = RecursionData->NtPartitionRegion; // // Note: this PartialPathName contains the '\' at the beginning of the // Path, while the FileName used in RcLogonDiskRegionEnum // does not // wcsncpy( NtInstall->Path, PartialPathName, sizeof(NtInstall->Path)/sizeof(WCHAR)); InsertTailList( &NtInstallsFullScan, &NtInstall->ListEntry ); } } SpMemFree(FullPath); return TRUE; // continue processing } BOOL RcScanDisksForNTInstallsEnum( IN PPARTITIONED_DISK Disk, IN PDISK_REGION NtPartitionRegion, IN ULONG_PTR Context ) /*++ Routine Description: This routine launches the directory level scan for NT installs. Arguments: Disk - the disk we are scanning NtPartitionRegion - the partition we are scanning Context - the persistent recursion data Return Value: TRUE - continue scanning FALSE - stop scanning --*/ { ULONG EnumReturnData; ENUMFILESRESULT EnumFilesResult; PWSTR NtPartition; PWSTR DirName; PRC_SCAN_RECURSION_DATA RecursionData; // // make sure this is valid partition: // // not reserved // filesystem is ntfs || fat // if (((NtPartitionRegion->Filesystem != FilesystemFat) && (NtPartitionRegion->Filesystem != FilesystemFat32) && (NtPartitionRegion->Filesystem != FilesystemNtfs) ) || (NtPartitionRegion->IsReserved == 1) ) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SPCMDCON: RcScanDisksForNTInstallsEnum: skipping filesystem type %x\r\n", NtPartitionRegion->Filesystem )); return TRUE; } // // Get our context // RecursionData = (PRC_SCAN_RECURSION_DATA)Context; // // Keep track of which partition region we are dealing with // so that the file enumeration routine can pass this info // on to SpIsNtInDirectory. // RecursionData->NtPartitionRegion = NtPartitionRegion; // // Get the device path of the nt partition. // SpNtNameFromRegion( NtPartitionRegion, TemporaryBuffer, sizeof(TemporaryBuffer), PartitionOrdinalCurrent ); NtPartition = SpDupStringW(TemporaryBuffer); // // Begin searching at the root directory // wcscpy(TemporaryBuffer, NtPartition); SpConcatenatePaths(TemporaryBuffer, L"\\"); DirName = SpDupStringW(TemporaryBuffer); // // get the length of the root directory string less the // directory separator. This will be used to remove // the root dir component of the pathname when we pass // the dir name into SpIsNtInDirectory. We need to do this // because SpIsNtInDirectory adds the root dir back in. // RecursionData->RootDirLength = wcslen(DirName) - 1; KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SPCMDCON: SpScanDisksForNTInstalls: Scanning: %s\n", DirName )); // // Enumerate all the directories on the current partition // // Note: if the enumeration does not return with a status of NormalReturn, // we do not stop the scanning process, rather we will contine on // scanning any remaining disks/partitions. // EnumFilesResult = SpEnumFilesRecursiveLimited( DirName, RcScanForNTInstallEnum, MAX_FULL_SCAN_RECURSION_DEPTH, 0, &EnumReturnData, RecursionData ); if (EnumFilesResult != NormalReturn) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SPCMDCON: SpScanDisksForNTInstalls: Enum Files returned non-normal result: %x\n", EnumFilesResult )); } // // we are done with instance of DirName // SpMemFree(DirName); return TRUE; } NTSTATUS RcAuthorizePasswordLogon( IN PWSTR UserName, IN PWSTR UserPassword, IN PNT_INSTALLATION NtInstall ) { #define BUFFERSIZE (sizeof(KEY_VALUE_PARTIAL_INFORMATION)+256) OBJECT_ATTRIBUTES Obja; UNICODE_STRING UnicodeString; NTSTATUS Status; NTSTATUS TmpStatus; WCHAR KeyName[128]; PWSTR Hive = NULL; PWSTR HiveKey = NULL; PUCHAR buffer = NULL; PWSTR PartitionPath = NULL; HANDLE hKeySamRoot = NULL; HANDLE hKeyNames = NULL; HANDLE hKeyUser = NULL; HANDLE hKeySystemRoot = NULL; HANDLE hKeySecurityRoot = NULL; ULONG ResultLength; ULONG Number; ULONG Rid; NT_OWF_PASSWORD NtOwfPassword; NT_OWF_PASSWORD UserOwfPassword; ULONG i; BOOLEAN NtPasswordPresent; BOOLEAN NtPasswordNonNull; WCHAR PasswordBuffer[128]; UNICODE_STRING BootKeyPassword; PUNICODE_STRING pBootKeyPassword = NULL; USHORT BootKeyType = 0; PWCHAR MessageText = NULL; UNICODE_STRING SysKeyFileName; HANDLE SysKeyHandle; IO_STATUS_BLOCK IoStatusBlock; PWCHAR FloppyPath = NULL; BOOLEAN bSecurityHiveLoaded = FALSE; BOOLEAN bSysHiveLoaded = FALSE; BOOLEAN bSamHiveLoaded = FALSE; BOOLEAN bClearScreen = FALSE; // // Allocate buffers. // Hive = SpMemAlloc(MAX_PATH * sizeof(WCHAR)); HiveKey = SpMemAlloc(MAX_PATH * sizeof(WCHAR)); buffer = SpMemAlloc(BUFFERSIZE); // // Get the name of the target patition. // SpNtNameFromRegion( NtInstall->Region, _CmdConsBlock->TemporaryBuffer, _CmdConsBlock->TemporaryBufferSize, PartitionOrdinalCurrent ); PartitionPath = SpDupStringW(_CmdConsBlock->TemporaryBuffer); // // Load the SYSTEM hive // bSysHiveLoaded = RcOpenSystemHive(); if (!bSysHiveLoaded){ // // Note : System hive seems to be corrupted so go ahead // and let the user log in so that he/she can fix // the problem // Status = STATUS_SUCCESS; RcSetSETCommandStatus(TRUE); // enable the set command also goto exit; } // // Now get a key to the root of the hive we just loaded. // wcscpy(HiveKey,L"\\registry\\machine\\xSYSTEM"); INIT_OBJA(&Obja,&UnicodeString,HiveKey); Status = ZwOpenKey(&hKeySystemRoot,KEY_ALL_ACCESS,&Obja); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: Unable to open %ws (%lx)\n",HiveKey,Status)); goto exit; } // // Load the SAM hive // wcscpy(Hive,PartitionPath); SpConcatenatePaths(Hive,NtInstall->Path); SpConcatenatePaths(Hive,L"system32\\config"); SpConcatenatePaths(Hive,L"sam"); // // Form the path of the key into which we will // load the hive. We'll use the convention that // a hive will be loaded into \registry\machine\security. // wcscpy(HiveKey,L"\\registry\\machine\\security"); // // Attempt to load the key. // Status = SpLoadUnloadKey(NULL,NULL,HiveKey,Hive); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: Unable to load hive %ws to key %ws (%lx)\n",Hive,HiveKey,Status)); // // Note : SAM hive seems to be corrupted so go ahead // and let the user log in so that he/she can fix // the problem // Status = STATUS_SUCCESS; RcSetSETCommandStatus(TRUE); // enable the set command also goto exit; } bSamHiveLoaded = TRUE; // // Now get a key to the root of the hive we just loaded. // INIT_OBJA(&Obja,&UnicodeString,HiveKey); Status = ZwOpenKey(&hKeySamRoot,KEY_ALL_ACCESS,&Obja); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: Unable to open %ws (%lx)\n",HiveKey,Status)); goto exit; } // // load the "security" hive // bSecurityHiveLoaded = RcOpenHive(gszSecurityHiveName, gszSecurityHiveKey); if (!bSecurityHiveLoaded) { KdPrint(("SETUP: Unable to load hive %ws to key %ws\n", gszSecurityHiveName, gszSecurityHiveKey)); // // Note : securityy hive seems to be corrupted so go ahead // and let the user log in so that he/she can fix // the problem // Status = STATUS_SUCCESS; RcSetSETCommandStatus(TRUE); // enable the set command also goto exit; } // // Now get a key to the root of the security hive we just loaded. // INIT_OBJA(&Obja,&UnicodeString,gszSecurityHiveKey); Status = ZwOpenKey(&hKeySecurityRoot,KEY_ALL_ACCESS,&Obja); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: Unable to open %ws (%lx)\n",gszSecurityHiveName,Status)); goto exit; } if (_wcsicmp(UserName,L"administrator")==0) { Rid = DOMAIN_USER_RID_ADMIN; } else { // // Get the key to the account data base // wcscpy(KeyName,L"SAM\\Domains\\Account\\Users\\Names\\"); wcscat(KeyName,UserName); INIT_OBJA(&Obja,&UnicodeString,KeyName); Obja.RootDirectory = hKeySamRoot; Status = ZwOpenKey(&hKeyNames,KEY_READ,&Obja); if(!NT_SUCCESS(Status)) { goto exit; } // // Get the RID of the user // UnicodeString.Length = 0; UnicodeString.MaximumLength = 0; UnicodeString.Buffer = _CmdConsBlock->TemporaryBuffer; Status = ZwQueryValueKey( hKeyNames, &UnicodeString, KeyValuePartialInformation, _CmdConsBlock->TemporaryBuffer, _CmdConsBlock->TemporaryBufferSize, &ResultLength ); if(!NT_SUCCESS(Status)) { goto exit; } Rid = ((PKEY_VALUE_PARTIAL_INFORMATION)_CmdConsBlock->TemporaryBuffer)->Type; } while(TRUE){ Status = SamRetrieveOwfPasswordUser( Rid, hKeySecurityRoot, hKeySamRoot, hKeySystemRoot, pBootKeyPassword, BootKeyType, &NtOwfPassword, &NtPasswordPresent, &NtPasswordNonNull ); if (NT_SUCCESS(Status)) { break; } if (Status == STATUS_SAM_NEED_BOOTKEY_PASSWORD) { RcMessageOut( MSG_LOGON_PROMPT_SYSKEY_PASSWORD ); RtlZeroMemory( PasswordBuffer, sizeof(PasswordBuffer) ); RcPasswordIn( PasswordBuffer, sizeof(PasswordBuffer) / sizeof(WCHAR) ); RtlInitUnicodeString( &BootKeyPassword, PasswordBuffer ); pBootKeyPassword = &BootKeyPassword; BootKeyType = SamBootKeyPassword; } if (Status == STATUS_SAM_NEED_BOOTKEY_FLOPPY){ FloppyPath = SpDupStringW(L"\\Device\\Floppy0"); MessageText = SpRetreiveMessageText(ImageBase,MSG_LOGON_PROMPT_SYSKEY_FLOPPY,NULL,0); bClearScreen = TRUE; if (!SpPromptForDisk( MessageText, FloppyPath, L"StartKey.Key", TRUE, FALSE, FALSE, NULL )){ Status = STATUS_WRONG_PASSWORD; goto exit; } INIT_OBJA( &Obja, &SysKeyFileName, L"\\Device\\Floppy0\\StartKey.Key" ); Status = ZwCreateFile(&SysKeyHandle, FILE_GENERIC_READ, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (NT_SUCCESS(Status)) { Status = ZwReadFile( SysKeyHandle, NULL, NULL, NULL, &IoStatusBlock, (PVOID) &PasswordBuffer[0], sizeof(PasswordBuffer), 0, NULL ); ZwClose( SysKeyHandle ); if (NT_SUCCESS(Status)) { BootKeyPassword.Buffer = PasswordBuffer; BootKeyPassword.Length = BootKeyPassword.MaximumLength = (USHORT) IoStatusBlock.Information; pBootKeyPassword = &BootKeyPassword; BootKeyType = SamBootKeyDisk; } else { goto exit; } } else { goto exit; } } if (!NT_SUCCESS(Status) && Status != STATUS_SAM_NEED_BOOTKEY_PASSWORD && Status != STATUS_SAM_NEED_BOOTKEY_FLOPPY) { goto exit; } } if (NtPasswordPresent && !NtPasswordNonNull && *UserPassword == 0) { Status = STATUS_SUCCESS; goto exit; } if (!NtPasswordPresent && *UserPassword == 0) { Status = STATUS_SUCCESS; goto exit; } RtlInitUnicodeString( &UnicodeString, UserPassword ); Status = RtlCalculateNtOwfPassword( &UnicodeString, &UserOwfPassword ); if(!NT_SUCCESS(Status)) { goto exit; } if (!RtlEqualNtOwfPassword( &NtOwfPassword, &UserOwfPassword )) { Status = STATUS_WRONG_PASSWORD; } // // now check to see if this user has admin rights // exit: if(bClearScreen) pRcCls(); // // close handles // if (hKeySamRoot) ZwClose(hKeySamRoot); if (hKeySecurityRoot) ZwClose(hKeySecurityRoot); if (hKeyNames) { ZwClose( hKeyNames ); } if (hKeyUser) { ZwClose( hKeyUser ); } if (hKeySystemRoot) ZwClose(hKeySystemRoot); // // Unload the SAM hive // if (bSamHiveLoaded) { TmpStatus = SpLoadUnloadKey(NULL,NULL,HiveKey,NULL); if(!NT_SUCCESS(TmpStatus)) { KdPrint(("SETUP: warning: unable to unload key %ws (%lx)\n",HiveKey,TmpStatus)); } } // // unload the security hive // if (bSecurityHiveLoaded) { if (!RcCloseHive(gszSecurityHiveKey)) KdPrint(("SETUP: warning: unable to unload key %ws\n",gszSecurityHiveKey)); } // // unload system hive // if (bSysHiveLoaded) RcCloseSystemHive(); // // free memory // if (Hive) { SpMemFree( Hive ); } if (HiveKey) { SpMemFree( HiveKey ); } if (buffer) { SpMemFree( buffer ); } if (PartitionPath) { SpMemFree( PartitionPath ); } if (MessageText) { SpMemFree( MessageText ); } if (FloppyPath) { SpMemFree( FloppyPath ); } return Status; } ULONG RcCmdLogon( IN PTOKENIZED_LINE TokenizedLine ) { #define MAX_FAILURES 3 NTSTATUS Status; PLIST_ENTRY Next; PNT_INSTALLATION NtInstall; PNT_INSTALLATION OldSelectedNtInstall = SelectedInstall; ULONG InstallNumber; WCHAR Buffer[128]; WCHAR UserNameBuffer[128]; WCHAR PasswordBuffer[128]; UNICODE_STRING UnicodeString; ULONG FailureCount = 0; ULONG u; BOOLEAN bRegCorrupted = FALSE; if (RcCmdParseHelp( TokenizedLine, MSG_LOGON_HELP )) { return 1; } // // Initialize list referring to the depth first search results // (These will be used via RcCmdBootCfg) // RcDestroyList(&NtInstallsFullScan); InstallCountFullScan = 0; // // Do a SHALLOW search for NT installs by default (at cmdcons boot) // RcDestroyList(&NtInstalls); InstallCount = 0; SpEnumerateDiskRegions( (PSPENUMERATEDISKREGIONS)RcLogonDiskRegionEnum, 0 ); if (InstallCount == 0) { // // no nt installations on the machine so let the // user logon anyway // SelectedInstall = NULL; firstTime = FALSE; return 1; } retry: RcTextOut( L"\r\n" ); Next = NtInstalls.Flink; while ((UINT_PTR)Next != (UINT_PTR)&NtInstalls) { NtInstall = CONTAINING_RECORD( Next, NT_INSTALLATION, ListEntry ); Next = NtInstall->ListEntry.Flink; swprintf( Buffer, L"%d: %c:\\", NtInstall->InstallNumber, NtInstall->DriveLetter ); wcscat( Buffer, NtInstall->Path ); wcscat( Buffer, L"\r\n" ); RcTextOut( Buffer ); } RcTextOut( L"\r\n" ); if (InBatchMode) { if (TokenizedLine && TokenizedLine->TokenCount >= 2) { RtlInitUnicodeString( &UnicodeString, TokenizedLine->Tokens->Next->String ); RtlUnicodeStringToInteger( &UnicodeString, 10, &InstallNumber ); } else { InstallNumber = 1; } if(!IS_VALID_INSTALL(InstallNumber)/* InstallNumber > InstallCount*/){ RcMessageOut( MSG_INSTALL_SELECT_ERROR ); return 1; // will err out } } else { if (TokenizedLine && TokenizedLine->TokenCount == 2) { // Note : this could have been invoked only by executing a logon command // at the prompt RtlInitUnicodeString( &UnicodeString, TokenizedLine->Tokens->Next->String ); Status = RtlUnicodeStringToInteger( &UnicodeString, 10, &InstallNumber ); KdPrint(("SPCMDCON:Loging into %lx (%ws)\n", InstallNumber, TokenizedLine->Tokens->Next->String)); if (*TokenizedLine->Tokens->Next->String < L'0' || *TokenizedLine->Tokens->Next->String > L'9' || !NT_SUCCESS(Status) || !IS_VALID_INSTALL(InstallNumber)) { RcMessageOut( MSG_INSTALL_SELECT_ERROR ); return 1; // just err out for the command } } else { RtlZeroMemory( Buffer, sizeof(Buffer) ); RcMessageOut( MSG_INSTALL_SELECT ); if (!RcLineIn( Buffer, 2 )) { if( firstTime == TRUE ) { return 0; } else { return 1; } } if (*Buffer < L'0' || *Buffer > L'9') { RcMessageOut( MSG_INSTALL_SELECT_ERROR ); goto retry; } RtlInitUnicodeString( &UnicodeString, Buffer ); Status = RtlUnicodeStringToInteger( &UnicodeString, 10, &InstallNumber ); if(!NT_SUCCESS(Status) || !IS_VALID_INSTALL(InstallNumber)){ RcMessageOut( MSG_INSTALL_SELECT_ERROR ); goto retry; } } } Next = NtInstalls.Flink; while ((UINT_PTR)Next != (UINT_PTR)&NtInstalls) { NtInstall = CONTAINING_RECORD( Next, NT_INSTALLATION, ListEntry ); Next = NtInstall->ListEntry.Flink; if (NtInstall->InstallNumber == InstallNumber) { OldSelectedNtInstall = SelectedInstall; SelectedInstall = NtInstall; break; } } if (SelectedInstall == NULL) { if( firstTime == TRUE ) { return 0; } else { RcMessageOut( MSG_INSTALL_SELECT_ERROR ); goto retry; } } // // Note : check the SYSTEM, SAM, SECURITY hives and if corrupted then // allow the user to log in without asking for password // so that he/she may be able correct the problem // if (RcIsValidSystemHive()) { if (RcOpenHive( gszSAMHiveName, gszSAMHiveKey )) { RcCloseHive( gszSAMHiveKey ); if (!RcOpenHive(gszSecurityHiveName, gszSecurityHiveKey)){ bRegCorrupted = TRUE; goto success_exit; } RcCloseHive(gszSecurityHiveKey); } else{ bRegCorrupted = TRUE; goto success_exit; } } else{ bRegCorrupted = TRUE; goto success_exit; } // // Get the bias information for displaying the file times properly // glBias = RcGetTimeZoneBias(); KdPrint(("SPCMDCON: RcGetTimeZoneBias returned : %lx-%lx\n", glBias.HighPart, glBias.LowPart)); if (InBatchMode) { if (TokenizedLine && TokenizedLine->TokenCount == 3) { Status = RcAuthorizePasswordLogon( L"Administrator", TokenizedLine->Tokens->Next->Next->String, NtInstall ); if(NT_SUCCESS(Status)) { goto success_exit; } } else { Status = RcAuthorizePasswordLogon( L"Administrator", L"", NtInstall ); if(NT_SUCCESS(Status)) { goto success_exit; } } } else { // Login only if required if (!LoginRequired()) goto success_exit; wcscpy(UserNameBuffer,L"Administrator"); RtlZeroMemory( PasswordBuffer, sizeof(PasswordBuffer) ); while (FailureCount < MAX_FAILURES) { // // get the password // RcMessageOut( MSG_LOGON_PROMPT_PASSWORD ); RtlZeroMemory( PasswordBuffer, sizeof(PasswordBuffer) ); RcPasswordIn(PasswordBuffer, sizeof(PasswordBuffer)/sizeof(WCHAR)); // // authorize the logon attempt // Status = RcAuthorizePasswordLogon( UserNameBuffer, PasswordBuffer, NtInstall ); if(NT_SUCCESS(Status)) { goto success_exit; } RcMessageOut( MSG_LOGON_FAILURE ); FailureCount += 1; } } RcMessageOut( MSG_LOGON_FAILUE_BAD ); RcMessageOut( MSG_REBOOT_NOW ); RcTextOut(L"\r\n"); // // wait for the use to press ENTER // while (SpInputGetKeypress() != ASCI_CR); return 0; success_exit: // // Enable the set command if specified and not already // enabled (would be enabled if registries are corrupted) // if (bRegCorrupted) { AllowAllPaths = TRUE; RcSetSETCommandStatus(TRUE); } else { RcSetSETCommandStatus(IsSetCommandEnabled()); } // // set the current drive to the selected install. // _CurDrive = SelectedInstall->DriveLetter; // // set the current dir to the correct one. // RtlZeroMemory( Buffer, sizeof(Buffer) ); wcscat( Buffer, L"\\" ); wcscat( Buffer, SelectedInstall->Path ); wcscat( Buffer, L"\\" ); u = RcToUpper(SelectedInstall->DriveLetter) - L'A'; if(_CurDirs[u]) { SpMemFree(_CurDirs[u]); } _CurDirs[u] = SpDupStringW( Buffer ); firstTime = FALSE; RcPurgeHistoryBuffer(); return 1; } /*++ Routine Description: Checks the "SecurityLevel" value under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Setup\RecoveryConsole to see if login is needed or not Arguments: None Return Value: TRUE if Login is required or FALSE otherwise --*/ BOOLEAN LoginRequired( VOID ) { BOOLEAN bLogin = TRUE; PWSTR szValueName = L"SecurityLevel"; HANDLE hKey = NULL; UNICODE_STRING unicodeStr; NTSTATUS status; BYTE buffer[ sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR) ]; ULONG ulResultLen = 0; PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)buffer; OBJECT_ATTRIBUTES stObjAttr; PWSTR szWinLogonKey = L"\\registry\\machine\\xSOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Setup\\RecoveryConsole"; RtlZeroMemory(buffer, sizeof(buffer)); // // Load the SOFTWARE hive // if (RcOpenHive( gszSoftwareHiveName, gszSoftwareHiveKey )) { // // Open the key // INIT_OBJA( &stObjAttr, &unicodeStr, szWinLogonKey ); status = ZwOpenKey( &hKey, KEY_ALL_ACCESS, &stObjAttr ); if (NT_SUCCESS(status)) { RtlInitUnicodeString( &unicodeStr, szValueName ); // // read the value // status = ZwQueryValueKey( hKey, &unicodeStr, KeyValuePartialInformation, pKeyValueInfo, sizeof(buffer), &ulResultLen ); if (NT_SUCCESS(status) && (pKeyValueInfo->Type == REG_DWORD)) { bLogin = !(*((PDWORD)(pKeyValueInfo->Data)) == 1); } } if (hKey) ZwClose(hKey); // close the hive RcCloseHive( gszSoftwareHiveKey ); } return bLogin; } /*++ Routine Description: Checks the "SetCommand" value under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Setup\RecoveryConsole to see if SET command needs to be enabled or disabled Arguments: None Return Value: TRUE if Login is required or FALSE otherwise --*/ BOOLEAN IsSetCommandEnabled( VOID ) { BOOLEAN bSetEnabled = FALSE; PWSTR szValueName = L"SetCommand"; HANDLE hKey = NULL; UNICODE_STRING unicodeStr; NTSTATUS status; BYTE buffer[ sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR) ]; ULONG ulResultLen = 0; PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)buffer; OBJECT_ATTRIBUTES stObjAttr; PWSTR szWinLogonKey = L"\\registry\\machine\\xSOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Setup\\RecoveryConsole"; RtlZeroMemory(buffer, sizeof(buffer)); // // Load the SOFTWARE hive // if (RcOpenHive( gszSoftwareHiveName, gszSoftwareHiveKey )) { // // Open the key // INIT_OBJA( &stObjAttr, &unicodeStr, szWinLogonKey ); status = ZwOpenKey( &hKey, KEY_ALL_ACCESS, &stObjAttr ); if (NT_SUCCESS(status)) { RtlInitUnicodeString( &unicodeStr, szValueName ); // // read the value // status = ZwQueryValueKey( hKey, &unicodeStr, KeyValuePartialInformation, pKeyValueInfo, sizeof(buffer), &ulResultLen ); if (NT_SUCCESS(status) && (pKeyValueInfo->Type == REG_DWORD)) { bSetEnabled = (*((PDWORD)(pKeyValueInfo->Data)) == 1); } } if (hKey) ZwClose(hKey); // close the hive RcCloseHive( gszSoftwareHiveKey ); } return bSetEnabled; } LARGE_INTEGER RcGetTimeZoneBias( VOID ) /*++ Routine Description: Reads the bias information from "\\HKLM\\System\\CurrentControlSet\\Control\\TimeZoneInformation" key's "Bias" value. We use our own conversion routine because RtlSetTimeZoneInformation() updates the system time (which we don't want to change). Arguments: none Return Value: 0 if error, otherwise value stored in the registry for the key (could be zero). --*/ { LARGE_INTEGER lBias; OBJECT_ATTRIBUTES stObjAttr; HANDLE hKey = NULL; NTSTATUS status; UNICODE_STRING unicodeStr; unsigned uIndex; ULONG uControl = -1; WCHAR szKeyName[MAX_PATH]; BYTE dataBuff[MAX_PATH + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; KEY_VALUE_PARTIAL_INFORMATION *pKeyData = (KEY_VALUE_PARTIAL_INFORMATION*)dataBuff; ULONG ulResultLen = 0; UNICODE_STRING szValueName; DWORD dwDaylightBias = 0; DWORD dwStandardBias = 0; BOOLEAN bSysHiveOpened; lBias.QuadPart = 0; // // open the system hive & determine correct control set to use // bSysHiveOpened = RcOpenHive(gszSystemHiveName, gszSystemHiveKey); if (bSysHiveOpened && RcDetermineCorrectControlKey(&uControl)) { // // open the key and read the // RtlZeroMemory(pKeyData, sizeof(dataBuff)); swprintf(szKeyName, L"\\registry\\machine\\xSYSTEM\\ControlSet%03d\\Control\\TimeZoneInformation", uControl); INIT_OBJA(&stObjAttr, &unicodeStr, szKeyName); RtlInitUnicodeString(&szValueName, L"Bias"); status = ZwOpenKey(&hKey, KEY_READ, &stObjAttr); if (!NT_SUCCESS(status)) { KdPrint(("SPCMDCON: RcGetTimeZoneBias - Couldnot open hive key: %ws(%lx)\n", szKeyName, status)); } else { // // Query the "Bias" value under the key // status = ZwQueryValueKey( hKey, &szValueName, KeyValuePartialInformation, pKeyData, sizeof(dataBuff), &ulResultLen ); if (NT_SUCCESS(status) && (pKeyData->Type == REG_DWORD)) { lBias.QuadPart = Int32x32To64(*(DWORD*)(pKeyData->Data) * 60, 10000000); RtlZeroMemory(pKeyData, sizeof(dataBuff)); RtlInitUnicodeString(&szValueName, L"DaylightBias"); // // Query the "DaylightBias" value under the key // status = ZwQueryValueKey( hKey, &szValueName, KeyValuePartialInformation, pKeyData, sizeof(dataBuff), &ulResultLen ); if (NT_SUCCESS(status) && (pKeyData->Type == REG_DWORD)) { dwDaylightBias = *(DWORD*)(pKeyData->Data); if (dwDaylightBias == 0 ) { // // there could be a standard bias // RtlZeroMemory(pKeyData, sizeof(dataBuff)); RtlInitUnicodeString(&szValueName, L"StandardBias"); // // Query the "StandardBias" value under the key // status = ZwQueryValueKey( hKey, &szValueName, KeyValuePartialInformation, pKeyData, sizeof(dataBuff), &ulResultLen ); if (NT_SUCCESS(status) && (pKeyData->Type == REG_DWORD)) { dwStandardBias = *(DWORD*)(pKeyData->Data); } } lBias.QuadPart += Int32x32To64((dwDaylightBias + dwStandardBias) * 60, 10000000); } else { lBias.QuadPart = 0; // } } if (!NT_SUCCESS(status)) KdPrint(("SPCMDCON: RcGetTimeZoneBias Error:(%lx)", status)); } if (hKey) ZwClose(hKey); } if (bSysHiveOpened) RcCloseHive(gszSystemHiveKey); return lBias; } BOOLEAN RcIsValidSystemHive( VOID ) /*++ Routine Description: Verifies whether the system hive of the selected NT install is fine. Checks for the presence of "Control\Lsa" and "Control\SessionManager" currently under ControlSet. Arguments: none Return Value: TRUE - indicates system hive is fine FALSE - indicates system hive is corrupted --*/ { BOOLEAN bResult = FALSE; OBJECT_ATTRIBUTES stObjAttr; HANDLE hKey = NULL; NTSTATUS status; UNICODE_STRING unicodeStr; unsigned uIndex; ULONG uControl = -1; WCHAR szKeyName[MAX_PATH]; BOOLEAN bSysHiveOpened; KEY_CHECK_STRUCT aKeysToCheck[] = { { L"\\registry\\machine\\xSYSTEM\\ControlSet%03d\\Control\\Lsa", TRUE }, { L"\\registry\\machine\\xSYSTEM\\ControlSet%03d\\Control\\Session Manager", TRUE } }; // // open the system hive & determine correct control set to use // bSysHiveOpened = RcOpenHive(gszSystemHiveName, gszSystemHiveKey); if ( bSysHiveOpened && RcDetermineCorrectControlKey(&uControl)) { bResult = TRUE; // // open each of the key and then close it to verify its presence // for (uIndex = 0; uIndex < (sizeof(aKeysToCheck) / sizeof(KEY_CHECK_STRUCT)); uIndex++) { if (aKeysToCheck[uIndex].bControlSet) swprintf(szKeyName, aKeysToCheck[uIndex].szKeyName, uControl); else wcscpy(szKeyName, aKeysToCheck[uIndex].szKeyName); INIT_OBJA(&stObjAttr, &unicodeStr, szKeyName); status = ZwOpenKey(&hKey, KEY_READ, &stObjAttr); if (!NT_SUCCESS(status)) { KdPrint(("SPCMDCON: RcIsValidSystemHive - Couldnot open hive key: %ws(%lx)\n", szKeyName, status)); bResult = FALSE; break; } if (hKey) ZwClose(hKey); } } if (bSysHiveOpened) RcCloseHive(gszSystemHiveKey); return bResult; } BOOLEAN RcOpenHive( PWSTR szHiveName, PWSTR szHiveKey ) /*++ Routine Description: Opens the requested hive of the selected NT install. Arguments: szHiveName - hive file name (just file name alone) szHiveKey - the key into which the hive needs to be loaded Return Value: TRUE - indicates sucess FALSE - indicates failure --*/ { PWSTR Hive = NULL; PWSTR HiveKey = NULL; PUCHAR buffer = NULL; PWSTR PartitionPath = NULL; NTSTATUS Status; BOOLEAN bResult = FALSE; if ((SelectedInstall == NULL) || (szHiveName == NULL) || (szHiveKey == NULL)) { return FALSE; } // // Allocate buffers. // Hive = SpMemAlloc(MAX_PATH * sizeof(WCHAR)); HiveKey = SpMemAlloc(MAX_PATH * sizeof(WCHAR)); buffer = SpMemAlloc(BUFFERSIZE); // // Get the name of the target patition. // SpNtNameFromRegion( SelectedInstall->Region, // SelectedInstall is a global defined in cmdcons.h _CmdConsBlock->TemporaryBuffer, _CmdConsBlock->TemporaryBufferSize, PartitionOrdinalCurrent ); PartitionPath = SpDupStringW(_CmdConsBlock->TemporaryBuffer); // // Load the hive // wcscpy(Hive,PartitionPath); SpConcatenatePaths(Hive,SelectedInstall->Path); SpConcatenatePaths(Hive,L"system32\\config"); SpConcatenatePaths(Hive,szHiveName); // // Form the path of the key into which we will // load the hive. We'll use the convention that // a hive will be loaded into \registry\machine\x. // wcscpy(HiveKey, szHiveKey); // // Attempt to load the key. // Status = SpLoadUnloadKey(NULL,NULL,HiveKey,Hive); if (NT_SUCCESS(Status)) bResult = TRUE; else DEBUG_PRINTF(("CMDCONS: Unable to load hive %ws to key %ws (%lx)\n",Hive,HiveKey,Status)); if (Hive != NULL) SpMemFree( Hive ); if (HiveKey != NULL) SpMemFree( HiveKey ); if (buffer != NULL) SpMemFree( buffer ); return bResult; } BOOLEAN RcCloseHive( PWSTR szHiveKey ) /*++ Routine Description: Closes the specified hive of the selected NT install. Arguments: szHiveKey - specifies the key of the hive to be unloaded Return Value: TRUE - indicates sucess FALSE - indicates failure --*/ { NTSTATUS TmpStatus; BOOLEAN bResult = FALSE; if (szHiveKey != NULL) { // // Unload the hive // TmpStatus = SpLoadUnloadKey( NULL, NULL, szHiveKey, NULL ); if (NT_SUCCESS(TmpStatus)) { bResult = TRUE; } else { KdPrint(("CMDCONS: warning: unable to unload key %ws (%lx)\n", szHiveKey, TmpStatus)); } } return bResult; }