X-Git-Url: http://git.jankratochvil.net/?a=blobdiff_plain;f=src%2Flibcaptive%2Fsandbox%2Fsplit.c;h=72107a1ef7470ee9da3d71373f891afd6a6f66c3;hb=d9ed28783f1fead15ddacd50782e3c7fdc004b7d;hp=021d03f57e962975aab9ca2ab73798c0eb1a07f3;hpb=b0ea568364223ff4e8bb5a6bf03f23bc7e211f36;p=captive.git diff --git a/src/libcaptive/sandbox/split.c b/src/libcaptive/sandbox/split.c index 021d03f..72107a1 100644 --- a/src/libcaptive/sandbox/split.c +++ b/src/libcaptive/sandbox/split.c @@ -21,7 +21,7 @@ #include "split.h" /* self */ #include "sandbox.h" -#include "server-GlibLogFunc.h" +#include "server-GLogFunc.h" #include "captive/macros.h" #include #include @@ -29,9 +29,15 @@ #include #include #include /* for linc_main_get_loop() */ -#include "server-GlibLogFunc.h" #include "server-Directory.h" #include "server-Vfs.h" +#include "../client/vfs.h" +#include "parent-Vfs.h" +#include +#include "server-CaptiveIOChannel.h" +#include +#include "../client/giochannel-blind.h" /* for captive_giochannel_blind_new() */ +#include /* CONFIG: */ @@ -40,16 +46,26 @@ #define HEARTBEAT_SOURCE_CHECK_REVENTS (HEARTBEAT_SOURCE_CHECK_EVENTS|G_IO_ERR|G_IO_HUP|G_IO_NVAL) -gboolean validate_CORBA_Environment(const CORBA_Environment *evp) +gboolean validate_CORBA_Environment(CORBA_Environment *evp) { - g_return_val_if_fail(evp->_major==CORBA_NO_EXCEPTION,FALSE); + if (evp->_major==CORBA_NO_EXCEPTION) + return TRUE; - return TRUE; + g_error(_("CORBA Exception occured: id=\"%s\", value=%p"), + CORBA_exception_id(evp),CORBA_exception_value(evp)); + CORBA_exception_free(evp); + return FALSE; } +CORBA_Environment captive_corba_ev; +CORBA_ORB captive_corba_orb; +PortableServer_POA captive_corba_poa; + +static void corba_shutdown_atexit(void); static gboolean corba_init(const char *pname,CORBA_Environment *evp,CORBA_ORB *orbp,PortableServer_POA *poap) { +static gboolean done=FALSE; int orb_argc=1; gchar *orb_argv[]={ (gchar *)captive_strdup_alloca(pname), @@ -59,6 +75,9 @@ gchar *orb_argv[]={ g_return_val_if_fail(orbp!=NULL,FALSE); g_return_val_if_fail(poap!=NULL,FALSE); + if (done) + return TRUE; /* FIXME: '*poap' is left invalid! */ + /* Init 'ev' */ CORBA_exception_init(evp); @@ -80,13 +99,16 @@ PortableServer_POAManager poa_mgr; g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE); } + g_atexit(corba_shutdown_atexit); + + done=TRUE; return TRUE; } static CORBA_ORB heartbeat_source_callback_orb=CORBA_OBJECT_NIL; -static gboolean corba_shutdown(CORBA_Environment *evp,CORBA_ORB *orbp,PortableServer_POA *poap) +gboolean corba_shutdown(CORBA_Environment *evp,CORBA_ORB *orbp,PortableServer_POA *poap) { PortableServer_POA poa; CORBA_ORB orb; @@ -106,7 +128,11 @@ CORBA_ORB orb; *orbp=CORBA_OBJECT_NIL; heartbeat_source_callback_orb=CORBA_OBJECT_NIL; CORBA_ORB_destroy(orb,evp); - g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE); + /* Do not: g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE); + * here as CORBA_ORB_destroy() sometimes reports: + * WARNING **: ORB: a total of X refs to X ORB objects were leaked + */ + CORBA_exception_free(evp); /* Shutdown 'ev' */ CORBA_exception_free(evp); @@ -114,234 +140,796 @@ CORBA_ORB orb; return TRUE; } +static void sandbox_parent_own_orbit_dir_cleanup_atexit(void); -static gboolean corba_servant_object_destroy(PortableServer_POA poa,CORBA_Object reference,CORBA_Environment *evp) +static void corba_shutdown_atexit(void) { -PortableServer_ObjectId *objid; -PortableServer_Servant servant; +gboolean errbool; - g_return_val_if_fail(poa!=CORBA_OBJECT_NIL,FALSE); - g_return_val_if_fail(reference!=CORBA_OBJECT_NIL,FALSE); - g_return_val_if_fail(evp!=NULL,FALSE); + errbool=corba_shutdown(&captive_corba_ev,&captive_corba_orb,&captive_corba_poa); + g_assert(errbool==TRUE); - objid=PortableServer_POA_reference_to_id(poa,reference,evp); - g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE); - servant=PortableServer_POA_reference_to_servant(poa,reference,evp); - g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE); - PortableServer_POA_deactivate_object(poa,objid,evp); - g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE); - CORBA_free(objid); - (*((PortableServer_ServantBase *)servant)->vepv[0]->finalize)(servant,evp); - g_return_val_if_fail(validate_CORBA_Environment(evp),FALSE); - g_free(servant); + /* Delete the CORBA ORB socket directory only after full CORBA ORB shutdown. */ + sandbox_parent_own_orbit_dir_cleanup_atexit(); +} - return TRUE; + +static GSource *captive_corba_sandbox_child_heartbeat_gsource; + +#if 0 /* Currently unused - see server-Vfs.c:impl_Captive_Vfs_shutdown() */ +void sandbox_child_prepare_shutdown(void) +{ + /* Prevent during shutdown: Captive-WARNING **: CORBA Exception occured: id="IDL:omg.org/CORBA/COMM_FAILURE:1.0" */ + if (captive_corba_sandbox_child_heartbeat_gsource) { + g_source_destroy(captive_corba_sandbox_child_heartbeat_gsource); + g_source_unref(captive_corba_sandbox_child_heartbeat_gsource); + captive_corba_sandbox_child_heartbeat_gsource=NULL; + } } +#endif -static gboolean heartbeat_source_callback(gpointer data /* unused */) +void sandbox_child_shutdown(void) { -CORBA_Environment ev; + /* Do not fail by passing logging messages to the master. */ + impl_Captive_Vfs_init_g_log_func_disable(); + + g_main_loop_quit(linc_main_get_loop()); +} + +static gboolean heartbeat_source_callback(gpointer data /* unused */) +{ g_return_val_if_fail(heartbeat_source_callback_orb!=CORBA_OBJECT_NIL,FALSE); /* the source should be removed */ - CORBA_exception_init(&ev); - /* CORBA_ORB_shutdown() is not enough as 'init_level' still >0 */ - CORBA_ORB_destroy( - heartbeat_source_callback_orb, /* orb */ - &ev); /* ev */ - g_assert(validate_CORBA_Environment(&ev)); - CORBA_exception_free(&ev); + sandbox_child_shutdown(); return FALSE; /* the source should be removed */ } -static void sandbox_child(int Vfs_IOR_fd_write,GSource *gsource) G_GNUC_NORETURN; -static void sandbox_child(int Vfs_IOR_fd_write,GSource *gsource) +static gboolean heartbeat_source_prepare(GSource *source,gint *timeout) +{ + *timeout=-1; + + return FALSE; +} + +static GPollFD heartbeat_source_check_gpollfd; + +static gboolean heartbeat_source_check(GSource *source) +{ + return !!(heartbeat_source_check_gpollfd.revents & HEARTBEAT_SOURCE_CHECK_REVENTS); +} + +static gboolean heartbeat_source_dispatch(GSource *source,GSourceFunc callback,gpointer user_data) +{ + g_assert(callback!=NULL); + return (*callback)(user_data); +} + +static GSourceFuncs heartbeat_source_watch_funcs={ + heartbeat_source_prepare, + heartbeat_source_check, + heartbeat_source_dispatch, + NULL, /* finalize */ + }; + +void captive_corba_sandbox_child(const gchar *chrooted_orbit_dir) { -CORBA_Environment ev; -CORBA_ORB orb; -PortableServer_POA poa; Captive_Vfs Vfs_object; +impl_POA_Captive_Vfs *Vfs_servant; gboolean errbool; -int errint; guint errguint; +int errint; - errbool=corba_init("sandbox_child",&ev,&orb,&poa); - g_assert(errbool==TRUE); - heartbeat_source_callback_orb=orb; + /* attach heartbeat_source_callback() to watch for any abnormalities + * on our open pipe 'parentheart_fds' and terminate the child if parent dies. + */ + captive_corba_sandbox_child_heartbeat_gsource=g_source_new(&heartbeat_source_watch_funcs,sizeof(GSource)); + g_return_if_fail(captive_corba_sandbox_child_heartbeat_gsource!=NULL); + g_source_set_callback( + captive_corba_sandbox_child_heartbeat_gsource, /* source */ + heartbeat_source_callback, /* func */ + NULL, /* data */ + NULL); /* notify */ + heartbeat_source_check_gpollfd.fd=0 /* STDIN */; /* parentheart_fd_read */ + heartbeat_source_check_gpollfd.events=HEARTBEAT_SOURCE_CHECK_EVENTS; + heartbeat_source_check_gpollfd.revents=0; + g_source_add_poll(captive_corba_sandbox_child_heartbeat_gsource,&heartbeat_source_check_gpollfd); + + errbool=corba_init("captive-sandbox-child",&captive_corba_ev,&captive_corba_orb,&captive_corba_poa); + g_return_if_fail(errbool==TRUE); + + heartbeat_source_callback_orb=captive_corba_orb; /* linc_main_get_loop() makes sense only after corba_init() -> CORBA_ORB_init() */ errguint=g_source_attach( - gsource, /* source */ + captive_corba_sandbox_child_heartbeat_gsource, /* source */ g_main_loop_get_context(linc_main_get_loop())); /* context; NULL means 'default context' */ g_assert(errguint!=0); /* Init 'Vfs_object' */ - Vfs_object=impl_Captive_Vfs__create(poa,&ev); - g_assert(validate_CORBA_Environment(&ev)); + Vfs_object=impl_Captive_Vfs__create(captive_corba_poa,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); - /* pass IOR to our parent */ + /* Pass IOR to our parent. + * It will also create the socket needed for 'chrooted_orbit_dir' below + * by CORBA_ORB_object_to_string()->ORBit_marshal_object()->IOP_generate_profiles()->ORBit_ORB_start_servers... + */ { char *Vfs_IOR; - Vfs_IOR=CORBA_ORB_object_to_string(orb,Vfs_object,&ev); - g_assert(validate_CORBA_Environment(&ev)); + Vfs_IOR=CORBA_ORB_object_to_string(captive_corba_orb,Vfs_object,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); g_assert(Vfs_IOR!=NULL); - errint=write(Vfs_IOR_fd_write,Vfs_IOR,strlen(Vfs_IOR)+1); - g_assert((unsigned)errint==strlen(Vfs_IOR)+1); - errint=close(Vfs_IOR_fd_write); - g_assert(errint==0); + errint=printf("ior=%s\n",Vfs_IOR); + g_assert(errint>=0); CORBA_free(Vfs_IOR); } + /* Default mode is 0700, permit parent non-"captive" users to access our IOR socket. */ + if (chrooted_orbit_dir) { +DIR *dir; +struct dirent *dirent; +const gchar *socketname=NULL,*socketpathname; + + errint=chmod(chrooted_orbit_dir,0755); + g_assert(errint==0); + + dir=opendir(chrooted_orbit_dir); + g_assert(dir!=NULL); + while (errno=0,(dirent=readdir(dir))) { + if (!strcmp(dirent->d_name,".") || !strcmp(dirent->d_name,"..")) + continue; + g_assert(socketname==NULL); + socketname=captive_strdup_alloca(dirent->d_name); + } + g_assert(errno==0); + errint=closedir(dir); + g_assert(errint==0); + g_assert(socketname!=NULL); + + socketpathname=captive_printf_alloca("%s/%s",chrooted_orbit_dir,socketname); + errint=chmod(socketpathname,0666); + g_assert(errint==0); + + printf("socketname=%s\n",socketname); + } + + /* Close the output to flush it to our spawning parent. */ + errint=fflush(stdout); + g_assert(errint==0); + errint=fclose(stdout); + g_assert(errint==0); + /* CORBA_ORB_run() -> linc_main_loop_run() -> g_main_loop_run() * and therefore we should be safe with glib events handling. */ - CORBA_ORB_run(orb,&ev); - g_assert(validate_CORBA_Environment(&ev)); + CORBA_ORB_run(captive_corba_orb,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); /* Shutdown 'Vfs' servant */ - errbool=corba_servant_object_destroy(poa,Vfs_object,&ev); - g_assert(errbool==TRUE); - - errbool=corba_shutdown(&ev,&orb,&poa); + Vfs_servant=PortableServer_POA_reference_to_servant(captive_corba_poa,Vfs_object,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + CORBA_Object_release(Vfs_object,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + impl_Captive_Vfs__destroy(Vfs_servant,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + + errbool=corba_shutdown(&captive_corba_ev,&captive_corba_orb,&captive_corba_poa); g_assert(errbool==TRUE); _exit(EXIT_SUCCESS); } -static void sandbox_parent(int Vfs_IOR_fd_read) + +static void options_module_captive_to_options_module_corba + (Captive_CaptiveOptionsModule *dest_options_module_corba,const struct captive_options_module *src_options_module_captive) { -CORBA_Environment ev; -CORBA_ORB orb; -PortableServer_POA poa; -gboolean errbool; -char *Vfs_IOR; -gsize Vfs_IOR_size; -Captive_Directory directory_object; -Captive_Vfs Vfs_object; -Captive_GlibLogFunc GlibLogFunc_object; + g_return_if_fail(dest_options_module_corba!=NULL); + g_return_if_fail(src_options_module_captive!=NULL); + + g_return_if_fail(src_options_module_captive->type==CAPTIVE_OPTIONS_MODULE_TYPE_PE32); + + dest_options_module_corba->pathname_utf8=CORBA_string_dup(src_options_module_captive->pathname_utf8); + dest_options_module_corba->data._maximum=src_options_module_captive->u.pe32.length; + dest_options_module_corba->data._length =src_options_module_captive->u.pe32.length; + dest_options_module_corba->data._buffer=Captive_Bytes_allocbuf(dest_options_module_corba->data._maximum); + memcpy(dest_options_module_corba->data._buffer,src_options_module_captive->u.pe32.base, + src_options_module_captive->u.pe32.length); + dest_options_module_corba->data._release=TRUE; +} + +static void unlink_nonrecursive(const gchar *dirname) +{ +DIR *dir; +struct dirent *dirent; int errint; - errbool=corba_init("sandbox_parent",&ev,&orb,&poa); - g_return_if_fail(errbool==TRUE); + dir=opendir(dirname); + g_assert(dir!=NULL); - Vfs_IOR=captive_rtl_file_read(Vfs_IOR_fd_read,&Vfs_IOR_size); - g_assert(Vfs_IOR!=NULL); - g_assert(Vfs_IOR_size>=1); - g_assert(memchr(Vfs_IOR,0,Vfs_IOR_size)==Vfs_IOR+(Vfs_IOR_size-1)); /* check exactly for 0-terminated string */ - errint=close(Vfs_IOR_fd_read); + while (errno=0,(dirent=readdir(dir))) { +gchar *pathname; + + if (!strcmp(dirent->d_name,".") || !strcmp(dirent->d_name,"..")) + continue; + pathname=g_strdup_printf("%s/%s",dirname,dirent->d_name); + errint=unlink(pathname); + g_assert(errint==0); + g_free(pathname); + } + g_assert(errno==0); + errint=closedir(dir); + g_assert(errint==0); + errint=rmdir(dirname); g_assert(errint==0); +} - Vfs_object=CORBA_ORB_string_to_object(orb,Vfs_IOR,&ev); - g_assert(validate_CORBA_Environment(&ev)); - g_free(Vfs_IOR); +static const gchar *sandbox_parent_own_orbit_dir; +static const gchar *sandbox_parent_own_orbit_socket; - /* Init 'GlibLogFunc_object' */ - GlibLogFunc_object=impl_Captive_GlibLogFunc__create(poa,&ev); - g_assert(validate_CORBA_Environment(&ev)); - Captive_Vfs_registerGlibLogFunc(Vfs_object,GlibLogFunc_object,&ev); - g_assert(validate_CORBA_Environment(&ev)); +static void sandbox_parent_own_orbit_dir_cleanup_atexit(void) +{ +static gboolean done=FALSE; - directory_object=Captive_Vfs_directory_new_open(Vfs_object,"/directory",&ev); - g_assert(validate_CORBA_Environment(&ev)); - puts("TEST DONE"); + g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s; done=%d",G_STRLOC,(int)done); - /* Shutdown 'GlibLogFunc' servant */ - errbool=corba_servant_object_destroy(poa,GlibLogFunc_object,&ev); - g_assert(errbool==TRUE); + if (done) + return; + done=TRUE; + + if (sandbox_parent_own_orbit_dir) + unlink_nonrecursive(sandbox_parent_own_orbit_dir); +} + +static struct sandbox_parent_own_orbit_dir_cleanup_signal { + int signum; + /* FIXME: Why we cannot use 'sighandler_t'? */ void (*sighandler_orig)(int signum); + } sandbox_parent_own_orbit_dir_cleanup_signals[]={ + { SIGINT }, + { SIGQUIT }, + { SIGTERM }, + { SIGHUP }, + { SIGABRT }, + { SIGFPE }, + }; + +static void sandbox_parent_own_orbit_dir_cleanup_sighandler(int signum) +{ +struct sandbox_parent_own_orbit_dir_cleanup_signal *sigstructp; + + for ( + sigstructp=sandbox_parent_own_orbit_dir_cleanup_signals; + sigstructpsignum==signum) + break; + } + g_assert(sigstructpsighandler_orig); + + /* Prevent recursive fatal logging before signal restore: */ + /* Do not: g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: signum=%d,sighandler_orig=%p",G_STRLOC,signum,sigstructp->sighandler_orig); + * as it is dangerous to g_log() from sighandler. + */ - CORBA_Object_release(Vfs_object,&ev); - g_assert(validate_CORBA_Environment(&ev)); + sandbox_parent_own_orbit_dir_cleanup_atexit(); - errbool=corba_shutdown(&ev,&orb,&poa); + /* Do not: g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: re-raising...",G_STRLOC); + * as it is dangerous to g_log() from sighandler. + */ + raise(signum); +} + +static void sandbox_parent_own_orbit_dir_cleanup_init(void) +{ +struct sandbox_parent_own_orbit_dir_cleanup_signal *sigstructp; + + for ( + sigstructp=sandbox_parent_own_orbit_dir_cleanup_signals; + sigstructpsighandler_orig=signal(sigstructp->signum,sandbox_parent_own_orbit_dir_cleanup_sighandler); + if (sigstructp->sighandler_orig==SIG_IGN) + sigstructp->sighandler_orig=SIG_DFL; + } +} + +static gchar *sandbox_parent_read_ior + (int Vfs_IOR_fd_read,gchar **child_chroot_pid_hashkey_dirp,CaptiveVfsParentObject *captive_vfs_parent_object) +{ +gchar *data; +gsize data_size; +GHashTable *hash; +gchar *ior,*child_chroot_pid_hashkey_dir; +int errint; +gchar *s,*sd,*se; +gboolean errbool; + + /* Initialize /tmp/orbit-$username directory for linking IOR socket. */ + errbool=corba_init("captive-sandbox-parent",&captive_corba_ev,&captive_corba_orb,&captive_corba_poa); g_assert(errbool==TRUE); + + /* FIXME: Security: Duplicate giop_tmpdir_init() here. */ + if (!sandbox_parent_own_orbit_dir) { + /* FIXME: Make 'CAPTIVE_SANDBOX_CHROOT' configurable. */ + sandbox_parent_own_orbit_dir=g_strdup_printf("%s/tmp/captive-orbit-%d",CAPTIVE_SANDBOX_CHROOT,getpid()); + if (mkdir(sandbox_parent_own_orbit_dir,0700)) { + g_assert(errno==EEXIST); + sandbox_parent_own_orbit_dir_cleanup_init(); + unlink_nonrecursive(sandbox_parent_own_orbit_dir); + if (mkdir(sandbox_parent_own_orbit_dir,0700)) + g_assert_not_reached(); + } + sandbox_parent_own_orbit_dir_cleanup_init(); + linc_set_tmpdir(sandbox_parent_own_orbit_dir); + } + + data=captive_rtl_file_read(Vfs_IOR_fd_read,&data_size); /* data_fd_read */ + errint=close(Vfs_IOR_fd_read); + g_assert(errint==0); + g_assert(data!=NULL); + g_assert(data_size>=1); + g_assert(data[data_size-1]=='\n'); + + hash=g_hash_table_new(g_str_hash,g_str_equal); + + for (s=data;scorba_chrooted_orbit_dir=g_strdup(chrooted_orbit_dir); + /* 0700 as this directory will not be reused + * to commuicate with any other sandbox child. + */ + if (mkdir(chrooted_orbit_dir,0700)) { + g_assert(errno==EEXIST); + } + + socketname=g_hash_table_lookup(hash,"socketname"); + g_assert(socketname!=NULL); + captive_vfs_parent_object->corba_socketname=g_strdup(socketname); + + socketpathname_src=captive_printf_alloca("%s/%s/%s",child_chroot_pid_hashkey_dir,chrooted_orbit_dir,socketname); + socketpathname_dest=g_strdup_printf("%s/%s",chrooted_orbit_dir,socketname); + errint=link(socketpathname_src,socketpathname_dest); + if (errint) + g_error("link(\"%s\",\"%s\")=%d:%m",socketpathname_src,socketpathname_dest,errint); + } + if (child_chroot_pid_hashkey_dirp) + *child_chroot_pid_hashkey_dirp=g_strdup(child_chroot_pid_hashkey_dir); + + ior=g_hash_table_lookup(hash,"ior"); + g_assert(ior!=NULL); + ior=g_strdup(ior); + g_free(data); + + g_hash_table_destroy(hash); + + return ior; } -static gboolean heartbeat_source_prepare(GSource *source,gint *timeout) + +static xmlNode *options_module_captive_to_xml + (xmlNode *dest_xml_parent,const struct captive_options_module *src_options_module_captive) { - *timeout=-1; + g_return_val_if_fail(dest_xml_parent!=NULL,NULL); + g_return_val_if_fail(src_options_module_captive!=NULL,NULL); + + { xmlNode *module=xmlNewTextChild(dest_xml_parent,NULL,"module",NULL); + const gchar *type_string="???"; /* Prevent: ... might be used uninitialized in this function */ + const gchar *basename,*cgs; + + basename=src_options_module_captive->pathname_utf8; + if ((cgs=strrchr(basename,'/'))) + basename=cgs+1; + xmlNewProp(module,"basename",basename); + switch (src_options_module_captive->type) { + case CAPTIVE_OPTIONS_MODULE_TYPE_PE32: + type_string="PE32"; + xmlNewProp(module,"length",captive_printf_alloca("%lu",(unsigned long)src_options_module_captive->u.pe32.length)); + xmlNewProp(module,"md5" ,src_options_module_captive->u.pe32.md5); + break; + case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE: + type_string="gmodule"; + break; + default: g_assert_not_reached(); + } + xmlNewProp(module,"type",type_string); /* AFTER the 'switch' to set 'type_string'! */ + return module; + } +} - return FALSE; + +static void sandbox_parent_bug_doc_make(CaptiveVfsParentObject *captive_vfs_parent_object) +{ + { xmlDoc *doc=xmlNewDoc("1.0"); + captive_vfs_parent_object->corba_bug_doc=doc; + { xmlNode *bug=xmlNewDocNode(captive_vfs_parent_object->corba_bug_doc,NULL,"bug",NULL); + xmlDocSetRootElement(captive_vfs_parent_object->corba_bug_doc,bug); + captive_vfs_parent_object->corba_bug=bug; + { xmlNode *bug_captive=xmlNewTextChild(bug,NULL,"captive",NULL); + xmlNewProp(bug_captive,"version",VERSION); + } + { xmlNode *bug_filesystem=xmlNewTextChild(bug,NULL,"filesystem",NULL); + options_module_captive_to_xml(bug_filesystem,&CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.filesystem); + } + { xmlNode *bug_load_module=xmlNewTextChild(bug,NULL,"load_module",NULL); + guint load_moduleui; + struct captive_options_module *options_module; + GList *load_module_node; + + for (load_moduleui=0,load_module_node=CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.load_module; + load_module_node; + load_moduleui++,load_module_node=load_module_node->next) { + options_module=load_module_node->data; + options_module_captive_to_xml(bug_load_module,options_module); + } + } + { xmlNode *bug_action=xmlNewTextChild(bug,NULL,"action",NULL); + captive_vfs_parent_object->corba_bug_action=bug_action; + } + { xmlNode *bug_log=xmlNewTextChild(bug,NULL,"log",NULL); + captive_vfs_parent_object->corba_bug_log=bug_log; + } + } + } } -static GPollFD heartbeat_source_check_gpollfd; -static gboolean heartbeat_source_check(GSource *source) +static void sandbox_parent(const gchar *Vfs_IOR,const gchar *child_chroot_pid_hashkey_dir,CaptiveVfsParentObject *captive_vfs_parent_object) { - return !!(heartbeat_source_check_gpollfd.revents & HEARTBEAT_SOURCE_CHECK_REVENTS); +Captive_Vfs Vfs_object; +Captive_GLogFunc GLogFunc_object; +Captive_CaptiveIOChannel CaptiveIOChannel_object; +Captive_CaptiveOptions options_corba; +guint load_module_length,load_moduleui; +struct captive_options_module *options_module; +GList *load_module_node; +const gchar *child_chroot_parent_own_orbit_socket,*child_chroot_parent_own_orbit_dir; +int errint; + + g_return_if_fail(Vfs_IOR!=NULL); + /* 'child_chroot_pid_hashkey_dir' may be NULL */ + g_return_if_fail(CAPTIVE_VFS_PARENT_IS_OBJECT(captive_vfs_parent_object)); + + Vfs_object=CORBA_ORB_string_to_object(captive_corba_orb,Vfs_IOR,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + + /* Init 'GLogFunc_object' */ + GLogFunc_object=impl_Captive_GLogFunc__create(captive_corba_poa,captive_vfs_parent_object,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + + /* Init 'CaptiveIOChannel_object' */ + if (!captive_vfs_parent_object->corba_parent_giochanel_blind_source) + switch (CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.rwmode) { + case CAPTIVE_OPTION_RWMODE_RO: + case CAPTIVE_OPTION_RWMODE_RW: + captive_vfs_parent_object->corba_parent_giochanel_blind_source=CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.image_iochannel; + break; + case CAPTIVE_OPTION_RWMODE_BLIND: + captive_vfs_parent_object->corba_parent_giochanel_blind_source=(GIOChannel *)captive_giochannel_blind_new( + CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.image_iochannel, /* giochannel_orig */ + TRUE); /* writeable */ + break; + default: g_assert_not_reached(); + } + if (!captive_vfs_parent_object->corba_parent_giochanel_blind) + captive_vfs_parent_object->corba_parent_giochanel_blind=(GIOChannel *)captive_giochannel_blind_new( + captive_vfs_parent_object->corba_parent_giochanel_blind_source, /* giochannel_orig */ + (CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.rwmode!=CAPTIVE_OPTION_RWMODE_RO)); /* writeable */ + CaptiveIOChannel_object=impl_Captive_CaptiveIOChannel__create(captive_corba_poa, + captive_vfs_parent_object->corba_parent_giochanel_blind,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + + /* Create the socket needed for 'sandbox_parent_own_orbit_socket' below + * by CORBA_ORB_object_to_string()->ORBit_marshal_object()->IOP_generate_profiles()->ORBit_ORB_start_servers... + */ + { +char *GLogFunc_IOR; + GLogFunc_IOR=CORBA_ORB_object_to_string(captive_corba_orb,GLogFunc_object,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + g_assert(GLogFunc_IOR!=NULL); + CORBA_free(GLogFunc_IOR); + } + + if (sandbox_parent_own_orbit_dir && !sandbox_parent_own_orbit_socket) { +DIR *dir; +struct dirent *dirent; + + dir=opendir(sandbox_parent_own_orbit_dir); + g_assert(dir!=NULL); + + while (errno=0,(dirent=readdir(dir))) { + if (!strcmp(dirent->d_name,".") || !strcmp(dirent->d_name,"..")) + continue; + g_assert(sandbox_parent_own_orbit_socket==NULL); + sandbox_parent_own_orbit_socket=g_strdup_printf("%s/%s",sandbox_parent_own_orbit_dir,dirent->d_name); + } + g_assert(errno==0); + errint=closedir(dir); + g_assert(errint==0); + g_assert(sandbox_parent_own_orbit_socket!=NULL); + } + + if (child_chroot_pid_hashkey_dir) { +gchar *s; + + child_chroot_parent_own_orbit_dir=captive_printf_alloca("%s/%s",child_chroot_pid_hashkey_dir,sandbox_parent_own_orbit_dir); + s=(/* de-const */ gchar *)child_chroot_parent_own_orbit_dir; + do { + s=strchr(s,'/'); + if (s) + *s=0; + if (*child_chroot_parent_own_orbit_dir) { + errint=mkdir(child_chroot_parent_own_orbit_dir,0777); + if (errint) + g_assert(errno==EEXIST); + else { + /* chmod(2) it to prevent mode limitation by + * active ulimit(2) of being executed by mount(8). + */ + errint=chmod(child_chroot_parent_own_orbit_dir,0777); + g_assert(errint==0); + } + } + if (s) + *s++='/'; + } while (s); + child_chroot_parent_own_orbit_socket=captive_printf_alloca("%s/%s", + child_chroot_pid_hashkey_dir,sandbox_parent_own_orbit_socket); + errint=link(sandbox_parent_own_orbit_socket,child_chroot_parent_own_orbit_socket); + g_assert(errint==0); + /* chmod(2)s also our orig. one (!) but this one is protected by its 0777 directory. */ + errint=chmod(child_chroot_parent_own_orbit_socket,0666); + g_assert(errint==0); + } + + options_corba.g_log_func=CORBA_Object_duplicate(GLogFunc_object,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + + options_module_captive_to_options_module_corba(&options_corba.filesystem,&CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.filesystem); + /* Prevent secondary captive_giochannel_blind inside of our sandbox child + * as we already have one captive_giochannel_blind in the parent. + */ + options_corba.rwmode =(CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.rwmode == CAPTIVE_OPTION_RWMODE_BLIND ? CAPTIVE_OPTION_RWMODE_RW + : CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.rwmode); + options_corba.media =CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.media; + options_corba.debug_messages=CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.debug_messages; + + options_corba.image_iochannel=CORBA_Object_duplicate(CaptiveIOChannel_object,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + + load_module_length=g_list_length(CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.load_module); + options_corba.load_module._maximum=load_module_length; + options_corba.load_module._length=load_module_length; + options_corba.load_module._buffer=Captive_CaptiveOptionsModuleList_allocbuf(options_corba.load_module._maximum); + options_corba.load_module._release=TRUE; + for (load_moduleui=0,load_module_node=CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.load_module; + load_module_node; + load_moduleui++,load_module_node=load_module_node->next) { + options_module=load_module_node->data; + options_module_captive_to_options_module_corba(options_corba.load_module._buffer+load_moduleui,options_module); + } + + Captive_Vfs_init(Vfs_object,&options_corba,&captive_corba_ev); + g_assert(validate_CORBA_Environment(&captive_corba_ev)); + + Captive_CaptiveOptions__freekids(&options_corba, + NULL); /* d; unused */ + + captive_vfs_parent_object->corba_Vfs_object=Vfs_object; + captive_vfs_parent_object->corba_GLogFunc_object=GLogFunc_object; + captive_vfs_parent_object->corba_CaptiveIOChannel_object=CaptiveIOChannel_object; + + if (CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.bug_pathname) + sandbox_parent_bug_doc_make(captive_vfs_parent_object); } -static gboolean heartbeat_source_dispatch(GSource *source,GSourceFunc callback,gpointer user_data) +static void fd_shiftup(int *fdp) { - g_assert(callback!=NULL); - return (*callback)(user_data); + g_return_if_fail(fdp!=NULL); + + while (*fdp<=2 /* STDERR */) { + *fdp=dup(*fdp); + g_assert(*fdp!=-1); + } } -static GSourceFuncs heartbeat_source_watch_funcs={ - heartbeat_source_prepare, - heartbeat_source_check, - heartbeat_source_dispatch, - NULL, /* finalize */ - }; +void captive_sandbox_fd_closeup(int fd_first_to_delete) +{ +DIR *dir; +int errint; +int dir_fd; +struct dirent *dirent; + + dir=opendir("/proc/self/fd/"); + g_return_if_fail(dir!=NULL); + dir_fd=dirfd(dir); + g_return_if_fail(dir_fd!=-1); + + while (errno=0,(dirent=readdir(dir))) { +long dirent_fd; +char *endptr; + + if (0 + || !strcmp(dirent->d_name,".") + || !strcmp(dirent->d_name,"..")) + continue; + dirent_fd=strtol(dirent->d_name,&endptr,10 /* base */); + g_assert(dirent_fd>=0 && (!endptr || !*endptr)); + if (dirent_fdoptions.sandbox_server_ior) { + g_assert(CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.sandbox_server_argv==NULL); + + errbool=corba_init("captive-sandbox-parent",&captive_corba_ev,&captive_corba_orb,&captive_corba_poa); + g_assert(errbool==TRUE); + + captive_vfs_parent_object->corba_parentheart_fds_1=-1; + captive_vfs_parent_object->corba_child_pid=-1; + sandbox_parent( + CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.sandbox_server_ior, /* Vfs_IOR */ + NULL, /* child_chroot_pid_hashkey_dir */ + captive_vfs_parent_object); /* captive_vfs_parent_object */ + return TRUE; + } + + g_assert(CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.sandbox_server_argv!=NULL); + switch ((captive_vfs_parent_object->corba_child_pid=fork())) { case -1: /* error */ - g_assert_not_reached(); + g_return_val_if_reached(FALSE); case 0: { /* child */ -GSource *gsource; errint=close(Vfs_IOR_fds[0]); /* close Vfs_IOR_fd_read */ - g_assert(errint==0); + g_return_val_if_fail(errint==0,FALSE); errint=close(parentheart_fds[1]); /* close parentheart_fd_write */ - g_assert(errint==0); + g_return_val_if_fail(errint==0,FALSE); - /* attach heartbeat_source_callback() to watch for any abnormalities - * on our open pipe 'parentheart_fds' and terminate the child if parent dies. - */ - gsource=g_source_new(&heartbeat_source_watch_funcs,sizeof(GSource)); - g_assert(gsource!=NULL); - g_source_set_callback( - gsource, /* source */ - heartbeat_source_callback, /* func */ - NULL, /* data */ - NULL); /* notify */ - heartbeat_source_check_gpollfd.fd=parentheart_fds[0]; /* parentheart_fd_read */ - heartbeat_source_check_gpollfd.events=HEARTBEAT_SOURCE_CHECK_EVENTS; - heartbeat_source_check_gpollfd.revents=0; - g_source_add_poll(gsource,&heartbeat_source_check_gpollfd); - sandbox_child(Vfs_IOR_fds[1],gsource); /* pass Vfs_IOR_fd_write */ + fd_shiftup(Vfs_IOR_fds+1); /* Vfs_IOR_fd_write */ + fd_shiftup(parentheart_fds+0); /* parentheart_fd_read */ + errint=dup2(Vfs_IOR_fds[1],1 /* STDOUT */); /* Vfs_IOR_fd_write */ + g_return_val_if_fail(errint==1 /* STDOUT */,FALSE); + errint=dup2(parentheart_fds[0],0 /* STDIN */); /* parentheart_fd_read */ + g_return_val_if_fail(errint==0 /* STDIN */,FALSE); + + captive_sandbox_fd_closeup(2 /* STDERR */ +1); + + execv(CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.sandbox_server_argv[0], + /* re-const */ (char * const *)CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.sandbox_server_argv); + g_return_val_if_reached(FALSE); } /* NOTREACHED */ - default: /* parent */ + default: { /* parent */ +gchar *Vfs_IOR; +gchar *child_chroot_pid_hashkey_dir; + errint=close(Vfs_IOR_fds[1]); /* close Vfs_IOR_fd_write */ - g_assert(errint==0); + g_return_val_if_fail(errint==0,FALSE); errint=close(parentheart_fds[0]); /* close parentheart_fd_read */ - g_assert(errint==0); + g_return_val_if_fail(errint==0,FALSE); errint=fcntl(parentheart_fds[1],F_SETFD,FD_CLOEXEC); /* This fcntl(2) may not be enough - some fork(2) may duplicate this * write descriptor and even if we do some process finish the child * may remain alone connected with some unknown fork(2)er from us. * Currently I am not aware such case would occur. */ - g_assert(errint==0); - sandbox_parent(Vfs_IOR_fds[0]); /* pass Vfs_IOR_fd_read, it will be closed there */ - break; + g_return_val_if_fail(errint==0,FALSE); + captive_vfs_parent_object->corba_parentheart_fds_1=parentheart_fds[1]; + + Vfs_IOR=sandbox_parent_read_ior( + Vfs_IOR_fds[0], /* Vfs_IOR_fd_read */ + &child_chroot_pid_hashkey_dir, + captive_vfs_parent_object); + + sandbox_parent( + Vfs_IOR, /* Vfs_IOR */ + child_chroot_pid_hashkey_dir, /* child_chroot_pid_hashkey_dir */ + captive_vfs_parent_object); /* captive_vfs_parent_object */ + + g_free(Vfs_IOR); + g_free(child_chroot_pid_hashkey_dir); + + /* 'parentheart_fds[1]' - parentheart_fd_write - is left open here */ + return TRUE; + } } - /* 'parentheart_fds[1]' - parentheart_fd_write - is left open here */ + /* NOTREACHED */ + g_return_val_if_reached(FALSE); +} + + +GnomeVFSResult captive_sandbox_parent_return_from_CORBA_Environment + (CORBA_Environment *evp,CaptiveVfsParentObject *captive_vfs_parent_object) +{ +GnomeVFSResult r; + + if (evp->_major==CORBA_NO_EXCEPTION) + return GNOME_VFS_OK; + + /* If !CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.sandbox_server_argv it is CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.sandbox_server_ior + * where we cannot do any restart anyway. + */ + if (captive_vfs_parent_object && CAPTIVE_VFS_OBJECT(captive_vfs_parent_object)->options.sandbox_server_argv + && (evp->_major==CORBA_SYSTEM_EXCEPTION && !strcmp(ex_CORBA_COMM_FAILURE,CORBA_exception_id(evp)))) { + r=GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE; + if (captive_vfs_parent_object->corba_Vfs_object!=CORBA_OBJECT_NIL) + captive_vfs_parent_object_aborted(captive_vfs_parent_object); /* errors ignored */ + } + else if (evp->_major==CORBA_USER_EXCEPTION && !strcmp(ex_Captive_GnomeVFSResultException,CORBA_exception_id(evp))) { + r=((Captive_GnomeVFSResultException *)CORBA_exception_value(evp))->gnome_vfs_result; + g_assert(r!=GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE); /* code reserved for sandbox restarts */ + } + else { + r=GNOME_VFS_ERROR_GENERIC; + g_warning(_("CORBA Exception occured: id=\"%s\", value=%p"), + CORBA_exception_id(evp),CORBA_exception_value(evp)); + } + CORBA_exception_free(evp); + + return r; +} + + +void captive_sandbox_child_GnomeVFSResultException_throw(CORBA_Environment *evp,GnomeVFSResult errvfsresult) +{ +Captive_GnomeVFSResultException *gnome_vfs_result_exception; + + g_return_if_fail(evp!=NULL); + + gnome_vfs_result_exception=Captive_GnomeVFSResultException__alloc(); + gnome_vfs_result_exception->gnome_vfs_result=errvfsresult; + CORBA_exception_set(evp,CORBA_USER_EXCEPTION,ex_Captive_GnomeVFSResultException,gnome_vfs_result_exception); }