Fix bug #1053
authorWerner Koch <wk@gnupg.org>
Fri, 15 May 2009 11:16:28 +0000 (11:16 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 15 May 2009 11:16:28 +0000 (11:16 +0000)
Add option --qualitybar to command GET_PASSPHRASE.

agent/ChangeLog
agent/agent.h
agent/cache.c
agent/call-pinentry.c
agent/command-ssh.c
agent/command.c
agent/findkey.c
agent/pkdecrypt.c
agent/pksign.c

index 7c948e4..9a07219 100644 (file)
@@ -1,3 +1,22 @@
+2009-05-15  Werner Koch  <wk@g10code.com>
+
+       Fix bug #1053.
+       
+       * agent.h (lookup_ttl_t): New.
+       * findkey.c (unprotect): Add arg LOOKUP_TTL.
+       (agent_key_from_file): Ditto.
+       * pksign.c (agent_pksign_do): Ditto.
+       * command-ssh.c (ttl_from_sshcontrol): New.
+       (data_sign): Pass new function to agent_pksign_do.
+       (search_control_file): Add new arg R_TTL.
+
+2009-05-14  Werner Koch  <wk@g10code.com>
+
+       * command.c (cmd_get_passphrase): Add option --qualitybar.
+       * call-pinentry.c (agent_askpin): Factor some code out to ...
+       (setup_qualitybar): .. new.
+       (agent_get_passphrase): Add arg WITH_QUALITYBAR and implement it.
+
 2009-04-14  Marcus Brinkmann  <marcus@g10code.de>
 
        * call-pinentry.c (agent_get_confirmation): Try SETNOTOK command
index ba31d93..e37485f 100644 (file)
@@ -201,6 +201,10 @@ typedef enum
 cache_mode_t;
 
 
+/* The type of a function to lookup a TTL by a keygrip.  */
+typedef int (*lookup_ttl_t)(const char *hexgrip);
+
+
 /*-- gpg-agent.c --*/
 void agent_exit (int rc) JNLIB_GCC_A_NR; /* Also implemented in other tools */
 const char *get_agent_socket_name (void);
@@ -229,6 +233,7 @@ gpg_error_t agent_key_from_file (ctrl_t ctrl,
                                  const unsigned char *grip,
                                  unsigned char **shadow_info,
                                  cache_mode_t cache_mode,
+                                 lookup_ttl_t lookup_ttl,
                                  gcry_sexp_t *result);
 gpg_error_t agent_public_key_from_file (ctrl_t ctrl, 
                                         const unsigned char *grip,
@@ -249,7 +254,7 @@ int agent_askpin (ctrl_t ctrl,
                   struct pin_entry_info_s *pininfo);
 int agent_get_passphrase (ctrl_t ctrl, char **retpass,
                           const char *desc, const char *prompt,
-                          const char *errtext);
+                          const char *errtext, int with_qualitybar);
 int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok,
                            const char *cancel);
 int agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn);
@@ -270,7 +275,7 @@ void agent_unlock_cache_entry (void **cache_id);
 /*-- pksign.c --*/
 int agent_pksign_do (ctrl_t ctrl, const char *desc_text,
                     gcry_sexp_t *signature_sexp,
-                     cache_mode_t cache_mode);
+                     cache_mode_t cache_mode, lookup_ttl_t lookup_ttl);
 int agent_pksign (ctrl_t ctrl, const char *desc_text,
                   membuf_t *outbuf, cache_mode_t cache_mode);
 
index addd1e8..10f9ef6 100644 (file)
@@ -194,8 +194,8 @@ agent_flush_cache (void)
    with a maximum lifetime of TTL seconds.  If there is already data
    under this key, it will be replaced.  Using a DATA of NULL deletes
    the entry.  A TTL of 0 is replaced by the default TTL and a TTL of
-   -1 set infinite timeout. CACHE_MODE is stored with the cache entry
-   and used t select different timeouts. */
+   -1 set infinite timeout.  CACHE_MODE is stored with the cache entry
+   and used to select different timeouts.  */
 int
 agent_put_cache (const char *key, cache_mode_t cache_mode,
                  const char *data, int ttl)
index 38561e3..41fe6f4 100644 (file)
@@ -570,6 +570,59 @@ inq_quality (void *opaque, const char *line)
 }
 
 
+/* Helper for agent_askpin and agent_get_passphrase.  */
+static int
+setup_qualitybar (void)
+{
+  int rc;
+  char line[ASSUAN_LINELENGTH];
+  char *tmpstr, *tmpstr2;
+  const char *tooltip;
+  
+  /* TRANSLATORS: This string is displayed by Pinentry as the label
+     for the quality bar.  */
+  tmpstr = try_percent_escape (_("Quality:"), "\t\r\n\f\v");
+  snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
+  line[DIM(line)-1] = 0;
+  xfree (tmpstr);
+  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+  if (rc == 103 /*(Old assuan error code)*/
+      || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
+    ; /* Ignore Unknown Command from old Pinentry versions.  */
+  else if (rc)
+    return rc;
+  
+  tmpstr2 = gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
+  if (tmpstr2)
+    tooltip = tmpstr2;
+  else
+    {
+      /* TRANSLATORS: This string is a tooltip, shown by pinentry when
+         hovering over the quality bar.  Please use an appropriate
+         string to describe what this is about.  The length of the
+         tooltip is limited to about 900 characters.  If you do not
+         translate this entry, a default english text (see source)
+         will be used. */
+      tooltip =  _("pinentry.qualitybar.tooltip");
+      if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
+        tooltip = ("The quality of the text entered above.\n"
+                   "Please ask your administrator for "
+                   "details about the criteria.");
+    }
+  tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
+  xfree (tmpstr2);
+  snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
+  line[DIM(line)-1] = 0;
+  xfree (tmpstr);
+  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+  if (rc == 103 /*(Old assuan error code)*/
+          || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
+    ; /* Ignore Unknown Command from old pinentry versions.  */
+  else if (rc)
+    return rc;
+
+  return 0;
+}
 
 
 \f
@@ -627,51 +680,8 @@ agent_askpin (ctrl_t ctrl,
      to the pinentry.  */
   if (pininfo->with_qualitybar && opt.min_passphrase_len )
     {
-      char *tmpstr, *tmpstr2;
-      const char *tooltip;
-
-      /* TRANSLATORS: This string is displayed by pinentry as the
-         label for the quality bar.  */
-      tmpstr = try_percent_escape (_("Quality:"), "\t\r\n\f\v");
-      snprintf (line, DIM(line)-1, "SETQUALITYBAR %s", tmpstr? tmpstr:"");
-      line[DIM(line)-1] = 0;
-      xfree (tmpstr);
-      rc = assuan_transact (entry_ctx, line,
-                            NULL, NULL, NULL, NULL, NULL, NULL);
-      if (rc == 103 /*(Old assuan error code)*/
-          || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
-        ; /* Ignore Unknown Command from old pinentry versions.  */
-      else if (rc)
-        return unlock_pinentry (rc);
-
-      tmpstr2 = gnupg_get_help_string ("pinentry.qualitybar.tooltip", 0);
-      if (tmpstr2)
-        tooltip = tmpstr2;
-      else
-        {
-          /* TRANSLATORS: This string is a tooltip, shown by pinentry
-             when hovering over the quality bar.  Please use an
-             appropriate string to describe what this is about.  The
-             length of the tooltip is limited to about 900 characters.
-             If you do not translate this entry, a default english
-             text (see source) will be used. */
-          tooltip =  _("pinentry.qualitybar.tooltip");
-          if (!strcmp ("pinentry.qualitybar.tooltip", tooltip))
-            tooltip = ("The quality of the text entered above.\n"
-                       "Please ask your administrator for "
-                       "details about the criteria.");
-        }
-      tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
-      xfree (tmpstr2);
-      snprintf (line, DIM(line)-1, "SETQUALITYBAR_TT %s", tmpstr? tmpstr:"");
-      line[DIM(line)-1] = 0;
-      xfree (tmpstr);
-      rc = assuan_transact (entry_ctx, line,
-                            NULL, NULL, NULL, NULL, NULL, NULL);
-      if (rc == 103 /*(Old assuan error code)*/
-          || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
-        ; /* Ignore Unknown Command from old pinentry versions.  */
-      else if (rc)
+      rc = setup_qualitybar ();
+      if (rc)
         return unlock_pinentry (rc);
     }
 
@@ -764,7 +774,7 @@ agent_askpin (ctrl_t ctrl,
 int 
 agent_get_passphrase (ctrl_t ctrl,
                       char **retpass, const char *desc, const char *prompt,
-                      const char *errtext)
+                      const char *errtext, int with_qualitybar)
 {
 
   int rc;
@@ -798,6 +808,13 @@ agent_get_passphrase (ctrl_t ctrl,
   if (rc)
     return unlock_pinentry (rc);
 
+  if (with_qualitybar && opt.min_passphrase_len)
+    {
+      rc = setup_qualitybar ();
+      if (rc)
+        return unlock_pinentry (rc);
+    }
+
   if (errtext)
     {
       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
@@ -815,7 +832,7 @@ agent_get_passphrase (ctrl_t ctrl,
 
   assuan_begin_confidential (entry_ctx);
   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
-                        NULL, NULL, NULL, NULL);
+                        inq_quality, entry_ctx, NULL, NULL);
   /* Most pinentries out in the wild return the old Assuan error code
      for canceled which gets translated to an assuan Cancel error and
      not to the code for a user cancel.  Fix this here. */
index c262cad..76f310a 100644 (file)
@@ -1,5 +1,5 @@
 /* command-ssh.c - gpg-agent's ssh-agent emulation layer
- * Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2005, 2006, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -710,17 +710,20 @@ open_control_file (FILE **r_fp, int append)
 
 /* Search the file at stream FP from the beginning until a matching
    HEXGRIP is found; return success in this case and store true at
-   DISABLED if the found key has been disabled.  */
+   DISABLED if the found key has been disabled.  If R_TTL is not NULL
+   a specified TTL for that key is stored there. */
 static gpg_error_t
-search_control_file (FILE *fp, const char *hexgrip, int *disabled)
+search_control_file (FILE *fp, const char *hexgrip, 
+                     int *r_disabled, int *r_ttl)
 {
   int c, i;
-  char *p, line[256];
-  
+  char *p, *pend, line[256];
+  long ttl;
+
   assert (strlen (hexgrip) == 40 );
 
   rewind (fp);
-  *disabled = 0;
+  *r_disabled = 0;
  next_line:
   do
     {
@@ -746,10 +749,10 @@ search_control_file (FILE *fp, const char *hexgrip, int *disabled)
     }
   while (!*p || *p == '\n' || *p == '#');
   
-  *disabled = 0;
+  *r_disabled = 0;
   if (*p == '!')
     {
-      *disabled = 1;
+      *r_disabled = 1;
       for (p++; spacep (p); p++)
         ;
     }
@@ -763,7 +766,17 @@ search_control_file (FILE *fp, const char *hexgrip, int *disabled)
       return gpg_error (GPG_ERR_BAD_DATA);
     }
 
-  /* Fixme: Get TTL and flags.  */
+  ttl = strtol (p, &pend, 10);
+  p = pend;
+  if (!(spacep (p) || *p == '\n') || ttl < -1)
+    {
+      log_error ("invalid TTL value in ssh control file; assuming 0\n");
+      ttl = 0;
+    }
+  if (r_ttl)
+    *r_ttl = ttl;
+
+  /* Here is the place to parse flags if we need them.  */  
 
   return 0; /* Okay:  found it.  */
 }
@@ -788,7 +801,7 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
   if (err)
     return err;
 
-  err = search_control_file (fp, hexgrip, &disabled);
+  err = search_control_file (fp, hexgrip, &disabled, NULL);
   if (err && gpg_err_code(err) == GPG_ERR_EOF)
     {
       struct tm *tp;
@@ -808,6 +821,29 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
 }
 
 
+/* Scan the sshcontrol file and return the TTL.  */
+static int
+ttl_from_sshcontrol (const char *hexgrip)
+{
+  FILE *fp;
+  int disabled, ttl;
+
+  if (!hexgrip || strlen (hexgrip) != 40)
+    return 0;  /* Wrong input: Use global default.  */
+
+  if (open_control_file (&fp, 0))
+    return 0; /* Error: Use the global default TTL.  */
+
+  if (search_control_file (fp, hexgrip, &disabled, &ttl)
+      || disabled)
+    ttl = 0;  /* Use the global default if not found or disabled.  */
+
+  fclose (fp); 
+
+  return ttl;
+}
+
+
 
 \f
 
@@ -1875,7 +1911,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
           hexgrip[40] = 0;
           if ( strlen (hexgrip) != 40 )
             continue;
-          if (search_control_file (ctrl_fp, hexgrip, &disabled)
+          if (search_control_file (ctrl_fp, hexgrip, &disabled, NULL)
               || disabled)
             continue;
 
@@ -1972,6 +2008,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
   return ret_err;
 }
 
+
 /* This function hashes the data contained in DATA of size DATA_N
    according to the message digest algorithm specified by MD_ALGORITHM
    and writes the message digest to HASH, which needs to large enough
@@ -2017,7 +2054,7 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder,
   err = agent_pksign_do (ctrl,
                          _("Please enter the passphrase "
                            "for the ssh key%0A  %c"), &signature_sexp,
-                         CACHE_MODE_SSH);
+                         CACHE_MODE_SSH, ttl_from_sshcontrol);
   ctrl->use_auth_call = 0;
   if (err)
     goto out;
index 728b160..01f3ae2 100644 (file)
@@ -986,7 +986,8 @@ send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
 }
 
 
-/* GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]] <cache_id>
+/* GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]] 
+                  [--qualitybar] <cache_id>
                   [<error_message> <prompt> <description>]
 
    This function is usually used to ask for a passphrase to be used
@@ -1007,6 +1008,10 @@ send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
    If the option "--no-ask" is used and the passphrase is not in the
    cache the user will not be asked to enter a passphrase but the error
    code GPG_ERR_NO_DATA is returned.  
+
+   If the option "--qualitybar" is used a visual indication of the
+   entered passphrase quality is shown.  (Unless no minimum passphrase
+   length has been configured.)
 */
 
 static int
@@ -1020,7 +1025,8 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
   const char *desc2 = _("Please re-enter this passphrase");
   char *p;
   void *cache_marker;
-  int opt_data, opt_check, opt_no_ask, opt_repeat = 0;
+  int opt_data, opt_check, opt_no_ask, opt_qualbar;
+  int opt_repeat = 0;
   char *repeat_errtext = NULL;
 
   opt_data = has_option (line, "--data");
@@ -1034,6 +1040,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
       else
        opt_repeat = 1;
     }
+  opt_qualbar = has_option (line, "--qualitybar");
   line = skip_options (line);
 
   cacheid = line;
@@ -1102,7 +1109,8 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
 
     next_try:
       rc = agent_get_passphrase (ctrl, &response, desc, prompt, 
-                                 repeat_errtext? repeat_errtext:errtext);
+                                 repeat_errtext? repeat_errtext:errtext, 
+                                 opt_qualbar);
       xfree (repeat_errtext);
       repeat_errtext = NULL;
       if (!rc)
@@ -1119,7 +1127,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
               char *response2;
 
               rc = agent_get_passphrase (ctrl, &response2, desc2, prompt,
-                                         errtext);
+                                         errtext, 0);
               if (rc)
                 break;
               if (strcmp (response2, response))
@@ -1265,7 +1273,8 @@ cmd_passwd (assuan_context_t ctx, char *line)
 
   ctrl->in_passwd++;
   rc = agent_key_from_file (ctrl, ctrl->server_local->keydesc,
-                            grip, &shadow_info, CACHE_MODE_IGNORE, &s_skey);
+                            grip, &shadow_info, CACHE_MODE_IGNORE, NULL, 
+                            &s_skey);
   if (rc)
     ;
   else if (!s_skey)
index 867e196..5fe7352 100644 (file)
@@ -297,11 +297,12 @@ modify_description (const char *in, const char *comment, char **result)
 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
    should be the hex encoded keygrip of that key to be used with the
    caching mechanism. DESC_TEXT may be set to override the default
-   description used for the pinentry. */
+   description used for the pinentry.  If LOOKUP_TTL is given this
+   function is used to lookup the default ttl. */
 static int
 unprotect (ctrl_t ctrl, const char *desc_text,
            unsigned char **keybuf, const unsigned char *grip, 
-           cache_mode_t cache_mode)
+           cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
 {
   struct pin_entry_info_s *pi;
   struct try_unprotect_arg_s arg;
@@ -406,7 +407,8 @@ unprotect (ctrl_t ctrl, const char *desc_text,
               return rc;
             }
         }
-      agent_put_cache (hexgrip, cache_mode, pi->pin, 0);
+      agent_put_cache (hexgrip, cache_mode, pi->pin, 
+                       lookup_ttl? lookup_ttl (hexgrip) : 0);
       xfree (*keybuf);
       *keybuf = arg.unprotected_key;
     }
@@ -488,11 +490,16 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
    to a token; in this case an allocated S-expression with the
    shadow_info part from the file is stored at SHADOW_INFO.
    CACHE_MODE defines now the cache shall be used.  DESC_TEXT may be
-   set to present a custom description for the pinentry.  */
+   set to present a custom description for the pinentry.  LOOKUP_TTL
+   is an optional function to convey a TTL to the cache manager; we do
+   not simply pass the TTL value because the value is only needed if an
+   unprotect action was needed and looking up the TTL may have some
+   overhead (e.g. scanning the sshcontrol file). */
 gpg_error_t
 agent_key_from_file (ctrl_t ctrl, const char *desc_text,
                      const unsigned char *grip, unsigned char **shadow_info,
-                     cache_mode_t cache_mode, gcry_sexp_t *result)
+                     cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
+                     gcry_sexp_t *result)
 {
   int rc;
   unsigned char *buf;
@@ -502,7 +509,7 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
   
   *result = NULL;
   if (shadow_info)
-      *shadow_info = NULL;
+    *shadow_info = NULL;
 
   rc = read_key_file (grip, &s_skey);
   if (rc)
@@ -563,7 +570,8 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
 
        if (!rc)
          {
-           rc = unprotect (ctrl, desc_text_final, &buf, grip, cache_mode);
+           rc = unprotect (ctrl, desc_text_final, &buf, grip,
+                            cache_mode, lookup_ttl);
            if (rc)
              log_error ("failed to unprotect the secret key: %s\n",
                         gpg_strerror (rc));
index 75e8e8f..9e1c47d 100644 (file)
@@ -66,7 +66,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
     }
   rc = agent_key_from_file (ctrl, desc_text,
                             ctrl->keygrip, &shadow_info,
-                            CACHE_MODE_NORMAL, &s_skey);
+                            CACHE_MODE_NORMAL, NULL, &s_skey);
   if (rc)
     {
       if (gpg_err_code (rc) == GPG_ERR_ENOENT)
index 926438e..25cadb2 100644 (file)
@@ -125,10 +125,12 @@ do_encode_raw_pkcs1 (const byte *md, size_t mdlen, unsigned int nbits,
 
 
 /* SIGN whatever information we have accumulated in CTRL and return
-   the signature S-Expression. */
+   the signature S-expression.  LOOKUP is an optional function to
+   provide a way for lower layers to ask for the caching TTL. */
 int
 agent_pksign_do (ctrl_t ctrl, const char *desc_text,
-                gcry_sexp_t *signature_sexp, cache_mode_t cache_mode)
+                gcry_sexp_t *signature_sexp,
+                 cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
 {
   gcry_sexp_t s_skey = NULL, s_sig = NULL;
   unsigned char *shadow_info = NULL;
@@ -138,7 +140,8 @@ agent_pksign_do (ctrl_t ctrl, const char *desc_text,
     return gpg_error (GPG_ERR_NO_SECKEY);
 
   rc = agent_key_from_file (ctrl, desc_text, ctrl->keygrip,
-                            &shadow_info, cache_mode, &s_skey);
+                            &shadow_info, cache_mode, lookup_ttl,
+                            &s_skey);
   if (rc)
     {
       log_error ("failed to read the secret key\n");
@@ -238,7 +241,7 @@ agent_pksign (ctrl_t ctrl, const char *desc_text,
   size_t len = 0;
   int rc = 0;
 
-  rc = agent_pksign_do (ctrl, desc_text, &s_sig, cache_mode);
+  rc = agent_pksign_do (ctrl, desc_text, &s_sig, cache_mode, NULL);
   if (rc)
     goto leave;