mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
gpg: New option --list-filter
* g10/gpg.c (oListFilter): New. (opts): Add --list-filter. (main): Parse oListFilter. * g10/keylist.c: Include init.h and recsel.h. (struct list_filter_s, list_filter): New. (release_list_filter): New. (cleanup_keylist_globals): New. (parse_and_set_list_filter): New. (list_keyblock): Implement --list-filter type "select". * g10/import.c (impex_filter_getval): Add scope support and new property names "key-size", "algostr", "origin", "lastupd", and "url". -- This option is pretty useful to select keys based on their properties. The scope thing can be sued to limit a selection to just the primary key or to subkeys. For example: gpg -k --list-filter 'select=revoked-f && sub/algostr=ed25519' Lists all non-revoked keys with an ed25519 (signing)-subkey.
This commit is contained in:
parent
d70779bdc6
commit
1324dc3490
41
doc/gpg.texi
41
doc/gpg.texi
@ -1338,6 +1338,13 @@ Assume "yes" on most questions. Should not be used in an option file.
|
||||
Assume "no" on most questions. Should not be used in an option file.
|
||||
|
||||
|
||||
@item --list-filter @{select=@var{expr}@}
|
||||
@opindex list-filter
|
||||
A list filter can be used to output only certain keys during key
|
||||
listsin command. For the availbale property names, see the description
|
||||
of @option{--import-filter}.
|
||||
|
||||
|
||||
@item --list-options @var{parameters}
|
||||
@opindex list-options
|
||||
This is a space or comma delimited string that gives options used when
|
||||
@ -2550,11 +2557,21 @@ The available filter types are:
|
||||
Self-signatures are not considered.
|
||||
Currently only implemented for --import-filter.
|
||||
|
||||
@item select
|
||||
This filter is only implemented by @option{--list-filter}. All
|
||||
property names may be used.
|
||||
|
||||
@end table
|
||||
|
||||
For the syntax of the expression see the chapter "FILTER EXPRESSIONS".
|
||||
The property names for the expressions depend on the actual filter
|
||||
type and are indicated in the following table.
|
||||
type and are indicated in the following table. Note that all property
|
||||
names may also be used by @option{--list-filter}.
|
||||
|
||||
Property names may be prefix with a scope delimited by a slash. Valid
|
||||
scopes are "pub" for public and secret primary keys, "sub" for public
|
||||
and secret subkeys, "uid" for for user-ID packets, and "sig" for
|
||||
signature packets. Invalid scopes are currently ignored.
|
||||
|
||||
The available properties are:
|
||||
|
||||
@ -2567,10 +2584,18 @@ The available properties are:
|
||||
The addr-spec part of a user id with mailbox or the empty string.
|
||||
(keep-uid)
|
||||
|
||||
@item algostr
|
||||
A string with the key algorithm description. For example "rsa3072"
|
||||
or "ed25519".
|
||||
|
||||
@item key_algo
|
||||
A number with the public key algorithm of a key or subkey packet.
|
||||
(drop-subkey)
|
||||
|
||||
@item key_size
|
||||
A number with the effective key size of a key or subkey packet.
|
||||
(drop-subkey)
|
||||
|
||||
@item key_created
|
||||
@itemx key_created_d
|
||||
The first is the timestamp a public key or subkey packet was
|
||||
@ -2593,7 +2618,7 @@ The available properties are:
|
||||
been revoked.
|
||||
|
||||
@item disabled
|
||||
Boolean indicating whether a primary key is disabled. (not used)
|
||||
Boolean indicating whether a primary key is disabled.
|
||||
|
||||
@item secret
|
||||
Boolean indicating whether a key or subkey is a secret one.
|
||||
@ -2616,6 +2641,18 @@ The available properties are:
|
||||
@item sig_digest_algo
|
||||
A number with the digest algorithm of a signature packet. (drop-sig)
|
||||
|
||||
@item origin
|
||||
A string with the key origin or a question mark. For example the
|
||||
string ``wkd'' is used if a key originated from a Web Key Directory
|
||||
lookup.
|
||||
|
||||
@item lastupd
|
||||
The timestamp the key was last updated from a keyserver or the Web
|
||||
Key Directory.
|
||||
|
||||
@item url
|
||||
A string with the the URL associated wit the last key lookup.
|
||||
|
||||
@end table
|
||||
|
||||
@item --export-options @var{parameters}
|
||||
|
@ -327,6 +327,7 @@ enum cmd_and_opt_values
|
||||
oExportOptions,
|
||||
oExportFilter,
|
||||
oListOptions,
|
||||
oListFilter,
|
||||
oVerifyOptions,
|
||||
oTempDir,
|
||||
oExecPath,
|
||||
@ -794,6 +795,7 @@ static gpgrt_opt_t opts[] = {
|
||||
ARGPARSE_header ("Keylist", N_("Options controlling key listings")),
|
||||
|
||||
ARGPARSE_s_s (oListOptions, "list-options", "@"),
|
||||
ARGPARSE_s_s (oListFilter, "list-filter", "@"),
|
||||
ARGPARSE_s_n (oFullTimestrings, "full-timestrings", "@"),
|
||||
ARGPARSE_s_n (oShowPhotos, "show-photos", "@"),
|
||||
ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"),
|
||||
@ -3357,6 +3359,11 @@ main (int argc, char **argv)
|
||||
if (rc)
|
||||
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
|
||||
break;
|
||||
case oListFilter:
|
||||
rc = parse_and_set_list_filter (pargs.r.ret_str);
|
||||
if (rc)
|
||||
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
|
||||
break;
|
||||
case oListOptions:
|
||||
if(!parse_list_options(pargs.r.ret_str))
|
||||
{
|
||||
|
@ -812,3 +812,11 @@ get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||
*r_comment = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
impex_filter_getval (void *cookie, const char *propname)
|
||||
{
|
||||
(void)cookie;
|
||||
(void)propname;
|
||||
return NULL;
|
||||
}
|
||||
|
71
g10/import.c
71
g10/import.c
@ -1430,7 +1430,8 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
|
||||
}
|
||||
|
||||
|
||||
/* Helper for apply_*_filter in import.c and export.c. */
|
||||
/* Helper for apply_*_filter in import.c and export.c and also used by
|
||||
* keylist.c. */
|
||||
const char *
|
||||
impex_filter_getval (void *cookie, const char *propname)
|
||||
{
|
||||
@ -1440,11 +1441,32 @@ impex_filter_getval (void *cookie, const char *propname)
|
||||
kbnode_t node = parm->node;
|
||||
static char numbuf[20];
|
||||
const char *result;
|
||||
const char *s;
|
||||
enum { scpNone = 0, scpPub, scpSub, scpUid, scpSig} scope = 0;
|
||||
|
||||
log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC);
|
||||
|
||||
if (node->pkt->pkttype == PKT_USER_ID
|
||||
|| node->pkt->pkttype == PKT_ATTRIBUTE)
|
||||
/* We allow a prefix delimited by a slash to limit the scope of the
|
||||
* keyword. Note that "pub" also includes "sec" and "sub" includes
|
||||
* "ssb". */
|
||||
if ((s=strchr (propname, '/')) && s != propname)
|
||||
{
|
||||
size_t n = s - propname;
|
||||
if (!strncmp (propname, "pub", n))
|
||||
scope = scpPub;
|
||||
else if (!strncmp (propname, "sub", n))
|
||||
scope = scpSub;
|
||||
else if (!strncmp (propname, "uid", n))
|
||||
scope = scpUid;
|
||||
else if (!strncmp (propname, "sig", n))
|
||||
scope = scpSig;
|
||||
|
||||
propname = s + 1;
|
||||
}
|
||||
|
||||
if ((node->pkt->pkttype == PKT_USER_ID
|
||||
|| node->pkt->pkttype == PKT_ATTRIBUTE)
|
||||
&& (!scope || scope == scpUid))
|
||||
{
|
||||
PKT_user_id *uid = node->pkt->pkt.user_id;
|
||||
|
||||
@ -1473,7 +1495,8 @@ impex_filter_getval (void *cookie, const char *propname)
|
||||
else
|
||||
result = NULL;
|
||||
}
|
||||
else if (node->pkt->pkttype == PKT_SIGNATURE)
|
||||
else if (node->pkt->pkttype == PKT_SIGNATURE
|
||||
&& (!scope || scope == scpSig))
|
||||
{
|
||||
PKT_signature *sig = node->pkt->pkt.signature;
|
||||
|
||||
@ -1503,10 +1526,12 @@ impex_filter_getval (void *cookie, const char *propname)
|
||||
else
|
||||
result = NULL;
|
||||
}
|
||||
else if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_KEY
|
||||
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
else if (((node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_KEY)
|
||||
&& (!scope || scope == scpPub))
|
||||
|| ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||
&& (!scope || scope == scpSub)))
|
||||
{
|
||||
PKT_public_key *pk = node->pkt->pkt.public_key;
|
||||
|
||||
@ -1520,6 +1545,16 @@ impex_filter_getval (void *cookie, const char *propname)
|
||||
snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo);
|
||||
result = numbuf;
|
||||
}
|
||||
else if (!strcmp (propname, "key_size"))
|
||||
{
|
||||
snprintf (numbuf, sizeof numbuf, "%u", nbits_from_pk (pk));
|
||||
result = numbuf;
|
||||
}
|
||||
else if (!strcmp (propname, "algostr"))
|
||||
{
|
||||
pubkey_string (pk, parm->hexfpr, sizeof parm->hexfpr);
|
||||
result = parm->hexfpr;
|
||||
}
|
||||
else if (!strcmp (propname, "key_created"))
|
||||
{
|
||||
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp);
|
||||
@ -1556,6 +1591,26 @@ impex_filter_getval (void *cookie, const char *propname)
|
||||
hexfingerprint (pk, parm->hexfpr, sizeof parm->hexfpr);
|
||||
result = parm->hexfpr;
|
||||
}
|
||||
else if (!strcmp (propname, "origin"))
|
||||
{
|
||||
result = key_origin_string (pk->keyorg);
|
||||
}
|
||||
else if (!strcmp (propname, "lastupd"))
|
||||
{
|
||||
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->keyupdate);
|
||||
result = numbuf;
|
||||
}
|
||||
else if (!strcmp (propname, "url"))
|
||||
{
|
||||
if (pk->updateurl && *pk->updateurl)
|
||||
{
|
||||
/* Fixme: This might get truncated. */
|
||||
mem2str (parm->hexfpr, pk->updateurl, sizeof parm->hexfpr);
|
||||
result = parm->hexfpr;
|
||||
}
|
||||
else
|
||||
result = "";
|
||||
}
|
||||
else
|
||||
result = NULL;
|
||||
}
|
||||
|
@ -44,6 +44,8 @@
|
||||
#include "../common/mbox-util.h"
|
||||
#include "../common/zb32.h"
|
||||
#include "tofu.h"
|
||||
#include "../common/init.h"
|
||||
#include "../common/recsel.h"
|
||||
#include "../common/compliance.h"
|
||||
#include "../common/pkscreening.h"
|
||||
|
||||
@ -64,16 +66,26 @@ struct keylist_context
|
||||
int no_validity; /* Do not show validity. */
|
||||
};
|
||||
|
||||
|
||||
static void list_keyblock (ctrl_t ctrl,
|
||||
kbnode_t keyblock, int secret, int has_secret,
|
||||
int fpr, struct keylist_context *listctx);
|
||||
/* An object and a global instance to store selectors created from
|
||||
* --list-filter select=EXPR.
|
||||
*/
|
||||
struct list_filter_s
|
||||
{
|
||||
recsel_expr_t selkey;
|
||||
};
|
||||
struct list_filter_s list_filter;
|
||||
|
||||
|
||||
/* The stream used to write attribute packets to. */
|
||||
static estream_t attrib_fp;
|
||||
|
||||
|
||||
|
||||
|
||||
static void list_keyblock (ctrl_t ctrl,
|
||||
kbnode_t keyblock, int secret, int has_secret,
|
||||
int fpr, struct keylist_context *listctx);
|
||||
|
||||
/* Release resources from a keylist context. */
|
||||
static void
|
||||
keylist_context_release (struct keylist_context *listctx)
|
||||
@ -82,6 +94,49 @@ keylist_context_release (struct keylist_context *listctx)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
release_list_filter (struct list_filter_s *filt)
|
||||
{
|
||||
recsel_release (filt->selkey);
|
||||
filt->selkey = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cleanup_keylist_globals (void)
|
||||
{
|
||||
release_list_filter (&list_filter);
|
||||
}
|
||||
|
||||
|
||||
/* Parse and set an list filter from string. STRING has the format
|
||||
* "NAME=EXPR" with NAME being the name of the filter. Spaces before
|
||||
* and after NAME are not allowed. If this function is all called
|
||||
* several times all expressions for the same NAME are concatenated.
|
||||
* Supported filter names are:
|
||||
*
|
||||
* - select :: If the expression evaluates to true for a certain key
|
||||
* this key will be listed. The expression may use any
|
||||
* variable defined for the export and import filters.
|
||||
*
|
||||
*/
|
||||
gpg_error_t
|
||||
parse_and_set_list_filter (const char *string)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
/* Auto register the cleanup function. */
|
||||
register_mem_cleanup_func (cleanup_keylist_globals);
|
||||
|
||||
if (!strncmp (string, "select=", 7))
|
||||
err = recsel_parse_expr (&list_filter.selkey, string+7);
|
||||
else
|
||||
err = gpg_error (GPG_ERR_INV_NAME);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* List the keys. If list is NULL, all available keys are listed.
|
||||
* With LOCATE_MODE set the locate algorithm is used to find a key; if
|
||||
* in addition NO_LOCAL is set the locate does not look into the local
|
||||
@ -2163,6 +2218,7 @@ reorder_keyblock (KBNODE keyblock)
|
||||
do_reorder_keyblock (keyblock, 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
list_keyblock (ctrl_t ctrl,
|
||||
KBNODE keyblock, int secret, int has_secret, int fpr,
|
||||
@ -2170,6 +2226,24 @@ list_keyblock (ctrl_t ctrl,
|
||||
{
|
||||
reorder_keyblock (keyblock);
|
||||
|
||||
if (list_filter.selkey)
|
||||
{
|
||||
int selected = 0;
|
||||
struct impex_filter_parm_s parm;
|
||||
parm.ctrl = ctrl;
|
||||
|
||||
for (parm.node = keyblock; parm.node; parm.node = parm.node->next)
|
||||
{
|
||||
if (recsel_select (list_filter.selkey, impex_filter_getval, &parm))
|
||||
{
|
||||
selected = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!selected)
|
||||
return; /* Skip this one. */
|
||||
}
|
||||
|
||||
if (opt.with_colons)
|
||||
list_keyblock_colon (ctrl, keyblock, secret, has_secret);
|
||||
else if ((opt.list_options & LIST_SHOW_ONLY_FPR_MBOX))
|
||||
|
@ -464,6 +464,7 @@ void release_revocation_reason_info (struct revocation_reason_info *reason);
|
||||
void public_key_list (ctrl_t ctrl, strlist_t list,
|
||||
int locate_mode, int no_local);
|
||||
void secret_key_list (ctrl_t ctrl, strlist_t list );
|
||||
gpg_error_t parse_and_set_list_filter (const char *string);
|
||||
void print_subpackets_colon(PKT_signature *sig);
|
||||
void reorder_keyblock (KBNODE keyblock);
|
||||
void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,
|
||||
|
@ -572,3 +572,11 @@ get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||
*r_comment = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
impex_filter_getval (void *cookie, const char *propname)
|
||||
{
|
||||
(void)cookie;
|
||||
(void)propname;
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user