2003-08-11 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / subsys / smss / init.c
index 64e2d5f..c8d1eaa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.20 2000/12/05 18:14:07 ekohl Exp $
+/* $Id: init.c,v 1.50 2003/08/11 18:50:12 chorns Exp $
  *
  * init.c - Session Manager initialization
  * 
  *     19990530 (Emanuele Aliberti)
  *             Compiled successfully with egcs 1.1.2
  */
+
+/* INCLUDES *****************************************************************/
+
 #include <ntos.h>
 #include <ntdll/rtl.h>
+#include <ntdll/ldr.h>
 #include <napi/lpc.h>
-#include <napi/shared_data.h>
 
 #include "smss.h"
 
 #define NDEBUG
+#include <debug.h>
 
-/* GLOBAL VARIABLES *********************************************************/
+/* GLOBALS ******************************************************************/
 
-HANDLE SmApiPort = INVALID_HANDLE_VALUE;
 HANDLE DbgSsApiPort = INVALID_HANDLE_VALUE;
 HANDLE DbgUiApiPort = INVALID_HANDLE_VALUE;
 
-PVOID SmSystemEnvironment = NULL;
+PWSTR SmSystemEnvironment = NULL;
 
 
 /* FUNCTIONS ****************************************************************/
 
-#if 0
-static VOID
-SmCreatePagingFiles (VOID)
+static NTSTATUS STDCALL
+SmObjectDirectoryQueryRoutine(PWSTR ValueName,
+                             ULONG ValueType,
+                             PVOID ValueData,
+                             ULONG ValueLength,
+                             PVOID Context,
+                             PVOID EntryContext)
 {
-       UNICODE_STRING FileName;
-       ULONG ulCurrentSize;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING UnicodeString;
+  HANDLE WindowsDirectory;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+#ifndef NDEBUG
+  DbgPrint("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
+  DbgPrint("ValueData '%S'\n", (PWSTR)ValueData);
+#endif
+  if (ValueType != REG_SZ)
+    {
+      return(STATUS_SUCCESS);
+    }
+
+  RtlInitUnicodeString(&UnicodeString,
+                      (PWSTR)ValueData);
 
-       /* FIXME: Read file names from registry */
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &UnicodeString,
+                            0,
+                            NULL,
+                            NULL);
 
-       RtlInitUnicodeString (&FileName,
-                             L"\\SystemRoot\\pagefile.sys");
+  Status = ZwCreateDirectoryObject(&WindowsDirectory,
+                                  0,
+                                  &ObjectAttributes);
 
-       NtCreatePagingFile (&FileName,
-                           50,
-                           80,
-                           &ulCurrentSize);
+  return(Status);
 }
-#endif
 
 
-static VOID
-SmSetEnvironmentVariables (VOID)
+static NTSTATUS
+SmCreateObjectDirectories(VOID)
 {
-       UNICODE_STRING EnvVariable;
-       UNICODE_STRING EnvValue;
-       UNICODE_STRING EnvExpandedValue;
-       ULONG ExpandedLength;
-       WCHAR ExpandBuffer[512];
-       WCHAR ValueBuffer[MAX_PATH];
-       PKUSER_SHARED_DATA SharedUserData = 
-               (PKUSER_SHARED_DATA)USER_SHARED_DATA_BASE;
-
-       /*
-        * The following environment variables are read from the registry.
-        * Because the registry does not work yet, the environment variables
-        * are set one by one, using information from the shared user page.
-        *
-        * Variables (example):
-        *    SystemRoot = C:\reactos
-        *    SystemDrive = C:
-        *
-        *    OS = ReactOS
-        *    Path = %SystemRoot%\system32;%SystemRoot%
-        *    windir = %SystemRoot%
-        */
-
-       /* copy system root into value buffer */
-       wcscpy (ValueBuffer, SharedUserData->NtSystemRoot);
-
-       /* set "SystemRoot = C:\reactos" */
-       RtlInitUnicodeString (&EnvVariable,
-                             L"SystemRoot");
-       RtlInitUnicodeString (&EnvValue,
-                             ValueBuffer);
-       RtlSetEnvironmentVariable (&SmSystemEnvironment,
-                                  &EnvVariable,
-                                  &EnvValue);
-
-       /* cut off trailing path */
-       ValueBuffer[2] = 0;
-
-       /* Set "SystemDrive = C:" */
-       RtlInitUnicodeString (&EnvVariable,
-                             L"SystemDrive");
-       RtlSetEnvironmentVariable (&SmSystemEnvironment,
-                                  &EnvVariable,
-                                  &EnvValue);
-
-
-       /* Set "OS = ReactOS" */
-       RtlInitUnicodeString (&EnvVariable,
-                             L"OS");
-       RtlInitUnicodeString (&EnvValue,
-                             L"ReactOS");
-       RtlSetEnvironmentVariable (&SmSystemEnvironment,
-                                  &EnvVariable,
-                                  &EnvValue);
-
-
-       /* Set "Path = %SystemRoot%\system32;%SystemRoot%" */
-       RtlInitUnicodeString (&EnvVariable,
-                             L"Path");
-       RtlInitUnicodeString (&EnvValue,
-                             L"%SystemRoot%\\system32;%SystemRoot%");
-       EnvExpandedValue.Length = 0;
-       EnvExpandedValue.MaximumLength = 512 * sizeof(WCHAR);
-       EnvExpandedValue.Buffer = ExpandBuffer;
-       *ExpandBuffer = 0;
-       RtlExpandEnvironmentStrings_U (SmSystemEnvironment,
-                                      &EnvValue,
-                                      &EnvExpandedValue,
-                                      &ExpandedLength);
-       RtlSetEnvironmentVariable (&SmSystemEnvironment,
-                                  &EnvVariable,
-                                  &EnvExpandedValue);
-
-       /* Set "windir = %SystemRoot%" */
-       RtlInitUnicodeString (&EnvVariable,
-                             L"windir");
-       RtlInitUnicodeString (&EnvValue,
-                             L"%SystemRoot%");
-       EnvExpandedValue.Length = 0;
-       EnvExpandedValue.MaximumLength = 512 * sizeof(WCHAR);
-       EnvExpandedValue.Buffer = ExpandBuffer;
-       *ExpandBuffer = 0;
-       RtlExpandEnvironmentStrings_U (SmSystemEnvironment,
-                                      &EnvValue,
-                                      &EnvExpandedValue,
-                                      &ExpandedLength);
-       RtlSetEnvironmentVariable (&SmSystemEnvironment,
-                                  &EnvVariable,
-                                  &EnvExpandedValue);
+  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+  NTSTATUS Status;
+
+  RtlZeroMemory(&QueryTable,
+               sizeof(QueryTable));
+
+  QueryTable[0].Name = L"ObjectDirectories";
+  QueryTable[0].QueryRoutine = SmObjectDirectoryQueryRoutine;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                 L"\\Session Manager",
+                                 QueryTable,
+                                 NULL,
+                                 NULL);
+
+  return(Status);
 }
 
 
-BOOL InitSessionManager (HANDLE        Children[])
+static NTSTATUS STDCALL
+SmDosDevicesQueryRoutine(PWSTR ValueName,
+                        ULONG ValueType,
+                        PVOID ValueData,
+                        ULONG ValueLength,
+                        PVOID Context,
+                        PVOID EntryContext)
 {
-   NTSTATUS Status;
-   UNICODE_STRING UnicodeString;
-   OBJECT_ATTRIBUTES ObjectAttributes;
-   UNICODE_STRING CmdLineW;
-   PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
-   RTL_USER_PROCESS_INFO ProcessInfo;
-   HANDLE CsrssInitEvent;
-
-   WCHAR UnicodeBuffer[MAX_PATH];
-   PKUSER_SHARED_DATA SharedUserData = 
-       (PKUSER_SHARED_DATA)USER_SHARED_DATA_BASE;
-   
-   /* Create the "\SmApiPort" object (LPC) */
-   RtlInitUnicodeString (&UnicodeString,
-                        L"\\SmApiPort");
-   InitializeObjectAttributes (&ObjectAttributes,
-                              &UnicodeString,
-                              0xff,
-                              NULL,
-                              NULL);
-   
-   Status = NtCreatePort (&SmApiPort,
-                         &ObjectAttributes,
-                         0,
-                         0,
-                         0);
-
-   if (!NT_SUCCESS(Status))
-     {
-       return FALSE;
-     }
-   
-#ifndef NDEBUG
-   DisplayString (L"SM: \\SmApiPort created...\n");
-#endif
-   
-   /* Create two threads for "\SmApiPort" */
-   RtlCreateUserThread (NtCurrentProcess (),
-                       NULL,
-                       FALSE,
-                       0,
-                       NULL,
-                       NULL,
-                       (PTHREAD_START_ROUTINE)SmApiThread,
-                       (PVOID)SmApiPort,
-                       NULL,
-                       NULL);
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING DeviceName;
+  UNICODE_STRING LinkName;
+  HANDLE LinkHandle;
+  WCHAR LinkBuffer[80];
+  NTSTATUS Status;
+
+  DPRINT("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
+  DPRINT("ValueData '%S'\n", (PWSTR)ValueData);
+
+  if (ValueType != REG_SZ)
+    {
+      return(STATUS_SUCCESS);
+    }
 
-   RtlCreateUserThread (NtCurrentProcess (),
-                       NULL,
+  swprintf(LinkBuffer,
+          L"\\??\\%s",
+          ValueName);
+  RtlInitUnicodeString(&LinkName,
+                      LinkBuffer);
+  RtlInitUnicodeString(&DeviceName,
+                      (PWSTR)ValueData);
+
+  DPRINT("SM: Linking %wZ --> %wZ\n",
+             &LinkName,
+             &DeviceName);
+
+  /* create symbolic link */
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &LinkName,
+                            OBJ_PERMANENT,
+                            NULL,
+                            NULL);
+  Status = NtCreateSymbolicLinkObject(&LinkHandle,
+                                     SYMBOLIC_LINK_ALL_ACCESS,
+                                     &ObjectAttributes,
+                                     &DeviceName);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SmDosDevicesQueryRoutine: NtCreateSymbolicLink( %wZ --> %wZ ) failed!\n",
+                 &LinkName,
+                 &DeviceName);
+    }
+  NtClose(LinkHandle);
+
+  return(Status);
+}
+
+
+static NTSTATUS
+SmInitDosDevices(VOID)
+{
+  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+  NTSTATUS Status;
+
+  RtlZeroMemory(&QueryTable,
+               sizeof(QueryTable));
+
+  QueryTable[0].QueryRoutine = SmDosDevicesQueryRoutine;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                 L"\\Session Manager\\DOS Devices",
+                                 QueryTable,
+                                 NULL,
+                                 NULL);
+  return(Status);
+}
+
+
+static NTSTATUS STDCALL
+SmRunBootAppsQueryRoutine(PWSTR ValueName,
+                         ULONG ValueType,
+                         PVOID ValueData,
+                         ULONG ValueLength,
+                         PVOID Context,
+                         PVOID EntryContext)
+{
+  PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+  RTL_PROCESS_INFO ProcessInfo;
+  UNICODE_STRING ImagePathString;
+  UNICODE_STRING CommandLineString;
+  WCHAR Description[256];
+  WCHAR ImageName[256];
+  WCHAR ImagePath[256];
+  WCHAR CommandLine[256];
+  PWSTR p1, p2;
+  ULONG len;
+  NTSTATUS Status;
+
+  DPRINT("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
+  DPRINT("ValueData '%S'\n", (PWSTR)ValueData);
+
+  if (ValueType != REG_SZ)
+    {
+      return(STATUS_SUCCESS);
+    }
+
+  /* Extract the description */
+  p1 = wcschr((PWSTR)ValueData, L' ');
+  len = p1 - (PWSTR)ValueData;
+  memcpy(Description,ValueData, len * sizeof(WCHAR));
+  Description[len] = 0;
+
+  /* Extract the image name */
+  p1++;
+  p2 = wcschr(p1, L' ');
+  if (p2 != NULL)
+    len = p2 - p1;
+  else
+    len = wcslen(p1);
+  memcpy(ImageName, p1, len * sizeof(WCHAR));
+  ImageName[len] = 0;
+
+  /* Extract the command line */
+  if (p2 == NULL)
+    {
+      CommandLine[0] = 0;
+    }
+  else
+    {
+      p2++;
+      wcscpy(CommandLine, p2);
+    }
+
+  DPRINT("Running %S...\n", Description);
+  DPRINT("ImageName: '%S'\n", ImageName);
+  DPRINT("CommandLine: '%S'\n", CommandLine);
+
+  /* initialize executable path */
+  wcscpy(ImagePath, L"\\SystemRoot\\system32\\");
+  wcscat(ImagePath, ImageName);
+  wcscat(ImagePath, L".exe");
+
+  RtlInitUnicodeString(&ImagePathString,
+                      ImagePath);
+
+  RtlInitUnicodeString(&CommandLineString,
+                      CommandLine);
+
+  RtlCreateProcessParameters(&ProcessParameters,
+                            &ImagePathString,
+                            NULL,
+                            NULL,
+                            &CommandLineString,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL);
+
+  Status = RtlCreateUserProcess(&ImagePathString,
+                               OBJ_CASE_INSENSITIVE,
+                               ProcessParameters,
+                               NULL,
+                               NULL,
+                               NULL,
+                               FALSE,
+                               NULL,
+                               NULL,
+                               &ProcessInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Running %s failed (Status %lx)\n", Description, Status);
+      return(STATUS_SUCCESS);
+    }
+
+  RtlDestroyProcessParameters(ProcessParameters);
+
+  /* Wait for process termination */
+  NtWaitForSingleObject(ProcessInfo.ProcessHandle,
                        FALSE,
-                       0,
-                       NULL,
-                       NULL,
-                       (PTHREAD_START_ROUTINE)SmApiThread,
-                       (PVOID)SmApiPort,
-                       NULL,
                        NULL);
-   
-   /* Create the system environment */
-   Status = RtlCreateEnvironment (TRUE,
-                                 &SmSystemEnvironment);
-   if (!NT_SUCCESS(Status))
-     return FALSE;
-#ifndef NDEBUG
-   DisplayString (L"SM: System Environment created\n");
-#endif
 
-   /* FIXME: Define symbolic links to kernel devices (MS-DOS names) */
-   
-   /* FIXME: Run all programs in the boot execution list */
-   
-   /* FIXME: Process the file rename list */
-   
-   /* FIXME: Load the well known DLLs */
-   
-#if 0
-   /* Create paging files */
-   SmCreatePagingFiles ();
-#endif
-   
-   /* Load remaining registry hives */
-   NtInitializeRegistry (FALSE);
-   
-   /* Set environment variables from registry */
-   SmSetEnvironmentVariables ();
-
-   /* Load the kernel mode driver win32k.sys */
-   RtlInitUnicodeString (&CmdLineW,
-                        L"\\SystemRoot\\system32\\drivers\\win32k.sys");
-   Status = NtLoadDriver (&CmdLineW);
-   
-   if (!NT_SUCCESS(Status))
-     {
-       return FALSE;
-     }
-   
-   /* Run csrss.exe */
-   RtlInitUnicodeString(&UnicodeString,
-                       L"\\CsrssInitDone");
-   InitializeObjectAttributes(&ObjectAttributes,
-                             &UnicodeString,
-                             EVENT_ALL_ACCESS,
-                             0,
-                             NULL);
-   Status = NtCreateEvent(&CsrssInitEvent,
-                         EVENT_ALL_ACCESS,
-                         &ObjectAttributes,
-                         TRUE,
-                         FALSE);
-   if (!NT_SUCCESS(Status))
-     {
-       DbgPrint("Failed to create csrss notification event\n");
-     }
-   
-   /*
-    * Start the Win32 subsystem (csrss.exe)
-    */
-   DisplayString (L"SM: Running csrss.exe\n");
-   
-   /* initialize executable path */
-   wcscpy(UnicodeBuffer, L"\\??\\");
-   wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
-   wcscat(UnicodeBuffer, L"\\system32\\csrss.exe");
-   RtlInitUnicodeString (&UnicodeString,
-                        UnicodeBuffer);
-   
-   RtlCreateProcessParameters (&ProcessParameters,
-                              &UnicodeString,
-                              NULL,
-                              NULL,
-                              NULL,
-                              SmSystemEnvironment,
-                              NULL,
-                              NULL,
-                              NULL,
-                              NULL);
-
-   Status = RtlCreateUserProcess (&UnicodeString,
-                                 0,
-                                 ProcessParameters,
+  NtClose(ProcessInfo.ThreadHandle);
+  NtClose(ProcessInfo.ProcessHandle);
+
+  return(STATUS_SUCCESS);
+}
+
+
+/*
+ * Run native applications listed in the registry.
+ *
+ *  Key:
+ *    \Registry\Machine\SYSTEM\CurrentControlSet\Control\Session Manager
+ *
+ *  Value (format: "<description> <executable> <command line>":
+ *    BootExecute = "autocheck autochk *"
+ */
+static NTSTATUS
+SmRunBootApps(VOID)
+{
+  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+  NTSTATUS Status;
+
+  RtlZeroMemory(&QueryTable,
+               sizeof(QueryTable));
+
+  QueryTable[0].Name = L"BootExecute";
+  QueryTable[0].QueryRoutine = SmRunBootAppsQueryRoutine;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                 L"\\Session Manager",
+                                 QueryTable,
                                  NULL,
+                                 NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SmRunBootApps: RtlQueryRegistryValues() failed! (Status %lx)\n", Status);
+    }
+
+  return(Status);
+}
+
+
+static NTSTATUS
+SmProcessFileRenameList(VOID)
+{
+  DPRINT("SmProcessFileRenameList() called\n");
+
+  /* FIXME: implement it! */
+
+  DPRINT("SmProcessFileRenameList() done\n");
+
+  return(STATUS_SUCCESS);
+}
+
+
+static NTSTATUS STDCALL
+SmKnownDllsQueryRoutine(PWSTR ValueName,
+                       ULONG ValueType,
+                       PVOID ValueData,
+                       ULONG ValueLength,
+                       PVOID Context,
+                       PVOID EntryContext)
+{
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  IO_STATUS_BLOCK IoStatusBlock;
+  UNICODE_STRING ImageName;
+  HANDLE FileHandle;
+  HANDLE SectionHandle;
+  NTSTATUS Status;
+
+  DPRINT("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
+  DPRINT("ValueData '%S'  Context %p  EntryContext %p\n", (PWSTR)ValueData, Context, EntryContext);
+
+  /* Ignore the 'DllDirectory' value */
+  if (!_wcsicmp(ValueName, L"DllDirectory"))
+    return STATUS_SUCCESS;
+
+  /* Open the DLL image file */
+  RtlInitUnicodeString(&ImageName,
+                      ValueData);
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &ImageName,
+                            OBJ_CASE_INSENSITIVE,
+                            (HANDLE)Context,
+                            NULL);
+  Status = NtOpenFile(&FileHandle,
+                     SYNCHRONIZE | FILE_EXECUTE,
+                     &ObjectAttributes,
+                     &IoStatusBlock,
+                     FILE_SHARE_READ,
+                     FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
+      return STATUS_SUCCESS;
+    }
+
+  DPRINT("Opened file %wZ successfully\n", &ImageName);
+
+  /* Check for valid image checksum */
+  Status = LdrVerifyImageMatchesChecksum (FileHandle,
+                                         0,
+                                         0,
+                                         0);
+  if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH)
+    {
+      /* Raise a hard error (crash the system/BSOD) */
+      NtRaiseHardError (Status,
+                       0,
+                       0,
+                       0,
+                       0,
+                       0);
+    }
+  else if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to check the image checksum\n");
+
+      NtClose(SectionHandle);
+      NtClose(FileHandle);
+
+      return STATUS_SUCCESS;
+    }
+
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &ImageName,
+                            OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+                            (HANDLE)EntryContext,
+                            NULL);
+  Status = NtCreateSection(&SectionHandle,
+                          SECTION_ALL_ACCESS,
+                          &ObjectAttributes,
+                          NULL,
+                          PAGE_EXECUTE,
+                          SEC_IMAGE,
+                          FileHandle);
+  if (NT_SUCCESS(Status))
+    {
+      DPRINT("Created section successfully\n");
+      NtClose(SectionHandle);
+    }
+
+  NtClose(FileHandle);
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+SmLoadKnownDlls(VOID)
+{
+  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  IO_STATUS_BLOCK IoStatusBlock;
+  UNICODE_STRING DllDosPath;
+  UNICODE_STRING DllNtPath;
+  UNICODE_STRING Name;
+  HANDLE ObjectDirHandle;
+  HANDLE FileDirHandle;
+  HANDLE SymlinkHandle;
+  NTSTATUS Status;
+
+  DPRINT("SmLoadKnownDlls() called\n");
+
+  /* Create 'KnownDlls' object directory */
+  RtlInitUnicodeString(&Name,
+                      L"\\KnownDlls");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &Name,
+                            OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+                            NULL,
+                            NULL);
+  Status = NtCreateDirectoryObject(&ObjectDirHandle,
+                                  DIRECTORY_ALL_ACCESS,
+                                  &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("NtCreateDirectoryObject() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  RtlInitUnicodeString(&DllDosPath, NULL);
+
+  RtlZeroMemory(&QueryTable,
+               sizeof(QueryTable));
+
+  QueryTable[0].Name = L"DllDirectory";
+  QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+  QueryTable[0].EntryContext = &DllDosPath;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                 L"\\Session Manager\\KnownDlls",
+                                 QueryTable,
                                  NULL,
-                                 FALSE,
-                                 0,
-                                 0,
-                                 0,
-                                 &ProcessInfo);
-   
-   RtlDestroyProcessParameters (ProcessParameters);
-   
-   if (!NT_SUCCESS(Status))
-     {
-       DisplayString (L"SM: Loading csrss.exe failed!\n");
-       return FALSE;
-     }
-   
-   DbgPrint("SM: Waiting for csrss\n");
-   NtWaitForSingleObject(CsrssInitEvent,
-                        FALSE,
-                        NULL);
-   DbgPrint("SM: Finished waiting for csrss\n");
-   
-   Children[CHILD_CSRSS] = ProcessInfo.ProcessHandle;
-   
-   /*
-    * Start the logon process (winlogon.exe)
-    */
-   DisplayString(L"SM: Running winlogon.exe\n");
-   
-   /* initialize executable path */
-   wcscpy(UnicodeBuffer, L"\\??\\");
-   wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
-   wcscat(UnicodeBuffer, L"\\system32\\winlogon.exe");
-   RtlInitUnicodeString (&UnicodeString,
-                        UnicodeBuffer);
-   
-   RtlCreateProcessParameters(&ProcessParameters,
-                             &UnicodeString,
-                             NULL,
-                             NULL,
-                             NULL,
-                             SmSystemEnvironment,
-                             NULL,
-                             NULL,
-                             NULL,
-                             NULL);
-   
-   Status = RtlCreateUserProcess(&UnicodeString,
-                                0,
-                                ProcessParameters,
-                                NULL,
-                                NULL,
-                                FALSE,
-                                0,
-                                0,
-                                0,
-                                &ProcessInfo);
-   
-   RtlDestroyProcessParameters(ProcessParameters);
-   
-   if (!NT_SUCCESS(Status))
-     {
-       DisplayString(L"SM: Loading winlogon.exe failed!\n");
-       NtTerminateProcess(Children[CHILD_CSRSS],
-                          0);
-       return FALSE;
-     }
-   Children[CHILD_WINLOGON] = ProcessInfo.ProcessHandle;
-   
-       /* Create the \DbgSsApiPort object (LPC) */
-       RtlInitUnicodeString (&UnicodeString,
-                             L"\\DbgSsApiPort");
-       InitializeObjectAttributes (&ObjectAttributes,
-                                   &UnicodeString,
-                                   0xff,
-                                   NULL,
-                                   NULL);
-
-       Status = NtCreatePort (&DbgSsApiPort,
-                              &ObjectAttributes,
-                              0,
-                              0,
-                              0);
-
-       if (!NT_SUCCESS(Status))
+                                 SmSystemEnvironment);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  DPRINT("DllDosPath: '%wZ'\n", &DllDosPath);
+
+  if (!RtlDosPathNameToNtPathName_U(DllDosPath.Buffer,
+                                   &DllNtPath,
+                                   NULL,
+                                   NULL))
+    {
+      DPRINT1("RtlDosPathNameToNtPathName_U() failed\n");
+      return STATUS_OBJECT_NAME_INVALID;
+    }
+
+  DPRINT("DllNtPath: '%wZ'\n", &DllNtPath);
+
+  /* Open the dll path directory */
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &DllNtPath,
+                            OBJ_CASE_INSENSITIVE,
+                            NULL,
+                            NULL);
+  Status = NtOpenFile(&FileDirHandle,
+                     SYNCHRONIZE | FILE_READ_DATA,
+                     &ObjectAttributes,
+                     &IoStatusBlock,
+                     FILE_SHARE_READ | FILE_SHARE_WRITE,
+                     FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("NtOpenFile() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  /* Link 'KnownDllPath' the dll path directory */
+  RtlInitUnicodeString(&Name,
+                      L"KnownDllPath");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &Name,
+                            OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+                            ObjectDirHandle,
+                            NULL);
+  Status = NtCreateSymbolicLinkObject(&SymlinkHandle,
+                                     SYMBOLIC_LINK_ALL_ACCESS,
+                                     &ObjectAttributes,
+                                     &DllDosPath);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("NtCreateSymbolicLink() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  NtClose(SymlinkHandle);
+
+  RtlZeroMemory(&QueryTable,
+               sizeof(QueryTable));
+
+  QueryTable[0].QueryRoutine = SmKnownDllsQueryRoutine;
+  QueryTable[0].EntryContext = ObjectDirHandle;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                 L"\\Session Manager\\KnownDlls",
+                                 QueryTable,
+                                 (PVOID)FileDirHandle,
+                                 NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+    }
+
+  DPRINT("SmLoadKnownDlls() done\n");
+
+  return Status;
+}
+
+
+static NTSTATUS STDCALL
+SmPagingFilesQueryRoutine(PWSTR ValueName,
+                         ULONG ValueType,
+                         PVOID ValueData,
+                         ULONG ValueLength,
+                         PVOID Context,
+                         PVOID EntryContext)
+{
+  UNICODE_STRING FileName;
+  LARGE_INTEGER InitialSize;
+  LARGE_INTEGER MaximumSize;
+  NTSTATUS Status;
+  LPWSTR p;
+
+  DPRINT("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
+  DPRINT("ValueData '%S'\n", (PWSTR)ValueData);
+
+  if (ValueType != REG_SZ)
+    {
+      return(STATUS_SUCCESS);
+    }
+
+  /*
+   * Format: "<path>[ <initial_size>[ <maximum_size>]]"
+   */
+  if ((p = wcschr(ValueData, ' ')) != NULL)
+    {
+      *p = L'\0';
+      InitialSize.QuadPart = wcstoul(p + 1, &p, 0) * 256 * 4096;
+      if (*p == ' ')
        {
-               return FALSE;
+         MaximumSize.QuadPart = wcstoul(p + 1, NULL, 0) * 256 * 4096;
        }
+      else
+       MaximumSize = InitialSize;
+    }
+  else
+    {
+      InitialSize.QuadPart = 50 * 4096;
+      MaximumSize.QuadPart = 80 * 4096;
+    }
+
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)ValueData,
+                                    &FileName,
+                                    NULL,
+                                    NULL))
+    {
+      return (STATUS_SUCCESS);
+    }
+
+  DbgPrint("SMSS: Created paging file %wZ with size %dKB\n",
+          &FileName, InitialSize.QuadPart / 1024);
+  Status = NtCreatePagingFile(&FileName,
+                             &InitialSize,
+                             &MaximumSize,
+                             0);
+
+  RtlFreeUnicodeString(&FileName);
+
+  return(STATUS_SUCCESS);
+}
+
+
+static NTSTATUS
+SmCreatePagingFiles(VOID)
+{
+  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+  NTSTATUS Status;
+
+  RtlZeroMemory(&QueryTable,
+               sizeof(QueryTable));
+
+  QueryTable[0].Name = L"PagingFiles";
+  QueryTable[0].QueryRoutine = SmPagingFilesQueryRoutine;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                 L"\\Session Manager\\Memory Management",
+                                 QueryTable,
+                                 NULL,
+                                 NULL);
+
+  return(Status);
+}
+
+
+static NTSTATUS STDCALL
+SmEnvironmentQueryRoutine(PWSTR ValueName,
+                         ULONG ValueType,
+                         PVOID ValueData,
+                         ULONG ValueLength,
+                         PVOID Context,
+                         PVOID EntryContext)
+{
+  UNICODE_STRING EnvVariable;
+  UNICODE_STRING EnvValue;
+
+  DPRINT("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
+  DPRINT("ValueData '%S'\n", (PWSTR)ValueData);
+
+  if (ValueType != REG_SZ)
+    {
+      return(STATUS_SUCCESS);
+    }
+
+  RtlInitUnicodeString(&EnvVariable,
+                      ValueName);
+  RtlInitUnicodeString(&EnvValue,
+                      (PWSTR)ValueData);
+  RtlSetEnvironmentVariable(Context,
+                           &EnvVariable,
+                           &EnvValue);
+
+  return(STATUS_SUCCESS);
+}
+
+
+static NTSTATUS
+SmSetEnvironmentVariables(VOID)
+{
+  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+  UNICODE_STRING EnvVariable;
+  UNICODE_STRING EnvValue;
+  WCHAR ValueBuffer[MAX_PATH];
+  NTSTATUS Status;
+
+  /*
+   * The following environment variables must be set prior to reading
+   * other variables from the registry.
+   *
+   * Variables (example):
+   *    SystemRoot = "C:\reactos"
+   *    SystemDrive = "C:"
+   */
+
+  /* Copy system root into value buffer */
+  wcscpy(ValueBuffer,
+        SharedUserData->NtSystemRoot);
+
+  /* Set SystemRoot = "C:\reactos" */
+  RtlInitUnicodeStringFromLiteral(&EnvVariable,
+                      L"SystemRoot");
+  RtlInitUnicodeString(&EnvValue,
+                      ValueBuffer);
+  RtlSetEnvironmentVariable(&SmSystemEnvironment,
+                           &EnvVariable,
+                           &EnvValue);
+
+  /* Cut off trailing path */
+  ValueBuffer[2] = 0;
+
+  /* Set SystemDrive = "C:" */
+  RtlInitUnicodeStringFromLiteral(&EnvVariable,
+                      L"SystemDrive");
+  RtlInitUnicodeString(&EnvValue,
+                      ValueBuffer);
+  RtlSetEnvironmentVariable(&SmSystemEnvironment,
+                           &EnvVariable,
+                           &EnvValue);
+
+  /* Read system environment from the registry. */
+  RtlZeroMemory(&QueryTable,
+               sizeof(QueryTable));
+
+  QueryTable[0].QueryRoutine = SmEnvironmentQueryRoutine;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                 L"\\Session Manager\\Environment",
+                                 QueryTable,
+                                 &SmSystemEnvironment,
+                                 SmSystemEnvironment);
+
+  return(Status);
+}
+
+
+static NTSTATUS
+SmLoadSubsystems(VOID)
+{
+  SYSTEM_LOAD_AND_CALL_IMAGE ImageInfo;
+  NTSTATUS Status;
+
+  /* Load kernel mode subsystem (aka win32k.sys) */
+  RtlInitUnicodeStringFromLiteral(&ImageInfo.ModuleName,
+                      L"\\SystemRoot\\system32\\win32k.sys");
+
+  Status = NtSetSystemInformation(SystemLoadAndCallImage,
+                                 &ImageInfo,
+                                 sizeof(SYSTEM_LOAD_AND_CALL_IMAGE));
+
+  DPRINT("SMSS: Loaded win32k.sys (Status %lx)\n", Status);
+#if 0
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+#endif
+
+  /* FIXME: load more subsystems (csrss!) */
+
+  return(Status);
+}
+
+
+static VOID
+SignalInitEvent()
+{
+  NTSTATUS Status;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING UnicodeString;
+  HANDLE ReactOSInitEvent;
+
+  RtlInitUnicodeStringFromLiteral(&UnicodeString, L"\\ReactOSInitDone");
+  InitializeObjectAttributes(&ObjectAttributes,
+    &UnicodeString,
+    EVENT_ALL_ACCESS,
+    0,
+    NULL);
+  Status = NtOpenEvent(&ReactOSInitEvent,
+    EVENT_ALL_ACCESS,
+    &ObjectAttributes);
+  if (NT_SUCCESS(Status))
+    {
+      LARGE_INTEGER Timeout;
+      /* This will cause the boot screen image to go away (if displayed) */
+      NtPulseEvent(ReactOSInitEvent, NULL);
+
+      /* Wait for the display mode to be changed (if in graphics mode) */
+      Timeout.QuadPart = -50000000LL;  /* 5 second timeout */
+      NtWaitForSingleObject(ReactOSInitEvent, FALSE, &Timeout);
+
+      NtClose(ReactOSInitEvent);
+    }
+  else
+    {
+      /* We don't really care if this fails */
+      DPRINT1("SM: Failed to open ReactOS init notification event\n");
+    }
+}
+
+
+NTSTATUS
+InitSessionManager(HANDLE Children[])
+{
+  NTSTATUS Status;
+  UNICODE_STRING UnicodeString;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING CmdLineW;
+  PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+  RTL_PROCESS_INFO ProcessInfo;
+  HANDLE CsrssInitEvent;
+  WCHAR UnicodeBuffer[MAX_PATH];
+
+  /* Create object directories */
+  Status = SmCreateObjectDirectories();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to create object directories (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  /* Create the SmApiPort object (LPC) */
+  Status = SmCreateApiPort();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to create SmApiPort (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  /* Create the system environment */
+  Status = RtlCreateEnvironment(FALSE,
+                               &SmSystemEnvironment);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to create the system environment (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  /* Set environment variables */
+  Status = SmSetEnvironmentVariables();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to set system environment variables (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  /* Define symbolic links to kernel devices (MS-DOS names) */
+  Status = SmInitDosDevices();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to create dos device links (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  /* Run all programs in the boot execution list */
+  Status = SmRunBootApps();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to run boot applications (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  /* Process the file rename list */
+  Status = SmProcessFileRenameList();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to process the file rename list (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  DPRINT("SM: loading well-known DLLs\n");
+
+  /* Load the well known DLLs */
+  Status = SmLoadKnownDlls();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to preload system DLLs (Status %lx)\n", Status);
+      /* Don't crash ReactOS if DLLs cannot be loaded */
+    }
+
+  DPRINT("SM: creating system paging files\n");
+
+  /* Create paging files */
+  Status = SmCreatePagingFiles();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to create paging files (Status %lx)\n", Status);
+      return(Status);
+    }
+
+  DPRINT("SM: initializing registry\n");
+
+  /* Load remaining registry hives */
+  NtInitializeRegistry(FALSE);
+
+  /* Set environment variables from registry */
+#if 0
+  Status = SmUpdateEnvironment();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to update environment variables (Status %lx)\n", Status);
+      return(Status);
+    }
+#endif
+
+  DPRINT("SM: loading subsystems\n");
+
+  /* Load the subsystems */
+  Status = SmLoadSubsystems();
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("SM: Failed to load subsystems (Status %lx)\n", Status);
+      return(Status);
+    }
+
+
+  SignalInitEvent();
+
+
+  DPRINT("SM: initializing csrss\n");
+
+  /* Run csrss.exe */
+  RtlInitUnicodeStringFromLiteral(&UnicodeString,
+                                 L"\\CsrssInitDone");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &UnicodeString,
+                            EVENT_ALL_ACCESS,
+                            0,
+                            NULL);
+  Status = NtCreateEvent(&CsrssInitEvent,
+                        EVENT_ALL_ACCESS,
+                        &ObjectAttributes,
+                        TRUE,
+                        FALSE);
+  if (!NT_SUCCESS(Status))
+    {
+      DbgPrint("Failed to create csrss notification event\n");
+    }
+
+  /*
+   * Start the Win32 subsystem (csrss.exe)
+   */
+
+  /* initialize executable path */
+  wcscpy(UnicodeBuffer, L"\\??\\");
+  wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
+  wcscat(UnicodeBuffer, L"\\system32\\csrss.exe");
+  RtlInitUnicodeString(&UnicodeString,
+                      UnicodeBuffer);
+
+  RtlCreateProcessParameters(&ProcessParameters,
+                            &UnicodeString,
+                            NULL,
+                            NULL,
+                            NULL,
+                            SmSystemEnvironment,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL);
+
+  Status = RtlCreateUserProcess(&UnicodeString,
+                               OBJ_CASE_INSENSITIVE,
+                               ProcessParameters,
+                               NULL,
+                               NULL,
+                               NULL,
+                               FALSE,
+                               NULL,
+                               NULL,
+                               &ProcessInfo);
+
+  RtlDestroyProcessParameters (ProcessParameters);
+
+  if (!NT_SUCCESS(Status))
+    {
+      DisplayString(L"SM: Loading csrss.exe failed!\n");
+      return(Status);
+    }
+
+  NtWaitForSingleObject(CsrssInitEvent,
+                       FALSE,
+                       NULL);
+
+  Children[CHILD_CSRSS] = ProcessInfo.ProcessHandle;
+
+  /*
+   * Start the logon process (winlogon.exe)
+   */
+
+  DPRINT("SM: starting winlogon\n");
+
+  /* initialize executable path */
+  wcscpy(UnicodeBuffer, L"\\??\\");
+  wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
+  wcscat(UnicodeBuffer, L"\\system32\\winlogon.exe");
+  RtlInitUnicodeString(&UnicodeString,
+                      UnicodeBuffer);
+
+  RtlCreateProcessParameters(&ProcessParameters,
+                            &UnicodeString,
+                            NULL,
+                            NULL,
+                            NULL,
+                            SmSystemEnvironment,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL);
+
+  Status = RtlCreateUserProcess(&UnicodeString,
+                               OBJ_CASE_INSENSITIVE,
+                               ProcessParameters,
+                               NULL,
+                               NULL,
+                               NULL,
+                               FALSE,
+                               NULL,
+                               NULL,
+                               &ProcessInfo);
+
+  RtlDestroyProcessParameters(ProcessParameters);
+
+  if (!NT_SUCCESS(Status))
+    {
+      DisplayString(L"SM: Loading winlogon.exe failed!\n");
+      NtTerminateProcess(Children[CHILD_CSRSS],
+                        0);
+      return(Status);
+    }
+  Children[CHILD_WINLOGON] = ProcessInfo.ProcessHandle;
+
+  /* Create the \DbgSsApiPort object (LPC) */
+  RtlInitUnicodeStringFromLiteral(&UnicodeString,
+                      L"\\DbgSsApiPort");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &UnicodeString,
+                            PORT_ALL_ACCESS,
+                            NULL,
+                            NULL);
+
+  Status = NtCreatePort(&DbgSsApiPort,
+                       &ObjectAttributes,
+                       0,
+                       0,
+                       0);
+
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
 #ifndef NDEBUG
-       DisplayString (L"SM: DbgSsApiPort created...\n");
+  DisplayString(L"SM: DbgSsApiPort created...\n");
 #endif
 
-       /* Create the \DbgUiApiPort object (LPC) */
-       RtlInitUnicodeString (&UnicodeString,
-                             L"\\DbgUiApiPort");
-       InitializeObjectAttributes (&ObjectAttributes,
-                                   &UnicodeString,
-                                   0xff,
-                                   NULL,
-                                   NULL);
-
-       Status = NtCreatePort (&DbgUiApiPort,
-                              &ObjectAttributes,
-                              0,
-                              0,
-                              0);
-
-       if (!NT_SUCCESS(Status))
-       {
-               return FALSE;
-       }
+  /* Create the \DbgUiApiPort object (LPC) */
+  RtlInitUnicodeStringFromLiteral(&UnicodeString,
+                      L"\\DbgUiApiPort");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &UnicodeString,
+                            PORT_ALL_ACCESS,
+                            NULL,
+                            NULL);
+
+  Status = NtCreatePort(&DbgUiApiPort,
+                       &ObjectAttributes,
+                       0,
+                       0,
+                       0);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
 #ifndef NDEBUG
-       DisplayString (L"SM: DbgUiApiPort created...\n");
+  DisplayString (L"SM: DbgUiApiPort created...\n");
 #endif
 
-       return TRUE;
+  return(STATUS_SUCCESS);
 }
 
 /* EOF */