diff options
Diffstat (limited to 'gpgme/rungpg.c')
-rw-r--r-- | gpgme/rungpg.c | 146 |
1 files changed, 125 insertions, 21 deletions
diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 6353ad27..ac6ba114 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -29,6 +29,7 @@ #include <unistd.h> #include <sys/wait.h> #include <signal.h> +#include <fcntl.h> #include "gpgme.h" #include "util.h" @@ -84,6 +85,7 @@ struct gpg_object_s { static void kill_gpg ( GpgObject gpg ); static void free_argv ( char **argv ); +static void free_fd_data_map ( struct fd_data_map_s *fd_data_map ); static int gpg_status_handler ( void *opaque, pid_t pid, int fd ); static int gpg_inbound_handler ( void *opaque, pid_t pid, int fd ); static int gpg_outbound_handler ( void *opaque, pid_t pid, int fd ); @@ -96,7 +98,6 @@ GpgmeError _gpgme_gpg_new_object ( GpgObject *r_gpg ) { GpgObject gpg; - char buf[20]; int rc = 0; gpg = xtrycalloc ( 1, sizeof *gpg ); @@ -109,9 +110,6 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg ) gpg->status.fd[0] = -1; gpg->status.fd[1] = -1; - /* The name of the beast will be gpg - so put it into argv[0] */ - _gpgme_gpg_add_arg ( gpg, "gpg" ); - /* allocate the read buffer for the status pipe */ gpg->status.bufsize = 1024; gpg->status.readpos = 0; @@ -128,8 +126,13 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg ) } gpg->status.eof = 0; _gpgme_gpg_add_arg ( gpg, "--status-fd" ); - sprintf ( buf, "%d", gpg->status.fd[1]); - _gpgme_gpg_add_arg ( gpg, buf ); + { + char buf[25]; + sprintf ( buf, "%d", gpg->status.fd[1]); + _gpgme_gpg_add_arg ( gpg, buf ); + } + _gpgme_gpg_add_arg ( gpg, "--batch" ); + _gpgme_gpg_add_arg ( gpg, "--no-tty" ); leave: if (rc) { @@ -153,8 +156,7 @@ _gpgme_gpg_release_object ( GpgObject gpg ) close (gpg->status.fd[0]); if (gpg->status.fd[1] != -1 ) close (gpg->status.fd[1]); - /* fixme: walk over the data map and close all fds */ - xfree (gpg->fd_data_map); + free_fd_data_map (gpg->fd_data_map); kill_gpg (gpg); /* fixme: should be done asyncronously */ xfree (gpg); } @@ -162,6 +164,7 @@ _gpgme_gpg_release_object ( GpgObject gpg ) static void kill_gpg ( GpgObject gpg ) { + #if 0 if ( gpg->running ) { /* still running? Must send a killer */ kill ( gpg->pid, SIGTERM); @@ -172,6 +175,7 @@ kill_gpg ( GpgObject gpg ) } gpg->running = 0; } + #endif } @@ -238,6 +242,21 @@ free_argv ( char **argv ) xfree (argv); } +static void +free_fd_data_map ( struct fd_data_map_s *fd_data_map ) +{ + int i; + + for (i=0; fd_data_map[i].data; i++ ) { + if ( fd_data_map[i].fd != -1 ) + close (fd_data_map[i].fd); + if ( fd_data_map[i].peer_fd != -1 ) + close (fd_data_map[i].peer_fd); + /* don't realease data because this is only a reference */ + } + xfree (fd_data_map); +} + static GpgmeError build_argv ( GpgObject gpg ) @@ -246,22 +265,32 @@ build_argv ( GpgObject gpg ) struct fd_data_map_s *fd_data_map; size_t datac=0, argc=0; char **argv; + int need_special = 0; if ( gpg->argv ) { free_argv ( gpg->argv ); gpg->argv = NULL; } - /* fixme: release fd_data_map */ + if (gpg->fd_data_map) { + free_fd_data_map (gpg->fd_data_map); + gpg->fd_data_map = NULL; + } + argc++; /* for argv[0] */ for ( a=gpg->arglist; a; a = a->next ) { argc++; if (a->data) { - fprintf (stderr, "build_argv: data\n" ); + /*fprintf (stderr, "build_argv: data\n" );*/ datac++; + if ( a->dup_to == -1 ) + need_special = 1; + } + else { + /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ } - else - fprintf (stderr, "build_argv: arg=`%s'\n", a->arg ); } + if ( need_special ) + argc++; argv = xtrycalloc ( argc+1, sizeof *argv ); if (!argv) @@ -273,6 +302,22 @@ build_argv ( GpgObject gpg ) } argc = datac = 0; + argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */ + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + argc++; + if ( need_special ) { + argv[argc] = xtrystrdup ( "--enable-special-filenames" ); + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + argc++; + } for ( a=gpg->arglist; a; a = a->next ) { if ( a->data ) { switch ( _gpgme_query_data_mode (a->data) ) { @@ -328,6 +373,16 @@ build_argv ( GpgObject gpg ) } fd_data_map[datac].data = a->data; fd_data_map[datac].dup_to = a->dup_to; + if ( a->dup_to == -1 ) { + argv[argc] = xtrymalloc ( 25 ); + if (!argv[argc]) { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); + } + sprintf ( argv[argc], "-&%d", fd_data_map[datac].peer_fd ); + argc++; + } datac++; } else { @@ -337,8 +392,8 @@ build_argv ( GpgObject gpg ) free_argv (argv); return mk_error (Out_Of_Core); } + argc++; } - argc++; } gpg->argv = argv; @@ -372,6 +427,11 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque ) } if ( !pid ) { /* child */ + int duped_stdin = 0; + int duped_stderr = 0; + + close (gpg->status.fd[0]); + for (i=0; gpg->fd_data_map[i].data; i++ ) { close (gpg->fd_data_map[i].fd); gpg->fd_data_map[i].fd = -1; @@ -382,20 +442,49 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque ) strerror (errno)); _exit (8); } + if ( gpg->fd_data_map[i].dup_to == 0 ) + duped_stdin=1; + if ( gpg->fd_data_map[i].dup_to == 2 ) + duped_stderr=1; close ( gpg->fd_data_map[i].peer_fd ); } } - - if ( gpg->status.fd[0] != -1 ) - close (gpg->status.fd[0]); - /* FIXME: dup /dev/null to stdin if nothing is connected to stdin */ - execv ("/usr/local/bin/gpg", gpg->argv ); - fprintf (stderr,"exec of gpg failed\n"); fflush (stderr); + if( !duped_stdin || !duped_stderr ) { + int fd = open ( "/dev/null", O_RDONLY ); + if ( fd == -1 ) { + fprintf (stderr,"can't open `/dev/null': %s\n", + strerror (errno) ); + _exit (8); + } + /* Make sure that gpg has a connected stdin */ + if ( !duped_stdin ) { + if ( dup2 ( fd, 0 ) == -1 ) { + fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n", + strerror (errno) ); + _exit (8); + } + } + /* We normally don't want all the normal output */ + if ( !duped_stderr ) { + if ( dup2 ( fd, 2 ) == -1 ) { + fprintf (stderr,"dup2(dev/null, 2) failed: %s\n", + strerror (errno) ); + _exit (8); + } + } + close (fd); + } + + execv ("./gpg", gpg->argv ); + fprintf (stderr,"exec of gpg failed\n"); _exit (8); } + /* parent */ gpg->pid = pid; + /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ + if ( gpg->status.fd[1] != -1 ) close (gpg->status.fd[1]); if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler, @@ -424,7 +513,6 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque ) gpg->running = 1; return 0; - } @@ -432,6 +520,7 @@ static int gpg_inbound_handler ( void *opaque, pid_t pid, int fd ) { GpgmeData dh = opaque; + GpgmeError err; int nread; char buf[200]; @@ -448,7 +537,19 @@ gpg_inbound_handler ( void *opaque, pid_t pid, int fd ) } else if (!nread) return 1; /* eof */ + + /* We could improve this with a GpgmeData function which takes + * the read function or provides a memory area for writing to it. + */ + err = _gpgme_append_data ( dh, buf, nread ); + if ( err ) { + fprintf (stderr, "_gpgme_append_data failed: %s\n", + gpgme_strerror(err)); + /* Fixme: we should close the pipe or read it to /dev/null in + * this case. Returnin EOF is not sufficient */ + return 1; + } return 0; } @@ -520,8 +621,11 @@ gpg_status_handler ( void *opaque, pid_t pid, int fd ) static int -status_cmp (const struct status_table_s *a, const struct status_table_s *b) +status_cmp (const void *ap, const void *bp) { + const struct status_table_s *a = ap; + const struct status_table_s *b = bp; + return strcmp (a->name, b->name); } |