gpg: Screen keyserver responses.
[gnupg.git] / g10 / delkey.c
index 9785498..3de705d 100644 (file)
@@ -1,6 +1,7 @@
 /* delkey.c - delete keys
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004,
  *               2005, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -39,6 +40,7 @@
 #include "ttyio.h"
 #include "status.h"
 #include "i18n.h"
+#include "call-agent.h"
 
 
 /****************
  * r_sec_avail will be set if a secret key is available and the public
  * key can't be deleted for that reason.
  */
-static int
+static gpg_error_t
 do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
 {
-    int rc = 0;
-    KBNODE keyblock = NULL;
-    KBNODE node;
-    KEYDB_HANDLE hd = keydb_new ();
-    PKT_public_key *pk = NULL;
-    u32 keyid[2];
-    int okay=0;
-    int yes;
-    KEYDB_SEARCH_DESC desc;
-    int exactmatch;
-
-    *r_sec_avail = 0;
-
-    /* Search the userid */
-    rc = classify_user_id (username, &desc);
-    exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR
-                  || desc.mode == KEYDB_SEARCH_MODE_FPR16
-                  || desc.mode == KEYDB_SEARCH_MODE_FPR20);
-    if (!rc)
-      rc = keydb_search (hd, &desc, 1);
-    if (rc) {
-       log_error (_("key \"%s\" not found: %s\n"), username, g10_errstr (rc));
-       write_status_text( STATUS_DELETE_PROBLEM, "1" );
-       goto leave;
+  gpg_error_t err;
+  kbnode_t keyblock = NULL;
+  kbnode_t node, kbctx;
+  KEYDB_HANDLE hd;
+  PKT_public_key *pk = NULL;
+  u32 keyid[2];
+  int okay=0;
+  int yes;
+  KEYDB_SEARCH_DESC desc;
+  int exactmatch;
+
+  *r_sec_avail = 0;
+
+  hd = keydb_new ();
+
+  /* Search the userid.  */
+  err = classify_user_id (username, &desc, 1);
+  exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR
+                || desc.mode == KEYDB_SEARCH_MODE_FPR16
+                || desc.mode == KEYDB_SEARCH_MODE_FPR20);
+  if (!err)
+    err = keydb_search (hd, &desc, 1, NULL);
+  if (err)
+    {
+      log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err));
+      write_status_text (STATUS_DELETE_PROBLEM, "1");
+      goto leave;
     }
 
-    /* read the keyblock */
-    rc = keydb_get_keyblock (hd, &keyblock );
-    if (rc) {
-       log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
-       goto leave;
+  /* Read the keyblock.  */
+  err = keydb_get_keyblock (hd, &keyblock);
+  if (err)
+    {
+      log_error (_("error reading keyblock: %s\n"), gpg_strerror (err) );
+      goto leave;
     }
 
-    /* get the keyid from the keyblock */
-    node = find_kbnode( keyblock, secret? PKT_SECRET_KEY:PKT_PUBLIC_KEY );
-    if( !node ) {
-       log_error("Oops; key not found anymore!\n");
-       rc = G10ERR_GENERAL;
-       goto leave;
+  /* Get the keyid from the keyblock.  */
+  node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+  if (!node)
+    {
+      log_error ("Oops; key not found anymore!\n");
+      err = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
     }
+  pk = node->pkt->pkt.public_key;
+  keyid_from_pk (pk, keyid);
 
-    pk = node->pkt->pkt.public_key;
-    keyid_from_pk( pk, keyid );
+  if (!secret && !force)
+    {
+      if (have_secret_key_with_kid (keyid))
+        {
+          *r_sec_avail = 1;
+          err = gpg_error (GPG_ERR_EOF);
+          goto leave;
+        }
+      else
+        err = 0;
+    }
 
-    if (!force)
-      {
-        if (have_secret_key_with_kid (keyid))
-          {
-            *r_sec_avail = 1;
-            rc = -1;
-            goto leave;
-          }
-        else
-          rc = 0;
-      }
-
-    if( rc )
-       rc = 0;
-    else if (opt.batch && exactmatch)
-        okay++;
-    else if( opt.batch && secret )
-      {
-       log_error(_("can't do this in batch mode\n"));
-        log_info (_("(unless you specify the key by fingerprint)\n"));
-      }
-    else if( opt.batch && opt.answer_yes )
-       okay++;
-    else if( opt.batch )
-      {
-       log_error(_("can't do this in batch mode without \"--yes\"\n"));
-        log_info (_("(unless you specify the key by fingerprint)\n"));
-      }
-    else {
-        if( secret )
-            print_seckey_info (pk);
-        else
-            print_pubkey_info (NULL, pk );
-       tty_printf( "\n" );
-
-       yes = cpr_get_answer_is_yes( secret? "delete_key.secret.okay"
-                                          : "delete_key.okay",
-                             _("Delete this key from the keyring? (y/N) "));
-       if( !cpr_enabled() && secret && yes ) {
-           /* I think it is not required to check a passphrase; if
-            * the user is so stupid as to let others access his secret keyring
-            * (and has no backup) - it is up him to read some very
-            * basic texts about security.
-            */
-           yes = cpr_get_answer_is_yes("delete_key.secret.okay",
-                        _("This is a secret key! - really delete? (y/N) "));
+  if (opt.batch && exactmatch)
+    okay++;
+  else if (opt.batch && secret)
+    {
+      log_error(_("can't do this in batch mode\n"));
+      log_info (_("(unless you specify the key by fingerprint)\n"));
+    }
+  else if (opt.batch && opt.answer_yes)
+    okay++;
+  else if (opt.batch)
+    {
+      log_error(_("can't do this in batch mode without \"--yes\"\n"));
+      log_info (_("(unless you specify the key by fingerprint)\n"));
+    }
+  else
+    {
+      if (secret)
+        print_seckey_info (pk);
+      else
+        print_pubkey_info (NULL, pk );
+      tty_printf( "\n" );
+
+      yes = cpr_get_answer_is_yes
+        (secret? "delete_key.secret.okay": "delete_key.okay",
+         _("Delete this key from the keyring? (y/N) "));
+
+      if (!cpr_enabled() && secret && yes)
+        {
+          /* I think it is not required to check a passphrase; if the
+           * user is so stupid as to let others access his secret
+           * keyring (and has no backup) - it is up him to read some
+           * very basic texts about security.  */
+          yes = cpr_get_answer_is_yes
+            ("delete_key.secret.okay",
+             _("This is a secret key! - really delete? (y/N) "));
        }
-       if( yes )
-           okay++;
+
+      if (yes)
+        okay++;
     }
 
 
-    if( okay ) {
-       rc = keydb_delete_keyblock (hd);
-       if (rc) {
-           log_error (_("deleting keyblock failed: %s\n"), g10_errstr(rc) );
-           goto leave;
+  if (okay)
+    {
+      if (secret)
+       {
+          char *prompt;
+          gpg_error_t firsterr = 0;
+          char *hexgrip;
+
+          setup_main_keyids (keyblock);
+          for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+            {
+              if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
+                    || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
+                continue;
+
+              if (agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
+                continue;  /* No secret key for that public (sub)key.  */
+
+              prompt = gpg_format_keydesc (node->pkt->pkt.public_key,
+                                           FORMAT_KEYDESC_DELKEY, 1);
+              err = hexkeygrip_from_pk (node->pkt->pkt.public_key, &hexgrip);
+              if (!err)
+                err = agent_delete_key (NULL, hexgrip, prompt);
+              xfree (prompt);
+              xfree (hexgrip);
+              if (err)
+                {
+                  if (gpg_err_code (err) == GPG_ERR_KEY_ON_CARD)
+                    write_status_text (STATUS_DELETE_PROBLEM, "1");
+                  log_error (_("deleting secret %s failed: %s\n"),
+                             (node->pkt->pkttype == PKT_PUBLIC_KEY
+                              ? _("key"):_("subkey")),
+                             gpg_strerror (err));
+                  if (!firsterr)
+                    firsterr = err;
+                  if (gpg_err_code (err) == GPG_ERR_CANCELED
+                      || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
+                    break;
+                }
+
+            }
+
+          err = firsterr;
+          if (firsterr)
+            goto leave;
+       }
+      else
+       {
+         err = keydb_delete_keyblock (hd);
+         if (err)
+            {
+              log_error (_("deleting keyblock failed: %s\n"),
+                         gpg_strerror (err));
+              goto leave;
+            }
        }
 
-       /* Note that the ownertrust being cleared will trigger a
-           revalidation_mark().  This makes sense - only deleting keys
-           that have ownertrust set should trigger this. */
+      /* Note that the ownertrust being cleared will trigger a
+        revalidation_mark().  This makes sense - only deleting keys
+        that have ownertrust set should trigger this. */
 
-        if (!secret && pk && clear_ownertrusts (pk)) {
+      if (!secret && pk && clear_ownertrusts (pk))
+        {
           if (opt.verbose)
             log_info (_("ownertrust information cleared\n"));
         }
     }
 
 leave:
-    keydb_release (hd);
-    release_kbnode (keyblock);
-    return rc;
+ leave:
+  keydb_release (hd);
+  release_kbnode (keyblock);
+  return err;
 }
 
 /****************
  * Delete a public or secret key from a keyring.
  */
-int
-delete_keys( strlist_t names, int secret, int allow_both )
+gpg_error_t
+delete_keys (strlist_t names, int secret, int allow_both)
 {
-    int rc, avail, force=(!allow_both && !secret && opt.expert);
-
-    /* Force allows us to delete a public key even if a secret key
-       exists. */
-
-    for(;names;names=names->next) {
-       rc = do_delete_key (names->d, secret, force, &avail );
-       if ( rc && avail ) {
-        if ( allow_both ) {
-          rc = do_delete_key (names->d, 1, 0, &avail );
-          if ( !rc )
-            rc = do_delete_key (names->d, 0, 0, &avail );
-        }
-        else {
-          log_error(_(
-             "there is a secret key for public key \"%s\"!\n"),names->d);
-          log_info(_(
-             "use option \"--delete-secret-keys\" to delete it first.\n"));
-          write_status_text( STATUS_DELETE_PROBLEM, "2" );
-          return rc;
-        }
-       }
-
-       if(rc) {
-        log_error("%s: delete key failed: %s\n", names->d, g10_errstr(rc) );
-        return rc;
-       }
+  gpg_error_t err;
+  int avail;
+  int force = (!allow_both && !secret && opt.expert);
+
+  /* Force allows us to delete a public key even if a secret key
+     exists. */
+
+  for ( ;names ; names=names->next )
+    {
+      err = do_delete_key (names->d, secret, force, &avail);
+      if (err && avail)
+        {
+          if (allow_both)
+            {
+              err = do_delete_key (names->d, 1, 0, &avail);
+              if (!err)
+                err = do_delete_key (names->d, 0, 0, &avail);
+            }
+          else
+            {
+              log_error (_("there is a secret key for public key \"%s\"!\n"),
+                         names->d);
+              log_info(_("use option \"--delete-secret-keys\" to delete"
+                         " it first.\n"));
+              write_status_text (STATUS_DELETE_PROBLEM, "2");
+              return err;
+            }
+        }
+
+      if (err)
+        {
+          log_error ("%s: delete key failed: %s\n",
+                     names->d, gpg_strerror (err));
+          return err;
+        }
     }
 
-    return 0;
+  return 0;
 }