2003-08-11 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / subsys / smss / init.c
index 0e9e091..c8d1eaa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.34 2002/05/22 15:55:51 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 "smss.h"
 
 #define NDEBUG
+#include <debug.h>
 
-/* TYPES ********************************************************************/
-
+/* GLOBALS ******************************************************************/
 
-/* GLOBAL VARIABLES *********************************************************/
-
-HANDLE SmApiPort = INVALID_HANDLE_VALUE;
 HANDLE DbgSsApiPort = INVALID_HANDLE_VALUE;
 HANDLE DbgUiApiPort = INVALID_HANDLE_VALUE;
 
@@ -48,7 +49,6 @@ PWSTR SmSystemEnvironment = NULL;
 
 /* FUNCTIONS ****************************************************************/
 
-
 static NTSTATUS STDCALL
 SmObjectDirectoryQueryRoutine(PWSTR ValueName,
                              ULONG ValueType,
@@ -60,12 +60,16 @@ SmObjectDirectoryQueryRoutine(PWSTR ValueName,
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING UnicodeString;
   HANDLE WindowsDirectory;
-  NTSTATUS Status;
+  NTSTATUS Status = STATUS_SUCCESS;
 
 #ifndef NDEBUG
-  PrintString("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
-  PrintString("ValueData '%S'\n", (PWSTR)ValueData);
+  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);
@@ -119,46 +123,45 @@ SmDosDevicesQueryRoutine(PWSTR ValueName,
   UNICODE_STRING LinkName;
   HANDLE LinkHandle;
   WCHAR LinkBuffer[80];
-  NTSTATUS Status = STATUS_SUCCESS;
+  NTSTATUS Status;
 
-#ifndef NDEBUG
-  PrintString("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
-  PrintString("ValueData '%S'\n", (PWSTR)ValueData);
-#endif
+  DPRINT("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
+  DPRINT("ValueData '%S'\n", (PWSTR)ValueData);
 
-  if (ValueType = REG_SZ)
+  if (ValueType != REG_SZ)
     {
-      swprintf(LinkBuffer, L"\\??\\%s",
-              ValueName);
-      RtlInitUnicodeString(&LinkName,
-                          LinkBuffer);
-      RtlInitUnicodeString(&DeviceName,
-                          (PWSTR)ValueData);
+      return(STATUS_SUCCESS);
+    }
 
-#ifndef NDEBUG
-      PrintString("SM: Linking %wZ --> %wZ\n",
+  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);
-#endif
-
-      /* create symbolic link */
-      InitializeObjectAttributes(&ObjectAttributes,
-                                &LinkName,
-                                OBJ_PERMANENT,
-                                NULL,
-                                NULL);
-      Status = NtCreateSymbolicLinkObject(&LinkHandle,
-                                         SYMBOLIC_LINK_ALL_ACCESS,
-                                         &ObjectAttributes,
-                                         &DeviceName);
-      if (!NT_SUCCESS(Status))
-       {
-         PrintString("SmDosDevicesQueryRoutine: NtCreateSymbolicLink( %wZ --> %wZ ) failed!\n",
-                     &LinkName,
-                     &DeviceName);
-       }
-      NtClose(LinkHandle);
     }
+  NtClose(LinkHandle);
 
   return(Status);
 }
@@ -192,20 +195,25 @@ SmRunBootAppsQueryRoutine(PWSTR ValueName,
                          PVOID Context,
                          PVOID EntryContext)
 {
-#if 0
   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 = STATUS_SUCCESS;
+  NTSTATUS Status;
 
-#ifndef NDEBUG
-  PrintString("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
-  PrintString("ValueData '%S'\n", (PWSTR)ValueData);
-#endif
+  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' ');
@@ -213,15 +221,15 @@ SmRunBootAppsQueryRoutine(PWSTR ValueName,
   memcpy(Description,ValueData, len * sizeof(WCHAR));
   Description[len] = 0;
 
-  /* Extract the full image path */
+  /* Extract the image name */
   p1++;
   p2 = wcschr(p1, L' ');
   if (p2 != NULL)
     len = p2 - p1;
   else
     len = wcslen(p1);
-  memcpy(ImagePath, p1, len * sizeof(WCHAR));
-  ImagePath[len] = 0;
+  memcpy(ImageName, p1, len * sizeof(WCHAR));
+  ImageName[len] = 0;
 
   /* Extract the command line */
   if (p2 == NULL)
@@ -234,19 +242,17 @@ SmRunBootAppsQueryRoutine(PWSTR ValueName,
       wcscpy(CommandLine, p2);
     }
 
-#ifndef NDEBUG
-  PrintString("Running %S...\n", Description);
-  PrintString("Executable: '%S'\n", ImagePath);
-  PrintString("CommandLine: '%S'\n", CommandLine);
-#endif
+  DPRINT("Running %S...\n", Description);
+  DPRINT("ImageName: '%S'\n", ImageName);
+  DPRINT("CommandLine: '%S'\n", CommandLine);
 
-#if 0
   /* initialize executable path */
-  wcscpy(UnicodeBuffer, L"\\??\\");
-  wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
-  wcscat(UnicodeBuffer, L"\\system32\\csrss.exe");
+  wcscpy(ImagePath, L"\\SystemRoot\\system32\\");
+  wcscat(ImagePath, ImageName);
+  wcscat(ImagePath, L".exe");
+
   RtlInitUnicodeString(&ImagePathString,
-                      UnicodeBuffer);
+                      ImagePath);
 
   RtlInitUnicodeString(&CommandLineString,
                       CommandLine);
@@ -262,7 +268,7 @@ SmRunBootAppsQueryRoutine(PWSTR ValueName,
                             NULL,
                             NULL);
 
-  Status = RtlCreateUserProcess(&UnicodeString,
+  Status = RtlCreateUserProcess(&ImagePathString,
                                OBJ_CASE_INSENSITIVE,
                                ProcessParameters,
                                NULL,
@@ -272,15 +278,22 @@ SmRunBootAppsQueryRoutine(PWSTR ValueName,
                                NULL,
                                NULL,
                                &ProcessInfo);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Running %s failed (Status %lx)\n", Description, Status);
+      return(STATUS_SUCCESS);
+    }
 
-  RtlDestroyProcessParameters (ProcessParameters);
+  RtlDestroyProcessParameters(ProcessParameters);
 
-  /* FIXME: wait for process termination */
+  /* Wait for process termination */
+  NtWaitForSingleObject(ProcessInfo.ProcessHandle,
+                       FALSE,
+                       NULL);
 
-#endif
+  NtClose(ProcessInfo.ThreadHandle);
+  NtClose(ProcessInfo.ProcessHandle);
 
-  return(Status);
-#endif
   return(STATUS_SUCCESS);
 }
 
@@ -313,12 +326,9 @@ SmRunBootApps(VOID)
                                  NULL);
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SmRunBootApps: RtlQueryRegistryValues() failed! (Status %lx)\n", Status);
+      DPRINT1("SmRunBootApps: RtlQueryRegistryValues() failed! (Status %lx)\n", Status);
     }
 
-//  PrintString("*** System stopped ***\n");
-//  for(;;);
-
   return(Status);
 }
 
@@ -326,18 +336,235 @@ SmRunBootApps(VOID)
 static NTSTATUS
 SmProcessFileRenameList(VOID)
 {
-#ifndef NDEBUG
-  PrintString("SmProcessFileRenameList() called\n");
-#endif
+  DPRINT("SmProcessFileRenameList() called\n");
 
-#ifndef NDEBUG
-  PrintString("SmProcessFileRenameList() done\n");
-#endif
+  /* 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,
+                                 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,
@@ -350,30 +577,53 @@ SmPagingFilesQueryRoutine(PWSTR ValueName,
   LARGE_INTEGER InitialSize;
   LARGE_INTEGER MaximumSize;
   NTSTATUS Status;
+  LPWSTR p;
 
-#ifndef NDEBUG
-  PrintString("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
-  PrintString("ValueData '%S'\n", (PWSTR)ValueData);
-#endif
+  DPRINT("ValueName '%S'  Type %lu  Length %lu\n", ValueName, ValueType, ValueLength);
+  DPRINT("ValueData '%S'\n", (PWSTR)ValueData);
 
-  RtlInitUnicodeString(&FileName,
-                      (PWSTR)ValueData);
+  if (ValueType != REG_SZ)
+    {
+      return(STATUS_SUCCESS);
+    }
 
   /*
-   * FIXME:
-   *  read initial and maximum size from the registry or use default values
-   *
    * 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 == ' ')
+       {
+         MaximumSize.QuadPart = wcstoul(p + 1, NULL, 0) * 256 * 4096;
+       }
+      else
+       MaximumSize = InitialSize;
+    }
+  else
+    {
+      InitialSize.QuadPart = 50 * 4096;
+      MaximumSize.QuadPart = 80 * 4096;
+    }
 
-  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);
 }
 
@@ -400,100 +650,158 @@ SmCreatePagingFiles(VOID)
 }
 
 
+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)
 {
-       UNICODE_STRING EnvVariable;
-       UNICODE_STRING EnvValue;
-       UNICODE_STRING EnvExpandedValue;
-       ULONG ExpandedLength;
-       WCHAR ExpandBuffer[512];
-       WCHAR ValueBuffer[MAX_PATH];
-
-       /*
-        * 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");
-       RtlInitUnicodeString (&EnvValue,
-                             ValueBuffer);
-       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];
+  UNICODE_STRING EnvVariable;
+  UNICODE_STRING EnvValue;
+  WCHAR ValueBuffer[MAX_PATH];
+  NTSTATUS Status;
 
-  return(STATUS_SUCCESS);
+  /*
+   * 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");
+    }
 }
 
 
@@ -513,72 +821,40 @@ InitSessionManager(HANDLE Children[])
   Status = SmCreateObjectDirectories();
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SM: Failed to create object directories! (Status %lx)\n", Status);
+      DPRINT1("SM: Failed to create object directories (Status %lx)\n", Status);
       return(Status);
     }
 
-  /* Create the "\SmApiPort" object (LPC) */
-  RtlInitUnicodeString(&UnicodeString,
-                      L"\\SmApiPort");
-  InitializeObjectAttributes(&ObjectAttributes,
-                            &UnicodeString,
-                            PORT_ALL_ACCESS,
-                            NULL,
-                            NULL);
-
-  Status = NtCreatePort(&SmApiPort,
-                       &ObjectAttributes,
-                       0,
-                       0,
-                       0);
+  /* Create the SmApiPort object (LPC) */
+  Status = SmCreateApiPort();
   if (!NT_SUCCESS(Status))
     {
+      DPRINT1("SM: Failed to create SmApiPort (Status %lx)\n", Status);
       return(Status);
     }
 
-#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);
-
-  RtlCreateUserThread(NtCurrentProcess(),
-                     NULL,
-                     FALSE,
-                     0,
-                     NULL,
-                     NULL,
-                     (PTHREAD_START_ROUTINE)SmApiThread,
-                     (PVOID)SmApiPort,
-                     NULL,
-                     NULL);
-
   /* 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);
     }
-#ifndef NDEBUG
-  DisplayString(L"SM: System Environment created\n");
-#endif
 
   /* Define symbolic links to kernel devices (MS-DOS names) */
   Status = SmInitDosDevices();
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SM: Failed to create dos device links! (Status %lx)\n", Status);
+      DPRINT1("SM: Failed to create dos device links (Status %lx)\n", Status);
       return(Status);
     }
 
@@ -586,7 +862,7 @@ InitSessionManager(HANDLE Children[])
   Status = SmRunBootApps();
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SM: Failed to run boot applications! (Status %lx)\n", Status);
+      DPRINT1("SM: Failed to run boot applications (Status %lx)\n", Status);
       return(Status);
     }
 
@@ -594,46 +870,64 @@ InitSessionManager(HANDLE Children[])
   Status = SmProcessFileRenameList();
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SM: Failed to process the file rename list (Status %lx)\n", Status);
+      DPRINT1("SM: Failed to process the file rename list (Status %lx)\n", Status);
       return(Status);
     }
 
-  /* FIXME: Load the well known DLLs */
-//  SmPreloadDlls();
+  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))
     {
-      PrintString("SM: Failed to create paging files (Status %lx)\n", 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 */
-  Status = SmSetEnvironmentVariables();
+#if 0
+  Status = SmUpdateEnvironment();
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SM: Failed to initialize the system environment (Status %lx)\n", Status);
+      DPRINT1("SM: Failed to update environment variables (Status %lx)\n", Status);
       return(Status);
     }
+#endif
 
-  /* Load the kernel mode driver win32k.sys */
-  RtlInitUnicodeString(&CmdLineW,
-                      L"\\SystemRoot\\system32\\drivers\\win32k.sys");
-  Status = NtLoadDriver(&CmdLineW);
-#if 0
+  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);
     }
-#endif
+
+
+  SignalInitEvent();
+
+
+  DPRINT("SM: initializing csrss\n");
 
   /* Run csrss.exe */
-  RtlInitUnicodeString(&UnicodeString,
-                      L"\\CsrssInitDone");
+  RtlInitUnicodeStringFromLiteral(&UnicodeString,
+                                 L"\\CsrssInitDone");
   InitializeObjectAttributes(&ObjectAttributes,
                             &UnicodeString,
                             EVENT_ALL_ACCESS,
@@ -700,6 +994,8 @@ InitSessionManager(HANDLE Children[])
    * Start the logon process (winlogon.exe)
    */
 
+  DPRINT("SM: starting winlogon\n");
+
   /* initialize executable path */
   wcscpy(UnicodeBuffer, L"\\??\\");
   wcscat(UnicodeBuffer, SharedUserData->NtSystemRoot);
@@ -741,7 +1037,7 @@ InitSessionManager(HANDLE Children[])
   Children[CHILD_WINLOGON] = ProcessInfo.ProcessHandle;
 
   /* Create the \DbgSsApiPort object (LPC) */
-  RtlInitUnicodeString(&UnicodeString,
+  RtlInitUnicodeStringFromLiteral(&UnicodeString,
                       L"\\DbgSsApiPort");
   InitializeObjectAttributes(&ObjectAttributes,
                             &UnicodeString,
@@ -764,7 +1060,7 @@ InitSessionManager(HANDLE Children[])
 #endif
 
   /* Create the \DbgUiApiPort object (LPC) */
-  RtlInitUnicodeString(&UnicodeString,
+  RtlInitUnicodeStringFromLiteral(&UnicodeString,
                       L"\\DbgUiApiPort");
   InitializeObjectAttributes(&ObjectAttributes,
                             &UnicodeString,