/* 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)
{
{
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)
/* 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);
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;
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;
/* 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 */
*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
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);
*/
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)
{
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.");
}
safe_fclose (&tmpfp);
mutt_unlink (tmpfname);
}
- if (pgpout)
- {
- safe_fclose (&pgpout);
- mutt_unlink (outfile);
- }
+ safe_fclose (&pgpout);
+ safe_fclose (&pgperr);
FREE(&gpgcharset);