mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4694 lines
146 KiB
4694 lines
146 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sminit.c
|
|
|
|
Abstract:
|
|
|
|
Session Manager Initialization
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 04-Oct-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "smsrvp.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
void
|
|
SmpDisplayString( char *s );
|
|
|
|
// #define SMP_SHOW_REGISTRY_DATA 1
|
|
|
|
|
|
#define MAX_PAGING_FILES 16
|
|
|
|
|
|
//
|
|
// Protection mode flags
|
|
//
|
|
|
|
#define SMP_NO_PROTECTION (0x0)
|
|
#define SMP_STANDARD_PROTECTION (0x1)
|
|
|
|
#define SMP_PROTECTION_REQUIRED \
|
|
(SMP_STANDARD_PROTECTION)
|
|
|
|
|
|
ULONG CountPageFiles;
|
|
LONG PageFileMinSizes[ MAX_PAGING_FILES ];
|
|
LONG PageFileMaxSizes[ MAX_PAGING_FILES ];
|
|
UNICODE_STRING PageFileSpecs[ MAX_PAGING_FILES ];
|
|
PSECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor;
|
|
SECURITY_DESCRIPTOR SmpPrimarySDBody;
|
|
PSECURITY_DESCRIPTOR SmpLiberalSecurityDescriptor;
|
|
SECURITY_DESCRIPTOR SmpLiberalSDBody;
|
|
PSECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor;
|
|
SECURITY_DESCRIPTOR SmpKnownDllsSDBody;
|
|
PSECURITY_DESCRIPTOR SmpApiPortSecurityDescriptor;
|
|
SECURITY_DESCRIPTOR SmpApiPortSDBody;
|
|
ULONG SmpProtectionMode = 0;
|
|
|
|
#if DBG
|
|
BOOLEAN SmpEnableDots = FALSE;
|
|
#else
|
|
BOOLEAN SmpEnableDots = TRUE;
|
|
#endif
|
|
|
|
|
|
WCHAR InitialCommandBuffer[ 256 ];
|
|
|
|
UNICODE_STRING SmpDebugKeyword;
|
|
UNICODE_STRING SmpASyncKeyword;
|
|
UNICODE_STRING SmpAutoChkKeyword;
|
|
UNICODE_STRING SmpKnownDllPath;
|
|
|
|
HANDLE SmpWindowsSubSysProcess;
|
|
|
|
typedef struct _SMP_REGISTRY_VALUE {
|
|
LIST_ENTRY Entry;
|
|
UNICODE_STRING Name;
|
|
UNICODE_STRING Value;
|
|
LPSTR AnsiValue;
|
|
} SMP_REGISTRY_VALUE, *PSMP_REGISTRY_VALUE;
|
|
|
|
LIST_ENTRY SmpBootExecuteList;
|
|
LIST_ENTRY SmpPagingFileList;
|
|
LIST_ENTRY SmpDosDevicesList;
|
|
LIST_ENTRY SmpFileRenameList;
|
|
LIST_ENTRY SmpKnownDllsList;
|
|
LIST_ENTRY SmpExcludeKnownDllsList;
|
|
LIST_ENTRY SmpSubSystemList;
|
|
LIST_ENTRY SmpSubSystemsToLoad;
|
|
LIST_ENTRY SmpSubSystemsToDefer;
|
|
LIST_ENTRY SmpExecuteList;
|
|
|
|
|
|
NTSTATUS
|
|
SmpCreateSecurityDescriptors(
|
|
IN BOOLEAN InitialCall
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpLoadDataFromRegistry(
|
|
OUT PUNICODE_STRING InitialCommand
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpCreateDynamicEnvironmentVariables(
|
|
VOID
|
|
);
|
|
|
|
PSMP_REGISTRY_VALUE
|
|
SmpFindRegistryValue(
|
|
IN PLIST_ENTRY ListHead,
|
|
IN PWSTR Name
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpSaveRegistryValue(
|
|
IN OUT PLIST_ENTRY ListHead,
|
|
IN PWSTR Name,
|
|
IN PWSTR Value OPTIONAL,
|
|
IN BOOLEAN CheckForDuplicate
|
|
);
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
VOID
|
|
SmpDumpQuery(
|
|
IN PCHAR RoutineName,
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength
|
|
);
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
SmpConfigureProtectionMode(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureObjectDirectories(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureExecute(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureFileRenames(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureMemoryMgmt(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureDosDevices(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureKnownDlls(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureExcludeKnownDlls(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureSubSystems(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureEnvironment(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
RTL_QUERY_REGISTRY_TABLE SmpRegistryConfigurationTable[] = {
|
|
|
|
//
|
|
// Note that the SmpConfigureProtectionMode entry should preceed others
|
|
// to ensure we set up the right protection for use by the others.
|
|
//
|
|
|
|
{SmpConfigureProtectionMode, 0,
|
|
L"ProtectionMode", NULL,
|
|
REG_DWORD, (PVOID)0, 0},
|
|
|
|
{SmpConfigureObjectDirectories, 0,
|
|
L"ObjectDirectories", NULL,
|
|
REG_MULTI_SZ, (PVOID)L"\\Windows\0\\RPC Control\0", 0},
|
|
|
|
{SmpConfigureExecute, 0,
|
|
L"BootExecute", &SmpBootExecuteList,
|
|
REG_MULTI_SZ, L"autocheck \\SystemRoot\\Windows\\System32\\AutoChk.exe *\0", 0},
|
|
|
|
{SmpConfigureFileRenames, RTL_QUERY_REGISTRY_DELETE,
|
|
L"PendingFileRenameOperations", &SmpFileRenameList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureExcludeKnownDlls, 0,
|
|
L"ExcludeFromKnownDlls", &SmpExcludeKnownDllsList,
|
|
REG_MULTI_SZ, L"\0", 0},
|
|
|
|
{NULL, RTL_QUERY_REGISTRY_SUBKEY,
|
|
L"Memory Management", NULL,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureMemoryMgmt, 0,
|
|
L"PagingFiles", &SmpPagingFileList,
|
|
REG_MULTI_SZ, "?:\\pagefile.sys 10 60\0", 0},
|
|
|
|
{SmpConfigureDosDevices, RTL_QUERY_REGISTRY_SUBKEY,
|
|
L"DOS Devices", &SmpDosDevicesList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureKnownDlls, RTL_QUERY_REGISTRY_SUBKEY,
|
|
L"KnownDlls", &SmpKnownDllsList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureEnvironment, RTL_QUERY_REGISTRY_SUBKEY,
|
|
L"Environment", NULL,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureSubSystems, RTL_QUERY_REGISTRY_SUBKEY,
|
|
L"SubSystems", &SmpSubSystemList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureSubSystems, RTL_QUERY_REGISTRY_NOEXPAND,
|
|
L"Required", &SmpSubSystemList,
|
|
REG_MULTI_SZ, L"Debug\0Windows\0", 0},
|
|
|
|
{SmpConfigureSubSystems, RTL_QUERY_REGISTRY_NOEXPAND,
|
|
L"Optional", &SmpSubSystemList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureSubSystems, 0,
|
|
L"Kmode", &SmpSubSystemList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureExecute, RTL_QUERY_REGISTRY_TOPKEY,
|
|
L"Execute", &SmpExecuteList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{NULL, 0,
|
|
NULL, NULL,
|
|
REG_NONE, NULL, 0}
|
|
|
|
};
|
|
|
|
|
|
NTSTATUS
|
|
SmpInvokeAutoChk(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING Arguments,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpLoadSubSystem(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpExecuteCommand(
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpInitializeDosDevices( VOID );
|
|
|
|
NTSTATUS
|
|
SmpInitializeKnownDlls( VOID );
|
|
|
|
VOID
|
|
SmpProcessFileRenames( VOID );
|
|
|
|
NTSTATUS
|
|
SmpParseToken(
|
|
IN PUNICODE_STRING Source,
|
|
IN BOOLEAN RemainderOfSource,
|
|
OUT PUNICODE_STRING Token
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpParseCommandLine(
|
|
IN PUNICODE_STRING CommandLine,
|
|
OUT PULONG Flags,
|
|
OUT PUNICODE_STRING ImageFileName,
|
|
OUT PUNICODE_STRING ImageFileDirectory,
|
|
OUT PUNICODE_STRING Arguments
|
|
);
|
|
|
|
#define SMP_DEBUG_FLAG 0x00000001
|
|
#define SMP_ASYNC_FLAG 0x00000002
|
|
#define SMP_AUTOCHK_FLAG 0x00000004
|
|
#define SMP_SUBSYSTEM_FLAG 0x00000008
|
|
#define SMP_IMAGE_NOT_FOUND 0x00000010
|
|
#define SMP_DONT_START 0x00000020
|
|
|
|
ULONG
|
|
SmpConvertInteger(
|
|
IN PWSTR String
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpAddPagingFile(
|
|
IN PUNICODE_STRING PagingFileSpec
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpCreatePagingFile(
|
|
PUNICODE_STRING PagingFileSpec,
|
|
LARGE_INTEGER MinPagingFileSize,
|
|
LARGE_INTEGER MaxPagingFileSize
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpCreatePagingFiles( VOID );
|
|
|
|
VOID
|
|
SmpTranslateSystemPartitionInformation( VOID );
|
|
|
|
#define VALUE_BUFFER_SIZE (sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR))
|
|
|
|
//
|
|
// local Macros
|
|
//
|
|
|
|
//
|
|
// VOID
|
|
// SmpSetDaclDefaulted(
|
|
// IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
// OUT PSECURITY_DESCRIPTOR_CONTROL CurrentSdControl
|
|
// )
|
|
//
|
|
// Description:
|
|
//
|
|
// This routine will set the DaclDefaulted flag of the DACL passed
|
|
// via the ObjectAttributes parameter. If the ObjectAttributes do
|
|
// not include a SecurityDescriptor, then no action is taken.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// ObjectAttributes - The object attributes whose security descriptor is
|
|
// to have its DaclDefaulted flag set.
|
|
//
|
|
// CurrentSdControl - Receives the current value of the security descriptor's
|
|
// control flags. This may be used in a subsequent call to
|
|
// SmpRestoreDaclDefaulted() to restore the flag to its original state.
|
|
//
|
|
|
|
#define SmpSetDaclDefaulted( OA, SDC ) \
|
|
if( (OA)->SecurityDescriptor != NULL) { \
|
|
(*SDC) = ((PISECURITY_DESCRIPTOR)((OA)->SecurityDescriptor))->Control & \
|
|
SE_DACL_DEFAULTED; \
|
|
((PISECURITY_DESCRIPTOR)((OA)->SecurityDescriptor))->Control |= \
|
|
SE_DACL_DEFAULTED; \
|
|
}
|
|
|
|
|
|
//
|
|
// VOID
|
|
// SmpRestoreDaclDefaulted(
|
|
// IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
// IN SECURITY_DESCRIPTOR_CONTROL OriginalSdControl
|
|
// )
|
|
//
|
|
// Description:
|
|
//
|
|
// This routine will set the DaclDefaulted flag of the DACL back to
|
|
// a prior state (indicated by the value in OriginalSdControl).
|
|
//
|
|
// Parameters:
|
|
//
|
|
// ObjectAttributes - The object attributes whose security descriptor is
|
|
// to have its DaclDefaulted flag restored. If the object attributes
|
|
// have no security descriptor, then no action is taken.
|
|
//
|
|
// OriginalSdControl - The original value of the security descriptor's
|
|
// control flags. This typically is obtained via a prior call to
|
|
// SmpSetDaclDefaulted().
|
|
//
|
|
|
|
#define SmpRestoreDaclDefaulted( OA, SDC ) \
|
|
if( (OA)->SecurityDescriptor != NULL) { \
|
|
((PISECURITY_DESCRIPTOR)((OA)->SecurityDescriptor))->Control = \
|
|
(((PISECURITY_DESCRIPTOR)((OA)->SecurityDescriptor))->Control & \
|
|
~SE_DACL_DEFAULTED) | \
|
|
(SDC & SE_DACL_DEFAULTED); \
|
|
}
|
|
|
|
//
|
|
// routines
|
|
//
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SmpQueryRegistrySosOption(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function queries the registry to determine if the loadoptions
|
|
boot environment variable contains the string "SOS".
|
|
|
|
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control:SystemStartOptions
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if "SOS" was set. Otherwise FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Key;
|
|
WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
|
|
ULONG ValueLength;
|
|
|
|
//
|
|
// Open the registry key.
|
|
//
|
|
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
RtlInitUnicodeString(&KeyName,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: can't open control key: 0x%x\n", Status));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Query the key value.
|
|
//
|
|
|
|
RtlInitUnicodeString(&ValueName, L"SystemStartOptions");
|
|
Status = NtQueryValueKey(Key,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
VALUE_BUFFER_SIZE,
|
|
&ValueLength);
|
|
|
|
ASSERT(ValueLength < VALUE_BUFFER_SIZE);
|
|
|
|
NtClose(Key);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: can't query value key: 0x%x\n", Status));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check is "sos" or "SOS" ois specified.
|
|
//
|
|
|
|
if (NULL != wcsstr((PWCHAR)&KeyValueInfo->Data, L"SOS") ||
|
|
NULL != wcsstr((PWCHAR)&KeyValueInfo->Data, L"sos")) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpSaveRegistryValue(
|
|
IN OUT PLIST_ENTRY ListHead,
|
|
IN PWSTR Name,
|
|
IN PWSTR Value OPTIONAL,
|
|
IN BOOLEAN CheckForDuplicate
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
UNICODE_STRING UnicodeName;
|
|
UNICODE_STRING UnicodeValue;
|
|
ANSI_STRING AnsiString;
|
|
|
|
RtlInitUnicodeString( &UnicodeName, Name );
|
|
RtlInitUnicodeString( &UnicodeValue, Value );
|
|
if (CheckForDuplicate) {
|
|
Next = ListHead->Flink;
|
|
p = NULL;
|
|
while ( Next != ListHead ) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
if (!RtlCompareUnicodeString( &p->Name, &UnicodeName, TRUE )) {
|
|
if ((!ARGUMENT_PRESENT( Value ) && p->Value.Buffer == NULL) ||
|
|
(ARGUMENT_PRESENT( Value ) &&
|
|
!RtlCompareUnicodeString( &p->Value, &UnicodeValue, TRUE )
|
|
)
|
|
) {
|
|
return( STATUS_OBJECT_NAME_EXISTS );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
Next = Next->Flink;
|
|
p = NULL;
|
|
}
|
|
}
|
|
else {
|
|
p = NULL;
|
|
}
|
|
|
|
if (p == NULL) {
|
|
p = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), sizeof( *p ) + UnicodeName.MaximumLength );
|
|
if (p == NULL) {
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
InitializeListHead( &p->Entry );
|
|
p->Name.Buffer = (PWSTR)(p+1);
|
|
p->Name.Length = UnicodeName.Length;
|
|
p->Name.MaximumLength = UnicodeName.MaximumLength;
|
|
RtlMoveMemory( p->Name.Buffer,
|
|
UnicodeName.Buffer,
|
|
UnicodeName.MaximumLength
|
|
);
|
|
p->Value.Buffer = NULL;
|
|
InsertTailList( ListHead, &p->Entry );
|
|
}
|
|
|
|
if (p->Value.Buffer != NULL) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer );
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( Value )) {
|
|
p->Value.Buffer = (PWSTR)RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
|
|
UnicodeValue.MaximumLength
|
|
);
|
|
if (p->Value.Buffer == NULL) {
|
|
RemoveEntryList( &p->Entry );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
p->Value.Length = UnicodeValue.Length;
|
|
p->Value.MaximumLength = UnicodeValue.MaximumLength;
|
|
RtlMoveMemory( p->Value.Buffer,
|
|
UnicodeValue.Buffer,
|
|
UnicodeValue.MaximumLength
|
|
);
|
|
p->AnsiValue = (LPSTR)RtlAllocateHeap( RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
(UnicodeValue.Length / sizeof( WCHAR )) + 1
|
|
);
|
|
if (p->AnsiValue == NULL) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer );
|
|
RemoveEntryList( &p->Entry );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
AnsiString.Buffer = p->AnsiValue;
|
|
AnsiString.Length = 0;
|
|
AnsiString.MaximumLength = (UnicodeValue.Length / sizeof( WCHAR )) + 1;
|
|
RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeValue, FALSE );
|
|
}
|
|
else {
|
|
RtlInitUnicodeString( &p->Value, NULL );
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
PSMP_REGISTRY_VALUE
|
|
SmpFindRegistryValue(
|
|
IN PLIST_ENTRY ListHead,
|
|
IN PWSTR Name
|
|
)
|
|
{
|
|
PLIST_ENTRY Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
UNICODE_STRING UnicodeName;
|
|
|
|
RtlInitUnicodeString( &UnicodeName, Name );
|
|
Next = ListHead->Flink;
|
|
while ( Next != ListHead ) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
if (!RtlCompareUnicodeString( &p->Name, &UnicodeName, TRUE )) {
|
|
return( p );
|
|
}
|
|
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpInit(
|
|
OUT PUNICODE_STRING InitialCommand,
|
|
OUT PHANDLE WindowsSubSystem
|
|
)
|
|
{
|
|
NTSTATUS st;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
HANDLE SmpApiConnectionPort;
|
|
UNICODE_STRING Unicode;
|
|
NTSTATUS Status;
|
|
ULONG HardErrorMode;
|
|
|
|
SmBaseTag = RtlCreateTagHeap( RtlProcessHeap(),
|
|
0,
|
|
L"SMSS!",
|
|
L"INIT\0"
|
|
L"DBG\0"
|
|
L"SM\0"
|
|
);
|
|
//
|
|
// Make sure we specify hard error popups
|
|
//
|
|
|
|
HardErrorMode = 1;
|
|
NtSetInformationProcess( NtCurrentProcess(),
|
|
ProcessDefaultHardErrorMode,
|
|
(PVOID) &HardErrorMode,
|
|
sizeof( HardErrorMode )
|
|
);
|
|
|
|
RtlInitUnicodeString( &SmpSubsystemName, L"NT-Session Manager" );
|
|
|
|
|
|
RtlInitializeCriticalSection(&SmpKnownSubSysLock);
|
|
InitializeListHead(&SmpKnownSubSysHead);
|
|
|
|
RtlInitializeCriticalSection(&SmpSessionListLock);
|
|
InitializeListHead(&SmpSessionListHead);
|
|
SmpNextSessionId = 1;
|
|
SmpNextSessionIdScanMode = FALSE;
|
|
SmpDbgSsLoaded = FALSE;
|
|
|
|
//
|
|
// Initialize security descriptors to grant wide access
|
|
// (protection mode not yet read in from registry).
|
|
//
|
|
|
|
st = SmpCreateSecurityDescriptors( TRUE );
|
|
if ( !NT_SUCCESS(st) ) {
|
|
return(st);
|
|
}
|
|
|
|
|
|
|
|
InitializeListHead(&NativeProcessList);
|
|
|
|
SmpHeap = RtlProcessHeap();
|
|
|
|
RtlInitUnicodeString( &Unicode, L"\\SmApiPort" );
|
|
InitializeObjectAttributes( &ObjA, &Unicode, 0, NULL, SmpApiPortSecurityDescriptor);
|
|
|
|
st = NtCreatePort(
|
|
&SmpApiConnectionPort,
|
|
&ObjA,
|
|
sizeof(SBCONNECTINFO),
|
|
sizeof(SMMESSAGE_SIZE),
|
|
sizeof(SBAPIMSG) * 32
|
|
);
|
|
ASSERT( NT_SUCCESS(st) );
|
|
|
|
SmpDebugPort = SmpApiConnectionPort;
|
|
|
|
st = RtlCreateUserThread(
|
|
NtCurrentProcess(),
|
|
NULL,
|
|
FALSE,
|
|
0L,
|
|
0L,
|
|
0L,
|
|
SmpApiLoop,
|
|
(PVOID) SmpApiConnectionPort,
|
|
NULL,
|
|
NULL
|
|
);
|
|
ASSERT( NT_SUCCESS(st) );
|
|
|
|
st = RtlCreateUserThread(
|
|
NtCurrentProcess(),
|
|
NULL,
|
|
FALSE,
|
|
0L,
|
|
0L,
|
|
0L,
|
|
SmpApiLoop,
|
|
(PVOID) SmpApiConnectionPort,
|
|
NULL,
|
|
NULL
|
|
);
|
|
ASSERT( NT_SUCCESS(st) );
|
|
|
|
//
|
|
// Configure the system
|
|
//
|
|
|
|
Status = SmpLoadDataFromRegistry( InitialCommand );
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
*WindowsSubSystem = SmpWindowsSubSysProcess;
|
|
}
|
|
return( Status );
|
|
}
|
|
|
|
typedef struct _SMP_ACQUIRE_STATE {
|
|
HANDLE Token;
|
|
PTOKEN_PRIVILEGES OldPrivileges;
|
|
PTOKEN_PRIVILEGES NewPrivileges;
|
|
UCHAR OldPrivBuffer[ 1024 ];
|
|
} SMP_ACQUIRE_STATE, *PSMP_ACQUIRE_STATE;
|
|
|
|
NTSTATUS
|
|
SmpAcquirePrivilege(
|
|
ULONG Privilege,
|
|
PVOID *ReturnedState
|
|
)
|
|
{
|
|
PSMP_ACQUIRE_STATE State;
|
|
ULONG cbNeeded;
|
|
LUID LuidPrivilege;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Make sure we have access to adjust and to get the old token privileges
|
|
//
|
|
|
|
*ReturnedState = NULL;
|
|
State = RtlAllocateHeap( RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
sizeof(SMP_ACQUIRE_STATE) +
|
|
sizeof(TOKEN_PRIVILEGES) +
|
|
(1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES)
|
|
);
|
|
if (State == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
Status = NtOpenProcessToken(
|
|
NtCurrentProcess(),
|
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
|
&State->Token
|
|
);
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State );
|
|
return Status;
|
|
}
|
|
|
|
State->NewPrivileges = (PTOKEN_PRIVILEGES)(State+1);
|
|
State->OldPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer);
|
|
|
|
//
|
|
// Initialize the privilege adjustment structure
|
|
//
|
|
|
|
LuidPrivilege = RtlConvertUlongToLuid(Privilege);
|
|
State->NewPrivileges->PrivilegeCount = 1;
|
|
State->NewPrivileges->Privileges[0].Luid = LuidPrivilege;
|
|
State->NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
//
|
|
// Enable the privilege
|
|
//
|
|
|
|
cbNeeded = sizeof( State->OldPrivBuffer );
|
|
Status = NtAdjustPrivilegesToken( State->Token,
|
|
FALSE,
|
|
State->NewPrivileges,
|
|
cbNeeded,
|
|
State->OldPrivileges,
|
|
&cbNeeded
|
|
);
|
|
|
|
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
|
State->OldPrivileges = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), cbNeeded );
|
|
if (State->OldPrivileges == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
else {
|
|
Status = NtAdjustPrivilegesToken( State->Token,
|
|
FALSE,
|
|
State->NewPrivileges,
|
|
cbNeeded,
|
|
State->OldPrivileges,
|
|
&cbNeeded
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// STATUS_NOT_ALL_ASSIGNED means that the privilege isn't
|
|
// in the token, so we can't proceed.
|
|
//
|
|
// This is a warning level status, so map it to an error status.
|
|
//
|
|
|
|
if (Status == STATUS_NOT_ALL_ASSIGNED) {
|
|
Status = STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
if (State->OldPrivileges != (PTOKEN_PRIVILEGES)(State->OldPrivBuffer)) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges );
|
|
}
|
|
|
|
NtClose( State->Token );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State );
|
|
return Status;
|
|
}
|
|
|
|
*ReturnedState = State;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
SmpReleasePrivilege(
|
|
PVOID StatePointer
|
|
)
|
|
{
|
|
PSMP_ACQUIRE_STATE State = (PSMP_ACQUIRE_STATE)StatePointer;
|
|
|
|
NtAdjustPrivilegesToken( State->Token,
|
|
FALSE,
|
|
State->OldPrivileges,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (State->OldPrivileges != (PTOKEN_PRIVILEGES)(State->OldPrivBuffer)) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges );
|
|
}
|
|
|
|
NtClose( State->Token );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, State );
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpLoadDataFromRegistry(
|
|
OUT PUNICODE_STRING InitialCommand
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function loads all of the configurable data for the NT Session
|
|
Manager from the registry.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Status of operation
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY Head, Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
PVOID OriginalEnvironment;
|
|
|
|
RtlInitUnicodeString( &SmpDebugKeyword, L"debug" );
|
|
RtlInitUnicodeString( &SmpASyncKeyword, L"async" );
|
|
RtlInitUnicodeString( &SmpAutoChkKeyword, L"autocheck" );
|
|
|
|
InitializeListHead( &SmpBootExecuteList );
|
|
InitializeListHead( &SmpPagingFileList );
|
|
InitializeListHead( &SmpDosDevicesList );
|
|
InitializeListHead( &SmpFileRenameList );
|
|
InitializeListHead( &SmpKnownDllsList );
|
|
InitializeListHead( &SmpExcludeKnownDllsList );
|
|
InitializeListHead( &SmpSubSystemList );
|
|
InitializeListHead( &SmpSubSystemsToLoad );
|
|
InitializeListHead( &SmpSubSystemsToDefer );
|
|
InitializeListHead( &SmpExecuteList );
|
|
|
|
Status = RtlCreateEnvironment( TRUE, &SmpDefaultEnvironment );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(("SMSS: Unable to allocate default environment - Status == %X\n", Status ));
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// In order to track growth in smpdefaultenvironment, make it sm's environment
|
|
// while doing the registry groveling and then restore it
|
|
//
|
|
|
|
OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
|
|
NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment;
|
|
Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
|
|
L"Session Manager",
|
|
SmpRegistryConfigurationTable,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
|
|
NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment;
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status ));
|
|
return( Status );
|
|
}
|
|
|
|
Status = SmpInitializeDosDevices();
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to initialize DosDevices configuration - Status == %lx\n", Status ));
|
|
return( Status );
|
|
}
|
|
|
|
Head = &SmpBootExecuteList;
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: BootExecute( %wZ )\n", &p->Name );
|
|
#endif
|
|
SmpExecuteCommand( &p->Name, 0 );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
SmpProcessFileRenames();
|
|
|
|
Status = SmpInitializeKnownDlls();
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to initialize KnownDll configuration - Status == %lx\n", Status ));
|
|
return( Status );
|
|
}
|
|
|
|
|
|
//
|
|
// Process the list of paging files.
|
|
//
|
|
|
|
Head = &SmpPagingFileList;
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: PagingFile( %wZ )\n", &p->Name );
|
|
#endif
|
|
SmpAddPagingFile( &p->Name );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
//
|
|
// Create any paging files specified in NT section(s)
|
|
//
|
|
|
|
SmpCreatePagingFiles();
|
|
|
|
//
|
|
// Finish registry initialization
|
|
//
|
|
|
|
NtInitializeRegistry(FALSE);
|
|
|
|
Status = SmpCreateDynamicEnvironmentVariables( );
|
|
if (!NT_SUCCESS( Status )) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Translate the system partition information stored during IoInitSystem into
|
|
// a DOS path and store in Win32-standard location.
|
|
//
|
|
|
|
SmpTranslateSystemPartitionInformation();
|
|
|
|
Head = &SmpSubSystemList;
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
if ( !_wcsicmp( p->Name.Buffer, L"Kmode" )) {
|
|
BOOLEAN TranslationStatus;
|
|
UNICODE_STRING FileName;
|
|
|
|
TranslationStatus = RtlDosPathNameToNtPathName_U(
|
|
p->Value.Buffer,
|
|
&FileName,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( TranslationStatus ) {
|
|
PVOID State;
|
|
|
|
Status = SmpAcquirePrivilege( SE_LOAD_DRIVER_PRIVILEGE, &State );
|
|
if (NT_SUCCESS( Status )) {
|
|
Status = NtSetSystemInformation(
|
|
SystemExtendServiceTableInformation,
|
|
(PVOID)&FileName,
|
|
sizeof(FileName)
|
|
);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
|
|
SmpReleasePrivilege( State );
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
|
}
|
|
}
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: Unused SubSystem( %wZ = %wZ )\n", &p->Name, &p->Value );
|
|
#endif
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
Head = &SmpSubSystemsToLoad;
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: Loaded SubSystem( %wZ = %wZ )\n", &p->Name, &p->Value );
|
|
#endif
|
|
if (!_wcsicmp( p->Name.Buffer, L"debug" )) {
|
|
SmpExecuteCommand( &p->Value, SMP_SUBSYSTEM_FLAG | SMP_DEBUG_FLAG );
|
|
}
|
|
else {
|
|
SmpExecuteCommand( &p->Value, SMP_SUBSYSTEM_FLAG );
|
|
}
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
|
|
Head = &SmpExecuteList;
|
|
if (!IsListEmpty( Head )) {
|
|
Next = Head->Blink;
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
RemoveEntryList( &p->Entry );
|
|
*InitialCommand = p->Name;
|
|
|
|
//
|
|
// This path is only taken when people want to run ntsd -p -1 winlogon
|
|
//
|
|
// This is nearly impossible to do in a race free manner. In some
|
|
// cases, we can get in a state where we can not properly fail
|
|
// a debug API. This is due to the subsystem switch that occurs
|
|
// when ntsd is invoked on csr. If csr is relatively idle, this
|
|
// does not occur. If it is active when you attach, then we can get
|
|
// into a potential race. The slimy fix is to do a 5 second delay
|
|
// if the command line is anything other that the default.
|
|
//
|
|
|
|
{
|
|
LARGE_INTEGER DelayTime;
|
|
DelayTime.QuadPart = Int32x32To64( 5000, -10000 );
|
|
NtDelayExecution(
|
|
FALSE,
|
|
&DelayTime
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
RtlInitUnicodeString( InitialCommand, L"winlogon.exe" );
|
|
InitialCommandBuffer[ 0 ] = UNICODE_NULL;
|
|
LdrQueryImageFileExecutionOptions( InitialCommand,
|
|
L"Debugger",
|
|
REG_SZ,
|
|
InitialCommandBuffer,
|
|
sizeof( InitialCommandBuffer ),
|
|
NULL
|
|
);
|
|
if (InitialCommandBuffer[ 0 ] != UNICODE_NULL) {
|
|
wcscat( InitialCommandBuffer, L" " );
|
|
wcscat( InitialCommandBuffer, InitialCommand->Buffer );
|
|
RtlInitUnicodeString( InitialCommand, InitialCommandBuffer );
|
|
KdPrint(( "SMSS: InitialCommand == '%wZ'\n", InitialCommand ));
|
|
}
|
|
}
|
|
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: Execute( %wZ )\n", &p->Name );
|
|
#endif
|
|
SmpExecuteCommand( &p->Name, 0 );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: InitialCommand( %wZ )\n", InitialCommand );
|
|
#endif
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpCreateDynamicEnvironmentVariables(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
SYSTEM_BASIC_INFORMATION SystemInfo;
|
|
SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
PWSTR ValueData;
|
|
WCHAR ValueBuffer[ 256 ];
|
|
WCHAR ValueBuffer1[ 256 ];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
|
|
ULONG ValueLength;
|
|
HANDLE Key, Key1;
|
|
|
|
Status = NtQuerySystemInformation( SystemBasicInformation,
|
|
&SystemInfo,
|
|
sizeof( SystemInfo ),
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to query system basic information - %x\n", Status ));
|
|
return Status;
|
|
}
|
|
|
|
Status = NtQuerySystemInformation( SystemProcessorInformation,
|
|
&ProcessorInfo,
|
|
sizeof( ProcessorInfo ),
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to query system processor information - %x\n", Status ));
|
|
return Status;
|
|
}
|
|
|
|
RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Environment" );
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = NtOpenKey( &Key, GENERIC_WRITE, &ObjectAttributes );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to open %wZ - %x\n", &KeyName, Status ));
|
|
return Status;
|
|
}
|
|
|
|
RtlInitUnicodeString( &ValueName, L"OS" );
|
|
ValueData = L"Windows_NT";
|
|
Status = NtSetValueKey( Key,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
ValueData,
|
|
(wcslen( ValueData ) + 1) * sizeof( WCHAR )
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status ));
|
|
goto failexit;
|
|
}
|
|
|
|
RtlInitUnicodeString( &ValueName, L"PROCESSOR_ARCHITECTURE" );
|
|
switch( ProcessorInfo.ProcessorArchitecture ) {
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
ValueData = L"x86";
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_MIPS:
|
|
ValueData = L"MIPS";
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_ALPHA:
|
|
ValueData = L"ALPHA";
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_PPC:
|
|
ValueData = L"PPC";
|
|
break;
|
|
|
|
default:
|
|
ValueData = L"Unknown";
|
|
break;
|
|
}
|
|
|
|
Status = NtSetValueKey( Key,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
ValueData,
|
|
(wcslen( ValueData ) + 1) * sizeof( WCHAR )
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status ));
|
|
goto failexit;
|
|
}
|
|
|
|
RtlInitUnicodeString( &ValueName, L"PROCESSOR_LEVEL" );
|
|
switch( ProcessorInfo.ProcessorArchitecture ) {
|
|
case PROCESSOR_ARCHITECTURE_MIPS:
|
|
//
|
|
// Multiple MIPS level by 1000 so 4 becomes 4000
|
|
//
|
|
swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel * 1000 );
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_PPC:
|
|
//
|
|
// Just output the ProcessorLevel in decimal.
|
|
//
|
|
swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel );
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
case PROCESSOR_ARCHITECTURE_ALPHA:
|
|
default:
|
|
//
|
|
// All others use a single level number
|
|
//
|
|
swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel );
|
|
break;
|
|
}
|
|
Status = NtSetValueKey( Key,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
ValueBuffer,
|
|
(wcslen( ValueBuffer ) + 1) * sizeof( WCHAR )
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status ));
|
|
goto failexit;
|
|
}
|
|
|
|
RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\Hardware\\Description\\System\\CentralProcessor\\0" );
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = NtOpenKey( &Key1, KEY_READ, &ObjectAttributes );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to open %wZ - %x\n", &KeyName, Status ));
|
|
goto failexit;
|
|
}
|
|
RtlInitUnicodeString( &ValueName, L"Identifier" );
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
Status = NtQueryValueKey( Key1,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
sizeof( ValueBuffer ),
|
|
&ValueLength
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
NtClose( Key1 );
|
|
KdPrint(( "SMSS: Unable to read %wZ\\%wZ - %x\n", &KeyName, &ValueName, Status ));
|
|
goto failexit;
|
|
}
|
|
|
|
ValueData = (PWSTR)KeyValueInfo->Data;
|
|
RtlInitUnicodeString( &ValueName, L"VendorIdentifier" );
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer1;
|
|
Status = NtQueryValueKey( Key1,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
sizeof( ValueBuffer1 ),
|
|
&ValueLength
|
|
);
|
|
NtClose( Key1 );
|
|
if (NT_SUCCESS( Status )) {
|
|
swprintf( ValueData + wcslen( ValueData ),
|
|
L", %ws",
|
|
(PWSTR)KeyValueInfo->Data
|
|
);
|
|
}
|
|
|
|
RtlInitUnicodeString( &ValueName, L"PROCESSOR_IDENTIFIER" );
|
|
Status = NtSetValueKey( Key,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
ValueData,
|
|
(wcslen( ValueData ) + 1) * sizeof( WCHAR )
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status ));
|
|
goto failexit;
|
|
}
|
|
|
|
RtlInitUnicodeString( &ValueName, L"PROCESSOR_REVISION" );
|
|
switch( ProcessorInfo.ProcessorArchitecture ) {
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF) {
|
|
//
|
|
// Intel 386/486 are An stepping format
|
|
//
|
|
swprintf( ValueBuffer, L"%02x",
|
|
ProcessorInfo.ProcessorRevision & 0xFF
|
|
);
|
|
_wcsupr( ValueBuffer );
|
|
break;
|
|
}
|
|
|
|
// Fall through for Cyrix/NextGen 486 and Pentium processors.
|
|
|
|
case PROCESSOR_ARCHITECTURE_PPC:
|
|
//
|
|
// Intel and PowerPC use fixed point binary number
|
|
// Output is 4 hex digits, no formatting.
|
|
//
|
|
swprintf( ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision );
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_ALPHA:
|
|
swprintf( ValueBuffer, L"Model %c, Pass %u",
|
|
'A' + (ProcessorInfo.ProcessorRevision >> 8),
|
|
ProcessorInfo.ProcessorRevision & 0xFF
|
|
);
|
|
swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision );
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_MIPS:
|
|
default:
|
|
//
|
|
// All others use a single revision number
|
|
//
|
|
swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision );
|
|
break;
|
|
}
|
|
|
|
Status = NtSetValueKey( Key,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
ValueBuffer,
|
|
(wcslen( ValueBuffer ) + 1) * sizeof( WCHAR )
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status ));
|
|
goto failexit;
|
|
}
|
|
|
|
RtlInitUnicodeString( &ValueName, L"NUMBER_OF_PROCESSORS" );
|
|
swprintf( ValueBuffer, L"%u", SystemInfo.NumberOfProcessors );
|
|
Status = NtSetValueKey( Key,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
ValueBuffer,
|
|
(wcslen( ValueBuffer ) + 1) * sizeof( WCHAR )
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status ));
|
|
goto failexit;
|
|
}
|
|
|
|
failexit:
|
|
NtClose( Key );
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpInitializeDosDevices( VOID )
|
|
{
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY Head, Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE LinkHandle;
|
|
SECURITY_DESCRIPTOR_CONTROL OriginalSdControl;
|
|
|
|
//
|
|
// Do DosDevices initialization - the directory object is created in I/O init
|
|
//
|
|
|
|
RtlInitUnicodeString( &UnicodeString, L"\\??" );
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = NtOpenDirectoryObject( &SmpDosDevicesObjectDirectory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to open %wZ directory - Status == %lx\n", &UnicodeString, Status ));
|
|
return( Status );
|
|
}
|
|
|
|
|
|
//
|
|
// Process the list of defined DOS devices and create their
|
|
// associated symbolic links in the \DosDevices object directory.
|
|
//
|
|
|
|
Head = &SmpDosDevicesList;
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: DosDevices( %wZ = %wZ )\n", &p->Name, &p->Value );
|
|
#endif
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&p->Name,
|
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF,
|
|
SmpDosDevicesObjectDirectory,
|
|
SmpPrimarySecurityDescriptor
|
|
);
|
|
SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //Use inheritable protection if available
|
|
Status = NtCreateSymbolicLinkObject( &LinkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
&p->Value
|
|
);
|
|
|
|
if (Status == STATUS_OBJECT_NAME_EXISTS) {
|
|
NtMakeTemporaryObject( LinkHandle );
|
|
NtClose( LinkHandle );
|
|
if (p->Value.Length != 0) {
|
|
ObjectAttributes.Attributes &= ~OBJ_OPENIF;
|
|
Status = NtCreateSymbolicLinkObject( &LinkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
&p->Value
|
|
);
|
|
}
|
|
else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
SmpRestoreDaclDefaulted( &ObjectAttributes, OriginalSdControl );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
|
|
&p->Name,
|
|
&p->Value,
|
|
Status
|
|
));
|
|
return( Status );
|
|
}
|
|
|
|
NtClose( LinkHandle );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
VOID
|
|
SmpProcessModuleImports(
|
|
IN PVOID Parameter,
|
|
IN PCHAR ModuleName
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
WCHAR NameBuffer[ DOS_MAX_PATH_LENGTH ];
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AnsiString;
|
|
PWSTR Name, Value;
|
|
ULONG n;
|
|
PWSTR s;
|
|
PSMP_REGISTRY_VALUE p;
|
|
|
|
//
|
|
// Skip NTDLL.DLL as it is implicitly added to KnownDll list by kernel
|
|
// before SMSS.EXE is started.
|
|
//
|
|
if (!_stricmp( ModuleName, "ntdll.dll" )) {
|
|
return;
|
|
}
|
|
|
|
RtlInitAnsiString( &AnsiString, ModuleName );
|
|
UnicodeString.Buffer = NameBuffer;
|
|
UnicodeString.Length = 0;
|
|
UnicodeString.MaximumLength = sizeof( NameBuffer );
|
|
|
|
Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
|
|
if (!NT_SUCCESS( Status )) {
|
|
return;
|
|
}
|
|
UnicodeString.MaximumLength = (USHORT)(UnicodeString.Length + sizeof( UNICODE_NULL ));
|
|
|
|
s = UnicodeString.Buffer;
|
|
n = 0;
|
|
while (n < UnicodeString.Length) {
|
|
if (*s == L'.') {
|
|
break;
|
|
}
|
|
else {
|
|
n += sizeof( WCHAR );
|
|
s += 1;
|
|
}
|
|
}
|
|
|
|
Value = UnicodeString.Buffer;
|
|
Name = UnicodeString.Buffer + (UnicodeString.MaximumLength / sizeof( WCHAR ));
|
|
n = n / sizeof( WCHAR );
|
|
wcsncpy( Name, Value, n );
|
|
Name[ n ] = UNICODE_NULL;
|
|
|
|
Status = SmpSaveRegistryValue( (PLIST_ENTRY)&SmpKnownDllsList,
|
|
Name,
|
|
Value,
|
|
TRUE
|
|
);
|
|
if (Status == STATUS_OBJECT_NAME_EXISTS || !NT_SUCCESS( Status )) {
|
|
return;
|
|
}
|
|
|
|
p = CONTAINING_RECORD( (PLIST_ENTRY)Parameter,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
KdPrint(( "SMSS: %wZ added %ws to KnownDlls\n", &p->Value, Value ));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpInitializeKnownDlls( VOID )
|
|
{
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY Head, Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
PSMP_REGISTRY_VALUE pExclude;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE LinkHandle, FileHandle, SectionHandle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
UNICODE_STRING FileName;
|
|
SECURITY_DESCRIPTOR_CONTROL OriginalSdControl;
|
|
USHORT ImageCharacteristics;
|
|
|
|
//
|
|
// Create \KnownDlls object directory
|
|
//
|
|
|
|
RtlInitUnicodeString( &UnicodeString, L"\\KnownDlls" );
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
NULL,
|
|
SmpKnownDllsSecurityDescriptor
|
|
);
|
|
Status = NtCreateDirectoryObject( &SmpKnownDllObjectDirectory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to create %wZ directory - Status == %lx\n", &UnicodeString, Status ));
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Open a handle to the file system directory that contains all the
|
|
// known DLL files so we can do relative opens.
|
|
//
|
|
|
|
if (!RtlDosPathNameToNtPathName_U( SmpKnownDllPath.Buffer,
|
|
&FileName,
|
|
NULL,
|
|
NULL
|
|
)
|
|
) {
|
|
KdPrint(( "SMSS: Unable to to convert %wZ to an Nt path\n", &SmpKnownDllPath ));
|
|
return( STATUS_OBJECT_NAME_INVALID );
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&FileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Open a handle to the known dll file directory. Don't allow
|
|
// deletes of the directory.
|
|
//
|
|
|
|
Status = NtOpenFile( &SmpKnownDllFileDirectory,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to open a handle to the KnownDll directory (%wZ) - Status == %lx\n",
|
|
&SmpKnownDllPath, Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
RtlInitUnicodeString( &UnicodeString, L"KnownDllPath" );
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
SmpKnownDllObjectDirectory,
|
|
SmpPrimarySecurityDescriptor
|
|
);
|
|
SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //Use inheritable protection if available
|
|
Status = NtCreateSymbolicLinkObject( &LinkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
&SmpKnownDllPath
|
|
);
|
|
SmpRestoreDaclDefaulted( &ObjectAttributes, OriginalSdControl );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
|
|
&UnicodeString, Status
|
|
));
|
|
return( Status );
|
|
}
|
|
|
|
Head = &SmpKnownDllsList;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
HANDLE ObjectDirectory;
|
|
|
|
ObjectDirectory = NULL;
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
pExclude = SmpFindRegistryValue( &SmpExcludeKnownDllsList, p->Name.Buffer );
|
|
if (pExclude == NULL) {
|
|
pExclude = SmpFindRegistryValue( &SmpExcludeKnownDllsList, p->Value.Buffer );
|
|
}
|
|
|
|
if (pExclude != NULL) {
|
|
KdPrint(( "Excluding %wZ from KnownDlls\n", &p->Value ));
|
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
else {
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: KnownDll( %wZ = %wZ )\n", &p->Name, &p->Value );
|
|
#endif
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&p->Value,
|
|
OBJ_CASE_INSENSITIVE,
|
|
SmpKnownDllFileDirectory,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile( &FileHandle,
|
|
SYNCHRONIZE | FILE_EXECUTE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_DELETE,
|
|
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
ObjectDirectory = SmpKnownDllObjectDirectory;
|
|
Status = LdrVerifyImageMatchesChecksum(FileHandle,
|
|
SmpProcessModuleImports,
|
|
Next,
|
|
&ImageCharacteristics
|
|
);
|
|
if ( Status == STATUS_IMAGE_CHECKSUM_MISMATCH ) {
|
|
|
|
ULONG ErrorParameters;
|
|
ULONG ErrorResponse;
|
|
|
|
//
|
|
// Hard error time. One of the know DLL's is corrupt !
|
|
//
|
|
|
|
ErrorParameters = (ULONG)(&p->Value);
|
|
|
|
NtRaiseHardError(
|
|
Status,
|
|
1,
|
|
1,
|
|
&ErrorParameters,
|
|
OptionOk,
|
|
&ErrorResponse
|
|
);
|
|
}
|
|
else
|
|
if (ImageCharacteristics & IMAGE_FILE_DLL) {
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&p->Value,
|
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
|
ObjectDirectory,
|
|
SmpLiberalSecurityDescriptor
|
|
);
|
|
SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //use inheritable protection if available
|
|
Status = NtCreateSection( &SectionHandle,
|
|
SECTION_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
NULL,
|
|
PAGE_EXECUTE,
|
|
SEC_IMAGE,
|
|
FileHandle
|
|
);
|
|
SmpRestoreDaclDefaulted( &ObjectAttributes, OriginalSdControl );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
|
|
&p->Value,
|
|
Status
|
|
));
|
|
}
|
|
else {
|
|
NtClose(SectionHandle);
|
|
}
|
|
}
|
|
else {
|
|
KdPrint(( "SMSS: Ignoring %wZ as KnownDll since it is not a DLL\n", &p->Value ));
|
|
}
|
|
|
|
NtClose( FileHandle );
|
|
}
|
|
|
|
Next = Next->Flink;
|
|
|
|
//
|
|
// Note that section remains open. This will keep it around.
|
|
// Maybe this should be a permenent section ?
|
|
//
|
|
}
|
|
|
|
Head = &SmpKnownDllsList;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
Next = Next->Flink;
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SmpProcessFileRenames( VOID )
|
|
{
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY Head, Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
HANDLE OldFileHandle;
|
|
PFILE_RENAME_INFORMATION RenameInformation;
|
|
FILE_DISPOSITION_INFORMATION DeleteInformation;
|
|
FILE_INFORMATION_CLASS SetInfoClass;
|
|
ULONG SetInfoLength;
|
|
PVOID SetInfoBuffer;
|
|
PWSTR s;
|
|
BOOLEAN WasEnabled;
|
|
|
|
Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
|
|
TRUE,
|
|
FALSE,
|
|
&WasEnabled
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
WasEnabled = TRUE;
|
|
}
|
|
|
|
//
|
|
// Process the list of file rename operations.
|
|
//
|
|
|
|
Head = &SmpFileRenameList;
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: FileRename( %wZ => %wZ )\n", &p->Name, &p->Value );
|
|
#endif
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&p->Name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Open the file for delete access
|
|
//
|
|
|
|
Status = NtOpenFile( &OldFileHandle,
|
|
(ACCESS_MASK)DELETE | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
if (p->Value.Length == 0) {
|
|
SetInfoClass = FileDispositionInformation;
|
|
SetInfoLength = sizeof( DeleteInformation );
|
|
SetInfoBuffer = &DeleteInformation;
|
|
DeleteInformation.DeleteFile = TRUE;
|
|
RenameInformation = NULL;
|
|
}
|
|
else {
|
|
SetInfoClass = FileRenameInformation;
|
|
SetInfoLength = p->Value.Length +
|
|
sizeof( *RenameInformation );
|
|
s = p->Value.Buffer;
|
|
if (*s == L'!') {
|
|
s++;
|
|
SetInfoLength -= sizeof( UNICODE_NULL );
|
|
}
|
|
|
|
SetInfoBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
|
|
SetInfoLength
|
|
);
|
|
|
|
if (SetInfoBuffer != NULL) {
|
|
RenameInformation = SetInfoBuffer;
|
|
RenameInformation->ReplaceIfExists = (BOOLEAN)(s != p->Value.Buffer);
|
|
RenameInformation->RootDirectory = NULL;
|
|
RenameInformation->FileNameLength = SetInfoLength - sizeof( *RenameInformation );
|
|
RtlMoveMemory( RenameInformation->FileName,
|
|
s,
|
|
RenameInformation->FileNameLength
|
|
);
|
|
}
|
|
else {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
Status = NtSetInformationFile( OldFileHandle,
|
|
&IoStatusBlock,
|
|
SetInfoBuffer,
|
|
SetInfoLength,
|
|
SetInfoClass
|
|
);
|
|
}
|
|
|
|
NtClose( OldFileHandle );
|
|
}
|
|
|
|
#if DBG
|
|
if (!NT_SUCCESS( Status )) {
|
|
DbgPrint( "SM: %wZ => %wZ failed - Status == %x\n",
|
|
&p->Name, &p->Value, Status
|
|
);
|
|
}
|
|
else
|
|
if (p->Value.Length == 0) {
|
|
DbgPrint( "SM: %wZ (deleted)\n", &p->Name );
|
|
}
|
|
else {
|
|
DbgPrint( "SM: %wZ (renamed to) %wZ\n", &p->Name, &p->Value );
|
|
}
|
|
#endif
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
if (!WasEnabled) {
|
|
Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
|
|
FALSE,
|
|
FALSE,
|
|
&WasEnabled
|
|
);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
VOID
|
|
SmpDumpQuery(
|
|
IN PCHAR RoutineName,
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength
|
|
)
|
|
{
|
|
PWSTR s;
|
|
|
|
if (ValueName == NULL) {
|
|
DbgPrint( "SM: SmpConfigure%s( %ws )\n", RoutineName );
|
|
return;
|
|
}
|
|
|
|
if (ValueData == NULL) {
|
|
DbgPrint( "SM: SmpConfigure%s( %ws, %ws NULL ValueData )\n", RoutineName, ValueName );
|
|
return;
|
|
}
|
|
|
|
s = (PWSTR)ValueData;
|
|
DbgPrint( "SM: SmpConfigure%s( %ws, %u, (%u) ", RoutineName, ValueName, ValueType, ValueLength );
|
|
if (ValueType == REG_SZ || ValueType == REG_EXPAND_SZ || ValueType == REG_MULTI_SZ) {
|
|
while (*s) {
|
|
if (s != (PWSTR)ValueData) {
|
|
DbgPrint( ", " );
|
|
}
|
|
DbgPrint( "'%ws'", s );
|
|
while(*s++) {
|
|
}
|
|
if (ValueType != REG_MULTI_SZ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DbgPrint( "*** non-string data (%08lx)", *(PULONG)ValueData );
|
|
}
|
|
|
|
DbgPrint( "\n" );
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
SmpConfigureObjectDirectories(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
PWSTR s;
|
|
UNICODE_STRING UnicodeString;
|
|
UNICODE_STRING RpcControl;
|
|
UNICODE_STRING Windows;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE DirectoryHandle;
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
|
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
RtlInitUnicodeString( &RpcControl, L"\\RPC Control");
|
|
RtlInitUnicodeString( &Windows, L"\\Windows");
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "ObjectDirectories", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueName );
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
UNREFERENCED_PARAMETER( ValueLength );
|
|
#endif
|
|
s = (PWSTR)ValueData;
|
|
while (*s) {
|
|
RtlInitUnicodeString( &UnicodeString, s );
|
|
|
|
//
|
|
// This is NOT how I would choose to do this if starting from
|
|
// scratch, but we are very close to shipping Daytona and I
|
|
// needed to get the right protection on these objects.
|
|
//
|
|
|
|
SecurityDescriptor = SmpPrimarySecurityDescriptor;
|
|
if (RtlEqualString( (PSTRING)&UnicodeString, (PSTRING)&RpcControl, TRUE ) ||
|
|
RtlEqualString( (PSTRING)&UnicodeString, (PSTRING)&Windows, TRUE) ) {
|
|
SecurityDescriptor = SmpLiberalSecurityDescriptor;
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
NULL,
|
|
SecurityDescriptor
|
|
);
|
|
Status = NtCreateDirectoryObject( &DirectoryHandle,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to create %wZ object directory - Status == %lx\n", &UnicodeString, Status ));
|
|
}
|
|
else {
|
|
NtClose( DirectoryHandle );
|
|
}
|
|
|
|
while (*s++) {
|
|
}
|
|
}
|
|
|
|
//
|
|
// We dont care if the creates failed.
|
|
//
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpConfigureExecute(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "Execute", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueName );
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
UNREFERENCED_PARAMETER( ValueLength );
|
|
#endif
|
|
return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
|
|
ValueData,
|
|
NULL,
|
|
TRUE
|
|
)
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpConfigureMemoryMgmt(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "MemoryMgmt", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueName );
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
UNREFERENCED_PARAMETER( ValueLength );
|
|
#endif
|
|
return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
|
|
ValueData,
|
|
NULL,
|
|
TRUE
|
|
)
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpConfigureFileRenames(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
static PWSTR OldName = NULL;
|
|
|
|
UNREFERENCED_PARAMETER( Context );
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "FileRenameOperation", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
#endif
|
|
|
|
//
|
|
// This routine gets called for each string in the MULTI_SZ. The
|
|
// first string we get is the old name, the next string is the new name.
|
|
//
|
|
if (OldName == NULL) {
|
|
//
|
|
// Save a pointer to the old name, we'll need it on the next
|
|
// callback.
|
|
//
|
|
OldName = ValueData;
|
|
return(STATUS_SUCCESS);
|
|
} else {
|
|
Status = SmpSaveRegistryValue((PLIST_ENTRY)EntryContext,
|
|
OldName,
|
|
ValueData,
|
|
FALSE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint("SMSS: SmpSaveRegistryValue returned %08lx for FileRenameOperation\n", Status);
|
|
DbgPrint("SMSS: %ws %ws\n", OldName, ValueData);
|
|
#endif
|
|
}
|
|
OldName = NULL;
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpConfigureDosDevices(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "DosDevices", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
UNREFERENCED_PARAMETER( ValueLength );
|
|
#endif
|
|
return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
|
|
ValueName,
|
|
ValueData,
|
|
TRUE
|
|
)
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpConfigureKnownDlls(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "KnownDlls", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
#endif
|
|
if (!_wcsicmp( ValueName, L"DllDirectory" )) {
|
|
SmpKnownDllPath.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
|
|
ValueLength
|
|
);
|
|
if (SmpKnownDllPath.Buffer == NULL) {
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
SmpKnownDllPath.Length = (USHORT)(ValueLength - sizeof( UNICODE_NULL ) );
|
|
SmpKnownDllPath.MaximumLength = (USHORT)ValueLength;
|
|
RtlMoveMemory( SmpKnownDllPath.Buffer,
|
|
ValueData,
|
|
ValueLength
|
|
);
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
else {
|
|
return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
|
|
ValueName,
|
|
ValueData,
|
|
TRUE
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpConfigureExcludeKnownDlls(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "ExcludeKnownDlls", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
#endif
|
|
if (ValueType == REG_MULTI_SZ || ValueType == REG_SZ) {
|
|
PWSTR s;
|
|
|
|
s = (PWSTR)ValueData;
|
|
while (*s != UNICODE_NULL) {
|
|
Status = SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
|
|
s,
|
|
NULL,
|
|
TRUE
|
|
);
|
|
if (!NT_SUCCESS( Status ) || ValueType == REG_SZ) {
|
|
return Status;
|
|
}
|
|
|
|
while (*s++ != UNICODE_NULL) {
|
|
}
|
|
}
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpConfigureEnvironment(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING Name, Value;
|
|
UNREFERENCED_PARAMETER( Context );
|
|
UNREFERENCED_PARAMETER( EntryContext );
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "Environment", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
#endif
|
|
|
|
|
|
RtlInitUnicodeString( &Name, ValueName );
|
|
RtlInitUnicodeString( &Value, ValueData );
|
|
|
|
Status = RtlSetEnvironmentVariable( NULL,
|
|
&Name,
|
|
&Value
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n",
|
|
&Name, &Value, Status
|
|
));
|
|
return( Status );
|
|
}
|
|
|
|
if (!_wcsicmp( ValueName, L"Path" )) {
|
|
|
|
SmpDefaultLibPathBuffer = RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
ValueLength
|
|
);
|
|
if ( !SmpDefaultLibPathBuffer ) {
|
|
return ( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
RtlMoveMemory( SmpDefaultLibPathBuffer,
|
|
ValueData,
|
|
ValueLength
|
|
);
|
|
|
|
RtlInitUnicodeString( &SmpDefaultLibPath, SmpDefaultLibPathBuffer );
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpConfigureSubSystems(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "SubSystems", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueLength );
|
|
#endif
|
|
|
|
if (!_wcsicmp( ValueName, L"Required" ) || !_wcsicmp( ValueName, L"Optional" )) {
|
|
if (ValueType == REG_MULTI_SZ) {
|
|
//
|
|
// Here if processing Required= or Optional= values, since they are
|
|
// the only REG_MULTI_SZ value types under the SubSystem key.
|
|
//
|
|
PSMP_REGISTRY_VALUE p;
|
|
PWSTR s;
|
|
|
|
s = (PWSTR)ValueData;
|
|
while (*s != UNICODE_NULL) {
|
|
p = SmpFindRegistryValue( (PLIST_ENTRY)EntryContext,
|
|
s
|
|
);
|
|
if (p != NULL) {
|
|
RemoveEntryList( &p->Entry );
|
|
|
|
|
|
//
|
|
// Required Subsystems are loaded. Optional subsystems are
|
|
// defered.
|
|
//
|
|
|
|
if (!_wcsicmp( ValueName, L"Required" ) ) {
|
|
InsertTailList( &SmpSubSystemsToLoad, &p->Entry );
|
|
}
|
|
else {
|
|
InsertTailList( &SmpSubSystemsToDefer, &p->Entry );
|
|
}
|
|
}
|
|
else {
|
|
KdPrint(( "SMSS: Invalid subsystem name - %ws\n", s ));
|
|
}
|
|
|
|
while (*s++ != UNICODE_NULL) {
|
|
}
|
|
}
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
else {
|
|
return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
|
|
ValueName,
|
|
ValueData,
|
|
TRUE
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpParseToken(
|
|
IN PUNICODE_STRING Source,
|
|
IN BOOLEAN RemainderOfSource,
|
|
OUT PUNICODE_STRING Token
|
|
)
|
|
{
|
|
PWSTR s, s1;
|
|
ULONG i, cb;
|
|
|
|
RtlInitUnicodeString( Token, NULL );
|
|
s = Source->Buffer;
|
|
if (Source->Length == 0) {
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
i = 0;
|
|
while ((USHORT)i < Source->Length && *s <= L' ') {
|
|
s++;
|
|
i += 2;
|
|
}
|
|
if (RemainderOfSource) {
|
|
cb = Source->Length - (i * sizeof( WCHAR ));
|
|
s1 = (PWSTR)((PCHAR)s + cb);
|
|
i = Source->Length / sizeof( WCHAR );
|
|
}
|
|
else {
|
|
s1 = s;
|
|
while ((USHORT)i < Source->Length && *s1 > L' ') {
|
|
s1++;
|
|
i += 2;
|
|
}
|
|
cb = (PCHAR)s1 - (PCHAR)s;
|
|
while ((USHORT)i < Source->Length && *s1 <= L' ') {
|
|
s1++;
|
|
i += 2;
|
|
}
|
|
}
|
|
|
|
if (cb > 0) {
|
|
Token->Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), cb + sizeof( UNICODE_NULL ) );
|
|
if (Token->Buffer == NULL) {
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
Token->Length = (USHORT)cb;
|
|
Token->MaximumLength = (USHORT)(cb + sizeof( UNICODE_NULL ));
|
|
RtlMoveMemory( Token->Buffer, s, cb );
|
|
Token->Buffer[ cb / sizeof( WCHAR ) ] = UNICODE_NULL;
|
|
}
|
|
|
|
Source->Length -= (USHORT)((PCHAR)s1 - (PCHAR)Source->Buffer);
|
|
Source->Buffer = s1;
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpParseCommandLine(
|
|
IN PUNICODE_STRING CommandLine,
|
|
OUT PULONG Flags OPTIONAL,
|
|
OUT PUNICODE_STRING ImageFileName,
|
|
OUT PUNICODE_STRING ImageFileDirectory,
|
|
OUT PUNICODE_STRING Arguments
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING Input, Token;
|
|
UNICODE_STRING PathVariableName;
|
|
UNICODE_STRING PathVariableValue;
|
|
PWSTR DosFilePart;
|
|
WCHAR FullDosPathBuffer[ DOS_MAX_PATH_LENGTH ];
|
|
ULONG SpResult;
|
|
|
|
RtlInitUnicodeString( ImageFileName, NULL );
|
|
RtlInitUnicodeString( Arguments, NULL );
|
|
|
|
//
|
|
// make sure lib path has systemroot\system32. Otherwise, the system will
|
|
// not boot properly
|
|
//
|
|
|
|
if ( !SmpSystemRoot.Length ) {
|
|
UNICODE_STRING NewLibString;
|
|
|
|
RtlInitUnicodeString( &SmpSystemRoot,USER_SHARED_DATA->NtSystemRoot );
|
|
|
|
|
|
NewLibString.Length = 0;
|
|
NewLibString.MaximumLength =
|
|
SmpSystemRoot.MaximumLength +
|
|
20 + // length of \system32;
|
|
SmpDefaultLibPath.MaximumLength;
|
|
|
|
NewLibString.Buffer = RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
NewLibString.MaximumLength
|
|
);
|
|
|
|
if ( NewLibString.Buffer ) {
|
|
RtlAppendUnicodeStringToString(&NewLibString,&SmpSystemRoot );
|
|
RtlAppendUnicodeToString(&NewLibString,L"\\system32;");
|
|
RtlAppendUnicodeStringToString(&NewLibString,&SmpDefaultLibPath );
|
|
|
|
RtlFreeHeap(RtlProcessHeap(), 0, SmpDefaultLibPath.Buffer );
|
|
|
|
SmpDefaultLibPath = NewLibString;
|
|
}
|
|
}
|
|
|
|
Input = *CommandLine;
|
|
while (TRUE) {
|
|
Status = SmpParseToken( &Input, FALSE, &Token );
|
|
if (!NT_SUCCESS( Status ) || Token.Buffer == NULL) {
|
|
return( STATUS_UNSUCCESSFUL );
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( Flags )) {
|
|
if (RtlEqualUnicodeString( &Token, &SmpDebugKeyword, TRUE )) {
|
|
*Flags |= SMP_DEBUG_FLAG;
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
|
|
continue;
|
|
}
|
|
else
|
|
if (RtlEqualUnicodeString( &Token, &SmpASyncKeyword, TRUE )) {
|
|
*Flags |= SMP_ASYNC_FLAG;
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
|
|
continue;
|
|
}
|
|
else
|
|
if (RtlEqualUnicodeString( &Token, &SmpAutoChkKeyword, TRUE )) {
|
|
*Flags |= SMP_AUTOCHK_FLAG;
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
|
|
continue;
|
|
}
|
|
}
|
|
|
|
SpResult = 0;
|
|
RtlInitUnicodeString( &PathVariableName, L"Path" );
|
|
PathVariableValue.Length = 0;
|
|
PathVariableValue.MaximumLength = 4096;
|
|
PathVariableValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
|
|
PathVariableValue.MaximumLength
|
|
);
|
|
Status = RtlQueryEnvironmentVariable_U( SmpDefaultEnvironment,
|
|
&PathVariableName,
|
|
&PathVariableValue
|
|
);
|
|
if ( Status == STATUS_BUFFER_TOO_SMALL ) {
|
|
PathVariableValue.MaximumLength = PathVariableValue.Length + 2;
|
|
PathVariableValue.Length = 0;
|
|
PathVariableValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
|
|
PathVariableValue.MaximumLength
|
|
);
|
|
Status = RtlQueryEnvironmentVariable_U( SmpDefaultEnvironment,
|
|
&PathVariableName,
|
|
&PathVariableValue
|
|
);
|
|
}
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: %wZ environment variable not defined.\n", &PathVariableName ));
|
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
else
|
|
if (!ARGUMENT_PRESENT( Flags ) ||
|
|
!(SpResult = RtlDosSearchPath_U( PathVariableValue.Buffer,
|
|
Token.Buffer,
|
|
L".exe",
|
|
sizeof( FullDosPathBuffer ),
|
|
FullDosPathBuffer,
|
|
&DosFilePart
|
|
))
|
|
) {
|
|
if (!ARGUMENT_PRESENT( Flags )) {
|
|
wcscpy( FullDosPathBuffer, Token.Buffer );
|
|
}
|
|
else {
|
|
|
|
if ( !SpResult ) {
|
|
|
|
//
|
|
// The search path call failed. Now try the call again using
|
|
// the default lib path. This always has systemroot\system32
|
|
// at the front.
|
|
//
|
|
|
|
SpResult = RtlDosSearchPath_U(
|
|
SmpDefaultLibPath.Buffer,
|
|
Token.Buffer,
|
|
L".exe",
|
|
sizeof( FullDosPathBuffer ),
|
|
FullDosPathBuffer,
|
|
&DosFilePart
|
|
);
|
|
}
|
|
if ( !SpResult ) {
|
|
*Flags |= SMP_IMAGE_NOT_FOUND;
|
|
*ImageFileName = Token;
|
|
RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer );
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
}
|
|
}
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer );
|
|
if (NT_SUCCESS( Status ) &&
|
|
!RtlDosPathNameToNtPathName_U( FullDosPathBuffer,
|
|
ImageFileName,
|
|
NULL,
|
|
NULL
|
|
)
|
|
) {
|
|
KdPrint(( "SMSS: Unable to translate %ws into an NT File Name\n",
|
|
FullDosPathBuffer
|
|
));
|
|
Status = STATUS_OBJECT_PATH_INVALID;
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ImageFileDirectory )) {
|
|
if (DosFilePart > FullDosPathBuffer) {
|
|
*--DosFilePart = UNICODE_NULL;
|
|
RtlCreateUnicodeString( ImageFileDirectory,
|
|
FullDosPathBuffer
|
|
);
|
|
}
|
|
else {
|
|
RtlInitUnicodeString( ImageFileDirectory, NULL );
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
Status = SmpParseToken( &Input, TRUE, Arguments );
|
|
return( Status );
|
|
}
|
|
|
|
|
|
ULONG
|
|
SmpConvertInteger(
|
|
IN PWSTR String
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING UnicodeString;
|
|
ULONG Value;
|
|
|
|
RtlInitUnicodeString( &UnicodeString, String );
|
|
Status = RtlUnicodeStringToInteger( &UnicodeString, 0, &Value );
|
|
if (NT_SUCCESS( Status )) {
|
|
return( Value );
|
|
}
|
|
else {
|
|
return( 0 );
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpAddPagingFile(
|
|
IN PUNICODE_STRING PagingFileSpec
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called during configuration to add a paging file
|
|
to the system.
|
|
|
|
The format of PagingFileSpec is:
|
|
|
|
name-of-paging-file size-of-paging-file(in megabytes)
|
|
|
|
Arguments:
|
|
|
|
PagingFileSpec - Unicode string that specifies the paging file name
|
|
and size.
|
|
|
|
Return Value:
|
|
|
|
Status of operation
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING PagingFileName;
|
|
UNICODE_STRING Arguments;
|
|
ULONG PageFileMinSizeInMb;
|
|
ULONG PageFileMaxSizeInMb;
|
|
PWSTR ArgSave, Arg2;
|
|
|
|
if (CountPageFiles == MAX_PAGING_FILES) {
|
|
KdPrint(( "SMSS: Too many paging files specified - %d\n", CountPageFiles ));
|
|
return( STATUS_TOO_MANY_PAGING_FILES );
|
|
}
|
|
|
|
Status = SmpParseCommandLine( PagingFileSpec,
|
|
NULL,
|
|
&PagingFileName,
|
|
NULL,
|
|
&Arguments
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", PagingFileSpec, Status ));
|
|
return( Status );
|
|
}
|
|
|
|
PageFileMaxSizeInMb = 0;
|
|
Status = RtlUnicodeStringToInteger( &Arguments, 0, &PageFileMinSizeInMb );
|
|
if (!NT_SUCCESS( Status )) {
|
|
PageFileMinSizeInMb = 10;
|
|
}
|
|
else {
|
|
ArgSave = Arguments.Buffer;
|
|
Arg2 = ArgSave;
|
|
while (*Arg2 != UNICODE_NULL) {
|
|
if (*Arg2++ == L' ') {
|
|
Arguments.Length -= (USHORT)((PCHAR)Arg2 - (PCHAR)ArgSave);
|
|
Arguments.Buffer = Arg2;
|
|
Status = RtlUnicodeStringToInteger( &Arguments, 0, &PageFileMaxSizeInMb );
|
|
if (!NT_SUCCESS( Status )) {
|
|
PageFileMaxSizeInMb = 0;
|
|
}
|
|
|
|
Arguments.Buffer = ArgSave;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PageFileMinSizeInMb == 0) {
|
|
PageFileMinSizeInMb = 10;
|
|
}
|
|
|
|
if (PageFileMaxSizeInMb == 0) {
|
|
PageFileMaxSizeInMb = PageFileMinSizeInMb + 50;
|
|
}
|
|
else
|
|
if (PageFileMaxSizeInMb < PageFileMinSizeInMb) {
|
|
PageFileMaxSizeInMb = PageFileMinSizeInMb;
|
|
}
|
|
|
|
PageFileSpecs[ CountPageFiles ] = PagingFileName;
|
|
PageFileMinSizes[ CountPageFiles ] = (LONG)PageFileMinSizeInMb;
|
|
PageFileMaxSizes[ CountPageFiles ] = (LONG)PageFileMaxSizeInMb;
|
|
|
|
CountPageFiles++;
|
|
|
|
if (Arguments.Buffer) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Arguments.Buffer );
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpCreatePagingFile(
|
|
PUNICODE_STRING PageFileSpec,
|
|
LARGE_INTEGER MinPagingFileSize,
|
|
LARGE_INTEGER MaxPagingFileSize
|
|
)
|
|
{
|
|
NTSTATUS Status, Status1;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Handle;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
BOOLEAN FileSizeInfoValid;
|
|
FILE_STANDARD_INFORMATION FileSizeInfo;
|
|
FILE_DISPOSITION_INFORMATION Disposition;
|
|
FILE_FS_SIZE_INFORMATION SizeInfo;
|
|
UNICODE_STRING VolumePath;
|
|
ULONG n;
|
|
PWSTR s;
|
|
LARGE_INTEGER AvailableBytes;
|
|
LARGE_INTEGER MinimumSlop;
|
|
|
|
FileSizeInfoValid = FALSE;
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
PageFileSpec,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile( &Handle,
|
|
(ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
Status = NtQueryInformationFile( Handle,
|
|
&IoStatusBlock,
|
|
&FileSizeInfo,
|
|
sizeof( FileSizeInfo ),
|
|
FileStandardInformation
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
FileSizeInfoValid = TRUE;
|
|
}
|
|
|
|
NtClose( Handle );
|
|
}
|
|
|
|
VolumePath = *PageFileSpec;
|
|
n = VolumePath.Length;
|
|
VolumePath.Length = 0;
|
|
s = VolumePath.Buffer;
|
|
while (n) {
|
|
if (*s++ == L':' && *s == OBJ_NAME_PATH_SEPARATOR) {
|
|
s++;
|
|
break;
|
|
}
|
|
else {
|
|
n -= sizeof( WCHAR );
|
|
}
|
|
}
|
|
VolumePath.Length = (USHORT)((PCHAR)s - (PCHAR)VolumePath.Buffer);
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&VolumePath,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile( &Handle,
|
|
(ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Determine the size parameters of the volume.
|
|
//
|
|
|
|
Status = NtQueryVolumeInformationFile( Handle,
|
|
&IoStatusBlock,
|
|
&SizeInfo,
|
|
sizeof( SizeInfo ),
|
|
FileFsSizeInformation
|
|
);
|
|
NtClose( Handle );
|
|
if (!NT_SUCCESS( Status )) {
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Deal with 64 bit sizes
|
|
//
|
|
|
|
AvailableBytes = RtlExtendedIntegerMultiply( SizeInfo.AvailableAllocationUnits,
|
|
SizeInfo.SectorsPerAllocationUnit
|
|
);
|
|
|
|
AvailableBytes = RtlExtendedIntegerMultiply( AvailableBytes,
|
|
SizeInfo.BytesPerSector
|
|
);
|
|
if (FileSizeInfoValid) {
|
|
AvailableBytes.QuadPart += FileSizeInfo.AllocationSize.QuadPart;
|
|
}
|
|
|
|
if ( AvailableBytes.QuadPart <= MinPagingFileSize.QuadPart ) {
|
|
Status = STATUS_DISK_FULL;
|
|
}
|
|
else {
|
|
AvailableBytes.QuadPart -= ( 2 * 1024 * 1024 );
|
|
if ( AvailableBytes.QuadPart <= MinPagingFileSize.QuadPart ) {
|
|
Status = STATUS_DISK_FULL;
|
|
}
|
|
else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
Status = NtCreatePagingFile( PageFileSpec,
|
|
&MinPagingFileSize,
|
|
&MaxPagingFileSize,
|
|
0
|
|
);
|
|
}
|
|
else
|
|
if (FileSizeInfoValid) {
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
PageFileSpec,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status1 = NtOpenFile( &Handle,
|
|
(ACCESS_MASK)DELETE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_DELETE |
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE,
|
|
FILE_NON_DIRECTORY_FILE
|
|
);
|
|
if (NT_SUCCESS( Status1 )) {
|
|
Disposition.DeleteFile = TRUE;
|
|
Status1 = NtSetInformationFile( Handle,
|
|
&IoStatusBlock,
|
|
&Disposition,
|
|
sizeof( Disposition ),
|
|
FileDispositionInformation
|
|
);
|
|
|
|
if (NT_SUCCESS( Status1 )) {
|
|
KdPrint(( "SMSS: Deleted stale paging file - %wZ\n", PageFileSpec ));
|
|
}
|
|
|
|
NtClose(Handle);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpCreatePagingFiles( VOID )
|
|
{
|
|
LARGE_INTEGER MinPagingFileSize, MaxPagingFileSize;
|
|
NTSTATUS Status;
|
|
ULONG i, Pass;
|
|
PWSTR CurrentDrive;
|
|
char MessageBuffer[ 128 ];
|
|
BOOLEAN CreatedAtLeastOnePagingFile = FALSE;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
for (Pass=1; Pass<=2; Pass++) {
|
|
for (i=0; i<CountPageFiles; i++) {
|
|
if (CurrentDrive = wcsstr( PageFileSpecs[ i ].Buffer, L"?:" )) {
|
|
if (Pass == 2 && CreatedAtLeastOnePagingFile) {
|
|
continue;
|
|
}
|
|
|
|
*CurrentDrive = L'C';
|
|
}
|
|
else
|
|
if (Pass == 2) {
|
|
continue;
|
|
}
|
|
retry:
|
|
MinPagingFileSize.QuadPart = Int32x32To64( PageFileMinSizes[ i ],
|
|
0x100000
|
|
);
|
|
MaxPagingFileSize.QuadPart = Int32x32To64( PageFileMaxSizes[ i ],
|
|
0x100000
|
|
);
|
|
Status = SmpCreatePagingFile( &PageFileSpecs[ i ],
|
|
MinPagingFileSize,
|
|
MaxPagingFileSize
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
if (CurrentDrive &&
|
|
Pass == 1 &&
|
|
*CurrentDrive < L'Z' &&
|
|
Status != STATUS_NO_SUCH_DEVICE &&
|
|
Status != STATUS_OBJECT_PATH_NOT_FOUND &&
|
|
Status != STATUS_OBJECT_NAME_NOT_FOUND
|
|
) {
|
|
*CurrentDrive += 1;
|
|
goto retry;
|
|
}
|
|
else
|
|
if (PageFileMinSizes[ i ] > 2 &&
|
|
(CurrentDrive == NULL || Pass == 2) &&
|
|
Status == STATUS_DISK_FULL
|
|
) {
|
|
PageFileMinSizes[ i ] -= 2;
|
|
goto retry;
|
|
}
|
|
else
|
|
if (CurrentDrive &&
|
|
Pass == 2 &&
|
|
*CurrentDrive < L'Z' &&
|
|
Status == STATUS_DISK_FULL
|
|
) {
|
|
*CurrentDrive += 1;
|
|
goto retry;
|
|
}
|
|
else
|
|
if (CurrentDrive && Pass == 2) {
|
|
*CurrentDrive = L'?';
|
|
sprintf( MessageBuffer,
|
|
"INIT: Failed to find drive with space for %wZ (%u MB)\n",
|
|
&PageFileSpecs[ i ],
|
|
PageFileMinSizes[ i ]
|
|
);
|
|
|
|
#if DBG
|
|
SmpDisplayString( MessageBuffer );
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
CreatedAtLeastOnePagingFile = TRUE;
|
|
if (CurrentDrive) {
|
|
sprintf( MessageBuffer,
|
|
"INIT: Created paging file: %wZ [%u..%u] MB\n",
|
|
&PageFileSpecs[ i ],
|
|
PageFileMinSizes[ i ],
|
|
PageFileMaxSizes[ i ]
|
|
);
|
|
|
|
#if DBG
|
|
SmpDisplayString( MessageBuffer );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (Pass == 2) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, PageFileSpecs[ i ].Buffer );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!CreatedAtLeastOnePagingFile) {
|
|
sprintf( MessageBuffer,
|
|
"INIT: Unable to create a paging file. Proceeding anyway.\n"
|
|
);
|
|
|
|
#if DBG
|
|
SmpDisplayString( MessageBuffer );
|
|
#endif
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpExecuteImage(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG Flags,
|
|
IN OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates and starts a process specified by the
|
|
CommandLine parameter. After starting the process, the procedure
|
|
will optionally wait for the first thread in the process to
|
|
terminate.
|
|
|
|
Arguments:
|
|
|
|
ImageFileName - Supplies the full NT path for the image file to
|
|
execute. Presumably computed or extracted from the first
|
|
token of the CommandLine.
|
|
|
|
CommandLine - Supplies the command line to execute. The first blank
|
|
separate token on the command line must be a fully qualified NT
|
|
Path name of an image file to execute.
|
|
|
|
Flags - Supplies information about how to invoke the command.
|
|
|
|
ProcessInformation - Optional parameter, which if specified, receives
|
|
information for images invoked with the SMP_ASYNC_FLAG. Ignore
|
|
if this flag is not set.
|
|
|
|
Return Value:
|
|
|
|
Status of operation
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
RTL_USER_PROCESS_INFORMATION MyProcessInformation;
|
|
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
|
|
|
if (!ARGUMENT_PRESENT( ProcessInformation )) {
|
|
ProcessInformation = &MyProcessInformation;
|
|
}
|
|
|
|
|
|
Status = RtlCreateProcessParameters( &ProcessParameters,
|
|
ImageFileName,
|
|
(SmpDefaultLibPath.Length == 0 ?
|
|
NULL : &SmpDefaultLibPath
|
|
),
|
|
CurrentDirectory,
|
|
CommandLine,
|
|
SmpDefaultEnvironment,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
ASSERTMSG( "RtlCreateProcessParameters", NT_SUCCESS( Status ) );
|
|
if (Flags & SMP_DEBUG_FLAG) {
|
|
ProcessParameters->DebugFlags = TRUE;
|
|
}
|
|
else {
|
|
ProcessParameters->DebugFlags = SmpDebug;
|
|
}
|
|
|
|
if ( Flags & SMP_SUBSYSTEM_FLAG ) {
|
|
ProcessParameters->Flags |= RTL_USER_PROC_RESERVE_1MB;
|
|
}
|
|
|
|
ProcessInformation->Length = sizeof( RTL_USER_PROCESS_INFORMATION );
|
|
Status = RtlCreateUserProcess( ImageFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
ProcessParameters,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
ProcessInformation
|
|
);
|
|
RtlDestroyProcessParameters( ProcessParameters );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
KdPrint(( "SMSS: Failed load of %wZ - Status == %lx\n",
|
|
ImageFileName,
|
|
Status
|
|
));
|
|
return( Status );
|
|
}
|
|
|
|
if (!(Flags & SMP_DONT_START)) {
|
|
if (ProcessInformation->ImageInformation.SubSystemType !=
|
|
IMAGE_SUBSYSTEM_NATIVE
|
|
) {
|
|
NtTerminateProcess( ProcessInformation->Process,
|
|
STATUS_INVALID_IMAGE_FORMAT
|
|
);
|
|
NtWaitForSingleObject( ProcessInformation->Thread, FALSE, NULL );
|
|
NtClose( ProcessInformation->Thread );
|
|
NtClose( ProcessInformation->Process );
|
|
KdPrint(( "SMSS: Not an NT image - %wZ\n", ImageFileName ));
|
|
return( STATUS_INVALID_IMAGE_FORMAT );
|
|
}
|
|
|
|
NtResumeThread( ProcessInformation->Thread, NULL );
|
|
|
|
if (!(Flags & SMP_ASYNC_FLAG)) {
|
|
NtWaitForSingleObject( ProcessInformation->Thread, FALSE, NULL );
|
|
}
|
|
|
|
NtClose( ProcessInformation->Thread );
|
|
NtClose( ProcessInformation->Process );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpExecuteCommand(
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to execute a command.
|
|
|
|
The format of CommandLine is:
|
|
|
|
Nt-Path-To-AutoChk.exe Nt-Path-To-Disk-Partition
|
|
|
|
If the NT path to the disk partition is an asterisk, then invoke
|
|
the AutoChk.exe utility on all hard disk partitions.
|
|
|
|
Arguments:
|
|
|
|
CommandLine - Supplies the Command line to invoke.
|
|
|
|
Flags - Specifies the type of command and options.
|
|
|
|
Return Value:
|
|
|
|
Status of operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING ImageFileName;
|
|
UNICODE_STRING CurrentDirectory;
|
|
UNICODE_STRING Arguments;
|
|
|
|
if (Flags & SMP_DEBUG_FLAG) {
|
|
return( SmpLoadDbgSs( NULL ) );
|
|
}
|
|
|
|
Status = SmpParseCommandLine( CommandLine,
|
|
&Flags,
|
|
&ImageFileName,
|
|
&CurrentDirectory,
|
|
&Arguments
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", CommandLine, Status ));
|
|
return( Status );
|
|
}
|
|
|
|
if (Flags & SMP_AUTOCHK_FLAG) {
|
|
Status = SmpInvokeAutoChk( &ImageFileName, &CurrentDirectory, &Arguments, Flags );
|
|
}
|
|
else
|
|
if (Flags & SMP_SUBSYSTEM_FLAG) {
|
|
Status = SmpLoadSubSystem( &ImageFileName, &CurrentDirectory, CommandLine, Flags );
|
|
}
|
|
else {
|
|
if (Flags & SMP_IMAGE_NOT_FOUND) {
|
|
KdPrint(( "SMSS: Image file (%wZ) not found\n", &ImageFileName ));
|
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
else {
|
|
Status = SmpExecuteImage( &ImageFileName,
|
|
&CurrentDirectory,
|
|
CommandLine,
|
|
Flags,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
|
|
if (ImageFileName.Buffer && !(Flags & SMP_IMAGE_NOT_FOUND)) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, ImageFileName.Buffer );
|
|
if (CurrentDirectory.Buffer != NULL) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, CurrentDirectory.Buffer );
|
|
}
|
|
}
|
|
|
|
if (Arguments.Buffer) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Arguments.Buffer );
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Command '%wZ' failed - Status == %x\n", CommandLine, Status ));
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SmpInvokeAutoChk(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING Arguments,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Handle;
|
|
|
|
POBJECT_DIRECTORY_INFORMATION DirInfo;
|
|
CHAR DirInfoBuffer[ 256 ];
|
|
ULONG Context, Length;
|
|
BOOLEAN RestartScan;
|
|
BOOLEAN ForceAutoChk;
|
|
|
|
UNICODE_STRING ArgPrefix;
|
|
UNICODE_STRING LinkTarget;
|
|
UNICODE_STRING LinkTypeName;
|
|
UNICODE_STRING LinkTargetPrefix;
|
|
WCHAR LinkTargetBuffer[ MAXIMUM_FILENAME_LENGTH ];
|
|
|
|
CHAR DisplayBuffer[ MAXIMUM_FILENAME_LENGTH ];
|
|
ANSI_STRING AnsiDisplayString;
|
|
UNICODE_STRING DisplayString;
|
|
|
|
UNICODE_STRING CmdLine;
|
|
WCHAR CmdLineBuffer[ 2 * MAXIMUM_FILENAME_LENGTH ];
|
|
UNICODE_STRING NtDllName;
|
|
PVOID NtDllHandle;
|
|
PMESSAGE_RESOURCE_ENTRY MessageEntry;
|
|
PSZ CheckingString = NULL;
|
|
|
|
//
|
|
// Query the system environment variable "osloadoptions" to determine
|
|
// if SOS is specified.
|
|
//
|
|
|
|
if (SmpQueryRegistrySosOption() != FALSE) {
|
|
SmpEnableDots = FALSE;
|
|
}
|
|
|
|
RtlInitUnicodeString(&NtDllName, L"ntdll");
|
|
Status = LdrGetDllHandle(
|
|
NULL,
|
|
NULL,
|
|
&NtDllName,
|
|
&NtDllHandle
|
|
);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
Status = RtlFindMessage(
|
|
NtDllHandle,
|
|
11,
|
|
#if defined(DBCS) // SmpInvokeAutoChk()
|
|
//
|
|
// We have to use ENGLISH resource anytime instead of default resource. Because
|
|
// We can only display ASCII character onto Blue Screen via HalDisplayString()
|
|
//
|
|
MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
|
|
#else
|
|
0,
|
|
#endif // defined(DBCS)
|
|
STATUS_CHECKING_FILE_SYSTEM,
|
|
&MessageEntry
|
|
);
|
|
if ( NT_SUCCESS(Status) ) {
|
|
CheckingString = MessageEntry->Text;
|
|
}
|
|
}
|
|
|
|
if (!CheckingString) {
|
|
CheckingString = "Checking File System on %wZ\n";
|
|
}
|
|
|
|
if (Flags & SMP_IMAGE_NOT_FOUND) {
|
|
sprintf( DisplayBuffer,
|
|
"%wZ program not found - skipping AUTOCHECK\n",
|
|
ImageFileName
|
|
);
|
|
|
|
RtlInitAnsiString( &AnsiDisplayString, DisplayBuffer );
|
|
Status = RtlAnsiStringToUnicodeString( &DisplayString,
|
|
&AnsiDisplayString,
|
|
TRUE
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
NtDisplayString( &DisplayString );
|
|
RtlFreeUnicodeString( &DisplayString );
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
RtlInitUnicodeString( &ArgPrefix, L"/p " );
|
|
if (RtlPrefixUnicodeString( &ArgPrefix, Arguments, TRUE )) {
|
|
Arguments->Length -= 3 * sizeof( WCHAR );
|
|
RtlMoveMemory( Arguments->Buffer,
|
|
Arguments->Buffer + 3,
|
|
Arguments->Length
|
|
);
|
|
ForceAutoChk = TRUE;
|
|
}
|
|
else {
|
|
ForceAutoChk = FALSE;
|
|
}
|
|
|
|
CmdLine.Buffer = CmdLineBuffer;
|
|
CmdLine.MaximumLength = sizeof( CmdLineBuffer );
|
|
RtlInitUnicodeString( &LinkTarget, L"*" );
|
|
if (!RtlEqualUnicodeString( Arguments, &LinkTarget, TRUE )) {
|
|
CmdLine.Length = 0;
|
|
RtlAppendUnicodeStringToString( &CmdLine, ImageFileName );
|
|
RtlAppendUnicodeToString( &CmdLine, L" " );
|
|
if (ForceAutoChk) {
|
|
RtlAppendUnicodeToString( &CmdLine, L"/p " );
|
|
}
|
|
RtlAppendUnicodeStringToString( &CmdLine, Arguments );
|
|
SmpExecuteImage( ImageFileName,
|
|
CurrentDirectory,
|
|
&CmdLine,
|
|
Flags & ~SMP_AUTOCHK_FLAG,
|
|
NULL
|
|
);
|
|
}
|
|
else {
|
|
LinkTarget.Buffer = LinkTargetBuffer;
|
|
|
|
DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer;
|
|
RestartScan = TRUE;
|
|
RtlInitUnicodeString( &LinkTypeName, L"SymbolicLink" );
|
|
RtlInitUnicodeString( &LinkTargetPrefix, L"\\Device\\Harddisk" );
|
|
while (TRUE) {
|
|
|
|
Status = NtQueryDirectoryObject( SmpDosDevicesObjectDirectory,
|
|
(PVOID)DirInfo,
|
|
sizeof( DirInfoBuffer ),
|
|
TRUE,
|
|
RestartScan,
|
|
&Context,
|
|
&Length
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if (RtlEqualUnicodeString( &DirInfo->TypeName, &LinkTypeName, TRUE ) &&
|
|
DirInfo->Name.Buffer[(DirInfo->Name.Length>>1)-1] == L':') {
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&DirInfo->Name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
SmpDosDevicesObjectDirectory,
|
|
NULL
|
|
);
|
|
Status = NtOpenSymbolicLinkObject( &Handle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
LinkTarget.Length = 0;
|
|
LinkTarget.MaximumLength = sizeof( LinkTargetBuffer );
|
|
Status = NtQuerySymbolicLinkObject( Handle,
|
|
&LinkTarget,
|
|
NULL
|
|
);
|
|
NtClose( Handle );
|
|
if (NT_SUCCESS( Status ) &&
|
|
RtlPrefixUnicodeString( &LinkTargetPrefix, &LinkTarget, TRUE )
|
|
) {
|
|
sprintf( DisplayBuffer,
|
|
CheckingString,
|
|
&DirInfo->Name
|
|
);
|
|
|
|
if (SmpEnableDots != FALSE) {
|
|
RtlInitAnsiString( &AnsiDisplayString, "." );
|
|
|
|
} else {
|
|
RtlInitAnsiString( &AnsiDisplayString, DisplayBuffer );
|
|
}
|
|
|
|
Status = RtlAnsiStringToUnicodeString( &DisplayString,
|
|
&AnsiDisplayString,
|
|
TRUE
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
NtDisplayString( &DisplayString );
|
|
RtlFreeUnicodeString( &DisplayString );
|
|
}
|
|
CmdLine.Length = 0;
|
|
RtlAppendUnicodeStringToString( &CmdLine, ImageFileName );
|
|
RtlAppendUnicodeToString( &CmdLine, L" " );
|
|
if (ForceAutoChk) {
|
|
RtlAppendUnicodeToString( &CmdLine, L"/p " );
|
|
}
|
|
RtlAppendUnicodeToString( &CmdLine, L" /d" );
|
|
RtlAppendUnicodeToString( &CmdLine, DirInfo->Name.Buffer );
|
|
RtlAppendUnicodeToString( &CmdLine, L" " );
|
|
RtlAppendUnicodeStringToString( &CmdLine, &LinkTarget );
|
|
SmpExecuteImage( ImageFileName,
|
|
CurrentDirectory,
|
|
&CmdLine,
|
|
Flags & ~SMP_AUTOCHK_FLAG,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
RestartScan = FALSE;
|
|
if (!NT_SUCCESS( Status )) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpLoadSubSystem(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function loads and starts the specified system service
|
|
emulation subsystem. The system freezes until the loaded subsystem
|
|
completes the subsystem connection protocol by connecting to SM,
|
|
and then accepting a connection from SM.
|
|
|
|
Arguments:
|
|
|
|
CommandLine - Supplies the command line to execute the subsystem.
|
|
|
|
Return Value:
|
|
|
|
TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
RTL_USER_PROCESS_INFORMATION ProcessInformation;
|
|
PSMPKNOWNSUBSYS KnownSubSys;
|
|
PSMPKNOWNSUBSYS TargetSubSys;
|
|
|
|
|
|
if (Flags & SMP_IMAGE_NOT_FOUND) {
|
|
KdPrint(( "SMSS: Unable to find subsystem - %wZ\n", ImageFileName ));
|
|
return( STATUS_OBJECT_NAME_NOT_FOUND );
|
|
}
|
|
|
|
Flags |= SMP_DONT_START;
|
|
Status = SmpExecuteImage( ImageFileName,
|
|
CurrentDirectory,
|
|
CommandLine,
|
|
Flags,
|
|
&ProcessInformation
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
KnownSubSys = RtlAllocateHeap( SmpHeap, MAKE_TAG( INIT_TAG ), sizeof( SMPKNOWNSUBSYS ) );
|
|
KnownSubSys->Process = ProcessInformation.Process;
|
|
KnownSubSys->InitialClientId = ProcessInformation.ClientId;
|
|
KnownSubSys->ImageType = (ULONG)0xFFFFFFFF;
|
|
KnownSubSys->SmApiCommunicationPort = (HANDLE) NULL;
|
|
KnownSubSys->SbApiCommunicationPort = (HANDLE) NULL;
|
|
|
|
Status = NtCreateEvent( &KnownSubSys->Active,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
//
|
|
// now that we have the process all set, make sure that the
|
|
// subsystem is either an NT native app, or an app type of
|
|
// a previously loaded subsystem
|
|
//
|
|
|
|
if (ProcessInformation.ImageInformation.SubSystemType !=
|
|
IMAGE_SUBSYSTEM_NATIVE ) {
|
|
SBAPIMSG SbApiMsg;
|
|
PSBCREATESESSION args;
|
|
ULONG SessionId;
|
|
|
|
args = &SbApiMsg.u.CreateSession;
|
|
|
|
args->ProcessInformation = ProcessInformation;
|
|
args->DebugSession = 0;
|
|
args->DebugUiClientId.UniqueProcess = NULL;
|
|
args->DebugUiClientId.UniqueThread = NULL;
|
|
|
|
TargetSubSys = SmpLocateKnownSubSysByType(
|
|
ProcessInformation.ImageInformation.SubSystemType
|
|
);
|
|
if ( !TargetSubSys ) {
|
|
return STATUS_NO_SUCH_PACKAGE;
|
|
}
|
|
//
|
|
// Transfer the handles to the subsystem responsible for this
|
|
// process
|
|
//
|
|
|
|
Status = NtDuplicateObject( NtCurrentProcess(),
|
|
ProcessInformation.Process,
|
|
TargetSubSys->Process,
|
|
&args->ProcessInformation.Process,
|
|
PROCESS_ALL_ACCESS,
|
|
0,
|
|
0
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
Status = NtDuplicateObject( NtCurrentProcess(),
|
|
ProcessInformation.Thread,
|
|
TargetSubSys->Process,
|
|
&args->ProcessInformation.Thread,
|
|
THREAD_ALL_ACCESS,
|
|
0,
|
|
0
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
SessionId = SmpAllocateSessionId( TargetSubSys,
|
|
NULL
|
|
);
|
|
args->SessionId = SessionId;
|
|
|
|
SbApiMsg.ApiNumber = SbCreateSessionApi;
|
|
SbApiMsg.h.u1.s1.DataLength = sizeof(*args) + 8;
|
|
SbApiMsg.h.u1.s1.TotalLength = sizeof(SbApiMsg);
|
|
SbApiMsg.h.u2.ZeroInit = 0L;
|
|
|
|
Status = NtRequestWaitReplyPort(
|
|
TargetSubSys->SbApiCommunicationPort,
|
|
(PPORT_MESSAGE) &SbApiMsg,
|
|
(PPORT_MESSAGE) &SbApiMsg
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
Status = SbApiMsg.ReturnedStatus;
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
SmpDeleteSession( SessionId, FALSE, Status );
|
|
return( Status );
|
|
}
|
|
}
|
|
else {
|
|
SmpWindowsSubSysProcess = ProcessInformation.Process;
|
|
}
|
|
|
|
ASSERTMSG( "NtCreateEvent", NT_SUCCESS( Status ) );
|
|
|
|
RtlEnterCriticalSection( &SmpKnownSubSysLock );
|
|
|
|
InsertHeadList( &SmpKnownSubSysHead, &KnownSubSys->Links );
|
|
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
|
|
NtResumeThread( ProcessInformation.Thread, NULL );
|
|
|
|
NtWaitForSingleObject( KnownSubSys->Active, FALSE, NULL );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpExecuteInitialCommand(
|
|
IN PUNICODE_STRING InitialCommand,
|
|
OUT PHANDLE InitialCommandProcess
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
RTL_USER_PROCESS_INFORMATION ProcessInformation;
|
|
ULONG Flags;
|
|
UNICODE_STRING ImageFileName;
|
|
UNICODE_STRING CurrentDirectory;
|
|
UNICODE_STRING Arguments;
|
|
HANDLE SmApiPort;
|
|
|
|
Status = SmConnectToSm( NULL,
|
|
NULL,
|
|
0,
|
|
&SmApiPort
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: Unable to connect to SM - Status == %lx\n", Status ));
|
|
return( Status );
|
|
}
|
|
|
|
Flags = 0;
|
|
Status = SmpParseCommandLine( InitialCommand,
|
|
&Flags,
|
|
&ImageFileName,
|
|
&CurrentDirectory,
|
|
&Arguments
|
|
);
|
|
if (Flags & SMP_IMAGE_NOT_FOUND) {
|
|
KdPrint(( "SMSS: Initial command image (%wZ) not found\n", &ImageFileName ));
|
|
return( STATUS_OBJECT_NAME_NOT_FOUND );
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", InitialCommand, Status ));
|
|
return( Status );
|
|
}
|
|
|
|
Status = SmpExecuteImage( &ImageFileName,
|
|
&CurrentDirectory,
|
|
InitialCommand,
|
|
SMP_DONT_START,
|
|
&ProcessInformation
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
Status = NtDuplicateObject( NtCurrentProcess(),
|
|
ProcessInformation.Process,
|
|
NtCurrentProcess(),
|
|
InitialCommandProcess,
|
|
PROCESS_ALL_ACCESS,
|
|
0,
|
|
0
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status) ) {
|
|
KdPrint(( "SMSS: DupObject Failed. Status == %lx\n",
|
|
Status
|
|
));
|
|
NtTerminateProcess( ProcessInformation.Process, Status );
|
|
NtResumeThread( ProcessInformation.Thread, NULL );
|
|
NtClose( ProcessInformation.Thread );
|
|
NtClose( ProcessInformation.Process );
|
|
return( Status );
|
|
}
|
|
|
|
Status = SmExecPgm( SmApiPort,
|
|
&ProcessInformation,
|
|
FALSE
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrint(( "SMSS: SmExecPgm Failed. Status == %lx\n",
|
|
Status
|
|
));
|
|
return( Status );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
void
|
|
SmpDisplayString( char *s )
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
RtlInitAnsiString( &AnsiString, s );
|
|
|
|
RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE );
|
|
|
|
NtDisplayString( &UnicodeString );
|
|
|
|
RtlFreeUnicodeString( &UnicodeString );
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpLoadDeferedSubsystem(
|
|
IN PSMAPIMSG SmApiMsg,
|
|
IN PSMP_CLIENT_CONTEXT CallingClient,
|
|
IN HANDLE CallPort
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY Head, Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
UNICODE_STRING DeferedName;
|
|
PSMLOADDEFERED args;
|
|
|
|
args = &SmApiMsg->u.LoadDefered;
|
|
|
|
DeferedName.Length = (USHORT)args->SubsystemNameLength;
|
|
DeferedName.MaximumLength = (USHORT)args->SubsystemNameLength;
|
|
DeferedName.Buffer = args->SubsystemName;
|
|
|
|
Head = &SmpSubSystemsToDefer;
|
|
Next = Head->Flink;
|
|
while (Next != Head ) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
if ( RtlEqualUnicodeString(&DeferedName,&p->Name,TRUE)) {
|
|
|
|
//
|
|
// This is it. Load the subsystem...
|
|
//
|
|
|
|
RemoveEntryList(Next);
|
|
|
|
Status = SmpExecuteCommand( &p->Value, SMP_SUBSYSTEM_FLAG );
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
|
|
return Status;
|
|
|
|
}
|
|
Next = Next->Flink;
|
|
}
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpConfigureProtectionMode(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is a dispatch routine for the QueryRegistry call
|
|
(see SmpRegistryConfigurationTable[] earlier in this file).
|
|
|
|
The purpose of this routine is to read the Base Object Protection
|
|
Mode out of the registry. This information is kept in
|
|
|
|
Key Name: \\Hkey_Local_Machine\System\CurrentControlSet\SessionManager
|
|
Value: ProtectionMode [REG_DWORD]
|
|
|
|
The value is a flag word, with the following flags defined:
|
|
|
|
SMP_NO_PROTECTION - No base object protection
|
|
SMP_STANDARD_PROTECTION - Apply standard base
|
|
object protection
|
|
|
|
This information will be placed in the global variable
|
|
SmpProtectionMode.
|
|
|
|
No value, or an invalid value length or type results in no base
|
|
object protection being applied.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
#ifdef SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( "BaseObjectsProtection", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueName );
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
#endif
|
|
|
|
|
|
|
|
if (ValueLength != sizeof(ULONG)) {
|
|
|
|
//
|
|
// Key value not valid, set to run without base object protection.
|
|
// This is how we initialized, so no need to set up new
|
|
// security descriptors.
|
|
//
|
|
|
|
SmpProtectionMode = 0;
|
|
|
|
} else {
|
|
|
|
|
|
SmpProtectionMode = (*((PULONG)(ValueData)));
|
|
|
|
//
|
|
// Change the security descriptors
|
|
//
|
|
|
|
(VOID)SmpCreateSecurityDescriptors( FALSE );
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpCreateSecurityDescriptors(
|
|
IN BOOLEAN InitialCall
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates and initializes security descriptors
|
|
used in SM.
|
|
|
|
The security descriptors include:
|
|
|
|
SmpPrimarySecurityDescriptor - (global variable) This is
|
|
used to assign protection to objects created by
|
|
SM that need to be accessed by others, but not modified.
|
|
This descriptor grants the following access:
|
|
|
|
Grant: World: Execute | Read (Inherit)
|
|
Grant: Admin: All Access (Inherit)
|
|
Grant: Owner: All Access (Inherit Only)
|
|
|
|
SmpLiberalSecurityDescriptor = (globalVariable) This is used
|
|
to assign protection objects created by SM that need
|
|
to be modified by others (such as writing to a shared
|
|
memory section).
|
|
This descriptor grants the following access:
|
|
|
|
Grant: World: Execute | Read | Write (Inherit)
|
|
Grant: Admin: All Access (Inherit)
|
|
Grant: Owner: All Access (Inherit Only)
|
|
|
|
SmpKnownDllsSecurityDescriptor = (globalVariable) This is used
|
|
to assign protection to the \KnownDlls object directory.
|
|
This descriptor grants the following access:
|
|
|
|
Grant: World: Execute (No Inherit)
|
|
Grant: Admin: All Access (Inherit)
|
|
Grant: World: Execute | Read | Write (Inherit Only)
|
|
|
|
|
|
Note that System is an administrator, so granting Admin an
|
|
access also grants System that access.
|
|
|
|
Arguments:
|
|
|
|
InitialCall - Indicates whether this routine is being called for
|
|
the first time, or is being called to change the security
|
|
descriptors as a result of a protection mode change.
|
|
|
|
TRUE - being called for first time.
|
|
FALSE - being called a subsequent time.
|
|
|
|
(global variables: SmpBaseObjectsUnprotected)
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The security descriptor(s) have been allocated
|
|
and initialized.
|
|
|
|
STATUS_NO_MEMORY - couldn't allocate memory for a security
|
|
descriptor.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS
|
|
Status;
|
|
|
|
PSID
|
|
WorldSid,
|
|
AdminSid,
|
|
OwnerSid;
|
|
|
|
SID_IDENTIFIER_AUTHORITY
|
|
WorldAuthority = SECURITY_WORLD_SID_AUTHORITY,
|
|
NtAuthority = SECURITY_NT_AUTHORITY,
|
|
CreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY;
|
|
|
|
ACCESS_MASK
|
|
AdminAccess = (GENERIC_ALL),
|
|
WorldAccess = (GENERIC_EXECUTE | GENERIC_READ),
|
|
OwnerAccess = (GENERIC_ALL);
|
|
|
|
UCHAR
|
|
InheritOnlyFlags = (OBJECT_INHERIT_ACE |
|
|
CONTAINER_INHERIT_ACE |
|
|
INHERIT_ONLY_ACE);
|
|
|
|
ULONG
|
|
AceIndex,
|
|
AclLength;
|
|
|
|
PACL
|
|
Acl;
|
|
|
|
PACE_HEADER
|
|
Ace;
|
|
|
|
BOOLEAN
|
|
ProtectionRequired = FALSE,
|
|
WasEnabled;
|
|
|
|
|
|
if (InitialCall) {
|
|
|
|
//
|
|
// Now init the security descriptors for no protection.
|
|
// If told to, we will change these to have protection.
|
|
//
|
|
|
|
// Primary
|
|
|
|
SmpPrimarySecurityDescriptor = &SmpPrimarySDBody;
|
|
Status = RtlCreateSecurityDescriptor (
|
|
SmpPrimarySecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
SmpPrimarySecurityDescriptor,
|
|
TRUE, //DaclPresent,
|
|
NULL, //Dacl (no protection)
|
|
FALSE //DaclDefaulted OPTIONAL
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
|
|
// Liberal
|
|
|
|
SmpLiberalSecurityDescriptor = &SmpLiberalSDBody;
|
|
Status = RtlCreateSecurityDescriptor (
|
|
SmpLiberalSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
SmpLiberalSecurityDescriptor,
|
|
TRUE, //DaclPresent,
|
|
NULL, //Dacl (no protection)
|
|
FALSE //DaclDefaulted OPTIONAL
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
// KnownDlls
|
|
|
|
SmpKnownDllsSecurityDescriptor = &SmpKnownDllsSDBody;
|
|
Status = RtlCreateSecurityDescriptor (
|
|
SmpKnownDllsSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
SmpKnownDllsSecurityDescriptor,
|
|
TRUE, //DaclPresent,
|
|
NULL, //Dacl (no protection)
|
|
FALSE //DaclDefaulted OPTIONAL
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
|
|
// ApiPort
|
|
|
|
SmpApiPortSecurityDescriptor = &SmpApiPortSDBody;
|
|
Status = RtlCreateSecurityDescriptor (
|
|
SmpApiPortSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
SmpApiPortSecurityDescriptor,
|
|
TRUE, //DaclPresent,
|
|
NULL, //Dacl (no protection)
|
|
FALSE //DaclDefaulted OPTIONAL
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
}
|
|
|
|
|
|
|
|
if ((SmpProtectionMode & SMP_PROTECTION_REQUIRED) != 0) {
|
|
ProtectionRequired = TRUE;
|
|
}
|
|
|
|
if (!InitialCall && !ProtectionRequired) {
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
if (InitialCall || ProtectionRequired) {
|
|
|
|
//
|
|
// We need to set up the ApiPort protection, and maybe
|
|
// others.
|
|
//
|
|
|
|
Status = RtlAllocateAndInitializeSid(
|
|
&WorldAuthority,
|
|
1,
|
|
SECURITY_WORLD_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&WorldSid
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
Status = RtlAllocateAndInitializeSid(
|
|
&NtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&AdminSid
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
Status = RtlAllocateAndInitializeSid(
|
|
&CreatorAuthority,
|
|
1,
|
|
SECURITY_CREATOR_OWNER_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&OwnerSid
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
//
|
|
// Build the ApiPort security descriptor only
|
|
// if this is the initial call
|
|
//
|
|
|
|
if (InitialCall) {
|
|
|
|
WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_READ;
|
|
AdminAccess = GENERIC_ALL;
|
|
|
|
AclLength = sizeof( ACL ) +
|
|
2 * sizeof( ACCESS_ALLOWED_ACE ) +
|
|
(RtlLengthSid( WorldSid )) +
|
|
(RtlLengthSid( AdminSid ));
|
|
|
|
Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength );
|
|
|
|
if (Acl == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Create the ACL, then add each ACE
|
|
//
|
|
|
|
Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Only Non-inheritable ACEs in this ACL
|
|
// World
|
|
// Admin
|
|
//
|
|
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
SmpApiPortSecurityDescriptor,
|
|
TRUE, //DaclPresent,
|
|
Acl, //Dacl
|
|
FALSE //DaclDefaulted OPTIONAL
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
}
|
|
}
|
|
|
|
//
|
|
// The remaining security descriptors are only
|
|
// built if we are running with the correct in
|
|
// protection mode set. Notice that we only
|
|
// put protection on if standard protection is
|
|
// also specified. Otherwise, there is no protection
|
|
// on the objects, and nothing should fail.
|
|
//
|
|
|
|
if (SmpProtectionMode & SMP_STANDARD_PROTECTION) {
|
|
|
|
//
|
|
// Build the primary Security descriptor
|
|
//
|
|
|
|
WorldAccess = GENERIC_EXECUTE | GENERIC_READ;
|
|
AdminAccess = GENERIC_ALL;
|
|
OwnerAccess = GENERIC_ALL;
|
|
|
|
AclLength = sizeof( ACL ) +
|
|
5 * sizeof( ACCESS_ALLOWED_ACE ) +
|
|
(2*RtlLengthSid( WorldSid )) +
|
|
(2*RtlLengthSid( AdminSid )) +
|
|
RtlLengthSid( OwnerSid );
|
|
|
|
Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength );
|
|
|
|
if (Acl == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Create the ACL, then add each ACE
|
|
//
|
|
|
|
Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Non-inheritable ACEs first
|
|
// World
|
|
// Admin
|
|
//
|
|
|
|
AceIndex = 0;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Inheritable ACEs at end of ACE
|
|
// World
|
|
// Admin
|
|
// Owner
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Ace->AceFlags = InheritOnlyFlags;
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Ace->AceFlags = InheritOnlyFlags;
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, OwnerAccess, OwnerSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Ace->AceFlags = InheritOnlyFlags;
|
|
|
|
|
|
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
SmpPrimarySecurityDescriptor,
|
|
TRUE, //DaclPresent,
|
|
Acl, //Dacl
|
|
FALSE //DaclDefaulted OPTIONAL
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Build the liberal security descriptor
|
|
//
|
|
|
|
|
|
AdminAccess = GENERIC_ALL;
|
|
WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE;
|
|
|
|
AclLength = sizeof( ACL ) +
|
|
5 * sizeof( ACCESS_ALLOWED_ACE ) +
|
|
(2*RtlLengthSid( WorldSid )) +
|
|
(2*RtlLengthSid( AdminSid )) +
|
|
RtlLengthSid( OwnerSid );
|
|
|
|
Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength );
|
|
|
|
if (Acl == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Create the ACL
|
|
//
|
|
|
|
Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Add the non-inheritable ACEs first
|
|
// World
|
|
// Admin
|
|
//
|
|
|
|
AceIndex = 0;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Put the inherit only ACEs at at the end
|
|
// World
|
|
// Admin
|
|
// Owner
|
|
//
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Ace->AceFlags = InheritOnlyFlags;
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Ace->AceFlags = InheritOnlyFlags;
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, OwnerAccess, OwnerSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Ace->AceFlags = InheritOnlyFlags;
|
|
|
|
|
|
//
|
|
// Put the Acl in the security descriptor
|
|
//
|
|
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
SmpLiberalSecurityDescriptor,
|
|
TRUE, //DaclPresent,
|
|
Acl, //Dacl
|
|
FALSE //DaclDefaulted OPTIONAL
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
}
|
|
|
|
|
|
//
|
|
// Build the KnownDlls security descriptor
|
|
//
|
|
|
|
|
|
AdminAccess = GENERIC_ALL;
|
|
|
|
AclLength = sizeof( ACL ) +
|
|
4 * sizeof( ACCESS_ALLOWED_ACE ) +
|
|
(2*RtlLengthSid( WorldSid )) +
|
|
(2*RtlLengthSid( AdminSid ));
|
|
|
|
Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength );
|
|
|
|
if (Acl == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Create the ACL
|
|
//
|
|
|
|
Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Add the non-inheritable ACEs first
|
|
// World
|
|
// Admin
|
|
//
|
|
|
|
AceIndex = 0;
|
|
WorldAccess = GENERIC_EXECUTE;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Put the inherit only ACEs at at the end
|
|
// World
|
|
// Admin
|
|
//
|
|
|
|
AceIndex++;
|
|
WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Ace->AceFlags = InheritOnlyFlags;
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
Ace->AceFlags = InheritOnlyFlags;
|
|
|
|
|
|
//
|
|
// Put the Acl in the security descriptor
|
|
//
|
|
|
|
Status = RtlSetDaclSecurityDescriptor (
|
|
SmpKnownDllsSecurityDescriptor,
|
|
TRUE, //DaclPresent,
|
|
Acl, //Dacl
|
|
FALSE //DaclDefaulted OPTIONAL
|
|
);
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// No more security descriptors to build
|
|
//
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, OwnerSid );
|
|
}
|
|
RtlFreeHeap( RtlProcessHeap(), 0, AdminSid );
|
|
}
|
|
RtlFreeHeap( RtlProcessHeap(), 0, WorldSid );
|
|
}
|
|
}
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SmpTranslateSystemPartitionInformation( VOID )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine translates the NT device path for the system partition (stored
|
|
during IoInitSystem) into a DOS path, and stores the resulting REG_SZ 'BootDir'
|
|
value under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Key;
|
|
UCHAR ValueBuffer[ VALUE_BUFFER_SIZE ];
|
|
ULONG ValueLength;
|
|
UNICODE_STRING SystemPartitionString;
|
|
POBJECT_DIRECTORY_INFORMATION DirInfo;
|
|
UCHAR DirInfoBuffer[ sizeof(OBJECT_DIRECTORY_INFORMATION) + (256 + sizeof("SymbolicLink")) * sizeof(WCHAR) ];
|
|
UNICODE_STRING LinkTypeName;
|
|
BOOLEAN RestartScan;
|
|
ULONG Context;
|
|
HANDLE SymbolicLinkHandle;
|
|
WCHAR UnicodeBuffer[ MAXIMUM_FILENAME_LENGTH ];
|
|
UNICODE_STRING LinkTarget;
|
|
|
|
//
|
|
// Retrieve 'SystemPartition' value stored under HKLM\SYSTEM\Setup
|
|
//
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: can't open system setup key for reading: 0x%x\n", Status));
|
|
return;
|
|
}
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"SystemPartition");
|
|
Status = NtQueryValueKey(Key,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
ValueBuffer,
|
|
sizeof(ValueBuffer),
|
|
&ValueLength
|
|
);
|
|
|
|
NtClose(Key);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: can't query SystemPartition value: 0x%x\n", Status));
|
|
return;
|
|
}
|
|
|
|
RtlInitUnicodeString(&SystemPartitionString,
|
|
(PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer)->Data)
|
|
);
|
|
|
|
//
|
|
// Next, examine objects in the DosDevices directory, looking for one that's a symbolic link
|
|
// to the system partition.
|
|
//
|
|
|
|
LinkTarget.Buffer = UnicodeBuffer;
|
|
|
|
DirInfo = (POBJECT_DIRECTORY_INFORMATION)DirInfoBuffer;
|
|
RestartScan = TRUE;
|
|
RtlInitUnicodeString(&LinkTypeName, L"SymbolicLink");
|
|
|
|
while (TRUE) {
|
|
|
|
Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory,
|
|
DirInfo,
|
|
sizeof(DirInfoBuffer),
|
|
TRUE,
|
|
RestartScan,
|
|
&Context,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
|
|
if (RtlEqualUnicodeString(&DirInfo->TypeName, &LinkTypeName, TRUE) &&
|
|
(DirInfo->Name.Length == 2 * sizeof(WCHAR)) &&
|
|
(DirInfo->Name.Buffer[1] == L':')) {
|
|
|
|
//
|
|
// We have a drive letter--check the NT device name it's linked to.
|
|
//
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&DirInfo->Name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
SmpDosDevicesObjectDirectory,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
LinkTarget.Length = 0;
|
|
LinkTarget.MaximumLength = sizeof(UnicodeBuffer);
|
|
|
|
Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle,
|
|
&LinkTarget,
|
|
NULL
|
|
);
|
|
NtClose(SymbolicLinkHandle);
|
|
|
|
if (NT_SUCCESS(Status) &&
|
|
RtlEqualUnicodeString(&SystemPartitionString, &LinkTarget, TRUE)) {
|
|
|
|
//
|
|
// We've found the drive letter corresponding to the system partition.
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RestartScan = FALSE;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: can't find drive letter for system partition\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Now write out the DOS path for the system partition to
|
|
// HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup
|
|
//
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenKey(&Key, KEY_ALL_ACCESS, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: can't open software setup key for writing: 0x%x\n", Status));
|
|
return;
|
|
}
|
|
|
|
wcsncpy(UnicodeBuffer, DirInfo->Name.Buffer, 2);
|
|
UnicodeBuffer[2] = L'\\';
|
|
UnicodeBuffer[3] = L'\0';
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"BootDir");
|
|
|
|
Status = NtSetValueKey(Key,
|
|
&UnicodeString,
|
|
0,
|
|
REG_SZ,
|
|
UnicodeBuffer,
|
|
4 * sizeof(WCHAR)
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("SMSS: couldn't write BootDir value: 0x%x\n", Status));
|
|
}
|
|
|
|
NtClose(Key);
|
|
}
|
|
|