windows-nt/Source/XPSP1/NT/base/ntsetup/opktools/setupcl/setupcl.c

1923 lines
61 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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