From: Kevin McCarthy Date: Tue, 5 Jun 2018 04:31:33 +0000 (-0700) Subject: Add GnuPG status fd checks for inline pgp. X-Git-Tag: mutt-1-10-1-rel~14 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=edb4ec84f7078a188ee4c9491405418adf26eb1c;p=mutt Add GnuPG status fd checks for inline pgp. The difficulty is that "BEGIN PGP MESSAGE" could be a signed and armored part, so we can't fail hard if it isn't encrypted. Change pgp_check_decryption_okay() to return more status codes, with >=0 indicating an actual decryption; -2 and -1 indicating plaintext found; and -3 indicating an actual DECRYPTION_FAILED status code seen. Fail hard on -3, but change the message for -2 and -1 to indicate the message was not encrypted. --- diff --git a/pgp.c b/pgp.c index c9a4c91f..60971119 100644 --- a/pgp.c +++ b/pgp.c @@ -268,6 +268,20 @@ static int pgp_check_pgp_decryption_okay_regexp (FILE *fpin) /* Checks GnuPGP status fd output for various status codes indicating * an issue. If $pgp_check_gpg_decrypt_status_fd is unset, it falls * back to the old behavior of just scanning for $pgp_decryption_okay. + * + * pgp_decrypt_part() should fail if the part is not encrypted, so we return + * less than 0 to indicate part or all was NOT actually encrypted. + * + * On the other hand, for pgp_application_pgp_handler(), a + * "BEGIN PGP MESSAGE" could indicate a signed and armored message. + * For that we allow -1 and -2 as "valid" (with a warning). + * + * Returns: + * 1 - no patterns were matched (if delegated to decryption_okay_regexp) + * 0 - DECRYPTION_OKAY was seen, with no PLAINTEXT outside. + * -1 - No decryption status codes were encountered + * -2 - PLAINTEXT was encountered outside of DECRYPTION delimeters. + * -3 - DECRYPTION_FAILED was encountered */ static int pgp_check_decryption_okay (FILE *fpin) { @@ -295,15 +309,15 @@ static int pgp_check_decryption_okay (FILE *fpin) { if (!inside_decrypt) { - dprint (2, (debugfile, "\tPLAINTEXT encountered outside of DECRYPTION. Failure.\n")); - rv = -1; - break; + dprint (2, (debugfile, "\tPLAINTEXT encountered outside of DECRYPTION.\n")); + if (rv > -2) + rv = -2; } } else if (mutt_strncmp (s, "DECRYPTION_FAILED", 17) == 0) { dprint (2, (debugfile, "\tDECRYPTION_FAILED encountered. Failure.\n")); - rv = -1; + rv = -3; break; } else if (mutt_strncmp (s, "DECRYPTION_OKAY", 15) == 0) @@ -311,7 +325,8 @@ static int pgp_check_decryption_okay (FILE *fpin) /* Don't break out because we still have to check for * PLAINTEXT outside of the decryption boundaries. */ dprint (2, (debugfile, "\tDECRYPTION_OKAY encountered.\n")); - rv = 0; + if (rv > -2) + rv = 0; } } FREE (&line); @@ -386,14 +401,15 @@ static void pgp_copy_clearsigned (FILE *fpin, STATE *s, char *charset) int pgp_application_pgp_handler (BODY *m, STATE *s) { - int could_not_decrypt = 0; + int could_not_decrypt, decrypt_okay_rc; int needpass = -1, pgp_keyblock = 0; int clearsign = 0, rv, rc; int c = 1; /* silence GCC warning */ long bytes; LOFF_T last_pos, offset; char buf[HUGE_STRING]; - char outfile[_POSIX_PATH_MAX]; + char pgpoutfile[_POSIX_PATH_MAX]; + char pgperrfile[_POSIX_PATH_MAX]; char tmpfname[_POSIX_PATH_MAX]; FILE *pgpout = NULL, *pgpin = NULL, *pgperr = NULL; FILE *tmpfp = NULL; @@ -423,6 +439,8 @@ int pgp_application_pgp_handler (BODY *m, STATE *s) if (mutt_strncmp ("-----BEGIN PGP ", buf, 15) == 0) { clearsign = 0; + could_not_decrypt = 0; + decrypt_okay_rc = 0; if (mutt_strcmp ("MESSAGE-----\n", buf + 15) == 0) needpass = 1; @@ -487,21 +505,31 @@ int pgp_application_pgp_handler (BODY *m, STATE *s) /* Invoke PGP if needed */ if (!clearsign || (s->flags & MUTT_VERIFY)) { - mutt_mktemp (outfile, sizeof (outfile)); - if ((pgpout = safe_fopen (outfile, "w+")) == NULL) + mutt_mktemp (pgpoutfile, sizeof (pgpoutfile)); + if ((pgpout = safe_fopen (pgpoutfile, "w+")) == NULL) { - mutt_perror (outfile); - return -1; + mutt_perror (pgpoutfile); + rc = -1; + goto out; } - - if ((thepid = pgp_invoke_decode (&pgpin, NULL, &pgperr, -1, - fileno (pgpout), -1, tmpfname, - needpass)) == -1) + unlink (pgpoutfile); + + mutt_mktemp (pgperrfile, sizeof (pgperrfile)); + if ((pgperr = safe_fopen (pgperrfile, "w+")) == NULL) + { + mutt_perror (pgperrfile); + rc = -1; + goto out; + } + unlink (pgperrfile); + + if ((thepid = pgp_invoke_decode (&pgpin, NULL, NULL, + -1, fileno (pgpout), fileno (pgperr), + tmpfname, needpass)) == -1) { safe_fclose (&pgpout); maybe_goodsig = 0; pgpin = NULL; - pgperr = NULL; state_attach_puts (_("[-- Error: unable to create PGP subprocess! --]\n"), s); } else /* PGP started successfully */ @@ -513,20 +541,33 @@ int pgp_application_pgp_handler (BODY *m, STATE *s) *PgpPass = 0; fprintf (pgpin, "%s\n", PgpPass); } - + safe_fclose (&pgpin); + rv = mutt_wait_filter (thepid); + + fflush (pgperr); + /* If we are expecting an encrypted message, verify status fd output. + * Note that BEGIN PGP MESSAGE does not guarantee the content is encrypted, + * so we need to be more selective about the value of decrypt_okay_rc. + * + * -3 indicates we actively found a DECRYPTION_FAILED. + * -2 and -1 indicate part or all of the content was plaintext. + */ + if (needpass) + { + rewind (pgperr); + decrypt_okay_rc = pgp_check_decryption_okay (pgperr); + if (decrypt_okay_rc <= -3) + safe_fclose (&pgpout); + } + if (s->flags & MUTT_DISPLAY) { + rewind (pgperr); crypt_current_time (s, "PGP"); rc = pgp_copy_checksig (pgperr, s->fpout); - } - - safe_fclose (&pgperr); - rv = mutt_wait_filter (thepid); - - if (s->flags & MUTT_DISPLAY) - { + if (rc == 0) have_any_sigs = 1; /* * Sig is bad if @@ -556,7 +597,8 @@ int pgp_application_pgp_handler (BODY *m, STATE *s) pgp_void_passphrase (); } - if (could_not_decrypt && !(s->flags & MUTT_DISPLAY)) + if ((could_not_decrypt || (decrypt_okay_rc <= -3)) && + !(s->flags & MUTT_DISPLAY)) { mutt_error _("Could not decrypt PGP message"); mutt_sleep (1); @@ -608,11 +650,8 @@ int pgp_application_pgp_handler (BODY *m, STATE *s) */ safe_fclose (&tmpfp); mutt_unlink (tmpfname); - if (pgpout) - { - safe_fclose (&pgpout); - mutt_unlink (outfile); - } + safe_fclose (&pgpout); + safe_fclose (&pgperr); if (s->flags & MUTT_DISPLAY) { @@ -620,8 +659,10 @@ int pgp_application_pgp_handler (BODY *m, STATE *s) if (needpass) { state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s); - if (could_not_decrypt) + if (could_not_decrypt || (decrypt_okay_rc <= -3)) mutt_error _("Could not decrypt PGP message"); + else if (decrypt_okay_rc < 0) + mutt_error _("PGP message was not encrypted."); else mutt_message _("PGP message successfully decrypted."); } @@ -651,11 +692,8 @@ out: safe_fclose (&tmpfp); mutt_unlink (tmpfname); } - if (pgpout) - { - safe_fclose (&pgpout); - mutt_unlink (outfile); - } + safe_fclose (&pgpout); + safe_fclose (&pgperr); FREE(&gpgcharset);