gpg: Fix informative printing of user ids.
authorWerner Koch <wk@gnupg.org>
Mon, 13 Oct 2014 12:54:26 +0000 (14:54 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 13 Oct 2014 12:54:26 +0000 (14:54 +0200)
* g10/getkey.c (keyid_list): Add field "fpr".
(cache_user_id): Store fpr and check for dups only by fpr.
(get_pubkey_byfpr): New.
(get_user_id_string): Make static and use xasprintf.
(get_long_user_id_string): Use xasprintf.
(get_user_id_byfpr): New.
(get_user_id_byfpr_native): New.
* g10/keyid.c (fingerprint_from_pk): Make arg RET_LEN optional.
* g10/import.c (import_one): Use get_user_id_byfpr_native.
--

We now cache the userids using the fingerprint.  This allows to print
the correct user id for keys with a duplicated key id.  We should
eventually start to retire the use of all the old keyid based
functions.  However, at some places we only have the keyid and thus
some of them will need to be kept (maybe changed with an indication to
show that more than several user ids are matching).

Signed-off-by: Werner Koch <wk@gnupg.org>
g10/getkey.c
g10/gpg.h
g10/import.c
g10/keydb.h
g10/keyid.c

index 707a106..4f10c18 100644 (file)
@@ -74,6 +74,7 @@ static struct
 typedef struct keyid_list
 {
   struct keyid_list *next;
+  char fpr[MAX_FINGERPRINT_LEN];
   u32 keyid[2];
 } *keyid_list_t;
 
@@ -263,6 +264,7 @@ cache_user_id (KBNODE keyblock)
          keyid_list_t a = xmalloc_clear (sizeof *a);
          /* Hmmm: For a long list of keyids it might be an advantage
           * to append the keys.  */
+          fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, NULL);
          keyid_from_pk (k->pkt->pkt.public_key, a->keyid);
          /* First check for duplicates.  */
          for (r = user_id_db; r; r = r->next)
@@ -270,8 +272,7 @@ cache_user_id (KBNODE keyblock)
              keyid_list_t b = r->keyids;
              for (b = r->keyids; b; b = b->next)
                {
-                 if (b->keyid[0] == a->keyid[0]
-                     && b->keyid[1] == a->keyid[1])
+                 if (!memcmp (b->fpr, a->fpr, MAX_FINGERPRINT_LEN))
                    {
                      if (DBG_CACHE)
                        log_debug ("cache_user_id: already in cache\n");
@@ -950,6 +951,34 @@ get_pubkey_end (GETKEY_CTX ctx)
 }
 
 
+/* Search for a key with the given standard fingerprint.  In contrast
+ * to get_pubkey_byfprint we assume a right padded fingerprint of the
+ * standard length.  PK may be NULL to only put the result into the
+ * internal caches.  */
+gpg_error_t
+get_pubkey_byfpr (PKT_public_key *pk, const byte *fpr)
+{
+  gpg_error_t err;
+  struct getkey_ctx_s ctx;
+  kbnode_t kb = NULL;
+
+  memset (&ctx, 0, sizeof ctx);
+  ctx.exact = 1;
+  ctx.not_allocated = 1;
+  ctx.kr_handle = keydb_new ();
+  ctx.nitems = 1;
+  ctx.items[0].mode = KEYDB_SEARCH_MODE_FPR;
+  memcpy (ctx.items[0].u.fpr, fpr, MAX_FINGERPRINT_LEN);
+  err = lookup (&ctx, &kb, 0);
+  if (!err && pk)
+    pk_from_block (&ctx, pk, kb);
+  release_kbnode (kb);
+  get_pubkey_end (&ctx);
+
+  return err;
+}
+
+
 /* Search for a key with the given fingerprint.
  * FIXME:
  * We should replace this with the _byname function.  This can be done
@@ -2687,11 +2716,10 @@ enum_secret_keys (void **context, PKT_public_key *sk)
 
 /* Return a string with a printable representation of the user_id.
  * this string must be freed by xfree.   */
-char *
+static char *
 get_user_id_string (u32 * keyid)
 {
   user_id_db_t r;
-  char *p;
   int pass = 0;
   /* Try it two times; second pass reads from key resources.  */
   do
@@ -2703,17 +2731,13 @@ get_user_id_string (u32 * keyid)
            {
              if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
                {
-                 p = xmalloc (keystrlen () + 1 + r->len + 1);
-                 sprintf (p, "%s %.*s", keystr (keyid), r->len, r->name);
-                 return p;
+                 return xasprintf ("%s %.*s", keystr (keyid), r->len, r->name);
                }
            }
        }
     }
   while (++pass < 2 && !get_pubkey (NULL, keyid));
-  p = xmalloc (keystrlen () + 5);
-  sprintf (p, "%s [?]", keystr (keyid));
-  return p;
+  return xasprintf ("%s [?]", keystr (keyid));
 }
 
 
@@ -2731,33 +2755,30 @@ char *
 get_long_user_id_string (u32 * keyid)
 {
   user_id_db_t r;
-  char *p;
+  keyid_list_t a;
   int pass = 0;
   /* Try it two times; second pass reads from key resources.  */
   do
     {
       for (r = user_id_db; r; r = r->next)
        {
-         keyid_list_t a;
          for (a = r->keyids; a; a = a->next)
            {
              if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
                {
-                 p = xmalloc (r->len + 20);
-                 sprintf (p, "%08lX%08lX %.*s",
-                          (ulong) keyid[0], (ulong) keyid[1],
-                          r->len, r->name);
-                 return p;
+                 return xasprintf ("%08lX%08lX %.*s",
+                                    (ulong) keyid[0], (ulong) keyid[1],
+                                    r->len, r->name);
                }
            }
        }
     }
   while (++pass < 2 && !get_pubkey (NULL, keyid));
-  p = xmalloc (25);
-  sprintf (p, "%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
-  return p;
+  return xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
 }
 
+
+/* Please try to use get_user_id_native instead of this one.  */
 char *
 get_user_id (u32 * keyid, size_t * rn)
 {
@@ -2792,6 +2813,7 @@ get_user_id (u32 * keyid, size_t * rn)
   return p;
 }
 
+/* Please try to use get_user_id_byfpr_native instead of this one.  */
 char *
 get_user_id_native (u32 * keyid)
 {
@@ -2802,6 +2824,55 @@ get_user_id_native (u32 * keyid)
   return p2;
 }
 
+
+/* Return a user id from the caching by looking it up using the FPR
+   which mustbe of size MAX_FINGERPRINT_LEN.  */
+char *
+get_user_id_byfpr (const byte *fpr, size_t *rn)
+{
+  user_id_db_t r;
+  char *p;
+  int pass = 0;
+
+  /* Try it two times; second pass reads from key resources.  */
+  do
+    {
+      for (r = user_id_db; r; r = r->next)
+       {
+         keyid_list_t a;
+         for (a = r->keyids; a; a = a->next)
+           {
+             if (!memcmp (a->fpr, fpr, MAX_FINGERPRINT_LEN))
+               {
+                  /* An empty string as user id is possible.  Make
+                     sure that the malloc allocates one byte and does
+                     not bail out.  */
+                 p = xmalloc (r->len? r->len : 1);
+                 memcpy (p, r->name, r->len);
+                 *rn = r->len;
+                 return p;
+               }
+           }
+       }
+    }
+  while (++pass < 2 && !get_pubkey_byfpr (NULL, fpr));
+  p = xstrdup (user_id_not_found_utf8 ());
+  *rn = strlen (p);
+  return p;
+}
+
+char *
+get_user_id_byfpr_native (const byte *fpr)
+{
+  size_t rn;
+  char *p = get_user_id_byfpr (fpr, &rn);
+  char *p2 = utf8_to_native (p, rn, 0);
+  xfree (p);
+  return p2;
+}
+
+
+
 KEYDB_HANDLE
 get_ctx_handle (GETKEY_CTX ctx)
 {
index 3251dd0..ce4d253 100644 (file)
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -37,7 +37,8 @@
 /* Number of bits we accept when reading or writing MPIs. */
 #define MAX_EXTERN_MPI_BITS 16384
 
-/* The maximum length of a binary fingerprints.  */
+/* The maximum length of a binary fingerprints.
+   Warning: At some places we still use 20 instead of this macro. */
 #define MAX_FINGERPRINT_LEN 20
 
 
index be2fd63..8f7595c 100644 (file)
@@ -1009,9 +1009,9 @@ import_one (ctrl_t ctrl,
        /* we are ready */
        if( !opt.quiet && !silent)
          {
-           char *p=get_user_id_native (keyid);
-           log_info_("key %s: public key \"%s\" imported\n"),
-                     keystr(keyid),p);
+           char *p = get_user_id_byfpr_native (fpr2);
+           log_info (_("key %s: public key \"%s\" imported\n"),
+                     keystr(keyid), p);
            xfree(p);
          }
        if( is_status_enabled() )
@@ -1094,7 +1094,7 @@ import_one (ctrl_t ctrl,
            /* we are ready */
            if( !opt.quiet && !silent)
              {
-               char *p=get_user_id_native(keyid);
+               char *p = get_user_id_byfpr_native (fpr2);
                if( n_uids == 1 )
                  log_info( _("key %s: \"%s\" 1 new user ID\n"),
                           keystr(keyid),p);
@@ -1145,7 +1145,7 @@ import_one (ctrl_t ctrl,
 
            if( !opt.quiet && !silent)
              {
-               char *p=get_user_id_native(keyid);
+               char *p = get_user_id_byfpr_native (fpr2);
                log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p);
                xfree(p);
              }
index 55f8fc2..c61e0ae 100644 (file)
@@ -222,6 +222,7 @@ int get_pubkey_bynames( GETKEY_CTX *rx, PKT_public_key *pk,
 int get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock );
 void get_pubkey_end( GETKEY_CTX ctx );
 gpg_error_t get_seckey (PKT_public_key *pk, u32 *keyid);
+gpg_error_t get_pubkey_byfpr (PKT_public_key *pk, const byte *fpr);
 int get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint,
                                                 size_t fprint_len );
 int get_pubkey_byfprint_fast (PKT_public_key *pk,
@@ -252,11 +253,12 @@ gpg_error_t enum_secret_keys (void **context, PKT_public_key *pk);
 
 void setup_main_keyids (kbnode_t keyblock);
 void merge_keys_and_selfsig( KBNODE keyblock );
-char*get_user_id_string( u32 *keyid );
 char*get_user_id_string_native( u32 *keyid );
 char*get_long_user_id_string( u32 *keyid );
 char*get_user_id( u32 *keyid, size_t *rn );
 char*get_user_id_native( u32 *keyid );
+char *get_user_id_byfpr (const byte *fpr, size_t *rn);
+char *get_user_id_byfpr_native (const byte *fpr);
 KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx);
 void release_akl(void);
 int parse_auto_key_locate(char *options);
index 3b4c10c..8b4eeb1 100644 (file)
@@ -767,7 +767,8 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
       gcry_md_close( md);
     }
 
-  *ret_len = len;
+  if (ret_len)
+    *ret_len = len;
   return array;
 }