Open \Windows directory if it exists
[reactos.git] / reactos / subsys / csrss / init.c
index 3e99ff7..43b8ae7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.24 2003/12/02 11:38:47 gvg Exp $
+/* $Id$
  * 
  * reactos/subsys/csrss/init.c
  *
 
 /* INCLUDES ******************************************************************/
 
+#include <csrss/csrss.h>
 #include <ddk/ntddk.h>
 #include <ntdll/csr.h>
 #include <ntdll/rtl.h>
 #include <ntdll/ldr.h>
-#include <csrss/csrss.h>
 #include <win32k/win32k.h>
 #include <rosrtl/string.h>
+#include <sm/helper.h>
 
 #include "api.h"
 #include "csrplugin.h"
 
 /* GLOBALS ******************************************************************/
 
-HANDLE CsrInitEvent = INVALID_HANDLE_VALUE;
-HANDLE CsrHeap = INVALID_HANDLE_VALUE;
+HANDLE CsrHeap = (HANDLE) 0;
 
-HANDLE CsrObjectDirectory = INVALID_HANDLE_VALUE;
+HANDLE CsrObjectDirectory = (HANDLE) 0;
 
 UNICODE_STRING CsrDirectoryName;
 
 extern HANDLE CsrssApiHeap;
 
+static unsigned InitCompleteProcCount;
+static CSRPLUGIN_INIT_COMPLETE_PROC *InitCompleteProcs = NULL;
+
+HANDLE hSbApiPort = (HANDLE) 0;
+
+HANDLE hBootstrapOk = (HANDLE) 0;
+
+HANDLE hSmApiPort = (HANDLE) 0;
+
+HANDLE hApiPort = (HANDLE) 0;
+
+/**********************************************************************
+ * CsrpAddInitCompleteProc/1
+ */
+static NTSTATUS FASTCALL
+CsrpAddInitCompleteProc(CSRPLUGIN_INIT_COMPLETE_PROC Proc)
+{
+  CSRPLUGIN_INIT_COMPLETE_PROC *NewProcs;
+
+  DPRINT("CSR: %s called\n", __FUNCTION__);
+
+  NewProcs = RtlAllocateHeap(CsrssApiHeap, 0,
+                             (InitCompleteProcCount + 1)
+                             * sizeof(CSRPLUGIN_INIT_COMPLETE_PROC));
+  if (NULL == NewProcs)
+    {
+      return STATUS_NO_MEMORY;
+    }
+  if (0 != InitCompleteProcCount)
+    {
+      RtlCopyMemory(NewProcs, InitCompleteProcs,
+                    InitCompleteProcCount * sizeof(CSRPLUGIN_INIT_COMPLETE_PROC));
+      RtlFreeHeap(CsrssApiHeap, 0, InitCompleteProcs);
+    }
+  NewProcs[InitCompleteProcCount] = Proc;
+  InitCompleteProcs = NewProcs;
+  InitCompleteProcCount++;
+
+  return STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ * CallInitComplete/0
+ */
+static BOOL FASTCALL
+CallInitComplete(void)
+{
+  BOOL Ok;
+  unsigned i;
+
+  DPRINT("CSR: %s called\n", __FUNCTION__);
+
+  Ok = TRUE;
+  if (0 != InitCompleteProcCount)
+    {
+      for (i = 0; i < InitCompleteProcCount && Ok; i++)
+        {
+          Ok = (*(InitCompleteProcs[i]))();
+        }
+      RtlFreeHeap(CsrssApiHeap, 0, InitCompleteProcs);
+    }
+
+  return Ok;
+}
+
 ULONG
 InitializeVideoAddressSpace(VOID);
 
+/**********************************************************************
+ * CsrpParseCommandLine/2
+ */
 static NTSTATUS
-CsrParseCommandLine (
+CsrpParseCommandLine (
        ULONG ArgumentCount,
        PWSTR *ArgumentArray
        )
@@ -47,6 +115,8 @@ CsrParseCommandLine (
    NTSTATUS Status;
    OBJECT_ATTRIBUTES Attributes;
 
+  DPRINT("CSR: %s called\n", __FUNCTION__);
+
 
    /*   DbgPrint ("Arguments: %ld\n", ArgumentCount);
    for (i = 0; i < ArgumentCount; i++)
@@ -61,26 +131,32 @@ CsrParseCommandLine (
 
        InitializeObjectAttributes (&Attributes,
                                    &CsrDirectoryName,
-                                   0,
+                                   OBJ_OPENIF,
                                    NULL,
                                    NULL);
 
-       Status = NtCreateDirectoryObject(&CsrObjectDirectory,
-                                        0xF000F,
-                                        &Attributes);
-
+       Status = NtOpenDirectoryObject(&CsrObjectDirectory,
+                                      0xF000F, /* ea:??? */
+                                      &Attributes);
        return Status;
 }
 
-
-static VOID
-CsrInitVideo(VOID)
+/**********************************************************************
+ * CsrpInitVideo/0
+ *
+ * TODO: we need a virtual device for sessions other than
+ * TODO: the console one
+ */
+static NTSTATUS
+CsrpInitVideo (ULONG argc, PWSTR* argv)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING DeviceName;
   IO_STATUS_BLOCK Iosb;
-  HANDLE VideoHandle;
-  NTSTATUS Status;
+  HANDLE VideoHandle = (HANDLE) 0;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  DPRINT("CSR: %s called\n", __FUNCTION__);
 
   InitializeVideoAddressSpace();
 
@@ -100,10 +176,23 @@ CsrInitVideo(VOID)
     {
       NtClose(VideoHandle);
     }
+  return Status;
 }
 
-static NTSTATUS FASTCALL
-InitWin32Csr()
+/**********************************************************************
+ * CsrpInitWin32Csr/0
+ *
+ * TODO: this function should be turned more general to load an
+ * TODO: hosted server DLL as received from the command line;
+ * TODO: for instance: ServerDll=winsrv:ConServerDllInitialization,2
+ * TODO:               ^method   ^dll   ^api                       ^sid
+ * TODO:
+ * TODO: CsrpHostServerDll (LPWSTR DllName,
+ * TODO:                    LPWSTR ApiName,
+ * TODO:                    DWORD  ServerId)
+ */
+static NTSTATUS
+CsrpInitWin32Csr (ULONG argc, PWSTR* argv)
 {
   NTSTATUS Status;
   UNICODE_STRING DllName;
@@ -113,6 +202,9 @@ InitWin32Csr()
   CSRSS_EXPORTED_FUNCS Exports;
   PCSRSS_API_DEFINITION ApiDefinitions;
   PCSRSS_OBJECT_DEFINITION ObjectDefinitions;
+  CSRPLUGIN_INIT_COMPLETE_PROC InitCompleteProc;
+
+  DPRINT("CSR: %s called\n", __FUNCTION__);
 
   RtlInitUnicodeString(&DllName, L"win32csr.dll");
   Status = LdrLoadDll(NULL, 0, &DllName, (PVOID *) &hInst);
@@ -129,7 +221,8 @@ InitWin32Csr()
   Exports.CsrInsertObjectProc = CsrInsertObject;
   Exports.CsrGetObjectProc = CsrGetObject;
   Exports.CsrReleaseObjectProc = CsrReleaseObject;
-  if (! (*InitProc)(&ApiDefinitions, &ObjectDefinitions, &Exports, CsrssApiHeap))
+  if (! (*InitProc)(&ApiDefinitions, &ObjectDefinitions, &InitCompleteProc,
+                    &Exports, CsrssApiHeap))
     {
       return STATUS_UNSUCCESSFUL;
     }
@@ -140,6 +233,14 @@ InitWin32Csr()
       return Status;
     }
   Status = CsrRegisterObjectDefinitions(ObjectDefinitions);
+  if (! NT_SUCCESS(Status))
+    {
+      return Status;
+    }
+  if (NULL != InitCompleteProc)
+    {
+      Status = CsrpAddInitCompleteProc(InitCompleteProc);
+    }
 
   return Status;
 }
@@ -150,7 +251,6 @@ CSRSS_API_DEFINITION NativeDefinitions[] =
     CSRSS_DEFINE_API(CSRSS_TERMINATE_PROCESS,            CsrTerminateProcess),
     CSRSS_DEFINE_API(CSRSS_CONNECT_PROCESS,              CsrConnectProcess),
     CSRSS_DEFINE_API(CSRSS_REGISTER_SERVICES_PROCESS,    CsrRegisterServicesProcess),
-    CSRSS_DEFINE_API(CSRSS_EXIT_REACTOS,                 CsrExitReactos),
     CSRSS_DEFINE_API(CSRSS_GET_SHUTDOWN_PARAMETERS,      CsrGetShutdownParameters),
     CSRSS_DEFINE_API(CSRSS_SET_SHUTDOWN_PARAMETERS,      CsrSetShutdownParameters),
     CSRSS_DEFINE_API(CSRSS_GET_INPUT_HANDLE,             CsrGetInputHandle),
@@ -158,105 +258,297 @@ CSRSS_API_DEFINITION NativeDefinitions[] =
     CSRSS_DEFINE_API(CSRSS_CLOSE_HANDLE,                 CsrCloseHandle),
     CSRSS_DEFINE_API(CSRSS_VERIFY_HANDLE,                CsrVerifyHandle),
     CSRSS_DEFINE_API(CSRSS_DUPLICATE_HANDLE,             CsrDuplicateHandle),
+    CSRSS_DEFINE_API(CSRSS_GET_INPUT_WAIT_HANDLE,        CsrGetInputWaitHandle),
     { 0, 0, 0, NULL }
   };
 
+static NTSTATUS STDCALL
+CsrpCreateListenPort (IN     LPWSTR  Name,
+                     IN OUT PHANDLE Port,
+                     IN     PTHREAD_START_ROUTINE ListenThread)
+{
+       NTSTATUS           Status = STATUS_SUCCESS;
+       OBJECT_ATTRIBUTES  PortAttributes;
+       UNICODE_STRING     PortName;
+
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       RtlInitUnicodeString (& PortName, Name);
+       InitializeObjectAttributes (& PortAttributes,
+                                   & PortName,
+                                   0,
+                                   NULL,
+                                   NULL);
+       Status = NtCreatePort ( Port,
+                               & PortAttributes,
+                               260, /* TODO: make caller set it*/
+                               328, /* TODO: make caller set it*/
+                               0); /* TODO: make caller set it*/
+       if(!NT_SUCCESS(Status))
+       {
+               DPRINT1("CSR: %s: NtCreatePort failed (Status=%08lx)\n",
+                       __FUNCTION__, Status);
+               return Status;
+       }
+       Status = RtlCreateUserThread(NtCurrentProcess(),
+                               NULL,
+                               FALSE,
+                               0,
+                               NULL,
+                               NULL,
+                               (PTHREAD_START_ROUTINE) ListenThread,
+                               Port,
+                               NULL,
+                               NULL);
+       return Status;
+}
+
+/* === INIT ROUTINES === */
+
+/**********************************************************************
+ * CsrpCreateCallbackPort/0
+ */
+static NTSTATUS
+CsrpCreateHeap (ULONG argc, PWSTR* argv)
+{
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       CsrssApiHeap = RtlCreateHeap(HEAP_GROWABLE,
+                                      NULL,
+                                      65536,
+                                      65536,
+                                      NULL,
+                                      NULL);
+       if (CsrssApiHeap == NULL)
+       {
+               return STATUS_UNSUCCESSFUL;
+       }
+       return STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ * CsrpCreateCallbackPort/0
+ */
+static NTSTATUS
+CsrpCreateCallbackPort (ULONG argc, PWSTR* argv)
+{
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       return CsrpCreateListenPort (L"\\Windows\\SbApiPort",
+                                    & hSbApiPort,
+                                    ServerSbApiPortThread);
+}
+
+/**********************************************************************
+ * CsrpRegisterSubsystem/2
+ */
+static NTSTATUS
+CsrpRegisterSubsystem (ULONG argc, PWSTR* argv)
+{
+       NTSTATUS           Status = STATUS_SUCCESS;
+       OBJECT_ATTRIBUTES  BootstrapOkAttributes;
+       UNICODE_STRING     Name;
+
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       /*
+        * Create the event object the callback port
+        * thread will signal *if* the SM will
+        * authorize us to bootstrap.
+        */
+       RtlInitUnicodeString (& Name, L"\\CsrssBooting");
+       InitializeObjectAttributes(& BootstrapOkAttributes,
+                                  & Name,
+                                  0, NULL, NULL);
+       Status = NtCreateEvent (& hBootstrapOk,
+                               EVENT_ALL_ACCESS,
+                               & BootstrapOkAttributes,
+                               SynchronizationEvent,
+                               FALSE);
+       if(!NT_SUCCESS(Status))
+       {
+               DPRINT("CSR: %s: NtCreateEvent failed (Status=0x%08lx)\n",
+                       __FUNCTION__, Status);
+               return Status;
+       }
+       /*
+        * Let's tell the SM a new environment
+        * subsystem server is in the system.
+        */
+       RtlInitUnicodeString (& Name, L"\\Windows\\SbApiPort");
+       DPRINT("CSR: %s: registering with SM for\n  IMAGE_SUBSYSTEM_WINDOWS_CUI == 3\n", __FUNCTION__);
+       Status = SmConnectApiPort (& Name,
+                                  hSbApiPort,
+                                  IMAGE_SUBSYSTEM_WINDOWS_CUI,
+                                  & hSmApiPort);
+       if(!NT_SUCCESS(Status))
+       {
+               DPRINT("CSR: %s unable to connect to the SM (Status=0x%08lx)\n",
+                       __FUNCTION__, Status);
+               NtClose (hBootstrapOk);
+               return Status;
+       }
+       /*
+        *  Wait for SM to reply OK... If the SM
+        *  won't answer, we hang here forever!
+        */
+       DPRINT("CSR: %s: waiting for SM to OK boot...\n", __FUNCTION__);
+       Status = NtWaitForSingleObject (hBootstrapOk,
+                                       FALSE,
+                                       NULL);
+       NtClose (hBootstrapOk);
+       return Status;  
+}
+
+/**********************************************************************
+ * CsrpCreateApiPort/0
+ */
+static NTSTATUS
+CsrpCreateApiPort (ULONG argc, PWSTR* argv)
+{
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       return CsrpCreateListenPort (L"\\Windows\\ApiPort",
+                                    & hApiPort,
+                                    ServerApiPortThread);
+}
+
+/**********************************************************************
+ * CsrpApiRegisterDef/0
+ */
+static NTSTATUS
+CsrpApiRegisterDef (ULONG argc, PWSTR* argv)
+{
+       return CsrApiRegisterDefinitions(NativeDefinitions);
+}
+
+/**********************************************************************
+ * CsrpCCTS/2
+ */
+static NTSTATUS
+CsrpCCTS (ULONG argc, PWSTR* argv)
+{
+       return CsrClientConnectToServer();
+}
+
+/**********************************************************************
+ * CsrpRunWinlogon/0
+ *
+ * Start the logon process (winlogon.exe).
+ *
+ * TODO: this should be moved in CsrpCreateSession/x (one per session)
+ * TODO: in its own desktop (one logon desktop per winstation).
+ */
+static NTSTATUS
+CsrpRunWinlogon (ULONG argc, PWSTR* argv)
+{
+       NTSTATUS                      Status = STATUS_SUCCESS;
+       UNICODE_STRING                ImagePath;
+       UNICODE_STRING                CommandLine;
+       PRTL_USER_PROCESS_PARAMETERS  ProcessParameters = NULL;
+       RTL_PROCESS_INFO              ProcessInfo;
+
+
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       /* initialize the process parameters */
+       RtlInitUnicodeString (& ImagePath, L"\\SystemRoot\\system32\\winlogon.exe");
+       RtlInitUnicodeString (& CommandLine, L"");
+       RtlCreateProcessParameters(& ProcessParameters,
+                                  & ImagePath,
+                                  NULL,
+                                  NULL,
+                                  & CommandLine,
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  NULL,
+                                  NULL);
+       /* Create the winlogon process */
+       Status = RtlCreateUserProcess (& ImagePath,
+                                      OBJ_CASE_INSENSITIVE,
+                                      ProcessParameters,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      FALSE,
+                                      NULL,
+                                      NULL,
+                                      & ProcessInfo);
+       /* Cleanup */
+       RtlDestroyProcessParameters (ProcessParameters);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT1("SM: %s: loading winlogon.exe failed (Status=%08lx)\n",
+                               __FUNCTION__, Status);
+       }
+   ZwResumeThread(ProcessInfo.ThreadHandle, NULL);
+       return Status;
+}
+
+
+
+typedef NTSTATUS (* CSR_INIT_ROUTINE)(ULONG, PWSTR*);
+
+struct {
+       BOOL Required;
+       CSR_INIT_ROUTINE EntryPoint;
+       PCHAR ErrorMessage;
+} InitRoutine [] = {
+       {TRUE, CsrpCreateCallbackPort, "create the callback port \\Windows\\SbApiPort"},
+       {TRUE, CsrpRegisterSubsystem,  "register with SM"},
+       {TRUE, CsrpCreateHeap,         "create the CSR heap"},
+       {TRUE, CsrpCreateApiPort,      "create the api port \\Windows\\ApiPort"},
+       {TRUE, CsrpParseCommandLine,   "parse the command line"},
+       {TRUE, CsrpInitVideo,          "initialize video"},
+       {TRUE, CsrpApiRegisterDef,     "initialize api definitions"},
+       {TRUE, CsrpCCTS,               "connect client to server"},
+       {TRUE, CsrpInitWin32Csr,       "load usermode dll"},
+       {TRUE, CsrpRunWinlogon,        "run WinLogon"},
+};
 
 /**********************************************************************
  * NAME
  *     CsrServerInitialization
  *
  * DESCRIPTION
- *     Create a directory object (\windows) and a named LPC port
- *     (\windows\ApiPort)
+ *     Initialize the Win32 environment subsystem server.
  *
  * RETURN VALUE
  *     TRUE: Initialization OK; otherwise FALSE.
  */
-BOOL
-STDCALL
+BOOL STDCALL
 CsrServerInitialization (
        ULONG ArgumentCount,
        PWSTR *ArgumentArray
        )
 {
-  NTSTATUS Status;
-  OBJECT_ATTRIBUTES ObAttributes;
-  UNICODE_STRING PortName;
-  HANDLE ApiPortHandle;
-
-  Status = CsrParseCommandLine (ArgumentCount, ArgumentArray);
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to parse the command line (Status: %x)\n", Status);
-      return FALSE;
-    }
-
-  CsrIsCsrss( );
-  CsrInitVideo();
-
-  Win32kInitialize();
-
-  CsrssApiHeap = RtlCreateHeap(HEAP_GROWABLE,
-                               NULL,
-                               65536,
-                               65536,
-                               NULL,
-                               NULL);
-  if (CsrssApiHeap == NULL)
-    {
-      DPRINT1("CSR: Failed to create private heap, aborting\n");
-      return FALSE;
-    }
-
-  Status = CsrApiRegisterDefinitions(NativeDefinitions);
-  if (! NT_SUCCESS(Status))
-    {
-      return Status;
-    }
-
-  Status = InitWin32Csr();
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to load usermode dll (Status %x)\n", Status);
-      return FALSE;
-    }
-
-  /* NEW NAMED PORT: \ApiPort */
-  RtlRosInitUnicodeStringFromLiteral(&PortName, L"\\Windows\\ApiPort");
-  InitializeObjectAttributes(&ObAttributes,
-                             &PortName,
-                             0,
-                             NULL,
-                             NULL);
-  Status = NtCreatePort(&ApiPortHandle,
-                        &ObAttributes,
-                        260,
-                        328,
-                        0);
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to create \\ApiPort (Status %x)\n", Status);
-      return FALSE;
-    }
-  Status = RtlCreateUserThread(NtCurrentProcess(),
-                               NULL,
-                               FALSE,
-                               0,
-                               NULL,
-                               NULL,
-                               (PTHREAD_START_ROUTINE)Thread_Api,
-                               ApiPortHandle,
-                               NULL,
-                               NULL);
-  if (! NT_SUCCESS(Status))
-    {
-      DPRINT1("CSR: Unable to create server thread\n");
-      NtClose(ApiPortHandle);
-      return FALSE;
-    }
-
-  return TRUE;
+       INT       i = 0;
+       NTSTATUS  Status = STATUS_SUCCESS;
+
+       DPRINT("CSR: %s called\n", __FUNCTION__);
+
+       for (i=0; i < (sizeof InitRoutine / sizeof InitRoutine[0]); i++)
+       {
+               Status = InitRoutine[i].EntryPoint(ArgumentCount,ArgumentArray);
+               if(!NT_SUCCESS(Status))
+               {
+                       DPRINT1("CSR: %s: failed to %s (Status=%08lx)\n", 
+                               __FUNCTION__,
+                               InitRoutine[i].ErrorMessage,
+                               Status);
+                       if (InitRoutine[i].Required)
+                       {
+                               return FALSE;
+                       }
+               }
+       }
+       if (CallInitComplete())
+       {
+               Status = SmCompleteSession (hSmApiPort,hSbApiPort,hApiPort);
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /* EOF */