gpg: Minor cleanup for key listing related code.
[gnupg.git] / g10 / keyserver.c
index 3a3bc40..1b2e128 100644 (file)
@@ -1,6 +1,7 @@
 /* keyserver.c - generic keyserver code
  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  *               2009, 2011, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -110,7 +111,8 @@ static struct parse_options keyserver_opts[]=
 
 static gpg_error_t keyserver_get (ctrl_t ctrl,
                                   KEYDB_SEARCH_DESC *desc, int ndesc,
-                                  struct keyserver_spec *keyserver);
+                                  struct keyserver_spec *keyserver,
+                                  unsigned char **r_fpr, size_t *r_fprlen);
 static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
                                   struct keyserver_spec *keyserver);
 
@@ -819,7 +821,7 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc,
           }
         for (idx = 0; idx < numidx; idx++)
           selarray[idx] = desc[numarray[idx]-1];
-        err = keyserver_get (ctrl, selarray, numidx, NULL);
+        err = keyserver_get (ctrl, selarray, numidx, NULL, NULL, NULL);
         xfree (selarray);
       }
     }
@@ -834,7 +836,7 @@ show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc,
    KS_SEARCH command.  If SPECIAL is 0, LINE is the actual data line
    received with all escaping removed and guaranteed to be exactly one
    line with stripped LF; an EOF is indicated by LINE passed as NULL.
-   If special is 1, the line conatins the source of the information
+   If special is 1, the line contains the source of the information
    (usually an URL).  LINE may be modified after return.  */
 static gpg_error_t
 search_line_handler (void *opaque, int special, char *line)
@@ -863,7 +865,7 @@ search_line_handler (void *opaque, int special, char *line)
   /* Print the received line.  */
   if (opt.with_colons && line)
     {
-      log_debug ("%s\n",line);
+      es_printf ("%s\n", line);
     }
 
   /* Look for an info: line.  The only current info: values defined
@@ -1039,6 +1041,86 @@ keyserver_export (ctrl_t ctrl, strlist_t users)
   return rc;
 }
 
+
+/* Structure to convey the arg to keyserver_retrieval_screener.  */
+struct ks_retrieval_screener_arg_s
+{
+  KEYDB_SEARCH_DESC *desc;
+  int ndesc;
+};
+
+
+/* Check whether a key matches the search description.  The function
+   returns 0 if the key shall be imported.  */
+static gpg_error_t
+keyserver_retrieval_screener (kbnode_t keyblock, void *opaque)
+{
+  struct ks_retrieval_screener_arg_s *arg = opaque;
+  KEYDB_SEARCH_DESC *desc = arg->desc;
+  int ndesc = arg->ndesc;
+  kbnode_t node;
+  PKT_public_key *pk;
+  int n;
+  u32 keyid[2];
+  byte fpr[MAX_FINGERPRINT_LEN];
+  size_t fpr_len = 0;
+
+  /* Secret keys are not expected from a keyserver.  We do not
+     care about secret subkeys because the import code takes care
+     of skipping them.  Not allowing an import of a public key
+     with a secret subkey would make it too easy to inhibit the
+     downloading of a public key.  Recall that keyservers do only
+     limited checks.  */
+  node = find_kbnode (keyblock, PKT_SECRET_KEY);
+  if (node)
+    return gpg_error (GPG_ERR_GENERAL);   /* Do not import. */
+
+  if (!ndesc)
+    return 0; /* Okay if no description given.  */
+
+  /* Loop over all key packets.  */
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype != PKT_PUBLIC_KEY
+          && node->pkt->pkttype != PKT_PUBLIC_SUBKEY)
+        continue;
+
+      pk = node->pkt->pkt.public_key;
+      fingerprint_from_pk (pk, fpr, &fpr_len);
+      keyid_from_pk (pk, keyid);
+
+      /* Compare requested and returned fingerprints if available. */
+      for (n = 0; n < ndesc; n++)
+        {
+          if (desc[n].mode == KEYDB_SEARCH_MODE_FPR20)
+            {
+              if (fpr_len == 20 && !memcmp (fpr, desc[n].u.fpr, 20))
+                return 0;
+            }
+          else if (desc[n].mode == KEYDB_SEARCH_MODE_FPR16)
+            {
+              if (fpr_len == 16 && !memcmp (fpr, desc[n].u.fpr, 16))
+                return 0;
+            }
+          else if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID)
+            {
+              if (keyid[0] == desc[n].u.kid[0] && keyid[1] == desc[n].u.kid[1])
+                return 0;
+            }
+          else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID)
+            {
+              if (keyid[1] == desc[n].u.kid[1])
+                return 0;
+            }
+          else /* No keyid or fingerprint - can't check.  */
+            return 0; /* allow import.  */
+        }
+    }
+
+  return gpg_error (GPG_ERR_GENERAL);
+}
+
+
 int
 keyserver_import (ctrl_t ctrl, strlist_t users)
 {
@@ -1071,13 +1153,31 @@ keyserver_import (ctrl_t ctrl, strlist_t users)
     }
 
   if(count>0)
-    rc=keyserver_get (ctrl, desc, count, NULL);
+    rc=keyserver_get (ctrl, desc, count, NULL, NULL, NULL);
 
   xfree(desc);
 
   return rc;
 }
 
+
+/* Import all keys that exactly match NAME */
+int
+keyserver_import_name (ctrl_t ctrl, const char *name,
+                       unsigned char **fpr, size_t *fprlen,
+                       struct keyserver_spec *keyserver)
+{
+  KEYDB_SEARCH_DESC desc;
+
+  memset (&desc, 0, sizeof desc);
+
+  desc.mode = KEYDB_SEARCH_MODE_EXACT;
+  desc.u.name = name;
+
+  return keyserver_get (ctrl, &desc, 1, keyserver, fpr, fprlen);
+}
+
+
 int
 keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
                         struct keyserver_spec *keyserver)
@@ -1097,7 +1197,7 @@ keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
 
   /* TODO: Warn here if the fingerprint we got doesn't match the one
      we asked for? */
-  return keyserver_get (ctrl, &desc, 1, keyserver);
+  return keyserver_get (ctrl, &desc, 1, keyserver, NULL, NULL);
 }
 
 int
@@ -1112,7 +1212,7 @@ keyserver_import_keyid (ctrl_t ctrl,
   desc.u.kid[0]=keyid[0];
   desc.u.kid[1]=keyid[1];
 
-  return keyserver_get (ctrl, &desc,1, keyserver);
+  return keyserver_get (ctrl, &desc,1, keyserver, NULL, NULL);
 }
 
 /* code mostly stolen from do_export_stream */
@@ -1316,7 +1416,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
              /* We use the keyserver structure we parsed out before.
                 Note that a preferred keyserver without a scheme://
                 will be interpreted as hkp:// */
-             rc = keyserver_get (ctrl, &desc[i], 1, keyserver);
+             rc = keyserver_get (ctrl, &desc[i], 1, keyserver, NULL, NULL);
              if(rc)
                log_info(_("WARNING: unable to refresh key %s"
                           " via %s: %s\n"),keystr_from_desc(&desc[i]),
@@ -1346,7 +1446,7 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
                     count,opt.keyserver->uri);
        }
 
-      rc=keyserver_get (ctrl, desc, numdesc, NULL);
+      rc=keyserver_get (ctrl, desc, numdesc, NULL, NULL, NULL);
     }
 
   xfree(desc);
@@ -1469,21 +1569,15 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
 
 
 
-/* Called using:
-
-import_name:
-  rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
-                       0, fpr, fpr_len, keyserver);
-
-import_ldap:
-  rc = keyserver_work (ctrl, KS_GETNAME, list, NULL,
-                       0, fpr, fpr_len, keyserver);
-
- */
-
+/* Retrieve a key from a keyserver.  The search pattern are in
+   (DESC,NDESC).  Allowed search modes are keyid, fingerprint, and
+   exact searches.  KEYSERVER gives an optional override keyserver. If
+   (R_FPR,R_FPRLEN) are not NULL, the may retrun the fingerprint of
+   one imported key.  */
 static gpg_error_t
 keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
-               struct keyserver_spec *keyserver)
+               struct keyserver_spec *keyserver,
+               unsigned char **r_fpr, size_t *r_fprlen)
 
 {
   gpg_error_t err = 0;
@@ -1536,10 +1630,12 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
         }
       else if(desc[idx].mode == KEYDB_SEARCH_MODE_EXACT)
         {
-          /* FIXME: We don't need this.  It is used as a dummy by
-             keyserver_fetch which passes an entire URL.  Better use a
-             separate function here. */
-          pattern[npat] = xtrystrdup ("0x0000000000000000");
+          /* The Dirmngr uses also classify_user_id to detect the type
+             of the search string.  By adding the '=' prefix we force
+             Dirmngr's KS_GET to consider this an exact search string.
+             (In gpg 1.4 and gpg 2.0 the keyserver helpers used the
+             KS_GETNAME command to indicate this.)  */
+          pattern[npat] = strconcat ("=", desc[idx].u.name, NULL);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
           else
@@ -1578,12 +1674,13 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
   for (idx=0; idx < npat; idx++)
     xfree (pattern[idx]);
   xfree (pattern);
-  if (opt.verbose)
+  if (opt.verbose && source)
     log_info ("data source: %s\n", source);
 
   if (!err)
     {
       void *stats_handle;
+      struct ks_retrieval_screener_arg_s screenerarg;
 
       stats_handle = import_new_stats_handle();
 
@@ -1599,9 +1696,14 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
          never accept or send them but we better protect against rogue
          keyservers. */
 
-      import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
+      screenerarg.desc = desc;
+      screenerarg.ndesc = ndesc;
+      import_keys_es_stream (ctrl, datastream, stats_handle,
+                             r_fpr, r_fprlen,
                              (opt.keyserver_options.import_options
-                              | IMPORT_NO_SECKEY));
+                              | IMPORT_NO_SECKEY),
+                             keyserver_retrieval_screener, &screenerarg);
+
       import_print_stats (stats_handle);
       import_release_stats_handle (stats_handle);
     }
@@ -1666,7 +1768,7 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
 }
 
 
-/* Loop over all URLs in STRLIST and fetch the key that URL.  Note
+/* Loop over all URLs in STRLIST and fetch the key at that URL.  Note
    that the fetch operation ignores the configured key servers and
    instead directly retrieves the keys.  */
 int
@@ -1694,7 +1796,8 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
 
           stats_handle = import_new_stats_handle();
           import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
-                                 opt.keyserver_options.import_options);
+                                 opt.keyserver_options.import_options,
+                                 NULL, NULL);
 
           import_print_stats (stats_handle);
           import_release_stats_handle (stats_handle);
@@ -1744,7 +1847,8 @@ keyserver_import_cert (ctrl_t ctrl,
 
       err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
                                    (opt.keyserver_options.import_options
-                                    | IMPORT_NO_SECKEY));
+                                    | IMPORT_NO_SECKEY),
+                                   NULL, NULL);
 
       opt.no_armor=armor_status;
 
@@ -1824,31 +1928,18 @@ keyserver_import_pka (ctrl_t ctrl,
   return rc;
 }
 
-/* Import all keys that match name */
-int
-keyserver_import_name (ctrl_t ctrl, const char *name,
-                       unsigned char **fpr, size_t *fpr_len,
-                       struct keyserver_spec *keyserver)
-{
-  strlist_t list=NULL;
-  int rc;
-
-  append_to_strlist(&list,name);
-
-  rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);  /* FIXME */
-       /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */
-       /*                 0, fpr, fpr_len, keyserver); */
-
-  free_strlist(list);
-
-  return rc;
-}
 
 /* Import a key by name using LDAP */
 int
 keyserver_import_ldap (ctrl_t ctrl,
-                       const char *name,unsigned char **fpr,size_t *fpr_len)
+                       const char *name, unsigned char **fpr, size_t *fprlen)
 {
+  (void)ctrl;
+  (void)name;
+  (void)fpr;
+  (void)fprlen;
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/
+#if 0
   char *domain;
   struct keyserver_spec *keyserver;
   strlist_t list=NULL;
@@ -1919,4 +2010,5 @@ keyserver_import_ldap (ctrl_t ctrl,
   free_keyserver_spec(keyserver);
 
   return rc;
+#endif
 }