tests: Use gpgconf to set the ssh socket envvar.
[gnupg.git] / g10 / import.c
index 8cfd6ea..3c7edd7 100644 (file)
@@ -220,6 +220,113 @@ import_release_stats_handle (import_stats_t p)
 }
 
 
+/* Read a key from a file.  Only the first key in the file is
+ * considered and stored at R_KEYBLOCK.  FNAME is the name of the
+ * file.
+ */
+gpg_error_t
+read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
+{
+  gpg_error_t err;
+  iobuf_t inp;
+  PACKET *pending_pkt = NULL;
+  kbnode_t keyblock = NULL;
+  u32 keyid[2];
+  int v3keys;   /* Dummy */
+  int non_self; /* Dummy */
+
+  (void)ctrl;
+
+  *r_keyblock = NULL;
+
+  inp = iobuf_open (fname);
+  if (!inp)
+    err = gpg_error_from_syserror ();
+  else if (is_secured_file (iobuf_get_fd (inp)))
+    {
+      iobuf_close (inp);
+      inp = NULL;
+      err = gpg_error (GPG_ERR_EPERM);
+    }
+  else
+    err = 0;
+  if (err)
+    {
+      log_error (_("can't open '%s': %s\n"),
+                 iobuf_is_pipe_filename (fname)? "[stdin]": fname,
+                 gpg_strerror (err));
+      if (gpg_err_code (err) == GPG_ERR_ENOENT)
+        err = gpg_error (GPG_ERR_NO_PUBKEY);
+      goto leave;
+    }
+
+  /* Push the armor filter.  */
+  {
+    armor_filter_context_t *afx;
+    afx = new_armor_context ();
+    afx->only_keyblocks = 1;
+    push_armor_filter (afx, inp);
+    release_armor_context (afx);
+  }
+
+  /* Read the first non-v3 keyblock.  */
+  while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
+    {
+      if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
+        break;
+      log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
+      release_kbnode (keyblock);
+      keyblock = NULL;
+    }
+  if (err)
+    {
+      if (gpg_err_code (err) != GPG_ERR_INV_KEYRING)
+        log_error (_("error reading '%s': %s\n"),
+                   iobuf_is_pipe_filename (fname)? "[stdin]": fname,
+                   gpg_strerror (err));
+      goto leave;
+    }
+
+  keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
+
+  if (!find_next_kbnode (keyblock, PKT_USER_ID))
+    {
+      err = gpg_error (GPG_ERR_NO_USER_ID);
+      goto leave;
+    }
+
+  collapse_uids (&keyblock);
+
+  clear_kbnode_flags (keyblock);
+  if (chk_self_sigs (keyblock, keyid, &non_self))
+    {
+      err = gpg_error (GPG_ERR_INV_KEYRING);
+      goto leave;
+    }
+
+  if (!delete_inv_parts (keyblock, keyid, 0) )
+    {
+      err = gpg_error (GPG_ERR_NO_USER_ID);
+      goto leave;
+    }
+
+  *r_keyblock = keyblock;
+  keyblock = NULL;
+
+ leave:
+  if (inp)
+    {
+      iobuf_close (inp);
+      /* Must invalidate that ugly cache to actually close the file. */
+      iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
+    }
+  release_kbnode (keyblock);
+  /* FIXME: Do we need to free PENDING_PKT ? */
+  return err;
+}
+
+
+
 /*
  * Import the public keys from the given filename. Input may be armored.
  * This function rejects all keys which are not validly self signed on at
@@ -830,63 +937,6 @@ fix_bad_direct_key_sigs (kbnode_t keyblock, u32 *keyid)
 }
 
 
-/* Write the keyblock either to stdin or to the file set with
- * the --output option.  */
-static gpg_error_t
-write_keyblock_to_output (kbnode_t keyblock)
-{
-  gpg_error_t err;
-  const char *fname;
-  iobuf_t out;
-  kbnode_t node;
-  armor_filter_context_t *afx = NULL;
-
-  fname = opt.outfile? opt.outfile : "-";
-  if (is_secured_filename (fname) )
-    return gpg_error (GPG_ERR_EPERM);
-
-  out = iobuf_create (fname, 0);
-  if (!out)
-    {
-      err = gpg_error_from_syserror ();
-      log_error(_("can't create '%s': %s\n"), fname, gpg_strerror (err));
-      return err;
-    }
-  if (opt.verbose)
-    log_info (_("writing to '%s'\n"), iobuf_get_fname_nonnull (out));
-
-  if (opt.armor)
-    {
-      afx = new_armor_context ();
-      afx->what = 1;
-      push_armor_filter (afx, out);
-    }
-
-  for (node = keyblock; node; node = node->next)
-    {
-      if (!is_deleted_kbnode (node))
-       {
-         err = build_packet (out, node->pkt);
-         if (err)
-           {
-             log_error ("build_packet(%d) failed: %s\n",
-                        node->pkt->pkttype, gpg_strerror (err) );
-             goto leave;
-           }
-       }
-    }
-  err = 0;
-
- leave:
-  if (err)
-    iobuf_cancel (out);
-  else
-    iobuf_close (out);
-  release_armor_context (afx);
-  return err;
-}
-
-
 static void
 print_import_ok (PKT_public_key *pk, unsigned int reason)
 {
@@ -1280,7 +1330,7 @@ import_one (ctrl_t ctrl,
           merge_keys_and_selfsig (keyblock);
           merge_keys_done = 1;
         }
-      rc = write_keyblock_to_output (keyblock);
+      rc = write_keyblock_to_output (keyblock, opt.armor, opt.export_options);
       goto leave;
     }
 
@@ -1970,7 +2020,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"));
@@ -2017,8 +2067,11 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
             {
               gpg_error_t err;
 
-             nr_prev = stats->secret_imported;
-              err = transfer_secret_keys (ctrl, stats, keyblock, batch, 0);
+              /* transfer_secret_keys collects subkey stats.  */
+              struct import_stats_s subkey_stats = {0};
+
+              err = transfer_secret_keys (ctrl, &subkey_stats, keyblock,
+                                          batch, 0);
               if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED)
                 {
                   /* TRANSLATORS: For smartcard, each private key on
@@ -2041,8 +2094,14 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
                   if (!opt.quiet)
                     log_info (_("key %s: secret key imported\n"),
                               keystr_from_pk (pk));
-                 if (stats->secret_imported > nr_prev)
-                   status |= 1;
+                 if (subkey_stats.secret_imported)
+                    {
+                      status |= 1;
+                      stats->secret_imported += 1;
+                    }
+                 if (subkey_stats.secret_dups)
+                    stats->secret_dups += 1;
+
                   if (is_status_enabled ())
                     print_import_ok (pk, status);
                   check_prefs (ctrl, node);