dirmngr: After a connection failure log a hint if Tor is not running.
[gnupg.git] / g10 / import.c
index b83f371..1ed11bf 100644 (file)
@@ -15,7 +15,7 @@
  * 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/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -76,14 +76,22 @@ struct import_stats_s
 #define NODE_FLAG_A  8
 
 
-/* A global variable to store the selector created from
+/* A an object and a global instance to store selectors created from
  * --import-filter keep-uid=EXPR.
+ * --import-filter drop-sig=EXPR.
  *
  * FIXME: We should put this into the CTRL object but that requires a
- * lot more changes right now.
+ * lot more changes right now.  For now we use save and restore
+ * function to temporary change them.
  */
-static recsel_expr_t import_keep_uid;
-
+/* Definition of the import filters.  */
+struct import_filter_s
+{
+  recsel_expr_t keep_uid;
+  recsel_expr_t drop_sig;
+};
+/* The current instance.  */
+struct import_filter_s import_filter;
 
 
 static int import (ctrl_t ctrl,
@@ -103,10 +111,12 @@ static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
                               struct import_stats_s *stats, int batch,
                               unsigned int options, int for_migration,
                               import_screener_t screener, void *screener_arg);
-static int import_revoke_cert (kbnode_t node, struct import_stats_s *stats);
+static int import_revoke_cert (ctrl_t ctrl,
+                               kbnode_t node, struct import_stats_s *stats);
 static int chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self);
 static int delete_inv_parts (kbnode_t keyblock,
                              u32 *keyid, unsigned int options);
+static int any_uid_left (kbnode_t keyblock);
 static int merge_blocks (kbnode_t keyblock_orig,
                         kbnode_t keyblock, u32 *keyid,
                         int *n_uids, int *n_sigs, int *n_subk );
@@ -118,10 +128,18 @@ static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs);
 
 \f
 static void
+release_import_filter (import_filter_t filt)
+{
+  recsel_release (filt->keep_uid);
+  filt->keep_uid = NULL;
+  recsel_release (filt->drop_sig);
+  filt->drop_sig = NULL;
+}
+
+static void
 cleanup_import_globals (void)
 {
-  recsel_release (import_keep_uid);
-  import_keep_uid = NULL;
+  release_import_filter (&import_filter);
 }
 
 
@@ -197,7 +215,9 @@ parse_and_set_import_filter (const char *string)
   register_mem_cleanup_func (cleanup_import_globals);
 
   if (!strncmp (string, "keep-uid=", 9))
-    err = recsel_parse_expr (&import_keep_uid, string+9);
+    err = recsel_parse_expr (&import_filter.keep_uid, string+9);
+  else if (!strncmp (string, "drop-sig=", 9))
+    err = recsel_parse_expr (&import_filter.drop_sig, string+9);
   else
     err = gpg_error (GPG_ERR_INV_NAME);
 
@@ -205,6 +225,36 @@ parse_and_set_import_filter (const char *string)
 }
 
 
+/* Save the current import filters, return them, and clear the current
+ * filters.  Returns NULL on error and sets ERRNO.  */
+import_filter_t
+save_and_clear_import_filter (void)
+{
+  import_filter_t filt;
+
+  filt = xtrycalloc (1, sizeof *filt);
+  if (!filt)
+    return NULL;
+  *filt = import_filter;
+  memset (&import_filter, 0, sizeof import_filter);
+
+  return filt;
+}
+
+
+/* Release the current import filters and restore them from NEWFILT.
+ * Ownership of NEWFILT is moved to this function.  */
+void
+restore_import_filter (import_filter_t filt)
+{
+  if (filt)
+    {
+      release_import_filter (&import_filter);
+      import_filter = *filt;
+      xfree (filt);
+    }
+}
+
 
 import_stats_t
 import_new_stats_handle (void)
@@ -459,7 +509,7 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp,
   int rc;
   iobuf_t inp;
 
-  inp = iobuf_esopen (fp, "r", 1);
+  inp = iobuf_esopen (fp, "rb", 1);
   if (!inp)
     {
       rc = gpg_error_from_syserror ();
@@ -513,7 +563,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
                                 screener, screener_arg);
       else if (keyblock->pkt->pkttype == PKT_SIGNATURE
                && keyblock->pkt->pkt.signature->sig_class == 0x20 )
-        rc = import_revoke_cert (keyblock, stats);
+        rc = import_revoke_cert (ctrl, keyblock, stats);
       else
         {
           log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
@@ -1097,11 +1147,13 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
 }
 
 
-/* Helper for apply_keep_uid_filter.  */
-static const char *
-filter_getval (void *cookie, const char *propname)
+/* Helper for apply_*_filter in im,port.c and export.c.  */
+const char *
+impex_filter_getval (void *cookie, const char *propname)
 {
+  /* FIXME: Malloc our static buffers and access them via the cookie.  */
   kbnode_t node = cookie;
+  static char numbuf[20];
   const char *result;
 
   if (node->pkt->pkttype == PKT_USER_ID)
@@ -1115,19 +1167,76 @@ filter_getval (void *cookie, const char *propname)
               node->pkt->pkt.user_id->mbox
                 = mailbox_from_userid (node->pkt->pkt.user_id->name);
             }
-          return node->pkt->pkt.user_id->mbox;
+          result = node->pkt->pkt.user_id->mbox;
         }
       else if (!strcmp (propname, "primary"))
         result = node->pkt->pkt.user_id->is_primary? "1":"0";
       else
         result = NULL;
     }
+  else if (node->pkt->pkttype == PKT_SIGNATURE
+           || node->pkt->pkttype == PKT_ATTRIBUTE)
+    {
+      PKT_signature *sig = node->pkt->pkt.signature;
+
+      if (!strcmp (propname, "sig_created"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%lu", (ulong)sig->timestamp);
+          result = numbuf;
+        }
+      else if (!strcmp (propname, "sig_created_d"))
+        {
+          result = datestr_from_sig (sig);
+        }
+      else if (!strcmp (propname, "sig_algo"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%d", sig->pubkey_algo);
+          result = numbuf;
+        }
+      else if (!strcmp (propname, "sig_digest_algo"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%d", sig->digest_algo);
+          result = numbuf;
+        }
+      else
+        result = NULL;
+    }
+  else if (node->pkt->pkttype == PKT_PUBLIC_KEY
+           || node->pkt->pkttype == PKT_SECRET_KEY
+           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+           || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+    {
+      PKT_public_key *pk = node->pkt->pkt.public_key;
+
+      if (!strcmp (propname, "secret"))
+        {
+          result = (node->pkt->pkttype == PKT_SECRET_KEY
+                    || node->pkt->pkttype == PKT_SECRET_SUBKEY)? "1":"0";
+        }
+      else if (!strcmp (propname, "key_algo"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo);
+          result = numbuf;
+        }
+      if (!strcmp (propname, "key_created"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp);
+          result = numbuf;
+        }
+      else if (!strcmp (propname, "key_created_d"))
+        {
+          result = datestr_from_pk (pk);
+        }
+      else
+        result = NULL;
+    }
   else
     result = NULL;
 
   return result;
 }
 
+
 /*
  * Apply the keep-uid filter to the keyblock.  The deleted nodes are
  * marked and thus the caller should call commit_kbnode afterwards.
@@ -1142,7 +1251,7 @@ apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
     {
       if (node->pkt->pkttype == PKT_USER_ID)
         {
-          if (!recsel_select (selector, filter_getval, node))
+          if (!recsel_select (selector, impex_filter_getval, node))
             {
 
               /* log_debug ("keep-uid: deleting '%s'\n", */
@@ -1166,6 +1275,49 @@ apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
 
 
 /*
+ * Apply the drop-sig filter to the keyblock.  The deleted nodes are
+ * marked and thus the caller should call commit_kbnode afterwards.
+ * KEYBLOCK must not have any blocks marked as deleted.
+ */
+static void
+apply_drop_sig_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+  kbnode_t node;
+  int active = 0;
+  u32 main_keyid[2];
+  PKT_signature *sig;
+
+  keyid_from_pk (keyblock->pkt->pkt.public_key, main_keyid);
+
+  /* Loop over all signatures for user id and attribute packets which
+   * are not self signatures.  */
+  for (node = keyblock->next; node; node = node->next )
+    {
+      if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+          || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+        break; /* ready.  */
+      if (node->pkt->pkttype == PKT_USER_ID)
+        active = 1;
+      if (!active)
+        continue;
+      if (node->pkt->pkttype != PKT_SIGNATURE
+          && node->pkt->pkttype != PKT_ATTRIBUTE)
+        continue;
+
+      sig = node->pkt->pkt.signature;
+      if (main_keyid[0] == sig->keyid[0] || main_keyid[1] == sig->keyid[1])
+        continue;  /* Skip self-signatures.  */
+
+      if (IS_UID_SIG(sig) || IS_UID_REV(sig))
+        {
+          if (recsel_select (selector, impex_filter_getval, node))
+            delete_kbnode (node);
+        }
+    }
+}
+
+
+/*
  * Try to import one keyblock. Return an error only in serious cases,
  * but never for an invalid keyblock.  It uses log_error to increase
  * the internal errorcount, so that invalid input can be detected by
@@ -1194,6 +1346,7 @@ import_one (ctrl_t ctrl,
   size_t an;
   char pkstrbuf[PUBKEY_STRING_SIZE];
   int merge_keys_done = 0;
+  int any_filter = 0;
 
   /* Get the key and print some info about it. */
   node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
@@ -1301,12 +1454,29 @@ import_one (ctrl_t ctrl,
   commit_kbnode (&keyblock);
 
   /* Apply import filter.  */
-  if (import_keep_uid)
+  if (import_filter.keep_uid)
     {
-      apply_keep_uid_filter (keyblock, import_keep_uid);
+      apply_keep_uid_filter (keyblock, import_filter.keep_uid);
       commit_kbnode (&keyblock);
+      any_filter = 1;
+    }
+  if (import_filter.drop_sig)
+    {
+      apply_drop_sig_filter (keyblock, import_filter.drop_sig);
+      commit_kbnode (&keyblock);
+      any_filter = 1;
     }
 
+  /* If we ran any filter we need to check that at least one user id
+   * is left in the keyring.  Note that we do not use log_error in
+   * this case. */
+  if (any_filter && !any_uid_left (keyblock))
+    {
+      if (!opt.quiet )
+        log_info ( _("key %s: no valid user IDs\n"), keystr_from_pk (pk));
+      stats->no_user_id++;
+      return 0;
+    }
 
   /* Show the key in the form it is merged or inserted.  We skip this
    * if "import-export" is also active without --armor or the output
@@ -1473,7 +1643,7 @@ import_one (ctrl_t ctrl,
         {
           mod_key = 1;
           /* KEYBLOCK_ORIG has been updated; write */
-          rc = keydb_update_keyblock (hd, keyblock_orig);
+          rc = keydb_update_keyblock (ctrl, hd, keyblock_orig);
           if (rc)
             log_error (_("error writing keyring '%s': %s\n"),
                        keydb_get_resource_name (hd), gpg_strerror (rc) );
@@ -2020,7 +2190,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
 #ifdef ENABLE_SELINUX_HACKS
   if (1)
     {
-      /* We don't allow to import secret keys because that may be used
+      /* We don't allow importing secret keys because that may be used
          to put a secret key into the keyring and the user might later
          be tricked into signing stuff with that key.  */
       log_error (_("importing secret keys not allowed\n"));
@@ -2119,7 +2289,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
  * Import a revocation certificate; this is a single signature packet.
  */
 static int
-import_revoke_cert (kbnode_t node, struct import_stats_s *stats)
+import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
 {
   PKT_public_key *pk = NULL;
   kbnode_t onode;
@@ -2210,7 +2380,7 @@ import_revoke_cert (kbnode_t node, struct import_stats_s *stats)
   insert_kbnode( keyblock, clone_kbnode(node), 0 );
 
   /* and write the keyblock back */
-  rc = keydb_update_keyblock (hd, keyblock );
+  rc = keydb_update_keyblock (ctrl, hd, keyblock );
   if (rc)
     log_error (_("error writing keyring '%s': %s\n"),
                keydb_get_resource_name (hd), gpg_strerror (rc) );
@@ -2588,6 +2758,19 @@ delete_inv_parts (kbnode_t keyblock, u32 *keyid, unsigned int options)
   return nvalid;
 }
 
+/* This function returns true if any UID is left in the keyring.  */
+static int
+any_uid_left (kbnode_t keyblock)
+{
+  kbnode_t node;
+
+  for (node=keyblock->next; node; node = node->next)
+    if (node->pkt->pkttype == PKT_USER_ID)
+      return 1;
+  return 0;
+}
+
+
 
 /****************
  * It may happen that the imported keyblock has duplicated user IDs.
@@ -2772,7 +2955,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
                              keyserver_import_fprint (ctrl,
                                                        sig->revkey[idx].fpr,
                                                        MAX_FINGERPRINT_LEN,
-                                                       opt.keyserver);
+                                                       opt.keyserver, 0);
 
                              /* Do we have it now? */
                              rc=get_pubkey_byfprint_fast (NULL,