[git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-149-g21feecd

by Werner Koch cvs at cvs.gnupg.org
Thu Feb 7 20:50:16 CET 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  21feecd48f990b2569cb4b385dea3e57b9501525 (commit)
       via  84de484bc3eaeeba755412918b01bc8444a532ee (commit)
       via  8b2b8dfe5c4cd346bbea2c228e75737bbeeca4c4 (commit)
       via  4483a4f0ea030046137ba04905eb5220c14a2161 (commit)
      from  c27315fc6466cceb862c9e67755a8e044e9b7688 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 21feecd48f990b2569cb4b385dea3e57b9501525
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Feb 7 20:37:58 2013 +0100

    gpg: Add pinentry-mode feature.
    
    * g10/gpg.c: Include shareddefs.h.
    (main): Add option --pinentry-mode.
    * g10/options.h (struct opt): Add field pinentry_mode.
    * g10/passphrase.c: Include shareddefs.h.
    (have_static_passphrase): Take care of loopback pinentry_mode.
    (read_passphrase_from_fd): Ditto.
    (get_static_passphrase): New.
    (passphrase_to_dek_ext): Factor some code out to ...
    (emit_status_need_passphrase): new.
    * g10/call-agent.c (start_agent): Send the pinentry mode.
    (default_inq_cb): Take care of the PASSPHRASE inquiry.  Return a
    proper error code.
    (agent_pksign): Add args keyid, mainkeyid and pubkey_algo.
    (agent_pkdecrypt): Ditto.
    * g10/pubkey-enc.c (get_it): Pass new args.
    * g10/sign.c (do_sign): Pass new args.
    
    * g10/call-agent.c (struct default_inq_parm_s): New.  Change all
    similar structs to reference this one.  Change all users and inquire
    callback to use this struct, instead of NULL or some undefined but not
    used structs.  This change will help to eventually get rid of global
    variables.
    --
    
    This new features allows to use gpg without a Pinentry.  As a
    prerequisite the agent must be configured to allow the loopback
    pinentry mode (option --allow-loopback-pinentry).  For example
    
      gpg2 --pinentry-mode=loopback FILE.gpg
    
    may be used to decrypt FILE.gpg while entering the passphrase on the
    tty.  If batch is used, --passphrase et al. may be used, if
    --command-fd is used, the passphrase may be provided by another
    process.  Note that there are no try-again prompts in case of a bad
    passphrase.

diff --git a/NEWS b/NEWS
index a8352ca..b81759c 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,8 @@ Noteworthy changes in version 2.1.0beta4 (unreleased)
 
  * The hash algorithm is now printed for sig records in key listings.
 
+ * New option --pinentry-mode for GPG.
+
 
 Noteworthy changes in version 2.1.0beta3 (2011-12-20)
 -----------------------------------------------------
diff --git a/doc/gpg.texi b/doc/gpg.texi
index d679000..cf647e1 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -2611,6 +2611,26 @@ Note that this passphrase is only used if the option @option{--batch}
 has also been given.  This is different from @command{gpg}.
 @end ifclear
 
+ at ifset gpgtwoone
+ at item --pinentry-mode @code{mode}
+ at opindex pinentry-mode
+Set the pinentry mode to @code{mode}.  Allowed values for @code{mode}
+are:
+ at table @asis
+  @item default
+  Use the default of the agent, which is @code{ask}.
+  @item ask
+  Force the use of the Pinentry.
+  @item cancel
+  Emulate use of Pinentry's cancel button.
+  @item error
+  Return a Pinentry error (``No Pinentry'').
+  @item loopback
+  Redirect Pinentry queries to the caller.  Note that in contrast to
+  Pinentry the user is not prompted again if he enters a bad password.
+ at end table
+ at end ifset
+
 @item --command-fd @code{n}
 @opindex command-fd
 This is a replacement for the deprecated shared-memory IPC mode.
diff --git a/g10/call-agent.c b/g10/call-agent.c
index a4d1dbb..ed141da 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -1,6 +1,6 @@
 /* call-agent.c - Divert GPG operations to the agent.
  * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008, 2009,
- *               2010, 2011 Free Software Foundation, Inc.
+ *               2010, 2011, 2013 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -40,47 +40,60 @@
 #include "sysutils.h"
 #include "call-agent.h"
 #include "status.h"
+#include "../common/shareddefs.h"
 
 #ifndef DBG_ASSUAN
 # define DBG_ASSUAN 1
 #endif
 
+#define CONTROL_D ('D' - 'A' + 1)
+
+
 static assuan_context_t agent_ctx = NULL;
 static int did_early_card_test;
 
-struct cipher_parm_s
+struct default_inq_parm_s
 {
   ctrl_t ctrl;
   assuan_context_t ctx;
+  struct {
+    u32 *keyid;
+    u32 *mainkeyid;
+    int pubkey_algo;
+  } keyinfo;
+};
+
+struct cipher_parm_s
+{
+  struct default_inq_parm_s *dflt;
+  assuan_context_t ctx;
   unsigned char *ciphertext;
   size_t ciphertextlen;
 };
 
 struct writecert_parm_s
 {
-  assuan_context_t ctx;
+  struct default_inq_parm_s *dflt;
   const unsigned char *certdata;
   size_t certdatalen;
 };
 
 struct writekey_parm_s
 {
-  assuan_context_t ctx;
+  struct default_inq_parm_s *dflt;
   const unsigned char *keydata;
   size_t keydatalen;
 };
 
 struct genkey_parm_s
 {
-  ctrl_t ctrl;
-  assuan_context_t ctx;
+  struct default_inq_parm_s *dflt;
   const char *keyparms;
 };
 
 struct import_key_parm_s
 {
-  ctrl_t ctrl;
-  assuan_context_t ctx;
+  struct default_inq_parm_s *dflt;
   const void *key;
   size_t keylen;
 };
@@ -161,6 +174,19 @@ start_agent (ctrl_t ctrl, int for_card)
              here used to indirectly enable GPG_ERR_FULLY_CANCELED.  */
           assuan_transact (agent_ctx, "OPTION agent-awareness=2.1.0",
                            NULL, NULL, NULL, NULL, NULL, NULL);
+          /* Pass on the pinentry mode.  */
+          if (opt.pinentry_mode)
+            {
+              char *tmp = xasprintf ("OPTION pinentry-mode=%s",
+                                     str_pinentry_mode (opt.pinentry_mode));
+              rc = assuan_transact (agent_ctx, tmp,
+                               NULL, NULL, NULL, NULL, NULL, NULL);
+              xfree (tmp);
+              if (rc)
+                log_error ("setting pinentry mode '%s' failed: %s\n",
+                           str_pinentry_mode (opt.pinentry_mode),
+                           gpg_strerror (rc));
+            }
 
         }
     }
@@ -307,21 +333,46 @@ get_serialno_cb (void *opaque, const char *line)
 static gpg_error_t
 default_inq_cb (void *opaque, const char *line)
 {
-  gpg_error_t err;
-  ctrl_t ctrl = opaque;
+  gpg_error_t err = 0;
+  struct default_inq_parm_s *parm = opaque;
 
   if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
     {
-      err = gpg_proxy_pinentry_notify (ctrl, line);
+      err = gpg_proxy_pinentry_notify (parm->ctrl, line);
       if (err)
         log_error (_("failed to proxy %s inquiry to client\n"),
                    "PINENTRY_LAUNCHED");
       /* We do not pass errors to avoid breaking other code.  */
     }
+  else if (!strncmp (line, "PASSPHRASE", 10) && (line[10]==' '||!line[10])
+           && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
+    {
+      if (have_static_passphrase ())
+        {
+          const char *s = get_static_passphrase ();
+          err = assuan_send_data (parm->ctx, s, strlen (s));
+        }
+      else
+        {
+          char *pw;
+
+          if (parm->keyinfo.keyid)
+            emit_status_need_passphrase (parm->keyinfo.keyid,
+                                         parm->keyinfo.mainkeyid,
+                                         parm->keyinfo.pubkey_algo);
+          pw = cpr_get_hidden ("passphrase.enter", _("Enter passphrase: "));
+          cpr_kill_prompt ();
+          if (*pw == CONTROL_D && !pw[1])
+            err = gpg_error (GPG_ERR_CANCELED);
+          else
+            err = assuan_send_data (parm->ctx, pw, strlen (pw));
+          xfree (pw);
+        }
+    }
   else
     log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
 
-  return 0;
+  return err;
 }
 
 
@@ -516,6 +567,9 @@ int
 agent_learn (struct agent_card_info_s *info)
 {
   int rc;
+  struct default_inq_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
 
   rc = start_agent (NULL, 1);
   if (rc)
@@ -533,10 +587,10 @@ agent_learn (struct agent_card_info_s *info)
   if (rc)
     return rc;
 
-
+  parm.ctx = agent_ctx;
   memset (info, 0, sizeof *info);
   rc = assuan_transact (agent_ctx, "SCD LEARN --force",
-                        dummy_data_cb, NULL, default_inq_cb, NULL,
+                        dummy_data_cb, NULL, default_inq_cb, &parm,
                         learn_status_cb, info);
   /* Also try to get the key attributes.  */
   if (!rc)
@@ -553,6 +607,9 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
 
   if (!*name)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -566,7 +623,8 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info)
   if (rc)
     return rc;
 
-  rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, NULL,
+  parm.ctx = agent_ctx;
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &parm,
                         learn_status_cb, info);
 
   return rc;
@@ -584,6 +642,9 @@ agent_scd_setattr (const char *name,
   int rc;
   char line[ASSUAN_LINELENGTH];
   char *p;
+  struct default_inq_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
 
   (void)serialno;
 
@@ -615,8 +676,9 @@ agent_scd_setattr (const char *name,
   rc = start_agent (NULL, 1);
   if (!rc)
     {
+      parm.ctx = agent_ctx;
       rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                            default_inq_cb, NULL, NULL, NULL);
+                            default_inq_cb, &parm, NULL, NULL);
     }
 
   status_sc_op_failure (rc);
@@ -636,10 +698,11 @@ inq_writecert_parms (void *opaque, const char *line)
 
   if (!strncmp (line, "CERTDATA", 8) && (line[8]==' '||!line[8]))
     {
-      rc = assuan_send_data (parm->ctx, parm->certdata, parm->certdatalen);
+      rc = assuan_send_data (parm->dflt->ctx,
+                             parm->certdata, parm->certdatalen);
     }
   else
-    rc = default_inq_cb (opaque, line);
+    rc = default_inq_cb (parm->dflt, line);
 
   return rc;
 }
@@ -653,6 +716,9 @@ agent_scd_writecert (const char *certidstr,
   int rc;
   char line[ASSUAN_LINELENGTH];
   struct writecert_parm_s parms;
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   rc = start_agent (NULL, 1);
   if (rc)
@@ -662,7 +728,8 @@ agent_scd_writecert (const char *certidstr,
 
   snprintf (line, DIM(line)-1, "SCD WRITECERT %s", certidstr);
   line[DIM(line)-1] = 0;
-  parms.ctx = agent_ctx;
+  dfltparm.ctx = agent_ctx;
+  parms.dflt = &dfltparm;
   parms.certdata = certdata;
   parms.certdatalen = certdatalen;
 
@@ -684,10 +751,10 @@ inq_writekey_parms (void *opaque, const char *line)
 
   if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7]))
     {
-      rc = assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen);
+      rc = assuan_send_data (parm->dflt->ctx, parm->keydata, parm->keydatalen);
     }
   else
-    rc = default_inq_cb (opaque, line);
+    rc = default_inq_cb (parm->dflt, line);
 
   return rc;
 }
@@ -701,6 +768,9 @@ agent_scd_writekey (int keyno, const char *serialno,
   int rc;
   char line[ASSUAN_LINELENGTH];
   struct writekey_parm_s parms;
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   (void)serialno;
 
@@ -712,7 +782,8 @@ agent_scd_writekey (int keyno, const char *serialno,
 
   snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno);
   line[DIM(line)-1] = 0;
-  parms.ctx = agent_ctx;
+  dfltparm.ctx = agent_ctx;
+  parms.dflt = &dfltparm;
   parms.keydata = keydata;
   parms.keydatalen = keydatalen;
 
@@ -837,6 +908,9 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
   char line[ASSUAN_LINELENGTH];
   gnupg_isotime_t tbuf;
   struct scd_genkey_parm_s parms;
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   (void)serialno;
 
@@ -858,9 +932,10 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
             keyno);
   line[DIM(line)-1] = 0;
 
+  dfltparm.ctx = agent_ctx;
   memset (info, 0, sizeof *info);
   rc = assuan_transact (agent_ctx, line,
-                        NULL, NULL, default_inq_cb, NULL,
+                        NULL, NULL, default_inq_cb, &dfltparm,
                         scd_genkey_cb, &parms);
 
   xfree (parms.savedbytes);
@@ -986,19 +1061,25 @@ agent_scd_readcert (const char *certidstr,
   char line[ASSUAN_LINELENGTH];
   membuf_t data;
   size_t len;
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   *r_buf = NULL;
   rc = start_agent (NULL, 1);
   if (rc)
     return rc;
 
+  dfltparm.ctx = agent_ctx;
+
   init_membuf (&data, 2048);
 
   snprintf (line, DIM(line)-1, "SCD READCERT %s", certidstr);
   line[DIM(line)-1] = 0;
   rc = assuan_transact (agent_ctx, line,
                         membuf_data_cb, &data,
-                        default_inq_cb, NULL, NULL, NULL);
+                        default_inq_cb, &dfltparm,
+                        NULL, NULL);
   if (rc)
     {
       xfree (get_membuf (&data, &len));
@@ -1029,6 +1110,9 @@ agent_scd_change_pin (int chvno, const char *serialno)
   int rc;
   char line[ASSUAN_LINELENGTH];
   const char *reset = "";
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   (void)serialno;
 
@@ -1039,11 +1123,14 @@ agent_scd_change_pin (int chvno, const char *serialno)
   rc = start_agent (NULL, 1);
   if (rc)
     return rc;
+  dfltparm.ctx = agent_ctx;
 
   snprintf (line, DIM(line)-1, "SCD PASSWD %s %d", reset, chvno);
   line[DIM(line)-1] = 0;
-  rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, line,
+                        NULL, NULL,
+                        default_inq_cb, &dfltparm,
+                        NULL, NULL);
   status_sc_op_failure (rc);
   return rc;
 }
@@ -1057,16 +1144,21 @@ agent_scd_checkpin  (const char *serialno)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   rc = start_agent (NULL, 1);
   if (rc)
     return rc;
+  dfltparm.ctx = agent_ctx;
 
   snprintf (line, DIM(line)-1, "SCD CHECKPIN %s", serialno);
   line[DIM(line)-1] = 0;
   rc = assuan_transact (agent_ctx, line,
                         NULL, NULL,
-                        default_inq_cb, NULL, NULL, NULL);
+                        default_inq_cb, &dfltparm,
+                        NULL, NULL);
   status_sc_op_failure (rc);
   return rc;
 }
@@ -1102,12 +1194,16 @@ agent_get_passphrase (const char *cache_id,
   char *arg3 = NULL;
   char *arg4 = NULL;
   membuf_t data;
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   *r_passphrase = NULL;
 
   rc = start_agent (NULL, 0);
   if (rc)
     return rc;
+  dfltparm.ctx = agent_ctx;
 
   /* Check that the gpg-agent understands the repeat option.  */
   if (assuan_transact (agent_ctx,
@@ -1145,7 +1241,8 @@ agent_get_passphrase (const char *cache_id,
   init_membuf_secure (&data, 64);
   rc = assuan_transact (agent_ctx, line,
                         membuf_data_cb, &data,
-                        default_inq_cb, NULL, NULL, NULL);
+                        default_inq_cb, &dfltparm,
+                        NULL, NULL);
 
   if (rc)
     xfree (get_membuf (&data, NULL));
@@ -1172,6 +1269,9 @@ agent_clear_passphrase (const char *cache_id)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   if (!cache_id || !*cache_id)
     return 0;
@@ -1179,11 +1279,14 @@ agent_clear_passphrase (const char *cache_id)
   rc = start_agent (NULL, 0);
   if (rc)
     return rc;
+  dfltparm.ctx = agent_ctx;
 
   snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
   line[DIM(line)-1] = 0;
-  return assuan_transact (agent_ctx, line, NULL, NULL,
-                          default_inq_cb, NULL, NULL, NULL);
+  return assuan_transact (agent_ctx, line,
+                          NULL, NULL,
+                          default_inq_cb, &dfltparm,
+                          NULL, NULL);
 }
 
 
@@ -1195,10 +1298,14 @@ gpg_agent_get_confirmation (const char *desc)
   int rc;
   char *tmp;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
 
   rc = start_agent (NULL, 0);
   if (rc)
     return rc;
+  dfltparm.ctx = agent_ctx;
 
   tmp = percent_plus_escape (desc);
   if (!tmp)
@@ -1207,8 +1314,10 @@ gpg_agent_get_confirmation (const char *desc)
   line[DIM(line)-1] = 0;
   xfree (tmp);
 
-  rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, line,
+                        NULL, NULL,
+                        default_inq_cb, &dfltparm,
+                        NULL, NULL);
   return rc;
 }
 
@@ -1439,11 +1548,11 @@ inq_genkey_parms (void *opaque, const char *line)
 
   if (!strncmp (line, "KEYPARAM", 8) && (line[8]==' '||!line[8]))
     {
-      err = assuan_send_data (parm->ctx,
+      err = assuan_send_data (parm->dflt->ctx,
                               parm->keyparms, strlen (parm->keyparms));
     }
   else
-    err = default_inq_cb (parm->ctrl, line);
+    err = default_inq_cb (parm->dflt, line);
 
   return err;
 }
@@ -1460,15 +1569,20 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
   gpg_error_t err;
   struct genkey_parm_s gk_parm;
   struct cache_nonce_parm_s cn_parm;
+  struct default_inq_parm_s dfltparm;
   membuf_t data;
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
 
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
+
   *r_pubkey = NULL;
   err = start_agent (ctrl, 0);
   if (err)
     return err;
+  dfltparm.ctx = agent_ctx;
 
   err = assuan_transact (agent_ctx, "RESET",
                          NULL, NULL, NULL, NULL, NULL, NULL);
@@ -1476,8 +1590,7 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
     return err;
 
   init_membuf (&data, 1024);
-  gk_parm.ctrl     = ctrl;
-  gk_parm.ctx      = agent_ctx;
+  gk_parm.dflt     = &dfltparm;
   gk_parm.keyparms = keyparms;
   snprintf (line, sizeof line, "GENKEY%s%s%s",
             no_protection? " --no-protection":"",
@@ -1521,11 +1634,16 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
 
   *r_pubkey = NULL;
   err = start_agent (ctrl, 0);
   if (err)
     return err;
+  dfltparm.ctx = agent_ctx;
 
   err = assuan_transact (agent_ctx, "RESET",NULL, NULL, NULL, NULL, NULL, NULL);
   if (err)
@@ -1536,7 +1654,8 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   init_membuf (&data, 1024);
   err = assuan_transact (agent_ctx, line,
                          membuf_data_cb, &data,
-                         default_inq_cb, NULL, NULL, NULL);
+                         default_inq_cb, &dfltparm,
+                         NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));
@@ -1565,17 +1684,26 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
 gpg_error_t
 agent_pksign (ctrl_t ctrl, const char *cache_nonce,
               const char *keygrip, const char *desc,
+              u32 *keyid, u32 *mainkeyid, int pubkey_algo,
               unsigned char *digest, size_t digestlen, int digestalgo,
               gcry_sexp_t *r_sigval)
 {
   gpg_error_t err;
   char line[ASSUAN_LINELENGTH];
   membuf_t data;
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
+  dfltparm.keyinfo.keyid       = keyid;
+  dfltparm.keyinfo.mainkeyid   = mainkeyid;
+  dfltparm.keyinfo.pubkey_algo = pubkey_algo;
 
   *r_sigval = NULL;
   err = start_agent (ctrl, 0);
   if (err)
     return err;
+  dfltparm.ctx = agent_ctx;
 
   if (digestlen*2 + 50 > DIM(line))
     return gpg_error (GPG_ERR_GENERAL);
@@ -1613,8 +1741,9 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce,
             cache_nonce? " -- ":"",
             cache_nonce? cache_nonce:"");
   err = assuan_transact (agent_ctx, line,
-                        membuf_data_cb, &data, default_inq_cb, ctrl,
-                        NULL, NULL);
+                         membuf_data_cb, &data,
+                         default_inq_cb, &dfltparm,
+                         NULL, NULL);
   if (err)
     xfree (get_membuf (&data, NULL));
   else
@@ -1647,11 +1776,12 @@ inq_ciphertext_cb (void *opaque, const char *line)
   if (!strncmp (line, "CIPHERTEXT", 10) && (line[10]==' '||!line[10]))
     {
       assuan_begin_confidential (parm->ctx);
-      rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen);
+      rc = assuan_send_data (parm->dflt->ctx,
+                             parm->ciphertext, parm->ciphertextlen);
       assuan_end_confidential (parm->ctx);
     }
   else
-    rc = default_inq_cb (parm->ctrl, line);
+    rc = default_inq_cb (parm->dflt, line);
 
   return rc;
 }
@@ -1660,9 +1790,12 @@ inq_ciphertext_cb (void *opaque, const char *line)
 /* Call the agent to do a decrypt operation using the key identified
    by the hex string KEYGRIP and the input data S_CIPHERTEXT.  On the
    success the decoded value is stored verbatim at R_BUF and its
-   length at R_BUF; the callers needs to release it.  */
+   length at R_BUF; the callers needs to release it.  KEYID, MAINKEYID
+   and PUBKEY_ALGO are used to construct additional promots or status
+   messages. */
 gpg_error_t
 agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
+                 u32 *keyid, u32 *mainkeyid, int pubkey_algo,
                  gcry_sexp_t s_ciphertext,
                  unsigned char **r_buf, size_t *r_buflen)
 {
@@ -1671,6 +1804,13 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
   membuf_t data;
   size_t n, len;
   char *p, *buf, *endp;
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
+  dfltparm.keyinfo.keyid       = keyid;
+  dfltparm.keyinfo.mainkeyid   = mainkeyid;
+  dfltparm.keyinfo.pubkey_algo = pubkey_algo;
 
   if (!keygrip || strlen(keygrip) != 40 || !s_ciphertext || !r_buf || !r_buflen)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -1679,6 +1819,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
   err = start_agent (ctrl, 0);
   if (err)
     return err;
+  dfltparm.ctx = agent_ctx;
 
   err = assuan_transact (agent_ctx, "RESET",
                          NULL, NULL, NULL, NULL, NULL, NULL);
@@ -1704,7 +1845,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
   {
     struct cipher_parm_s parm;
 
-    parm.ctrl = ctrl;
+    parm.dflt = &dfltparm;
     parm.ctx = agent_ctx;
     err = make_canon_sexp (s_ciphertext, &parm.ciphertext, &parm.ciphertextlen);
     if (err)
@@ -1773,11 +1914,16 @@ agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen)
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
 
   *r_kek = NULL;
   err = start_agent (ctrl, 0);
   if (err)
     return err;
+  dfltparm.ctx = agent_ctx;
 
   snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s",
             forexport? "--export":"--import");
@@ -1785,7 +1931,8 @@ agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen)
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
                          membuf_data_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         default_inq_cb, &dfltparm,
+                         NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));
@@ -1810,10 +1957,10 @@ inq_import_key_parms (void *opaque, const char *line)
 
   if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7]))
     {
-      err = assuan_send_data (parm->ctx, parm->key, parm->keylen);
+      err = assuan_send_data (parm->dflt->ctx, parm->key, parm->keylen);
     }
   else
-    err = default_inq_cb (parm->ctrl, line);
+    err = default_inq_cb (parm->dflt, line);
 
   return err;
 }
@@ -1828,10 +1975,15 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
   struct import_key_parm_s parm;
   struct cache_nonce_parm_s cn_parm;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
 
   err = start_agent (ctrl, 0);
   if (err)
     return err;
+  dfltparm.ctx = agent_ctx;
 
   if (desc)
     {
@@ -1843,8 +1995,7 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
         return err;
     }
 
-  parm.ctrl   = ctrl;
-  parm.ctx    = agent_ctx;
+  parm.dflt   = &dfltparm;
   parm.key    = key;
   parm.keylen = keylen;
 
@@ -1854,7 +2005,8 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
   cn_parm.cache_nonce_addr = cache_nonce_addr;
   cn_parm.passwd_nonce_addr = NULL;
   err = assuan_transact (agent_ctx, line,
-                         NULL, NULL, inq_import_key_parms, &parm,
+                         NULL, NULL,
+                         inq_import_key_parms, &parm,
                          cache_nonce_status_cb, &cn_parm);
   return err;
 }
@@ -1876,12 +2028,17 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
 
   *r_result = NULL;
 
   err = start_agent (ctrl, 0);
   if (err)
     return err;
+  dfltparm.ctx = agent_ctx;
 
   if (desc)
     {
@@ -1902,7 +2059,7 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   cn_parm.passwd_nonce_addr = NULL;
   err = assuan_transact (agent_ctx, line,
                          membuf_data_cb, &data,
-                         default_inq_cb, ctrl,
+                         default_inq_cb, &dfltparm,
                          cache_nonce_status_cb, &cn_parm);
   if (err)
     {
@@ -1932,14 +2089,20 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   gpg_error_t err;
   struct cache_nonce_parm_s cn_parm;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
 
   err = start_agent (ctrl, 0);
   if (err)
     return err;
+  dfltparm.ctx = agent_ctx;
 
   if (!hexkeygrip || strlen (hexkeygrip) != 40)
     return gpg_error (GPG_ERR_INV_VALUE);
 
+
   if (desc)
     {
       snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
@@ -1958,7 +2121,7 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
   cn_parm.cache_nonce_addr = cache_nonce_addr;
   cn_parm.passwd_nonce_addr = passwd_nonce_addr;
   err = assuan_transact (agent_ctx, line, NULL, NULL,
-                         default_inq_cb, ctrl,
+                         default_inq_cb, &dfltparm,
                          cache_nonce_status_cb, &cn_parm);
   return err;
 }
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 43de14f..de05d7a 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -155,12 +155,14 @@ gpg_error_t agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
 /* Create a signature.  */
 gpg_error_t agent_pksign (ctrl_t ctrl, const char *cache_nonce,
                           const char *hexkeygrip, const char *desc,
+                          u32 *keyid, u32 *mainkeyid, int pubkey_algo,
                           unsigned char *digest, size_t digestlen,
                           int digestalgo,
                           gcry_sexp_t *r_sigval);
 
 /* Decrypt a ciphertext.  */
 gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
+                             u32 *keyid, u32 *mainkeyid, int pubkey_algo,
                              gcry_sexp_t s_ciphertext,
                              unsigned char **r_buf, size_t *r_buflen);
 
diff --git a/g10/gpg.c b/g10/gpg.c
index b614a94..9adc21a 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -56,6 +56,7 @@
 #include "asshelp.h"
 #include "call-dirmngr.h"
 #include "../common/init.h"
+#include "../common/shareddefs.h"
 
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
 #define MY_O_BINARY  O_BINARY
@@ -217,6 +218,7 @@ enum cmd_and_opt_values
     oPassphraseFD,
     oPassphraseFile,
     oPassphraseRepeat,
+    oPinentryMode,
     oCommandFD,
     oCommandFile,
     oQuickRandom,
@@ -611,6 +613,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_i (oPassphraseFD,    "passphrase-fd", "@"),
   ARGPARSE_s_s (oPassphraseFile,  "passphrase-file", "@"),
   ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
+  ARGPARSE_s_s (oPinentryMode,    "pinentry-mode", "@"),
   ARGPARSE_s_i (oCommandFD, "command-fd", "@"),
   ARGPARSE_s_s (oCommandFile, "command-file", "@"),
   ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
@@ -2593,7 +2596,16 @@ main (int argc, char **argv)
 	  case oPassphraseFile:
             pwfd = open_info_file (pargs.r.ret_str, 0, 1);
             break;
-	  case oPassphraseRepeat: opt.passphrase_repeat=pargs.r.ret_int; break;
+	  case oPassphraseRepeat:
+            opt.passphrase_repeat = pargs.r.ret_int;
+            break;
+
+          case oPinentryMode:
+	    opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str);
+	    if (opt.pinentry_mode == -1)
+              log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
+	    break;
+
 	  case oCommandFD:
             opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
             break;
diff --git a/g10/keydb.h b/g10/keydb.h
index 22c2b67..fd80c25 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -181,6 +181,7 @@ unsigned char encode_s2k_iterations (int iterations);
 assuan_context_t agent_open (int try, const char *orig_codeset);
 void agent_close (assuan_context_t ctx);
 int  have_static_passphrase(void);
+const char *get_static_passphrase (void);
 void set_passphrase_from_string(const char *pass);
 void read_passphrase_from_fd( int fd );
 void passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo );
@@ -196,6 +197,8 @@ void set_next_passphrase( const char *s );
 char *get_last_passphrase(void);
 void next_to_last_passphrase(void);
 
+void emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo);
+
 char *gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped);
 
 
diff --git a/g10/options.h b/g10/options.h
index e67d0ce..223b115 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -242,6 +242,7 @@ struct
   } *auto_key_locate;
 
   int passphrase_repeat;
+  int pinentry_mode;
 } opt;
 
 /* CTRL is used to keep some global variables we currently can't
diff --git a/g10/passphrase.c b/g10/passphrase.c
index cc56555..d872e36 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -43,7 +43,7 @@
 #include "i18n.h"
 #include "status.h"
 #include "call-agent.h"
-
+#include "../common/shareddefs.h"
 
 static char *fd_passwd = NULL;
 static char *next_pw = NULL;
@@ -104,9 +104,21 @@ encode_s2k_iterations (int iterations)
 int
 have_static_passphrase()
 {
-  return !!fd_passwd && opt.batch;
+  return (!!fd_passwd
+          && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK));
+}
+
+/* Return a static passphrase.  The returned value is only valid as
+   long as no other passphrase related function is called.  NULL may
+   be returned if no passphrase has been set; better use
+   have_static_passphrase first.  */
+const char *
+get_static_passphrase (void)
+{
+  return fd_passwd;
 }
 
+
 /****************
  * Set the passphrase to be used for the next query and only for the next
  * one.
@@ -156,7 +168,7 @@ read_passphrase_from_fd( int fd )
   int i, len;
   char *pw;
 
-  if ( !opt.batch )
+  if ( !opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK)
     { /* Not used but we have to do a dummy read, so that it won't end
          up at the begin of the message if the quite usual trick to
          prepend the passphtrase to the message is used. */
@@ -187,7 +199,7 @@ read_passphrase_from_fd( int fd )
         break;
     }
   pw[i] = 0;
-  if (!opt.batch)
+  if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK)
     tty_printf("\b\b\b   \n" );
 
   xfree ( fd_passwd );
@@ -458,30 +470,9 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
 
       if ( keyid )
         {
-          u32 used_kid[2];
-          char *us;
-
-          if ( keyid[2] && keyid[3] )
-            {
-              used_kid[0] = keyid[2];
-              used_kid[1] = keyid[3];
-            }
-          else
-            {
-              used_kid[0] = keyid[0];
-              used_kid[1] = keyid[1];
-            }
-
-          us = get_long_user_id_string ( keyid );
-          write_status_text ( STATUS_USERID_HINT, us );
-          xfree(us);
-
-          snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0",
-                    (ulong)keyid[0], (ulong)keyid[1],
-                    (ulong)used_kid[0], (ulong)used_kid[1],
-                    pubkey_algo );
-
-          write_status_text ( STATUS_NEED_PASSPHRASE, buf );
+          emit_status_need_passphrase (keyid,
+                                       keyid[2] && keyid[3]? keyid+2:NULL,
+                                       pubkey_algo);
 	}
       else
         {
@@ -614,6 +605,29 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo,
 }
 
 
+/* Emit the USERID_HINT and the NEED_PASSPHRASE status messages.
+   MAINKEYID may be NULL. */
+void
+emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo)
+{
+  char buf[50];
+  char *us;
+
+  us = get_long_user_id_string (keyid);
+  write_status_text (STATUS_USERID_HINT, us);
+  xfree (us);
+
+  snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0",
+            (ulong)keyid[0],
+            (ulong)keyid[1],
+            (ulong)(mainkeyid? mainkeyid[0]:keyid[0]),
+            (ulong)(mainkeyid? mainkeyid[1]:keyid[1]),
+            pubkey_algo);
+
+  write_status_text (STATUS_NEED_PASSPHRASE, buf);
+}
+
+
 /* Return an allocated utf-8 string describing the key PK.  If ESCAPED
    is true spaces and control characters are percent or plus escaped.
    MODE 0 is for the common prompt, MODE 1 for the import prompt. */
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 254e810..a98a723 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -193,7 +193,9 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
 
   /* Decrypt. */
   desc = gpg_format_keydesc (sk, 0, 1);
-  err = agent_pkdecrypt (NULL, keygrip, desc, s_data, &frame, &nframe);
+  err = agent_pkdecrypt (NULL, keygrip,
+                         desc, sk->keyid, sk->main_keyid, sk->pubkey_algo,
+                         s_data, &frame, &nframe);
   xfree (desc);
   gcry_sexp_release (s_data);
   if (err)
diff --git a/g10/sign.c b/g10/sign.c
index 501f1ff..8944067 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -272,6 +272,7 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig,
 
       desc = gpg_format_keydesc (pksk, 0, 1);
       err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc,
+                          pksk->keyid, pksk->main_keyid, pksk->pubkey_algo,
                           dp, gcry_md_get_algo_dlen (mdalgo), mdalgo,
                           &s_sigval);
       xfree (desc);

commit 84de484bc3eaeeba755412918b01bc8444a532ee
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Feb 7 20:18:31 2013 +0100

    doc: Fix description for NEED_PASSPHRASE status.
    
    --

diff --git a/doc/DETAILS b/doc/DETAILS
index 6d30efe..a52979f 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -664,7 +664,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
 *** USERID_HINT <long main keyid> <string>
     Give a hint about the user ID for a certain keyID.
 
-*** NEED_PASSPHRASE <long main keyid> <long keyid> <keytype> <keylength>
+*** NEED_PASSPHRASE <long keyid> <long main keyid> <keytype> <keylength>
     Issued whenever a passphrase is needed.  KEYTYPE is the numerical
     value of the public key algorithm or 0 if this is not applicable,
     KEYLENGTH is the length of the key or 0 if it is not known (this

commit 8b2b8dfe5c4cd346bbea2c228e75737bbeeca4c4
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Feb 6 12:49:52 2013 +0100

    agent: Move a typedef to common and provide parse_pinentry_mode.
    
    * common/agent-opt.c: New.
    * common/shareddefs.h: New.
    * common/Makefile.am: Add new files.
    * agent/agent.h: Include shareddefs.h.
    (pinentry_mode_t): Factor out to shareddefs.h.
    * agent/command.c (option_handler): Use parse_pinentry_mode.

diff --git a/agent/agent.h b/agent/agent.h
index 45bc507..8b1cae9 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -34,6 +34,7 @@
 #include "../common/membuf.h"
 #include "../common/sysutils.h" /* (gnupg_fd_t) */
 #include "../common/session-env.h"
+#include "../common/shareddefs.h"
 
 /* To convey some special hash algorithms we use algorithm numbers
    reserved for application use. */
@@ -46,16 +47,6 @@
 #define MAX_DIGEST_LEN 64
 
 
-/* Values for the pinentry mode.  */
-typedef enum
-  {
-    PINENTRY_MODE_ASK = 0, /* Ask via pinentry (default).  */
-    PINENTRY_MODE_CANCEL,  /* Always return a cancel error.  */
-    PINENTRY_MODE_ERROR,   /* Return error code for no pinentry.  */
-    PINENTRY_MODE_LOOPBACK,/* Use an inquiry to get the value.    */
-  }
-pinentry_mode_t;
-
 
 /* A large struct name "opt" to keep global flags */
 struct
diff --git a/agent/command.c b/agent/command.c
index 3ba921b..715e70a 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -2548,21 +2548,13 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
     ctrl->server_local->allow_pinentry_notify = 1;
   else if (!strcmp (key, "pinentry-mode"))
     {
-      if (!strcmp (value, "ask") || !strcmp (value, "default"))
-        ctrl->pinentry_mode = PINENTRY_MODE_ASK;
-      else if (!strcmp (value, "cancel"))
-        ctrl->pinentry_mode = PINENTRY_MODE_CANCEL;
-      else if (!strcmp (value, "error"))
-        ctrl->pinentry_mode = PINENTRY_MODE_ERROR;
-      else if (!strcmp (value, "loopback"))
-        {
-          if (opt.allow_loopback_pinentry)
-            ctrl->pinentry_mode = PINENTRY_MODE_LOOPBACK;
-          else
-            err = gpg_error (GPG_ERR_NOT_SUPPORTED);
-        }
-      else
+      int tmp = parse_pinentry_mode (value);
+      if (tmp == -1)
         err = gpg_error (GPG_ERR_INV_VALUE);
+      else if (tmp == PINENTRY_MODE_LOOPBACK && !opt.allow_loopback_pinentry)
+        err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      else
+        ctrl->pinentry_mode = tmp;
     }
   else if (!strcmp (key, "cache-ttl-opt-preset"))
     {
diff --git a/common/Makefile.am b/common/Makefile.am
index e0f4b80..ff8fee3 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -59,6 +59,7 @@ common_sources = \
 	util.h i18n.c i18n.h \
 	estream.c estream.h estream-printf.c estream-printf.h \
 	status.c status.h\
+	shareddefs.h \
 	openpgpdefs.h \
 	gc-opt-flags.h \
 	keyserver.h \
@@ -92,6 +93,7 @@ common_sources = \
 	userids.c userids.h \
 	openpgp-oid.c \
 	ssh-utils.c ssh-utils.h \
+	agent-opt.c \
 	helpfile.c
 
 # To make the code easier to read we have split home some code into
diff --git a/common/agent-opt.c b/common/agent-opt.c
new file mode 100644
index 0000000..4317ba3
--- /dev/null
+++ b/common/agent-opt.c
@@ -0,0 +1,71 @@
+/* agent-opt.c - Helper for certain agent options
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "shareddefs.h"
+
+
+/* Parse VALUE and return an integer representing a pinentry_mode_t.
+   (-1) is returned for an invalid VALUE.  */
+int
+parse_pinentry_mode (const char *value)
+{
+  int result;
+
+  if (!strcmp (value, "ask") || !strcmp (value, "default"))
+    result = PINENTRY_MODE_ASK;
+  else if (!strcmp (value, "cancel"))
+    result = PINENTRY_MODE_CANCEL;
+  else if (!strcmp (value, "error"))
+    result = PINENTRY_MODE_ERROR;
+  else if (!strcmp (value, "loopback"))
+    result = PINENTRY_MODE_LOOPBACK;
+  else
+    result = -1;
+
+  return result;
+}
+
+/* Return the string representation for the pinentry MODE.  Returns
+   "?" for an invalid mode.  */
+const char *
+str_pinentry_mode (pinentry_mode_t mode)
+{
+  switch (mode)
+    {
+    case PINENTRY_MODE_ASK:      return "ask";
+    case PINENTRY_MODE_CANCEL:   return "cancel";
+    case PINENTRY_MODE_ERROR:    return "error";
+    case PINENTRY_MODE_LOOPBACK: return "loopback";
+    }
+ return "?";
+}
diff --git a/common/shareddefs.h b/common/shareddefs.h
new file mode 100644
index 0000000..604b7e9
--- /dev/null
+++ b/common/shareddefs.h
@@ -0,0 +1,48 @@
+/* shareddefs.h - Constants and helpers useful for all modules
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SHAREDDEFS_H
+#define GNUPG_COMMON_SHAREDDEFS_H
+
+/* Values for the pinentry mode.  */
+typedef enum
+  {
+    PINENTRY_MODE_ASK = 0, /* Ask via pinentry (default).  */
+    PINENTRY_MODE_CANCEL,  /* Always return a cancel error.  */
+    PINENTRY_MODE_ERROR,   /* Return error code for no pinentry.  */
+    PINENTRY_MODE_LOOPBACK /* Use an inquiry to get the value.    */
+  }
+pinentry_mode_t;
+
+
+/*-- agent-opt.c --*/
+int parse_pinentry_mode (const char *value);
+const char *str_pinentry_mode (pinentry_mode_t mode);
+
+
+
+#endif /*GNUPG_COMMON_SHAREDDEFS_H*/

commit 4483a4f0ea030046137ba04905eb5220c14a2161
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Feb 6 12:42:07 2013 +0100

    agent: Return a better error code if no passphrase was given.
    
    * agent/protect.c (hash_passphrase): Handle an empty passphrase.
    --
    
    This is mostly useful in loopback pinentry-mode.

diff --git a/agent/protect.c b/agent/protect.c
index d26573d..3e2cbb9 100644
--- a/agent/protect.c
+++ b/agent/protect.c
@@ -1075,7 +1075,11 @@ hash_passphrase (const char *passphrase, int hashalgo,
                  unsigned long s2kcount,
                  unsigned char *key, size_t keylen)
 {
-
+  /* The key derive function does not support a zero length string for
+     the passphrase in the S2K modes.  Return a better suited error
+     code than GPG_ERR_INV_DATA.  */
+  if (!passphrase || !*passphrase)
+    return gpg_error (GPG_ERR_NO_PASSPHRASE);
   return gcry_kdf_derive (passphrase, strlen (passphrase),
                           s2kmode == 3? GCRY_KDF_ITERSALTED_S2K :
                           s2kmode == 1? GCRY_KDF_SALTED_S2K :

-----------------------------------------------------------------------

Summary of changes:
 NEWS                           |    2 +
 agent/agent.h                  |   11 +--
 agent/command.c                |   20 +--
 agent/protect.c                |    6 +-
 common/Makefile.am             |    2 +
 common/agent-opt.c             |   71 +++++++++++
 common/{srv.h => shareddefs.h} |   45 +++----
 doc/DETAILS                    |    2 +-
 doc/gpg.texi                   |   20 +++
 g10/call-agent.c               |  265 ++++++++++++++++++++++++++++++++--------
 g10/call-agent.h               |    2 +
 g10/gpg.c                      |   14 ++-
 g10/keydb.h                    |    3 +
 g10/options.h                  |    1 +
 g10/passphrase.c               |   70 +++++++----
 g10/pubkey-enc.c               |    4 +-
 g10/sign.c                     |    1 +
 17 files changed, 404 insertions(+), 135 deletions(-)
 create mode 100644 common/agent-opt.c
 copy common/{srv.h => shareddefs.h} (57%)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list