1142 lines
28 KiB
C
1142 lines
28 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
usetup.c
|
||
|
||
Abstract:
|
||
|
||
User-mode text-setup process.
|
||
|
||
Author:
|
||
|
||
Ted Miller (tedm) 29-July-1993
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <ntdddisk.h>
|
||
#include <fmifs.h>
|
||
#include <setupdd.h>
|
||
|
||
|
||
HANDLE hEventRequestReady,hEventRequestServiced;
|
||
SETUP_COMMUNICATION Communication;
|
||
|
||
//
|
||
// Global variables (global to the module) used by the functions
|
||
// that set a security descriptor to a file.
|
||
//
|
||
BOOLEAN _SecurityDescriptorInitialized = FALSE;
|
||
SECURITY_DESCRIPTOR _SecurityDescriptor;
|
||
PSID _WorldSid;
|
||
PSID _SystemSid;
|
||
|
||
|
||
BOOLEAN
|
||
uSpInitializeDefaultSecurityDescriptor(
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build the security descriptor that will be set in the files, that
|
||
contain bogus security descriptor.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - Returns TRUE if the security descriptor was successfully
|
||
initialized. Returns FALSE otherwise.
|
||
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
NTSTATUS NtStatus;
|
||
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
||
CHAR Acl[256]; // 256 is more than big enough
|
||
ULONG AclLength=256;
|
||
SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
|
||
|
||
//
|
||
// Create the SIDs for World and System
|
||
//
|
||
|
||
NtStatus = RtlAllocateAndInitializeSid( &WorldSidAuthority,
|
||
1,
|
||
SECURITY_WORLD_RID,
|
||
0, 0, 0, 0, 0, 0, 0,
|
||
&_WorldSid
|
||
);
|
||
|
||
if ( !NT_SUCCESS( NtStatus )) {
|
||
KdPrint(( "uSETUP: Unable to allocate and initialize SID %x \n", NtStatus ));
|
||
return( FALSE );
|
||
}
|
||
|
||
NtStatus = RtlAllocateAndInitializeSid( &SystemSidAuthority,
|
||
1,
|
||
SECURITY_LOCAL_SYSTEM_RID,
|
||
0, 0, 0, 0, 0, 0, 0,
|
||
&_SystemSid
|
||
);
|
||
|
||
if ( !NT_SUCCESS( NtStatus )) {
|
||
KdPrint(( "uSETUP: Unable to allocate and initialize SID, status = %x \n", NtStatus ));
|
||
RtlFreeSid( _WorldSid );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// Create the ACL
|
||
//
|
||
|
||
NtStatus = RtlCreateAcl( (PACL)Acl,
|
||
AclLength,
|
||
ACL_REVISION2
|
||
);
|
||
|
||
if ( !NT_SUCCESS( NtStatus )) {
|
||
KdPrint(( "uSETUP: Unable to create Acl, status = %x \n", NtStatus ));
|
||
RtlFreeSid( _WorldSid );
|
||
RtlFreeSid( _SystemSid );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// Copy the World SID into the ACL
|
||
//
|
||
NtStatus = RtlAddAccessAllowedAce( (PACL)Acl,
|
||
ACL_REVISION2,
|
||
GENERIC_ALL,
|
||
_WorldSid
|
||
);
|
||
|
||
if ( !NT_SUCCESS( NtStatus )) {
|
||
KdPrint(( "uSETUP: Unable to add Access Allowed Ace to Acl, status = %x \n", NtStatus ));
|
||
RtlFreeSid( _WorldSid );
|
||
RtlFreeSid( _SystemSid );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// Sid has been copied into the ACL
|
||
//
|
||
// RtlFreeSid( WorldSid );
|
||
|
||
//
|
||
// Create and initialize the security descriptor
|
||
//
|
||
|
||
NtStatus = RtlCreateSecurityDescriptor( &_SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
|
||
|
||
if ( !NT_SUCCESS( NtStatus )) {
|
||
KdPrint(( "uSETUP: Unable to create security descriptor, status = %x \n", NtStatus ));
|
||
RtlFreeSid( _WorldSid );
|
||
RtlFreeSid( _SystemSid );
|
||
return( FALSE );
|
||
}
|
||
|
||
NtStatus = RtlSetDaclSecurityDescriptor ( &_SecurityDescriptor,
|
||
TRUE,
|
||
(PACL)Acl,
|
||
FALSE
|
||
);
|
||
if ( !NT_SUCCESS( NtStatus )) {
|
||
KdPrint(( "uSETUP: Unable to set Acl to _SecurityDescriptor, status = %x \n", NtStatus ));
|
||
RtlFreeSid( _WorldSid );
|
||
RtlFreeSid( _SystemSid );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// Copy the owner into the security descriptor
|
||
//
|
||
NtStatus = RtlSetOwnerSecurityDescriptor( &_SecurityDescriptor,
|
||
_SystemSid,
|
||
FALSE );
|
||
|
||
// RtlFreeSid( SystemSid );
|
||
|
||
if ( !NT_SUCCESS( NtStatus )) {
|
||
KdPrint(( "uSETUP: Unable to set Owner to _SecurityDescriptor, status = %x \n", NtStatus ));
|
||
RtlFreeSid( _WorldSid );
|
||
RtlFreeSid( _SystemSid );
|
||
return( FALSE );
|
||
}
|
||
_SecurityDescriptorInitialized = TRUE;
|
||
return( TRUE );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
uSpSetFileSecurity(
|
||
PWSTR FileName,
|
||
SECURITY_INFORMATION SecurityInformation,
|
||
PSECURITY_DESCRIPTOR pSecurityDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets the security of a file.
|
||
It is based on the Win32 API SetFileSecurity.
|
||
This API can be used to set the security of a file or directory
|
||
(process, file, event, etc.). This call is only successful if the
|
||
following conditions are met:
|
||
|
||
o If the object's owner or group is to be set, the caller must
|
||
have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.
|
||
|
||
o If the object's DACL is to be set, the caller must have
|
||
WRITE_DAC permission or be the object's owner.
|
||
|
||
o If the object's SACL is to be set, the caller must have
|
||
SeSecurityPrivilege.
|
||
|
||
Arguments:
|
||
|
||
lpFileName - Supplies the file name of the file whose security
|
||
is to be set.
|
||
|
||
SecurityInformation - A pointer to information describing the
|
||
contents of the Security Descriptor.
|
||
|
||
pSecurityDescriptor - A pointer to a well formed Security
|
||
Descriptor.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - An NT status code indcating the result of the operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
HANDLE FileHandle;
|
||
ACCESS_MASK DesiredAccess;
|
||
|
||
OBJECT_ATTRIBUTES Obja;
|
||
UNICODE_STRING UnicodeFileName;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
||
|
||
DesiredAccess = 0;
|
||
|
||
if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
|
||
(SecurityInformation & GROUP_SECURITY_INFORMATION) ) {
|
||
DesiredAccess |= WRITE_OWNER;
|
||
}
|
||
|
||
if (SecurityInformation & DACL_SECURITY_INFORMATION) {
|
||
DesiredAccess |= WRITE_DAC;
|
||
}
|
||
|
||
if (SecurityInformation & SACL_SECURITY_INFORMATION) {
|
||
DesiredAccess |= ACCESS_SYSTEM_SECURITY;
|
||
}
|
||
|
||
RtlInitUnicodeString( &UnicodeFileName,
|
||
FileName );
|
||
|
||
InitializeObjectAttributes(
|
||
&Obja,
|
||
&UnicodeFileName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
Status = NtOpenFile(
|
||
&FileHandle,
|
||
DesiredAccess,
|
||
&Obja,
|
||
&IoStatusBlock,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||
0
|
||
);
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
Status = NtSetSecurityObject(
|
||
FileHandle,
|
||
SecurityInformation,
|
||
pSecurityDescriptor
|
||
);
|
||
|
||
NtClose(FileHandle);
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
uSpSetDefaultFileSecurity(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Set a default security descriptor onto a file.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PWSTR FileName;
|
||
PSERVICE_DEFAULT_FILE_SECURITY Params = (PSERVICE_DEFAULT_FILE_SECURITY)Communication.Buffer;
|
||
|
||
FileName = Params->FileName;
|
||
|
||
if( !_SecurityDescriptorInitialized ) {
|
||
Status = uSpInitializeDefaultSecurityDescriptor();
|
||
if( !NT_SUCCESS( Status ) ) {
|
||
KdPrint(( "uSETUP: Unable to initialize default security descriptor. Status = %x \n", Status ));
|
||
return( Status );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Attempt to write the DACL
|
||
//
|
||
Status = uSpSetFileSecurity( FileName,
|
||
DACL_SECURITY_INFORMATION,
|
||
&_SecurityDescriptor );
|
||
|
||
if( !NT_SUCCESS( Status ) ) {
|
||
|
||
//
|
||
// Make the system the owner of the file
|
||
//
|
||
Status = uSpSetFileSecurity( FileName,
|
||
OWNER_SECURITY_INFORMATION,
|
||
&_SecurityDescriptor );
|
||
#if DBG
|
||
if( !NT_SUCCESS( Status ) ) {
|
||
KdPrint(( "uSETUP: Unable to set file OWNER. Status = %x \n", Status ));
|
||
}
|
||
#endif
|
||
|
||
if( NT_SUCCESS( Status ) ) {
|
||
|
||
//
|
||
// Write the DACL to the file
|
||
//
|
||
Status = uSpSetFileSecurity( FileName,
|
||
DACL_SECURITY_INFORMATION,
|
||
&_SecurityDescriptor );
|
||
#if DBG
|
||
if( !NT_SUCCESS( Status ) ) {
|
||
KdPrint(( "uSETUP: Unable to set file DACL. Status = %x \n", Status ));
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
return( Status );
|
||
}
|
||
|
||
NTSTATUS
|
||
uSpVerifyFileAccess(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check whether or not the security descriptor set in a file allows
|
||
textmode setup to perform some file operation. If textmode setup
|
||
is not allowed to open the file for certain accesses, we assume
|
||
that the security information in the file is not valid.
|
||
|
||
Arguments:
|
||
|
||
FileName - Full path to the file to be examined
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS -
|
||
|
||
--*/
|
||
{
|
||
ACCESS_MASK DesiredAccess;
|
||
HANDLE FileHandle;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
NTSTATUS Status;
|
||
UNICODE_STRING UnicodeFileName;
|
||
PWSTR FileName;
|
||
PSERVICE_VERIFY_FILE_ACCESS Params = (PSERVICE_VERIFY_FILE_ACCESS)Communication.Buffer;
|
||
|
||
FileName = Params->FileName;
|
||
|
||
|
||
DesiredAccess = Params->DesiredAccess;
|
||
|
||
RtlInitUnicodeString( &UnicodeFileName,
|
||
FileName );
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes,
|
||
&UnicodeFileName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL );
|
||
|
||
|
||
Status = NtOpenFile( &FileHandle,
|
||
DesiredAccess,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
0,
|
||
FILE_SYNCHRONOUS_IO_NONALERT );
|
||
|
||
if( NT_SUCCESS( Status ) ) {
|
||
NtClose( FileHandle );
|
||
}
|
||
|
||
#if DBG
|
||
if( !NT_SUCCESS( Status ) ) {
|
||
KdPrint( ("uSETUP: NtOpenFile() failed. File = %ls, Status = %x\n",FileName, Status ) );
|
||
}
|
||
#endif
|
||
return( Status );
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
uSpLoadKbdLayoutDll(
|
||
VOID
|
||
)
|
||
{
|
||
UNICODE_STRING DllNameU;
|
||
PSERVICE_LOAD_KBD_LAYOUT_DLL Params = (PSERVICE_LOAD_KBD_LAYOUT_DLL)Communication.Buffer;
|
||
NTSTATUS Status;
|
||
PVOID DllBaseAddress;
|
||
PVOID (*RoutineAddress)(VOID);
|
||
|
||
RtlInitUnicodeString(&DllNameU,Params->DllName);
|
||
|
||
Status = LdrLoadDll(NULL,NULL,&DllNameU,&DllBaseAddress);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to load dll %ws (%lx)\n",Params->DllName,Status));
|
||
return(Status);
|
||
}
|
||
|
||
Status = LdrGetProcedureAddress(DllBaseAddress,NULL,1,(PVOID)&RoutineAddress);
|
||
if(NT_SUCCESS(Status)) {
|
||
Params->TableAddress = (*RoutineAddress)();
|
||
} else {
|
||
KdPrint(("uSETUP: Unable to get address of proc 1 from dll %ws (%lx)\n",Params->DllName,Status));
|
||
LdrUnloadDll(DllBaseAddress);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
uSpExecuteImage(
|
||
VOID
|
||
)
|
||
{
|
||
UNICODE_STRING CommandLineU,ImagePathU,CurrentDirectoryU;
|
||
PSERVICE_EXECUTE Params = (PSERVICE_EXECUTE)Communication.Buffer;
|
||
NTSTATUS Status;
|
||
RTL_USER_PROCESS_INFORMATION ProcessInformation;
|
||
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
||
WCHAR Env[2] = { 0,0 };
|
||
PROCESS_BASIC_INFORMATION BasicInformation;
|
||
|
||
//
|
||
// Initialize unicode strings.
|
||
//
|
||
RtlInitUnicodeString(&CommandLineU,Params->CommandLine);
|
||
RtlInitUnicodeString(&ImagePathU,Params->FullImagePath);
|
||
RtlInitUnicodeString(&CurrentDirectoryU,L"\\");
|
||
|
||
//
|
||
// Create process parameters.
|
||
//
|
||
Status = RtlCreateProcessParameters(
|
||
&ProcessParameters,
|
||
&ImagePathU,
|
||
NULL,
|
||
&CurrentDirectoryU,
|
||
&CommandLineU,
|
||
Env,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to create process params for %ws (%lx)\n",Params->FullImagePath,Status));
|
||
return(Status);
|
||
}
|
||
|
||
ProcessParameters->DebugFlags = 0;
|
||
|
||
//
|
||
// Create the user process.
|
||
//
|
||
ProcessInformation.Length = sizeof(RTL_USER_PROCESS_INFORMATION);
|
||
Status = RtlCreateUserProcess(
|
||
&ImagePathU,
|
||
OBJ_CASE_INSENSITIVE,
|
||
ProcessParameters,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
FALSE,
|
||
NULL,
|
||
NULL,
|
||
&ProcessInformation
|
||
);
|
||
|
||
RtlDestroyProcessParameters(ProcessParameters);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to create user process %ws (%lx)\n",Params->FullImagePath,Status));
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// Make sure the image is a native NT image.
|
||
//
|
||
if(ProcessInformation.ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_NATIVE) {
|
||
|
||
KdPrint(("uSETUP: %ws is not an NT image\n",Params->FullImagePath));
|
||
NtTerminateProcess(ProcessInformation.Process,STATUS_INVALID_IMAGE_FORMAT);
|
||
NtWaitForSingleObject(ProcessInformation.Thread,FALSE,NULL);
|
||
NtClose(ProcessInformation.Thread);
|
||
NtClose(ProcessInformation.Process);
|
||
return(STATUS_INVALID_IMAGE_FORMAT);
|
||
}
|
||
|
||
//
|
||
// Start the process going.
|
||
//
|
||
Status = NtResumeThread(ProcessInformation.Thread,NULL);
|
||
|
||
//
|
||
// Wait for the process to finish.
|
||
//
|
||
NtWaitForSingleObject(ProcessInformation.Process,FALSE,NULL);
|
||
|
||
//
|
||
// Get process return status
|
||
//
|
||
Status = NtQueryInformationProcess(
|
||
ProcessInformation.Process,
|
||
ProcessBasicInformation,
|
||
&BasicInformation,
|
||
sizeof(BasicInformation),
|
||
NULL
|
||
);
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
Params->ReturnStatus = BasicInformation.ExitStatus;
|
||
}
|
||
|
||
//
|
||
// Clean up and return.
|
||
//
|
||
NtClose(ProcessInformation.Thread);
|
||
NtClose(ProcessInformation.Process);
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
uSpDeleteKey(
|
||
VOID
|
||
)
|
||
{
|
||
UNICODE_STRING KeyName;
|
||
OBJECT_ATTRIBUTES Obja;
|
||
HANDLE hKey;
|
||
NTSTATUS Status;
|
||
|
||
|
||
PSERVICE_DELETE_KEY Params = (PSERVICE_DELETE_KEY)Communication.Buffer;
|
||
|
||
//
|
||
// Initialize unicode strings and object attributes.
|
||
//
|
||
RtlInitUnicodeString(&KeyName,Params->Key);
|
||
InitializeObjectAttributes(
|
||
&Obja,
|
||
&KeyName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
Params->KeyRootDirectory,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Open the key and delete it
|
||
//
|
||
|
||
Status = NtOpenKey(&hKey,KEY_ALL_ACCESS,&Obja);
|
||
if(NT_SUCCESS(Status)) {
|
||
Status = NtDeleteKey(hKey);
|
||
NtClose(hKey);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
NTSTATUS
|
||
uSpQueryDirectoryObject(
|
||
VOID
|
||
)
|
||
{
|
||
PSERVICE_QUERY_DIRECTORY_OBJECT Params = (PSERVICE_QUERY_DIRECTORY_OBJECT)Communication.Buffer;
|
||
NTSTATUS Status;
|
||
|
||
Status = NtQueryDirectoryObject(
|
||
Params->DirectoryHandle,
|
||
Params->Buffer,
|
||
sizeof(Params->Buffer),
|
||
TRUE, // return single entry
|
||
Params->RestartScan,
|
||
&Params->Context,
|
||
NULL
|
||
);
|
||
|
||
if(!NT_SUCCESS(Status) && (Status != STATUS_NO_MORE_ENTRIES)) {
|
||
KdPrint(("uSETUP: Unable to query directory object (%lx)\n",Status));
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
uSpFlushVirtualMemory(
|
||
VOID
|
||
)
|
||
{
|
||
PSERVICE_FLUSH_VIRTUAL_MEMORY Params = (PSERVICE_FLUSH_VIRTUAL_MEMORY)Communication.Buffer;
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
|
||
PVOID BaseAddress;
|
||
SIZE_T RangeLength;
|
||
|
||
BaseAddress = Params->BaseAddress;
|
||
RangeLength = Params->RangeLength;
|
||
|
||
Status = NtFlushVirtualMemory(
|
||
NtCurrentProcess(),
|
||
&BaseAddress,
|
||
&RangeLength,
|
||
&IoStatus
|
||
);
|
||
|
||
if(NT_SUCCESS(Status)) {
|
||
if(BaseAddress != Params->BaseAddress) {
|
||
KdPrint((
|
||
"uSETUP: Warning: uSpFlushVirtualMemory: base address %lx changed to %lx\n",
|
||
Params->BaseAddress,
|
||
BaseAddress
|
||
));
|
||
}
|
||
} else {
|
||
KdPrint((
|
||
"uSETUP: Unable to flush virtual memory @%p length %p (%lx)\n",
|
||
Params->BaseAddress,
|
||
Params->RangeLength,
|
||
Status
|
||
));
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
uSpShutdownSystem(
|
||
VOID
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = NtShutdownSystem(ShutdownReboot);
|
||
|
||
KdPrint(("uSETUP: NtShutdownSystem returned (%lx)\n",Status));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
NTSTATUS
|
||
uSpLockUnlockVolume(
|
||
VOID
|
||
)
|
||
{
|
||
HANDLE Handle;
|
||
NTSTATUS Status;
|
||
BOOLEAN Locking;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
||
PSERVICE_LOCK_UNLOCK_VOLUME Params = (PSERVICE_LOCK_UNLOCK_VOLUME)Communication.Buffer;
|
||
|
||
Handle = Params->Handle;
|
||
Locking = (BOOLEAN)(Communication.u.RequestNumber == SetupServiceLockVolume);
|
||
|
||
Status = NtFsControlFile( Handle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
( Locking )? FSCTL_LOCK_VOLUME : FSCTL_UNLOCK_VOLUME,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0 );
|
||
|
||
if( !NT_SUCCESS( Status ) ) {
|
||
KdPrint((
|
||
"uSETUP: Unable to %ws volume (%lx)\n",
|
||
( Locking )? L"lock" : L"unlock",
|
||
Status
|
||
));
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
uSpDismountVolume(
|
||
VOID
|
||
)
|
||
{
|
||
HANDLE Handle;
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
||
PSERVICE_DISMOUNT_VOLUME Params = (PSERVICE_DISMOUNT_VOLUME)Communication.Buffer;
|
||
|
||
Handle = Params->Handle;
|
||
|
||
Status = NtFsControlFile( Handle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
FSCTL_DISMOUNT_VOLUME,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0 );
|
||
|
||
if( !NT_SUCCESS( Status ) ) {
|
||
KdPrint((
|
||
"uSETUP: Unable to dismount volume (%lx)\n",
|
||
Status
|
||
));
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
uSpCreatePageFile(
|
||
VOID
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
UNICODE_STRING UnicodeString;
|
||
|
||
PSERVICE_CREATE_PAGEFILE Params = (PSERVICE_CREATE_PAGEFILE)Communication.Buffer;
|
||
|
||
RtlInitUnicodeString(&UnicodeString,Params->FileName);
|
||
|
||
Status = NtCreatePagingFile(&UnicodeString,&Params->MinSize,&Params->MaxSize,0);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
|
||
KdPrint((
|
||
"uSETUP: Unable to create pagefile %ws %x-%x (%x)",
|
||
Params->FileName,
|
||
Params->MinSize.LowPart,
|
||
Params->MaxSize.LowPart,
|
||
Status
|
||
));
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
uSpGetFullPathName(
|
||
VOID
|
||
)
|
||
{
|
||
ULONG len;
|
||
ULONG u;
|
||
|
||
PSERVICE_GETFULLPATHNAME Params = (PSERVICE_GETFULLPATHNAME)Communication.Buffer;
|
||
|
||
len = wcslen(Params->FileName);
|
||
|
||
Params->NameOut = Params->FileName + len + 1;
|
||
|
||
u = RtlGetFullPathName_U(
|
||
Params->FileName,
|
||
(sizeof(Communication.Buffer) - ((len+1)*sizeof(WCHAR))) - sizeof(PVOID),
|
||
Params->NameOut,
|
||
NULL
|
||
);
|
||
|
||
return(u ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
SpRequestServiceThread(
|
||
PVOID ThreadParameter
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
while(1) {
|
||
|
||
//
|
||
// Wait for the driver to fill the request buffer and indicate
|
||
// that a request requires servicing.
|
||
//
|
||
Status = NtWaitForSingleObject(hEventRequestReady,FALSE,NULL);
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: wait on RequestReady event returned %lx\n",Status));
|
||
return(Status);
|
||
}
|
||
|
||
switch(Communication.u.RequestNumber) {
|
||
|
||
case SetupServiceExecute:
|
||
|
||
Status = uSpExecuteImage();
|
||
break;
|
||
|
||
case SetupServiceLockVolume:
|
||
case SetupServiceUnlockVolume:
|
||
|
||
Status = uSpLockUnlockVolume();
|
||
break;
|
||
|
||
case SetupServiceDismountVolume:
|
||
|
||
Status = uSpDismountVolume();
|
||
break;
|
||
|
||
case SetupServiceQueryDirectoryObject:
|
||
|
||
Status = uSpQueryDirectoryObject();
|
||
break;
|
||
|
||
case SetupServiceFlushVirtualMemory:
|
||
|
||
Status = uSpFlushVirtualMemory();
|
||
break;
|
||
|
||
case SetupServiceShutdownSystem:
|
||
|
||
Status = uSpShutdownSystem();
|
||
break;
|
||
|
||
case SetupServiceDeleteKey:
|
||
|
||
Status = uSpDeleteKey();
|
||
break;
|
||
|
||
case SetupServiceLoadKbdLayoutDll:
|
||
|
||
Status = uSpLoadKbdLayoutDll();
|
||
break;
|
||
|
||
case SetupServiceDone:
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
case SetupServiceSetDefaultFileSecurity:
|
||
|
||
Status = uSpSetDefaultFileSecurity();
|
||
break;
|
||
|
||
case SetupServiceVerifyFileAccess:
|
||
|
||
Status = uSpVerifyFileAccess();
|
||
break;
|
||
|
||
case SetupServiceCreatePageFile:
|
||
|
||
Status = uSpCreatePageFile();
|
||
break;
|
||
|
||
case SetupServiceGetFullPathName:
|
||
|
||
Status = uSpGetFullPathName();
|
||
break;
|
||
|
||
default:
|
||
|
||
KdPrint(("uSETUP: unknown service %u requested\n",Communication.u.RequestNumber));
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Store the result status where the driver can get at it.
|
||
//
|
||
Communication.u.Status = Status;
|
||
|
||
//
|
||
// Inform the driver that we're done servicing the request.
|
||
//
|
||
Status = NtSetEvent(hEventRequestServiced,NULL);
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: set RequestServiced event returned %lx\n",Status));
|
||
return(Status);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void
|
||
__cdecl
|
||
main(
|
||
int argc,
|
||
char *argv[],
|
||
char *envp[],
|
||
ULONG DebugParameter OPTIONAL
|
||
)
|
||
{
|
||
HANDLE handle;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
UNICODE_STRING UnicodeString;
|
||
OBJECT_ATTRIBUTES Attributes;
|
||
NTSTATUS Status;
|
||
HANDLE hThread;
|
||
SETUP_START_INFO SetupStartInfo;
|
||
BOOLEAN b;
|
||
|
||
//
|
||
// Enable several privileges that we will need.
|
||
//
|
||
Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE,TRUE,FALSE,&b);
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Warning: unable to enable backup privilege (%lx)\n",Status));
|
||
}
|
||
|
||
Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,TRUE,FALSE,&b);
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Warning: unable to enable restore privilege (%lx)\n",Status));
|
||
}
|
||
|
||
Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,TRUE,FALSE,&b);
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Warning: unable to enable shutdown privilege (%lx)\n",Status));
|
||
}
|
||
|
||
Status = RtlAdjustPrivilege(SE_TAKE_OWNERSHIP_PRIVILEGE,TRUE,FALSE,&b);
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Warning: unable to enable take ownership privilege (%lx)\n",Status));
|
||
}
|
||
|
||
//
|
||
// Get the registry going. Pass a flag indicating that this is a setup boot.
|
||
//
|
||
Status = NtInitializeRegistry(REG_INIT_BOOT_SETUP);
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to initialize registry (%lx)\n",Status));
|
||
goto main0;
|
||
}
|
||
|
||
//
|
||
// Query basic system info.
|
||
//
|
||
Status = NtQuerySystemInformation(
|
||
SystemBasicInformation,
|
||
&SetupStartInfo.SystemBasicInfo,
|
||
sizeof(SYSTEM_BASIC_INFORMATION),
|
||
NULL
|
||
);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to query system basic information (%lx)\n",Status));
|
||
goto main0;
|
||
}
|
||
|
||
//
|
||
// Create two events for cummunicating with the setup device driver.
|
||
// One event indicates that the request buffer is filled (ie, request service)
|
||
// and the other indicates that the request has been processed.
|
||
// Both events are initially not signalled.
|
||
//
|
||
Status = NtCreateEvent(
|
||
&hEventRequestReady,
|
||
EVENT_ALL_ACCESS,
|
||
NULL,
|
||
SynchronizationEvent,
|
||
FALSE
|
||
);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to create event (%lx)\n",Status));
|
||
goto main0;
|
||
}
|
||
|
||
Status = NtCreateEvent(
|
||
&hEventRequestServiced,
|
||
EVENT_ALL_ACCESS,
|
||
NULL,
|
||
SynchronizationEvent,
|
||
FALSE
|
||
);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to create event (%lx)\n",Status));
|
||
goto main1;
|
||
}
|
||
|
||
//
|
||
// Open the setup device.
|
||
//
|
||
|
||
RtlInitUnicodeString(&UnicodeString,DD_SETUP_DEVICE_NAME_U);
|
||
|
||
InitializeObjectAttributes(
|
||
&Attributes,
|
||
&UnicodeString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
Status = NtCreateFile(
|
||
&handle,
|
||
FILE_ALL_ACCESS,
|
||
&Attributes,
|
||
&IoStatusBlock,
|
||
NULL, // allocation size
|
||
0,
|
||
FILE_SHARE_READ,
|
||
FILE_OPEN,
|
||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||
NULL, // no EAs
|
||
0
|
||
);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to open %ws (%lx)\n",DD_SETUP_DEVICE_NAME_U,Status));
|
||
goto main2;
|
||
}
|
||
|
||
//
|
||
// Create a thread to service requests from the text setup device driver.
|
||
//
|
||
Status = RtlCreateUserThread(
|
||
NtCurrentProcess(),
|
||
NULL, // security descriptor
|
||
FALSE, // not suspended
|
||
0, // zero bits
|
||
0, // stack reserve
|
||
0, // stack commit
|
||
SpRequestServiceThread,
|
||
NULL, // parameter
|
||
&hThread,
|
||
NULL // client id
|
||
);
|
||
|
||
if(!NT_SUCCESS(Status)) {
|
||
KdPrint(("uSETUP: Unable to create thread (%lx)\n",Status));
|
||
goto main3;
|
||
}
|
||
|
||
//
|
||
// Determine the image base of this program.
|
||
//
|
||
RtlPcToFileHeader(main,&SetupStartInfo.UserModeImageBase);
|
||
if(!SetupStartInfo.UserModeImageBase) {
|
||
KdPrint(("uSETUP: Unable to get image base\n"));
|
||
goto main3;
|
||
}
|
||
|
||
//
|
||
// Invoke the setup ioctl to get setup going.
|
||
// Note that this is a synchronous call -- so this routine
|
||
// will not return until text setup is done.
|
||
// However the second thread we started above will be servicing
|
||
// requests from the text setup device driver.
|
||
//
|
||
SetupStartInfo.RequestReadyEvent = hEventRequestReady;
|
||
SetupStartInfo.RequestServicedEvent = hEventRequestServiced;
|
||
SetupStartInfo.Communication = &Communication;
|
||
Status = NtDeviceIoControlFile(
|
||
handle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
IOCTL_SETUP_START,
|
||
&SetupStartInfo,
|
||
sizeof(SetupStartInfo),
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
if(Status != STATUS_SUCCESS) {
|
||
KdPrint(("uSETUP: Warning: start setup ioctl returned %lx\n",Status));
|
||
}
|
||
|
||
//
|
||
// Clean up.
|
||
//
|
||
NtClose(hThread);
|
||
|
||
main3:
|
||
|
||
NtClose(handle);
|
||
|
||
main2:
|
||
|
||
NtClose(hEventRequestServiced);
|
||
|
||
main1:
|
||
|
||
NtClose(hEventRequestReady);
|
||
|
||
main0:
|
||
|
||
NtTerminateProcess(NULL,STATUS_SUCCESS);
|
||
}
|