1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-05-31 22:18:03 +02:00

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} @item --quick-revoke-uid @var{user-id} @var{user-id-to-revoke}
@opindex quick-revoke-uid @opindex quick-revoke-uid
This command revokes a User ID on an existing key. It cannot be used 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 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 remain), with revocation reason ``User ID is no longer valid''. If
you want to specify a different revocation reason, or to supply you want to specify a different revocation reason, or to supply
supplementary revocation text, you should use the interactive supplementary revocation text, you should use the interactive
sub-command @code{revuid} of @option{--edit-key}. 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 @opindex change-passphrase
@itemx --passwd @var{user_id} @itemx --passwd @var{user-id}
@opindex passwd @opindex passwd
Change the passphrase of the secret key belonging to the certificate 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. @code{passwd} of the edit key menu.
@end table @end table
@ -1767,7 +1776,7 @@ when verifying signatures made by keys that are not on the local
keyring. keyring.
If the method "wkd" is included in the list of methods given to 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, signature, and the option @option{--disable-signer-uid} is not used,
the "wkd" method may also be used to retrieve a key. 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) /* gpg.c - The GnuPG utility (main for gpg)
* Copyright (C) 1998-2011 Free Software Foundation, Inc. * Copyright (C) 1998-2011 Free Software Foundation, Inc.
* Copyright (C) 1997-2016 Werner Koch * Copyright (C) 1997-2017 Werner Koch
* Copyright (C) 2015-2016 g10 Code GmbH * Copyright (C) 2015-2017 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -124,6 +124,7 @@ enum cmd_and_opt_values
aQuickAddKey, aQuickAddKey,
aQuickRevUid, aQuickRevUid,
aQuickSetExpire, aQuickSetExpire,
aQuickSetPrimaryUid,
aListConfig, aListConfig,
aListGcryptConfig, aListGcryptConfig,
aGPGConfList, aGPGConfList,
@ -460,6 +461,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aQuickRevUid, "quick-revuid", "@"), ARGPARSE_c (aQuickRevUid, "quick-revuid", "@"),
ARGPARSE_c (aQuickSetExpire, "quick-set-expire", ARGPARSE_c (aQuickSetExpire, "quick-set-expire",
N_("quickly set a new expiration date")), N_("quickly set a new expiration date")),
ARGPARSE_c (aQuickSetPrimaryUid, "quick-set-primary-uid", "@"),
ARGPARSE_c (aFullKeygen, "full-generate-key" , ARGPARSE_c (aFullKeygen, "full-generate-key" ,
N_("full featured key pair generation")), N_("full featured key pair generation")),
ARGPARSE_c (aFullKeygen, "full-gen-key", "@"), ARGPARSE_c (aFullKeygen, "full-gen-key", "@"),
@ -2581,6 +2583,7 @@ main (int argc, char **argv)
case aQuickAddKey: case aQuickAddKey:
case aQuickRevUid: case aQuickRevUid:
case aQuickSetExpire: case aQuickSetExpire:
case aQuickSetPrimaryUid:
case aExportOwnerTrust: case aExportOwnerTrust:
case aImportOwnerTrust: case aImportOwnerTrust:
case aRebuildKeydbCaches: case aRebuildKeydbCaches:
@ -4002,6 +4005,7 @@ main (int argc, char **argv)
case aQuickAddUid: case aQuickAddUid:
case aQuickAddKey: case aQuickAddKey:
case aQuickRevUid: case aQuickRevUid:
case aQuickSetPrimaryUid:
case aFullKeygen: case aFullKeygen:
case aKeygen: case aKeygen:
case aImport: case aImport:
@ -4445,6 +4449,18 @@ main (int argc, char **argv)
} }
break; 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: case aFastImport:
opt.import_options |= IMPORT_FAST; opt.import_options |= IMPORT_FAST;
case aImport: case aImport:

View File

@ -1,6 +1,6 @@
/* keyedit.c - Edit properties of a key /* keyedit.c - Edit properties of a key
* Copyright (C) 1998-2010 Free Software Foundation, Inc. * 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 * Copyright (C) 2015, 2016 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
@ -2860,36 +2860,28 @@ leave:
} }
/* Unattended adding of a new keyid. USERNAME specifies the /* Helper for quick commands to find the keyblock for USERNAME.
key. NEWUID is the new user id to add to the key. */ * Returns on success the key database handle at R_KDBHD and the
void * keyblock at R_KEYBLOCK. */
keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid) 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; gpg_error_t err;
KEYDB_HANDLE kdbhd = NULL; KEYDB_HANDLE kdbhd = NULL;
KEYDB_SEARCH_DESC desc;
kbnode_t keyblock = NULL; kbnode_t keyblock = NULL;
KEYDB_SEARCH_DESC desc;
kbnode_t node; kbnode_t node;
char *uidstring = NULL;
uidstring = xstrdup (newuid); *r_kdbhd = NULL;
trim_spaces (uidstring); *r_keyblock = NULL;
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. */ /* Search the key; we don't want the whole getkey stuff here. */
kdbhd = keydb_new (); kdbhd = keydb_new ();
if (!kdbhd) if (!kdbhd)
{ {
/* Note that keydb_new has already used log_error. */ /* Note that keydb_new has already used log_error. */
err = gpg_error_from_syserror ();
goto leave; goto leave;
} }
@ -2917,24 +2909,65 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
if (!err) 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); node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
if (!node) log_assert (node);
BUG ();
err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key); 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) if (err)
{ {
log_error (_("secret key \"%s\" not found: %s\n"), log_error (_("key \"%s\" not found: %s\n"),
username, gpg_strerror (err)); username, gpg_strerror (err));
goto leave; goto leave;
} }
fix_keyblock (&keyblock); fix_keyblock (&keyblock);
merge_keys_and_selfsig (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)) if (menu_adduid (ctrl, keyblock, 0, NULL, uidstring))
{ {
err = keydb_update_keyblock (ctrl, kdbhd, keyblock); 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); keydb_release (kdbhd);
} }
/* Unattended revocation of a keyid. USERNAME specifies the /* Unattended revocation of a keyid. USERNAME specifies the
key. UIDTOREV is the user id revoke from the key. */ key. UIDTOREV is the user id revoke from the key. */
void void
@ -2961,7 +2995,6 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
{ {
gpg_error_t err; gpg_error_t err;
KEYDB_HANDLE kdbhd = NULL; KEYDB_HANDLE kdbhd = NULL;
KEYDB_SEARCH_DESC desc;
kbnode_t keyblock = NULL; kbnode_t keyblock = NULL;
kbnode_t node; kbnode_t node;
int modified = 0; int modified = 0;
@ -2974,65 +3007,20 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
#endif #endif
/* Search the key; we don't want the whole getkey stuff here. */ /* Search the key; we don't want the whole getkey stuff here. */
kdbhd = keydb_new (); err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
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);
}
}
if (err) if (err)
{ goto leave;
log_error (_("secret key \"%s\" not found: %s\n"),
username, gpg_strerror (err));
goto leave;
}
fix_keyblock (&keyblock);
merge_keys_and_selfsig (keyblock);
/* Too make sure that we do not revoke the last valid UID, we first /* Too make sure that we do not revoke the last valid UID, we first
count how many valid UIDs there are. */ count how many valid UIDs there are. */
valid_uids = 0; valid_uids = 0;
for (node = keyblock; node; node = node->next) for (node = keyblock; node; node = node->next)
valid_uids += valid_uids += (node->pkt->pkttype == PKT_USER_ID
node->pkt->pkttype == PKT_USER_ID && !node->pkt->pkt.user_id->flags.revoked
&& ! node->pkt->pkt.user_id->flags.revoked && !node->pkt->pkt.user_id->flags.expired);
&& ! node->pkt->pkt.user_id->flags.expired;
/* Find the right UID. */
revlen = strlen (uidtorev); revlen = strlen (uidtorev);
/* find the right UID */
for (node = keyblock; node; node = node->next) for (node = keyblock; node; node = node->next)
{ {
if (node->pkt->pkttype == PKT_USER_ID 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.revoked
&& ! node->pkt->pkt.user_id->flags.expired) && ! 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; 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); err = core_revuid (ctrl, keyblock, node, reason, &modified);
release_revocation_reason_info (reason); release_revocation_reason_info (reason);
if (err) if (err)
{ goto leave;
log_error (_("User ID revocation failed: %s\n"),
gpg_strerror (err));
goto leave;
}
err = keydb_update_keyblock (ctrl, kdbhd, keyblock); err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err) if (err)
{ {
@ -3066,13 +3051,81 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
goto leave; goto leave;
} }
if (update_trust) revalidation_mark ();
revalidation_mark ();
goto leave; 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: leave:
release_kbnode (keyblock); 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 * 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 * 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 * 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 * 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); strlist_t uids, strlist_t locusr, int local);
void keyedit_quick_set_expire (ctrl_t ctrl, void keyedit_quick_set_expire (ctrl_t ctrl,
const char *fpr, const char *expirestr); 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); void show_basic_key_info (KBNODE keyblock);
/*-- keygen.c --*/ /*-- keygen.c --*/