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);  } | 
