"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.1/src/pgp.c" (12 Oct 2016, 13212 Bytes) of package /linux/misc/tin-2.4.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pgp.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.0_vs_2.4.1.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : pgp.c
    4  *  Author    : Steven J. Madsen
    5  *  Created   : 1995-05-12
    6  *  Updated   : 2013-11-12
    7  *  Notes     : PGP support
    8  *
    9  * Copyright (c) 1995-2017 Steven J. Madsen <steve@erinet.com>
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. The name of the author may not be used to endorse or promote
   21  *    products derived from this software without specific prior written
   22  *    permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
   25  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   28  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   30  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35  */
   36 
   37 
   38 #ifndef TIN_H
   39 #   include "tin.h"
   40 #endif /* !TIN_H */
   41 
   42 #ifdef HAVE_PGP_GPG
   43 #   ifndef TCURSES_H
   44 #       include "tcurses.h"
   45 #   endif /* !TCURSES_H */
   46 
   47 
   48 /*
   49  * The first two args are typically the PGP command name and then $PGPOPTS
   50  * NB: The '1' variations on DO_{SIGN,BOTH} are used when local-user name is
   51  * used and are valid only when signing
   52  */
   53 #   if defined(HAVE_PGP) /* pgp-2 */
   54 #       define PGPNAME      PATH_PGP
   55 #       define PGPDIR       ".pgp"
   56 #       define PGP_PUBRING  "pubring.pgp"
   57 #       define CHECK_SIGN   "%s %s -f <%s %s"
   58 #       define ADD_KEY      "%s %s -ka %s"
   59 #       define APPEND_KEY   "%s %s -kxa %s %s", PGPNAME, pgpopts, buf, keyfile
   60 #       define DO_ENCRYPT   "%s %s -ate %s %s", PGPNAME, pgpopts, pt, mailto
   61 #       define DO_SIGN      "%s %s -ats %s %s", PGPNAME, pgpopts, pt, mailto
   62 #       define DO_SIGN1     "%s %s -ats %s %s -u %s", PGPNAME, pgpopts, pt, mailto, mailfrom
   63 #       define DO_BOTH      "%s %s -ates %s %s", PGPNAME, pgpopts, pt, mailto
   64 #       define DO_BOTH1     "%s %s -ates %s %s -u %s", PGPNAME, pgpopts, pt, mailto, mailfrom
   65 #   endif /* HAVE_PGP */
   66 
   67 #   if defined(HAVE_PGPK) /* pgp-5 */
   68 #       define PGPNAME      "pgp"   /* FIXME: this is AFAIK not PATH_PGPK */
   69 #       define PGPDIR       ".pgp"
   70 #       define PGP_PUBRING  "pubring.pkr"
   71 #       define CHECK_SIGN   "%sv %s -f <%s %s"
   72 #       define ADD_KEY      "%sk %s -a %s"
   73 #       define APPEND_KEY   "%sk %s -xa %s -o %s", PGPNAME, pgpopts, keyfile, buf
   74 #       define DO_ENCRYPT   "%se %s -at %s %s", PGPNAME, pgpopts, pt, mailto
   75 #       define DO_SIGN      "%ss %s -at %s %s", PGPNAME, pgpopts, pt, mailto
   76 #       define DO_SIGN1     "%ss %s -at %s %s -u %s", PGPNAME, pgpopts, pt, mailto, mailfrom
   77 #       define DO_BOTH      "%se %s -ats %s %s", PGPNAME, pgpopts, pt, mailto
   78 #       define DO_BOTH1     "%se %s -ats %s %s -u %s", PGPNAME, pgpopts, pt, mailto, mailfrom
   79 #   endif /* HAVE_PGPK */
   80 
   81 #   if defined(HAVE_GPG) /* gpg */
   82 #       define PGPNAME      PATH_GPG
   83 #       define PGPDIR       ".gnupg"
   84 #       define PGP_PUBRING  "pubring.gpg"
   85 #       if 0 /* gpg 1.4.11 doesn't like this */
   86 #           define CHECK_SIGN   "%s %s --no-batch --decrypt <%s %s"
   87 #       else
   88 #           define CHECK_SIGN   "%s %s < %s %s"
   89 #       endif /* 0 */
   90 #       define ADD_KEY      "%s %s --no-batch --import %s"
   91 #       define APPEND_KEY   "%s %s --no-batch --armor --output %s --export %s", PGPNAME, pgpopts, keyfile, buf
   92 #       define DO_ENCRYPT   \
   93 "%s %s --textmode --armor --no-batch --output %s.asc --recipient %s --encrypt %s", \
   94 PGPNAME, pgpopts, pt, mailto, pt
   95 #       define DO_SIGN      \
   96 "%s %s --textmode --armor --no-batch --output %s.asc --escape-from --clearsign %s", \
   97 PGPNAME, pgpopts, pt, pt
   98 #       define DO_SIGN1     \
   99 "%s %s --textmode --armor --no-batch --local-user %s --output %s.asc --escape-from --clearsign %s", \
  100 PGPNAME, pgpopts, mailfrom, pt, pt
  101 #       define DO_BOTH      \
  102 "%s %s --textmode --armor --no-batch --output %s.asc --recipient %s --sign --encrypt %s", \
  103 PGPNAME, pgpopts, pt, mailto, pt
  104 #       define DO_BOTH1     \
  105 "%s %s --textmode --armor --no-batch --output %s.asc --recipient %s --local-user %s --sign --encrypt %s", \
  106 PGPNAME, pgpopts, pt, mailto, mailfrom, pt
  107 #   endif /* HAVE_GPG */
  108 
  109 #   define PGP_SIG_TAG "-----BEGIN PGP SIGNED MESSAGE-----\n"
  110 #   define PGP_KEY_TAG "-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
  111 
  112 #   define HEADERS  "tin-%ld.h"
  113 #   ifdef HAVE_LONG_FILE_NAMES
  114 #       define PLAINTEXT    "tin-%ld.pt"
  115 #       define CIPHERTEXT   "tin-%ld.pt.asc"
  116 #       define KEYFILE      "tin-%ld.k.asc"
  117 #   else
  118 #       define PLAINTEXT    "tn-%ld.p"
  119 #       define CIPHERTEXT   "tn-%ld.p.asc"
  120 #       define KEYFILE      "tn-%ld.k.asc"
  121 #   endif /* HAVE_LONG_FILE_NAMES */
  122 
  123 
  124 /*
  125  * local prototypes
  126  */
  127 static t_bool pgp_available(void);
  128 static void do_pgp(t_function what, const char *file, const char *mail_to);
  129 static void join_files(const char *file);
  130 static void pgp_append_public_key(char *file);
  131 static void split_file(const char *file);
  132 
  133 static char pgp_data[PATH_LEN];
  134 static char hdr[PATH_LEN], pt[PATH_LEN], ct[PATH_LEN];
  135 static const char *pgpopts = "";
  136 
  137 
  138 void
  139 init_pgp(
  140     void)
  141 {
  142     char *ptr;
  143 
  144     pgpopts = get_val("PGPOPTS", "");
  145 
  146 #ifdef HAVE_GPG
  147     if ((ptr = getenv("GNUPGHOME")) != NULL)
  148         my_strncpy(pgp_data, ptr, sizeof(pgp_data) - 1);
  149     else
  150 #endif /* HAVE_GPG */
  151     {
  152         if ((ptr = getenv("PGPPATH")) != NULL)
  153             my_strncpy(pgp_data, ptr, sizeof(pgp_data) - 1);
  154         else
  155             joinpath(pgp_data, sizeof(pgp_data), homedir, PGPDIR);
  156     }
  157 }
  158 
  159 
  160 /*
  161  * Write the header file then the ciphertext file to the art file
  162  * This function is void, no way to return errs
  163  */
  164 static void
  165 join_files(
  166     const char *file)
  167 {
  168     FILE *art, *header, *text;
  169 
  170     if ((header = fopen(hdr, "r")) != NULL) {
  171         if ((text = fopen(ct, "r")) != NULL) {
  172             if ((art = fopen(file, "w")) != NULL) {
  173                 if (copy_fp(header, art))
  174                     copy_fp(text, art);
  175                 fclose(art);
  176             }
  177             fclose(text);
  178         }
  179         fclose(header);
  180     }
  181 
  182     unlink(hdr);
  183     unlink(pt);
  184     unlink(ct);
  185 }
  186 
  187 
  188 /*
  189  * Split the file parameter into a header file 'hdr' and a plaintext
  190  * file 'pt'
  191  */
  192 static void
  193 split_file(
  194     const char *file)
  195 {
  196     FILE *art, *header, *plaintext;
  197     char buf[LEN];
  198     char tmp[PATH_LEN];
  199     mode_t mask;
  200 
  201     snprintf(tmp, sizeof(tmp), HEADERS, (long) process_id);
  202     joinpath(hdr, sizeof(hdr), TMPDIR, tmp);
  203     snprintf(tmp, sizeof(tmp), PLAINTEXT, (long) process_id);
  204     joinpath(pt, sizeof(pt), TMPDIR, tmp);
  205     snprintf(tmp, sizeof(tmp), CIPHERTEXT, (long) process_id);
  206     joinpath(ct, sizeof(ct), TMPDIR, tmp);
  207 
  208     if ((art = fopen(file, "r")) == NULL)
  209         return;
  210 
  211     mask = umask((mode_t) (S_IRWXO|S_IRWXG));
  212 
  213     if ((header = fopen(hdr, "w")) == NULL)
  214         goto err_art;
  215 
  216     if ((plaintext = fopen(pt, "w")) == NULL)
  217         goto err_hdr;
  218 
  219     fgets(buf, LEN, art);           /* Copy the hdr up to and including the \n */
  220     while (strcmp(buf, "\n")) {
  221         fputs(buf, header);
  222         fgets(buf, LEN, art);
  223     }
  224     fputs(buf, header);
  225     copy_fp(art, plaintext);
  226 
  227     fclose(plaintext);
  228 err_hdr:
  229     fclose(header);
  230 err_art:
  231     fclose(art);
  232     umask(mask);
  233 }
  234 
  235 
  236 static void
  237 do_pgp(
  238     t_function what,
  239     const char *file,
  240     const char *mail_to)
  241 {
  242     char cmd[LEN];
  243     char mailfrom[LEN];
  244     const char *mailto = BlankIfNull(mail_to);
  245 
  246     mailfrom[0] = '\0';
  247 
  248     split_file(file);
  249 
  250     /*
  251      * <mailfrom> is valid only when signing and a local address exists
  252      */
  253     if ((CURR_GROUP.attribute->from) != NULL)
  254         strip_name(CURR_GROUP.attribute->from, mailfrom);
  255 
  256     switch (what) {
  257         case PGP_KEY_SIGN:
  258             if (strlen(mailfrom))
  259                 sh_format(cmd, sizeof(cmd), DO_SIGN1);
  260             else
  261                 sh_format(cmd, sizeof(cmd), DO_SIGN);
  262             invoke_cmd(cmd);
  263             break;
  264 
  265         case PGP_KEY_ENCRYPT_SIGN:
  266             if (strlen(mailfrom))
  267                 sh_format(cmd, sizeof(cmd), DO_BOTH1);
  268             else
  269                 sh_format(cmd, sizeof(cmd), DO_BOTH);
  270             invoke_cmd(cmd);
  271             break;
  272 
  273         case PGP_KEY_ENCRYPT:
  274             sh_format(cmd, sizeof(cmd), DO_ENCRYPT);
  275             invoke_cmd(cmd);
  276             break;
  277 
  278         default:
  279             break;
  280     }
  281 
  282     join_files(file);
  283 }
  284 
  285 
  286 static void
  287 pgp_append_public_key(
  288     char *file)
  289 {
  290     FILE *fp, *key;
  291     char cmd[LEN], buf[LEN];
  292     char keyfile[PATH_LEN], tmp[PATH_LEN];
  293 
  294     if ((CURR_GROUP.attribute->from) != NULL && strlen(CURR_GROUP.attribute->from))
  295         strip_name(CURR_GROUP.attribute->from, buf);
  296     else
  297         snprintf(buf, sizeof(buf), "%s@%s", userid, BlankIfNull(get_host_name()));
  298 
  299     snprintf(tmp, sizeof(tmp), KEYFILE, (long) process_id);
  300     joinpath(keyfile, sizeof(keyfile), TMPDIR, tmp);
  301 
  302 /*
  303  * TODO: I'm guessing the pgp append key command creates 'keyfile' and that
  304  * we should remove it
  305  */
  306     sh_format(cmd, sizeof(cmd), APPEND_KEY);
  307     if (invoke_cmd(cmd)) {
  308         if ((fp = fopen(file, "a")) != NULL) {
  309             if ((key = fopen(keyfile, "r")) != NULL) {
  310                 fputc('\n', fp);            /* Add a blank line */
  311                 copy_fp(key, fp);           /* and copy in the key */
  312                 fclose(key);
  313             }
  314             fclose(fp);
  315         }
  316         unlink(keyfile);
  317     }
  318     return;
  319 }
  320 
  321 
  322 /*
  323  * Simply check for existence of keyring file
  324  */
  325 static t_bool
  326 pgp_available(
  327     void)
  328 {
  329     FILE *fp;
  330     char keyring[PATH_LEN];
  331 
  332     joinpath(keyring, sizeof(keyring), pgp_data, PGP_PUBRING);
  333     if ((fp = fopen(keyring, "r")) == NULL) {
  334         wait_message(2, _(txt_pgp_not_avail), keyring);
  335         return FALSE;
  336     }
  337 
  338     fclose(fp);
  339     return TRUE;
  340 }
  341 
  342 
  343 void
  344 invoke_pgp_mail(
  345     const char *nam,
  346     char *mail_to)
  347 {
  348     char keyboth[MAXKEYLEN], keyencrypt[MAXKEYLEN], keyquit[MAXKEYLEN];
  349     char keysign[MAXKEYLEN];
  350     t_function func, default_func = PGP_KEY_SIGN;
  351 
  352     if (!pgp_available())
  353         return;
  354 
  355     func = prompt_slk_response(default_func, pgp_mail_keys, _(txt_pgp_mail),
  356             printascii(keyencrypt, func_to_key(PGP_KEY_ENCRYPT, pgp_mail_keys)),
  357             printascii(keysign, func_to_key(PGP_KEY_SIGN, pgp_mail_keys)),
  358             printascii(keyboth, func_to_key(PGP_KEY_ENCRYPT_SIGN, pgp_mail_keys)),
  359             printascii(keyquit, func_to_key(GLOBAL_QUIT, pgp_mail_keys)));
  360     switch (func) {
  361         case PGP_KEY_SIGN:
  362 #ifdef HAVE_PGPK
  363             ClearScreen();
  364             MoveCursor(cLINES - 7, 0);
  365 #endif /* HAVE_PGPK */
  366             do_pgp(func, nam, NULL);
  367             break;
  368 
  369         case PGP_KEY_ENCRYPT_SIGN:
  370 #ifdef HAVE_PGPK
  371             ClearScreen();
  372             MoveCursor(cLINES - 7, 0);
  373 #endif /* HAVE_PGPK */
  374             do_pgp(func, nam, mail_to);
  375             break;
  376 
  377         case PGP_KEY_ENCRYPT:
  378             do_pgp(func, nam, mail_to);
  379             break;
  380 
  381         case GLOBAL_ABORT:
  382         case GLOBAL_QUIT:
  383         default:
  384             break;
  385     }
  386 }
  387 
  388 
  389 void
  390 invoke_pgp_news(
  391     char *artfile)
  392 {
  393     char keyinclude[MAXKEYLEN], keyquit[MAXKEYLEN], keysign[MAXKEYLEN];
  394     t_function func, default_func = PGP_KEY_SIGN;
  395 
  396     if (!pgp_available())
  397         return;
  398 
  399     func = prompt_slk_response(default_func, pgp_news_keys, _(txt_pgp_news),
  400                 printascii(keysign, func_to_key(PGP_KEY_SIGN, pgp_news_keys)),
  401                 printascii(keyinclude, func_to_key(PGP_INCLUDE_KEY, pgp_news_keys)),
  402                 printascii(keyquit, func_to_key(GLOBAL_QUIT, pgp_news_keys)));
  403     switch (func) {
  404         case GLOBAL_ABORT:
  405         case GLOBAL_QUIT:
  406             break;
  407 
  408         case PGP_KEY_SIGN:
  409 #ifdef HAVE_PGPK
  410             info_message(" ");
  411             MoveCursor(cLINES - 7, 0);
  412             my_printf("\n");
  413 #endif /* HAVE_PGPK */
  414             do_pgp(func, artfile, NULL);
  415             break;
  416 
  417         case PGP_INCLUDE_KEY:
  418 #ifdef HAVE_PGPK
  419             info_message(" ");
  420             MoveCursor(cLINES - 7, 0);
  421             my_printf("\n");
  422 #endif /* HAVE_PGPK */
  423             do_pgp(PGP_KEY_SIGN, artfile, NULL);
  424             pgp_append_public_key(artfile);
  425             break;
  426 
  427         default:
  428             break;
  429     }
  430 }
  431 
  432 
  433 t_bool
  434 pgp_check_article(
  435     t_openartinfo *artinfo)
  436 {
  437     FILE *art;
  438     char artfile[PATH_LEN], buf[LEN], cmd[LEN];
  439     t_bool pgp_signed = FALSE;
  440     t_bool pgp_key = FALSE;
  441 
  442     if (!pgp_available())
  443         return FALSE;
  444 
  445     joinpath(artfile, sizeof(artfile), homedir, TIN_ARTICLE_NAME);
  446 #   ifdef APPEND_PID
  447     snprintf(artfile + strlen(artfile), sizeof(artfile) - strlen(artfile), ".%ld", (long) process_id);
  448 #   endif /* APPEND_PID */
  449     if ((art = fopen(artfile, "w")) == NULL) {
  450         info_message(_(txt_cannot_open), artfile);
  451         return FALSE;
  452     }
  453     /* -> start of body */
  454     if (fseek(artinfo->raw, artinfo->hdr.ext->offset, SEEK_SET) != 0) {
  455         fclose(art);
  456         return FALSE;
  457     }
  458 
  459     fgets(buf, LEN, artinfo->raw);      /* Copy the body whilst looking for SIG/KEY tags */
  460     while (!feof(artinfo->raw)) {
  461         if (!pgp_signed && !strcmp(buf, PGP_SIG_TAG))
  462             pgp_signed = TRUE;
  463         if (!pgp_key && !strcmp(buf, PGP_KEY_TAG))
  464             pgp_key = TRUE;
  465         fputs(buf, art);
  466         fgets(buf, LEN, artinfo->raw);
  467     }
  468     fclose(art);
  469 
  470     if (!(pgp_signed || pgp_key)) {
  471         info_message(_(txt_pgp_nothing));
  472         return FALSE;
  473     }
  474     ClearScreen();
  475 
  476     if (pgp_signed) {
  477         Raw(FALSE);
  478 
  479         /*
  480          * We don't use sh_format here else the redirection get misquoted
  481          */
  482         snprintf(cmd, sizeof(cmd), CHECK_SIGN, PGPNAME, pgpopts, artfile, REDIRECT_PGP_OUTPUT);
  483         invoke_cmd(cmd);
  484         my_printf("\n");
  485         Raw(TRUE);
  486     }
  487 #   ifndef USE_CURSES
  488     EndWin();
  489     Raw(FALSE);
  490 #   endif /* !USE_CURSES */
  491     prompt_continue();
  492 #   ifndef USE_CURSES
  493     Raw(TRUE);
  494     InitWin();
  495 #   endif /* !USE_CURSES */
  496     if (pgp_key) {
  497         if (prompt_yn(_(txt_pgp_add), FALSE) == 1) {
  498             Raw(FALSE);
  499 
  500             sh_format(cmd, sizeof(cmd), ADD_KEY, PGPNAME, pgpopts, artfile);
  501             invoke_cmd(cmd);
  502             my_printf("\n");
  503             Raw(TRUE);
  504         }
  505     }
  506 
  507     unlink(artfile);
  508     return TRUE;
  509 }
  510 #endif /* HAVE_PGP_GPG */