Finished and deployed CORBA sandbox separation
[captive.git] / src / libcaptive / client / init.c
index c093103..bfeb479 100644 (file)
 
 #include "config.h"
 
-#include "captive/client.h"    /* self */
 #include "captive/ldr.h"
 #include "captive/ldr_exports.h"
 #include "captive/unicode.h"
-#include "captive/file.h"
+#include "captive/rtl-file.h"
 #include <glib/gtypes.h>
 #include <glib/gmessages.h>
 #include "reactos/internal/ldr.h"
 #include "captive/storage.h"
 #include "captive/signal.h"    /* for captive_signal_init() */
 #include "reactos/ddk/psfuncs.h"       /* for PsGetCurrentThread() */
+#include <stdio.h>
+#include <popt.h>
+#include <glib/gstrfuncs.h>
+#include <glib/glist.h>
+#include "giochannel-blind.h"
+#include <glib-object.h>
+#include "reactos/internal/se.h"       /* for SeInit2() */
+#include "captive/leave.h"
+#include "captive/options.h"
 
 
+struct captive_options *captive_options;
+
 /* Are we initialized? */
 static gboolean active;
 
-/* Module of fs module itself loaded by captive_init(fs_path) */
+/* Module of fs module itself loaded by captive_w32_init() */
 static PMODULE_OBJECT ModuleObject;
 
-/* Driver in fs module loaded by captive_init(fs_path) */
-static DRIVER_OBJECT DriverObject;
-
-/* Handle for the root directory of the mounted volume */
-static HANDLE root_Handle;
+/* Driver in fs module loaded by captive_w32_init() */
+DRIVER_OBJECT captive_DriverObject;
+PDRIVER_REINITIALIZE captive_DriverObject_ReinitRoutine;
+PVOID captive_DriverObject_ReinitRoutine_Context;
 
 /* Structure holding the pointer to the toplevel IRP */
 static TOP_LEVEL_IRP TopLevelIrp;      /* TODO:thread */
 
 
-/**
- * captive_init:
- * @fs_path: Host OS file #utf8 pathname of the filesystem module to load.
- * %NULL value is forbidden.
- * @image_pathname: Host OS file #utf8 pathname of the disk image to mount.
- * %NULL value is forbidden.
- *
- * Initializes %libcaptive and loads the specified filesystem.
- *
- * Returns: %TRUE if successfuly loaded.
- */
-gboolean captive_init(const gchar *fs_path,const gchar *image_pathname)
+void *_local_unwind2_addr;
+
+
+/* Acceleration hack for ntoskrnl/dbg/print.c/DbgPrint() */
+gboolean captive_get_debug_messages(void)
+{
+       g_return_val_if_fail(captive_options!=NULL,TRUE);
+
+       return captive_options->debug_messages;
+}
+
+
+static gboolean captive_w32_init(void)
 {
 NTSTATUS err;
 gboolean errbool;
-OBJECT_ATTRIBUTES root_ObjectAttributes;
-IO_STATUS_BLOCK root_IoStatusBlock;
-#if 0
-FILE_ID_BOTH_DIR_INFORMATION *FileIdBothDirInformation;
-#endif
-char QueryDirectory_buf[0x10000];
+GIOStatus erriostatus;
 
-#ifdef MAINTAINER_MODE
-       g_log_set_always_fatal(~(0
-                       |G_LOG_LEVEL_MESSAGE
-                       |G_LOG_LEVEL_INFO
-                       |G_LOG_LEVEL_DEBUG
-                       ));
-#endif
+       g_return_val_if_fail(captive_options!=NULL,FALSE);
+       g_return_val_if_fail(captive_options->filesystem!=NULL,FALSE);
 
-       g_return_val_if_fail(fs_path!=NULL,FALSE);
-       g_return_val_if_fail(image_pathname!=NULL,FALSE);
-       g_return_val_if_fail(active==FALSE,FALSE);
+       erriostatus=g_io_channel_set_encoding(captive_image_iochannel,
+                       NULL,   /* encoding; force binary data */
+                       NULL);  /* error */
+       g_assert(erriostatus==G_IO_STATUS_NORMAL);
+
+       /* captive_giochannel_size() only _after_ g_io_channel_set_encoding() ! */
+       captive_image_size=captive_giochannel_size(captive_image_iochannel);
+       g_return_val_if_fail(captive_image_size>0,FALSE);
 
        /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() begins. */
        /* ExpInitializeExecutive(); */
@@ -99,12 +104,21 @@ char QueryDirectory_buf[0x10000];
                        /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() begins. */
                        InitializeListHead(&ModuleTextListHead);
                        /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() ends. */
+               KeLowerIrql(DISPATCH_LEVEL);
                /*...*/
                /* create default nls tables */
                RtlpInitNlsTables();
                /*...*/
+               /* KeInit2() */
+                       /*...*/
+                       KeInitializeDispatcher();
+                       /*...*/
+               KeLowerIrql(PASSIVE_LEVEL);
+               errbool=SeInit1();
+               g_assert(errbool==TRUE);
                ObInit();
-               /*...*/
+               errbool=SeInit2();
+               g_assert(errbool==TRUE);
                /* PiInitProcessManager(); */
                        /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() begins. */
                        PsInitProcessManagment();
@@ -122,115 +136,218 @@ char QueryDirectory_buf[0x10000];
                        InitializeListHead(&ModuleListHead);
                        KeInitializeSpinLock(&ModuleListLock);
                        /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement ends. */
+               /*...*/
+               /* Ntinit(); */
+                       NtInitializeEventImplementation();
+                       /*...*/
                /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() ends. */
        /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() ends. */
 
-       /* Simulate our PE headers and export the symbols of {NTOSKRNL,HAL} */
+       /* Simulate our PE headers and export the symbols of our complete libraries */
        captive_kernel_exports();
 
-       errbool=captive_cdrom_init(image_pathname);
+       errbool=captive_cdrom_init();
+       g_return_val_if_fail(errbool==TRUE,FALSE);
+       errbool=captive_disk_init();
        g_return_val_if_fail(errbool==TRUE,FALSE);
 
-       err=captive_LdrpLoadAndCallImage(
-                       &ModuleObject,  /* ModuleObjectp */
-                       captive_utf8_to_UnicodeString_alloca(fs_path),  /* ModuleName */
-                       &DriverObject,  /* DriverEntry_DriverObject */
-                       captive_utf8_to_UnicodeString_alloca("\\captive\\filesystem")); /* DriverEntry_RegistryPath */
-       g_return_val_if_fail(NT_SUCCESS(err),FALSE);
+       while (captive_options->load_module) {
+gchar *modulename=captive_options->load_module->data;
+PMODULE_OBJECT ModuleObject_tmp;
+NTSTATUS err;
+
+               /* load the module */
+               err=LdrLoadModule(
+                               captive_utf8_to_UnicodeString_alloca(modulename),       /* ModuleName */
+                               &ModuleObject_tmp);     /* ModuleObjectp */
+               g_return_val_if_fail(NT_SUCCESS(err),FALSE);
+
+               captive_options->load_module=g_list_remove(captive_options->load_module,modulename);
+               }
+
+       /* Patch 'ntoskrnl.exe' loaded by 'captive_options->load_module' above. */
+       {
+       CHAR *KeNumberProcessorsp=captive_Module_GetExportAddress("ntoskrnl.exe","KeNumberProcessors");
+       
+               g_assert(*KeNumberProcessorsp==0);
+               *KeNumberProcessorsp=KeNumberProcessors;
+               g_assert(*KeNumberProcessorsp==1);
+               }
+       /* Apply captive_kernel_patches() AFTER any symbols sanity checks above! */
+       captive_kernel_patches();
+
+       _local_unwind2_addr=captive_Module_GetExportAddress("ntoskrnl.exe","_local_unwind2");
+
+       /* Initialize 'FsRtlLegalAnsiCharacterArray'.
+        * It requires 'ntoskrnl.exe' loaded by 'captive_options->load_module' above;
+        * captive_kernel_patches() should not be needed.
+        */
+       captive_FsRtlLegalAnsiCharacterArray_init();
 
        /* set TopLevelIrp() - FIXME: where is it set by native reactos? */
        PsGetCurrentThread()->TopLevelIrp=&TopLevelIrp; /* otherwise Io{Get,Set}TopLevelIrp() would SIGSEGV */
 
        /* Begin possible handling of foreign W32 binary code here */
+       /* If you want to disable SIGSEGV handler if not needed:
+        *      if (ModuleObject->Flags & MODULE_FLAG_PE)
+        */
        captive_signal_init();
 
-       /* Do not open "\Cdfs"(anything) as it is just the filesystem implementation.
-        * ntoskrnl/io/fs.c/IoMountVolume() will map
-        *      FILE_DEVICE_CD_ROM -> FILE_DEVICE_CD_ROM_FILE_SYSTEM
-        * for us automatically when opening the device itself.
-        * Also you must put some trailing content there as otherwise
-        *      IoCreateFile()->ObCreateObject()->ObFindObject()
-        * would leave 'ObCreateObject::RemainingPath' as NULL
-        * and later IopCreateFile() would consider it FO_DIRECT_DEVICE_OPEN (e.g. w/o any mount!)
-        */
-       InitializeObjectAttributes(
-                       &root_ObjectAttributes, /* InitializedAttributes */
-                       captive_utf8_to_UnicodeString_alloca("\\Device\\CdRom0\\."),    /* ObjectName */
-                       0,      /* Attributes; I hope no OBJ_KERNEL_HANDLE as we are 'system process' */
-                       NULL,   /* RootDirectory */
-                       NULL);  /* SecurityDescriptor; ignored */
-
-       /* wanted: * IoCreateFile()->ObCreateObject(,,,IoFileObjectType)->
-        * ->(IoFileObjectType->Create==IopCreateFile)()->IoMountVolume()
+       /* You must have already captive_signal_init() passed here as the module may
+        * call some functions from W32 ntoskrnl.exe.
         */
-       err=IoCreateFile(
-                       &root_Handle,   /* FileHandle */
-                       FILE_LIST_DIRECTORY,    /* DesiredAccess */
-                       &root_ObjectAttributes, /* ObjectAttributes */
-                       &root_IoStatusBlock,    /* IoStatusBlock */
-                       NULL,   /* AllocationSize; ignored for open */
-                       FILE_ATTRIBUTE_NORMAL,  /* FileAttributes; ignored for open */
-                       0,      /* ShareAccess; 0 means exclusive */
-                       FILE_OPEN,      /* CreateDisposition */
-                       /* FILE_SYNCHRONOUS_IO_{,NON}ALERT: We need to allow W32 filesystem
-                        * any waits to not to let it return STATUS_CANT_WAIT us.
-                        * Alertability should have only effect on asynchronous events
-                        * from KeWaitForSingleObject() by setting/clearing its parameter 'Alertable'.
-                        */
-                       FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_ALERT,  /* CreateOptions */
-                       NULL,   /* EaBuffer */
-                       0,      /* EaLength */
-                       CreateFileTypeNone,     /* CreateFileType */
-                       NULL,   /* ExtraCreateParameters */
-                       0);     /* Options */
-       g_return_val_if_fail(NT_SUCCESS(err),FALSE);
-       g_return_val_if_fail(NT_SUCCESS(root_IoStatusBlock.Status),FALSE);
-       g_return_val_if_fail(root_IoStatusBlock.Information==FILE_OPENED,FALSE);
-
-
-       err=NtQueryDirectoryFile(
-                       root_Handle,    /* FileHandle */
-      NULL,    /* PEvent; completion signalling; optional */
-                       NULL,   /* ApcRoutine; optional */
-                       NULL,   /* ApcContext; optional */
-                       &root_IoStatusBlock,    /* IoStatusBlock */
-                       (gpointer)QueryDirectory_buf,   /* FileInformation */
-                       sizeof(QueryDirectory_buf),     /* Length */
-                       FileIdBothDirectoryInformation, /* FileInformationClass; =>FILE_ID_BOTH_DIR_INFORMATION */
-                       FALSE,  /* ReturnSingleEntry */
-                       NULL,   /* FileName; wildcards possible; optional */
-                       TRUE);  /* RestartScan */
+       captive_DriverObject_ReinitRoutine=NULL;
+       err=captive_LdrpLoadAndCallImage(
+                       &ModuleObject,  /* ModuleObjectp */
+                       captive_utf8_to_UnicodeString_alloca(captive_options->filesystem),      /* ModuleName */
+                       &captive_DriverObject,  /* DriverEntry_DriverObject */
+                       captive_utf8_to_UnicodeString_alloca("\\captive\\filesystem")); /* DriverEntry_RegistryPath */
        g_return_val_if_fail(NT_SUCCESS(err),FALSE);
-       g_return_val_if_fail(NT_SUCCESS(root_IoStatusBlock.Status),FALSE);
+       if (captive_DriverObject_ReinitRoutine) {
+               (*captive_DriverObject_ReinitRoutine)(
+                               &captive_DriverObject,  /* DriverObject */
+                               captive_DriverObject_ReinitRoutine_Context,     /* Context */
+                               1);     /* Count: # of calls of ReinitRoutine incl. the current one */
+               }
+
+       return TRUE;
+}
+
+
+static void    log_discard_func(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
+{
+       /* NOP */
+}
+
+
+/**
+ * captive_init:
+ *
+ * Expects #captive_options: Parsed by captive_options_parse().
+ * %NULL value is forbidden. Field #image_iochannel %NULL value is forbidden.
+ *
+ * Initializes %libcaptive and loads the specified filesystem.
+ *
+ * Returns: %TRUE if successfuly initialized.
+ */
+gboolean captive_init(void)
+{
+gboolean errbool;
 
+#ifdef MAINTAINER_MODE
+       g_log_set_always_fatal(~(0
+                       |G_LOG_LEVEL_MESSAGE
+                       |G_LOG_LEVEL_INFO
+                       |G_LOG_LEVEL_DEBUG
+                       ));
+#endif
+
+       g_return_val_if_fail(active==FALSE,FALSE);
+
+       g_return_val_if_fail(captive_options!=NULL,FALSE);
+       g_return_val_if_fail(captive_options->image_iochannel!=NULL,FALSE);
+
+       /* Initialize GObject subsystem of GLib. */
+       g_type_init();
+
+       if (!captive_options->debug_messages) {
+               g_log_set_handler(
+                               G_LOG_DOMAIN,   /* log_domain; "Captive" */
+                               0       /* log_levels */
+                                               | G_LOG_FLAG_RECURSION
+                                               | G_LOG_FLAG_FATAL
+                                               /* The same mask is in libcaptive/sandbox/server-GlibLogFunc.c ! */
+                                               | G_LOG_LEVEL_MESSAGE
+                                               | G_LOG_LEVEL_INFO
+                                               | G_LOG_LEVEL_DEBUG,
+                               log_discard_func,       /* log_func */
+                               NULL);  /* user_data */
+               }
+
+       if (captive_options->rwmode==CAPTIVE_OPTION_RWMODE_BLIND)
+               captive_image_iochannel=(GIOChannel *)captive_giochannel_blind_new(captive_options->image_iochannel);
+       else
+               captive_image_iochannel=captive_options->image_iochannel;
+
+       /* Do not initialize 'captive_image_size' by captive_giochannel_size() here
+        * as we yet need to do g_io_channel_set_encoding().
+        */
+
+       errbool=captive_w32_init();
+       g_return_val_if_fail(errbool==TRUE,FALSE);
 
        active=TRUE;
        return TRUE;
 }
 
 
+BOOLEAN captive_cc_FileObject_delete(FILE_OBJECT *FileObject);
+void captive_cc_flush(void);
+
 /**
- * captive_cleanup:
- *
- * Closes #libcaptive. Frees any used system resources. You are forbidden
- * to touch any #libcaptive data or funtions before a new captive_init()
- * is done. Forbidden to call it before successful captive_init() is done.
+ * captive_shutdown:
  *
- * Currently this function IS NOT IMPLEMENTED.
+ * Closes down %libcaptive. It should flush all pending buffers and successfuly
+ * close the filesystem. Variable #captive_options->image_iochannel will not be set to %NULL,
+ * you should close such channel yourself.
  *
- * Returns: %TRUE if the successful resource cleanup was done during the call.
+ * Returns: %TRUE if successfuly shutdown.
  */
-gboolean captive_cleanup(void)
+gboolean captive_shutdown(void)
 {
-NTSTATUS err;
+GIOStatus erriostatus;
 
        g_return_val_if_fail(active==TRUE,FALSE);
+       g_return_val_if_fail(captive_image_iochannel!=NULL,FALSE);
+       g_return_val_if_fail(captive_options->image_iochannel!=NULL,FALSE);
+
+       /* Invoke all pending idle functions just to not to forget for anything... */
+       while (g_main_context_iteration(
+                       NULL,   /* context; NULL means default one */
+                       FALSE)) /* may_block */
+               g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: g_main_context_iteration() proceeded",G_STRLOC);
+
+       captive_PoQueueShutdownWorkItem_hooklist_invoke();
+       captive_cc_flush();
+
+       /* During IoShutdownRegisteredFileSystems() - IRP_MJ_SHUTDOWN to be specific
+        * some buffers will be written but after the IofCallDriver() it will be
+        * no longer possible to flush such buffers to their DeviceVolumeFile.
+        * Therefore we must flush such buffers on the fly although such behaviour
+        * would crash us in regular case as filesystems access BCBs even after their
+        * CcUnpinData().
+        */
+       captive_cc_unmounting=TRUE;
+
+       /* FIXME: ntoskrnl/ex/power.c/NtShutdownSystem() does
+        * IoShutdownRegistered{Devices,FileSystems} order; is it correct?
+        */
+       IoShutdownRegisteredFileSystems();
+
+       /* Just a sanity check as all the dirty data should
+        * get already flushed during IoShutdownRegisteredFileSystems().
+        */
+       captive_cc_FileObject_delete(
+                       NULL);  /* FileObject */
+
+       IoShutdownRegisteredDevices();
+
+       /* libcaptive is not authorized to shutdown 'captive_image_channel'. */
+       erriostatus=g_io_channel_flush(
+                       captive_image_iochannel,        /* channel */
+                       NULL);  /* error */
+       g_assert(erriostatus==G_IO_STATUS_NORMAL);
 
-       err=LdrUnloadModule(ModuleObject);
-       g_assert(NT_SUCCESS(err));
+       /* 'captive_image_iochannel' may be blinded wrapper of 'captive_options->image_iochannel'. */
+       if (captive_image_iochannel!=captive_options->image_iochannel) {
+               erriostatus=g_io_channel_flush(
+                               captive_options->image_iochannel,       /* channel */
+                               NULL);  /* error */
+               g_assert(erriostatus==G_IO_STATUS_NORMAL);
+               g_io_channel_unref(captive_image_iochannel);
+               }
 
-       /* captive_cleanup() NOT IMPLEMENTED */
-       g_return_val_if_reached(FALSE);
+       captive_image_iochannel=NULL;
 
        active=FALSE;
        return TRUE;