/* 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. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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 . */ #include #include #include #include #include #include #include "gpg.h" #include "options.h" #include "packet.h" #include "status.h" #include "iobuf.h" #include "keydb.h" #include "util.h" #include "main.h" #include "trustdb.h" #include "filter.h" #include "ttyio.h" #include "status.h" #include "i18n.h" #include "call-agent.h" /**************** * Delete a public or secret key from a keyring. * r_sec_avail will be set if a secret key is available and the public * key can't be deleted for that reason. */ static gpg_error_t 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, 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 (); if (!hd) return gpg_error_from_syserror (); /* 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. */ 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, 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); 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 (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) { 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 (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) { write_status_error ("delete_key.secret", err); 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. */ if (!secret && pk && clear_ownertrusts (pk)) { if (opt.verbose) log_info (_("ownertrust information cleared\n")); } } leave: keydb_release (hd); release_kbnode (keyblock); return err; } /**************** * Delete a public or secret key from a keyring. */ gpg_error_t delete_keys (strlist_t names, int secret, int allow_both) { 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; }