summaryrefslogtreecommitdiffstats
path: root/gpglib/mimegpgfork.c
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /gpglib/mimegpgfork.c
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'gpglib/mimegpgfork.c')
-rw-r--r--gpglib/mimegpgfork.c449
1 files changed, 449 insertions, 0 deletions
diff --git a/gpglib/mimegpgfork.c b/gpglib/mimegpgfork.c
new file mode 100644
index 0000000..d1b849c
--- /dev/null
+++ b/gpglib/mimegpgfork.c
@@ -0,0 +1,449 @@
+/*
+** Copyright 2001-2010 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "gpg.h"
+
+#include <sys/types.h>
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#include "mimegpgfork.h"
+
+static int libmail_gpgmime_fork(const char *gpgdir,
+ const char *passphrase_fd,
+ int xargc, char **xargv, int argc, char **argv,
+ struct gpgmime_forkinfo *fi)
+{
+ int pipes[3][2];
+ int n;
+ pid_t p;
+ struct sigaction sa;
+
+ for (n=0; n<3; n++)
+ {
+ if (pipe(pipes[n]) < 0)
+ {
+ while (n)
+ {
+ --n;
+ close(pipes[n][0]);
+ close(pipes[n][1]);
+ return (-1);
+ }
+ }
+ }
+
+ if (fcntl(pipes[0][1], F_SETFL, O_NONBLOCK) ||
+ fcntl(pipes[1][0], F_SETFL, O_NONBLOCK) ||
+ fcntl(pipes[2][0], F_SETFL, O_NONBLOCK))
+ {
+ for (n=0; n<3; n++)
+ {
+ close(pipes[n][0]);
+ close(pipes[n][1]);
+ }
+ return (-1);
+ }
+
+ signal(SIGCHLD, SIG_DFL);
+
+ p=fork();
+ if (p < 0)
+ {
+ for (n=0; n<3; n++)
+ {
+ close(pipes[n][0]);
+ close(pipes[n][1]);
+ }
+ return (-1);
+ }
+
+ if (p == 0)
+ {
+ char **newargv;
+ int i;
+ const char *gpg;
+
+ dup2(pipes[0][0], 0);
+ dup2(pipes[1][1], 1);
+ dup2(pipes[2][1], 2);
+
+ for (n=0; n<3; n++)
+ {
+ close(pipes[n][0]);
+ close(pipes[n][1]);
+ }
+
+ newargv=malloc( (xargc + argc + 5) * sizeof(char *));
+ if (!newargv)
+ {
+ perror("malloc");
+ _exit(1);
+ }
+
+ i=0;
+ newargv[i++]="gpg";
+ if (passphrase_fd)
+ {
+ int n=atoi(passphrase_fd);
+
+ if (lseek(n, 0L, SEEK_SET) < 0)
+ {
+ perror("passphrase-fd: seek");
+ _exit(1);
+ }
+
+ newargv[i++]="--batch";
+ newargv[i++]="--passphrase-fd";
+ newargv[i++]=(char *)passphrase_fd;
+ }
+
+ for (n=0; n<xargc; n++)
+ newargv[i++]=xargv[n];
+ for (n=0; n<argc; n++)
+ newargv[i++]=argv[n];
+
+ newargv[i]=0;
+
+ if (gpgdir)
+ {
+ char *s;
+
+ s=malloc(sizeof("GNUPGHOME=")+strlen(gpgdir));
+ if (!s)
+ {
+ perror("malloc");
+ exit(1);
+ }
+ strcat(strcpy(s, "GNUPGHOME="), gpgdir);
+ if (putenv(s) < 0)
+ {
+ perror("putenv");
+ exit(1);
+ }
+ }
+
+ gpg=getenv("GPG");
+ if (!gpg || !*gpg)
+ gpg=GPG;
+
+ execvp(gpg, newargv);
+ perror(gpg);
+ _exit(1);
+ }
+
+ fi->gpg_errflag=0;
+ fi->togpg_fd=pipes[0][1];
+ close(pipes[0][0]);
+ fi->fromgpg_fd=pipes[1][0];
+ close(pipes[1][1]);
+ fi->fromgpg_errfd=pipes[2][0];
+ close(pipes[2][1]);
+
+ fi->gpg_writecnt=0;
+ fi->gpg_errcnt=0;
+ fi->gpg_errbuf[0]=0;
+ fi->gpg_pid=p;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler=SIG_IGN;
+ sigaction(SIGPIPE, &sa, &fi->old_pipe_sig);
+
+ fi->gpg_readhandler=0;
+ fi->gpg_voidarg=0;
+ return (0);
+}
+
+static void gpgmime_writeflush(struct gpgmime_forkinfo *);
+
+void libmail_gpgmime_write(struct gpgmime_forkinfo *fi, const char *p, size_t n)
+{
+ while (n)
+ {
+ size_t i;
+
+ if (fi->gpg_writecnt == sizeof(fi->gpg_writebuf))
+ gpgmime_writeflush(fi);
+
+ i=sizeof(fi->gpg_writebuf) - fi->gpg_writecnt;
+
+ if ((size_t)i > n)
+ i=n;
+
+ memcpy(fi->gpg_writebuf + fi->gpg_writecnt, p, i);
+
+ fi->gpg_writecnt += i;
+
+ p += i;
+ n -= i;
+ }
+}
+
+static void libmail_gpgmime_read(struct gpgmime_forkinfo *fi, fd_set *fdr)
+{
+ char readbuf[BUFSIZ];
+ int i;
+
+ if (fi->fromgpg_fd >= 0 && FD_ISSET(fi->fromgpg_fd, fdr))
+ {
+ i=read(fi->fromgpg_fd, readbuf, sizeof(readbuf));
+
+ if (i <= 0)
+ {
+ close(fi->fromgpg_fd);
+ fi->fromgpg_fd= -1;
+ }
+ else
+ {
+ if (fi->gpg_readhandler)
+ fi->gpg_errflag=
+ (*fi->gpg_readhandler)(readbuf, i,
+ fi->gpg_voidarg
+ );
+ }
+ }
+
+ if (fi->fromgpg_errfd >= 0 && FD_ISSET(fi->fromgpg_errfd, fdr))
+ {
+ i=read(fi->fromgpg_errfd, readbuf, sizeof(readbuf));
+
+ if (i <= 0)
+ {
+ close(fi->fromgpg_errfd);
+ fi->fromgpg_errfd= -1;
+ }
+ else
+ {
+ if (i >= sizeof(fi->gpg_errbuf)-1-fi->gpg_errcnt)
+ i=sizeof(fi->gpg_errbuf)-1-fi->gpg_errcnt;
+ if (i)
+ {
+ memcpy(fi->gpg_errbuf+fi->gpg_errcnt,
+ readbuf, i);
+ fi->gpg_errbuf[fi->gpg_errcnt += i]=0;
+ }
+ }
+ }
+}
+
+static void gpgmime_writeflush(struct gpgmime_forkinfo *fi)
+{
+ const char *p=fi->gpg_writebuf;
+ unsigned n=fi->gpg_writecnt;
+
+ while (n && !fi->gpg_errflag)
+ {
+ fd_set fdr, fdw;
+ int maxfd=fi->togpg_fd, i;
+
+ FD_ZERO(&fdr);
+ FD_ZERO(&fdw);
+
+ FD_SET(fi->togpg_fd, &fdw);
+
+ if (fi->fromgpg_fd >= 0)
+ {
+ FD_SET(fi->fromgpg_fd, &fdr);
+ if (fi->fromgpg_fd > maxfd)
+ maxfd=fi->fromgpg_fd;
+ }
+
+ if (fi->fromgpg_errfd >= 0)
+ {
+ FD_SET(fi->fromgpg_errfd, &fdr);
+ if (fi->fromgpg_errfd > maxfd)
+ maxfd=fi->fromgpg_errfd;
+ }
+
+ if (select(maxfd+1, &fdr, &fdw, NULL, NULL) <= 0)
+ continue;
+
+ libmail_gpgmime_read(fi, &fdr);
+
+ if (!FD_ISSET(fi->togpg_fd, &fdw))
+ continue;
+
+ i=write(fi->togpg_fd, p, n);
+
+ if (i <= 0)
+ fi->gpg_errflag=1;
+ else
+ {
+ p += i;
+ n -= i;
+ }
+ }
+ fi->gpg_writecnt=0;
+}
+
+int libmail_gpgmime_finish(struct gpgmime_forkinfo *fi)
+{
+ pid_t p2;
+ int waitstat;
+
+ gpgmime_writeflush(fi);
+ close(fi->togpg_fd);
+ sigaction(SIGPIPE, &fi->old_pipe_sig, NULL);
+
+ while (!fi->gpg_errflag &&
+ (fi->fromgpg_fd >= 0 || fi->fromgpg_errfd >= 0))
+ {
+ fd_set fdr;
+ int maxfd=0;
+
+ FD_ZERO(&fdr);
+
+ if (fi->fromgpg_fd >= 0)
+ {
+ FD_SET(fi->fromgpg_fd, &fdr);
+ if (fi->fromgpg_fd > maxfd)
+ maxfd=fi->fromgpg_fd;
+ }
+
+ if (fi->fromgpg_errfd >= 0)
+ {
+ FD_SET(fi->fromgpg_errfd, &fdr);
+ if (fi->fromgpg_errfd > maxfd)
+ maxfd=fi->fromgpg_errfd;
+ }
+
+ if (select(maxfd+1, &fdr, NULL, NULL, NULL) <= 0)
+ continue;
+
+ libmail_gpgmime_read(fi, &fdr);
+ }
+
+ while ((p2=wait(&waitstat)) != fi->gpg_pid)
+ {
+ if (p2 < 0 && errno == ECHILD)
+ break;
+ }
+
+ if (fi->gpg_errflag == 0)
+ {
+ if (!WIFEXITED(waitstat))
+ fi->gpg_errflag=1;
+ else
+ fi->gpg_errflag=WEXITSTATUS(waitstat);
+ }
+ return (fi->gpg_errflag);
+}
+
+int libmail_gpgmime_forksignencrypt(const char *gpgdir,
+ const char *passphrase_fd,
+ int flags,
+ int argc, char **argv,
+ int (*output_func)(const char *,
+ size_t, void *),
+ void *output_voidarg,
+ struct gpgmime_forkinfo *gpgfi)
+{
+ char *xargvec[5];
+ int xargc=0;
+ int rc;
+
+ if (flags & GPG_SE_SIGN)
+ {
+ xargvec[xargc++]="-s";
+ if (! (flags & GPG_SE_ENCRYPT))
+ xargvec[xargc++]="-b";
+ }
+
+ if (flags & GPG_SE_ENCRYPT)
+ xargvec[xargc++]="-e";
+
+ xargvec[xargc++]="-a";
+
+ rc=libmail_gpgmime_fork(gpgdir, passphrase_fd,
+ xargc, xargvec, argc, argv, gpgfi);
+
+ gpgfi->gpg_readhandler= output_func;
+ gpgfi->gpg_voidarg=output_voidarg;
+ return (rc);
+}
+
+int libmail_gpgmime_forkchecksign(const char *gpgdir,
+ const char *passphrase_fd,
+ const char *content_filename,
+ const char *signature_filename,
+ int argc, char **argv,
+ struct gpgmime_forkinfo *gpgfi)
+{
+ char *xargvec[3];
+ char **newargv;
+ int i;
+ int rc;
+
+ xargvec[0]="--verify";
+ xargvec[1]="--charset";
+ xargvec[2]=GPG_CHARSET;
+
+ newargv=(char **)malloc((argc+2)*sizeof(char *));
+ if (!newargv)
+ {
+ perror("malloc");
+ exit(1);
+ }
+
+ for (i=0; i<argc; i++)
+ newargv[i]=argv[i];
+ newargv[i++]=(char *)signature_filename;
+ newargv[i++]=(char *)content_filename;
+
+ rc=libmail_gpgmime_fork(gpgdir, passphrase_fd, 3, xargvec, i, newargv, gpgfi);
+ free(newargv);
+ return (rc);
+}
+
+int libmail_gpgmime_forkdecrypt(const char *gpgdir,
+ const char *passphrase_fd,
+ int argc, char **argv,
+ int (*output_func)(const char *, size_t, void *),
+ void *output_voidarg,
+ struct gpgmime_forkinfo *gpgfi)
+{
+ char *xargv[3];
+ int rc;
+
+ xargv[0]="--decrypt";
+ xargv[1]="--charset";
+ xargv[2]=GPG_CHARSET;
+
+ rc=libmail_gpgmime_fork(gpgdir, passphrase_fd, 3, xargv, argc, argv, gpgfi);
+
+ gpgfi->gpg_readhandler= output_func;
+ gpgfi->gpg_voidarg= output_voidarg;
+ return (rc);
+}
+
+const char *libmail_gpgmime_getoutput(struct gpgmime_forkinfo *gpgfi)
+{
+ return (gpgfi->gpg_errbuf);
+}
+
+const char *libmail_gpgmime_getcharset(struct gpgmime_forkinfo *gpgfi)
+{
+ return (GPG_CHARSET);
+}