]> granicus.if.org Git - mutt/commitdiff
Add GnuPG status fd checks for inline pgp.
authorKevin McCarthy <kevin@8t8.us>
Tue, 5 Jun 2018 04:31:33 +0000 (21:31 -0700)
committerKevin McCarthy <kevin@8t8.us>
Tue, 5 Jun 2018 04:37:49 +0000 (21:37 -0700)
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.

pgp.c

diff --git a/pgp.c b/pgp.c
index c9a4c91f5a06547b3d024af3d40d3d2faf988684..60971119eb9ca7f37b7c384686928f7a5e73bc92 100644 (file)
--- 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);