Improve error return by checking the FAILURE status.
authorWerner Koch <wk@gnupg.org>
Tue, 25 Aug 2015 11:22:43 +0000 (13:22 +0200)
committerWerner Koch <wk@gnupg.org>
Tue, 25 Aug 2015 11:23:51 +0000 (13:23 +0200)
* src/gpgme.h.in (GPGME_STATUS_FAILURE): New.
* src/status-table.c (FAILURE): New.
* src/op-support.c (_gpgme_parse_failure): New.
* src/passphrase.c (_gpgme_passphrase_status_handler): Forward FAILURE
status line to the status callback.

* src/decrypt.c (op_data_t): Add field failure_code.
(_gpgme_decrypt_status_handler): Parse that code and act upon it on EOF.
* src/encrypt.c (op_data_t): Add field failure_code.
(_gpgme_encrypt_status_handler): Parse that code and act upon it on EOF.
* src/genkey.c (op_data_t): Add field failure_code.
(genkey_status_handler): Parse that code and act upon it on EOF.
* src/passwd.c (op_data_t): Add field failure_code.
(passwd_status_handler): Parse that code and act upon it on EOF.
* src/sign.c (op_data_t): Add field failure_code.
(_gpgme_sign_status_handler): Parse that code and act upon it on EOF.
* src/verify.c (op_data_t): Add field failure_code.
(_gpgme_verify_status_handler): Parse that code and act upon it on EOF.

--

This requires GnuPG 2.1.8 to actually make a difference.

Signed-off-by: Werner Koch <wk@gnupg.org>
src/decrypt.c
src/encrypt.c
src/genkey.c
src/gpgme.h.in
src/op-support.c
src/ops.h
src/passphrase.c
src/passwd.c
src/sign.c
src/status-table.c
src/verify.c

index 4fd92c6..4db68a1 100644 (file)
@@ -38,6 +38,9 @@ typedef struct
 {
   struct _gpgme_op_decrypt_result result;
 
+  /* The error code from a FAILURE status line or 0.  */
+  gpg_error_t failure_code;
+
   int okay;
   int failed;
 
@@ -192,6 +195,10 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
 
   switch (code)
     {
+    case GPGME_STATUS_FAILURE:
+      opd->failure_code = _gpgme_parse_failure (args);
+      break;
+
     case GPGME_STATUS_EOF:
       /* FIXME: These error values should probably be attributed to
         the underlying crypto engine (as error source).  */
@@ -199,6 +206,8 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
        return gpg_error (GPG_ERR_DECRYPT_FAILED);
       else if (!opd->okay)
        return gpg_error (GPG_ERR_NO_DATA);
+      else if (opd->failure_code)
+        return opd->failure_code;
       break;
 
     case GPGME_STATUS_DECRYPTION_INFO:
index 792c25c..9f5134d 100644 (file)
@@ -36,6 +36,9 @@ typedef struct
 {
   struct _gpgme_op_encrypt_result result;
 
+  /* The error code from a FAILURE status line or 0.  */
+  gpg_error_t failure_code;
+
   /* A pointer to the next pointer of the last invalid recipient in
      the list.  This makes appending new invalid recipients painless
      while preserving the order.  */
@@ -114,9 +117,15 @@ _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code,
 
   switch (code)
     {
+    case GPGME_STATUS_FAILURE:
+      opd->failure_code = _gpgme_parse_failure (args);
+      break;
+
     case GPGME_STATUS_EOF:
       if (opd->result.invalid_recipients)
        return gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+      if (opd->failure_code)
+        return opd->failure_code;
       break;
 
     case GPGME_STATUS_INV_RECP:
index 18765dd..3afd3b4 100644 (file)
@@ -37,6 +37,9 @@ typedef struct
 {
   struct _gpgme_op_genkey_result result;
 
+  /* The error code from a FAILURE status line or 0.  */
+  gpg_error_t failure_code;
+
   /* The key parameters passed to the crypto engine.  */
   gpgme_data_t key_parameter;
 } *op_data_t;
@@ -118,10 +121,16 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
        }
       break;
 
+    case GPGME_STATUS_FAILURE:
+      opd->failure_code = _gpgme_parse_failure (args);
+      break;
+
     case GPGME_STATUS_EOF:
       /* FIXME: Should return some more useful error value.  */
       if (!opd->result.primary && !opd->result.sub)
        return gpg_error (GPG_ERR_GENERAL);
+      else if (opd->failure_code)
+        return opd->failure_code;
       break;
 
     case GPGME_STATUS_INQUIRE_MAXLEN:
index 7605570..432d18a 100644 (file)
@@ -548,7 +548,8 @@ typedef enum
     GPGME_STATUS_ATTRIBUTE = 89,
     GPGME_STATUS_BEGIN_SIGNING = 90,
     GPGME_STATUS_KEY_NOT_CREATED = 91,
-    GPGME_STATUS_INQUIRE_MAXLEN = 92
+    GPGME_STATUS_INQUIRE_MAXLEN = 92,
+    GPGME_STATUS_FAILURE = 93
   }
 gpgme_status_code_t;
 
index 2bcb3a3..02940ef 100644 (file)
@@ -337,3 +337,27 @@ _gpgme_parse_plaintext (char *args, char **filenamep)
     }
   return 0;
 }
+
+
+/* Parse a FAILURE status line and return the error code.  ARGS is
+   modified to contain the location part.  */
+gpgme_error_t
+_gpgme_parse_failure (char *args)
+{
+  char *where, *which;
+
+  where = strchr (args, ' ');
+  if (!where)
+    return trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+  *where = '\0';
+  which = where + 1;
+
+  where = strchr (which, ' ');
+  if (where)
+    *where = '\0';
+
+  where = args;
+
+  return atoi (which);
+}
index 782265e..3662d57 100644 (file)
--- a/src/ops.h
+++ b/src/ops.h
@@ -65,6 +65,10 @@ gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key);
    FILENAMEP.  */
 gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep);
 
+/* Parse a FAILURE status line and return the error code.  ARGS is
+   modified to contain the location part.  */
+gpgme_error_t _gpgme_parse_failure (char *args);
+
 
 \f
 /* From verify.c.  */
index 5d656b1..c88e57d 100644 (file)
@@ -128,6 +128,19 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code,
         }
       break;
 
+    case GPGME_STATUS_FAILURE:
+      /* We abuse this status handler to forward FAILURE status codes
+         to the caller.  This should better be done in a generic
+         handler, but for now this is sufficient.  */
+      if (ctx->status_cb)
+        {
+          err = ctx->status_cb (ctx->status_cb_value, "FAILURE", args);
+          if (err)
+            return err;
+        }
+      break;
+
+
     default:
       /* Ignore all other codes.  */
       break;
index e832026..ff30df0 100644 (file)
@@ -30,6 +30,9 @@
 
 typedef struct
 {
+  /* The error code from a FAILURE status line or 0.  */
+  gpg_error_t failure_code;
+
   int success_seen;
   int error_seen;
 } *op_data_t;
@@ -92,6 +95,10 @@ passwd_status_handler (void *priv, gpgme_status_code_t code, char *args)
       opd->success_seen = 1;
       break;
 
+    case GPGME_STATUS_FAILURE:
+      opd->failure_code = _gpgme_parse_failure (args);
+      break;
+
     case GPGME_STATUS_EOF:
       /* In case the OpenPGP engine does not properly implement the
          passwd command we won't get a success status back and thus we
@@ -102,6 +109,8 @@ passwd_status_handler (void *priv, gpgme_status_code_t code, char *args)
       if (ctx->protocol == GPGME_PROTOCOL_OpenPGP
           && !opd->error_seen && !opd->success_seen)
         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      else if (opd->failure_code)
+        err = opd->failure_code;
       break;
 
     default:
index 9e22fdb..6c9fc03 100644 (file)
@@ -39,6 +39,9 @@ typedef struct
 {
   struct _gpgme_op_sign_result result;
 
+  /* The error code from a FAILURE status line or 0.  */
+  gpg_error_t failure_code;
+
   /* A pointer to the next pointer of the last invalid signer in
      the list.  This makes appending new invalid signers painless
      while preserving the order.  */
@@ -327,6 +330,10 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
       opd->last_signer_p = &(*opd->last_signer_p)->next;
       break;
 
+    case GPGME_STATUS_FAILURE:
+      opd->failure_code = _gpgme_parse_failure (args);
+      break;
+
     case GPGME_STATUS_EOF:
       /* The UI server does not send information about the created
          signature.  This is irrelevant for this protocol and thus we
@@ -335,7 +342,7 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
        err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
       else if (!opd->sig_created_seen
                && ctx->protocol != GPGME_PROTOCOL_UISERVER)
-       err = gpg_error (GPG_ERR_GENERAL);
+       err = opd->failure_code? opd->failure_code:gpg_error (GPG_ERR_GENERAL);
       break;
 
     case GPGME_STATUS_INQUIRE_MAXLEN:
@@ -374,6 +381,7 @@ sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp)
   opd = hook;
   if (err)
     return err;
+  opd->failure_code = 0;
   opd->last_signer_p = &opd->result.invalid_signers;
   opd->last_sig_p = &opd->result.signatures;
   opd->ignore_inv_recp = !!ignore_inv_recp;
index c85fa95..6d428d7 100644 (file)
@@ -66,6 +66,7 @@ static struct status_table_s status_table[] =
   { "ERRSIG", GPGME_STATUS_ERRSIG },
   { "EXPKEYSIG", GPGME_STATUS_EXPKEYSIG },
   { "EXPSIG", GPGME_STATUS_EXPSIG },
+  { "FAILURE", GPGME_STATUS_FAILURE },
   { "FILE_DONE", GPGME_STATUS_FILE_DONE },
   { "FILE_ERROR", GPGME_STATUS_FILE_ERROR },
   { "FILE_START", GPGME_STATUS_FILE_START },
index 84487ee..75914e2 100644 (file)
@@ -38,6 +38,9 @@ typedef struct
 {
   struct _gpgme_op_verify_result result;
 
+  /* The error code from a FAILURE status line or 0.  */
+  gpg_error_t failure_code;
+
   gpgme_signature_t current_sig;
   int did_prepare_new_sig;
   int only_newsig_seen;
@@ -769,6 +772,10 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
          error code if we are not ready to process this status.  */
       return parse_error (sig, args, !!sig );
 
+    case GPGME_STATUS_FAILURE:
+      opd->failure_code = _gpgme_parse_failure (args);
+      break;
+
     case GPGME_STATUS_EOF:
       if (sig && !opd->did_prepare_new_sig)
        calc_sig_summary (sig);
@@ -795,6 +802,8 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
           opd->current_sig = NULL;
         }
       opd->only_newsig_seen = 0;
+      if (opd->failure_code)
+        return opd->failure_code;
       break;
 
     case GPGME_STATUS_PLAINTEXT: