Back to index

courier  0.68.2
gpg.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2001-2011 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 <ctype.h>
00012 #include <errno.h>
00013 #include <unistd.h>
00014 #include <time.h>
00015 #if    HAVE_FCNTL_H
00016 #include <fcntl.h>
00017 #endif
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 "mimegpgheader.h"
00033 #include "mimegpgstack.h"
00034 #include "mimegpgfork.h"
00035 #include "tempname.h"
00036 #include "gpglib.h"
00037 #include "rfc822/encode.h"
00038 #include "rfc2045/rfc2045.h"
00039 
00040 static int my_rewind(FILE *fp)
00041 {
00042        if (fflush(fp) || ferror(fp) || fseek(fp, 0L, SEEK_SET))
00043               return (-1);
00044        clearerr(fp);
00045        return (0);
00046 }
00047 
00048 int libmail_gpg_inputfunc_readfp(char *buf, size_t cnt, void *vp)
00049 {
00050        FILE *fp=(FILE *)vp;
00051        size_t i;
00052        int c;
00053 
00054        if (cnt == 0)
00055               return -1;
00056 
00057        --cnt;
00058 
00059        for (i=0; i<cnt; i++)
00060        {
00061               if ((c=getc(fp)) == EOF)
00062               {
00063                      if (i == 0)
00064                             return -1;
00065                      break;
00066               }
00067               buf[i]=c;
00068 
00069               if (c == '\n')
00070               {
00071                      ++i;
00072                      break;
00073               }
00074        }
00075        buf[i]=0;
00076        return 0;
00077 }
00078 
00079 void libmail_gpg_noexec(int fd)
00080 {
00081 #ifdef FD_CLOEXEC
00082        fcntl(fd, F_SETFD, FD_CLOEXEC);
00083 #endif
00084 }
00085 
00086 /*
00087 ** Check if the line just read is a MIME boundary line.  Search the
00088 ** current MIME stack for a matching MIME boundary delimiter.
00089 */
00090 
00091 static struct mimestack *is_boundary(struct mimestack *s, const char *line,
00092                                  int *isclosing)
00093 {
00094        struct mimestack *b;
00095 
00096        if (line[0] != '-' || line[1] != '-' ||
00097            (b=libmail_mimestack_search(s, line+2)) == 0)
00098               return (NULL);
00099 
00100 
00101        *isclosing=strncmp(line+2+strlen(b->boundary), "--", 2) == 0;
00102        return (b);
00103 }
00104 
00105 static const char *get_boundary(struct mimestack *,
00106                             const char *,
00107                             FILE *);
00108 
00109 /*
00110 ** Skip until EOF or a MIME boundary delimiter other than a closing MIME
00111 ** boundary delimiter.  After returning from bind_boundary we expect to
00112 ** see MIME headers.  Copy any intermediate lines to fpout.
00113 */
00114 
00115 static void find_boundary(struct mimestack **stack, int *iseof,
00116                        int (*input_func)(char *, size_t, void *vp),
00117                        void *input_func_arg,
00118                        void (*output_func)(const char *,
00119                                          size_t,
00120                                          void *),
00121                        void *output_func_arg,
00122                        int doappend)
00123 {
00124        char buf[BUFSIZ];
00125 
00126        for (;;)
00127        {
00128               int is_closing;
00129               struct mimestack *b;
00130 
00131               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
00132               {
00133                      *iseof=1;
00134                      return;
00135               }
00136 
00137               if (!(b=is_boundary(*stack, buf, &is_closing)))
00138               {
00139                      if (output_func)
00140                             (*output_func)(buf, strlen(buf),
00141                                           output_func_arg);
00142 
00143                      while (strchr(buf, '\n') == 0)
00144                      {
00145                             if ( (*input_func)(buf, sizeof(buf),
00146                                              input_func_arg))
00147                             {
00148                                    *iseof=1;
00149                                    return;
00150                             }
00151                             if (output_func)
00152                                    (*output_func)(buf, strlen(buf),
00153                                                  output_func_arg);
00154                      }
00155                      continue;
00156               }
00157 
00158               if (output_func)
00159               {
00160                      (*output_func)("--", 2, output_func_arg);
00161                      (*output_func)(b->boundary, strlen(b->boundary),
00162                                    output_func_arg);
00163 
00164                      if (is_closing)
00165                             (*output_func)("--", 2, output_func_arg);
00166 
00167                      (*output_func)("\n", 1, output_func_arg);
00168               }
00169 
00170               if (is_closing)
00171               {
00172                      libmail_mimestack_pop_to(stack, b);
00173                      continue;
00174               }
00175               break;
00176        }
00177 }
00178 
00179 
00180 /*
00181 ** Read a set of headers.
00182 */
00183 
00184 static struct header *read_headers(struct mimestack **stack, int *iseof,
00185                                int (*input_func)(char *, size_t, void *vp),
00186                                void *input_func_arg,
00187                                void (*output_func)(const char *,
00188                                                  size_t,
00189                                                  void *),
00190                                void *output_func_arg,
00191                                int doappend,
00192                                int *errflag)
00193 {
00194        char buf[BUFSIZ];
00195        struct read_header_context rhc;
00196        struct header *h;
00197 
00198        *errflag=0;
00199        libmail_readheader_init(&rhc);
00200 
00201        while (!*iseof)
00202        {
00203               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
00204               {
00205                      *iseof=1;
00206                      break;
00207               }
00208 
00209               if (READ_START_OF_LINE(rhc))
00210               {
00211                      struct mimestack *b;
00212                      int is_closing;
00213 
00214                      if (strcmp(buf, "\n") == 0
00215                          || strcmp(buf, "\r\n") == 0)
00216                             break;
00217 
00218                      b=is_boundary(*stack, buf, &is_closing);
00219 
00220                      if (b)
00221                      {
00222                             /*
00223                             ** Corrupted MIME message.  We should NOT
00224                             ** see a MIME boundary in the middle of the
00225                             ** headers!
00226                             **
00227                             ** Ignore this damage.
00228                             */
00229 
00230                             struct header *p;
00231 
00232                             h=libmail_readheader_finish(&rhc);
00233 
00234                             for (p=h; p; p=p->next)
00235                                    (*output_func)(p->header,
00236                                                  strlen(p->header),
00237                                                  output_func_arg);
00238 
00239                             (*output_func)("--", 2, output_func_arg);
00240                             (*output_func)(b->boundary,
00241                                           strlen(b->boundary),
00242                                           output_func_arg);
00243 
00244                             if (is_closing)
00245                                    (*output_func)("--", 2,
00246                                                  output_func_arg);
00247 
00248                             (*output_func)("\n", 1, output_func_arg);
00249 
00250                             if (is_closing)
00251                             {
00252                                    libmail_mimestack_pop_to(stack, b);
00253                                    find_boundary(stack, iseof,
00254                                                 input_func,
00255                                                 input_func_arg,
00256                                                 output_func,
00257                                                 output_func_arg,
00258                                                 doappend);
00259                             }
00260                             libmail_header_free(h);
00261 
00262                             libmail_readheader_init(&rhc);
00263                             continue; /* From the top */
00264                      }
00265               }
00266               if (libmail_readheader(&rhc, buf) < 0)
00267               {
00268                      libmail_header_free(libmail_readheader_finish(&rhc));
00269                      *errflag= -1;
00270                      return NULL;
00271               }
00272        }
00273 
00274        return (libmail_readheader_finish(&rhc));
00275 }
00276 
00277 /*
00278 ** Here we do actual signing/encoding
00279 */
00280 
00281 static int encode_header(const char *h)
00282 {
00283        if (strncasecmp(h, "content-", 8) == 0)
00284               return (1);
00285        return (0);
00286 }
00287 
00288 struct gpg_fork_output_info {
00289        void (*output_func)(const char *, size_t, void *);
00290        void *output_func_arg;
00291        struct gpgmime_forkinfo *gpgptr;
00292 };
00293 
00294 static int gpg_fork_output(const char *p, size_t n, void *dummy)
00295 {
00296        struct gpg_fork_output_info *info=(struct gpg_fork_output_info *)dummy;
00297 
00298        (*info->output_func)(p, n, info->output_func_arg);
00299        return 0;
00300 }
00301 
00302 
00303 static int dogpgencrypt(const char *gpghome,
00304                      const char *passphrase_fd,
00305                      struct mimestack **stack,
00306                      struct header *h, int *iseof,
00307                      int (*input_func)(char *, size_t, void *vp),
00308                      void *input_func_arg,
00309                      void (*output_func)(const char *,
00310                                        size_t,
00311                                        void *),
00312                      void *output_func_arg,
00313                      int argc,
00314                      char **argv,
00315                      int dosign,
00316                      void (*errhandler)(const char *, void *),
00317                      void *errhandler_arg)
00318 {
00319        struct header *hp;
00320        char buf[BUFSIZ];
00321        struct gpgmime_forkinfo gpg;
00322        int clos_flag=0;
00323        struct mimestack *b=0;
00324        int rc;
00325        const char *boundary;
00326        int need_crlf;
00327        struct gpg_fork_output_info gfoi;
00328 
00329        boundary=get_boundary(*stack, "", NULL);
00330 
00331        gfoi.output_func=output_func;
00332        gfoi.output_func_arg=output_func_arg;
00333 
00334        if (libmail_gpgmime_forksignencrypt(gpghome, passphrase_fd,
00335                                        (dosign ? GPG_SE_SIGN:0)
00336                                        | GPG_SE_ENCRYPT,
00337                                        argc, argv,
00338                                        &gpg_fork_output, &gfoi,
00339                                        &gpg))
00340        {
00341               return -1;
00342        }
00343 
00344        for (hp=h; hp; hp=hp->next)
00345        {
00346               if (encode_header(hp->header))
00347                      continue;
00348 
00349               (*output_func)(hp->header, strlen(hp->header),
00350                             output_func_arg);
00351        }
00352 
00353 #define C(s) (*output_func)( s, sizeof(s)-1, output_func_arg)
00354 #define S(s) (*output_func)( s, strlen(s), output_func_arg)
00355 
00356 
00357        C("Content-Type: multipart/encrypted;\n"
00358          "    boundary=\"");
00359 
00360        S(boundary);
00361 
00362        C("\";\n"
00363          "    protocol=\"application/pgp-encrypted\"\n"
00364          "\n"
00365          "This is a MIME GnuPG-encrypted message.  If you see this text, it means\n"
00366          "that your E-mail or Usenet software does not support MIME encrypted messages.\n"
00367          "The Internet standard for MIME PGP messages, RFC 2015, was published in 1996.\n"
00368          "To open this message correctly you will need to install E-mail or Usenet\n"
00369          "software that supports modern Internet standards.\n"
00370          "\n--");
00371 
00372        S(boundary);
00373 
00374        C("\n"
00375          "Content-Type: application/pgp-encrypted\n"
00376          "Content-Transfer-Encoding: 7bit\n"
00377          "\n"
00378          "Version: 1\n"
00379          "\n--");
00380 
00381        S(boundary);
00382 
00383        C("\n"
00384          "Content-Type: application/octet-stream\n"
00385          "Content-Transfer-Encoding: 7bit\n\n");
00386 
00387 #undef C
00388 #undef S
00389 
00390        /* For Eudora compatiblity */
00391         libmail_gpgmime_write(&gpg, "Mime-Version: 1.0\r\n", 19);
00392 
00393        for (hp=h; hp; hp=hp->next)
00394        {
00395               const char *p;
00396 
00397               if (!encode_header(hp->header))
00398                      continue;
00399 
00400               for (p=hp->header; *p; p++)
00401               {
00402                      if (*p == '\r')
00403                             continue;
00404 
00405                      if (*p == '\n')
00406                             libmail_gpgmime_write(&gpg, "\r\n", 2);
00407                      else
00408                             libmail_gpgmime_write(&gpg, p, 1);
00409               }
00410        }
00411 
00412        /*
00413        ** Chew the content until the next MIME boundary.
00414        */
00415        need_crlf=1;
00416 
00417        while (!*iseof)
00418        {
00419               const char *p;
00420 
00421               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
00422               {
00423                      *iseof=1;
00424                      break;
00425               }
00426 
00427               if (need_crlf)
00428               {
00429                      if ((b=is_boundary(*stack, buf, &clos_flag)) != NULL)
00430                             break;
00431 
00432                      libmail_gpgmime_write(&gpg, "\r\n", 2);
00433               }
00434 
00435               need_crlf=0;
00436               for (;;)
00437               {
00438                      for (p=buf; *p; p++)
00439                      {
00440                             if (*p == '\r')
00441                                    continue;
00442                             if (*p == '\n')
00443                             {
00444                                    need_crlf=1;
00445                                    break;
00446                             }
00447 
00448                             libmail_gpgmime_write(&gpg, p, 1);
00449                      }
00450                      if (*p == '\n')
00451                             break;
00452 
00453                      if ( (*input_func)(buf, sizeof(buf), input_func_arg))
00454                      {
00455                             *iseof=1;
00456                             break;
00457                      }
00458               }
00459        }
00460 
00461        /*
00462        ** This needs some 'splainin.  Note that we spit out a newline at
00463        ** the BEGINNING of each line, above.  This generates the blank
00464        ** header->body separator line.  Now, if we're NOT doing multiline
00465        ** content, we need to follow the last line of the content with a
00466        ** newline.  If we're already doing multiline content, that extra
00467        ** newline (if it exists) is already there.
00468        */
00469 
00470        if (!*stack)
00471        {
00472               libmail_gpgmime_write(&gpg, "\r\n", 2);
00473        }
00474 
00475        rc=libmail_gpgmime_finish(&gpg);
00476 
00477        if (rc)
00478        {
00479               (*errhandler)(libmail_gpgmime_getoutput(&gpg), errhandler_arg);
00480               return (-1);
00481        }
00482 
00483        (*output_func)("\n--", 3, output_func_arg);
00484        (*output_func)(boundary, strlen(boundary), output_func_arg);
00485        (*output_func)("--\n", 3, output_func_arg);
00486 
00487        if (*iseof)
00488               return 0;
00489 
00490        (*output_func)("\n--", 3, output_func_arg);
00491        (*output_func)(b->boundary, strlen(b->boundary), output_func_arg);
00492        if (clos_flag)
00493               (*output_func)("--", 2, output_func_arg);
00494        (*output_func)("\n", 1, output_func_arg);
00495 
00496        if (clos_flag)
00497        {
00498               libmail_mimestack_pop_to(stack, b);
00499               find_boundary(stack, iseof, input_func,
00500                            input_func_arg, output_func,
00501                            output_func_arg, 1);
00502        }
00503 
00504        return 0;
00505 }
00506 
00507 static int dogpgsign(const char *gpghome, const char *passphrase_fd,
00508                    struct mimestack **stack, struct header *h, int *iseof,
00509                    int (*input_func)(char *, size_t, void *vp),
00510                    void *input_func_arg,
00511                    void (*output_func)(const char *,
00512                                     size_t,
00513                                     void *),
00514                    void *output_func_arg,
00515                    int argc,
00516                    char **argv,
00517                    void (*errhandler)(const char *, void *),
00518                    void *errhandler_arg)
00519 {
00520        struct header *hp;
00521        char buf[8192];
00522        struct gpgmime_forkinfo gpg;
00523        int clos_flag=0;
00524        struct mimestack *b=0;
00525        int rc=0;
00526        char signed_content_name[TEMPNAMEBUFSIZE];
00527        int signed_content;
00528        FILE *signed_content_fp;
00529        const char *boundary;
00530        int need_crlf;
00531        struct gpg_fork_output_info gfoi;
00532 
00533        for (hp=h; hp; hp=hp->next)
00534        {
00535               if (encode_header(hp->header))
00536                      continue;
00537               (*output_func)(hp->header, strlen(hp->header),
00538                             output_func_arg);
00539        }
00540 
00541        signed_content=libmail_tempfile(signed_content_name);
00542        if (signed_content < 0 ||
00543            (signed_content_fp=fdopen(signed_content, "w+")) == NULL)
00544        {
00545               if (signed_content >= 0)
00546               {
00547                      close(signed_content);
00548                      unlink(signed_content_name);
00549               }
00550               return -1;
00551 
00552        }
00553        libmail_gpg_noexec(fileno(signed_content_fp));
00554        unlink(signed_content_name);       /* UNIX semantics */
00555 
00556        for (hp=h; hp; hp=hp->next)
00557        {
00558               const char *p;
00559 
00560               if (!encode_header(hp->header))
00561                      continue;
00562 
00563               for (p=hp->header; *p; p++)
00564               {
00565                      if (*p == '\r')
00566                             continue;
00567 
00568                      if (*p == '\n')
00569                             putc('\r', signed_content_fp);
00570                      putc(*p, signed_content_fp);
00571               }
00572        }
00573 
00574        /*
00575        ** Chew the content until the next MIME boundary.
00576        */
00577        need_crlf=1;
00578        while (!*iseof)
00579        {
00580               const char *p;
00581 
00582               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
00583               {
00584                      *iseof=1;
00585                      break;
00586               }
00587 
00588               if (need_crlf)
00589               {
00590                      if ((b=is_boundary(*stack, buf, &clos_flag)) != NULL)
00591                             break;
00592 
00593                      fprintf(signed_content_fp, "\r\n");
00594               }
00595 
00596               need_crlf=0;
00597               for (;;)
00598               {
00599                      for (p=buf; *p; p++)
00600                      {
00601                             if (*p == '\r')
00602                                    continue;
00603                             if (*p == '\n')
00604                             {
00605                                    need_crlf=1;
00606                                    break;
00607                             }
00608 
00609                             putc(*p, signed_content_fp);
00610                      }
00611                      if (*p == '\n')
00612                             break;
00613 
00614                      if ( (*input_func)(buf, sizeof(buf), input_func_arg))
00615                      {
00616                             *iseof=1;
00617                             break;
00618                      }
00619               }
00620        }
00621 
00622        /*
00623        ** This needs some 'splainin.  Note that we spit out a newline at
00624        ** the BEGINNING of each line, above.  This generates the blank
00625        ** header->body separator line.  Now, if we're NOT doing multiline
00626        ** content, we need to follow the last line of the content with a
00627        ** newline.  If we're already doing multiline content, that extra
00628        ** newline (if it exists) is already there.
00629        */
00630 
00631        if (!*stack)
00632        {
00633               fprintf(signed_content_fp, "\r\n");
00634        }
00635 
00636        if (fflush(signed_content_fp) < 0 || ferror(signed_content_fp))
00637        {
00638               fclose(signed_content_fp);
00639               return (-1);
00640        }
00641 
00642        boundary=get_boundary(*stack, "", signed_content_fp);
00643 
00644        if (my_rewind(signed_content_fp) < 0)
00645        {
00646               fclose(signed_content_fp);
00647               return (-1);
00648        }
00649 
00650 #define C(s) (*output_func)( s, sizeof(s)-1, output_func_arg)
00651 #define S(s) (*output_func)( s, strlen(s), output_func_arg)
00652 
00653        C("Content-Type: multipart/signed;\n"
00654          "    boundary=\"");
00655        S(boundary);
00656        C("\";\n"
00657          "    micalg=pgp-sha1;"
00658          " protocol=\"application/pgp-signature\"\n"
00659          "\n"
00660          "This is a MIME GnuPG-signed message.  If you see this text, it means that\n"
00661          "your E-mail or Usenet software does not support MIME signed messages.\n"
00662          "The Internet standard for MIME PGP messages, RFC 2015, was published in 1996.\n"
00663          "To open this message correctly you will need to install E-mail or Usenet\n"
00664          "software that supports modern Internet standards.\n"
00665          "\n--");
00666        S(boundary);
00667        C("\n");
00668 
00669 
00670        gfoi.output_func=output_func;
00671        gfoi.output_func_arg=output_func_arg;
00672        gfoi.gpgptr= &gpg;
00673 
00674        if (libmail_gpgmime_forksignencrypt(gpghome, passphrase_fd,
00675                                        GPG_SE_SIGN,
00676                                        argc, argv,
00677                                        &gpg_fork_output, &gfoi,
00678                                        &gpg))
00679        {
00680               fclose(signed_content_fp);
00681               return (-1);
00682        }
00683 
00684        while (fgets(buf, sizeof(buf), signed_content_fp) != NULL)
00685        {
00686               char *p;
00687               size_t j, k;
00688 
00689               libmail_gpgmime_write(&gpg, buf, strlen(buf));
00690 
00691               p=buf;
00692               for (j=k=0; p[j]; j++)
00693                      if (p[j] != '\r')
00694                             p[k++]=p[j];
00695 
00696               if (k)
00697                      (*output_func)(p, k, output_func_arg);
00698        }
00699 
00700        C("\n--");
00701        S(boundary);
00702 
00703        C("\n"
00704          "Content-Type: application/pgp-signature\n"
00705          "Content-Transfer-Encoding: 7bit\n\n");
00706 
00707 #undef C
00708 #undef S
00709 
00710        if (libmail_gpgmime_finish(&gpg))
00711               rc= -1; /* TODO */
00712 
00713        if (rc)
00714        {
00715               (*errhandler)(libmail_gpgmime_getoutput(&gpg),
00716                            errhandler_arg);
00717               fclose(signed_content_fp);
00718               return -1;
00719        }
00720 
00721        (*output_func)("\n--", 3, output_func_arg);
00722        (*output_func)(boundary, strlen(boundary), output_func_arg);
00723        (*output_func)("--\n", 3, output_func_arg);
00724 
00725        fclose(signed_content_fp);
00726        if (*iseof)
00727               return 0;
00728 
00729        (*output_func)("\n--", 3, output_func_arg);
00730        (*output_func)(b->boundary, strlen(b->boundary), output_func_arg);
00731        if (clos_flag)
00732               (*output_func)("--", 2, output_func_arg);
00733        (*output_func)("\n", 1, output_func_arg);
00734 
00735        if (clos_flag)
00736        {
00737               libmail_mimestack_pop_to(stack, b);
00738               find_boundary(stack, iseof, input_func, input_func_arg,
00739                            output_func, output_func_arg, 1);
00740        }
00741        return 0;
00742 }
00743 
00744 static int isgpg(struct mime_header *);
00745 static int checksign(const char *gpghome,
00746                    const char *passphrase_fd,
00747                    struct mimestack **, int *, struct header *,
00748                    int (*input_func)(char *, size_t, void *vp),
00749                    void *input_func_arg,
00750                    void (*)(const char *, size_t, void *),
00751                    void *,
00752                    int, char **,
00753                    int *);
00754 static int decrypt(const char *gpghome,
00755                  const char *passphrase_fd,
00756                  struct mimestack **, int *, struct header *,
00757                  int (*input_func)(char *, size_t, void *vp),
00758                  void *input_func_arg,
00759                  void (*)(const char *, size_t, void *),
00760                  void *,
00761                  int, char **,
00762                  int *);
00763 
00764 static void print_noncontent_headers(struct header *h,
00765                                  void (*output_func)(const char *,
00766                                                   size_t,
00767                                                   void *),
00768                                  void *output_func_arg)
00769 {
00770        struct header *p;
00771 
00772        for (p=h; p; p=p->next)
00773        {
00774               if (strncasecmp(p->header, "content-", 8) == 0)
00775                      continue;
00776               (*output_func)(p->header, strlen(p->header), output_func_arg);
00777        }
00778 }
00779 
00780 static int dosignencode2(int dosign, int doencode, int dodecode,
00781                       const char *gpghome,
00782                       const char *passphrase_fd,
00783                       int (*input_func)(char *, size_t, void *vp),
00784                       void *input_func_arg,
00785                       void (*output_func)(const char *,
00786                                         size_t,
00787                                         void *),
00788                       void *output_func_arg,
00789                       void (*errhandler_func)(const char *, void *),
00790                       void *errhandler_arg,
00791                       int argc, char **argv,
00792                       int *status)
00793 {
00794        struct mimestack *boundary_stack=0;
00795        int iseof=0;
00796 
00797        *status=0;
00798 
00799        while (!iseof)
00800        {
00801               int errflag;
00802 
00803               static const char ct_s[]="content-type:";
00804               struct header *h=read_headers(&boundary_stack, &iseof,
00805                                          input_func, input_func_arg,
00806                                          output_func,
00807                                          output_func_arg,
00808                                          dodecode ? 0:1,
00809                                          &errflag),
00810                      *hct;
00811 
00812               if (errflag)
00813                      return 1;
00814 
00815               if (iseof && !h)
00816                      continue;     /* Artifact */
00817 
00818               hct=libmail_header_find(h, ct_s);
00819 
00820               /*
00821               ** If this is a multipart MIME section, we can keep on
00822               ** truckin'.
00823               **
00824               */
00825 
00826               if (hct)
00827               {
00828                      struct mime_header *mh=
00829                             libmail_mimeheader_parse(hct->header+
00830                                                   (sizeof(ct_s)-1));
00831                      const char *bv;
00832 
00833                      if (!mh)
00834                      {
00835                             libmail_header_free(h);
00836                             return (-1);
00837                      }
00838 
00839                      if (strcasecmp(mh->header_name, "multipart/x-mimegpg")
00840                          == 0)
00841                      {
00842                             /* Punt */
00843 
00844                             char *buf=malloc(strlen(hct->header)+100);
00845                             const char *p;
00846 
00847                             if (!buf)
00848                             {
00849                                    libmail_mimeheader_free(mh);
00850                                    libmail_header_free(h);
00851                                    return (-1);
00852                             }
00853                             strcpy(buf, "Content-Type: multipart/mixed");
00854                             p=strchr(hct->header, ';');
00855                             strcat(buf, p ? p:"");
00856                             free(hct->header);
00857                             hct->header=buf;
00858 
00859                             libmail_mimeheader_free(mh);
00860                             mh=libmail_mimeheader_parse(hct->header+
00861                                                      sizeof(ct_s)-1);
00862                             if (!mh)
00863                             {
00864                                    libmail_header_free(h);
00865                                    return (-1);
00866                             }
00867                      }
00868 
00869                      if (strncasecmp(mh->header_name, "multipart/", 10)==0
00870                          && (bv=libmail_mimeheader_getattr(mh, "boundary")) != 0
00871 
00872                          && (doencode & LIBMAIL_GPG_ENCAPSULATE) == 0
00873 
00874                          && !dosign
00875                          )
00876                      {
00877                             struct header *p;
00878 
00879                             if (libmail_mimestack_push(&boundary_stack,
00880                                                     bv) < 0)
00881                             {
00882                                    libmail_header_free(h);
00883                                    return (-1);
00884                             }
00885 
00886                             if (dodecode)
00887                             {
00888                                    int rc;
00889 
00890                                    if (strcasecmp(mh->header_name,
00891                                                  "multipart/signed")==0
00892                                        && (dodecode & LIBMAIL_GPG_CHECKSIGN)
00893                                        && isgpg(mh))
00894                                    {
00895                                           int errflag;
00896 
00897                                           print_noncontent_headers(h,
00898                                                                 output_func,
00899                                                                 output_func_arg
00900                                                                 );
00901                                           libmail_mimeheader_free(mh);
00902                                           rc=checksign(gpghome,
00903                                                       passphrase_fd,
00904                                                       &boundary_stack,
00905                                                       &iseof,
00906                                                       h,
00907                                                       input_func,
00908                                                       input_func_arg,
00909                                                       output_func,
00910                                                       output_func_arg,
00911                                                       argc, argv,
00912                                                       &errflag);
00913                                           libmail_header_free(h);
00914 
00915                                           if (errflag)
00916                                                  *status |=
00917                                                         LIBMAIL_ERR_VERIFYSIG;
00918                                           if (rc)
00919                                                  return -1;
00920 
00921                                           continue;
00922                                    }
00923 
00924                                    if (strcasecmp(mh->header_name,
00925                                                  "multipart/encrypted")
00926                                        ==0
00927                                        && (dodecode & LIBMAIL_GPG_UNENCRYPT)
00928                                        && isgpg(mh))
00929                                    {
00930                                           int errflag;
00931 
00932                                           print_noncontent_headers(h,
00933                                                                 output_func,
00934                                                                 output_func_arg
00935                                                                 );
00936                                           libmail_mimeheader_free(mh);
00937                                           rc=decrypt(gpghome,
00938                                                     passphrase_fd,
00939                                                     &boundary_stack,
00940                                                     &iseof,
00941                                                     h,
00942                                                     input_func,
00943                                                     input_func_arg,
00944                                                     output_func,
00945                                                     output_func_arg,
00946                                                     argc, argv,
00947                                                     &errflag);
00948                                           libmail_header_free(h);
00949 
00950                                           if (errflag)
00951                                                  *status |=
00952                                                         LIBMAIL_ERR_DECRYPT;
00953                                           if (rc)
00954                                                  return -1;
00955                                           continue;
00956                                    }
00957                             }
00958 
00959                             for (p=h; p; p=p->next)
00960                             {
00961                                    (*output_func)(p->header,
00962                                                  strlen(p->header),
00963                                                  output_func_arg);
00964                             }
00965 
00966                             (*output_func)("\n", 1, output_func_arg);
00967                             libmail_header_free(h);
00968                             libmail_mimeheader_free(mh);
00969 
00970                             find_boundary(&boundary_stack, &iseof,
00971                                          input_func,
00972                                          input_func_arg,
00973                                          output_func,
00974                                          output_func_arg, dodecode ? 0:1);
00975                             continue;
00976                      }
00977                      libmail_mimeheader_free(mh);
00978               }
00979 
00980               if (dodecode)
00981               {
00982                      struct header *p;
00983                      int is_message_rfc822=0;
00984 
00985                      for (p=h; p; p=p->next)
00986                      {
00987                             (*output_func)(p->header,
00988                                           strlen(p->header),
00989                                           output_func_arg);
00990                      }
00991                      (*output_func)("\n", 1, output_func_arg);
00992 
00993                      /*
00994                      ** If this is a message/rfc822 attachment, we can
00995                      ** resume reading the next set of headers.
00996                      */
00997 
00998                      hct=libmail_header_find(h, ct_s);
00999                      if (hct)
01000                      {
01001                             struct mime_header *mh=
01002                                    libmail_mimeheader_parse(hct->header+
01003                                                          (sizeof(ct_s)
01004                                                           -1));
01005                             if (!mh)
01006                             {
01007                                    libmail_header_free(h);
01008                                    return (-1);
01009                             }
01010 
01011                             if (strcasecmp(mh->header_name,
01012                                           "message/rfc822") == 0)
01013                                    is_message_rfc822=1;
01014                             libmail_mimeheader_free(mh);
01015                      }
01016                      libmail_header_free(h);
01017 
01018                      if (!is_message_rfc822)
01019                             find_boundary(&boundary_stack, &iseof,
01020                                          input_func,
01021                                          input_func_arg,
01022                                          output_func,
01023                                          output_func_arg, 0);
01024                      continue;
01025               }
01026 
01027               if (doencode ?
01028                   dogpgencrypt(gpghome,
01029                              passphrase_fd,
01030                              &boundary_stack, h, &iseof,
01031                              input_func,
01032                              input_func_arg,
01033                              output_func,
01034                              output_func_arg,
01035                              argc, argv, dosign,
01036                              errhandler_func, errhandler_arg)
01037                   :
01038                   dogpgsign(gpghome,
01039                            passphrase_fd,
01040                            &boundary_stack, h, &iseof,
01041                            input_func,
01042                            input_func_arg,
01043                            output_func,
01044                            output_func_arg,
01045                            argc, argv,
01046                            errhandler_func, errhandler_arg))
01047               {
01048                      libmail_header_free(h);
01049                      return 1;
01050               }
01051 
01052               libmail_header_free(h);
01053        }
01054 
01055        return (0);
01056 }
01057 
01058 
01059 static int isgpg(struct mime_header *mh)
01060 {
01061        const char *attr;
01062 
01063        attr=libmail_mimeheader_getattr(mh, "protocol");
01064 
01065        if (!attr)
01066               return (0);
01067 
01068        if (strcasecmp(attr, "application/pgp-encrypted") == 0)
01069               return (1);
01070 
01071        if (strcasecmp(attr, "application/pgp-signature") == 0)
01072        {
01073               return (1);
01074        }
01075        return (0);
01076 }
01077 
01078 static int nybble(char c)
01079 {
01080        static const char x[]="0123456789ABCDEFabcdef";
01081 
01082        const char *p=strchr(x, c);
01083        int n;
01084 
01085        if (!p) p=x;
01086 
01087        n= p-x;
01088        if (n >= 16)
01089               n -= 6;
01090        return (n);
01091 }
01092 
01093 /*
01094 ** Check signature
01095 */
01096 
01097 static int dochecksign(const char *, const char *,
01098                      struct mimestack *,
01099                      FILE *,
01100                      void (*output_func)(const char *,
01101                                       size_t,
01102                                       void *),
01103                      void *output_func_arg,
01104                      const char *,
01105                      const char *,
01106                      int, char **, int *);
01107 
01108 static int checksign(const char *gpghome,
01109                    const char *passphrase_fd,
01110                    struct mimestack **stack, int *iseof,
01111                    struct header *h,
01112                    int (*input_func)(char *, size_t, void *vp),
01113                    void *input_func_arg,
01114                    void (*output_func)(const char *,
01115                                     size_t,
01116                                     void *),
01117                    void *output_func_arg,
01118                    int argc, char **argv, int *errptr)
01119 {
01120        char buf[BUFSIZ];
01121        struct header *h2;
01122 
01123        char signed_content[TEMPNAMEBUFSIZE];
01124        char signature[TEMPNAMEBUFSIZE];
01125        int signed_file, signature_file;
01126        FILE *signed_file_fp, *signature_file_fp;
01127        int clos_flag;
01128        int need_nl, check_boundary;
01129        struct mimestack *b=0;
01130        struct mime_header *mh;
01131        int qpdecode=0;
01132        int errflag;
01133 
01134        *errptr=0;
01135 
01136        signed_file=libmail_tempfile(signed_content);
01137 
01138        if (signed_file < 0 || (signed_file_fp=fdopen(signed_file, "w+")) == 0)
01139        {
01140               if (signed_file > 0)
01141               {
01142                      close(signed_file);
01143                      unlink(signed_content);
01144               }
01145               return -1;
01146        }
01147        libmail_gpg_noexec(fileno(signed_file_fp));
01148 
01149        find_boundary(stack, iseof, input_func,
01150                     input_func_arg, NULL, NULL, 0);
01151        if (*iseof)
01152               return 0;
01153 
01154        need_nl=0;
01155        check_boundary=1;
01156 
01157        while (!*iseof)
01158        {
01159               const char *p;
01160 
01161               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
01162               {
01163                      *iseof=1;
01164                      continue;
01165               }
01166 
01167               if (check_boundary
01168                   && (b=is_boundary(*stack, buf, &clos_flag)) != 0)
01169                      break;
01170               if (need_nl)
01171                      fprintf(signed_file_fp, "\r\n");
01172 
01173               for (p=buf; *p && *p != '\n'; p++)
01174                      putc(*p, signed_file_fp);
01175               need_nl=check_boundary= *p != 0;
01176        }
01177 
01178        if (my_rewind(signed_file_fp) < 0)
01179        {
01180               fclose(signed_file_fp);
01181               unlink(signed_content);
01182               return -1;
01183        }
01184 
01185        if (clos_flag)
01186        {
01187               fclose(signed_file_fp);
01188               unlink(signed_content);
01189               if (b)
01190                      libmail_mimestack_pop_to(stack, b);
01191               find_boundary(stack, iseof, input_func, input_func_arg,
01192                            output_func, output_func_arg, 1);
01193               return 0;
01194        }
01195 
01196        h=read_headers(stack, iseof, input_func, input_func_arg,
01197                      output_func, output_func_arg, 0, &errflag);
01198 
01199        if (errflag)
01200        {
01201               fclose(signed_file_fp);
01202               unlink(signed_content);
01203 
01204               return (-1);
01205        }
01206 
01207        if (!h || !(h2=libmail_header_find(h, "content-type:")))
01208        {
01209               if (h)
01210                      libmail_header_free(h);
01211               fclose(signed_file_fp);
01212               unlink(signed_content);
01213               if (!*iseof)
01214                      find_boundary(stack, iseof, input_func, input_func_arg,
01215                                   output_func, output_func_arg, 1);
01216               return 0;
01217        }
01218 
01219        mh=libmail_mimeheader_parse(h2->header+sizeof("content-type:")-1);
01220 
01221        if (!mh)
01222        {
01223               libmail_header_free(h);
01224               fclose(signed_file_fp);
01225               unlink(signed_content);
01226               return (-1);
01227        }
01228 
01229        if (strcasecmp(mh->header_name, "application/pgp-signature"))
01230        {
01231               libmail_mimeheader_free(mh);
01232               libmail_header_free(h);
01233               fclose(signed_file_fp);
01234               unlink(signed_content);
01235               if (!*iseof)
01236                      find_boundary(stack, iseof, input_func, input_func_arg,
01237                                   output_func, output_func_arg, 1);
01238               return (0);
01239        }
01240        libmail_mimeheader_free(mh);
01241 
01242        /*
01243        ** In rare instances, the signature is qp-encoded.
01244        */
01245 
01246        if ((h2=libmail_header_find(h, "content-transfer-encoding:")) != NULL)
01247        {
01248               mh=libmail_mimeheader_parse
01249                      (h2->header+sizeof("content-transfer-encoding:")-1);
01250 
01251               if (!mh)
01252               {
01253                      libmail_header_free(h);
01254                      fclose(signed_file_fp);
01255                      unlink(signed_content);
01256                      return -1;
01257               }
01258 
01259               if (strcasecmp(mh->header_name,
01260                             "quoted-printable") == 0)
01261                      qpdecode=1;
01262               libmail_mimeheader_free(mh);
01263        }
01264        libmail_header_free(h);
01265 
01266        signature_file=libmail_tempfile(signature);
01267 
01268        if (signature_file < 0
01269            || (signature_file_fp=fdopen(signature_file, "w+")) == 0)
01270        {
01271               if (signature_file > 0)
01272               {
01273                      close(signature_file);
01274                      unlink(signature);
01275               }
01276               unlink(signed_content);
01277               return (-1);
01278        }
01279 
01280        while (!*iseof)
01281        {
01282               const char *p;
01283 
01284               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
01285               {
01286                      *iseof=1;
01287                      continue;
01288               }
01289 
01290               if ((b=is_boundary(*stack, buf, &clos_flag)) != 0)
01291                      break;
01292 
01293               for (p=buf; *p; p++)
01294               {
01295                      int n;
01296 
01297                      if (!qpdecode)
01298                      {
01299                             putc(*p, signature_file_fp);
01300                             continue;
01301                      }
01302 
01303                      if (*p == '=' && p[1] == '\n')
01304                             break;
01305 
01306                      if (*p == '=' && p[1] && p[2])
01307                      {
01308                             n=nybble(p[1]) * 16 + nybble(p[2]);
01309                             if ( (char)n )
01310                             {
01311                                    putc((char)n, signature_file_fp);
01312                                    p += 2;
01313                             }
01314                             p += 2;
01315                             continue;
01316                      }
01317                      putc(*p, signature_file_fp);
01318 
01319                      /* If some spits out qp-lines > BUFSIZ, they deserve
01320                      ** this crap.
01321                      */
01322               }
01323        }
01324 
01325        fflush(signature_file_fp);
01326        if (ferror(signature_file_fp))
01327        {
01328               unlink(signature);
01329               fclose(signed_file_fp);
01330               unlink(signed_content);
01331               return -1;
01332        }
01333        if (fclose(signature_file_fp))
01334        {
01335               unlink(signature);
01336               unlink(signed_content);
01337               return -1;
01338        }
01339 
01340        errflag=dochecksign(gpghome,
01341                          passphrase_fd,
01342                          *stack, signed_file_fp,
01343                          output_func, output_func_arg, signed_content,
01344                          signature,
01345                          argc, argv, errptr);
01346 
01347        fclose(signed_file_fp);
01348        unlink(signature);
01349        unlink(signed_content);
01350 
01351        if (errflag)
01352               return -1;
01353 
01354        while (!clos_flag)
01355        {
01356               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
01357               {
01358                      *iseof=1;
01359                      break;
01360               }
01361               if (!(b=is_boundary(*stack, buf, &clos_flag)))
01362                      clos_flag=0;
01363        }
01364        if (b)
01365               libmail_mimestack_pop_to(stack, b);
01366 
01367        return 0;
01368 }
01369 
01370 static const char *newboundary()
01371 {
01372        static char buffer[256];
01373        static unsigned counter=0;
01374        time_t t;
01375        char hostnamebuf[256];
01376 
01377        time(&t);
01378        hostnamebuf[sizeof(hostnamebuf)-1]=0;
01379        if (gethostname(hostnamebuf, sizeof(hostnamebuf)-1) < 0)
01380               hostnamebuf[0]=0;
01381 
01382        sprintf(buffer, "=_%-1.30s-%u-%u-%04u",
01383               hostnamebuf, (unsigned)getpid(),
01384               (unsigned)t, ++counter);
01385        return (buffer);
01386 }
01387 
01388 static int good_boundary(const char *boundary,
01389                       struct mimestack *m, const char *errmsg, FILE *fp)
01390 {
01391        int dummy;
01392        int l=strlen(boundary);
01393        const char *p;
01394        char buf[BUFSIZ];
01395 
01396        if (is_boundary(m, boundary, &dummy))
01397               return (0);
01398 
01399        for (p=errmsg; *p; )
01400        {
01401               if (*p == '-' && p[1] == '-' && strncasecmp(p+2, boundary, l)
01402                   == 0)
01403                      return (0);
01404 
01405               while (*p)
01406                      if (*p++ == '\n')
01407                             break;
01408        }
01409 
01410        if (fp)
01411        {
01412               if (my_rewind(fp) < 0)
01413                      return 0;
01414 
01415               while (fgets(buf, sizeof(buf), fp))
01416               {
01417                      if (buf[0] == '-' && buf[1] == '-' &&
01418                          strncasecmp(buf+2, boundary, l) == 0)
01419                             return (0);
01420               }
01421        }
01422        return (1);
01423 }
01424 
01425 static const char *get_boundary(struct mimestack *m,
01426                             const char *errmsg,
01427                             FILE *fp)
01428 {
01429        const char *p;
01430 
01431        do
01432        {
01433               p=newboundary();
01434        } while (!good_boundary(p, m, errmsg, fp));
01435        return (p);
01436 }
01437 
01438 static const char *encoding_str(const char *p)
01439 {
01440        while (*p)
01441        {
01442               if (*p <= 0 || *p >= 0x7F)
01443                      return ("8bit");
01444               ++p;
01445        }
01446        return ("7bit");
01447 }
01448 
01449 
01450 static int copyfp(FILE *t,
01451                 void (*output_func)(const char *,
01452                                   size_t,
01453                                   void *),
01454                 void *output_func_arg,
01455                 int stripcr)
01456 {
01457        char buf[BUFSIZ];
01458        int rc=0;
01459 
01460        while ((rc=fread(buf, 1, sizeof(buf), t)) > 0)
01461        {
01462               if (stripcr)
01463               {
01464                      int i, j;
01465 
01466                      for (i=j=0; i<rc; ++i)
01467                      {
01468                             if (buf[i] != '\r')
01469                                    buf[j++]=buf[i];
01470                      }
01471                      rc=j;
01472               }
01473               (*output_func)(buf, rc, output_func_arg);
01474        }
01475 
01476        return rc;
01477 }
01478 
01479 static void open_result_multipart(void (*)(const char *, size_t, void *),
01480                               void *,
01481                               int, const char *, const char *,
01482                               const char *);
01483 
01484 static int dochecksign(const char *gpghome,
01485                      const char *passphrase_fd,
01486                      struct mimestack *stack,
01487                      FILE *content_fp,
01488                      void (*output_func)(const char *,
01489                                       size_t,
01490                                       void *),
01491                      void *output_func_arg,
01492                      const char *content_filename,
01493                      const char *signature_filename,
01494                      int argc,
01495                      char **argv, int *errptr)
01496 {
01497        struct gpgmime_forkinfo gpg;
01498        int i;
01499        const char *new_boundary;
01500        const char *output;
01501 
01502        if (libmail_gpgmime_forkchecksign(gpghome, passphrase_fd,
01503                               content_filename,
01504                               signature_filename,
01505                               argc, argv,
01506                               &gpg))
01507        {
01508               return -1;
01509        }
01510 
01511        *errptr=i=libmail_gpgmime_finish(&gpg);
01512 
01513        output=libmail_gpgmime_getoutput(&gpg);
01514 
01515        new_boundary=get_boundary(stack, output, content_fp);
01516 
01517        open_result_multipart(output_func, output_func_arg,
01518                            i, new_boundary, output,
01519                            libmail_gpgmime_getcharset(&gpg));
01520 
01521        (*output_func)("\n--", 3, output_func_arg);
01522        (*output_func)(new_boundary, strlen(new_boundary), output_func_arg);
01523        (*output_func)("\n", 1, output_func_arg);
01524 
01525        if (my_rewind(content_fp) < 0)
01526        {
01527               return -1;
01528        }
01529 
01530        if (copyfp(content_fp, output_func, output_func_arg, 1))
01531               return -1;
01532 
01533        (*output_func)("\n--", 3, output_func_arg);
01534        (*output_func)(new_boundary, strlen(new_boundary), output_func_arg);
01535        (*output_func)("--\n", 3, output_func_arg);
01536        return 0;
01537 }
01538 
01539 static void open_result_multipart(void (*output_func)(const char *,
01540                                                 size_t,
01541                                                 void *),
01542                               void *output_func_arg,
01543                               int rc,
01544                               const char *new_boundary,
01545                               const char *err_str,
01546                               const char *err_charset)
01547 {
01548 #define C(s) (*output_func)( s, sizeof(s)-1, output_func_arg)
01549 #define S(s) (*output_func)( s, strlen(s), output_func_arg)
01550 
01551        char n[10];
01552        const char *p;
01553 
01554        sprintf(n, "%d", rc);
01555 
01556        C("Content-Type: multipart/x-mimegpg; xpgpstatus=");
01557 
01558        S(n);
01559 
01560        C("; boundary=\"");
01561 
01562        S(new_boundary);
01563 
01564        C("\"\n"
01565          "\nThis is a MIME GnuPG-processed message.  If you see this text, it means\n"
01566          "that your E-mail or Usenetsoftware does not support MIME-formatted messages.\n\n"
01567          "--");
01568 
01569        S(new_boundary);
01570        C("\nContent-Type: text/x-gpg-output; charset=");
01571        S(err_charset);
01572        C("\nContent-Transfer-Encoding: ");
01573 
01574        p=encoding_str(err_str);
01575        S(p);
01576        C("\n\n");
01577        S(err_str);
01578 #undef C
01579 #undef S
01580 }
01581 
01582 static void close_mime(struct mimestack **stack, int *iseof,
01583                      int (*input_func)(char *, size_t, void *vp),
01584                      void *input_func_arg,
01585                      void (*output_func)(const char *,
01586                                       size_t,
01587                                       void *),
01588                      void *output_func_arg)
01589 {
01590        char buf[BUFSIZ];
01591        int is_closing;
01592        struct mimestack *b;
01593 
01594        for (;;)
01595        {
01596               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
01597               {
01598                      *iseof=1;
01599                      break;
01600               }
01601 
01602               (*output_func)(buf, strlen(buf), output_func_arg);
01603               if (!(b=is_boundary(*stack, buf, &is_closing)))
01604                      continue;
01605               if (!is_closing)
01606                      continue;
01607 
01608               libmail_mimestack_pop_to(stack, b);
01609               break;
01610        }
01611 }
01612 
01613 static int dodecrypt(const char *, const char *,
01614                    struct mimestack **, int *,
01615                    int (*input_func)(char *, size_t, void *vp),
01616                    void *input_func_arg,
01617                    FILE *, int, char **, const char *,
01618                    void (*)(const char *,
01619                            size_t,
01620                            void *),
01621                    void *,
01622                    int *);
01623 
01624 static void write_temp_fp(const char *p, size_t n, void *vp)
01625 {
01626        if (fwrite(p, n, 1, (FILE *)vp) != 1)
01627               ; /* ignored */
01628 }
01629 
01630 static int decrypt(const char *gpghome,
01631                  const char *passphrase_fd,
01632                  struct mimestack **stack, int *iseof,
01633                  struct header *h,
01634                  int (*input_func)(char *, size_t, void *vp),
01635                  void *input_func_arg,
01636                  void (*output_func)(const char *,
01637                                    size_t,
01638                                    void *),
01639                  void *output_func_arg,
01640                  int argc, char **argv,
01641                  int *errptr)
01642 {
01643        struct header *p, *q;
01644        char temp_file[TEMPNAMEBUFSIZE];
01645        int temp_fd;
01646        FILE *temp_fp;
01647        struct mime_header *mh;
01648        int flag;
01649        int errflag;
01650 
01651        *errptr=0;
01652        temp_fd=libmail_tempfile(temp_file);
01653        if (temp_fd < 0 || (temp_fp=fdopen(temp_fd, "w+")) == 0)
01654        {
01655               if (temp_fd >= 0)
01656                      close(temp_fd);
01657               return -1;
01658        }
01659 
01660        for (p=h; p; p=p->next)
01661        {
01662               fprintf(temp_fp, "%s", p->header);
01663        }
01664        putc('\n', temp_fp);
01665 
01666        find_boundary(stack, iseof, input_func, input_func_arg,
01667                     write_temp_fp, temp_fp, 0);
01668        if (*iseof)
01669        {
01670               fclose(temp_fp);
01671               unlink(temp_file);
01672               return (0);
01673        }
01674 
01675        p=read_headers(stack, iseof, input_func, input_func_arg, write_temp_fp,
01676                      temp_fp, 0, &errflag);
01677 
01678        if (*iseof || errflag)
01679        {
01680               libmail_header_free(p);
01681               fclose(temp_fp);
01682               unlink(temp_file);
01683 
01684               if (errflag)
01685                      return -1;
01686               return 0;
01687        }
01688 
01689        q=libmail_header_find(p, "content-type:");
01690 
01691        flag=0;
01692 
01693        if (q)
01694        {
01695               mh=libmail_mimeheader_parse(q->header+13);
01696               if (!mh)
01697               {
01698                      libmail_header_free(p);
01699                      fclose(temp_fp);
01700                      unlink(temp_file);
01701                      return -1;
01702               }
01703 
01704               if (strcasecmp(mh->header_name, "application/pgp-encrypted")
01705                   == 0)
01706                      flag=1;
01707               libmail_mimeheader_free(mh);
01708        }
01709 
01710        for (q=p; q; q=q->next)
01711        {
01712               fprintf(temp_fp, "%s", q->header);
01713        }
01714        libmail_header_free(p);
01715        putc('\n', temp_fp);
01716 
01717        p=read_headers(stack, iseof, input_func, input_func_arg,
01718                      write_temp_fp, temp_fp, 0,
01719                      &errflag);
01720 
01721        if (*iseof || errflag)
01722        {
01723               libmail_header_free(p);
01724               fclose(temp_fp);
01725               unlink(temp_file);
01726 
01727               if (errflag)
01728                      return -1;
01729 
01730               return 0;
01731        }
01732 
01733        q=libmail_header_find(p, "version:");
01734 
01735        if (flag)
01736        {
01737               if (!q || atoi(p->header + 8) != 1)
01738                      flag=0;
01739        }
01740        for (q=p; q; q=q->next)
01741        {
01742               fprintf(temp_fp, "%s", q->header);
01743        }
01744        libmail_header_free(p);
01745        putc('\n', temp_fp);
01746 
01747        find_boundary(stack, iseof, input_func, input_func_arg,
01748                     write_temp_fp, temp_fp, 0);
01749 
01750        if (*iseof)
01751        {
01752               fclose(temp_fp);
01753               unlink(temp_file);
01754               return 0;
01755        }
01756 
01757        p=read_headers(stack, iseof, input_func, input_func_arg, write_temp_fp,
01758                      temp_fp, 0, &errflag);
01759 
01760        if (*iseof || errflag)
01761        {
01762               libmail_header_free(p);
01763               fclose(temp_fp);
01764               unlink(temp_file);
01765 
01766               if (errflag)
01767                      return -1;
01768 
01769               return 0;
01770        }
01771 
01772        q=libmail_header_find(p, "content-type:");
01773 
01774        if (q && flag)
01775        {
01776               flag=0;
01777               mh=libmail_mimeheader_parse(q->header+13);
01778               if (!mh)
01779               {
01780                      libmail_header_free(p);
01781                      fclose(temp_fp);
01782                      unlink(temp_file);
01783                      return -1;
01784               }
01785 
01786               if (strcasecmp(mh->header_name, "application/octet-stream")
01787                   == 0)
01788                      flag=1;
01789               libmail_mimeheader_free(mh);
01790 
01791               q=libmail_header_find(p, "content-transfer-encoding:");
01792               if (q && flag)
01793               {
01794                      flag=0;
01795                      mh=libmail_mimeheader_parse(strchr(q->header, ':')+1);
01796                      if (!mh)
01797                      {
01798                             libmail_header_free(p);
01799                             fclose(temp_fp);
01800                             unlink(temp_file);
01801                             return -1;
01802                      }
01803 
01804                      if (strcasecmp(mh->header_name, "7bit") == 0 ||
01805                          strcasecmp(mh->header_name, "8bit") == 0)
01806                             flag=1;
01807                      libmail_mimeheader_free(mh);
01808               }
01809        }
01810 
01811        for (q=p; q; q=q->next)
01812        {
01813               fprintf(temp_fp, "%s", q->header);
01814        }
01815        libmail_header_free(p);
01816        putc('\n', temp_fp);
01817 
01818        if (fflush(temp_fp) || ferror(temp_fp) || my_rewind(temp_fp) < 0)
01819        {
01820               fclose(temp_fp);
01821               unlink(temp_file);
01822               return -1;
01823        }
01824 
01825        if (!flag)
01826        {
01827               int c=copyfp(temp_fp, output_func, output_func_arg, 0);
01828 
01829               fclose(temp_fp);
01830               unlink(temp_file);
01831               close_mime(stack, iseof, input_func, input_func_arg,
01832                         output_func, output_func_arg);
01833               return (c);
01834        }
01835 
01836        fclose(temp_fp);
01837        if ((temp_fp=fopen(temp_file, "w+")) == NULL)
01838        {
01839               unlink(temp_file);
01840               return (-1);
01841        }
01842        libmail_gpg_noexec(fileno(temp_fp));
01843        errflag=dodecrypt(gpghome, passphrase_fd,
01844                        stack, iseof, input_func, input_func_arg,
01845                        temp_fp, argc, argv, temp_file,
01846                        output_func, output_func_arg, errptr);
01847        fclose(temp_fp);
01848        unlink(temp_file);
01849        return errflag;
01850 }
01851 
01852 static int dumpdecrypt(const char *c, size_t n, void *vp)
01853 {
01854        FILE *fp=(FILE *)vp;
01855 
01856        if (n == 0)
01857               return 0;
01858 
01859        if (fwrite(c, n, 1, fp) != 1)
01860               return -1;
01861        return (0);
01862 }
01863 
01864 static int dodecrypt(const char *gpghome,
01865                    const char *passphrase_fd,
01866                    struct mimestack **stack, int *iseof,
01867                    int (*input_func)(char *, size_t, void *vp),
01868                    void *input_func_arg,
01869                    FILE *fpout, int argc, char **argv,
01870                    const char *temp_file,
01871                    void (*output_func)(const char *,
01872                            size_t,
01873                            void *),
01874                    void *output_func_arg,
01875                    int *errptr)
01876 {
01877        struct gpgmime_forkinfo gpg;
01878        char buf[BUFSIZ];
01879        int is_closing;
01880        struct mimestack *b=NULL;
01881        int dowrite=1;
01882        int rc;
01883        const char *new_boundary;
01884        const char *output;
01885 
01886        if (libmail_gpgmime_forkdecrypt(gpghome,
01887                             passphrase_fd,
01888                             argc, argv, &dumpdecrypt, fpout, &gpg))
01889               return -1;
01890 
01891        for (;;)
01892        {
01893               if ( (*input_func)(buf, sizeof(buf), input_func_arg))
01894               {
01895                      *iseof=1;
01896                      break;
01897               }
01898 
01899               if (dowrite)
01900                      libmail_gpgmime_write(&gpg, buf, strlen(buf));
01901 
01902               if (!(b=is_boundary(*stack, buf, &is_closing)))
01903                      continue;
01904               dowrite=0;
01905               if (!is_closing)
01906                      continue;
01907               break;
01908        }
01909 
01910        rc=libmail_gpgmime_finish(&gpg);
01911        if (fflush(fpout) || ferror(fpout) || my_rewind(fpout) < 0)
01912        {
01913               fclose(fpout);
01914               unlink(temp_file);
01915               return -1;
01916        }
01917 
01918        if (*iseof)
01919               return 0;
01920 
01921        output=libmail_gpgmime_getoutput(&gpg),
01922 
01923        new_boundary=get_boundary(*stack, output, rc ? NULL:fpout);
01924 
01925        open_result_multipart(output_func,
01926                            output_func_arg, rc, new_boundary,
01927                            output,
01928                            libmail_gpgmime_getcharset(&gpg));
01929 
01930        *errptr=rc;
01931 
01932 #if 0
01933 
01934        /*
01935        ** gnupg returns non-zero exit even if succesfully unencrypted, when
01936        ** just the signature is bad.
01937        */
01938        if (rc == 0)
01939 #endif
01940        {
01941               if (fseek(fpout, 0L, SEEK_SET) < 0)
01942               {
01943                      fclose(fpout);
01944                      unlink(temp_file);
01945                      return -1;
01946               }
01947 
01948               (*output_func)("\n--", 3, output_func_arg);
01949               (*output_func)(new_boundary, strlen(new_boundary),
01950                             output_func_arg);
01951               (*output_func)("\n", 1, output_func_arg);
01952 
01953               if (copyfp(fpout, output_func, output_func_arg, 1))
01954                   return -1;
01955        }
01956 
01957        (*output_func)("\n--", 3, output_func_arg);
01958        (*output_func)(new_boundary, strlen(new_boundary),
01959                      output_func_arg);
01960        (*output_func)("--\n", 3, output_func_arg);
01961 
01962        libmail_mimestack_pop_to(stack, b);
01963        return 0;
01964 }
01965 
01966 struct libmail_gpg_errhandler {
01967 
01968        struct libmail_gpg_info *options;
01969        int err_flag;
01970 };
01971 
01972 static void libmail_gpg_errfunc(const char *errmsg, void *vp)
01973 {
01974        struct libmail_gpg_errhandler *eh=(struct libmail_gpg_errhandler *)vp;
01975 
01976        if (!eh->err_flag)
01977        {
01978               eh->err_flag=1;
01979 
01980               (*eh->options->errhandler_func)(errmsg,
01981                                           eh->options->errhandler_arg);
01982        }
01983 }
01984  
01985 static int input_func_from_fp(char *buf, size_t cnt, void *vp)
01986 {
01987        if (fgets(buf, cnt, (FILE *)vp) == NULL)
01988               return (-1);
01989        return (0);
01990 }
01991 
01992 /*
01993 ** When signing, but not encoding, signed text must be 7bit, as per RFC.
01994 **
01995 ** Use rfc2045's rewriter to do this.
01996 */
01997 
01998 static int dosignencode(int dosign, int doencode, int dodecode,
01999                      const char *gpghome,
02000                      const char *passphrase_fd,
02001                      int (*input_func)(char *, size_t, void *vp),
02002                      void *input_func_arg,
02003                      void (*output_func)(const char *,
02004                                        size_t,
02005                                        void *),
02006                      void *output_func_arg,
02007                      void (*errhandler_func)(const char *, void *),
02008                      void *errhandler_arg,
02009                      int argc, char **argv,
02010                      int *status)
02011 {
02012        char temp_decode_name[TEMPNAMEBUFSIZE];
02013        int fdin;
02014        int fdout;
02015        FILE *fdin_fp;
02016        char buffer[8192];
02017        struct rfc2045src *src;
02018        struct rfc2045 *rfcp;
02019        int rc;
02020 
02021        if (!dosign || doencode)
02022               return dosignencode2(dosign, doencode, dodecode,
02023                                  gpghome,
02024                                  passphrase_fd,
02025                                  input_func,
02026                                  input_func_arg,
02027                                  output_func,
02028                                  output_func_arg,
02029                                  errhandler_func,
02030                                  errhandler_arg,
02031                                  argc, argv, status);
02032 
02033        /* Save the message into a temp file, first */
02034 
02035        fdin=libmail_tempfile(temp_decode_name);
02036 
02037        if (fdin < 0 ||
02038            (fdin_fp=fdopen(fdin, "w+")) == NULL)
02039        {
02040               if (fdin >= 0)
02041                      close(fdin);
02042 
02043               (*errhandler_func)("Cannot create temporary file",
02044                                errhandler_arg);
02045               return (-1);
02046        }
02047 
02048        unlink(temp_decode_name);
02049 
02050        if (!(rfcp=rfc2045_alloc_ac()))
02051        {
02052               (*errhandler_func)(strerror(errno), errhandler_arg);
02053               fclose(fdin_fp);
02054               return (-1);
02055        }
02056 
02057        while ( (*input_func)(buffer, sizeof(buffer), input_func_arg) == 0)
02058        {
02059               size_t l=strlen(buffer);
02060 
02061               if (fwrite(buffer, l, 1, fdin_fp) != 1)
02062               {
02063                      (*errhandler_func)(strerror(errno), errhandler_arg);
02064                      fclose(fdin_fp);
02065                      rfc2045_free(rfcp);
02066                      return (-1);
02067               }
02068 
02069               /* Parse the message at the same time it's being saved */
02070 
02071               rfc2045_parse(rfcp, buffer, l);
02072        }
02073 
02074        if (fseek(fdin_fp, 0L, SEEK_SET) < 0)
02075        {
02076               (*errhandler_func)(strerror(errno), errhandler_arg);
02077               fclose(fdin_fp);
02078               rfc2045_free(rfcp);
02079               return (-1);
02080        }
02081 
02082        if (!rfc2045_ac_check(rfcp, RFC2045_RW_7BIT))
02083        {
02084               rfc2045_free(rfcp);
02085 
02086               /* No need to rewrite, just do this */
02087 
02088               rc=dosignencode2(dosign, doencode, dodecode,
02089                                  gpghome,
02090                                  passphrase_fd,
02091                                  input_func_from_fp,
02092                                  fdin_fp,
02093                                  output_func,
02094                                  output_func_arg,
02095                                  errhandler_func,
02096                                  errhandler_arg,
02097                                  argc, argv, status);
02098 
02099               fclose(fdin_fp);
02100 
02101               return rc;
02102        }
02103 
02104        /* Rewrite the message into another temp file */
02105 
02106        fdout=libmail_tempfile(temp_decode_name);
02107 
02108        src=rfc2045src_init_fd(fileno(fdin_fp));
02109 
02110        if (fdout < 0 || src == NULL ||
02111            rfc2045_rewrite(rfcp, src, fdout, "mimegpg") < 0 ||
02112            lseek(fdout, 0L, SEEK_SET) < 0)
02113        {
02114               if (fdout >= 0)
02115                      close(fdout);
02116               if (src)
02117                      rfc2045src_deinit(src);
02118 
02119               (*errhandler_func)(strerror(errno), errhandler_arg);
02120               rfc2045_free(rfcp);
02121               fclose(fdin_fp);
02122               return (-1);
02123        }
02124        fclose(fdin_fp);
02125        rfc2045_free(rfcp);
02126        rfc2045src_deinit(src);
02127 
02128        /* Now, read the converted message, from the temp file */
02129 
02130        if ((fdin_fp=fdopen(fdout, "w+")) == NULL)
02131        {
02132               close(fdout);
02133 
02134               (*errhandler_func)("Cannot create temporary file",
02135                                errhandler_arg);
02136               return (-1);
02137        }
02138 
02139        rc=dosignencode2(dosign, doencode, dodecode,
02140                       gpghome,
02141                       passphrase_fd,
02142                       input_func_from_fp,
02143                       fdin_fp,
02144                       output_func,
02145                       output_func_arg,
02146                       errhandler_func,
02147                       errhandler_arg,
02148                       argc, argv, status);
02149        fclose(fdin_fp);
02150        return rc;
02151 }
02152 
02153 int libmail_gpg_signencode(int dosign,
02154                         int doencode,
02155                         /*
02156                         ** One of LIBMAIL_GPG_INDIVIDUAL or
02157                         ** LIBMAIL_GPG_ENCAPSULATE
02158                         */
02159                         struct libmail_gpg_info *options)
02160 {
02161        int rc;
02162        struct libmail_gpg_errhandler eh;
02163 
02164        eh.options=options;
02165        eh.err_flag=0;
02166 
02167        if (doencode != LIBMAIL_GPG_INDIVIDUAL &&
02168            doencode != LIBMAIL_GPG_ENCAPSULATE)
02169               doencode=0;
02170 
02171        if (!dosign && !doencode)
02172        {
02173               (*options->errhandler_func)("Invalid arguments to"
02174                                        " libmail_gpg_signencode",
02175                                        options->errhandler_arg);
02176               return -1;
02177        }
02178 
02179        rc=dosignencode(dosign, doencode, 0,
02180                      options->gnupghome,
02181                      options->passphrase_fd,
02182                      options->input_func,
02183                      options->input_func_arg,
02184                      options->output_func,
02185                      options->output_func_arg,
02186                      &libmail_gpg_errfunc,
02187                      &eh,
02188                      options->argc,
02189                      options->argv,
02190                      &options->errstatus);
02191 
02192        if (rc && !eh.err_flag)
02193               (*options->errhandler_func)(strerror(errno),
02194                                        options->errhandler_arg);
02195        return rc;
02196 }
02197 
02198 int libmail_gpg_decode(int mode,
02199                      /*
02200                      ** LIBMAIL_GPG_UNENCRYPT OR LIBMAIL_GPG_CHECKSIGN
02201                      */
02202                      struct libmail_gpg_info *options)
02203 {
02204        int rc;
02205        struct libmail_gpg_errhandler eh;
02206 
02207        eh.options=options;
02208        eh.err_flag=0;
02209 
02210        if ((mode & (LIBMAIL_GPG_UNENCRYPT|LIBMAIL_GPG_CHECKSIGN)) == 0)
02211        {
02212               (*options->errhandler_func)("Invalid arguments to"
02213                                        " libmail_gpg_decode",
02214                                        options->errhandler_arg);
02215               return -1;
02216        }
02217 
02218        rc=dosignencode(0, 0, mode,
02219                      options->gnupghome,
02220                      options->passphrase_fd,
02221                      options->input_func,
02222                      options->input_func_arg,
02223                      options->output_func,
02224                      options->output_func_arg,
02225                      &libmail_gpg_errfunc,
02226                      &eh,
02227                      options->argc,
02228                      options->argv,
02229                      &options->errstatus);
02230 
02231        if (rc && !eh.err_flag)
02232               (*options->errhandler_func)(strerror(errno),
02233                                        options->errhandler_arg);
02234        return rc;
02235 }