mirror of https://github.com/tongzx/nt5src
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.
7075 lines
216 KiB
7075 lines
216 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 "pagefile.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <safeboot.h>
|
|
#include <wow64t.h>
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
#include <windows.h>
|
|
#ifdef DeleteFile
|
|
#undef DeleteFile
|
|
#endif
|
|
#include <shdcom.h> // CSC definitions
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
#include "sfcfiles.h"
|
|
|
|
void
|
|
SmpDisplayString( char *s );
|
|
|
|
//
|
|
// Protection mode flags
|
|
//
|
|
|
|
#define SMP_NO_PROTECTION (0x0)
|
|
#define SMP_STANDARD_PROTECTION (0x1)
|
|
#define SMP_PROTECTION_REQUIRED (SMP_STANDARD_PROTECTION)
|
|
|
|
#define REMOTE_BOOT_CFG_FILE L"RemoteBoot.cfg"
|
|
|
|
//
|
|
// Shows where was SmpInit execution when it returned
|
|
// with an error code. This aids debugging smss crashes a lot.
|
|
//
|
|
|
|
ULONG SmpInitProgressByLine;
|
|
NTSTATUS SmpInitReturnStatus;
|
|
PVOID SmpInitLastCall;
|
|
|
|
#define SAVE_SMPINIT_STATUS(caller, status) { \
|
|
\
|
|
SmpInitProgressByLine = __LINE__; \
|
|
SmpInitReturnStatus = (status); \
|
|
SmpInitLastCall = (PVOID)(caller); \
|
|
}
|
|
|
|
|
|
|
|
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 = SMP_STANDARD_PROTECTION;
|
|
UCHAR TmpBuffer[ 1024 + 2 * DOS_MAX_PATH_LENGTH * sizeof(WCHAR)];
|
|
ULONG AttachedSessionId = (-1);
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
WCHAR wszRemoteBootCfgFile[DOS_MAX_PATH_LENGTH];
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
#if DBG
|
|
BOOLEAN SmpEnableDots = FALSE;
|
|
#else
|
|
BOOLEAN SmpEnableDots = TRUE;
|
|
#endif
|
|
|
|
|
|
WCHAR InitialCommandBuffer[ 256 ];
|
|
|
|
UNICODE_STRING SmpDebugKeyword;
|
|
UNICODE_STRING SmpASyncKeyword;
|
|
UNICODE_STRING SmpAutoChkKeyword;
|
|
#if defined(REMOTE_BOOT)
|
|
UNICODE_STRING SmpAutoFmtKeyword;
|
|
#endif // defined(REMOTE_BOOT)
|
|
UNICODE_STRING SmpKnownDllPath;
|
|
#ifdef _WIN64
|
|
UNICODE_STRING SmpKnownDllPath32;
|
|
#endif
|
|
|
|
HANDLE SmpWindowsSubSysProcess;
|
|
ULONG_PTR SmpWindowsSubSysProcessId;
|
|
ULONG_PTR SmpInitialCommandProcessId;
|
|
UNICODE_STRING PosixName;
|
|
UNICODE_STRING Os2Name;
|
|
BOOLEAN RegPosixSingleInstance; // Make Softway Work.
|
|
ULONG SmpAllowProtectedRenames;
|
|
BOOLEAN MiniNTBoot = FALSE;
|
|
|
|
|
|
LIST_ENTRY SmpBootExecuteList;
|
|
LIST_ENTRY SmpSetupExecuteList;
|
|
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
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureProtectionMode(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpConfigureAllowProtectedRenames(
|
|
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
|
|
);
|
|
|
|
ULONGLONG
|
|
SmpGetFileVersion(
|
|
IN HANDLE FileHandle,
|
|
IN PUNICODE_STRING FileName
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpCallCsrCreateProcess(
|
|
IN OUT PSBAPIMSG m,
|
|
IN size_t ArgLength,
|
|
IN HANDLE CommunicationPort
|
|
);
|
|
|
|
|
|
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},
|
|
|
|
{SmpConfigureAllowProtectedRenames, RTL_QUERY_REGISTRY_DELETE,
|
|
L"AllowProtectedRenames", 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},
|
|
|
|
{SmpConfigureExecute, RTL_QUERY_REGISTRY_TOPKEY,
|
|
L"SetupExecute", &SmpSetupExecuteList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureFileRenames, RTL_QUERY_REGISTRY_DELETE,
|
|
L"PendingFileRenameOperations", &SmpFileRenameList,
|
|
REG_NONE, NULL, 0},
|
|
|
|
{SmpConfigureFileRenames, RTL_QUERY_REGISTRY_DELETE,
|
|
L"PendingFileRenameOperations2", &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, L"?:\\pagefile.sys\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},
|
|
|
|
//
|
|
// this needs to happen twice so that forward references are
|
|
// properly resolved
|
|
//
|
|
|
|
{SmpConfigureEnvironment, RTL_QUERY_REGISTRY_SUBKEY,
|
|
L"Environment", NULL,
|
|
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
|
|
);
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
NTSTATUS
|
|
SmpInvokeAutoFmt(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING Arguments,
|
|
IN ULONG Flags
|
|
);
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
NTSTATUS
|
|
SmpLoadSubSystem(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG MuSessionId,
|
|
OUT PULONG_PTR pWindowsSubSysProcessId,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpExecuteCommand(
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG MuSessionId,
|
|
OUT PULONG_PTR pWindowsSubSysProcessId,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
NTSTATUS
|
|
SmpInitializeDosDevices( VOID );
|
|
|
|
NTSTATUS
|
|
SmpInitializeKnownDlls( VOID );
|
|
|
|
NTSTATUS
|
|
SmpInitializeKnownDllPath(
|
|
IN PUNICODE_STRING KnownDllPath,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength);
|
|
|
|
NTSTATUS
|
|
SmpInitializeKnownDllsInternal(
|
|
IN PUNICODE_STRING ObjectDirectoryName,
|
|
IN PUNICODE_STRING KnownDllPath
|
|
);
|
|
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
NTSTATUS
|
|
SmpExecuteCommandLineArguments( VOID );
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
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 OPTIONAL,
|
|
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
|
|
#if defined(REMOTE_BOOT)
|
|
#define SMP_AUTOFMT_FLAG 0x00000040
|
|
#endif // defined(REMOTE_BOOT)
|
|
#define SMP_POSIX_SI_FLAG 0x00000080
|
|
#define SMP_POSIX_FLAG 0x00000100
|
|
#define SMP_OS2_FLAG 0x00000200
|
|
|
|
ULONG
|
|
SmpConvertInteger(
|
|
IN PWSTR String
|
|
);
|
|
|
|
VOID
|
|
SmpTranslateSystemPartitionInformation( VOID );
|
|
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
//
|
|
// Useful functions for iterating thru directories and files
|
|
//
|
|
typedef enum {
|
|
NormalReturn, // if the whole process completes uninterrupted
|
|
EnumFileError, // if an error occurs while enumerating files
|
|
CallbackReturn // if the callback returns FALSE, causing termination
|
|
} ENUMFILESRESULT;
|
|
|
|
typedef BOOLEAN (*ENUMFILESPROC) (
|
|
IN PWSTR,
|
|
IN PFILE_BOTH_DIR_INFORMATION,
|
|
OUT PULONG,
|
|
IN PVOID
|
|
);
|
|
|
|
typedef struct {
|
|
PVOID OptionalPtr;
|
|
ENUMFILESPROC EnumProc;
|
|
} RECURSION_DATA, *PRECURSION_DATA;
|
|
|
|
|
|
|
|
ENUMFILESRESULT
|
|
SmpEnumFiles(
|
|
IN PWSTR DirName,
|
|
IN ENUMFILESPROC EnumFilesProc,
|
|
OUT PULONG ReturnData,
|
|
IN PVOID Pointer
|
|
);
|
|
|
|
ENUMFILESRESULT
|
|
SmpEnumFilesRecursive (
|
|
IN PWSTR DirName,
|
|
IN ENUMFILESPROC EnumFilesProc,
|
|
OUT PULONG ReturnData,
|
|
IN PVOID Pointer OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
SmpConcatenatePaths(
|
|
IN OUT LPWSTR Path1,
|
|
IN LPCWSTR Path2
|
|
);
|
|
|
|
BOOLEAN
|
|
SmppRecursiveEnumProc (
|
|
IN PWSTR DirName,
|
|
IN PFILE_BOTH_DIR_INFORMATION FileInfo,
|
|
OUT PULONG ret,
|
|
IN PVOID Param
|
|
);
|
|
|
|
BOOLEAN
|
|
SmpDelEnumFile(
|
|
IN PWSTR DirName,
|
|
IN PFILE_BOTH_DIR_INFORMATION FileInfo,
|
|
OUT PULONG ret,
|
|
IN PVOID Pointer
|
|
);
|
|
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
|
|
|
|
//
|
|
// 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)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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
|
|
SmpInit(
|
|
OUT PUNICODE_STRING InitialCommand,
|
|
OUT PHANDLE WindowsSubSystem
|
|
)
|
|
{
|
|
NTSTATUS st;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
HANDLE SmpApiConnectionPort;
|
|
UNICODE_STRING Unicode;
|
|
NTSTATUS Status, Status2;
|
|
ULONG HardErrorMode;
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE VolumeSafeEvent;
|
|
|
|
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)) {
|
|
|
|
SAVE_SMPINIT_STATUS (SmpCreateSecurityDescriptors, st);
|
|
return(st);
|
|
}
|
|
|
|
InitializeListHead(&NativeProcessList);
|
|
|
|
SmpHeap = RtlProcessHeap();
|
|
|
|
RtlInitUnicodeString( &PosixName, L"POSIX" );
|
|
RtlInitUnicodeString( &Os2Name, L"OS2" );
|
|
|
|
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) );
|
|
|
|
|
|
|
|
//
|
|
// Create a event to signal that volume are safe for write access opens.
|
|
// Call this event 'VolumesSafeForWriteAccess'. This event will be
|
|
// signalled after AUTOCHK/AUTOCONV/AUTOFMT have done their business.
|
|
//
|
|
|
|
RtlInitUnicodeString( &UnicodeString, L"\\Device\\VolumesSafeForWriteAccess");
|
|
|
|
InitializeObjectAttributes( &ObjA,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status2 = NtCreateEvent( &VolumeSafeEvent,
|
|
EVENT_ALL_ACCESS,
|
|
&ObjA,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS( Status2 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to create %wZ event - Status == %lx\n",
|
|
&UnicodeString,
|
|
Status2));
|
|
|
|
ASSERT( NT_SUCCESS(Status2) );
|
|
}
|
|
|
|
//
|
|
// Configure the system
|
|
//
|
|
|
|
Status = SmpLoadDataFromRegistry( InitialCommand );
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
*WindowsSubSystem = SmpWindowsSubSysProcess;
|
|
}
|
|
|
|
//
|
|
// AUTOCHK/AUTOCONV/AUTOFMT are finished.
|
|
//
|
|
|
|
if (NT_SUCCESS(Status2)) {
|
|
NtSetEvent(VolumeSafeEvent, NULL);
|
|
NtClose(VolumeSafeEvent);
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
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;
|
|
ULONG MuSessionId = 0;
|
|
UNICODE_STRING KeyName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Key;
|
|
UNICODE_STRING SessionDirName;
|
|
#if defined(REMOTE_BOOT)
|
|
HANDLE RdrHandle = NULL;
|
|
IO_STATUS_BLOCK Iosb;
|
|
SHADOWINFO ShadowInfo;
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
|
|
RtlInitUnicodeString( &SmpDebugKeyword, L"debug" );
|
|
RtlInitUnicodeString( &SmpASyncKeyword, L"async" );
|
|
RtlInitUnicodeString( &SmpAutoChkKeyword, L"autocheck" );
|
|
#if defined(REMOTE_BOOT)
|
|
RtlInitUnicodeString( &SmpAutoFmtKeyword, L"autoformat" );
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
InitializeListHead( &SmpBootExecuteList );
|
|
InitializeListHead( &SmpSetupExecuteList );
|
|
InitializeListHead( &SmpPagingFileList );
|
|
InitializeListHead( &SmpDosDevicesList );
|
|
InitializeListHead( &SmpFileRenameList );
|
|
InitializeListHead( &SmpKnownDllsList );
|
|
InitializeListHead( &SmpExcludeKnownDllsList );
|
|
InitializeListHead( &SmpSubSystemList );
|
|
InitializeListHead( &SmpSubSystemsToLoad );
|
|
InitializeListHead( &SmpSubSystemsToDefer );
|
|
InitializeListHead( &SmpExecuteList );
|
|
|
|
SmpPagingFileInitialize ();
|
|
|
|
Status = RtlCreateEnvironment( TRUE, &SmpDefaultEnvironment );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to allocate default environment - Status == %X\n",
|
|
Status));
|
|
|
|
|
|
SAVE_SMPINIT_STATUS (RtlCreateEnvironment, Status);
|
|
return( Status );
|
|
}
|
|
|
|
RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\MiniNT" );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenKey( &Key, KEY_ALL_ACCESS, &ObjectAttributes );
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
NtClose( Key );
|
|
MiniNTBoot = TRUE;
|
|
}
|
|
|
|
if (MiniNTBoot) {
|
|
DbgPrint("SMSS: !!! MiniNT Boot !!!\n");
|
|
}
|
|
|
|
//
|
|
// before the environment is created we MUST delete the
|
|
// safemode reg value
|
|
//
|
|
|
|
RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Environment" );
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = NtOpenKey( &Key, KEY_ALL_ACCESS, &ObjectAttributes );
|
|
if (NT_SUCCESS( Status )) {
|
|
RtlInitUnicodeString( &KeyName, L"SAFEBOOT_OPTION" );
|
|
NtDeleteValueKey( Key, &KeyName );
|
|
NtClose( Key );
|
|
}
|
|
|
|
//
|
|
// 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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: RtlQueryRegistryValues failed - Status == %lx\n",
|
|
Status));
|
|
|
|
SAVE_SMPINIT_STATUS (RtlQueryRegistryValues, Status);
|
|
return( Status );
|
|
}
|
|
|
|
Status = SmpInitializeDosDevices();
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
|
|
Status));
|
|
|
|
SAVE_SMPINIT_STATUS (SmpInitializeDosDevices, Status);
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Create the root "Sessions Directory". This is the container for all session
|
|
// specific directories. Each session specific CSRSS during startup will
|
|
// create a <sessionid> direcotry under "\Sessions". "\Sessions\<sessionid>
|
|
// directory will be the container for that session.
|
|
//
|
|
|
|
RtlInitUnicodeString( &SessionDirName, L"\\Sessions" );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&SessionDirName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
NULL,
|
|
SmpPrimarySecurityDescriptor
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status = NtCreateDirectoryObject( &SmpSessionsObjectDirectory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
))) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to create %wZ object directory - Status == %lx\n",
|
|
&SessionDirName,
|
|
Status));
|
|
|
|
SAVE_SMPINIT_STATUS (NtCreateDirectoryObject, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
//
|
|
// On a remote boot client, the client-side cache is already initialized.
|
|
// We need to tell CSC not to cache database handles during the next phase
|
|
// so that autochk can run.
|
|
//
|
|
|
|
if (SmpNetboot) {
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING RdrNameString;
|
|
|
|
RtlInitUnicodeString( &RdrNameString, L"\\Device\\LanmanRedirector" );
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&RdrNameString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtCreateFile(
|
|
&RdrHandle,
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SmpLoadDataFromRegistry: Unable to open redirector: %x\n",
|
|
Status));
|
|
|
|
RdrHandle = NULL;
|
|
}
|
|
else {
|
|
|
|
ShadowInfo.uOp = SHADOW_CHANGE_HANDLE_CACHING_STATE;
|
|
ShadowInfo.uStatus = FALSE;
|
|
|
|
Status = NtDeviceIoControlFile(
|
|
RdrHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
IOCTL_DO_SHADOW_MAINTENANCE,
|
|
&ShadowInfo,
|
|
sizeof(ShadowInfo),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
Status = Iosb.Status;
|
|
}
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SmpLoadDataFromRegistry: Unable to IOCTL CSC: %x\n",
|
|
Status));
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = SmpExecuteCommandLineArguments();
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to process command line arguments - Status == %lx\n",
|
|
Status));
|
|
|
|
return( Status );
|
|
}
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
Head = &SmpBootExecuteList;
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: BootExecute( %wZ )\n", &p->Name );
|
|
#endif
|
|
SmpExecuteCommand( &p->Name, 0, NULL, 0 );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
//
|
|
// On a remote boot client, we can now reenable CSC handle caching.
|
|
//
|
|
|
|
if (SmpNetboot && (RdrHandle != NULL)) {
|
|
|
|
ShadowInfo.uOp = SHADOW_CHANGE_HANDLE_CACHING_STATE;
|
|
ShadowInfo.uStatus = TRUE;
|
|
|
|
Status = NtDeviceIoControlFile(
|
|
RdrHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&Iosb,
|
|
IOCTL_DO_SHADOW_MAINTENANCE,
|
|
&ShadowInfo,
|
|
sizeof(ShadowInfo),
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
Status = Iosb.Status;
|
|
}
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SmpLoadDataFromRegistry: Unable to IOCTL CSC (2): %x\n",
|
|
Status));
|
|
}
|
|
}
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
if (!MiniNTBoot) {
|
|
SmpProcessFileRenames();
|
|
}
|
|
|
|
//
|
|
// Begin process of verifying system DLL's
|
|
//
|
|
|
|
Status = SmpInitializeKnownDlls();
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
|
|
Status));
|
|
|
|
SAVE_SMPINIT_STATUS (SmpInitializeKnownDlls, Status);
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Create paging files.
|
|
//
|
|
|
|
if (! MiniNTBoot) {
|
|
|
|
Head = &SmpPagingFileList;
|
|
|
|
try {
|
|
|
|
//
|
|
// Process the list of paging file descriptors
|
|
// read from registry.
|
|
//
|
|
|
|
while (! IsListEmpty (Head)) {
|
|
|
|
Next = RemoveHeadList (Head);
|
|
|
|
p = CONTAINING_RECORD (Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry);
|
|
|
|
SmpCreatePagingFileDescriptor (&p->Name);
|
|
|
|
RtlFreeHeap (RtlProcessHeap(), 0, p);
|
|
}
|
|
|
|
//
|
|
// Create any paging files specified.
|
|
//
|
|
|
|
SmpCreatePagingFiles();
|
|
}
|
|
except (SmpPagingFileExceptionFilter (_exception_code(), _exception_info())) {
|
|
|
|
//
|
|
// Nothing.
|
|
//
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finish registry initialization
|
|
//
|
|
|
|
NtInitializeRegistry(REG_INIT_BOOT_SM);
|
|
|
|
Status = SmpCreateDynamicEnvironmentVariables( );
|
|
if (!NT_SUCCESS( Status )) {
|
|
|
|
SAVE_SMPINIT_STATUS (SmpCreateDynamicEnvironmentVariables, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Load subsystems for the console session. Console always has
|
|
// MuSessionId = 0
|
|
//
|
|
Status = SmpLoadSubSystemsForMuSession( &MuSessionId,
|
|
&SmpWindowsSubSysProcessId, InitialCommand );
|
|
|
|
ASSERT(MuSessionId == 0);
|
|
|
|
if (! NT_SUCCESS(Status)) {
|
|
|
|
SAVE_SMPINIT_STATUS (SmpLoadSubSystemsForMuSession, Status);
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpLoadSubSystemsForMuSession(
|
|
PULONG pMuSessionId,
|
|
PULONG_PTR pWindowsSubSysProcessId,
|
|
PUNICODE_STRING InitialCommand )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function starts all of the configured subsystems for the
|
|
specified Multi-User Session. For regular NT this routine is called once
|
|
to start CSRSS etc. For Terminal Server, this routine is called every time
|
|
we want to start a new Multi-User Session to start session specific subsystems
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
Status of operation
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = 0;
|
|
PLIST_ENTRY Head, Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
|
|
//
|
|
// Translate the system partition information stored during IoInitSystem into
|
|
// a DOS path and store in Win32-standard location.
|
|
//
|
|
|
|
SmpTranslateSystemPartitionInformation();
|
|
|
|
//
|
|
// Second pass of execution.
|
|
//
|
|
|
|
Next = SmpSetupExecuteList.Flink;
|
|
while( Next != &SmpSetupExecuteList ) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: SetupExecute( %wZ )\n", &p->Name );
|
|
#endif
|
|
SmpExecuteCommand( &p->Name, 0, NULL, 0 );
|
|
|
|
//
|
|
// Note this function is reentrant and is called every time we start
|
|
// a new Multi-User Session.
|
|
//
|
|
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
Next = SmpSubSystemList.Flink;
|
|
while ( Next != &SmpSubSystemList ) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
if ( !_wcsicmp( p->Name.Buffer, L"Kmode" )) {
|
|
BOOLEAN TranslationStatus;
|
|
UNICODE_STRING FileName;
|
|
UNICODE_STRING Win32kFileName;
|
|
|
|
TranslationStatus = RtlDosPathNameToNtPathName_U(
|
|
p->Value.Buffer,
|
|
&FileName,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if ( TranslationStatus ) {
|
|
PVOID State;
|
|
|
|
Status = SmpAcquirePrivilege( SE_LOAD_DRIVER_PRIVILEGE, &State );
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
|
|
//
|
|
// Create a session space before loading any extended
|
|
// service table providers. This call will create a session
|
|
// space for the Multi-User session. The session mananger
|
|
// will see the instance of the newly created session space
|
|
// after this call. Once session manager is done creating
|
|
// CSRSS and winlogon it will detach itself from this
|
|
// session space.
|
|
//
|
|
|
|
ASSERT( AttachedSessionId == -1 );
|
|
|
|
Status = NtSetSystemInformation(
|
|
SystemSessionCreate,
|
|
(PVOID)pMuSessionId,
|
|
sizeof(*pMuSessionId)
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Session space creation failed\n"));
|
|
|
|
//
|
|
// Do not load any subsystems without SessionSpace.
|
|
//
|
|
|
|
SmpReleasePrivilege( State );
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
|
|
return( Status );
|
|
};
|
|
|
|
AttachedSessionId = *pMuSessionId;
|
|
|
|
RtlInitUnicodeString(&Win32kFileName,L"\\SystemRoot\\System32\\win32k.sys");
|
|
|
|
Status = NtSetSystemInformation(
|
|
SystemExtendServiceTableInformation,
|
|
(PVOID)&Win32kFileName,
|
|
sizeof(Win32kFileName)
|
|
);
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
|
|
SmpReleasePrivilege( State );
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
|
|
//
|
|
// Do not load any subsystems without WIN32K!
|
|
//
|
|
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_ERROR_LEVEL,
|
|
"SMSS: Load of WIN32K failed.\n"));
|
|
|
|
return( Status );
|
|
}
|
|
}
|
|
else {
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
|
|
}
|
|
}
|
|
else {
|
|
Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
|
}
|
|
}
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: Unused SubSystem( %wZ = %wZ )\n", &p->Name, &p->Value );
|
|
#endif
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
Next = SmpSubSystemsToLoad.Flink;
|
|
while ( Next != &SmpSubSystemsToLoad ) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: Loaded SubSystem( %wZ = %wZ )\n", &p->Name, &p->Value );
|
|
#endif
|
|
if (!_wcsicmp( p->Name.Buffer, L"debug" )) {
|
|
Status = SmpExecuteCommand( &p->Value, *pMuSessionId, pWindowsSubSysProcessId, SMP_SUBSYSTEM_FLAG | SMP_DEBUG_FLAG );
|
|
}
|
|
else {
|
|
Status = SmpExecuteCommand( &p->Value, *pMuSessionId, pWindowsSubSysProcessId, SMP_SUBSYSTEM_FLAG );
|
|
}
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return( Status );
|
|
}
|
|
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
Head = &SmpExecuteList;
|
|
if ( !IsListEmpty( Head ) ) {
|
|
Next = Head->Blink;
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
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 );
|
|
}
|
|
}
|
|
|
|
Next = SmpExecuteList.Flink;
|
|
while( Next != &SmpExecuteList ) {
|
|
|
|
//
|
|
// We do not want to execute the last entry. It's
|
|
// the winlogon initial command.
|
|
//
|
|
|
|
if( Next == SmpExecuteList.Blink ) {
|
|
Next = Next->Flink;
|
|
continue;
|
|
}
|
|
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: Execute( %wZ )\n", &p->Name );
|
|
#endif
|
|
SmpExecuteCommand( &p->Name, *pMuSessionId, NULL, 0 );
|
|
Next = Next->Flink;
|
|
}
|
|
|
|
#if 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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to query system basic information - %x\n",
|
|
Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
Status = NtQuerySystemInformation( SystemProcessorInformation,
|
|
&ProcessorInfo,
|
|
sizeof( ProcessorInfo ),
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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, KEY_ALL_ACCESS, &ObjectAttributes );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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;
|
|
|
|
case PROCESSOR_ARCHITECTURE_ALPHA64:
|
|
ValueData = L"ALPHA64";
|
|
break;
|
|
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
ValueData = L"IA64";
|
|
break;
|
|
|
|
default:
|
|
ValueData = L"Unknown";
|
|
break;
|
|
}
|
|
|
|
Status = NtSetValueKey( Key,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
ValueData,
|
|
(wcslen( ValueData ) + 1) * sizeof( WCHAR )
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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_IA64:
|
|
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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 );
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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:
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Failed writing %wZ environment variable - %x\n",
|
|
&ValueName,
|
|
Status));
|
|
|
|
goto failexit;
|
|
}
|
|
|
|
|
|
//
|
|
// get the safeboot option
|
|
//
|
|
|
|
RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Safeboot\\Option" );
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = NtOpenKey( &Key1, KEY_ALL_ACCESS, &ObjectAttributes );
|
|
if (NT_SUCCESS(Status)) {
|
|
RtlInitUnicodeString( &ValueName, L"OptionValue" );
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
Status = NtQueryValueKey(
|
|
Key1,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
sizeof(ValueBuffer),
|
|
&ValueLength
|
|
);
|
|
NtClose( Key1 );
|
|
if (NT_SUCCESS(Status)) {
|
|
RtlInitUnicodeString( &ValueName, L"SAFEBOOT_OPTION" );
|
|
switch (*(PULONG)(KeyValueInfo->Data)) {
|
|
case SAFEBOOT_MINIMAL:
|
|
wcscpy(ValueBuffer,SAFEBOOT_MINIMAL_STR_W);
|
|
break;
|
|
|
|
case SAFEBOOT_NETWORK:
|
|
wcscpy(ValueBuffer,SAFEBOOT_NETWORK_STR_W);
|
|
break;
|
|
|
|
case SAFEBOOT_DSREPAIR:
|
|
wcscpy(ValueBuffer,SAFEBOOT_DSREPAIR_STR_W);
|
|
break;
|
|
}
|
|
Status = NtSetValueKey(
|
|
Key,
|
|
&ValueName,
|
|
0,
|
|
REG_SZ,
|
|
ValueBuffer,
|
|
(wcslen(ValueBuffer)+1) * sizeof( WCHAR )
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Failed writing %wZ environment variable - %x\n",
|
|
&ValueName,
|
|
Status));
|
|
|
|
goto failexit;
|
|
}
|
|
} else {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Failed querying safeboot option = %x\n",
|
|
Status));
|
|
}
|
|
}
|
|
Status = STATUS_SUCCESS;
|
|
|
|
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=0;
|
|
|
|
//
|
|
// 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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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
|
|
);
|
|
#if 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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpInitializeKnownDlls( VOID )
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING DirectoryObjectName;
|
|
PLIST_ENTRY Head, Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
|
|
RtlInitUnicodeString( &DirectoryObjectName, L"\\KnownDlls" );
|
|
|
|
Status = SmpInitializeKnownDllsInternal(
|
|
&DirectoryObjectName,
|
|
&SmpKnownDllPath);
|
|
|
|
#ifdef _WIN64
|
|
if (!MiniNTBoot && NT_SUCCESS(Status))
|
|
{
|
|
RtlInitUnicodeString( &DirectoryObjectName, L"\\KnownDlls32" );
|
|
|
|
Status = SmpInitializeKnownDllsInternal(
|
|
&DirectoryObjectName,
|
|
&SmpKnownDllPath32);
|
|
}
|
|
#endif
|
|
|
|
Head = &SmpKnownDllsList;
|
|
Next = Head->Flink;
|
|
while (Next != Head) {
|
|
p = CONTAINING_RECORD( Next,
|
|
SMP_REGISTRY_VALUE,
|
|
Entry
|
|
);
|
|
Next = Next->Flink;
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SmpInitializeKnownDllsInternal(
|
|
IN PUNICODE_STRING ObjectDirectoryName,
|
|
IN PUNICODE_STRING KnownDllPath
|
|
)
|
|
{
|
|
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;
|
|
HANDLE KnownDllFileDirectory;
|
|
HANDLE KnownDllObjectDirectory;
|
|
|
|
//
|
|
// Create \KnownDllsxx object directory
|
|
//
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
ObjectDirectoryName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
NULL,
|
|
SmpKnownDllsSecurityDescriptor
|
|
);
|
|
Status = NtCreateDirectoryObject( &KnownDllObjectDirectory,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&ObjectAttributes
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to create %wZ directory - Status == %lx\n",
|
|
ObjectDirectoryName,
|
|
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( KnownDllPath->Buffer,
|
|
&FileName,
|
|
NULL,
|
|
NULL
|
|
)
|
|
) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to to convert %wZ to an Nt path\n",
|
|
KnownDllPath));
|
|
|
|
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( &KnownDllFileDirectory,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to open a handle to the KnownDll directory (%wZ) - Status == %lx\n",
|
|
KnownDllPath,
|
|
Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
RtlInitUnicodeString( &UnicodeString, L"KnownDllPath" );
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
|
|
KnownDllObjectDirectory,
|
|
SmpPrimarySecurityDescriptor
|
|
);
|
|
SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //Use inheritable protection if available
|
|
Status = NtCreateSymbolicLinkObject( &LinkHandle,
|
|
SYMBOLIC_LINK_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
KnownDllPath
|
|
);
|
|
SmpRestoreDaclDefaulted( &ObjectAttributes, OriginalSdControl );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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) {
|
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
else {
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: KnownDll( %wZ = %wZ )\n", &p->Name, &p->Value );
|
|
#endif
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&p->Value,
|
|
OBJ_CASE_INSENSITIVE,
|
|
KnownDllFileDirectory,
|
|
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 )) {
|
|
|
|
//
|
|
// good old stevewo... We want the side effects of this call (import
|
|
// callout, but don't want to checksum anymore, so supress with
|
|
// handle tag bit
|
|
//
|
|
|
|
ObjectDirectory = KnownDllObjectDirectory;
|
|
Status = LdrVerifyImageMatchesChecksum((HANDLE)((UINT_PTR)FileHandle|1),
|
|
SmpProcessModuleImports,
|
|
Next,
|
|
&ImageCharacteristics
|
|
);
|
|
if ( Status == STATUS_IMAGE_CHECKSUM_MISMATCH ) {
|
|
|
|
ULONG_PTR ErrorParameters;
|
|
ULONG ErrorResponse;
|
|
|
|
//
|
|
// Hard error time. One of the know DLL's is corrupt !
|
|
//
|
|
|
|
ErrorParameters = (ULONG_PTR)(&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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
|
|
&p->Value,
|
|
Status));
|
|
}
|
|
else {
|
|
NtClose(SectionHandle);
|
|
}
|
|
}
|
|
else {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 ?
|
|
//
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpSetProtectedFilesEnvVars(
|
|
IN BOOLEAN SetEnvVar
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets some environment variables that are not part of the
|
|
default environment. (These environment variables are normally set by
|
|
winlogon.) The environment variables need to be set for us to resolve
|
|
all the environment variables in our protected files list.
|
|
|
|
Note that SFC mirrors the data into the location below since smss can't
|
|
get at the actual variable location
|
|
|
|
The variables are:
|
|
|
|
ProgramFiles
|
|
CommonProgramFiles
|
|
|
|
ProgramFiles(x86)
|
|
CommonProgramFiles(x86)
|
|
|
|
Arguments:
|
|
|
|
SetEnvVar - if TRUE, we should query the registry for this variables and
|
|
set them. if FALSE, we should clear the environment variables
|
|
|
|
|
|
Return Value:
|
|
|
|
Status of operation
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
UNICODE_STRING EnvVar;
|
|
UNICODE_STRING EnvVarValue;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE Key;
|
|
WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
|
|
ULONG ValueLength;
|
|
ULONG Count;
|
|
|
|
PCWSTR RegistryValues[] = {
|
|
L"ProgramFilesDir"
|
|
, L"CommonFilesDir"
|
|
#ifdef WX86
|
|
, L"ProgramFilesDir(x86)"
|
|
, L"CommonFilesDir(x86)"
|
|
#endif
|
|
};
|
|
|
|
PCWSTR EnvVars[] = {
|
|
L"ProgramFiles"
|
|
, L"CommonProgramFiles"
|
|
#ifdef WX86
|
|
, L"ProgramFiles(x86)"
|
|
, L"CommonProgramFiles(x86)"
|
|
#endif
|
|
};
|
|
|
|
#define EnvVarCount sizeof(RegistryValues)/sizeof(PCWSTR)
|
|
|
|
if (SetEnvVar) {
|
|
|
|
|
|
//
|
|
// Open the registry key.
|
|
//
|
|
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
RtlInitUnicodeString(&KeyName,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\SFC");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: can't open control key: 0x%x\n",
|
|
Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Query the key values.
|
|
//
|
|
for (Count = 0; Count < EnvVarCount; Count++) {
|
|
|
|
RtlInitUnicodeString(&ValueName, RegistryValues[Count]);
|
|
Status = NtQueryValueKey(Key,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
VALUE_BUFFER_SIZE,
|
|
&ValueLength);
|
|
|
|
ASSERT(ValueLength < VALUE_BUFFER_SIZE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: can't query value key %ws: 0x%x\n",
|
|
RegistryValues[Count],
|
|
Status));
|
|
|
|
} else {
|
|
|
|
|
|
ASSERT(KeyValueInfo->Type == REG_SZ);
|
|
|
|
RtlInitUnicodeString(&EnvVar, EnvVars[Count]);
|
|
|
|
EnvVarValue.Length = (USHORT)KeyValueInfo->DataLength;
|
|
EnvVarValue.MaximumLength = (USHORT)KeyValueInfo->DataLength;
|
|
EnvVarValue.Buffer = (PWSTR)KeyValueInfo->Data;
|
|
|
|
Status = RtlSetEnvironmentVariable( NULL,
|
|
&EnvVar,
|
|
&EnvVarValue
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: can't set environment variable %ws: 0x%x\n",
|
|
EnvVars[Count],
|
|
Status));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NtClose(Key);
|
|
|
|
} else {
|
|
//
|
|
// clear out the variables
|
|
//
|
|
for (Count = 0; Count < EnvVarCount; Count++) {
|
|
|
|
RtlInitUnicodeString(&EnvVar, EnvVars[Count]);
|
|
RtlInitUnicodeString(&EnvVarValue, NULL);
|
|
|
|
Status = RtlSetEnvironmentVariable( NULL,
|
|
&EnvVar,
|
|
&EnvVarValue
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: can't clear environment variable %ws: 0x%x\n",
|
|
EnvVars[Count],
|
|
Status));
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpGetProtectedFiles(
|
|
OUT PPROTECT_FILE_ENTRY *Files,
|
|
OUT PULONG FileCount,
|
|
OUT PVOID *hModule
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING DllName;
|
|
STRING ProcedureName;
|
|
PSFCGETFILES pSfcGetFiles;
|
|
|
|
ASSERT(hModule != NULL);
|
|
*hModule = NULL;
|
|
RtlInitUnicodeString( &DllName, L"sfcfiles.dll" );
|
|
|
|
Status = LdrLoadDll(
|
|
NULL,
|
|
NULL,
|
|
&DllName,
|
|
hModule
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: LdrLoadDll failed for %ws, ec=%lx\n",
|
|
DllName.Buffer,
|
|
Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
RtlInitString( &ProcedureName, "SfcGetFiles" );
|
|
|
|
Status = LdrGetProcedureAddress(
|
|
*hModule,
|
|
&ProcedureName,
|
|
0,
|
|
(PVOID*)&pSfcGetFiles
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: sfcfile.dll loaded successfully, address=%08x\n", *hModule );
|
|
#endif
|
|
|
|
Status = pSfcGetFiles( Files, FileCount );
|
|
}
|
|
else {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: LdrGetProcedureAddress failed for %ws, ec=%lx\n",
|
|
ProcedureName.Buffer,
|
|
Status));
|
|
|
|
LdrUnloadDll(*hModule);
|
|
*hModule = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
LONG
|
|
SpecialStringCompare(
|
|
PUNICODE_STRING s1,
|
|
PUNICODE_STRING s2
|
|
)
|
|
{
|
|
UNICODE_STRING tmp;
|
|
|
|
|
|
if (s1->Buffer[0] != L'!') {
|
|
return RtlCompareUnicodeString( s1, s2, TRUE );
|
|
}
|
|
|
|
tmp.Length = s1->Length - sizeof(WCHAR);
|
|
tmp.MaximumLength = s1->MaximumLength - sizeof(WCHAR);
|
|
tmp.Buffer = s1->Buffer + 1;
|
|
|
|
return RtlCompareUnicodeString( &tmp, s2, TRUE );
|
|
}
|
|
|
|
|
|
VOID
|
|
SmpProcessFileRenames( VOID )
|
|
{
|
|
NTSTATUS Status,OpenStatus;
|
|
PLIST_ENTRY Head, Next;
|
|
PSMP_REGISTRY_VALUE p;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
HANDLE OldFileHandle,SetAttributesHandle;
|
|
PFILE_RENAME_INFORMATION RenameInformation;
|
|
FILE_DISPOSITION_INFORMATION DeleteInformation;
|
|
FILE_INFORMATION_CLASS SetInfoClass;
|
|
FILE_BASIC_INFORMATION BasicInfo;
|
|
ULONG SetInfoLength;
|
|
PVOID SetInfoBuffer;
|
|
PWSTR s;
|
|
BOOLEAN WasEnabled;
|
|
UNICODE_STRING NewName;
|
|
ULONG i;
|
|
UNICODE_STRING ProtFileName = {0};
|
|
UNICODE_STRING Tier2Name;
|
|
UNICODE_STRING ProtName;
|
|
PPROTECT_FILE_ENTRY Tier2Files;
|
|
ULONG CountTier2Files;
|
|
PVOID hModule = NULL;
|
|
BOOLEAN EnvVarSet;
|
|
|
|
|
|
Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
|
|
TRUE,
|
|
FALSE,
|
|
&WasEnabled
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
WasEnabled = TRUE;
|
|
}
|
|
|
|
if (SmpAllowProtectedRenames == 0) {
|
|
Status = SmpGetProtectedFiles( &Tier2Files, &CountTier2Files, &hModule );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpGetProtectedFiles failed, ec=%08x\n",
|
|
Status));
|
|
|
|
SmpAllowProtectedRenames = 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// our list of protected files includes environment variables that are not
|
|
// in the default environment, they are normally set by winlogon. Set
|
|
// those environment variables temporarily until we process the file rename
|
|
// section, then we can clear them out again.
|
|
//
|
|
EnvVarSet = TRUE;
|
|
Status = SmpSetProtectedFilesEnvVars( TRUE );
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpSetProtectedFilesEnvVars failed, ec=%08x\n",
|
|
Status));
|
|
|
|
EnvVarSet = FALSE;
|
|
}
|
|
|
|
//
|
|
// Process the list of file rename operations.
|
|
//
|
|
|
|
Head = &SmpFileRenameList;
|
|
while (!IsListEmpty( Head )) {
|
|
Next = RemoveHeadList( Head );
|
|
p = CONTAINING_RECORD( Next, SMP_REGISTRY_VALUE, Entry );
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: FileRename( [%wZ] => [%wZ] )\n", &p->Name, &p->Value );
|
|
#endif
|
|
|
|
//
|
|
// ignore any file that is protected
|
|
//
|
|
|
|
if (SmpAllowProtectedRenames == 0) {
|
|
ProtName.MaximumLength = 256 * sizeof(WCHAR);
|
|
ProtName.Buffer = (PWSTR) RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), ProtName.MaximumLength );
|
|
if (ProtName.Buffer) {
|
|
for (i=0; i<CountTier2Files; i++) {
|
|
//
|
|
// if the file name is prefixed by the '@' character
|
|
// then we ignore the check and say the file is ok
|
|
//
|
|
if (p->Name.Buffer[0] == '@' || p->Value.Buffer[0] == L'@') {
|
|
break;
|
|
}
|
|
//
|
|
// convert the tier2 file name to an nt style file name
|
|
//
|
|
RtlInitUnicodeString(&Tier2Name,Tier2Files[i].FileName);
|
|
ProtName.Length = 0;
|
|
RtlZeroMemory( ProtName.Buffer, ProtName.MaximumLength );
|
|
if (ProtName.Buffer == NULL) {
|
|
continue;
|
|
}
|
|
Status = RtlExpandEnvironmentStrings_U(
|
|
NULL,
|
|
&Tier2Name,
|
|
&ProtName,
|
|
NULL
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
continue;
|
|
}
|
|
if (!RtlDosPathNameToNtPathName_U( ProtName.Buffer, &ProtFileName, NULL, NULL )) {
|
|
continue;
|
|
}
|
|
//
|
|
// check for matches against both file names
|
|
//
|
|
if (SpecialStringCompare( &p->Name, &ProtFileName ) == 0 ||
|
|
SpecialStringCompare( &p->Value, &ProtFileName ) == 0)
|
|
{
|
|
break;
|
|
}
|
|
RtlFreeUnicodeString(&ProtFileName);
|
|
ProtFileName.Buffer = NULL;
|
|
}
|
|
RtlFreeHeap( RtlProcessHeap(), 0, ProtName.Buffer );
|
|
if (i < CountTier2Files) {
|
|
if (p->Name.Buffer[0] == L'@' || p->Value.Buffer[0] == L'@') {
|
|
} else {
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: Skipping rename because it is protected\n" );
|
|
#endif
|
|
//
|
|
// delete the source file so we don't leave any turds
|
|
//
|
|
if (p->Value.Length > 0 && ProtFileName.Buffer && SpecialStringCompare( &p->Name, &ProtFileName ) != 0) {
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&p->Name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Status = NtOpenFile(
|
|
&OldFileHandle,
|
|
(ACCESS_MASK)DELETE | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
SetInfoClass = FileDispositionInformation;
|
|
SetInfoLength = sizeof( DeleteInformation );
|
|
SetInfoBuffer = &DeleteInformation;
|
|
DeleteInformation.DeleteFile = TRUE;
|
|
Status = NtSetInformationFile(
|
|
OldFileHandle,
|
|
&IoStatusBlock,
|
|
SetInfoBuffer,
|
|
SetInfoLength,
|
|
SetInfoClass
|
|
);
|
|
NtClose( OldFileHandle );
|
|
}
|
|
}
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
RtlFreeUnicodeString(&ProtFileName);
|
|
ProtFileName.Buffer = NULL;
|
|
continue;
|
|
}
|
|
} else {
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
DbgPrint( "SMSS: File is not in the protected list\n" );
|
|
#endif
|
|
}
|
|
if (ProtFileName.Buffer) {
|
|
RtlFreeUnicodeString(&ProtFileName);
|
|
ProtFileName.Buffer = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open the file for delete access
|
|
//
|
|
|
|
if (p->Value.Length == 0 && p->Name.Buffer[0] == '@') {
|
|
p->Name.Buffer += 1;
|
|
p->Name.Length -= sizeof(WCHAR);
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&p->Name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
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 == 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
|
|
);
|
|
if (!NT_SUCCESS( Status ) && SetInfoClass == FileRenameInformation && Status == STATUS_OBJECT_NAME_COLLISION && RenameInformation->ReplaceIfExists ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
|
|
&p->Name,
|
|
&p->Value,
|
|
Status));
|
|
|
|
//
|
|
// A rename was attempted, but the source existing file is readonly.
|
|
// this is a problem because folks that use movefileex to do delayed
|
|
// renames expect this to work and can leave a machine unbootable if
|
|
// the rename fails
|
|
//
|
|
|
|
//
|
|
// Open the file for Write Attributes access
|
|
//
|
|
|
|
NewName.Length = p->Value.Length - sizeof(L'!');
|
|
NewName.MaximumLength = p->Value.MaximumLength - sizeof(L'!');
|
|
NewName.Buffer = s;;
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&NewName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
OpenStatus = NtOpenFile( &SetAttributesHandle,
|
|
(ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
if (NT_SUCCESS( OpenStatus )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
" SMSS: Open Existing Success\n"));
|
|
|
|
RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
|
|
BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
OpenStatus = NtSetInformationFile(
|
|
SetAttributesHandle,
|
|
&IoStatusBlock,
|
|
&BasicInfo,
|
|
sizeof(BasicInfo),
|
|
FileBasicInformation
|
|
);
|
|
NtClose( SetAttributesHandle );
|
|
if ( NT_SUCCESS(OpenStatus) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
" SMSS: Set To NORMAL OK\n"));
|
|
|
|
Status = NtSetInformationFile( OldFileHandle,
|
|
&IoStatusBlock,
|
|
SetInfoBuffer,
|
|
SetInfoLength,
|
|
SetInfoClass
|
|
);
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
" SMSS: Re-Rename Worked OK\n"));
|
|
}
|
|
else {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
" SMSS: Re-Rename Failed - Status == %x\n",
|
|
Status));
|
|
}
|
|
}
|
|
else {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
" SMSS: Set To NORMAL Failed - Status == %x\n",
|
|
OpenStatus));
|
|
}
|
|
}
|
|
else {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
" SMSS: Open Existing file Failed - Status == %x\n",
|
|
OpenStatus));
|
|
}
|
|
}
|
|
}
|
|
|
|
NtClose( OldFileHandle );
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: %wZ => %wZ failed - Status == %x\n",
|
|
&p->Name,
|
|
&p->Value,
|
|
Status));
|
|
}
|
|
else
|
|
if (p->Value.Length == 0) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"SMSS: %wZ (deleted)\n",
|
|
&p->Name ));
|
|
}
|
|
else {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"SMSS: %wZ (renamed to) %wZ\n",
|
|
&p->Name,
|
|
&p->Value ));
|
|
}
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, p );
|
|
}
|
|
|
|
if (EnvVarSet) {
|
|
SmpSetProtectedFilesEnvVars( FALSE );
|
|
}
|
|
|
|
if (!WasEnabled) {
|
|
Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
|
|
FALSE,
|
|
FALSE,
|
|
&WasEnabled
|
|
);
|
|
}
|
|
|
|
if (hModule) {
|
|
LdrUnloadDll( hModule );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
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");
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 );
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "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
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "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 );
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "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)) {
|
|
#if 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 );
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "DosDevices", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
UNREFERENCED_PARAMETER( ValueLength );
|
|
#endif
|
|
return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
|
|
ValueName,
|
|
ValueData,
|
|
TRUE
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpInitializeKnownDllPath(
|
|
IN PUNICODE_STRING KnownDllPath,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength)
|
|
{
|
|
KnownDllPath->Buffer = RtlAllocateHeap(
|
|
RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
ValueLength);
|
|
|
|
if (KnownDllPath->Buffer == NULL)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
KnownDllPath->Length = (USHORT)( ValueLength - sizeof( UNICODE_NULL ) );
|
|
KnownDllPath->MaximumLength = (USHORT)ValueLength;
|
|
RtlMoveMemory(
|
|
KnownDllPath->Buffer,
|
|
ValueData,
|
|
ValueLength);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SmpConfigureKnownDlls(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER( Context );
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "KnownDlls", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
#endif
|
|
if (!_wcsicmp( ValueName, L"DllDirectory" )) {
|
|
return SmpInitializeKnownDllPath( &SmpKnownDllPath,
|
|
ValueData,
|
|
ValueLength
|
|
);
|
|
}
|
|
#ifdef _WIN64
|
|
if (!MiniNTBoot && !_wcsicmp( ValueName, L"DllDirectory32" )) {
|
|
return SmpInitializeKnownDllPath( &SmpKnownDllPath32,
|
|
ValueData,
|
|
ValueLength
|
|
);
|
|
}
|
|
#endif
|
|
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 );
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "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 );
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 );
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "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 {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Invalid subsystem name - %ws\n",
|
|
s));
|
|
}
|
|
|
|
while (*s++ != UNICODE_NULL) {
|
|
}
|
|
}
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
else if (!_wcsicmp( ValueName, L"PosixSingleInstance" ) &&
|
|
(ValueType == REG_DWORD)) {
|
|
RegPosixSingleInstance = TRUE;
|
|
#if 0
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"SMSS: Single Instance Posix Subsystem Configured\n"));
|
|
#endif
|
|
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 = (ULONG)((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 );
|
|
|
|
if (ARGUMENT_PRESENT( ImageFileDirectory )) {
|
|
RtlInitUnicodeString( ImageFileDirectory, 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;
|
|
}
|
|
#if defined(REMOTE_BOOT)
|
|
else
|
|
if (RtlEqualUnicodeString( &Token, &SmpAutoFmtKeyword, TRUE )) {
|
|
*Flags |= SMP_AUTOFMT_FLAG;
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
|
|
continue;
|
|
}
|
|
#endif // defined(REMOTE_BOOT)
|
|
}
|
|
|
|
SpResult = 0;
|
|
RtlInitUnicodeString( &PathVariableName, L"Path" );
|
|
PathVariableValue.Length = 0;
|
|
PathVariableValue.MaximumLength = 4096;
|
|
PathVariableValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
|
|
PathVariableValue.MaximumLength
|
|
);
|
|
if (PathVariableValue.Buffer == NULL) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = RtlQueryEnvironmentVariable_U( SmpDefaultEnvironment,
|
|
&PathVariableName,
|
|
&PathVariableValue
|
|
);
|
|
if ( Status == STATUS_BUFFER_TOO_SMALL ) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer );
|
|
PathVariableValue.MaximumLength = PathVariableValue.Length + 2;
|
|
PathVariableValue.Length = 0;
|
|
PathVariableValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
|
|
PathVariableValue.MaximumLength
|
|
);
|
|
if (PathVariableValue.Buffer == NULL) {
|
|
RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = RtlQueryEnvironmentVariable_U( SmpDefaultEnvironment,
|
|
&PathVariableName,
|
|
&PathVariableValue
|
|
);
|
|
}
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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, Token.Buffer );
|
|
RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer );
|
|
if (NT_SUCCESS( Status ) &&
|
|
!RtlDosPathNameToNtPathName_U( FullDosPathBuffer,
|
|
ImageFileName,
|
|
NULL,
|
|
NULL
|
|
)
|
|
) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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
|
|
SmpExecuteImage(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG MuSessionId,
|
|
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 0
|
|
BOOLEAN ImageWhacked;
|
|
#endif
|
|
if (!ARGUMENT_PRESENT( ProcessInformation )) {
|
|
ProcessInformation = &MyProcessInformation;
|
|
}
|
|
|
|
|
|
#if 0
|
|
//
|
|
// this seems to break setup's sense of what SystemRoot is
|
|
ImageWhacked = FALSE;
|
|
if ( ImageFileName && ImageFileName->Length > 8 ) {
|
|
if ( ImageFileName->Buffer[0] == L'\\'
|
|
&& ImageFileName->Buffer[1] == L'?'
|
|
&& ImageFileName->Buffer[2] == L'?'
|
|
&& ImageFileName->Buffer[3] == L'\\' ) {
|
|
ImageWhacked = TRUE;
|
|
ImageFileName->Buffer[1] = L'\\';
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Status = RtlCreateProcessParameters( &ProcessParameters,
|
|
ImageFileName,
|
|
(SmpDefaultLibPath.Length == 0 ?
|
|
NULL : &SmpDefaultLibPath
|
|
),
|
|
CurrentDirectory,
|
|
CommandLine,
|
|
SmpDefaultEnvironment,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
#if 0
|
|
if ( ImageWhacked ) {
|
|
ImageFileName->Buffer[1] = L'?';
|
|
}
|
|
#endif
|
|
|
|
ASSERTMSG( "RtlCreateProcessParameters", NT_SUCCESS( Status ) );
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: RtlCreateProcessParameters failed for %wZ - Status == %lx\n",
|
|
ImageFileName,
|
|
Status));
|
|
|
|
return( 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 ) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Failed load of %wZ - Status == %lx\n",
|
|
ImageFileName,
|
|
Status));
|
|
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Set the MuSessionId in the PEB of the new process.
|
|
//
|
|
|
|
Status = SmpSetProcessMuSessionId( ProcessInformation->Process, MuSessionId );
|
|
|
|
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 );
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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 MuSessionId,
|
|
OUT PULONG_PTR pWindowsSubSysProcessId,
|
|
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.
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
-or-
|
|
|
|
Nt-Path-To-AutoFmt.exe Nt-Path-To-Disk-Partition
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
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( STATUS_SUCCESS );
|
|
}
|
|
|
|
Status = SmpParseCommandLine( CommandLine,
|
|
&Flags,
|
|
&ImageFileName,
|
|
&CurrentDirectory,
|
|
&Arguments
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n",
|
|
CommandLine,
|
|
Status));
|
|
|
|
return( Status );
|
|
}
|
|
|
|
if (Flags & SMP_AUTOCHK_FLAG) {
|
|
Status = SmpInvokeAutoChk( &ImageFileName, &CurrentDirectory, &Arguments, Flags );
|
|
}
|
|
#if defined(REMOTE_BOOT)
|
|
else
|
|
if (Flags & SMP_AUTOFMT_FLAG) {
|
|
Status = SmpInvokeAutoFmt( &ImageFileName, &CurrentDirectory, &Arguments, Flags );
|
|
}
|
|
#endif // defined(REMOTE_BOOT)
|
|
else
|
|
if (Flags & SMP_SUBSYSTEM_FLAG) {
|
|
Status = SmpLoadSubSystem( &ImageFileName, &CurrentDirectory, CommandLine, MuSessionId, pWindowsSubSysProcessId, Flags );
|
|
}
|
|
else {
|
|
if (Flags & SMP_IMAGE_NOT_FOUND) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Image file (%wZ) not found\n",
|
|
&ImageFileName));
|
|
|
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
else {
|
|
Status = SmpExecuteImage( &ImageFileName,
|
|
&CurrentDirectory,
|
|
CommandLine,
|
|
MuSessionId,
|
|
Flags,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
|
|
// ImageFileName may be returned even
|
|
// when SMP_IMAGE_NOT_FOUND flag is set
|
|
if (ImageFileName.Buffer) {
|
|
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 )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Command '%wZ' failed - Status == %x\n",
|
|
CommandLine,
|
|
Status));
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
BOOLEAN
|
|
SmpSaveAndClearBootStatusData(
|
|
OUT PBOOLEAN BootOkay,
|
|
OUT PBOOLEAN ShutdownOkay
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine saves the boot status flags in the boot status data and then
|
|
sets the data file to indicate a successful boot and shutdown. This is
|
|
used to avoid triggering auto-recovery in the loader if autoconvert or
|
|
autochk reboots the machine as part of its run.
|
|
|
|
The caller is responsible for calling SmpRestoreBootStatusData if the
|
|
auto* program allows boot to continue.
|
|
|
|
Arguments:
|
|
|
|
BootOkay - the status of the boot
|
|
|
|
ShutdownOkay - the status of the shutdown
|
|
|
|
Return Value:
|
|
|
|
TRUE if the values were saved and should be restored.
|
|
FALSE if an error occurred and no values were saved.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PVOID BootStatusDataHandle;
|
|
|
|
*BootOkay = FALSE;
|
|
*ShutdownOkay = FALSE;
|
|
|
|
Status = RtlLockBootStatusData(&BootStatusDataHandle);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
BOOLEAN t = TRUE;
|
|
|
|
RtlGetSetBootStatusData(BootStatusDataHandle,
|
|
TRUE,
|
|
RtlBsdItemBootGood,
|
|
BootOkay,
|
|
sizeof(BOOLEAN),
|
|
NULL);
|
|
|
|
RtlGetSetBootStatusData(BootStatusDataHandle,
|
|
TRUE,
|
|
RtlBsdItemBootShutdown,
|
|
ShutdownOkay,
|
|
sizeof(BOOLEAN),
|
|
NULL);
|
|
|
|
RtlGetSetBootStatusData(BootStatusDataHandle,
|
|
FALSE,
|
|
RtlBsdItemBootGood,
|
|
&t,
|
|
sizeof(BOOLEAN),
|
|
NULL);
|
|
|
|
RtlGetSetBootStatusData(BootStatusDataHandle,
|
|
FALSE,
|
|
RtlBsdItemBootShutdown,
|
|
&t,
|
|
sizeof(BOOLEAN),
|
|
NULL);
|
|
|
|
RtlUnlockBootStatusData(BootStatusDataHandle);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
SmpRestoreBootStatusData(
|
|
IN BOOLEAN BootOkay,
|
|
IN BOOLEAN ShutdownOkay
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine restores the boot status flags in the boot status data to
|
|
the provided values.
|
|
|
|
Arguments:
|
|
|
|
BootOkay - the status of the boot
|
|
|
|
ShutdownOkay - the status of the shutdown
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PVOID BootStatusDataHandle;
|
|
|
|
Status = RtlLockBootStatusData(&BootStatusDataHandle);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
RtlGetSetBootStatusData(BootStatusDataHandle,
|
|
FALSE,
|
|
RtlBsdItemBootGood,
|
|
&BootOkay,
|
|
sizeof(BOOLEAN),
|
|
NULL);
|
|
|
|
RtlGetSetBootStatusData(BootStatusDataHandle,
|
|
FALSE,
|
|
RtlBsdItemBootShutdown,
|
|
&ShutdownOkay,
|
|
sizeof(BOOLEAN),
|
|
NULL);
|
|
|
|
RtlUnlockBootStatusData(BootStatusDataHandle);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpInvokeAutoChk(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING Arguments,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
CHAR DisplayBuffer[ MAXIMUM_FILENAME_LENGTH ];
|
|
ANSI_STRING AnsiDisplayString;
|
|
UNICODE_STRING DisplayString;
|
|
|
|
UNICODE_STRING CmdLine;
|
|
WCHAR CmdLineBuffer[ 2 * MAXIMUM_FILENAME_LENGTH ];
|
|
|
|
BOOLEAN BootStatusDataSaved = FALSE;
|
|
BOOLEAN BootOkay;
|
|
BOOLEAN ShutdownOkay;
|
|
|
|
//
|
|
// Query the system environment variable "osloadoptions" to determine
|
|
// if SOS is specified. What for though? No one is using it.
|
|
//
|
|
|
|
if (SmpQueryRegistrySosOption() != FALSE) {
|
|
SmpEnableDots = FALSE;
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
//
|
|
// Save away the boot & shutdown status flags in the boot status data
|
|
// and restore them after autochk returns. This way if autochk forces
|
|
// a reboot the loader won't put up the autorecovery menu.
|
|
//
|
|
|
|
BootStatusDataSaved = SmpSaveAndClearBootStatusData(&BootOkay,
|
|
&ShutdownOkay);
|
|
|
|
CmdLine.Buffer = CmdLineBuffer;
|
|
CmdLine.MaximumLength = sizeof( CmdLineBuffer );
|
|
CmdLine.Length = 0;
|
|
RtlAppendUnicodeStringToString( &CmdLine, ImageFileName );
|
|
RtlAppendUnicodeToString( &CmdLine, L" " );
|
|
RtlAppendUnicodeStringToString( &CmdLine, Arguments );
|
|
SmpExecuteImage( ImageFileName,
|
|
CurrentDirectory,
|
|
&CmdLine,
|
|
0, // MuSessionId
|
|
Flags & ~SMP_AUTOCHK_FLAG,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// If autochk doesn't shut us down then we end up back here. Restore the
|
|
// values we saved.
|
|
//
|
|
|
|
if(BootStatusDataSaved) {
|
|
SmpRestoreBootStatusData(BootOkay, ShutdownOkay);
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
NTSTATUS
|
|
SmpInvokeAutoFmt(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING Arguments,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
CHAR DisplayBuffer[ MAXIMUM_FILENAME_LENGTH ];
|
|
ANSI_STRING AnsiDisplayString;
|
|
UNICODE_STRING DisplayString;
|
|
UNICODE_STRING CmdLine;
|
|
WCHAR CmdLineBuffer[ 2 * MAXIMUM_FILENAME_LENGTH ];
|
|
|
|
BOOLEAN BootStatusDataSaved;
|
|
BOOLEAN BootOkay;
|
|
BOOLEAN ShutdownOkay;
|
|
|
|
//
|
|
// Query the system environment variable "osloadoptions" to determine
|
|
// if SOS is specified.
|
|
//
|
|
|
|
if (SmpQueryRegistrySosOption() != FALSE) {
|
|
SmpEnableDots = FALSE;
|
|
}
|
|
|
|
if (Flags & SMP_IMAGE_NOT_FOUND) {
|
|
sprintf( DisplayBuffer,
|
|
"%wZ program not found - skipping AUTOFMT\n",
|
|
ImageFileName
|
|
);
|
|
|
|
RtlInitAnsiString( &AnsiDisplayString, DisplayBuffer );
|
|
Status = RtlAnsiStringToUnicodeString( &DisplayString,
|
|
&AnsiDisplayString,
|
|
TRUE
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
NtDisplayString( &DisplayString );
|
|
RtlFreeUnicodeString( &DisplayString );
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
BootStatusDataSaved = SmpSaveAndClearBootStatusData(&BootOkay,
|
|
&ShutdownOkay);
|
|
|
|
CmdLine.Buffer = CmdLineBuffer;
|
|
CmdLine.MaximumLength = sizeof( CmdLineBuffer );
|
|
CmdLine.Length = 0;
|
|
RtlAppendUnicodeStringToString( &CmdLine, ImageFileName );
|
|
RtlAppendUnicodeToString( &CmdLine, L" " );
|
|
RtlAppendUnicodeStringToString( &CmdLine, Arguments );
|
|
|
|
SmpExecuteImage( ImageFileName,
|
|
CurrentDirectory,
|
|
&CmdLine,
|
|
0, //Console MuSessionId
|
|
Flags & ~SMP_AUTOFMT_FLAG,
|
|
NULL
|
|
);
|
|
|
|
if(BootStatusDataSaved) {
|
|
SmpRestoreBootStatusData(BootOkay, ShutdownOkay);
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
|
|
NTSTATUS
|
|
SmpLoadSubSystem(
|
|
IN PUNICODE_STRING ImageFileName,
|
|
IN PUNICODE_STRING CurrentDirectory,
|
|
IN PUNICODE_STRING CommandLine,
|
|
IN ULONG MuSessionId,
|
|
OUT PULONG_PTR pWindowsSubSysProcessId,
|
|
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.
|
|
|
|
For terminal server, the subsystem is started by csrss so that the
|
|
correct session is used.
|
|
|
|
Arguments:
|
|
|
|
CommandLine - Supplies the command line to execute the subsystem.
|
|
|
|
Return Value:
|
|
|
|
TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
RTL_USER_PROCESS_INFORMATION ProcessInformation;
|
|
PSMPKNOWNSUBSYS KnownSubSys = NULL;
|
|
PSMPKNOWNSUBSYS TargetSubSys = NULL;
|
|
PSMPKNOWNSUBSYS CreatorSubSys = NULL;
|
|
LARGE_INTEGER Timeout;
|
|
ULONG SubsysMuSessionId = MuSessionId;
|
|
PVOID State;
|
|
NTSTATUS AcquirePrivilegeStatus = STATUS_SUCCESS;
|
|
|
|
if (Flags & SMP_IMAGE_NOT_FOUND) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to find subsystem - %wZ\n",
|
|
ImageFileName));
|
|
|
|
return( STATUS_OBJECT_NAME_NOT_FOUND );
|
|
}
|
|
|
|
//
|
|
// Check for single instance POSIX subsystem
|
|
//
|
|
if (Flags & SMP_POSIX_SI_FLAG) {
|
|
// Run only one copy using the console Logon Id
|
|
SubsysMuSessionId = 0;
|
|
}
|
|
|
|
//
|
|
// There is a race condition on hydra loading subsystems. Two
|
|
// requests can be received from the same MuSessionId to load
|
|
// the same subsystem. There is a window in hydra since the
|
|
// ImageType == 0xFFFFFFFF until the newly started subsystem connects
|
|
// back. Non-hydra didn't have this problem since the optional
|
|
// subsystem entry was destroyed once started. Hydra does not do this
|
|
// since multiple sessions may want to start an optional subsystem.
|
|
//
|
|
// To close this window, on hydra this value is looked up based on
|
|
// the MuSessionId to see if any subsystems are starting.
|
|
// If so, we wait for the Active event. We can then
|
|
// run our checks for the subsystem already being loaded. This has
|
|
// the effect of serializing the startup of a subsystem on hydra
|
|
// per MuSessionId, but not across the system. IE: Posix and
|
|
// OS2 can't start at the same time, but will wait until
|
|
// the other has started on a MuSessionId basis.
|
|
//
|
|
// We also use the SmpKnownSubSysLock to handle existing
|
|
// race conditions since we have multiple SmpApiLoop() threads.
|
|
//
|
|
|
|
RtlEnterCriticalSection( &SmpKnownSubSysLock );
|
|
|
|
do {
|
|
|
|
TargetSubSys = SmpLocateKnownSubSysByType(
|
|
SubsysMuSessionId,
|
|
0xFFFFFFFF
|
|
);
|
|
|
|
if( TargetSubSys ) {
|
|
HANDLE hEvent = TargetSubSys->Active;
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
Status = NtWaitForSingleObject( hEvent, FALSE, NULL );
|
|
RtlEnterCriticalSection( &SmpKnownSubSysLock );
|
|
SmpDeferenceKnownSubSys(TargetSubSys);
|
|
}
|
|
|
|
} while ( TargetSubSys != NULL );
|
|
|
|
if (Flags & SMP_POSIX_FLAG) {
|
|
TargetSubSys = SmpLocateKnownSubSysByType(
|
|
SubsysMuSessionId,
|
|
IMAGE_SUBSYSTEM_POSIX_CUI
|
|
);
|
|
|
|
if( TargetSubSys ) {
|
|
SmpDeferenceKnownSubSys(TargetSubSys);
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
}
|
|
|
|
if (Flags & SMP_OS2_FLAG) {
|
|
TargetSubSys = SmpLocateKnownSubSysByType(
|
|
SubsysMuSessionId,
|
|
IMAGE_SUBSYSTEM_OS2_CUI
|
|
);
|
|
|
|
if( TargetSubSys ) {
|
|
SmpDeferenceKnownSubSys(TargetSubSys);
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create and register KnownSubSys entry before releasing the lock
|
|
// so that other threads will see that we are starting a subsystem
|
|
// on this MuSessionId.
|
|
//
|
|
KnownSubSys = RtlAllocateHeap( SmpHeap, MAKE_TAG( INIT_TAG ), sizeof( SMPKNOWNSUBSYS ) );
|
|
if ( KnownSubSys == NULL ) {
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
|
|
KnownSubSys->Deleting = FALSE;
|
|
KnownSubSys->Process = NULL;
|
|
KnownSubSys->Active = NULL;
|
|
KnownSubSys->MuSessionId = SubsysMuSessionId;
|
|
KnownSubSys->ImageType = (ULONG)0xFFFFFFFF;
|
|
KnownSubSys->SmApiCommunicationPort = (HANDLE) NULL;
|
|
KnownSubSys->SbApiCommunicationPort = (HANDLE) NULL;
|
|
KnownSubSys->RefCount = 1;
|
|
|
|
Status = NtCreateEvent( &KnownSubSys->Active,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if( !NT_SUCCESS(Status) ) {
|
|
RtlFreeHeap( SmpHeap, 0, KnownSubSys );
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
return( STATUS_NO_MEMORY );
|
|
}
|
|
|
|
InsertHeadList( &SmpKnownSubSysHead, &KnownSubSys->Links );
|
|
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
|
|
Flags |= SMP_DONT_START;
|
|
|
|
if (((Flags & SMP_OS2_FLAG) || (Flags & SMP_POSIX_FLAG))) {
|
|
|
|
SBAPIMSG m;
|
|
PSBCREATEPROCESS args = &m.u.CreateProcess;
|
|
|
|
//
|
|
// Create it in csrss instead.
|
|
//
|
|
|
|
CreatorSubSys = SmpLocateKnownSubSysByType(SubsysMuSessionId,
|
|
IMAGE_SUBSYSTEM_WINDOWS_GUI);
|
|
|
|
//
|
|
// CSRSS must have been started.
|
|
//
|
|
|
|
if (CreatorSubSys == NULL) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed\n"));
|
|
|
|
goto cleanup2;
|
|
}
|
|
|
|
args->i.ImageFileName = ImageFileName;
|
|
args->i.CurrentDirectory = CurrentDirectory;
|
|
args->i.CommandLine = CommandLine;
|
|
args->i.DefaultLibPath = (SmpDefaultLibPath.Length == 0 ?
|
|
NULL : &SmpDefaultLibPath
|
|
);
|
|
args->i.Flags = Flags;
|
|
args->i.DefaultDebugFlags = SmpDebug;
|
|
|
|
Status = SmpCallCsrCreateProcess(&m,
|
|
sizeof(*args),
|
|
CreatorSubSys->SbApiCommunicationPort
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - SmpCallCsrCreateProcess Failed with Status %lx\n",
|
|
Status));
|
|
|
|
goto cleanup2;
|
|
}
|
|
|
|
//
|
|
// Copy the output parameters to where smss expects them.
|
|
//
|
|
|
|
ProcessInformation.Process = args->o.Process;
|
|
ProcessInformation.Thread = args->o.Thread;
|
|
ProcessInformation.ClientId.UniqueProcess = args->o.ClientId.UniqueProcess;
|
|
ProcessInformation.ClientId.UniqueThread = args->o.ClientId.UniqueThread;
|
|
ProcessInformation.ImageInformation.SubSystemType = args->o.SubSystemType;
|
|
|
|
} else {
|
|
Status = SmpExecuteImage( ImageFileName,
|
|
CurrentDirectory,
|
|
CommandLine,
|
|
SubsysMuSessionId,
|
|
Flags,
|
|
&ProcessInformation
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - SmpExecuteImage Failed with Status %lx\n",
|
|
Status));
|
|
|
|
goto cleanup2;
|
|
}
|
|
}
|
|
|
|
KnownSubSys->Process = ProcessInformation.Process;
|
|
KnownSubSys->InitialClientId = ProcessInformation.ClientId;
|
|
|
|
//
|
|
// 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(
|
|
MuSessionId,
|
|
ProcessInformation.ImageInformation.SubSystemType
|
|
);
|
|
if ( !TargetSubSys ) {
|
|
Status = STATUS_NO_SUCH_PACKAGE;
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed with Status %lx for sessionid %ld\n",
|
|
Status,
|
|
MuSessionId));
|
|
|
|
goto cleanup;
|
|
}
|
|
//
|
|
// 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 )) {
|
|
KdPrintEx((DPFLTR_SETUP_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with Status %lx for sessionid %ld\n",
|
|
Status,
|
|
MuSessionId));
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = NtDuplicateObject( NtCurrentProcess(),
|
|
ProcessInformation.Thread,
|
|
TargetSubSys->Process,
|
|
&args->ProcessInformation.Thread,
|
|
THREAD_ALL_ACCESS,
|
|
0,
|
|
0
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SETUP_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with Status %lx for sessionid %ld\n",
|
|
Status,
|
|
MuSessionId));
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
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);
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - NtRequestWaitReplyPort Failed with Status %lx for sessionid %ld\n",
|
|
Status,
|
|
MuSessionId));
|
|
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else {
|
|
if ( pWindowsSubSysProcessId ) {
|
|
|
|
if ( *pWindowsSubSysProcessId == (ULONG_PTR)NULL ) {
|
|
|
|
*pWindowsSubSysProcessId = (ULONG_PTR)
|
|
ProcessInformation.ClientId.UniqueProcess;
|
|
}
|
|
}
|
|
if ( !MuSessionId ) { // Only for console
|
|
SmpWindowsSubSysProcessId = (ULONG_PTR)
|
|
ProcessInformation.ClientId.UniqueProcess;
|
|
SmpWindowsSubSysProcess = ProcessInformation.Process;
|
|
}
|
|
}
|
|
|
|
ASSERTMSG( "NtCreateEvent", NT_SUCCESS( Status ) );
|
|
|
|
Status = NtResumeThread( ProcessInformation.Thread, NULL );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - NtResumeThread failed Status %lx\n",
|
|
Status));
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
if(MuSessionId != 0) {
|
|
|
|
//
|
|
// Wait a max of 60 seconds for the subsystem to connect.
|
|
//
|
|
|
|
Timeout = RtlEnlargedIntegerMultiply( 60000, -10000 );
|
|
Status = NtWaitForSingleObject( KnownSubSys->Active, FALSE, &Timeout );
|
|
if ( !SmpCheckDuplicateMuSessionId( MuSessionId ) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - session deleted\n"));
|
|
|
|
return( STATUS_DELETE_PENDING );
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpLoadSubSystem - Timeout waiting for subsystem connect with Status %lx for sessionid %ld \n",
|
|
Status,
|
|
MuSessionId));
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
} else {
|
|
|
|
NtWaitForSingleObject( KnownSubSys->Active, FALSE, NULL );
|
|
|
|
}
|
|
|
|
// Close this now since we never need it again
|
|
NtClose( ProcessInformation.Thread );
|
|
|
|
RtlEnterCriticalSection( &SmpKnownSubSysLock );
|
|
if (KnownSubSys) {
|
|
SmpDeferenceKnownSubSys(KnownSubSys);
|
|
}
|
|
if (TargetSubSys) {
|
|
SmpDeferenceKnownSubSys(TargetSubSys);
|
|
}
|
|
if (CreatorSubSys) {
|
|
SmpDeferenceKnownSubSys(CreatorSubSys);
|
|
}
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
if ((AttachedSessionId != (-1))
|
|
&& !(Flags & SMP_POSIX_FLAG)
|
|
&& !(Flags & SMP_OS2_FLAG)
|
|
&& NT_SUCCESS(AcquirePrivilegeStatus = SmpAcquirePrivilege( SE_LOAD_DRIVER_PRIVILEGE, &State ))) {
|
|
|
|
NTSTATUS St;
|
|
//
|
|
// If we are attached to a session space, leave it
|
|
// so we can create a new one
|
|
//
|
|
|
|
if (NT_SUCCESS(St = NtSetSystemInformation(
|
|
SystemSessionDetach,
|
|
(PVOID)&AttachedSessionId,
|
|
sizeof(MuSessionId)
|
|
))) {
|
|
|
|
AttachedSessionId = (-1);
|
|
|
|
} else {
|
|
|
|
//
|
|
// This has to succeed otherwise we will bugcheck while trying to
|
|
// create another session
|
|
//
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpStartCsr, Couldn't Detach from Session Space. Status=%x\n",
|
|
St));
|
|
|
|
ASSERT(NT_SUCCESS(St));
|
|
}
|
|
|
|
SmpReleasePrivilege( State );
|
|
}
|
|
else
|
|
{
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"SMSS: Did not detach from Session Space: SessionId=%x Flags=%x Status=%x\n",
|
|
AttachedSessionId,
|
|
Flags,
|
|
AcquirePrivilegeStatus));
|
|
}
|
|
|
|
|
|
// There is a lot of cleanup that must be done here
|
|
NtTerminateProcess( ProcessInformation.Process, Status );
|
|
NtClose( ProcessInformation.Thread );
|
|
|
|
cleanup2:
|
|
|
|
RtlEnterCriticalSection( &SmpKnownSubSysLock );
|
|
if (TargetSubSys) {
|
|
SmpDeferenceKnownSubSys(TargetSubSys);
|
|
}
|
|
if (CreatorSubSys) {
|
|
SmpDeferenceKnownSubSys(CreatorSubSys);
|
|
}
|
|
RemoveEntryList( &KnownSubSys->Links );
|
|
NtSetEvent( KnownSubSys->Active, NULL );
|
|
KnownSubSys->Deleting = TRUE;
|
|
SmpDeferenceKnownSubSys(KnownSubSys);
|
|
RtlLeaveCriticalSection( &SmpKnownSubSysLock );
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpExecuteInitialCommand(
|
|
IN ULONG MuSessionId,
|
|
IN PUNICODE_STRING InitialCommand,
|
|
OUT PHANDLE InitialCommandProcess,
|
|
OUT PULONG_PTR InitialCommandProcessId
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
RTL_USER_PROCESS_INFORMATION ProcessInformation;
|
|
ULONG Flags;
|
|
UNICODE_STRING ImageFileName;
|
|
UNICODE_STRING CurrentDirectory;
|
|
UNICODE_STRING Arguments;
|
|
static HANDLE SmApiPort = NULL;
|
|
|
|
if ( SmApiPort == NULL ) {
|
|
Status = SmConnectToSm( NULL,
|
|
NULL,
|
|
0,
|
|
&SmApiPort
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Initial command image (%wZ) not found\n",
|
|
&ImageFileName));
|
|
|
|
if (ImageFileName.Buffer)
|
|
RtlFreeHeap( RtlProcessHeap(), 0, ImageFileName.Buffer );
|
|
return( STATUS_OBJECT_NAME_NOT_FOUND );
|
|
}
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n",
|
|
InitialCommand,
|
|
Status));
|
|
|
|
return( Status );
|
|
}
|
|
|
|
Status = SmpExecuteImage( &ImageFileName,
|
|
&CurrentDirectory,
|
|
InitialCommand,
|
|
MuSessionId,
|
|
SMP_DONT_START,
|
|
&ProcessInformation
|
|
);
|
|
if (ImageFileName.Buffer) {
|
|
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 )) {
|
|
return( Status );
|
|
}
|
|
|
|
Status = NtDuplicateObject( NtCurrentProcess(),
|
|
ProcessInformation.Process,
|
|
NtCurrentProcess(),
|
|
InitialCommandProcess,
|
|
PROCESS_ALL_ACCESS,
|
|
0,
|
|
0
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: DupObject Failed. Status == %lx\n",
|
|
Status));
|
|
|
|
NtTerminateProcess( ProcessInformation.Process, Status );
|
|
NtResumeThread( ProcessInformation.Thread, NULL );
|
|
NtClose( ProcessInformation.Thread );
|
|
NtClose( ProcessInformation.Process );
|
|
return( Status );
|
|
}
|
|
|
|
if ( InitialCommandProcessId != NULL )
|
|
*InitialCommandProcessId =
|
|
(ULONG_PTR)ProcessInformation.ClientId.UniqueProcess;
|
|
if ( !MuSessionId )
|
|
SmpInitialCommandProcessId =
|
|
(ULONG_PTR)ProcessInformation.ClientId.UniqueProcess;
|
|
Status = SmExecPgm( SmApiPort,
|
|
&ProcessInformation,
|
|
FALSE
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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;
|
|
ULONG MuSessionId;
|
|
ULONG Flags;
|
|
|
|
args = &SmApiMsg->u.LoadDefered;
|
|
|
|
DeferedName.Length = (USHORT)args->SubsystemNameLength;
|
|
DeferedName.MaximumLength = (USHORT)args->SubsystemNameLength;
|
|
DeferedName.Buffer = args->SubsystemName;
|
|
|
|
Head = &SmpSubSystemsToDefer;
|
|
|
|
//
|
|
// Get the pointer to the client process's Terminal Server session.
|
|
//
|
|
|
|
SmpGetProcessMuSessionId( CallingClient->ClientProcessHandle, &MuSessionId );
|
|
if ( !SmpCheckDuplicateMuSessionId( MuSessionId ) ) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Defered subsystem load ( %wZ ) for MuSessionId %u, status=0x%x\n",
|
|
&DeferedName,
|
|
MuSessionId,
|
|
STATUS_OBJECT_NAME_NOT_FOUND));
|
|
|
|
return( STATUS_OBJECT_NAME_NOT_FOUND );
|
|
}
|
|
|
|
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...
|
|
//
|
|
// To keep from loading multiple subsystems, we must
|
|
// flag the type so we can see if its running.
|
|
// This is only a problem with "Optional" subsystems.
|
|
// Other optional subsystems can still be added, but
|
|
// they may have startup race conditions.
|
|
//
|
|
|
|
Flags = SMP_SUBSYSTEM_FLAG;
|
|
|
|
if ( RtlEqualUnicodeString(&DeferedName,&PosixName,TRUE)) {
|
|
Flags |= SMP_POSIX_FLAG;
|
|
}
|
|
|
|
if ( RtlEqualUnicodeString(&DeferedName,&Os2Name,TRUE)) {
|
|
Flags |= SMP_OS2_FLAG;
|
|
}
|
|
|
|
if (RegPosixSingleInstance &&
|
|
RtlEqualUnicodeString(&DeferedName,&PosixName,TRUE)) {
|
|
Flags |= SMP_POSIX_SI_FLAG;
|
|
}
|
|
|
|
Status = SmpExecuteCommand( &p->Value, MuSessionId, NULL, Flags );
|
|
|
|
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:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
#if SMP_SHOW_REGISTRY_DATA
|
|
SmpDumpQuery( L"SMSS", "BaseObjectsProtection", ValueName, ValueType, ValueData, ValueLength );
|
|
#else
|
|
UNREFERENCED_PARAMETER( ValueName );
|
|
UNREFERENCED_PARAMETER( ValueType );
|
|
#endif
|
|
|
|
|
|
|
|
if (ValueLength != sizeof(ULONG)) {
|
|
|
|
//
|
|
// Key value not valid. Run protected
|
|
//
|
|
|
|
SmpProtectionMode = SMP_STANDARD_PROTECTION;
|
|
|
|
} else {
|
|
|
|
|
|
SmpProtectionMode = (*((PULONG)(ValueData)));
|
|
|
|
//
|
|
// Change the security descriptors
|
|
//
|
|
|
|
}
|
|
(VOID)SmpCreateSecurityDescriptors( FALSE );
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SmpConfigureAllowProtectedRenames(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
{
|
|
if (ValueLength != sizeof(ULONG)) {
|
|
SmpAllowProtectedRenames = 0;
|
|
} else {
|
|
SmpAllowProtectedRenames = (*((PULONG)(ValueData)));
|
|
}
|
|
|
|
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: Restricted: 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: Restricted: 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: Restricted: Execute (No Inherit)
|
|
Grant: Admin: All Access (Inherit)
|
|
Grant: World: Execute | Read | Write (Inherit Only)
|
|
Grant: Restricted: 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,
|
|
RestrictedSid,
|
|
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),
|
|
RestrictedAccess = (GENERIC_EXECUTE | GENERIC_READ);
|
|
|
|
UCHAR
|
|
InheritOnlyFlags = (OBJECT_INHERIT_ACE |
|
|
CONTAINER_INHERIT_ACE |
|
|
INHERIT_ONLY_ACE);
|
|
|
|
ULONG
|
|
AceIndex,
|
|
AclLength;
|
|
|
|
PACL
|
|
Acl;
|
|
|
|
PACE_HEADER
|
|
Ace;
|
|
|
|
BOOLEAN
|
|
ProtectionRequired = FALSE;
|
|
|
|
|
|
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 )) {
|
|
|
|
Status = RtlAllocateAndInitializeSid(
|
|
&NtAuthority,
|
|
1,
|
|
SECURITY_RESTRICTED_CODE_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&RestrictedSid
|
|
);
|
|
|
|
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;
|
|
RestrictedAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_READ;
|
|
AdminAccess = GENERIC_ALL;
|
|
|
|
AclLength = sizeof( ACL ) +
|
|
3 * sizeof( ACCESS_ALLOWED_ACE ) +
|
|
(RtlLengthSid( WorldSid )) +
|
|
(RtlLengthSid( RestrictedSid )) +
|
|
(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
|
|
// Restricted
|
|
// Admin
|
|
//
|
|
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
|
|
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) );
|
|
}
|
|
|
|
//
|
|
// Build the KnownDlls security descriptor
|
|
//
|
|
|
|
|
|
AdminAccess = GENERIC_ALL;
|
|
|
|
AclLength = sizeof( ACL ) +
|
|
6 * sizeof( ACCESS_ALLOWED_ACE ) +
|
|
(2*RtlLengthSid( WorldSid )) +
|
|
(2*RtlLengthSid( RestrictedSid ))+
|
|
(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
|
|
// Restricted
|
|
// Admin
|
|
//
|
|
|
|
AceIndex = 0;
|
|
WorldAccess = GENERIC_EXECUTE;
|
|
RestrictedAccess = GENERIC_EXECUTE;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
|
|
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
|
|
// Restricted
|
|
// Admin
|
|
//
|
|
|
|
AceIndex++;
|
|
WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE;
|
|
RestrictedAccess = 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, RestrictedAccess, RestrictedSid );
|
|
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) );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// 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;
|
|
RestrictedAccess = GENERIC_EXECUTE | GENERIC_READ;
|
|
AdminAccess = GENERIC_ALL;
|
|
OwnerAccess = GENERIC_ALL;
|
|
|
|
AclLength = sizeof( ACL ) +
|
|
7 * sizeof( ACCESS_ALLOWED_ACE ) +
|
|
(2*RtlLengthSid( WorldSid )) +
|
|
(2*RtlLengthSid( RestrictedSid )) +
|
|
(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
|
|
// Restricted
|
|
// Admin
|
|
//
|
|
|
|
AceIndex = 0;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// Inheritable ACEs at end of ACE
|
|
// World
|
|
// Restricted
|
|
// 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, RestrictedAccess, RestrictedSid );
|
|
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;
|
|
RestrictedAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE;
|
|
|
|
AclLength = sizeof( ACL ) +
|
|
7 * sizeof( ACCESS_ALLOWED_ACE ) +
|
|
(2*RtlLengthSid( WorldSid )) +
|
|
(2*RtlLengthSid( RestrictedSid ))+
|
|
(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
|
|
// Restricted
|
|
// Admin
|
|
//
|
|
|
|
AceIndex = 0;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
|
|
AceIndex++;
|
|
Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
|
|
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
|
|
// Restricted
|
|
// 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, RestrictedAccess, RestrictedSid );
|
|
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) );
|
|
}
|
|
|
|
//
|
|
// No more security descriptors to build
|
|
//
|
|
}
|
|
RtlFreeHeap( RtlProcessHeap(), 0, RestrictedSid );
|
|
|
|
}
|
|
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)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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);
|
|
|
|
//
|
|
// The last part of the test below handles the remote boot case,
|
|
// where the system partition is on a redirected drive.
|
|
//
|
|
|
|
if (NT_SUCCESS(Status) &&
|
|
( RtlEqualUnicodeString(&SystemPartitionString, &LinkTarget, TRUE)
|
|
|| (RtlPrefixUnicodeString(&SystemPartitionString, &LinkTarget, TRUE)
|
|
&& (LinkTarget.Buffer[SystemPartitionString.Length / sizeof(WCHAR)] == L'\\')) )
|
|
) {
|
|
|
|
//
|
|
// We've found the drive letter corresponding to the system partition.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RestartScan = FALSE;
|
|
}
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if defined (_WIN64)
|
|
if (Status == STATUS_NO_MORE_ENTRIES) {
|
|
DirInfo->Name.Buffer = (PWCHAR)(DirInfo+1);
|
|
DirInfo->Name.Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0];
|
|
DirInfo->Name.Buffer[1] = USER_SHARED_DATA->NtSystemRoot[1];
|
|
} else {
|
|
#endif
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: can't find drive letter for system partition\n"));
|
|
return;
|
|
#if defined (_WIN64)
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// 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)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"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)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: couldn't write BootDir value: 0x%x\n",
|
|
Status));
|
|
}
|
|
|
|
NtClose(Key);
|
|
}
|
|
|
|
#if defined(REMOTE_BOOT)
|
|
NTSTATUS
|
|
SmpExecuteCommandLineArguments( VOID )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes any command line arguments that were passed to SMSS.exe.
|
|
Currently the only valid ones are netboot commands.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Success or not.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING CfgFileName;
|
|
UNICODE_STRING MbrName;
|
|
UNICODE_STRING AutoFmtCmd;
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
OBJECT_ATTRIBUTES KeyObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
HANDLE FileHandle;
|
|
HANDLE SourceHandle;
|
|
HANDLE TargetHandle;
|
|
NTSTATUS Status;
|
|
ULONG BootSerialNumber;
|
|
ULONG DiskSignature;
|
|
ULONG CmdFlags;
|
|
ULONG Length;
|
|
LARGE_INTEGER ByteOffset;
|
|
PUCHAR AlignedBuffer;
|
|
ON_DISK_MBR OnDiskMbr;
|
|
BOOLEAN WasEnabled;
|
|
HANDLE Key;
|
|
WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
|
|
ULONG ValueLength;
|
|
ULONG Repartition;
|
|
ULONG Disk;
|
|
ULONG Partition;
|
|
ULONG CSCPartition;
|
|
PWCHAR pWchar;
|
|
|
|
if (!SmpNetboot || SmpNetbootDisconnected) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Open the remoteboot.cfg file
|
|
//
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"\\SystemRoot");
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenSymbolicLinkObject(&FileHandle,
|
|
(ACCESS_MASK)SYMBOLIC_LINK_QUERY,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Could not open symbolic link (Status 0x%x) -- quitting.\n",
|
|
Status));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto CleanUp;
|
|
}
|
|
|
|
UnicodeString.Length = 0;
|
|
UnicodeString.MaximumLength = sizeof(TmpBuffer);
|
|
UnicodeString.Buffer = (PWCHAR)TmpBuffer;
|
|
Status = NtQuerySymbolicLinkObject(FileHandle,
|
|
&UnicodeString,
|
|
NULL
|
|
);
|
|
|
|
NtClose(FileHandle);
|
|
FileHandle = NULL;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Could not get symbolic link name (Status 0x%x) -- quitting.\n",
|
|
Status));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto CleanUp;
|
|
}
|
|
|
|
ASSERT(((wcslen((PWCHAR)TmpBuffer) * sizeof(WCHAR)) - sizeof(L"BootDrive")) <
|
|
(sizeof(wszRemoteBootCfgFile) - sizeof(REMOTE_BOOT_CFG_FILE))
|
|
);
|
|
|
|
wcscpy(wszRemoteBootCfgFile, (PWCHAR)TmpBuffer);
|
|
|
|
pWchar = wcsstr(wszRemoteBootCfgFile, L"BootDrive");
|
|
ASSERT(pWchar != NULL);
|
|
*pWchar = UNICODE_NULL;
|
|
|
|
wcscat(wszRemoteBootCfgFile, REMOTE_BOOT_CFG_FILE);
|
|
|
|
CfgFileName.Length = wcslen(wszRemoteBootCfgFile) * sizeof(WCHAR);
|
|
CfgFileName.MaximumLength = sizeof(wszRemoteBootCfgFile);
|
|
CfgFileName.Buffer = wszRemoteBootCfgFile;
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&CfgFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile( &FileHandle,
|
|
GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS
|
|
);
|
|
|
|
//
|
|
// If it does not exist, then set the flags for reformatting and repinning.
|
|
//
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Could not open file (status 0x%x) -- creating it.\n",
|
|
Status));
|
|
|
|
//
|
|
// Create the remoteboot.cfg in the system32\config directory if it does not exist.
|
|
//
|
|
|
|
CreateFile:
|
|
|
|
Status = NtCreateFile( &FileHandle,
|
|
GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_HIDDEN,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OVERWRITE_IF,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
//
|
|
// Something is really wrong, we will just exit and hope all is good.
|
|
// DEADISSUE, HISTORICAL CODE ONLY: This OK?
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Could not create file (Status 0x%x) -- quitting.\n",
|
|
Status));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto CleanUp;
|
|
}
|
|
|
|
SmpAutoFormat = TRUE;
|
|
BootSerialNumber = 1;
|
|
|
|
} else {
|
|
|
|
Status = NtReadFile( FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
&BootSerialNumber,
|
|
sizeof(ULONG),
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Could not read file (Status 0x%x) -- creating it.\n",
|
|
Status));
|
|
|
|
NtClose( FileHandle );
|
|
goto CreateFile;
|
|
}
|
|
|
|
BootSerialNumber++;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Process each command
|
|
//
|
|
if (SmpAutoFormat) {
|
|
|
|
//
|
|
// Read from the registry if it is ok to reformat, or just leave the disk alone.
|
|
//
|
|
Repartition = 1;
|
|
|
|
KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
RtlInitUnicodeString(&UnicodeString,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\RemoteBoot");
|
|
|
|
InitializeObjectAttributes(&KeyObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&Key, KEY_READ, &KeyObjectAttributes);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Query the key value.
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, L"Repartition");
|
|
Status = NtQueryValueKey(Key,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
(PVOID)KeyValueInfo,
|
|
VALUE_BUFFER_SIZE,
|
|
&ValueLength);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
ASSERT(ValueLength <= VALUE_BUFFER_SIZE);
|
|
Repartition = *((PULONG)KeyValueInfo->Data);
|
|
}
|
|
|
|
NtClose(Key);
|
|
}
|
|
|
|
SmpGetHarddiskBootPartition(&Disk, &Partition);
|
|
|
|
if (Repartition) {
|
|
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"SMSS: Autoformatting local disk.\n"));
|
|
|
|
NtClose(FileHandle);
|
|
|
|
//
|
|
// Repartition the disk.
|
|
//
|
|
SmpPartitionDisk(Disk, &Partition);
|
|
|
|
//
|
|
// Call autoformat on the partition
|
|
//
|
|
swprintf((PWSTR)TmpBuffer,
|
|
L"autoformat autofmt \\Device\\Harddisk%d\\Partition%d /Q /fs:ntfs",
|
|
Disk,
|
|
Partition
|
|
);
|
|
AutoFmtCmd.Buffer = (PWSTR)TmpBuffer;
|
|
AutoFmtCmd.MaximumLength = sizeof(TmpBuffer);
|
|
AutoFmtCmd.Length = wcslen((PWSTR)TmpBuffer) * sizeof(WCHAR);
|
|
CmdFlags = 0;
|
|
|
|
Status = SmpExecuteCommand(&AutoFmtCmd, 0, NULL, CmdFlags);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
//
|
|
// Big Trouble....
|
|
// CSC is disabled if we get here, so just keep on booting.
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
goto CleanUp;
|
|
}
|
|
|
|
} else {
|
|
|
|
SmpFindCSCPartition(Disk, &CSCPartition);
|
|
|
|
if (CSCPartition != 0) {
|
|
//
|
|
// Just blow away the CSC directory so we can refresh it
|
|
//
|
|
swprintf((PWSTR)TmpBuffer,
|
|
L"\\Device\\Harddisk%d\\Partition%d%ws",
|
|
Disk,
|
|
CSCPartition,
|
|
REMOTE_BOOT_IMIRROR_PATH_W REMOTE_BOOT_CSC_SUBDIR_W
|
|
);
|
|
|
|
SmpEnumFilesRecursive(
|
|
(PWSTR)TmpBuffer,
|
|
SmpDelEnumFile,
|
|
&Status,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
//
|
|
// Ignore this error, and hope that the next boot will fix. Just keep booting this
|
|
// time and hope.
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
goto CleanUp;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the NtLdr to the local disk
|
|
//
|
|
SourceHandle = SmpOpenDir( TRUE, TRUE, L"\\" );
|
|
if (SourceHandle == NULL) {
|
|
Status = STATUS_SUCCESS;
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
swprintf((PWSTR)TmpBuffer,
|
|
L"\\Device\\Harddisk%d\\Partition%d",
|
|
Disk,
|
|
Partition
|
|
);
|
|
|
|
RtlInitUnicodeString(&UnicodeString, (PWSTR)TmpBuffer);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
|
|
Status = NtCreateFile( &TargetHandle,
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to open a handle to the (%ws) directory - Status == %lx\n",
|
|
UnicodeString.Buffer,
|
|
Status));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
NtClose(SourceHandle);
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// If any of the copies fail, there is nothing we can really do.
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, L"ntldr");
|
|
Status = SmpCopyFile(SourceHandle, TargetHandle, &UnicodeString);
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"boot.ini");
|
|
Status = SmpCopyFile(SourceHandle, TargetHandle, &UnicodeString);
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"bootfont.bin");
|
|
Status = SmpCopyFile(SourceHandle, TargetHandle, &UnicodeString);
|
|
|
|
RtlInitUnicodeString(&UnicodeString, L"ntdetect.com");
|
|
Status = SmpCopyFile(SourceHandle, TargetHandle, &UnicodeString);
|
|
|
|
NtClose(SourceHandle);
|
|
NtClose(TargetHandle);
|
|
|
|
//
|
|
// Read Master Boot Record and get disk serial number.
|
|
//
|
|
|
|
swprintf((PWSTR)TmpBuffer,
|
|
L"\\Device\\Harddisk%d\\Partition0",
|
|
Disk
|
|
);
|
|
|
|
|
|
MbrName.Buffer = (PWSTR)TmpBuffer;
|
|
MbrName.MaximumLength = (wcslen((PWSTR)TmpBuffer) + 1) * sizeof(WCHAR);
|
|
MbrName.Length = MbrName.MaximumLength - sizeof(WCHAR);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&MbrName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtCreateFile( &FileHandle,
|
|
GENERIC_READ | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
//
|
|
// Something iswrong, but we are running w/o caching, so it should be ok.
|
|
//
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Could not create file (Status 0x%x).\n",
|
|
Status));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto CleanUp;
|
|
}
|
|
|
|
ASSERT(sizeof(ON_DISK_MBR) == 512);
|
|
AlignedBuffer = ALIGN(TmpBuffer, 512);
|
|
|
|
Status = NtReadFile( FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
AlignedBuffer,
|
|
sizeof(ON_DISK_MBR),
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
NtClose( FileHandle );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Could not read file (Status 0x%x) -- creating it.\n",
|
|
Status));
|
|
|
|
goto CreateFile;
|
|
}
|
|
|
|
RtlMoveMemory(&OnDiskMbr,AlignedBuffer,sizeof(ON_DISK_MBR));
|
|
|
|
ASSERT(U_USHORT(OnDiskMbr.AA55Signature) == 0xAA55);
|
|
|
|
DiskSignature = U_ULONG(OnDiskMbr.NTFTSignature);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&CfgFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile( &FileHandle,
|
|
GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
//
|
|
// Big Trouble....
|
|
// CSC is disabled if we get here, so just keep on booting.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
goto CleanUp;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Update the information
|
|
//
|
|
ByteOffset.LowPart = 0;
|
|
ByteOffset.HighPart = 0;
|
|
|
|
NtWriteFile( FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
&BootSerialNumber,
|
|
sizeof(ULONG),
|
|
&ByteOffset,
|
|
NULL
|
|
);
|
|
|
|
if (SmpAutoFormat) {
|
|
ByteOffset.LowPart = sizeof(ULONG);
|
|
|
|
NtWriteFile( FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
&DiskSignature,
|
|
sizeof(DiskSignature),
|
|
&ByteOffset,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
ByteOffset.LowPart = sizeof(ULONG) + sizeof(ULONG);
|
|
|
|
NtWriteFile( FileHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
SmpHalName,
|
|
sizeof(SmpHalName),
|
|
&ByteOffset,
|
|
NULL
|
|
);
|
|
|
|
NtClose(FileHandle);
|
|
|
|
if (SmpAutoFormat) {
|
|
|
|
//
|
|
// Reboot the machine to start CSC
|
|
//
|
|
Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
|
|
(BOOLEAN)TRUE,
|
|
TRUE,
|
|
&WasEnabled
|
|
);
|
|
|
|
if (Status == STATUS_NO_TOKEN) {
|
|
|
|
//
|
|
// No thread token, use the process token
|
|
//
|
|
|
|
Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
|
|
(BOOLEAN)TRUE,
|
|
FALSE,
|
|
&WasEnabled
|
|
);
|
|
}
|
|
NtShutdownSystem(ShutdownReboot);
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
CleanUp:
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
ENUMFILESRESULT
|
|
SmpEnumFilesRecursive (
|
|
IN PWSTR DirName,
|
|
IN ENUMFILESPROC EnumFilesProc,
|
|
OUT PULONG ReturnData,
|
|
IN PVOID p1 OPTIONAL
|
|
)
|
|
{
|
|
RECURSION_DATA RecursionData;
|
|
|
|
RecursionData.OptionalPtr = p1;
|
|
RecursionData.EnumProc = EnumFilesProc;
|
|
|
|
return SmpEnumFiles(
|
|
DirName,
|
|
SmppRecursiveEnumProc,
|
|
ReturnData,
|
|
&RecursionData
|
|
);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SmppRecursiveEnumProc (
|
|
IN PWSTR DirName,
|
|
IN PFILE_BOTH_DIR_INFORMATION FileInfo,
|
|
OUT PULONG ret,
|
|
IN PVOID Param
|
|
)
|
|
{
|
|
PWSTR FullPath;
|
|
PWSTR temp;
|
|
ULONG Len;
|
|
NTSTATUS Status;
|
|
ULONG ReturnData;
|
|
ENUMFILESRESULT EnumResult;
|
|
BOOLEAN b = FALSE;
|
|
PRECURSION_DATA RecursionData;
|
|
|
|
RecursionData = (PRECURSION_DATA) Param;
|
|
|
|
//
|
|
// Build the full file or dir path
|
|
//
|
|
|
|
temp = (PWSTR)(TmpBuffer + (sizeof(TmpBuffer)/2));
|
|
Len = FileInfo->FileNameLength/sizeof(WCHAR);
|
|
|
|
wcsncpy(temp, FileInfo->FileName, Len);
|
|
temp[Len] = 0;
|
|
|
|
wcscpy((PWSTR)TmpBuffer, DirName);
|
|
SmpConcatenatePaths((PWSTR)TmpBuffer, temp);
|
|
|
|
|
|
//
|
|
// For directories, recurse
|
|
//
|
|
if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
if( (wcscmp( temp, L"." ) == 0) ||
|
|
(wcscmp( temp, L".." ) == 0) ) {
|
|
//
|
|
// Skip past . and .. directories
|
|
//
|
|
b = TRUE;
|
|
|
|
} else {
|
|
//
|
|
// Recurse through subdirectory
|
|
//
|
|
|
|
FullPath = RtlAllocateHeap(RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
(wcslen((PWSTR)TmpBuffer)+1) * sizeof(WCHAR)
|
|
);
|
|
if (FullPath == NULL) {
|
|
*ret = EnumFileError;
|
|
return FALSE;
|
|
}
|
|
|
|
wcscpy(FullPath, (PWSTR)TmpBuffer);
|
|
|
|
EnumResult = SmpEnumFilesRecursive (
|
|
FullPath,
|
|
RecursionData->EnumProc,
|
|
&ReturnData,
|
|
RecursionData->OptionalPtr
|
|
);
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, FullPath );
|
|
|
|
if (EnumResult != NormalReturn) {
|
|
*ret = EnumResult;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call normal enum proc for file or dir (except . or .. dirs)
|
|
//
|
|
|
|
if (!b) {
|
|
b = RecursionData->EnumProc (
|
|
DirName,
|
|
FileInfo,
|
|
ret,
|
|
RecursionData->OptionalPtr
|
|
);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
SmpConcatenatePaths(
|
|
IN OUT LPWSTR Path1,
|
|
IN LPCWSTR Path2
|
|
)
|
|
{
|
|
BOOLEAN NeedBackslash = TRUE;
|
|
ULONG l = wcslen(Path1);
|
|
|
|
//
|
|
// Determine whether we need to stick a backslash
|
|
// between the components.
|
|
//
|
|
if(l && (Path1[l-1] == L'\\')) {
|
|
|
|
NeedBackslash = FALSE;
|
|
}
|
|
|
|
if(*Path2 == L'\\') {
|
|
|
|
if(NeedBackslash) {
|
|
NeedBackslash = FALSE;
|
|
} else {
|
|
//
|
|
// Not only do we not need a backslash, but we
|
|
// need to eliminate one before concatenating.
|
|
//
|
|
Path2++;
|
|
}
|
|
}
|
|
|
|
if(NeedBackslash) {
|
|
wcscat(Path1,L"\\");
|
|
}
|
|
wcscat(Path1,Path2);
|
|
}
|
|
|
|
BOOLEAN
|
|
SmpDelEnumFile(
|
|
IN PWSTR DirName,
|
|
IN PFILE_BOTH_DIR_INFORMATION FileInfo,
|
|
OUT PULONG ret,
|
|
IN PVOID Pointer
|
|
)
|
|
{
|
|
PWSTR FileName;
|
|
PWSTR p;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
//
|
|
// Ignore subdirectories
|
|
//
|
|
if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
return TRUE; // continue processing
|
|
}
|
|
|
|
//
|
|
// We have to make a copy of the filename, because the info struct
|
|
// we get isn't NULL-terminated.
|
|
//
|
|
FileName = RtlAllocateHeap(RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
FileInfo->FileNameLength + sizeof(WCHAR)
|
|
);
|
|
if (FileName == NULL) {
|
|
*ret = EnumFileError;
|
|
return TRUE;
|
|
}
|
|
|
|
wcsncpy(FileName, FileInfo->FileName, FileInfo->FileNameLength);
|
|
|
|
FileName[FileInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
//
|
|
// Point to temporary buffer for pathname.
|
|
//
|
|
p = (PWSTR)TmpBuffer;
|
|
|
|
//
|
|
// Build up the full name of the file to delete.
|
|
//
|
|
wcscpy(p,DirName);
|
|
SmpConcatenatePaths(p,FileName);
|
|
|
|
//
|
|
// Prepare to open the file.
|
|
//
|
|
RtlInitUnicodeString(&UnicodeString, p);
|
|
|
|
//
|
|
// Ignore return status of delete
|
|
//
|
|
SmpDeleteFile(&UnicodeString);
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, FileName );
|
|
|
|
return TRUE; // continue processing
|
|
}
|
|
|
|
ENUMFILESRESULT
|
|
SmpEnumFiles(
|
|
IN PWSTR DirName,
|
|
IN ENUMFILESPROC EnumFilesProc,
|
|
OUT PULONG ReturnData,
|
|
IN PVOID p1 OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes every file (and subdirectory) in the directory
|
|
specified by 'DirName'. Each entry is sent to the callback function
|
|
'EnumFilesProc' for processing. If the callback returns TRUE, processing
|
|
continues, otherwise processing terminates.
|
|
|
|
Arguments:
|
|
|
|
DirName - Supplies the directory name containing the files/subdirectories
|
|
to be processed.
|
|
|
|
EnumFilesProc - Callback function to be called for each file/subdirectory.
|
|
The function must have the following prototype:
|
|
|
|
BOOLEAN EnumFilesProc(
|
|
IN PWSTR,
|
|
IN PFILE_BOTH_DIR_INFORMATION,
|
|
OUT PULONG
|
|
);
|
|
|
|
ReturnData - Pointer to the returned data. The contents stored here
|
|
depend on the reason for termination (See below).
|
|
|
|
p1 - Optional pointer, to be passed to the callback function.
|
|
|
|
Return Value:
|
|
|
|
This function can return one of three values. The data stored in
|
|
'ReturnData' depends upon which value is returned:
|
|
|
|
NormalReturn - if the whole process completes uninterrupted
|
|
(ReturnData is not used)
|
|
EnumFileError - if an error occurs while enumerating files
|
|
(ReturnData contains the error code)
|
|
CallbackReturn - if the callback returns FALSE, causing termination
|
|
(ReturnData contains data defined by the callback)
|
|
|
|
--*/
|
|
{
|
|
HANDLE hFindFile;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING PathName;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
|
|
BOOLEAN bStartScan;
|
|
ENUMFILESRESULT ret;
|
|
|
|
//
|
|
// Prepare to open the directory
|
|
//
|
|
RtlInitUnicodeString(&PathName, DirName);
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
&PathName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
|
|
//
|
|
// Open the specified directory for list access
|
|
//
|
|
Status = NtOpenFile(
|
|
&hFindFile,
|
|
FILE_LIST_DIRECTORY | SYNCHRONIZE,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to open directory %ws for list (%lx)\n",
|
|
DirName,
|
|
Status));
|
|
|
|
*ReturnData = Status;
|
|
return EnumFileError;
|
|
}
|
|
|
|
|
|
DirectoryInfo = RtlAllocateHeap(RtlProcessHeap(),
|
|
MAKE_TAG( INIT_TAG ),
|
|
DOS_MAX_PATH_LENGTH * 2 + sizeof(FILE_BOTH_DIR_INFORMATION)
|
|
);
|
|
if(!DirectoryInfo) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to allocate memory for SpEnumFiles()\n"));
|
|
|
|
*ReturnData = STATUS_INSUFFICIENT_RESOURCES;
|
|
return EnumFileError;
|
|
}
|
|
|
|
bStartScan = TRUE;
|
|
while(TRUE) {
|
|
Status = NtQueryDirectoryFile(
|
|
hFindFile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
DirectoryInfo,
|
|
(DOS_MAX_PATH_LENGTH * 2 + sizeof(FILE_BOTH_DIR_INFORMATION)),
|
|
FileBothDirectoryInformation,
|
|
TRUE,
|
|
NULL,
|
|
bStartScan
|
|
);
|
|
|
|
if(Status == STATUS_NO_MORE_FILES) {
|
|
|
|
ret = NormalReturn;
|
|
break;
|
|
|
|
} else if(!NT_SUCCESS(Status)) {
|
|
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to query directory %ws (%lx)\n",
|
|
DirName,
|
|
Status));
|
|
|
|
*ReturnData = Status;
|
|
ret = EnumFileError;
|
|
break;
|
|
}
|
|
|
|
if(bStartScan) {
|
|
bStartScan = FALSE;
|
|
}
|
|
|
|
//
|
|
// Now pass this entry off to our callback function for processing
|
|
//
|
|
if(!EnumFilesProc(DirName, DirectoryInfo, ReturnData, p1)) {
|
|
|
|
ret = CallbackReturn;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RtlFreeHeap( RtlProcessHeap(), 0, DirectoryInfo );
|
|
NtClose(hFindFile);
|
|
return ret;
|
|
}
|
|
|
|
#endif // defined(REMOTE_BOOT)
|
|
|
|
|
|
NTSTATUS
|
|
SmpDeleteFile(
|
|
IN PUNICODE_STRING pFile
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE Handle;
|
|
FILE_DISPOSITION_INFORMATION Disposition;
|
|
FILE_BASIC_INFORMATION BasicInfo;
|
|
|
|
InitializeObjectAttributes(
|
|
&Obja,
|
|
pFile,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
|
|
//
|
|
// Attempt to open the file.
|
|
//
|
|
Status = NtOpenFile(
|
|
&Handle,
|
|
(ACCESS_MASK)(DELETE | FILE_WRITE_ATTRIBUTES),
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE ,
|
|
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to open %ws for delete (%lx)\n",
|
|
pFile->Buffer,
|
|
Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Change the file attribute to normal
|
|
//
|
|
|
|
RtlZeroMemory( &BasicInfo, sizeof( FILE_BASIC_INFORMATION ) );
|
|
BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
Status = NtSetInformationFile(Handle,
|
|
&IoStatusBlock,
|
|
&BasicInfo,
|
|
sizeof(BasicInfo),
|
|
FileBasicInformation
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SMSS_ID,
|
|
DPFLTR_WARNING_LEVEL,
|
|
"SMSS: Unable to change attribute of %ls. Status = (%lx)\n",
|
|
pFile->Buffer,
|
|
Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Set up for delete and call worker to do it.
|
|
//
|
|
#undef DeleteFile
|
|
Disposition.DeleteFile = TRUE;
|
|
|
|
Status = NtSetInformationFile(Handle,
|
|
&IoStatusBlock,
|
|
&Disposition,
|
|
sizeof(Disposition),
|
|
FileDispositionInformation
|
|
);
|
|
|
|
//
|
|
// Clean up and return.
|
|
//
|
|
NtClose(Handle);
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SmpCallCsrCreateProcess(
|
|
IN OUT PSBAPIMSG m,
|
|
IN size_t ArgLength,
|
|
IN HANDLE CommunicationPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sends a message to CSR telling to start a process
|
|
|
|
Arguments:
|
|
|
|
m - message to send
|
|
ArgLength - length of argument struct inside message
|
|
CommunicationPort - LPC port to send to
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
m->h.u1.s1.DataLength = ArgLength + 8;
|
|
m->h.u1.s1.TotalLength = sizeof(SBAPIMSG);
|
|
m->h.u2.ZeroInit = 0L;
|
|
|
|
m->ApiNumber = SbCreateProcessApi;
|
|
|
|
Status = NtRequestWaitReplyPort(CommunicationPort,
|
|
(PPORT_MESSAGE) m,
|
|
(PPORT_MESSAGE) m
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
Status = m->ReturnedStatus;
|
|
}
|
|
|
|
return Status;
|
|
}
|