aboutsummaryrefslogtreecommitdiffstats
path: root/gpgme/rungpg.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpgme/rungpg.c')
-rw-r--r--gpgme/rungpg.c146
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);
}