Back to index

courier  0.68.2
mimegpgfork.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2001-2010 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 #include "config.h"
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <signal.h>
00012 #include <ctype.h>
00013 #include <errno.h>
00014 #include <unistd.h>
00015 #include <fcntl.h>
00016 #include "gpg.h"
00017 
00018 #include <sys/types.h>
00019 #if    HAVE_SYS_TIME_H
00020 #include      <sys/time.h>
00021 #endif
00022 #if HAVE_SYS_WAIT_H
00023 #include      <sys/wait.h>
00024 #endif
00025 #ifndef WEXITSTATUS
00026 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00027 #endif
00028 #ifndef WIFEXITED
00029 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00030 #endif
00031 
00032 #include      "mimegpgfork.h"
00033 
00034 static int libmail_gpgmime_fork(const char *gpgdir,
00035                      const char *passphrase_fd,
00036                      int xargc, char **xargv, int argc, char **argv,
00037                      struct gpgmime_forkinfo *fi)
00038 {
00039        int pipes[3][2];
00040        int n;
00041        pid_t p;
00042        struct sigaction sa;
00043 
00044        for (n=0; n<3; n++)
00045        {
00046               if (pipe(pipes[n]) < 0)
00047               {
00048                      while (n)
00049                      {
00050                             --n;
00051                             close(pipes[n][0]);
00052                             close(pipes[n][1]);
00053                             return (-1);
00054                      }
00055               }
00056        }
00057 
00058        if (fcntl(pipes[0][1], F_SETFL, O_NONBLOCK) ||
00059            fcntl(pipes[1][0], F_SETFL, O_NONBLOCK) ||
00060            fcntl(pipes[2][0], F_SETFL, O_NONBLOCK))
00061        {
00062               for (n=0; n<3; n++)
00063               {
00064                      close(pipes[n][0]);
00065                      close(pipes[n][1]);
00066               }
00067               return (-1);
00068        }
00069 
00070        signal(SIGCHLD, SIG_DFL);
00071 
00072        p=fork();
00073        if (p < 0)
00074        {
00075               for (n=0; n<3; n++)
00076               {
00077                      close(pipes[n][0]);
00078                      close(pipes[n][1]);
00079               }
00080               return (-1);
00081        }
00082 
00083        if (p == 0)
00084        {
00085               char **newargv;
00086               int i;
00087               const char *gpg;
00088 
00089               dup2(pipes[0][0], 0);
00090               dup2(pipes[1][1], 1);
00091               dup2(pipes[2][1], 2);
00092 
00093               for (n=0; n<3; n++)
00094               {
00095                      close(pipes[n][0]);
00096                      close(pipes[n][1]);
00097               }
00098 
00099               newargv=malloc( (xargc + argc + 5) * sizeof(char *));
00100               if (!newargv)
00101               {
00102                      perror("malloc");
00103                      _exit(1);
00104               }
00105 
00106               i=0;
00107               newargv[i++]="gpg";
00108               if (passphrase_fd)
00109               {
00110                      int n=atoi(passphrase_fd);
00111 
00112                      if (lseek(n, 0L, SEEK_SET) < 0)
00113                      {
00114                             perror("passphrase-fd: seek");
00115                             _exit(1);
00116                      }
00117 
00118                      newargv[i++]="--batch";
00119                      newargv[i++]="--passphrase-fd";
00120                      newargv[i++]=(char *)passphrase_fd;
00121               }
00122 
00123               for (n=0; n<xargc; n++)
00124                      newargv[i++]=xargv[n];
00125               for (n=0; n<argc; n++)
00126                      newargv[i++]=argv[n];
00127 
00128               newargv[i]=0;
00129 
00130               if (gpgdir)
00131               {
00132                      char *s;
00133 
00134                      s=malloc(sizeof("GNUPGHOME=")+strlen(gpgdir));
00135                      if (!s)
00136                      {
00137                             perror("malloc");
00138                             exit(1);
00139                      }
00140                      strcat(strcpy(s, "GNUPGHOME="), gpgdir);
00141                      if (putenv(s) < 0)
00142                      {
00143                             perror("putenv");
00144                             exit(1);
00145                      }
00146               }
00147 
00148               gpg=getenv("GPG");
00149               if (!gpg || !*gpg)
00150                      gpg=GPG;
00151 
00152               execvp(gpg, newargv);
00153               perror(gpg);
00154               _exit(1);
00155        }
00156 
00157        fi->gpg_errflag=0;
00158        fi->togpg_fd=pipes[0][1];
00159        close(pipes[0][0]);
00160        fi->fromgpg_fd=pipes[1][0];
00161        close(pipes[1][1]);
00162        fi->fromgpg_errfd=pipes[2][0];
00163        close(pipes[2][1]);
00164 
00165        fi->gpg_writecnt=0;
00166        fi->gpg_errcnt=0;
00167        fi->gpg_errbuf[0]=0;
00168        fi->gpg_pid=p;
00169 
00170        memset(&sa, 0, sizeof(sa));
00171        sa.sa_handler=SIG_IGN;
00172        sigaction(SIGPIPE, &sa, &fi->old_pipe_sig);
00173 
00174        fi->gpg_readhandler=0;
00175        fi->gpg_voidarg=0;
00176        return (0);
00177 }
00178 
00179 static void gpgmime_writeflush(struct gpgmime_forkinfo *);
00180 
00181 void libmail_gpgmime_write(struct gpgmime_forkinfo *fi, const char *p, size_t n)
00182 {
00183        while (n)
00184        {
00185               size_t i;
00186 
00187               if (fi->gpg_writecnt == sizeof(fi->gpg_writebuf))
00188                      gpgmime_writeflush(fi);
00189 
00190               i=sizeof(fi->gpg_writebuf) - fi->gpg_writecnt;
00191 
00192               if ((size_t)i > n)
00193                      i=n;
00194 
00195               memcpy(fi->gpg_writebuf + fi->gpg_writecnt, p, i);
00196 
00197               fi->gpg_writecnt += i;
00198 
00199               p += i;
00200               n -= i;
00201        }
00202 }
00203 
00204 static void libmail_gpgmime_read(struct gpgmime_forkinfo *fi, fd_set *fdr)
00205 {
00206        char readbuf[BUFSIZ];
00207        int i;
00208 
00209        if (fi->fromgpg_fd >= 0 && FD_ISSET(fi->fromgpg_fd, fdr))
00210        {
00211               i=read(fi->fromgpg_fd, readbuf, sizeof(readbuf));
00212 
00213               if (i <= 0)
00214               {
00215                      close(fi->fromgpg_fd);
00216                      fi->fromgpg_fd= -1;
00217               }
00218               else
00219               {
00220                      if (fi->gpg_readhandler)
00221                             fi->gpg_errflag=
00222                                    (*fi->gpg_readhandler)(readbuf, i,
00223                                                         fi->gpg_voidarg
00224                                                         );
00225               }
00226        }
00227 
00228        if (fi->fromgpg_errfd >= 0 && FD_ISSET(fi->fromgpg_errfd, fdr))
00229        {
00230               i=read(fi->fromgpg_errfd, readbuf, sizeof(readbuf));
00231 
00232               if (i <= 0)
00233               {
00234                      close(fi->fromgpg_errfd);
00235                      fi->fromgpg_errfd= -1;
00236               }
00237               else
00238               {
00239                      if (i >= sizeof(fi->gpg_errbuf)-1-fi->gpg_errcnt)
00240                             i=sizeof(fi->gpg_errbuf)-1-fi->gpg_errcnt;
00241                      if (i)
00242                      {
00243                             memcpy(fi->gpg_errbuf+fi->gpg_errcnt,
00244                                    readbuf, i);
00245                             fi->gpg_errbuf[fi->gpg_errcnt += i]=0;
00246                      }
00247               }
00248        }
00249 }
00250 
00251 static void gpgmime_writeflush(struct gpgmime_forkinfo *fi)
00252 {
00253        const char *p=fi->gpg_writebuf;
00254        unsigned n=fi->gpg_writecnt;
00255 
00256        while (n && !fi->gpg_errflag)
00257        {
00258               fd_set fdr, fdw;
00259               int maxfd=fi->togpg_fd, i;
00260 
00261               FD_ZERO(&fdr);
00262               FD_ZERO(&fdw);
00263 
00264               FD_SET(fi->togpg_fd, &fdw);
00265 
00266               if (fi->fromgpg_fd >= 0)
00267               {
00268                      FD_SET(fi->fromgpg_fd, &fdr);
00269                      if (fi->fromgpg_fd > maxfd)
00270                             maxfd=fi->fromgpg_fd;
00271               }
00272 
00273               if (fi->fromgpg_errfd >= 0)
00274               {
00275                      FD_SET(fi->fromgpg_errfd, &fdr);
00276                      if (fi->fromgpg_errfd > maxfd)
00277                             maxfd=fi->fromgpg_errfd;
00278               }
00279 
00280               if (select(maxfd+1, &fdr, &fdw, NULL, NULL) <= 0)
00281                      continue;
00282 
00283               libmail_gpgmime_read(fi, &fdr);
00284 
00285               if (!FD_ISSET(fi->togpg_fd, &fdw))
00286                      continue;
00287 
00288               i=write(fi->togpg_fd, p, n);
00289 
00290               if (i <= 0)
00291                      fi->gpg_errflag=1;
00292               else
00293               {
00294                      p += i;
00295                      n -= i;
00296               }
00297        }
00298        fi->gpg_writecnt=0;
00299 }
00300 
00301 int libmail_gpgmime_finish(struct gpgmime_forkinfo *fi)
00302 {
00303        pid_t p2;
00304        int waitstat;
00305 
00306        gpgmime_writeflush(fi);
00307        close(fi->togpg_fd);
00308        sigaction(SIGPIPE, &fi->old_pipe_sig, NULL);
00309 
00310        while (!fi->gpg_errflag &&
00311               (fi->fromgpg_fd >= 0 || fi->fromgpg_errfd >= 0))
00312        {
00313               fd_set fdr;
00314               int maxfd=0;
00315 
00316               FD_ZERO(&fdr);
00317 
00318               if (fi->fromgpg_fd >= 0)
00319               {
00320                      FD_SET(fi->fromgpg_fd, &fdr);
00321                      if (fi->fromgpg_fd > maxfd)
00322                             maxfd=fi->fromgpg_fd;
00323               }
00324 
00325               if (fi->fromgpg_errfd >= 0)
00326               {
00327                      FD_SET(fi->fromgpg_errfd, &fdr);
00328                      if (fi->fromgpg_errfd > maxfd)
00329                             maxfd=fi->fromgpg_errfd;
00330               }
00331 
00332               if (select(maxfd+1, &fdr, NULL, NULL, NULL) <= 0)
00333                      continue;
00334 
00335               libmail_gpgmime_read(fi, &fdr);
00336        }
00337 
00338        while ((p2=wait(&waitstat)) != fi->gpg_pid)
00339        {
00340               if (p2 < 0 && errno == ECHILD)
00341                      break;
00342        }
00343 
00344        if (fi->gpg_errflag == 0)
00345        {
00346               if (!WIFEXITED(waitstat))
00347                      fi->gpg_errflag=1;
00348               else
00349                      fi->gpg_errflag=WEXITSTATUS(waitstat);
00350        }
00351        return (fi->gpg_errflag);
00352 }
00353 
00354 int libmail_gpgmime_forksignencrypt(const char *gpgdir,
00355                                 const char *passphrase_fd,
00356                                 int flags,
00357                                 int argc, char **argv,
00358                                 int (*output_func)(const char *,
00359                                                  size_t, void *),
00360                                 void *output_voidarg,
00361                                 struct gpgmime_forkinfo *gpgfi)
00362 {
00363        char *xargvec[5];
00364        int xargc=0;
00365        int rc;
00366 
00367        if (flags & GPG_SE_SIGN)
00368        {
00369               xargvec[xargc++]="-s";
00370               if (! (flags & GPG_SE_ENCRYPT))
00371                      xargvec[xargc++]="-b";
00372        }
00373 
00374        if (flags & GPG_SE_ENCRYPT)
00375               xargvec[xargc++]="-e";
00376 
00377        xargvec[xargc++]="-a";
00378 
00379        rc=libmail_gpgmime_fork(gpgdir, passphrase_fd,
00380                      xargc, xargvec, argc, argv, gpgfi);
00381 
00382        gpgfi->gpg_readhandler= output_func;
00383        gpgfi->gpg_voidarg=output_voidarg;
00384        return (rc);
00385 }
00386 
00387 int libmail_gpgmime_forkchecksign(const char *gpgdir,
00388                        const char *passphrase_fd,
00389                        const char *content_filename,
00390                        const char *signature_filename,
00391                        int argc, char **argv,
00392                        struct gpgmime_forkinfo *gpgfi)
00393 {
00394        char *xargvec[3];
00395        char **newargv;
00396        int i;
00397        int rc;
00398 
00399        xargvec[0]="--verify";
00400        xargvec[1]="--charset";
00401        xargvec[2]=GPG_CHARSET;
00402 
00403        newargv=(char **)malloc((argc+2)*sizeof(char *));
00404        if (!newargv)
00405        {
00406               perror("malloc");
00407               exit(1);
00408        }
00409 
00410        for (i=0; i<argc; i++)
00411               newargv[i]=argv[i];
00412        newargv[i++]=(char *)signature_filename;
00413        newargv[i++]=(char *)content_filename;
00414 
00415        rc=libmail_gpgmime_fork(gpgdir, passphrase_fd, 3, xargvec, i, newargv, gpgfi);
00416        free(newargv);
00417        return (rc);
00418 }
00419 
00420 int libmail_gpgmime_forkdecrypt(const char *gpgdir,
00421                      const char *passphrase_fd,
00422                      int argc, char **argv,
00423                      int (*output_func)(const char *, size_t, void *),
00424                      void *output_voidarg,
00425                      struct gpgmime_forkinfo *gpgfi)
00426 {
00427        char *xargv[3];
00428        int rc;
00429 
00430        xargv[0]="--decrypt";
00431        xargv[1]="--charset";
00432        xargv[2]=GPG_CHARSET;
00433 
00434        rc=libmail_gpgmime_fork(gpgdir, passphrase_fd, 3, xargv, argc, argv, gpgfi);
00435 
00436        gpgfi->gpg_readhandler= output_func;
00437        gpgfi->gpg_voidarg= output_voidarg;
00438        return (rc);
00439 }
00440 
00441 const char *libmail_gpgmime_getoutput(struct gpgmime_forkinfo *gpgfi)
00442 {
00443        return (gpgfi->gpg_errbuf);
00444 }
00445 
00446 const char *libmail_gpgmime_getcharset(struct gpgmime_forkinfo *gpgfi)
00447 {
00448        return (GPG_CHARSET);
00449 }