gpg: New command --quick-set-primary-uid.

* g10/gpg.c (aQuickSetPrimaryUid): New const.
(opts): New command --quick-set-primary-uid.
(main): Implement it.
* g10/keyedit.c (keyedit_quick_adduid): Factor some code out to ...
(quick_find_keyblock): new func.
(keyedit_quick_revuid): Use quick_find_keyblock.
(keyedit_quick_set_primary): New.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2017-03-21 14:47:21 +01:00
parent 483c1288a8
commit 74c1f30ad6
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
4 changed files with 174 additions and 94 deletions

View File

@ -1096,19 +1096,28 @@ on its form are applied.
@item --quick-revoke-uid @var{user-id} @var{user-id-to-revoke}
@opindex quick-revoke-uid
This command revokes a User ID on an existing key. It cannot be used
to revoke the last User ID on key (some non-revoked User ID must
This command revokes a user ID on an existing key. It cannot be used
to revoke the last user ID on key (some non-revoked user ID must
remain), with revocation reason ``User ID is no longer valid''. If
you want to specify a different revocation reason, or to supply
supplementary revocation text, you should use the interactive
sub-command @code{revuid} of @option{--edit-key}.
@item --change-passphrase @var{user_id}
@item --quick-set-primary-uid @var{user-id} @var{primary-user-id}
@opindex quick-set-primary-uid
This command sets or updates the primary user ID flag on an existing
key. @var{user-id} specifies the key and @var{primary-user-id} the
user ID which shall be flagged as the primary user ID. The primary
user ID flag is removed from all other user ids and the timestamp of
all affected self-signatures is set one second ahead.
@item --change-passphrase @var{user-id}
@opindex change-passphrase
@itemx --passwd @var{user_id}
@itemx --passwd @var{user-id}
@opindex passwd
Change the passphrase of the secret key belonging to the certificate
specified as @var{user_id}. This is a shortcut for the sub-command
specified as @var{user-id}. This is a shortcut for the sub-command
@code{passwd} of the edit key menu.
@end table
@ -1767,7 +1776,7 @@ when verifying signatures made by keys that are not on the local
keyring.
If the method "wkd" is included in the list of methods given to
@option{auto-key-locate}, the Signer's User ID is part of the
@option{auto-key-locate}, the signer's user ID is part of the
signature, and the option @option{--disable-signer-uid} is not used,
the "wkd" method may also be used to retrieve a key.

View File

@ -1,7 +1,7 @@
/* gpg.c - The GnuPG utility (main for gpg)
* Copyright (C) 1998-2011 Free Software Foundation, Inc.
* Copyright (C) 1997-2016 Werner Koch
* Copyright (C) 2015-2016 g10 Code GmbH
* Copyright (C) 1997-2017 Werner Koch
* Copyright (C) 2015-2017 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -124,6 +124,7 @@ enum cmd_and_opt_values
aQuickAddKey,
aQuickRevUid,
aQuickSetExpire,
aQuickSetPrimaryUid,
aListConfig,
aListGcryptConfig,
aGPGConfList,
@ -460,6 +461,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aQuickRevUid, "quick-revuid", "@"),
ARGPARSE_c (aQuickSetExpire, "quick-set-expire",
N_("quickly set a new expiration date")),
ARGPARSE_c (aQuickSetPrimaryUid, "quick-set-primary-uid", "@"),
ARGPARSE_c (aFullKeygen, "full-generate-key" ,
N_("full featured key pair generation")),
ARGPARSE_c (aFullKeygen, "full-gen-key", "@"),
@ -2581,6 +2583,7 @@ main (int argc, char **argv)
case aQuickAddKey:
case aQuickRevUid:
case aQuickSetExpire:
case aQuickSetPrimaryUid:
case aExportOwnerTrust:
case aImportOwnerTrust:
case aRebuildKeydbCaches:
@ -4002,6 +4005,7 @@ main (int argc, char **argv)
case aQuickAddUid:
case aQuickAddKey:
case aQuickRevUid:
case aQuickSetPrimaryUid:
case aFullKeygen:
case aKeygen:
case aImport:
@ -4445,6 +4449,18 @@ main (int argc, char **argv)
}
break;
case aQuickSetPrimaryUid:
{
const char *uid, *primaryuid;
if (argc != 2)
wrong_args ("--quick-set-primary-uid USER-ID PRIMARY-USER-ID");
uid = *argv++; argc--;
primaryuid = *argv++; argc--;
keyedit_quick_set_primary (ctrl, uid, primaryuid);
}
break;
case aFastImport:
opt.import_options |= IMPORT_FAST;
case aImport:

View File

@ -1,6 +1,6 @@
/* keyedit.c - Edit properties of a key
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
* Copyright (C) 1998-2016 Werner Koch
* Copyright (C) 1998-2017 Werner Koch
* Copyright (C) 2015, 2016 g10 Code GmbH
*
* This file is part of GnuPG.
@ -2860,36 +2860,28 @@ leave:
}
/* Unattended adding of a new keyid. USERNAME specifies the
key. NEWUID is the new user id to add to the key. */
void
keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
/* Helper for quick commands to find the keyblock for USERNAME.
* Returns on success the key database handle at R_KDBHD and the
* keyblock at R_KEYBLOCK. */
static gpg_error_t
quick_find_keyblock (ctrl_t ctrl, const char *username,
KEYDB_HANDLE *r_kdbhd, kbnode_t *r_keyblock)
{
gpg_error_t err;
KEYDB_HANDLE kdbhd = NULL;
KEYDB_SEARCH_DESC desc;
kbnode_t keyblock = NULL;
KEYDB_SEARCH_DESC desc;
kbnode_t node;
char *uidstring = NULL;
uidstring = xstrdup (newuid);
trim_spaces (uidstring);
if (!*uidstring)
{
log_error ("%s\n", gpg_strerror (GPG_ERR_INV_USER_ID));
goto leave;
}
#ifdef HAVE_W32_SYSTEM
/* See keyedit_menu for why we need this. */
check_trustdb_stale (ctrl);
#endif
*r_kdbhd = NULL;
*r_keyblock = NULL;
/* Search the key; we don't want the whole getkey stuff here. */
kdbhd = keydb_new ();
if (!kdbhd)
{
/* Note that keydb_new has already used log_error. */
err = gpg_error_from_syserror ();
goto leave;
}
@ -2917,24 +2909,65 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
if (!err)
{
/* We require the secret primary key to add a UID. */
/* We require the secret primary key to set the primary UID. */
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
if (!node)
BUG ();
log_assert (node);
err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key);
}
}
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = gpg_error (GPG_ERR_NO_PUBKEY);
if (err)
{
log_error (_("secret key \"%s\" not found: %s\n"),
log_error (_("key \"%s\" not found: %s\n"),
username, gpg_strerror (err));
goto leave;
}
fix_keyblock (&keyblock);
merge_keys_and_selfsig (keyblock);
*r_keyblock = keyblock;
keyblock = NULL;
*r_kdbhd = kdbhd;
kdbhd = NULL;
leave:
release_kbnode (keyblock);
keydb_release (kdbhd);
return err;
}
/* Unattended adding of a new keyid. USERNAME specifies the
key. NEWUID is the new user id to add to the key. */
void
keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
{
gpg_error_t err;
KEYDB_HANDLE kdbhd = NULL;
kbnode_t keyblock = NULL;
char *uidstring = NULL;
uidstring = xstrdup (newuid);
trim_spaces (uidstring);
if (!*uidstring)
{
log_error ("%s\n", gpg_strerror (GPG_ERR_INV_USER_ID));
goto leave;
}
#ifdef HAVE_W32_SYSTEM
/* See keyedit_menu for why we need this. */
check_trustdb_stale (ctrl);
#endif
/* Search the key; we don't want the whole getkey stuff here. */
err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
if (err)
goto leave;
if (menu_adduid (ctrl, keyblock, 0, NULL, uidstring))
{
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
@ -2954,6 +2987,7 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
keydb_release (kdbhd);
}
/* Unattended revocation of a keyid. USERNAME specifies the
key. UIDTOREV is the user id revoke from the key. */
void
@ -2961,7 +2995,6 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
{
gpg_error_t err;
KEYDB_HANDLE kdbhd = NULL;
KEYDB_SEARCH_DESC desc;
kbnode_t keyblock = NULL;
kbnode_t node;
int modified = 0;
@ -2974,65 +3007,20 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
#endif
/* Search the key; we don't want the whole getkey stuff here. */
kdbhd = keydb_new ();
if (!kdbhd)
{
/* Note that keydb_new has already used log_error. */
goto leave;
}
err = classify_user_id (username, &desc, 1);
if (!err)
err = keydb_search (kdbhd, &desc, 1, NULL);
if (!err)
{
err = keydb_get_keyblock (kdbhd, &keyblock);
if (err)
{
log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
goto leave;
}
/* Now with the keyblock retrieved, search again to detect an
ambiguous specification. We need to save the found state so
that we can do an update later. */
keydb_push_found_state (kdbhd);
err = keydb_search (kdbhd, &desc, 1, NULL);
if (!err)
err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0;
keydb_pop_found_state (kdbhd);
if (!err)
{
/* We require the secret primary key to revoke a UID. */
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
if (!node)
BUG ();
err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key);
}
}
err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
if (err)
{
log_error (_("secret key \"%s\" not found: %s\n"),
username, gpg_strerror (err));
goto leave;
}
fix_keyblock (&keyblock);
merge_keys_and_selfsig (keyblock);
goto leave;
/* Too make sure that we do not revoke the last valid UID, we first
count how many valid UIDs there are. */
valid_uids = 0;
for (node = keyblock; node; node = node->next)
valid_uids +=
node->pkt->pkttype == PKT_USER_ID
&& ! node->pkt->pkt.user_id->flags.revoked
&& ! node->pkt->pkt.user_id->flags.expired;
valid_uids += (node->pkt->pkttype == PKT_USER_ID
&& !node->pkt->pkt.user_id->flags.revoked
&& !node->pkt->pkt.user_id->flags.expired);
/* Find the right UID. */
revlen = strlen (uidtorev);
/* find the right UID */
for (node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_USER_ID
@ -3046,7 +3034,8 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
&& ! node->pkt->pkt.user_id->flags.revoked
&& ! node->pkt->pkt.user_id->flags.expired)
{
log_error (_("Cannot revoke the last valid user ID.\n"));
log_error (_("cannot revoke the last valid user ID.\n"));
err = gpg_error (GPG_ERR_INV_USER_ID);
goto leave;
}
@ -3054,11 +3043,7 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
err = core_revuid (ctrl, keyblock, node, reason, &modified);
release_revocation_reason_info (reason);
if (err)
{
log_error (_("User ID revocation failed: %s\n"),
gpg_strerror (err));
goto leave;
}
goto leave;
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err)
{
@ -3066,13 +3051,81 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
goto leave;
}
if (update_trust)
revalidation_mark ();
revalidation_mark ();
goto leave;
}
}
err = gpg_error (GPG_ERR_NO_USER_ID);
log_error (_("User ID revocation failed: %s\n"), gpg_strerror (GPG_ERR_NOT_FOUND));
leave:
if (err)
log_error (_("revoking the user ID failed: %s\n"), gpg_strerror (err));
release_kbnode (keyblock);
keydb_release (kdbhd);
}
/* Unattended setting of the primary uid. USERNAME specifies the key.
PRIMARYUID is the user id which shall be primary. */
void
keyedit_quick_set_primary (ctrl_t ctrl, const char *username,
const char *primaryuid)
{
gpg_error_t err;
KEYDB_HANDLE kdbhd = NULL;
kbnode_t keyblock = NULL;
kbnode_t node;
size_t primaryuidlen;
int any;
#ifdef HAVE_W32_SYSTEM
/* See keyedit_menu for why we need this. */
check_trustdb_stale (ctrl);
#endif
err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
if (err)
goto leave;
/* Find and mark the UID - we mark only the first valid one. */
primaryuidlen = strlen (primaryuid);
any = 0;
for (node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_USER_ID
&& !any
&& !node->pkt->pkt.user_id->flags.revoked
&& !node->pkt->pkt.user_id->flags.expired
&& primaryuidlen == node->pkt->pkt.user_id->len
&& !memcmp (node->pkt->pkt.user_id->name, primaryuid, primaryuidlen))
{
node->flag |= NODFLG_SELUID;
any = 1;
}
else
node->flag &= ~NODFLG_SELUID;
}
if (!any)
err = gpg_error (GPG_ERR_NO_USER_ID);
else if (menu_set_primary_uid (keyblock))
{
merge_keys_and_selfsig (keyblock);
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));
goto leave;
}
revalidation_mark ();
}
else
err = gpg_error (GPG_ERR_GENERAL);
if (err)
log_error (_("setting the primary user ID failed: %s\n"),
gpg_strerror (err));
leave:
release_kbnode (keyblock);
@ -5205,7 +5258,7 @@ change_primary_uid_cb (PKT_signature * sig, void *opaque)
/*
* Set the primary uid flag for the selected UID. We will also reset
* all other primary uid flags. For this to work with have to update
* all other primary uid flags. For this to work we have to update
* all the signature timestamps. If we would do this with the current
* time, we lose quite a lot of information, so we use a kludge to
* do this: Just increment the timestamp by one second which is

View File

@ -300,6 +300,8 @@ void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
strlist_t uids, strlist_t locusr, int local);
void keyedit_quick_set_expire (ctrl_t ctrl,
const char *fpr, const char *expirestr);
void keyedit_quick_set_primary (ctrl_t ctrl, const char *username,
const char *primaryuid);
void show_basic_key_info (KBNODE keyblock);
/*-- keygen.c --*/