1923 lines
61 KiB
C
1923 lines
61 KiB
C
/*++
|
|
|
|
File Description:
|
|
|
|
This file contains the driver functions to modify the
|
|
domain SID on a machine.
|
|
|
|
Author:
|
|
|
|
Matt Holle (matth) Oct 1997
|
|
|
|
|
|
--*/
|
|
|
|
//
|
|
// System header files
|
|
//
|
|
#include <nt.h>
|
|
|
|
//
|
|
// Disable the DbgPrint for non-debug builds
|
|
//
|
|
#ifndef DBG
|
|
#define _DBGNT_
|
|
#endif
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntverp.h>
|
|
#include <wtypes.h>
|
|
#include <ntddksec.h>
|
|
|
|
#ifdef IA64
|
|
#include <winioctl.h>
|
|
#include <efisbent.h>
|
|
|
|
#if defined(EFI_NVRAM_ENABLED)
|
|
#include <efi.h>
|
|
#include <efiapi.h>
|
|
#endif
|
|
#endif
|
|
|
|
//
|
|
// CRT header files
|
|
//
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
//
|
|
// Private header files
|
|
//
|
|
#include "setupcl.h"
|
|
#include "msg.h"
|
|
|
|
#ifdef IA64
|
|
|
|
// Seed for GUID generator function:
|
|
//
|
|
// This is initialized first at the beginning of main() with the NtQuerySystemTime()
|
|
// and then is updated every time the CreateNewGuid function is called.
|
|
// We use the system time at the time CreateNewGuid is called for another part of the GUID.
|
|
// This is done so that we achieve some variability accross machines, as the time delta between
|
|
// calls to NtQuerySystemTime() should be somewhat different accross machines and invocations of
|
|
// this program.
|
|
//
|
|
ULONG RandomSeed;
|
|
|
|
#endif
|
|
|
|
// Start time for setupcl. This is used so we can display a UI if setupcl takes longer than 15 seconds to
|
|
// complete. Note that the checks for time only happen in the recursive function calls so if a step is added
|
|
// to setupcl that takes a considerable amount of time DisplayUI() should be called as part of that step as well.
|
|
//
|
|
|
|
LARGE_INTEGER StartTime;
|
|
LARGE_INTEGER CurrentTime;
|
|
LARGE_INTEGER LastDotTime; // For putting up dots every few seconds.
|
|
|
|
BOOL bDisplayUI = FALSE; // Initially don't display the UI.
|
|
|
|
NTSTATUS
|
|
ProcessHives(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
FinalHiveCleanup(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
ProcessRepairHives(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
RetrieveOldSid(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
GenerateUniqueSid(
|
|
IN DWORD Seed
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
ProcessHives(
|
|
VOID
|
|
)
|
|
/*++
|
|
===============================================================================
|
|
Routine Description:
|
|
|
|
This function check keys (and all subkeys) for:
|
|
- keys with the old SID name
|
|
- value keys with the old SID value
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
===============================================================================
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
PWSTR KeysToWhack[] = {
|
|
//
|
|
// SAM hive...
|
|
//
|
|
L"\\REGISTRY\\MACHINE\\SAM\\SAM",
|
|
|
|
//
|
|
// Security hive...
|
|
//
|
|
L"\\REGISTRY\\MACHINE\\SECURITY",
|
|
|
|
//
|
|
// Software hive...
|
|
//
|
|
L"\\REGISTRY\\MACHINE\\SOFTWARE",
|
|
|
|
//
|
|
// System hive...
|
|
//
|
|
L"\\REGISTRY\\MACHINE\\SYSTEM",
|
|
|
|
};
|
|
LARGE_INTEGER Start_Time, End_Time;
|
|
|
|
//
|
|
// Record our start time.
|
|
//
|
|
NtQuerySystemTime( &Start_Time );
|
|
|
|
for( i = 0; i < sizeof(KeysToWhack) / sizeof(PWSTR); i++ ) {
|
|
|
|
DbgPrint( "\nSETUPCL: ProcessHives - About to process %ws\n", KeysToWhack[i] );
|
|
|
|
Status = SiftKey( KeysToWhack[i] );
|
|
TEST_STATUS( "SETUPCL: ProcessHives - Failed to process key..." );
|
|
}
|
|
|
|
//
|
|
// Record our end time.
|
|
//
|
|
NtQuerySystemTime( &End_Time );
|
|
|
|
//
|
|
// Record our execution time.
|
|
//
|
|
End_Time.QuadPart = End_Time.QuadPart - Start_Time.QuadPart;
|
|
#if 0
|
|
Status = SetKey( TEXT(REG_SYSTEM_SETUP),
|
|
TEXT("SetupCL_Run_Time"),
|
|
(PUCHAR)&End_Time.LowPart,
|
|
sizeof( DWORD ),
|
|
REG_DWORD );
|
|
#endif
|
|
return( Status );
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
FinalHiveCleanup(
|
|
VOID
|
|
)
|
|
/*++
|
|
===============================================================================
|
|
Routine Description:
|
|
|
|
This function will go load each user-specific hive on the machine and
|
|
propogate the new SID into it.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
===============================================================================
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING UnicodeString,
|
|
UnicodeValue;
|
|
HANDLE hKey, hKeyChild;
|
|
ULONG ResultLength,
|
|
KeyValueLength,
|
|
Index,
|
|
LengthNeeded;
|
|
PKEY_BASIC_INFORMATION KeyInfo;
|
|
WCHAR KeyBuffer[BASIC_INFO_BUFFER_SIZE];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo = NULL;
|
|
|
|
|
|
//
|
|
// ========================
|
|
// User Profile Hives
|
|
// ========================
|
|
//
|
|
DbgPrint( "\nAbout to operate on user-specific profile hives.\n" );
|
|
|
|
//
|
|
// We need to go check the user profile hives out on the disk.
|
|
// If we find any, we need to change his ACLs to reflect the new
|
|
// SID.
|
|
//
|
|
|
|
//
|
|
// Open the PROFILELIST key.
|
|
//
|
|
INIT_OBJA( &Obja, &UnicodeString, TEXT( REG_SOFTWARE_PROFILELIST ) );
|
|
Status = NtOpenKey( &hKey,
|
|
KEY_ALL_ACCESS,
|
|
&Obja );
|
|
TEST_STATUS( "SETUPCL: FinalHiveCleanup - Failed to open PROFILELIST key." );
|
|
|
|
KeyInfo = (PKEY_BASIC_INFORMATION)KeyBuffer;
|
|
//
|
|
// Now enumerate all his subkeys and see if any of them have a
|
|
// ProfileImagePath key.
|
|
//
|
|
for( Index = 0; ; Index++ ) {
|
|
|
|
// Local variable.
|
|
//
|
|
DWORD dwPass;
|
|
PWCHAR lpszHiveName[] = {
|
|
L"\\NTUSER.DAT",
|
|
L"\\Local Settings\\Application Data\\Microsoft\\Windows\\UsrClass.dat"
|
|
};
|
|
|
|
Status = NtEnumerateKey( hKey,
|
|
Index,
|
|
KeyBasicInformation,
|
|
KeyInfo,
|
|
sizeof(KeyBuffer),
|
|
&ResultLength );
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
if(Status == STATUS_NO_MORE_ENTRIES) {
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
TEST_STATUS( "SETUPCL: FinalHiveCleanup - Failure during enumeration of subkeys." );
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Zero-terminate the subkey name just in case.
|
|
//
|
|
KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - enumerated %ws\n", KeyInfo->Name );
|
|
|
|
//
|
|
// Generate a handle for this child key and open him too.
|
|
//
|
|
INIT_OBJA( &Obja, &UnicodeString, KeyInfo->Name );
|
|
Obja.RootDirectory = hKey;
|
|
Status = NtOpenKey( &hKeyChild,
|
|
KEY_ALL_ACCESS,
|
|
&Obja );
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - If NtOpenKey fails, hKey is leaked
|
|
//
|
|
TEST_STATUS_RETURN( "SETUPCL: FinalHiveCleanup - Failed to open child key." );
|
|
|
|
//
|
|
// Now get the ProfileImagePath value.
|
|
//
|
|
RtlInitUnicodeString( &UnicodeString, TEXT( PROFILEIMAGEPATH ) );
|
|
|
|
//
|
|
// How big of a buffer do we need?
|
|
//
|
|
Status = NtQueryValueKey( hKeyChild,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
NULL,
|
|
0,
|
|
&LengthNeeded );
|
|
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - Check for STATUS_SUCCESS, not assume success on STATUS_OBJECT_NAME_NOT_FOUND
|
|
//
|
|
if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Unable to query key %ws size. Error (%lx)\n", TEXT( PROFILEIMAGEPATH ), Status );
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Allocate a block.
|
|
//
|
|
if( NT_SUCCESS( Status ) ) {
|
|
if( KeyValueInfo ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
|
|
KeyValueInfo = NULL;
|
|
}
|
|
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
|
|
0,
|
|
LengthNeeded + 0x10 );
|
|
|
|
if( KeyValueInfo == NULL ) {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Unable to allocate buffer\n" );
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the data.
|
|
//
|
|
if( NT_SUCCESS( Status ) ) {
|
|
Status = NtQueryValueKey( hKeyChild,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
LengthNeeded,
|
|
&KeyValueLength );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Failed to query key %ws (%lx)\n", TEXT( PROFILEIMAGEPATH ), Status );
|
|
}
|
|
}
|
|
NtClose( hKeyChild );
|
|
|
|
//
|
|
// Do two passes. First pass will be for the NTUSER.DAT hive and the second will be for
|
|
// UsrClass.dat hive.
|
|
//
|
|
for ( dwPass = 0; dwPass < AS(lpszHiveName); dwPass++ ) {
|
|
|
|
if( NT_SUCCESS( Status ) ) {
|
|
PWCHAR TmpChar;
|
|
ULONG i;
|
|
|
|
memset( TmpBuffer, 0, sizeof(TmpBuffer) );
|
|
wcsncpy( TmpBuffer, (PWCHAR)&KeyValueInfo->Data, AS(TmpBuffer) - 1);
|
|
|
|
//
|
|
// We've got the path to the profile hive, but it will contain
|
|
// an environment variable. Expand the variable.
|
|
//
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Before the expand, I think his ProfileImagePath is: %ws\n", TmpBuffer );
|
|
|
|
RtlInitUnicodeString( &UnicodeString, TmpBuffer );
|
|
|
|
UnicodeValue.Length = 0;
|
|
UnicodeValue.MaximumLength = MAX_PATH * sizeof(WCHAR);
|
|
UnicodeValue.Buffer = (PWSTR)RtlAllocateHeap( RtlProcessHeap(), 0, UnicodeValue.MaximumLength );
|
|
|
|
//
|
|
// Prefix Bug # 111373.
|
|
//
|
|
if ( UnicodeValue.Buffer )
|
|
{
|
|
RtlZeroMemory( UnicodeValue.Buffer, UnicodeValue.MaximumLength );
|
|
Status = RtlExpandEnvironmentStrings_U( NULL, &UnicodeString, &UnicodeValue, NULL );
|
|
|
|
//
|
|
// RtlExpandEnvironmentStrings_U has given us a path, but
|
|
// it will contain a drive letter. We need an NT path.
|
|
// Go convert it.
|
|
//
|
|
if( NT_SUCCESS( Status ) &&
|
|
( (UnicodeValue.Length + (wcslen(lpszHiveName[dwPass]) * sizeof(WCHAR))) < sizeof(TmpBuffer) ) )
|
|
{
|
|
WCHAR DriveLetter[3];
|
|
WCHAR NTPath[MAX_PATH] = {0};
|
|
|
|
//
|
|
// TmpBuffer will contain the complete path, except
|
|
// he's got the drive letter.
|
|
//
|
|
RtlCopyMemory( TmpBuffer, UnicodeValue.Buffer, UnicodeValue.Length );
|
|
TmpBuffer[(UnicodeValue.Length / sizeof(WCHAR))] = 0;
|
|
wcscat( TmpBuffer, lpszHiveName[dwPass] );
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - I think the dospath to his ProfileImagePath is: %ws\n", TmpBuffer );
|
|
|
|
|
|
DriveLetter[0] = TmpBuffer[0];
|
|
DriveLetter[1] = L':';
|
|
DriveLetter[2] = 0;
|
|
|
|
//
|
|
// Get the symbolic link from the drive letter.
|
|
//
|
|
Status = DriveLetterToNTPath( DriveLetter[0], NTPath, AS(NTPath) );
|
|
|
|
if( NT_SUCCESS( Status ) ) {
|
|
//
|
|
// Translation was successful. Insert the ntpath into our
|
|
// path to the profile.
|
|
//
|
|
Status = StringSwitchString( TmpBuffer, AS(TmpBuffer), DriveLetter, NTPath );
|
|
} else {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - We failed our call to DriveLetterToNTPath (%lx)\n", Status );
|
|
}
|
|
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - After the expand, I think his ProfileImagePath is: %ws\n", TmpBuffer );
|
|
} else {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - We failed our call to RtlExpandEnvironmentStrings_U (%lx)\n", Status );
|
|
}
|
|
|
|
RtlFreeHeap( RtlProcessHeap(),
|
|
0,
|
|
UnicodeValue.Buffer );
|
|
}
|
|
|
|
//
|
|
// Attempt to load the hive, open his root key, then
|
|
// go swap ACLs on all the subkeys.
|
|
//
|
|
Status = LoadUnloadHive( TEXT( TMP_HIVE_NAME ),
|
|
TmpBuffer );
|
|
if( NT_SUCCESS( Status ) ) {
|
|
|
|
|
|
//
|
|
// Let's go search for any instance of the SID in our
|
|
// newly loaded hive.
|
|
//
|
|
Status = SiftKey( TEXT( TMP_HIVE_NAME ) );
|
|
TEST_STATUS( "SETUPCL: FinalHiveCleanup - Failed to push new sid into user's hive." );
|
|
|
|
|
|
#if 0
|
|
//
|
|
// Move call to SetKeySecurityRecursive into
|
|
// SiftKey so that implicitly fixup ACLs too.
|
|
//
|
|
|
|
|
|
|
|
//
|
|
// Open the root of our newly loaded hive.
|
|
//
|
|
INIT_OBJA( &Obja, &UnicodeString, TEXT( TMP_HIVE_NAME ) );
|
|
Status = NtOpenKey( &hKeyChild,
|
|
KEY_ALL_ACCESS,
|
|
&Obja );
|
|
|
|
//
|
|
// Now go attempt to whack the ACLs on this, and
|
|
// all subkeys.
|
|
//
|
|
if( NT_SUCCESS( Status ) ) {
|
|
SetKeySecurityRecursive( hKeyChild );
|
|
|
|
NtClose( hKeyChild );
|
|
} else {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Failed open of TmpHive root.\n" );
|
|
}
|
|
#endif
|
|
|
|
LoadUnloadHive( TEXT( TMP_HIVE_NAME ),
|
|
NULL );
|
|
|
|
} else {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Failed load of TmpHive.\n" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NtClose( hKey );
|
|
|
|
//
|
|
// ========================
|
|
// \REGISTRY\MACHINE\SYSTEM\CURRENTCONTROLSET\CONTROL\REGISTRYSIZELIMIT
|
|
// ========================
|
|
//
|
|
DbgPrint( "\nAbout to operate on SYSTEM\\CURRENTCONTROLSET\\CONTROL\\REGISTRYSIZELIMIT.\n" );
|
|
|
|
//
|
|
// sysprep bumped the registry limit up by 4Mb. We need to lower it
|
|
// back down.
|
|
//
|
|
|
|
INIT_OBJA( &Obja,
|
|
&UnicodeString,
|
|
TEXT(REG_SYSTEM_CONTROL) );
|
|
Status = NtOpenKey( &hKey,
|
|
KEY_ALL_ACCESS,
|
|
&Obja );
|
|
TEST_STATUS( "SETUPCL: ProcessSYSTEMHive - Failed to open Control key!" );
|
|
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - Shouldn't try to query value if NtOpenKey fails!
|
|
//
|
|
|
|
//
|
|
// Get the data out of this key.
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, TEXT(REG_SIZE_LIMIT) );
|
|
|
|
//
|
|
// How big of a buffer do we need?
|
|
//
|
|
Status = NtQueryValueKey( hKey,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
NULL,
|
|
0,
|
|
&LengthNeeded );
|
|
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - Check for STATUS_SUCCESS, not assume success on STATUS_OBJECT_NAME_NOT_FOUND
|
|
//
|
|
if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Unable to query key %ws size. Error (%lx)\n", TEXT(REG_SIZE_LIMIT), Status );
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Allocate a block.
|
|
//
|
|
if( NT_SUCCESS( Status ) ) {
|
|
if( KeyValueInfo ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
|
|
KeyValueInfo = NULL;
|
|
}
|
|
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
|
|
0,
|
|
LengthNeeded + 0x10 );
|
|
|
|
if( KeyValueInfo == NULL ) {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Unable to allocate buffer\n" );
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the data.
|
|
//
|
|
if( NT_SUCCESS( Status ) ) {
|
|
Status = NtQueryValueKey( hKey,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
LengthNeeded,
|
|
&KeyValueLength );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
DbgPrint( "SETUPCL: FinalHiveCleanup - Failed to query key %ws (%lx)\n", TEXT(REG_SIZE_LIMIT), Status );
|
|
}
|
|
else{
|
|
Index = *(PDWORD)(&KeyValueInfo->Data);
|
|
Index = Index - REGISTRY_QUOTA_BUMP; //Bring it back to original value
|
|
|
|
//
|
|
// Set him.
|
|
//
|
|
Status = SetKey( TEXT(REG_SYSTEM_CONTROL),
|
|
TEXT(REG_SIZE_LIMIT),
|
|
(PUCHAR)&Index,
|
|
sizeof( DWORD ),
|
|
REG_DWORD );
|
|
DbgPrint("SETUPCL: ProcessSYSTEMHive - Size allocated = %lx\n",Index);
|
|
TEST_STATUS( "SETUPCL: ProcessSYSTEMHive - Failed to update SYSTEM\\CURRENTCONTROLSET\\CONTROL\\REGISTRYSIZELIMIT key." );
|
|
|
|
}
|
|
}
|
|
NtClose( hKey );
|
|
|
|
//
|
|
// ========================
|
|
// \REGISTRY\MACHINE\SYSTEM\CURRENTCONTROLSET\Control\Session Manager\SetupExecute
|
|
// ========================
|
|
//
|
|
DbgPrint( "\nAbout to operate on SYSTEM\\CURRENTCONTROLSET\\CONTROL\\SESSION MANAGER\\SETUPEXECUTE key.\n" );
|
|
|
|
//
|
|
// Open the Session manager key.
|
|
//
|
|
INIT_OBJA( &Obja,
|
|
&UnicodeString,
|
|
TEXT(REG_SYSTEM_SESSIONMANAGER) );
|
|
Status = NtOpenKey( &hKey,
|
|
KEY_ALL_ACCESS,
|
|
&Obja );
|
|
TEST_STATUS_RETURN( "SETUPCL: ProcessSYSTEMHive - Failed to open Session Manager key!" );
|
|
|
|
//
|
|
// Now delete the SetupExecute Key.
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, TEXT(EXECUTE) );
|
|
Status = NtDeleteValueKey( hKey, &UnicodeString );
|
|
NtClose( hKey );
|
|
TEST_STATUS( "SETUPCL: ProcessSYSTEMHive - Failed to update SYSTEM\\CURRENTCONTROLSET\\CONTROL\\SESSION MANAGER\\SETUPEXECUTE key." );
|
|
|
|
if( KeyValueInfo ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
|
|
KeyValueInfo = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ProcessRepairHives(
|
|
VOID
|
|
)
|
|
/*++
|
|
===============================================================================
|
|
Routine Description:
|
|
|
|
This function check keys (and all subkeys) for:
|
|
- keys with the old SID name
|
|
- value keys with the old SID value
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS.
|
|
|
|
===============================================================================
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
PWSTR KeysToWhack[] = {
|
|
//
|
|
// SAM hive...
|
|
//
|
|
L"\\REGISTRY\\MACHINE\\RSAM",
|
|
|
|
//
|
|
// Security hive...
|
|
//
|
|
L"\\REGISTRY\\MACHINE\\RSECURITY",
|
|
|
|
//
|
|
// Software hive...
|
|
//
|
|
L"\\REGISTRY\\MACHINE\\RSOFTWARE",
|
|
|
|
//
|
|
// System hive...
|
|
//
|
|
L"\\REGISTRY\\MACHINE\\RSYSTEM",
|
|
|
|
};
|
|
|
|
|
|
PWSTR KeysToLoad[] = {
|
|
//
|
|
// SAM hive...
|
|
//
|
|
L"\\SYSTEMROOT\\REPAIR\\SAM",
|
|
|
|
//
|
|
// Security hive...
|
|
//
|
|
L"\\SYSTEMROOT\\REPAIR\\SECURITY",
|
|
|
|
//
|
|
// Software hive...
|
|
//
|
|
L"\\SYSTEMROOT\\REPAIR\\SOFTWARE",
|
|
|
|
//
|
|
// System hive...
|
|
//
|
|
L"\\SYSTEMROOT\\REPAIR\\SYSTEM",
|
|
|
|
};
|
|
|
|
|
|
|
|
for( i = 0; i < sizeof(KeysToWhack) / sizeof(PWSTR); i++ ) {
|
|
|
|
//
|
|
// Load the repair hive.
|
|
//
|
|
DbgPrint( "\nSETUPCL: ProcessRepairHives - About to load %ws hive.\n", KeysToLoad[i] );
|
|
|
|
Status = LoadUnloadHive( KeysToWhack[i],
|
|
KeysToLoad[i] );
|
|
TEST_STATUS_RETURN( "SETUPCL: ProcessRepairHives - Failed to load repair hive." );
|
|
|
|
//
|
|
// Now operate on it.
|
|
//
|
|
DbgPrint( "SETUPCL: ProcessRepairHives - About to process %ws\n", KeysToWhack[i] );
|
|
|
|
Status = SiftKey( KeysToWhack[i] );
|
|
|
|
TEST_STATUS( "SETUPCL: ProcessRepairHives - Failed to process key..." );
|
|
|
|
//
|
|
// Unload the hive.
|
|
//
|
|
DbgPrint( "SETUPCL: ProcessRepairHives - About to unload %ws hive.\n", KeysToLoad[i] );
|
|
|
|
Status = LoadUnloadHive( KeysToWhack[i],
|
|
NULL );
|
|
TEST_STATUS( "SETUPCL: ProcessRepairHives - Failed to unload repair hive." );
|
|
}
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RetrieveOldSid(
|
|
VOID
|
|
)
|
|
/*++
|
|
===============================================================================
|
|
Routine Description:
|
|
|
|
Retrieves the current SID (as read from the registry.
|
|
|
|
Use RtlFreeSid() to free the SID allocated by this routine.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Status code indicating outcome.
|
|
===============================================================================
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hKey;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo = NULL;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
ULONG KeyValueLength,
|
|
LengthNeeded;
|
|
UNICODE_STRING SidString;
|
|
|
|
|
|
//
|
|
// We can conveniently retrieve our SID from
|
|
// \registry\machine\Security\Policy\PolAcDmS\<No Name>
|
|
//
|
|
// We'll open him up, read his data, then blast that into
|
|
// a SID structure.
|
|
//
|
|
|
|
//
|
|
// Open the PolAcDmS key.
|
|
//
|
|
INIT_OBJA( &ObjectAttributes, &UnicodeString, TEXT(REG_SECURITY_POLACDMS) );
|
|
Status = NtOpenKey( &hKey,
|
|
KEY_ALL_ACCESS,
|
|
&ObjectAttributes );
|
|
TEST_STATUS_RETURN( "SETUPCL: RetrieveOldSid - Failed to open PolAcDmS key!" );
|
|
|
|
//
|
|
// Get the data out of this key.
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, TEXT("") );
|
|
|
|
//
|
|
// How big of a buffer do we need?
|
|
//
|
|
Status = NtQueryValueKey( hKey,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
NULL,
|
|
0,
|
|
&LengthNeeded );
|
|
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - Check for STATUS_SUCCESS, not assume success on STATUS_OBJECT_NAME_NOT_FOUND
|
|
//
|
|
if( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
DbgPrint( "SETUPCL: RetrieveOldSid - Unable to query size of old sid. Error (%lx)\n", Status );
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Allocate a block.
|
|
//
|
|
if( NT_SUCCESS( Status ) ) {
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - This block will never get hit
|
|
//
|
|
if( KeyValueInfo ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
|
|
KeyValueInfo = NULL;
|
|
}
|
|
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)RtlAllocateHeap( RtlProcessHeap(),
|
|
0,
|
|
LengthNeeded + 0x10 );
|
|
|
|
if( KeyValueInfo == NULL ) {
|
|
DbgPrint( "SETUPCL: RetrieveOldSid - Unable to allocate buffer\n" );
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the data.
|
|
//
|
|
if( NT_SUCCESS( Status ) ) {
|
|
Status = NtQueryValueKey( hKey,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
LengthNeeded,
|
|
&KeyValueLength );
|
|
if( !NT_SUCCESS( Status ) ) {
|
|
DbgPrint( "SETUPCL: RetrieveOldSid - Failed to query old sid key (%lx)\n", Status );
|
|
}
|
|
}
|
|
|
|
|
|
TEST_STATUS_RETURN( "SETUPCL: RetrieveOldSid - Failed to query PolAcDmS key!" );
|
|
|
|
//
|
|
// Allocate space for our new SID.
|
|
//
|
|
G_OldSid = RtlAllocateHeap( RtlProcessHeap(), 0,
|
|
SID_SIZE );
|
|
if( G_OldSid == NULL ) {
|
|
DbgPrint( "SETUPCL: Call to RtlAllocateHeap failed!\n" );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
|
|
//
|
|
// Blast our Old SID into the memory we just allocated...
|
|
//
|
|
RtlCopyMemory( G_OldSid, ((PUCHAR)&KeyValueInfo->Data), SID_SIZE );
|
|
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - Close the key sooner!
|
|
//
|
|
NtClose( hKey );
|
|
|
|
//
|
|
// I need to get a text version of the 3 values that make
|
|
// up this SID's uniqueness. This is pretty gross. It turns
|
|
// out that the first 8 characters of the SID string (as gotten
|
|
// from a call to RtlConvertSidtoUnicodeString) are the same
|
|
// for any Domain SID. And it's always the 9th character that
|
|
// starts the 3 unique numbers.
|
|
//
|
|
Status = RtlConvertSidToUnicodeString( &SidString, G_OldSid, TRUE );
|
|
TEST_STATUS_RETURN( "SETUPCL: RetrieveOldSid - RtlConvertSidToUnicodeString failed!" );
|
|
memset( G_OldSidSubString, 0, sizeof(G_OldSidSubString) );
|
|
wcsncpy( G_OldSidSubString, &SidString.Buffer[9], AS(G_OldSidSubString) - 1 );
|
|
|
|
#ifdef DBG
|
|
//
|
|
// Debug spew.
|
|
//
|
|
{
|
|
int i;
|
|
|
|
DbgPrint( "SETUPCL: RetrieveOldSid - Retrieved SID:\n" );
|
|
for( i = 0; i < SID_SIZE; i += 4 ) {
|
|
DbgPrint( "%08lx ", *(PULONG)((PUCHAR)(G_OldSid) + i));
|
|
}
|
|
DbgPrint( "\n" );
|
|
|
|
DbgPrint("Old Sid = %ws \n",SidString.Buffer);
|
|
}
|
|
#endif
|
|
|
|
RtlFreeUnicodeString( &SidString );
|
|
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - Free the value buffer sooner? Do we need to assign KeyValueInfo to NULL after we're done with it?
|
|
//
|
|
if( KeyValueInfo ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
|
|
KeyValueInfo = NULL;
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
BOOL
|
|
SetupGenRandom(
|
|
OUT PVOID pbRandomKey,
|
|
IN ULONG cbRandomKey
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
HANDLE hFile;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING DriverName;
|
|
IO_STATUS_BLOCK IOSB;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
|
|
//
|
|
// have to use the Nt flavor of the file open call because it's a base
|
|
// device not aliased to \DosDevices
|
|
//
|
|
RtlInitUnicodeString( &DriverName, DD_KSEC_DEVICE_NAME_U );
|
|
InitializeObjectAttributes( &ObjA,
|
|
&DriverName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
0 );
|
|
|
|
Status = NtOpenFile( &hFile,
|
|
SYNCHRONIZE | FILE_READ_DATA,
|
|
&ObjA,
|
|
&IOSB,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_SYNCHRONOUS_IO_ALERT );
|
|
|
|
if ( NT_SUCCESS(Status) )
|
|
{
|
|
Status = NtDeviceIoControlFile( hFile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IOSB,
|
|
IOCTL_KSEC_RNG_REKEY, // indicate a RNG rekey
|
|
NULL, // input buffer (existing material)
|
|
0, // input buffer size
|
|
pbRandomKey, // output buffer
|
|
cbRandomKey ); // output buffer size
|
|
|
|
if ( NT_SUCCESS(Status) )
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
PRINT_STATUS( "SetupGenRandom: NtDeviceIoControlFile failed!" );
|
|
}
|
|
|
|
NtClose( hFile );
|
|
}
|
|
else
|
|
{
|
|
PRINT_STATUS( "SetupGenRandom: NtOpenFile failed!" );
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
NTSTATUS
|
|
SetupGenerateRandomDomainSid(
|
|
OUT PSID NewDomainSid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will generate a random sid to be used for the new account domain sid during
|
|
setup.
|
|
|
|
Arguments:
|
|
|
|
NewDomainSid - Where the new domain sid is returned. Freed via RtlFreeSid()
|
|
|
|
|
|
Return Values:
|
|
|
|
STATUS_SUCCESS -- Success.
|
|
STATUS_INVALID_PARAMETER -- We couldn't generate a random number
|
|
STATUS_INSUFFICIENT_RESOURCES -- A memory allocation failed
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
|
ULONG SubAuth1, SubAuth2, SubAuth3;
|
|
|
|
//
|
|
// Generate three random numbers for the new domain SID...
|
|
//
|
|
if ( SetupGenRandom( &SubAuth1, sizeof(SubAuth1) ) &&
|
|
SetupGenRandom( &SubAuth2, sizeof(SubAuth2) ) &&
|
|
SetupGenRandom( &SubAuth3, sizeof(SubAuth3) ) )
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
#ifdef DBG
|
|
DbgPrint( "New SID: 0x%lx, 0x%lx, 0x%lx\n", SubAuth1, SubAuth2, SubAuth3 );
|
|
#endif
|
|
Status = RtlAllocateAndInitializeSid( &IdentifierAuthority,
|
|
4,
|
|
0x15,
|
|
SubAuth1,
|
|
SubAuth2,
|
|
SubAuth3,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
NewDomainSid );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
GenerateUniqueSid(
|
|
IN DWORD Seed
|
|
)
|
|
|
|
/*++
|
|
===============================================================================
|
|
Routine Description:
|
|
|
|
Generates a (hopefully) unique SID for use by Setup. Setup uses this
|
|
SID as the Domain SID for the Account domain.
|
|
|
|
Use RtlFreeSid() to free the SID allocated by this routine.
|
|
|
|
Arguments:
|
|
|
|
Sid - On return points to the created SID.
|
|
|
|
Return Value:
|
|
|
|
Status code indicating outcome.
|
|
|
|
===============================================================================
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE hKey;
|
|
UNICODE_STRING SidString;
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo = NULL;
|
|
|
|
//
|
|
// Use the same logic as LSASS to generate a unique system SID...
|
|
//
|
|
Status = SetupGenerateRandomDomainSid( &G_NewSid );
|
|
TEST_STATUS_RETURN( "SETUPCL: GenerateUniqueSid - LsapGenerateRandomDomainSid failed!" );
|
|
|
|
//
|
|
// I need to get a text version of the 3 values that make
|
|
// up this SID's uniqueness. This is pretty gross. It turns
|
|
// out that the first 8 characters of the SID string (as gotten
|
|
// from a call to RtlConvertSidtoUnicodeString) are the same
|
|
// for any Domain SID. And it's always the 9th character that
|
|
// starts the 3 unique numbers.
|
|
//
|
|
Status = RtlConvertSidToUnicodeString( &SidString, G_NewSid, TRUE );
|
|
TEST_STATUS_RETURN( "SETUPCL: GenerateUniqueSid - RtlConvertSidToUnicodeString failed!" );
|
|
wcscpy( G_NewSidSubString, &SidString.Buffer[9] );
|
|
|
|
#ifdef DBG
|
|
//
|
|
// Debug spew.
|
|
//
|
|
{
|
|
int i;
|
|
|
|
DbgPrint( "SETUPCL: SetupGenerateUniqueSid - Generated SID:\n" );
|
|
for( i = 0; i < SID_SIZE; i += 4 ) {
|
|
DbgPrint( "%08lx ", *(PULONG)((PUCHAR)(G_NewSid) + i));
|
|
}
|
|
DbgPrint( "\n" );
|
|
|
|
DbgPrint("Generated Sid = %ws \n",SidString.Buffer);
|
|
}
|
|
#endif
|
|
|
|
|
|
RtlFreeUnicodeString( &SidString );
|
|
|
|
if( KeyValueInfo ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, KeyValueInfo );
|
|
KeyValueInfo = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
#ifdef IA64
|
|
|
|
VOID
|
|
CreateNewGuid(
|
|
IN GUID *Guid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a new pseudo GUID.
|
|
|
|
Arguments:
|
|
|
|
Guid - Place holder for the new pseudo
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
if (Guid)
|
|
{
|
|
LARGE_INTEGER Time;
|
|
ULONG Random1 = RtlRandom(&RandomSeed);
|
|
ULONG Random2 = RtlRandom(&RandomSeed);
|
|
|
|
//
|
|
// Get system time
|
|
//
|
|
NtQuerySystemTime(&Time);
|
|
|
|
RtlZeroMemory(Guid, sizeof(GUID));
|
|
|
|
//
|
|
// First 8 bytes is system time
|
|
//
|
|
RtlCopyMemory(Guid, &(Time.QuadPart), sizeof(Time.QuadPart));
|
|
|
|
//
|
|
// Next 8 bytes are two random numbers
|
|
//
|
|
RtlCopyMemory(Guid->Data4, &Random1, sizeof(ULONG));
|
|
|
|
RtlCopyMemory(((PCHAR)Guid->Data4) + sizeof(ULONG),
|
|
&Random2, sizeof(ULONG));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
VOID* MyMalloc(size_t Size)
|
|
{
|
|
return RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, Size );
|
|
}
|
|
|
|
|
|
VOID MyFree(VOID *Memory)
|
|
{
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Memory );
|
|
}
|
|
|
|
NTSTATUS
|
|
GetAndWriteBootEntry(
|
|
IN POS_BOOT_ENTRY pBootEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the boot entry from NVRAM for the given boot entry Id. Construct a filename
|
|
of the form BootXXXX, where XXXX = id. Put the file in the same directory as the
|
|
EFI OS loader. The directory is determined from the LoaderFile string.
|
|
|
|
Arguments:
|
|
|
|
pBootEntry pointer to the POS_BOOT_ENTRY structure
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
Remarks:
|
|
|
|
This was ported from \textmode\kernel\spboot.c on 6/9/2001.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING idStringUnicode;
|
|
WCHAR idStringWChar[9] = {0};
|
|
WCHAR BootEntryPath[MAX_PATH] = {0};
|
|
HANDLE hfile;
|
|
OBJECT_ATTRIBUTES oa;
|
|
IO_STATUS_BLOCK iostatus;
|
|
UCHAR* bootVar = NULL;
|
|
ULONG bootVarSize;
|
|
UNICODE_STRING uFilePath;
|
|
UINT64 BootNumber;
|
|
UINT64 BootSize;
|
|
GUID EfiBootVariablesGuid = EFI_GLOBAL_VARIABLE;
|
|
ULONG Id = 0;
|
|
WCHAR* pwsFilePart = NULL;
|
|
|
|
hfile = NULL;
|
|
|
|
if (NULL == pBootEntry)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
//
|
|
// BootEntryPath = OsLoaderVolumeName + OsLoaderPath
|
|
// OsLoaderVolumeName = "\Device\HarddriveVolume1"
|
|
// OsLoaderPath = "\Efi\Microsoft\Winnt50\ia64ldr.efi"
|
|
// Then Strip off the ia64ldr.efi and replace with BootXXX.
|
|
//
|
|
wcsncpy(BootEntryPath, pBootEntry->OsLoaderVolumeName, AS(BootEntryPath) - 1);
|
|
wcsncpy(BootEntryPath + wcslen(BootEntryPath), pBootEntry->OsLoaderPath, AS(BootEntryPath) - wcslen(BootEntryPath) - 1);
|
|
|
|
//
|
|
// Backup to last backslash before ia64ldr.efi careful of clength
|
|
//
|
|
pwsFilePart = wcsrchr(BootEntryPath, L'\\');
|
|
*(++pwsFilePart) = L'\0';
|
|
|
|
//
|
|
// Id = BootEntry Id
|
|
//
|
|
Id = pBootEntry->Id;
|
|
|
|
//
|
|
// Retrieve the NVRAM entry for the Id specified
|
|
//
|
|
_snwprintf( idStringWChar, AS(idStringWChar) - 1, L"Boot%04x", Id);
|
|
|
|
//
|
|
// Append the BootXXXX
|
|
//
|
|
wcsncpy(BootEntryPath + wcslen(BootEntryPath), idStringWChar, AS(BootEntryPath) - wcslen(BootEntryPath) - 1);
|
|
|
|
DbgPrint("SETUPCL: Writing to NVRBoot file %ws.\n", BootEntryPath);
|
|
|
|
RtlInitUnicodeString( &idStringUnicode, idStringWChar);
|
|
|
|
bootVarSize = 0;
|
|
|
|
status = NtQuerySystemEnvironmentValueEx(&idStringUnicode,
|
|
&EfiBootVariablesGuid,
|
|
NULL,
|
|
&bootVarSize,
|
|
NULL);
|
|
|
|
if (status != STATUS_BUFFER_TOO_SMALL) {
|
|
|
|
ASSERT(FALSE);
|
|
|
|
DbgPrint("SETUPCL: Failed to get size for boot entry buffer.\n");
|
|
|
|
goto Done;
|
|
|
|
} else {
|
|
|
|
bootVar = RtlAllocateHeap(RtlProcessHeap(), 0, bootVarSize);
|
|
if (!bootVar) {
|
|
|
|
status = STATUS_NO_MEMORY;
|
|
|
|
DbgPrint("SETUPCL: Failed to allocate boot entry buffer.\n");
|
|
|
|
goto Done;
|
|
}
|
|
|
|
status = NtQuerySystemEnvironmentValueEx(&idStringUnicode,
|
|
&EfiBootVariablesGuid,
|
|
bootVar,
|
|
&bootVarSize,
|
|
NULL);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
|
|
ASSERT(FALSE);
|
|
|
|
DbgPrint("SETUPCL: Failed to get boot entry.\n");
|
|
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
//
|
|
// open the file
|
|
//
|
|
|
|
INIT_OBJA(&oa, &uFilePath, BootEntryPath);
|
|
|
|
status = NtCreateFile(&hfile,
|
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
|
&oa,
|
|
&iostatus,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OVERWRITE_IF,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
if ( ! NT_SUCCESS(status) ) {
|
|
|
|
DbgPrint("SETUPCL: Failed to create boot entry recovery file %lx.\n", status);
|
|
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Write the bits to disk using the format required
|
|
// by base/efiutil/efinvram/savrstor.c
|
|
//
|
|
// [BootNumber][BootSize][BootEntry (of BootSize)]
|
|
//
|
|
|
|
//
|
|
// build the header info for the boot entry block
|
|
//
|
|
|
|
// [header] include the boot id
|
|
BootNumber = Id;
|
|
status = NtWriteFile( hfile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iostatus,
|
|
&BootNumber,
|
|
sizeof(BootNumber),
|
|
NULL,
|
|
NULL
|
|
);
|
|
if ( ! NT_SUCCESS(status) ) {
|
|
|
|
DbgPrint("SETUPCL: Failed writing boot number to boot entry recovery file.\n");
|
|
|
|
goto Done;
|
|
}
|
|
|
|
// [header] include the boot size
|
|
BootSize = bootVarSize;
|
|
status = NtWriteFile( hfile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iostatus,
|
|
&BootSize,
|
|
sizeof(BootSize),
|
|
NULL,
|
|
NULL
|
|
);
|
|
if ( ! NT_SUCCESS(status) ) {
|
|
|
|
DbgPrint("SETUPCL: Failed writing boot entry size to boot entry recovery file.\n");
|
|
|
|
goto Done;
|
|
}
|
|
|
|
// boot entry bits
|
|
status = NtWriteFile( hfile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iostatus,
|
|
bootVar,
|
|
bootVarSize,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if ( ! NT_SUCCESS(status) ) {
|
|
|
|
DbgPrint("SETUPCL: Failed writing boot entry to boot entry recovery file.\n");
|
|
|
|
goto Done;
|
|
}
|
|
|
|
Done:
|
|
|
|
//
|
|
// We are done
|
|
//
|
|
|
|
if (bootVar) {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, bootVar);
|
|
}
|
|
if (hfile) {
|
|
NtClose( hfile );
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ResetDiskGuids(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
SYSTEM_DEVICE_INFORMATION sdi;
|
|
ULONG iDrive;
|
|
|
|
// Clean up the memory
|
|
//
|
|
RtlZeroMemory(&sdi, sizeof(sdi));
|
|
|
|
// Query the number of physical devices on the system
|
|
//
|
|
Status = NtQuerySystemInformation(SystemDeviceInformation, &sdi, sizeof(SYSTEM_DEVICE_INFORMATION), NULL);
|
|
|
|
// We successfully queried the devices and there are devices there
|
|
//
|
|
if ( NT_SUCCESS(Status) && sdi.NumberOfDisks)
|
|
{
|
|
POS_BOOT_OPTIONS pBootOptions = NULL;
|
|
POS_BOOT_OPTIONS pBootOptionsInitial = NULL;
|
|
POS_BOOT_ENTRY pBootEntry = NULL;
|
|
|
|
DbgPrint("Successfully queried (%lx) disks.\n", sdi.NumberOfDisks);
|
|
|
|
// Initialize the library with our own memory management functions
|
|
//
|
|
if ( OSBOLibraryInit(MyMalloc, MyFree) )
|
|
{
|
|
// Determine initial BootOptions
|
|
//
|
|
pBootOptions = EFIOSBOCreate();
|
|
pBootOptionsInitial = EFIOSBOCreate();
|
|
|
|
// Were we able to create the BootOptions
|
|
//
|
|
if ( pBootOptions && pBootOptionsInitial )
|
|
{
|
|
// Iterate through each disk and determine the GUID
|
|
//
|
|
for ( iDrive = 0; iDrive < sdi.NumberOfDisks && NT_SUCCESS(Status); iDrive++ )
|
|
{
|
|
WCHAR szPhysicalDrives[MAX_PATH] = {0};
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE DiskHandle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
// Generate the path to the drive
|
|
//
|
|
_snwprintf(szPhysicalDrives, AS(szPhysicalDrives) - 1, L"\\Device\\Harddisk%d\\Partition0", iDrive);
|
|
|
|
// Initialize the handle to unicode string
|
|
//
|
|
INIT_OBJA(&Obja,&UnicodeString,szPhysicalDrives);
|
|
|
|
// Attempt to open the file
|
|
//
|
|
Status = NtCreateFile( &DiskHandle,
|
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
0,
|
|
NULL,
|
|
0 );
|
|
|
|
// Check to see if we were able to open the disk
|
|
//
|
|
if ( !NT_SUCCESS(Status) )
|
|
{
|
|
DbgPrint("Unable to open file on %ws. Error (%lx)\n", szPhysicalDrives, Status);
|
|
}
|
|
else
|
|
{
|
|
PDRIVE_LAYOUT_INFORMATION_EX pLayoutInfoEx = NULL;
|
|
ULONG lengthLayoutEx = 0,
|
|
iPart;
|
|
|
|
DbgPrint("Successfully opened file on %ws\n", szPhysicalDrives);
|
|
|
|
lengthLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX) * 128);
|
|
pLayoutInfoEx = (PDRIVE_LAYOUT_INFORMATION_EX) MyMalloc( lengthLayoutEx );
|
|
if ( pLayoutInfoEx )
|
|
{
|
|
// Attempt to get the drive layout
|
|
//
|
|
Status = NtDeviceIoControlFile( DiskHandle, 0, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, pLayoutInfoEx, lengthLayoutEx );
|
|
|
|
// Check the status of the drive layout
|
|
//
|
|
if ( !NT_SUCCESS(Status) )
|
|
DbgPrint("Unable to open IOCTL on %ws. Error (%lx)\n", szPhysicalDrives, Status);
|
|
else
|
|
{
|
|
DbgPrint("Opened IOCTL on drive %ws. Error (%lx)\n", szPhysicalDrives, Status);
|
|
DbgPrint("\tPhysical Disk %d\n", iDrive);
|
|
DbgPrint("\tPartition Count: %d\n", pLayoutInfoEx->PartitionCount);
|
|
|
|
// Iterate through each partition
|
|
//
|
|
for (iPart = 0; iPart < pLayoutInfoEx->PartitionCount; iPart++)
|
|
{
|
|
// We only would like to deal with GPT partitions
|
|
//
|
|
if ( pLayoutInfoEx->PartitionEntry[iPart].PartitionStyle == PARTITION_STYLE_GPT )
|
|
{
|
|
const UUID GuidNull = { 0 };
|
|
#ifdef DBG
|
|
UNICODE_STRING cGuid;
|
|
UNICODE_STRING cGuidNew;
|
|
#endif
|
|
// Only replace the Guid if it's NULL.
|
|
//
|
|
if (IsEqualGUID(&(pLayoutInfoEx->PartitionEntry[iPart].Gpt.PartitionId), &GuidNull))
|
|
{
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - CreateNewGuid expects GUID structure. Possible mismatch?
|
|
//
|
|
// (acosma 2002/04/24) Fix this issue in Longhorn. UUID is typedef to GUID or the
|
|
// other way around so they are the same thing, however for readability we will fix this.
|
|
//
|
|
UUID Guid;
|
|
|
|
// Create a new GUID for this machine
|
|
//
|
|
CreateNewGuid(&Guid);
|
|
#ifdef DBG
|
|
if ( NT_SUCCESS( RtlStringFromGUID((LPGUID) &(pLayoutInfoEx->PartitionEntry[iPart].Gpt.PartitionId), &cGuid) ) )
|
|
{
|
|
if ( NT_SUCCESS( RtlStringFromGUID((LPGUID) &Guid, &cGuidNew) ) )
|
|
{
|
|
DbgPrint("\tPartition: %ws (%x), %ws %ws\n",
|
|
pLayoutInfoEx->PartitionEntry[iPart].Gpt.Name, iPart, cGuid.Buffer, cGuidNew.Buffer);
|
|
|
|
RtlFreeUnicodeString(&cGuidNew);
|
|
}
|
|
RtlFreeUnicodeString(&cGuid);
|
|
}
|
|
#endif
|
|
|
|
// This is a struct to struct assignment. It is legal in C.
|
|
//
|
|
pLayoutInfoEx->PartitionEntry[iPart].Gpt.PartitionId = Guid;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_STATUS("SETUPCL: ResetDiskGuids - Failed to reset Disk Guids.");
|
|
|
|
if ( NT_SUCCESS( Status = NtDeviceIoControlFile( DiskHandle, 0, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, pLayoutInfoEx, lengthLayoutEx, NULL, 0 ) ) )
|
|
{
|
|
DbgPrint("\tSuccessfully reset %ws\n", szPhysicalDrives);
|
|
}
|
|
|
|
//
|
|
// Free the layout info buffer...
|
|
//
|
|
MyFree( pLayoutInfoEx );
|
|
}
|
|
|
|
// Clean up the memory
|
|
//
|
|
NtClose( DiskHandle );
|
|
}
|
|
}
|
|
|
|
// Delete the old boot entries and recreate them so we pick up the new GUIDS if they changed.
|
|
//
|
|
if ( NT_SUCCESS(Status) )
|
|
{
|
|
POS_BOOT_ENTRY pActiveBootEntry = NULL;
|
|
DWORD dwBootEntryCount = OSBOGetBootEntryCount(pBootOptionsInitial);
|
|
|
|
DbgPrint("SETUPCL: ResetDiskGuids - Updating boot entries to use new GUIDS.\n");
|
|
|
|
if (dwBootEntryCount)
|
|
{
|
|
ULONG Index;
|
|
BOOL bSetActive = FALSE;
|
|
|
|
// Get the current boot entry
|
|
//
|
|
pActiveBootEntry = OSBOGetActiveBootEntry(pBootOptionsInitial);
|
|
pBootEntry = OSBOGetFirstBootEntry(pBootOptionsInitial, &Index);
|
|
|
|
while ( pBootEntry )
|
|
{
|
|
// Don't set the current entry active by default.
|
|
//
|
|
bSetActive = FALSE;
|
|
|
|
if ( OSBE_IS_WINDOWS(pBootEntry) )
|
|
{
|
|
POS_BOOT_ENTRY pBootEntryToDelete = NULL;
|
|
WCHAR FriendlyName[MAX_PATH],
|
|
OsLoaderVolumeName[MAX_PATH],
|
|
OsLoaderPath[MAX_PATH],
|
|
BootVolumeName[MAX_PATH],
|
|
BootPath[MAX_PATH],
|
|
OsLoadOptions[MAX_PATH];
|
|
|
|
// Load the boot entry parameters into their own buffer
|
|
//
|
|
memset(FriendlyName, 0, AS(FriendlyName));
|
|
memset(OsLoaderVolumeName, 0, AS(OsLoaderVolumeName));
|
|
memset(OsLoaderPath, 0, AS(OsLoaderPath));
|
|
memset(BootVolumeName, 0, AS(BootVolumeName));
|
|
memset(BootPath, 0, AS(BootPath));
|
|
memset(OsLoadOptions, 0, AS(OsLoadOptions));
|
|
|
|
wcsncpy(FriendlyName, OSBEGetFriendlyName(pBootEntry), AS(FriendlyName) - 1);
|
|
wcsncpy(OsLoaderVolumeName, OSBEGetOsLoaderVolumeName(pBootEntry), AS(OsLoaderVolumeName) - 1);
|
|
wcsncpy(OsLoaderPath, OSBEGetOsLoaderPath(pBootEntry), AS(OsLoaderPath) - 1);
|
|
wcsncpy(BootVolumeName, OSBEGetBootVolumeName(pBootEntry), AS(BootVolumeName) - 1);
|
|
wcsncpy(BootPath, OSBEGetBootPath(pBootEntry), AS(BootPath) - 1);
|
|
wcsncpy(OsLoadOptions, OSBEGetOsLoadOptions(pBootEntry), AS(OsLoadOptions) - 1);
|
|
|
|
// If this is the active boot entry set active the new boot entry that we are going to create.
|
|
//
|
|
if ( pBootEntry == pActiveBootEntry )
|
|
{
|
|
bSetActive = TRUE;
|
|
}
|
|
|
|
if ( ( pBootEntryToDelete = OSBOFindBootEntry(pBootOptions, pBootEntry->Id) ) &&
|
|
OSBODeleteBootEntry(pBootOptions, pBootEntryToDelete) )
|
|
{
|
|
POS_BOOT_ENTRY pBootEntryNew = NULL;
|
|
|
|
pBootEntryNew = OSBOAddNewBootEntry(pBootOptions,
|
|
FriendlyName,
|
|
OsLoaderVolumeName,
|
|
OsLoaderPath,
|
|
BootVolumeName,
|
|
BootPath,
|
|
OsLoadOptions);
|
|
if ( pBootEntryNew )
|
|
{
|
|
if ( bSetActive )
|
|
{
|
|
OSBOSetActiveBootEntry(pBootOptions, pBootEntryNew);
|
|
}
|
|
|
|
// Update the NVRBoot file
|
|
//
|
|
GetAndWriteBootEntry(pBootEntryNew);
|
|
|
|
// Flush out the boot options
|
|
//
|
|
OSBEFlush(pBootEntryNew);
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("SETUPCL: ResetDiskGuids - Failed to add a boot entry [%ws]\n", FriendlyName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("SETUPCL: ResetDiskGuids - Failed to delete a boot entry [%ws]\n", FriendlyName);
|
|
}
|
|
}
|
|
|
|
// Get the next entry.
|
|
//
|
|
pBootEntry = OSBOGetNextBootEntry(pBootOptionsInitial, &Index);
|
|
}
|
|
}
|
|
|
|
// Flush the boot options if we've changed GUIDS.
|
|
//
|
|
OSBOFlush(pBootOptions);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("SETUPCL: ResetDiskGuids - Failed to load the existing boot entries.\n");
|
|
}
|
|
|
|
//
|
|
// Free the boot option structures.
|
|
//
|
|
if ( pBootOptions )
|
|
{
|
|
OSBODelete(pBootOptions);
|
|
}
|
|
|
|
if ( pBootOptionsInitial )
|
|
{
|
|
OSBODelete(pBootOptionsInitial);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("SETUPCL: ResetDiskGuids - Failed to initialize the boot options library.\n");
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
#endif \\ #ifdef IA64
|
|
|
|
// This function always deletes a CRLF from the end of the string. It assumes that there
|
|
// is a CRLF at the end of the line and just removes the last two characters.
|
|
//
|
|
void OutputString(LPTSTR szMsg)
|
|
{
|
|
UNICODE_STRING uMsg;
|
|
RtlInitUnicodeString(&uMsg, szMsg);
|
|
|
|
// Whack the CRLF at the end of the string. Doing this here for performance reasons.
|
|
// Don't want to put this in DisplayUI().
|
|
//
|
|
if (uMsg.Length > ( 2 * sizeof(WCHAR)) )
|
|
{
|
|
uMsg.Length -= (2 * sizeof(WCHAR));
|
|
uMsg.Buffer[uMsg.Length / sizeof(WCHAR)] = 0; // UNICODE_NULL
|
|
}
|
|
NtDisplayString(&uMsg);
|
|
}
|
|
|
|
// Keep this function as short as possible. This gets called a lot in the recursive functions of setupcl.
|
|
// Do not create any stack based variables here for performance reasons.
|
|
//
|
|
__inline void DisplayUI()
|
|
{
|
|
NtQuerySystemTime(&CurrentTime);
|
|
|
|
if ( !bDisplayUI )
|
|
{
|
|
if ( (CurrentTime.QuadPart - StartTime.QuadPart) > UITIME )
|
|
{
|
|
static UNICODE_STRING UnicodeString = { 0 };
|
|
bDisplayUI = TRUE;
|
|
LastDotTime.QuadPart = CurrentTime.QuadPart;
|
|
|
|
if ( LoadStringResource(&UnicodeString, IDS_UIMAIN) )
|
|
{
|
|
OutputString(UnicodeString.Buffer);
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{ // If more than 3 seconds passed since our last output put up a dot.
|
|
//
|
|
if ( (CurrentTime.QuadPart - LastDotTime.QuadPart) > UIDOTTIME )
|
|
{
|
|
LastDotTime.QuadPart = CurrentTime.QuadPart;
|
|
OutputString(TEXT("."));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int __cdecl
|
|
main(
|
|
int argc,
|
|
char** argv,
|
|
char** envp,
|
|
ULONG DebugParameter
|
|
)
|
|
/*++
|
|
===============================================================================
|
|
Routine Description:
|
|
|
|
This routine is the main entry point for the program.
|
|
|
|
We do a bit of error checking, then, if all goes well, we update the
|
|
registry to enable execution of our second half.
|
|
|
|
===============================================================================
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN b;
|
|
int i;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER Time;
|
|
|
|
//
|
|
// Get Time for seed generation...
|
|
//
|
|
NtQuerySystemTime(&Time);
|
|
|
|
#ifdef IA64
|
|
|
|
// Setup the Seed for generating GUIDs
|
|
//
|
|
RandomSeed = (ULONG) Time.LowPart;
|
|
|
|
|
|
#endif
|
|
|
|
// Initialize the StartTime
|
|
//
|
|
StartTime.QuadPart = Time.QuadPart;
|
|
LastDotTime.QuadPart = Time.QuadPart;
|
|
|
|
i = 0;
|
|
//
|
|
// Enable several privileges that we will need.
|
|
//
|
|
//
|
|
// NTRAID#NTBUG9-545904-2002/02/26-brucegr,jcohen - Do something smarter with regard to error conditions.
|
|
//
|
|
Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE,TRUE,FALSE,&b);
|
|
TEST_STATUS( "SETUPCL: Warning - unable to enable SE_BACKUP_PRIVILEGE privilege!" );
|
|
|
|
Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,TRUE,FALSE,&b);
|
|
TEST_STATUS( "SETUPCL: Warning - unable to enable SE_RESTORE_PRIVILEGE privilege!" );
|
|
|
|
Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,TRUE,FALSE,&b);
|
|
TEST_STATUS( "SETUPCL: Warning - unable to enable SE_SHUTDOWN_PRIVILEGE privilege!" );
|
|
|
|
Status = RtlAdjustPrivilege(SE_TAKE_OWNERSHIP_PRIVILEGE,TRUE,FALSE,&b);
|
|
TEST_STATUS( "SETUPCL: Warning - unable to enable SE_TAKE_OWNERSHIP_PRIVILEGE privilege!" );
|
|
|
|
Status = RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE,TRUE,FALSE,&b);
|
|
TEST_STATUS( "SETUPCL: Warning - unable to enable SE_SECURITY_PRIVILEGE privilege!" );
|
|
|
|
Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE,TRUE,FALSE,&b);
|
|
TEST_STATUS( "SETUPCL: Warning - unable to enable SE_TCB_PRIVILEGE privilege!" );
|
|
|
|
|
|
#ifdef IA64
|
|
//
|
|
// Reset the Disk GUIDs.
|
|
//
|
|
DbgPrint("We are currently running on IA64. Resetting disk GUIDs.\n");
|
|
|
|
//
|
|
// ISSUE-2002/02/26-brucegr,jcohen - Error code isn't tested!
|
|
//
|
|
ResetDiskGuids();
|
|
#endif
|
|
|
|
//
|
|
// Retrieve old Security ID.
|
|
//
|
|
Status = RetrieveOldSid( );
|
|
TEST_STATUS_RETURN( "SETUPCL: Retrieval of old SID failed!" );
|
|
|
|
//
|
|
// Generate a new Security ID.
|
|
//
|
|
//
|
|
// NTRAID#NTBUG9-545855-2002/02/26-brucegr,jcohen - Use same sid generation algorithm as LsapGenerateRandomDomainSid
|
|
// in ds\security\base\lsa\server\dspolicy\dbinit.c
|
|
//
|
|
Status = GenerateUniqueSid( Time.LowPart );
|
|
TEST_STATUS_RETURN( "SETUPCL: Generation of new SID failed!" );
|
|
|
|
//
|
|
// Make a copy of the repair hives.
|
|
//
|
|
Status = BackupRepairHives();
|
|
if( NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// Do the repair hives.
|
|
//
|
|
Status = ProcessRepairHives();
|
|
TEST_STATUS( "SETUPCL: Failed to update one of the Repair hives." );
|
|
}
|
|
//
|
|
// Decide if we need to restore the repair hives from our backups.
|
|
//
|
|
CleanupRepairHives( Status );
|
|
|
|
//
|
|
// Now process the hives, one at a time.
|
|
//
|
|
//
|
|
// NTRAID#NTBUG9-545904-2002/02/26-brucegr,jcohen - Do something smarter with regard to error conditions.
|
|
//
|
|
Status = ProcessHives();
|
|
|
|
//
|
|
// NTRAID#NTBUG9-545904-2002/02/26-brucegr,jcohen - Do something smarter with regard to error conditions.
|
|
//
|
|
Status = FinalHiveCleanup();
|
|
|
|
//
|
|
// Now go enumerate all the drives. For each NTFS drive,
|
|
// we'll whack the ACL to reflect the new SID.
|
|
//
|
|
//
|
|
// NTRAID#NTBUG9-545904-2002/02/26-brucegr,jcohen - Do something smarter with regard to error conditions.
|
|
//
|
|
Status = EnumerateDrives();
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Disable the DbgPrint for non-debug builds
|
|
//
|
|
#ifndef DBG
|
|
void DbgPrintSub(char *szBuffer, ...)
|
|
{
|
|
return;
|
|
}
|
|
#endif |