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 /*
00008 */
00009 #include      "sqwebmail.h"
00010 #include      "config.h"
00011 #include      "gpg.h"
00012 #include      "pref.h"
00013 #include      "cgi/cgi.h"
00014 #include      "gpglib/gpglib.h"
00015 #include      "unicode/unicode.h"
00016 #include      "numlib/numlib.h"
00017 #include      "rfc822/rfc822.h"
00018 #include      "htmllibdir.h"
00019 #include      <stdio.h>
00020 #include      <string.h>
00021 #include      <errno.h>
00022 #if HAVE_SYS_WAIT_H
00023 #include      <sys/wait.h>
00024 #endif
00025 #if HAVE_FCNTL_H
00026 #include      <fcntl.h>
00027 #endif
00028 
00029 #ifndef WEXITSTATUS
00030 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00031 #endif
00032 #ifndef WIFEXITED
00033 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00034 #endif
00035 
00036 extern void output_scriptptrget();
00037 extern void print_attrencodedlen(const char *, size_t, int, FILE *);
00038 extern void print_safe(const char *);
00039 const char *sqwebmail_content_charset;
00040 
00041 
00042 static char gpgerrbuf[1024];
00043 static size_t gpgerrcnt=0;
00044 
00045 static void gpginiterr()
00046 {
00047        gpgerrcnt=0;
00048 }
00049 
00050 static int gpg_error(const char *p, size_t l, void *dummy)
00051 {
00052        while (l && gpgerrcnt < sizeof(gpgerrbuf)-1)
00053        {
00054               gpgerrbuf[gpgerrcnt++]= *p++;
00055               --l;
00056        }
00057        return (0);
00058 }
00059 
00060 static void gpg_error_save(const char *errmsg, void *dummy)
00061 {
00062        gpg_error(errmsg, strlen(errmsg), dummy);
00063 }
00064 
00065 int gpgbadarg(const char *p)
00066 {
00067        for ( ; *p; p++)
00068        {
00069               int c=(unsigned char)*p;
00070 
00071               if (c < ' ' || strchr("\",'`;*?()<>", c))
00072                      return (1);
00073        }
00074        return (0);
00075 }
00076 
00077 static void dump_error()
00078 {
00079        if (gpgerrcnt >= 0)
00080        {
00081               printf("<span style=\"color: #e00000\"><pre class=\"gpgerroutput\">");
00082               print_attrencodedlen (gpgerrbuf, gpgerrcnt, 1, stdout);
00083               printf("</pre></span>\n");
00084        }
00085 }
00086 
00087 struct listinfo {
00088        int issecret;
00089        const char *default_key;
00090 } ;
00091 
00092 static int show_key(const char *fingerprint, const char *shortname,
00093                     const char *key, int invalid,
00094                   struct gpg_list_info *gli)
00095 {
00096        struct listinfo *li=(struct listinfo *)gli->voidarg;
00097 
00098        printf("<tr valign=\"middle\" class=\"%s\"><td>"
00099               "<input type=\"radio\" name=\"%s\" value=\"",
00100               li->issecret ? "gpgseckey":"gpgpubkey",
00101               li->issecret ? "seckeyname":"pubkeyname");
00102 
00103        print_attrencodedlen(fingerprint, strlen(fingerprint), 0, stdout);
00104        printf("\"%s /></td><td><span class=\"tt\">",
00105               li->default_key && strcmp(li->default_key, fingerprint) == 0
00106               ? " checked=\"checked\"":"");
00107        print_safe(key);
00108        printf("</span></td></tr>\n");
00109        return (0);
00110 }
00111 
00112 static void listpubsec(int flag,
00113                      int (*callback_func)(const char *,
00114                                        const char *,
00115                                        const char *,
00116                                        int,
00117                                        struct gpg_list_info *),
00118                      const char *default_key
00119                      )
00120 {
00121        int rc;
00122        struct gpg_list_info gli;
00123        struct listinfo li;
00124 
00125        li.issecret=flag;
00126 
00127        li.default_key=default_key;
00128 
00129        memset(&gli, 0, sizeof(gli));
00130        gli.charset=sqwebmail_content_charset;
00131 
00132        gli.disabled_msg=getarg("DISABLED");
00133        gli.revoked_msg=getarg("REVOKED");
00134        gli.expired_msg=getarg("EXPIRED");
00135        gli.voidarg= &li;
00136 
00137        gpginiterr();
00138 
00139        rc=libmail_gpg_listkeys(GPGDIR, flag, callback_func, gpg_error, &gli);
00140 
00141        if (rc)
00142        {
00143               dump_error();
00144        }
00145 }
00146 
00147 void gpglistpub()
00148 {
00149        printf("<table width=\"100%%\" border=\"0\" cellspacing=\"2\" cellpadding=\"0\" class=\"gpgpubkeys\">");
00150        listpubsec(0, show_key, NULL);
00151        printf("</table>");
00152 }
00153 
00154 void gpglistsec()
00155 {
00156        printf("<table width=\"100%%\" border=\"0\" cellspacing=\"2\" cellpadding=\"0\" class=\"gpgseckeys\">");
00157        listpubsec(1, show_key, NULL);
00158        printf("</table>");
00159 }
00160 
00161 static int select_key(const char *fingerprint, const char *shortname,
00162                     const char *key,
00163                     struct gpg_list_info *gli,
00164                     int is_select)
00165 {
00166        printf("<option value=\"");
00167        print_attrencodedlen(fingerprint, strlen(fingerprint), 0, stdout);
00168        printf("\"%s>", is_select ? " selected='selected'":"");
00169 
00170        print_safe(shortname);
00171        printf("</option>");
00172        return (0);
00173 }
00174 
00175 static int select_key_default(const char *fingerprint, const char *shortname,
00176                            const char *key,
00177                            int invalid,
00178                            struct gpg_list_info *gli)
00179 {
00180        struct listinfo *li=(struct listinfo *)gli->voidarg;
00181 
00182        return (select_key(fingerprint, shortname, key, gli,
00183                         li->default_key && strcmp(li->default_key,
00184                                                fingerprint)
00185                         == 0));
00186 }
00187 
00188 void gpgselectkey()
00189 {
00190        char *default_key=pref_getdefaultgpgkey();
00191 
00192        listpubsec(1, select_key_default, default_key);
00193 
00194        if (default_key)
00195               free(default_key);
00196 }
00197 
00198 void gpgselectpubkey()
00199 {
00200        listpubsec(0, select_key_default, NULL);
00201 }
00202 
00203 void gpgselectprivkey()
00204 {
00205        listpubsec(1, select_key_default, NULL);
00206 }
00207 
00208 /*
00209 ** Check if this encryption key address is included in the list of recipients
00210 ** of the message.
00211 */
00212 
00213 static int knownkey(const char *shortname, const char *known_keys)
00214 {
00215        struct rfc822t *t=rfc822t_alloc_new(shortname, NULL, NULL);
00216        struct rfc822a *a;
00217        int i;
00218 
00219        if (!t)
00220               return (0);
00221 
00222        a=rfc822a_alloc(t);
00223 
00224        if (!a)
00225        {
00226               rfc822t_free(t);
00227               return (0);
00228        }
00229 
00230        for (i=0; i<a->naddrs; i++)
00231        {
00232               char *p=rfc822_getaddr(a, i);
00233               int plen;
00234               const char *q;
00235 
00236               if (!p)
00237                      continue;
00238 
00239               if (!*p)
00240               {
00241                      free(p);
00242                      continue;
00243               }
00244 
00245               plen=strlen(p);
00246 
00247               for (q=known_keys; *q; )
00248               {
00249                      if (strncasecmp(q, p, plen) == 0 && q[plen] == '\n')
00250                      {
00251                             free(p);
00252                             rfc822a_free(a);
00253                             rfc822t_free(t);
00254                             return (1);
00255                      }
00256 
00257                      while (*q)
00258                             if (*q++ == '\n')
00259                                    break;
00260               }
00261               free(p);
00262        }
00263        rfc822a_free(a);
00264        rfc822t_free(t);
00265        return (0);
00266 }
00267 
00268 static int encrypt_key_default(const char *fingerprint, const char *shortname,
00269                             const char *key,
00270                             int invalid,
00271                             struct gpg_list_info *gli)
00272 {
00273        struct listinfo *li=(struct listinfo *)gli->voidarg;
00274 
00275        if (invalid)
00276               return (0);
00277 
00278        return (select_key(fingerprint, shortname, key, gli,
00279                         knownkey(shortname, li->default_key)));
00280 }
00281 
00282 void gpgencryptkeys(const char *select_keys)
00283 {
00284        listpubsec(0, encrypt_key_default, select_keys);
00285 }
00286 
00287 
00288 /*
00289 ** Create a new key
00290 */
00291 
00292 static int dump_func(const char *p, size_t l, void *vp)
00293 {
00294        int *ip=(int *)vp;
00295 
00296        while (l)
00297        {
00298               if (*ip >= 80)
00299               {
00300                      printf("\n");
00301                      *ip=0;
00302               }
00303 
00304               ++*ip;
00305 
00306               switch (*p) {
00307               case '<':
00308                      printf("&lt;");
00309                      break;
00310               case '>':
00311                      printf("&gt;");
00312                      break;
00313               case '\n':
00314                      *ip=0;
00315                      /* FALLTHROUGH */
00316               default:
00317                      putchar(*p);
00318                      break;
00319               }
00320 
00321               ++p;
00322               --l;
00323        }
00324        fflush(stdout);
00325        return (0);
00326 }
00327 
00328 static int timeout_func(void *vp)
00329 {
00330        return (dump_func("*", 1, vp));
00331 }
00332 
00333 void gpgcreate()
00334 {
00335        int linelen;
00336 
00337        const char *newname=cgi("newname");
00338        const char *newaddress=cgi("newaddress");
00339        const char *newcomment=cgi("newcomment");
00340        unsigned skl=atoi(cgi("skeylength"));
00341        unsigned ekl=atoi(cgi("ekeylength"));
00342        unsigned newexpire=atoi(cgi("newexpire"));
00343        char newexpirewhen=*cgi("newexpirewhen");
00344        const char *passphrase, *p;
00345 
00346        if (*newname == 0 || *newaddress == 0 || strchr(newaddress, '@') == 0
00347            || gpgbadarg(newname) || gpgbadarg(newaddress)
00348            || gpgbadarg(newcomment)
00349            || ekl < 512 || ekl > 2048 || skl < 512 || skl > 1024)
00350        {
00351               printf("%s\n", getarg("BADARGS"));
00352               return;
00353        }
00354        passphrase=cgi("passphrase");
00355        if (strcmp(passphrase, cgi("passphrase2")))
00356        {
00357               printf("%s\n", getarg("PASSPHRASEFAIL"));
00358               return;
00359        }
00360 
00361        for (p=passphrase; *p; p++)
00362        {
00363               if ((int)(unsigned char)*p < ' ')
00364               {
00365                      printf("%s\n", getarg("PASSPHRASEFAIL"));
00366                      return;
00367               }
00368        }
00369 
00370        printf("<pre class=\"gpgcreate\">");
00371 
00372        linelen=0;
00373 
00374        libmail_gpg_genkey(GPGDIR, sqwebmail_content_charset,
00375                         newname, newaddress, newcomment,
00376                         skl, ekl,
00377                         newexpire, newexpirewhen,
00378                         passphrase,
00379                         &dump_func,
00380                         &timeout_func,
00381                         &linelen);
00382        printf("</pre>");
00383 }
00384 
00385 static void delkey(const char *keyname, int flag)
00386 {
00387        int rc;
00388 
00389        if (gpgbadarg(keyname))
00390               return;
00391 
00392        gpginiterr();
00393 
00394        rc=libmail_gpg_deletekey(GPGDIR, flag, keyname, gpg_error, NULL);
00395 
00396        if (rc)
00397        {
00398               printf("<div class=\"indent\">%s\n", getarg("DELETEFAIL"));
00399               dump_error();
00400               printf("</div>\n");
00401        }
00402 }
00403 
00404 static FILE *passphrasefp()
00405 {
00406        FILE *fp=NULL;
00407        const char *passphrase;
00408 
00409        passphrase=cgi("passphrase");
00410        if (*passphrase)
00411        {
00412               fp=tmpfile();
00413               if (fp)
00414               {
00415                      fprintf(fp, "%s", passphrase);
00416                      if (fflush(fp) || ferror(fp)
00417                          || lseek(fileno(fp), 0L, SEEK_SET) < 0
00418                          || fcntl(fileno(fp), F_SETFD, 0) < 0)
00419                      {
00420                             fclose(fp);
00421                             fp=NULL;
00422                      }
00423               }
00424        }
00425        return (fp);
00426 }
00427 
00428 static void signkey(const char *signthis, const char *signwith,
00429                   const char *trustlevel)
00430 {
00431        int rc;
00432        FILE *fp=NULL;
00433 
00434        int n=atoi(trustlevel);
00435 
00436        if (n < 0 || n > 9)
00437               n=0;
00438 
00439        if (gpgbadarg(signthis) || gpgbadarg(signwith))
00440               return;
00441 
00442        gpginiterr();
00443 
00444 
00445        fp=passphrasefp();
00446 
00447        rc=libmail_gpg_signkey(GPGDIR, signthis, signwith,
00448                             fp ? fileno(fp):-1, gpg_error, n, NULL);
00449 
00450        if (fp)
00451               fclose(fp);
00452 
00453        if (rc)
00454        {
00455               printf("<div class=\"indent\">%s\n", getarg("SIGNFAIL"));
00456               dump_error();
00457               printf("</div>\n");
00458        }
00459 }
00460 
00461 static void setdefault(const char *def)
00462 {
00463        if (gpgbadarg(def))
00464               return;
00465 
00466        pref_setdefaultgpgkey(def);
00467 }
00468 
00469 void gpgdo()
00470 {
00471        if (*cgi("delpub"))
00472               delkey(cgi("pubkeyname"), 0);
00473        else if (*cgi("delsec") && *cgi("really"))
00474               delkey(cgi("seckeyname"), 1);
00475        else if (*cgi("sign"))
00476               signkey(cgi("pubkeyname"), cgi("seckeyname"),
00477                      cgi("signlevel"));
00478        else if (*cgi("setdefault"))
00479               setdefault(cgi("seckeyname"));
00480 }
00481 
00482 static char gpgerrbuf[1024];
00483 
00484 static int read_fd(char *buf, size_t cnt, void *vp)
00485 {
00486        FILE *fp=(FILE *)vp;
00487        size_t i;
00488        int c;
00489 
00490        if (cnt == 0)
00491               return -1;
00492 
00493        --cnt;
00494 
00495        for (i=0; i<cnt; i++)
00496        {
00497               if ((c=getc(fp)) == EOF)
00498               {
00499                      if (i == 0)
00500                             return -1;
00501                      break;
00502               }
00503               buf[i]=c;
00504 
00505               if (c == '\n')
00506               {
00507                      ++i;
00508                      break;
00509               }
00510        }
00511        buf[i]=0;
00512        return 0;
00513 }
00514 
00515 static void write_fd(const char *p, size_t n, void *dummy)
00516 {
00517        if (n == 0)
00518               return;
00519 
00520        if (fwrite(p, n, 1, (FILE *)dummy) != 1)
00521               exit(1);
00522 }
00523 
00524 int gpgdomsg(int in_fd, int out_fd, const char *signkey,
00525             const char *encryptkeys)
00526 {
00527        char *k=strdup(encryptkeys ? encryptkeys:"");
00528        int n;
00529        int i;
00530        char *p;
00531        char **argvec;
00532        FILE *passfd=NULL;
00533        char passfd_buf[NUMBUFSIZE];
00534        struct libmail_gpg_info gi;
00535 
00536        int in_dup, out_dup;
00537        FILE *in_fp, *out_fp;
00538 
00539        gpginiterr();
00540 
00541        if (!k)
00542        {
00543               enomem();
00544               return 1;
00545        }
00546 
00547        if ((in_dup=dup(in_fd)) < 0 || (in_fp=fdopen(in_dup, "r")) == NULL)
00548        {
00549               if (in_dup >= 0)
00550                      close(in_dup);
00551               free(k);
00552               enomem();
00553               return 1;
00554        }
00555 
00556        if ((out_dup=dup(out_fd)) < 0 || (out_fp=fdopen(out_dup, "w")) == NULL)
00557        {
00558               if (out_dup >= 0)
00559                      close(out_dup);
00560               fclose(in_fp);
00561               close(in_dup);
00562               free(k);
00563               enomem();
00564               return 1;
00565        }
00566 
00567        passfd=passphrasefp();
00568 
00569        n=0;
00570        for (p=k; (p=strtok(p, " ")) != NULL; p=NULL)
00571               ++n;
00572 
00573        argvec=malloc((n * 2 + 22)*sizeof(char *));
00574        if (!argvec)
00575        {
00576               fclose(out_fp);
00577               close(out_dup);
00578               fclose(in_fp);
00579               close(in_dup);
00580               free(k);
00581               enomem();
00582               return 1;
00583        }
00584 
00585        memset(&gi, 0, sizeof(gi));
00586 
00587        gi.gnupghome=GPGDIR;
00588        if (passfd)
00589        {
00590               gi.passphrase_fd=libmail_str_size_t(fileno(passfd),
00591                                               passfd_buf);
00592        }
00593 
00594        gi.input_func= read_fd;
00595        gi.input_func_arg= in_fp;
00596        gi.output_func= write_fd;
00597        gi.output_func_arg= out_fp;
00598        gi.errhandler_func= gpg_error_save;
00599        gi.errhandler_arg= NULL;
00600 
00601 
00602        i=0;
00603        argvec[i++] = "--no-tty";
00604        if (signkey)
00605        {
00606               argvec[i++]="--default-key";
00607               argvec[i++]=(char *)signkey;
00608        }
00609 
00610        argvec[i++]="--always-trust";
00611 
00612        for (p=strcpy(k, encryptkeys ? encryptkeys:"");
00613             (p=strtok(p, " ")) != NULL; p=NULL)
00614        {
00615               argvec[i++]="-r";
00616               argvec[i++]=p;
00617        }
00618        argvec[i]=0;
00619        gi.argc=i;
00620        gi.argv=argvec;
00621 
00622        i=libmail_gpg_signencode(signkey ? 1:0,
00623                              n > 0 ? LIBMAIL_GPG_ENCAPSULATE:0,
00624                              &gi);
00625 
00626        free(argvec);
00627        fclose(out_fp);
00628        close(out_dup);
00629        fclose(in_fp);
00630        close(in_dup);
00631        free(k);
00632        if (passfd)
00633               fclose(passfd);
00634 
00635        return i;
00636 }
00637 
00638 void sent_gpgerrtxt()
00639 {
00640        const char *p;
00641 
00642        for (p=gpgerrbuf; *p; p++)
00643        {
00644               switch (*p) {
00645               case '<':
00646                      printf("&lt;");
00647                      break;
00648               case '>':
00649                      printf("&gt;");
00650                      break;
00651               default:
00652                      putchar((int)(unsigned char)*p);
00653                      break;
00654               }
00655        }
00656 }
00657 
00658 void sent_gpgerrresume()
00659 {
00660        output_scriptptrget();
00661        printf("&form=newmsg&pos=%s&draft=%s", cgi("pos"),
00662               cgi("draftmessage"));
00663 }
00664 
00665 int gpgdecode(int in_fd, int out_fd)
00666 {
00667        char passfd_buf[NUMBUFSIZE];
00668        FILE *fp=passphrasefp();
00669        int in_dup, out_dup;
00670        FILE *in_fp, *out_fp;
00671        struct libmail_gpg_info gi;
00672        char *argvec[2];
00673        int i;
00674 
00675        gpginiterr();
00676 
00677        if ((in_dup=dup(in_fd)) < 0 || (in_fp=fdopen(in_dup, "r")) == NULL)
00678        {
00679               if (in_dup >= 0)
00680                      close(in_dup);
00681               fclose(fp);
00682               enomem();
00683               return 1;
00684        }
00685 
00686        if ((out_dup=dup(out_fd)) < 0 || (out_fp=fdopen(out_dup, "w")) == NULL)
00687        {
00688               if (out_dup >= 0)
00689                      close(out_dup);
00690               fclose(in_fp);
00691               close(in_dup);
00692               fclose(fp);
00693               enomem();
00694               return 1;
00695        }
00696 
00697        memset(&gi, 0, sizeof(gi));
00698 
00699        gi.gnupghome=GPGDIR;
00700        if (fp)
00701        {
00702               gi.passphrase_fd=libmail_str_size_t(fileno(fp), passfd_buf);
00703        }
00704 
00705        gi.input_func= read_fd;
00706        gi.input_func_arg= in_fp;
00707        gi.output_func= write_fd;
00708        gi.output_func_arg= out_fp;
00709        gi.errhandler_func= gpg_error_save;
00710        gi.errhandler_arg= NULL;
00711 
00712        argvec[0] = "--no-tty";
00713        argvec[1]=NULL;
00714        gi.argc=1;
00715        gi.argv=argvec;
00716 
00717        i=libmail_gpg_decode(LIBMAIL_GPG_UNENCRYPT|LIBMAIL_GPG_CHECKSIGN,
00718                           &gi);
00719        fclose(out_fp);
00720        close(out_dup);
00721        fclose(in_fp);
00722        close(in_dup);
00723        if (fp)
00724               fclose(fp);
00725 
00726        if (i)
00727        {
00728               printf("<div class=\"indent\"><pre style=\"color: red;\">");
00729               sent_gpgerrtxt();
00730               printf("</pre></div>\n");
00731        }
00732        return (i);
00733 }
00734 
00735 int gpgexportkey(const char *fingerprint, int issecret,
00736                int (*func)(const char *, size_t, void *),
00737                void *arg)
00738 {
00739        gpginiterr();
00740 
00741        return (libmail_gpg_exportkey(GPGDIR, issecret, fingerprint,
00742                                   func,
00743                                   gpg_error,
00744                                   arg));
00745 }
00746