2003-08-11 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / subsys / smss / init.c
index 1068a19..c8d1eaa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.42 2002/08/20 20:37:17 hyperion Exp $
+/* $Id: init.c,v 1.50 2003/08/11 18:50:12 chorns Exp $
  *
  * init.c - Session Manager initialization
  * 
 
 #include <ntos.h>
 #include <ntdll/rtl.h>
+#include <ntdll/ldr.h>
 #include <napi/lpc.h>
 
 #include "smss.h"
 
 #define NDEBUG
-
+#include <debug.h>
 
 /* GLOBALS ******************************************************************/
 
@@ -62,8 +63,8 @@ SmObjectDirectoryQueryRoutine(PWSTR ValueName,
   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)
     {
@@ -124,10 +125,8 @@ SmDosDevicesQueryRoutine(PWSTR ValueName,
   WCHAR LinkBuffer[80];
   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)
     {
@@ -142,11 +141,9 @@ SmDosDevicesQueryRoutine(PWSTR ValueName,
   RtlInitUnicodeString(&DeviceName,
                       (PWSTR)ValueData);
 
-#ifndef NDEBUG
-  PrintString("SM: Linking %wZ --> %wZ\n",
+  DPRINT("SM: Linking %wZ --> %wZ\n",
              &LinkName,
              &DeviceName);
-#endif
 
   /* create symbolic link */
   InitializeObjectAttributes(&ObjectAttributes,
@@ -160,7 +157,7 @@ SmDosDevicesQueryRoutine(PWSTR ValueName,
                                      &DeviceName);
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SmDosDevicesQueryRoutine: NtCreateSymbolicLink( %wZ --> %wZ ) failed!\n",
+      DPRINT1("SmDosDevicesQueryRoutine: NtCreateSymbolicLink( %wZ --> %wZ ) failed!\n",
                  &LinkName,
                  &DeviceName);
     }
@@ -210,10 +207,8 @@ SmRunBootAppsQueryRoutine(PWSTR ValueName,
   ULONG len;
   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)
     {
@@ -247,11 +242,9 @@ SmRunBootAppsQueryRoutine(PWSTR ValueName,
       wcscpy(CommandLine, p2);
     }
 
-  PrintString("Running %S...\n", Description);
-#ifndef NDEBUG
-  PrintString("ImageName: '%S'\n", ImageName);
-  PrintString("CommandLine: '%S'\n", CommandLine);
-#endif
+  DPRINT("Running %S...\n", Description);
+  DPRINT("ImageName: '%S'\n", ImageName);
+  DPRINT("CommandLine: '%S'\n", CommandLine);
 
   /* initialize executable path */
   wcscpy(ImagePath, L"\\SystemRoot\\system32\\");
@@ -287,7 +280,7 @@ SmRunBootAppsQueryRoutine(PWSTR ValueName,
                                &ProcessInfo);
   if (!NT_SUCCESS(Status))
     {
-      PrintString("Running %s failed (Status %lx)\n", Description, Status);
+      DPRINT1("Running %s failed (Status %lx)\n", Description, Status);
       return(STATUS_SUCCESS);
     }
 
@@ -333,7 +326,7 @@ SmRunBootApps(VOID)
                                  NULL);
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SmRunBootApps: RtlQueryRegistryValues() failed! (Status %lx)\n", Status);
+      DPRINT1("SmRunBootApps: RtlQueryRegistryValues() failed! (Status %lx)\n", Status);
     }
 
   return(Status);
@@ -343,34 +336,232 @@ SmRunBootApps(VOID)
 static NTSTATUS
 SmProcessFileRenameList(VOID)
 {
-#ifndef NDEBUG
-  PrintString("SmProcessFileRenameList() called\n");
-#endif
+  DPRINT("SmProcessFileRenameList() called\n");
 
   /* FIXME: implement it! */
 
-#ifndef NDEBUG
-  PrintString("SmProcessFileRenameList() done\n");
-#endif
+  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
-SmPreloadDlls(VOID)
+SmLoadKnownDlls(VOID)
 {
-#ifndef NDEBUG
-  PrintString("SmPreloadDlls() called\n");
-#endif
+  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;
 
-  /* FIXME: implement it! */
+  DPRINT("SmLoadKnownDlls() called\n");
 
-#ifndef NDEBUG
-  PrintString("SmPreloadDlls() done\n");
-#endif
+  /* 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;
+    }
 
-  return(STATUS_SUCCESS);
+  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;
 }
 
 
@@ -388,10 +579,8 @@ SmPagingFilesQueryRoutine(PWSTR ValueName,
   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);
 
   if (ValueType != REG_SZ)
     {
@@ -418,15 +607,15 @@ SmPagingFilesQueryRoutine(PWSTR ValueName,
       MaximumSize.QuadPart = 80 * 4096;
     }
 
-  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)ValueData, 
+  if (!RtlDosPathNameToNtPathName_U ((LPWSTR)ValueData,
                                     &FileName,
                                     NULL,
                                     NULL))
     {
       return (STATUS_SUCCESS);
-    }  
+    }
 
-  DbgPrint("SMSS: Created paging file %wZ with size %dKB\n", 
+  DbgPrint("SMSS: Created paging file %wZ with size %dKB\n",
           &FileName, InitialSize.QuadPart / 1024);
   Status = NtCreatePagingFile(&FileName,
                              &InitialSize,
@@ -472,10 +661,8 @@ SmEnvironmentQueryRoutine(PWSTR ValueName,
   UNICODE_STRING EnvVariable;
   UNICODE_STRING EnvValue;
 
-#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)
     {
@@ -516,7 +703,7 @@ SmSetEnvironmentVariables(VOID)
   wcscpy(ValueBuffer,
         SharedUserData->NtSystemRoot);
 
-  /* Cet SystemRoot = "C:\reactos" */
+  /* Set SystemRoot = "C:\reactos" */
   RtlInitUnicodeStringFromLiteral(&EnvVariable,
                       L"SystemRoot");
   RtlInitUnicodeString(&EnvValue,
@@ -561,13 +748,13 @@ SmLoadSubsystems(VOID)
 
   /* Load kernel mode subsystem (aka win32k.sys) */
   RtlInitUnicodeStringFromLiteral(&ImageInfo.ModuleName,
-                      L"\\SystemRoot\\system32\\drivers\\win32k.sys");
+                      L"\\SystemRoot\\system32\\win32k.sys");
 
   Status = NtSetSystemInformation(SystemLoadAndCallImage,
                                  &ImageInfo,
                                  sizeof(SYSTEM_LOAD_AND_CALL_IMAGE));
 
-  PrintString("SMSS: Loaded win32k.sys (Status %lx)\n", Status);
+  DPRINT("SMSS: Loaded win32k.sys (Status %lx)\n", Status);
 #if 0
   if (!NT_SUCCESS(Status))
     {
@@ -581,6 +768,43 @@ SmLoadSubsystems(VOID)
 }
 
 
+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[])
 {
@@ -597,7 +821,7 @@ 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);
     }
 
@@ -605,7 +829,7 @@ InitSessionManager(HANDLE Children[])
   Status = SmCreateApiPort();
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SM: Failed to create SmApiPort (Status %lx)\n", Status);
+      DPRINT1("SM: Failed to create SmApiPort (Status %lx)\n", Status);
       return(Status);
     }
 
@@ -614,7 +838,15 @@ InitSessionManager(HANDLE Children[])
                                &SmSystemEnvironment);
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SM: Failed to create the system environment (Status %lx)\n", 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);
     }
 
@@ -622,7 +854,7 @@ InitSessionManager(HANDLE Children[])
   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);
     }
 
@@ -630,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);
     }
 
@@ -638,48 +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);
     }
 
+  DPRINT("SM: loading well-known DLLs\n");
+
   /* Load the well known DLLs */
-  Status = SmPreloadDlls();
+  Status = SmLoadKnownDlls();
   if (!NT_SUCCESS(Status))
     {
-      PrintString("SM: Failed to preload system DLLs (Status %lx)\n", Status);
-      return(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 set system environment variables (Status %lx)\n", 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))
     {
-      PrintString("SM: Failed to load subsystems (Status %lx)\n", 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");
+                                 L"\\CsrssInitDone");
   InitializeObjectAttributes(&ObjectAttributes,
                             &UnicodeString,
                             EVENT_ALL_ACCESS,
@@ -746,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);