gpg: Consistent use of preprocessor conditionals.
[gnupg.git] / g10 / delkey.c
index 2e4477b..547b40d 100644 (file)
@@ -16,7 +16,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>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <ctype.h>
 
 #include "gpg.h"
 #include "options.h"
 #include "packet.h"
-#include "status.h"
-#include "iobuf.h"
+#include "../common/status.h"
+#include "../common/iobuf.h"
 #include "keydb.h"
-#include "util.h"
+#include "../common/util.h"
 #include "main.h"
 #include "trustdb.h"
 #include "filter.h"
-#include "ttyio.h"
-#include "status.h"
-#include "i18n.h"
+#include "../common/ttyio.h"
+#include "../common/i18n.h"
+#include "call-agent.h"
 
 
 /****************
@@ -52,7 +51,7 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
 {
   gpg_error_t err;
   kbnode_t keyblock = NULL;
-  kbnode_t node;
+  kbnode_t node, kbctx;
   KEYDB_HANDLE hd;
   PKT_public_key *pk = NULL;
   u32 keyid[2];
@@ -64,6 +63,8 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
   *r_sec_avail = 0;
 
   hd = keydb_new ();
+  if (!hd)
+    return gpg_error_from_syserror ();
 
   /* Search the userid.  */
   err = classify_user_id (username, &desc, 1);
@@ -110,6 +111,15 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
         err = 0;
     }
 
+  if (secret && !have_secret_key_with_kid (keyid))
+    {
+      err = gpg_error (GPG_ERR_NOT_FOUND);
+      log_error (_("key \"%s\" not found\n"), username);
+      write_status_text (STATUS_DELETE_PROBLEM, "1");
+      goto leave;
+    }
+
+
   if (opt.batch && exactmatch)
     okay++;
   else if (opt.batch && secret)
@@ -156,9 +166,56 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
     {
       if (secret)
        {
-         log_error (_("deleting secret key not implemented\n"));
-         err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */
-         goto leave;
+          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);
+              /* NB: We require --yes to advise the agent not to
+               * request a confirmation.  The rationale for this extra
+               * pre-caution is that since 2.1 the secret key may also
+               * be used for other protocols and thus deleting it from
+               * the gpg would also delete the key for other tools. */
+              if (!err)
+                err = agent_delete_key (NULL, hexgrip, prompt,
+                                        opt.answer_yes);
+              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)
+                   {
+                     write_status_error ("delete_key.secret", err);
+                     break;
+                   }
+                }
+
+            }
+
+          err = firsterr;
+          if (firsterr)
+            goto leave;
        }
       else
        {