"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.2/src/pgp.c" (8 Dec 2017, 13203 Bytes) of package /linux/misc/tin-2.4.2.tar.xz:


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.1_vs_2.4.2.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : pgp.c
    4  *  Author    : Steven J. Madsen
    5  *  Created   : 1995-05-12
    6  *  Updated   : 2017-03-28
    7  *  Notes     : PGP support
    8  *
    9  * Copyright (c) 1995-2018 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 }
  319 
  320 
  321 /*
  322  * Simply check for existence of keyring file
  323  */
  324 static t_bool
  325 pgp_available(
  326     void)
  327 {
  328     FILE *fp;
  329     char keyring[PATH_LEN];
  330 
  331     joinpath(keyring, sizeof(keyring), pgp_data, PGP_PUBRING);
  332     if ((fp = fopen(keyring, "r")) == NULL) {
  333         wait_message(2, _(txt_pgp_not_avail), keyring);
  334         return FALSE;
  335     }
  336 
  337     fclose(fp);
  338     return TRUE;
  339 }
  340 
  341 
  342 void
  343 invoke_pgp_mail(
  344     const char *nam,
  345     char *mail_to)
  346 {
  347     char keyboth[MAXKEYLEN], keyencrypt[MAXKEYLEN], keyquit[MAXKEYLEN];
  348     char keysign[MAXKEYLEN];
  349     t_function func, default_func = PGP_KEY_SIGN;
  350 
  351     if (!pgp_available())
  352         return;
  353 
  354     func = prompt_slk_response(default_func, pgp_mail_keys, _(txt_pgp_mail),
  355             printascii(keyencrypt, func_to_key(PGP_KEY_ENCRYPT, pgp_mail_keys)),
  356             printascii(keysign, func_to_key(PGP_KEY_SIGN, pgp_mail_keys)),
  357             printascii(keyboth, func_to_key(PGP_KEY_ENCRYPT_SIGN, pgp_mail_keys)),
  358             printascii(keyquit, func_to_key(GLOBAL_QUIT, pgp_mail_keys)));
  359     switch (func) {
  360         case PGP_KEY_SIGN:
  361 #ifdef HAVE_PGPK
  362             ClearScreen();
  363             MoveCursor(cLINES - 7, 0);
  364 #endif /* HAVE_PGPK */
  365             do_pgp(func, nam, NULL);
  366             break;
  367 
  368         case PGP_KEY_ENCRYPT_SIGN:
  369 #ifdef HAVE_PGPK
  370             ClearScreen();
  371             MoveCursor(cLINES - 7, 0);
  372 #endif /* HAVE_PGPK */
  373             do_pgp(func, nam, mail_to);
  374             break;
  375 
  376         case PGP_KEY_ENCRYPT:
  377             do_pgp(func, nam, mail_to);
  378             break;
  379 
  380         case GLOBAL_ABORT:
  381         case GLOBAL_QUIT:
  382         default:
  383             break;
  384     }
  385 }
  386 
  387 
  388 void
  389 invoke_pgp_news(
  390     char *artfile)
  391 {
  392     char keyinclude[MAXKEYLEN], keyquit[MAXKEYLEN], keysign[MAXKEYLEN];
  393     t_function func, default_func = PGP_KEY_SIGN;
  394 
  395     if (!pgp_available())
  396         return;
  397 
  398     func = prompt_slk_response(default_func, pgp_news_keys, _(txt_pgp_news),
  399                 printascii(keysign, func_to_key(PGP_KEY_SIGN, pgp_news_keys)),
  400                 printascii(keyinclude, func_to_key(PGP_INCLUDE_KEY, pgp_news_keys)),
  401                 printascii(keyquit, func_to_key(GLOBAL_QUIT, pgp_news_keys)));
  402     switch (func) {
  403         case GLOBAL_ABORT:
  404         case GLOBAL_QUIT:
  405             break;
  406 
  407         case PGP_KEY_SIGN:
  408 #ifdef HAVE_PGPK
  409             info_message(" ");
  410             MoveCursor(cLINES - 7, 0);
  411             my_printf("\n");
  412 #endif /* HAVE_PGPK */
  413             do_pgp(func, artfile, NULL);
  414             break;
  415 
  416         case PGP_INCLUDE_KEY:
  417 #ifdef HAVE_PGPK
  418             info_message(" ");
  419             MoveCursor(cLINES - 7, 0);
  420             my_printf("\n");
  421 #endif /* HAVE_PGPK */
  422             do_pgp(PGP_KEY_SIGN, artfile, NULL);
  423             pgp_append_public_key(artfile);
  424             break;
  425 
  426         default:
  427             break;
  428     }
  429 }
  430 
  431 
  432 t_bool
  433 pgp_check_article(
  434     t_openartinfo *artinfo)
  435 {
  436     FILE *art;
  437     char artfile[PATH_LEN], buf[LEN], cmd[LEN];
  438     t_bool pgp_signed = FALSE;
  439     t_bool pgp_key = FALSE;
  440 
  441     if (!pgp_available())
  442         return FALSE;
  443 
  444     joinpath(artfile, sizeof(artfile), homedir, TIN_ARTICLE_NAME);
  445 #   ifdef APPEND_PID
  446     snprintf(artfile + strlen(artfile), sizeof(artfile) - strlen(artfile), ".%ld", (long) process_id);
  447 #   endif /* APPEND_PID */
  448     if ((art = fopen(artfile, "w")) == NULL) {
  449         info_message(_(txt_cannot_open), artfile);
  450         return FALSE;
  451     }
  452     /* -> start of body */
  453     if (fseek(artinfo->raw, artinfo->hdr.ext->offset, SEEK_SET) != 0) {
  454         fclose(art);
  455         return FALSE;
  456     }
  457 
  458     fgets(buf, LEN, artinfo->raw);      /* Copy the body whilst looking for SIG/KEY tags */
  459     while (!feof(artinfo->raw)) {
  460         if (!pgp_signed && !strcmp(buf, PGP_SIG_TAG))
  461             pgp_signed = TRUE;
  462         if (!pgp_key && !strcmp(buf, PGP_KEY_TAG))
  463             pgp_key = TRUE;
  464         fputs(buf, art);
  465         fgets(buf, LEN, artinfo->raw);
  466     }
  467     fclose(art);
  468 
  469     if (!(pgp_signed || pgp_key)) {
  470         info_message(_(txt_pgp_nothing));
  471         return FALSE;
  472     }
  473     ClearScreen();
  474 
  475     if (pgp_signed) {
  476         Raw(FALSE);
  477 
  478         /*
  479          * We don't use sh_format here else the redirection get misquoted
  480          */
  481         snprintf(cmd, sizeof(cmd), CHECK_SIGN, PGPNAME, pgpopts, artfile, REDIRECT_PGP_OUTPUT);
  482         invoke_cmd(cmd);
  483         my_printf("\n");
  484         Raw(TRUE);
  485     }
  486 #   ifndef USE_CURSES
  487     EndWin();
  488     Raw(FALSE);
  489 #   endif /* !USE_CURSES */
  490     prompt_continue();
  491 #   ifndef USE_CURSES
  492     Raw(TRUE);
  493     InitWin();
  494 #   endif /* !USE_CURSES */
  495     if (pgp_key) {
  496         if (prompt_yn(_(txt_pgp_add), FALSE) == 1) {
  497             Raw(FALSE);
  498 
  499             sh_format(cmd, sizeof(cmd), ADD_KEY, PGPNAME, pgpopts, artfile);
  500             invoke_cmd(cmd);
  501             my_printf("\n");
  502             Raw(TRUE);
  503         }
  504     }
  505 
  506     unlink(artfile);
  507     return TRUE;
  508 }
  509 #endif /* HAVE_PGP_GPG */