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.
|
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}
|
@item --list-options @var{parameters}
|
||||||
@opindex list-options
|
@opindex list-options
|
||||||
This is a space or comma delimited string that gives options used when
|
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.
|
Self-signatures are not considered.
|
||||||
Currently only implemented for --import-filter.
|
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
|
@end table
|
||||||
|
|
||||||
For the syntax of the expression see the chapter "FILTER EXPRESSIONS".
|
For the syntax of the expression see the chapter "FILTER EXPRESSIONS".
|
||||||
The property names for the expressions depend on the actual filter
|
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:
|
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.
|
The addr-spec part of a user id with mailbox or the empty string.
|
||||||
(keep-uid)
|
(keep-uid)
|
||||||
|
|
||||||
|
@item algostr
|
||||||
|
A string with the key algorithm description. For example "rsa3072"
|
||||||
|
or "ed25519".
|
||||||
|
|
||||||
@item key_algo
|
@item key_algo
|
||||||
A number with the public key algorithm of a key or subkey packet.
|
A number with the public key algorithm of a key or subkey packet.
|
||||||
(drop-subkey)
|
(drop-subkey)
|
||||||
|
|
||||||
|
@item key_size
|
||||||
|
A number with the effective key size of a key or subkey packet.
|
||||||
|
(drop-subkey)
|
||||||
|
|
||||||
@item key_created
|
@item key_created
|
||||||
@itemx key_created_d
|
@itemx key_created_d
|
||||||
The first is the timestamp a public key or subkey packet was
|
The first is the timestamp a public key or subkey packet was
|
||||||
@ -2593,7 +2618,7 @@ The available properties are:
|
|||||||
been revoked.
|
been revoked.
|
||||||
|
|
||||||
@item disabled
|
@item disabled
|
||||||
Boolean indicating whether a primary key is disabled. (not used)
|
Boolean indicating whether a primary key is disabled.
|
||||||
|
|
||||||
@item secret
|
@item secret
|
||||||
Boolean indicating whether a key or subkey is a secret one.
|
Boolean indicating whether a key or subkey is a secret one.
|
||||||
@ -2616,6 +2641,18 @@ The available properties are:
|
|||||||
@item sig_digest_algo
|
@item sig_digest_algo
|
||||||
A number with the digest algorithm of a signature packet. (drop-sig)
|
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
|
@end table
|
||||||
|
|
||||||
@item --export-options @var{parameters}
|
@item --export-options @var{parameters}
|
||||||
|
@ -327,6 +327,7 @@ enum cmd_and_opt_values
|
|||||||
oExportOptions,
|
oExportOptions,
|
||||||
oExportFilter,
|
oExportFilter,
|
||||||
oListOptions,
|
oListOptions,
|
||||||
|
oListFilter,
|
||||||
oVerifyOptions,
|
oVerifyOptions,
|
||||||
oTempDir,
|
oTempDir,
|
||||||
oExecPath,
|
oExecPath,
|
||||||
@ -794,6 +795,7 @@ static gpgrt_opt_t opts[] = {
|
|||||||
ARGPARSE_header ("Keylist", N_("Options controlling key listings")),
|
ARGPARSE_header ("Keylist", N_("Options controlling key listings")),
|
||||||
|
|
||||||
ARGPARSE_s_s (oListOptions, "list-options", "@"),
|
ARGPARSE_s_s (oListOptions, "list-options", "@"),
|
||||||
|
ARGPARSE_s_s (oListFilter, "list-filter", "@"),
|
||||||
ARGPARSE_s_n (oFullTimestrings, "full-timestrings", "@"),
|
ARGPARSE_s_n (oFullTimestrings, "full-timestrings", "@"),
|
||||||
ARGPARSE_s_n (oShowPhotos, "show-photos", "@"),
|
ARGPARSE_s_n (oShowPhotos, "show-photos", "@"),
|
||||||
ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"),
|
ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"),
|
||||||
@ -3357,6 +3359,11 @@ main (int argc, char **argv)
|
|||||||
if (rc)
|
if (rc)
|
||||||
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
|
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
|
||||||
break;
|
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:
|
case oListOptions:
|
||||||
if(!parse_list_options(pargs.r.ret_str))
|
if(!parse_list_options(pargs.r.ret_str))
|
||||||
{
|
{
|
||||||
|
@ -812,3 +812,11 @@ get_revocation_reason (PKT_signature *sig, char **r_reason,
|
|||||||
*r_comment = NULL;
|
*r_comment = NULL;
|
||||||
return 0;
|
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 *
|
const char *
|
||||||
impex_filter_getval (void *cookie, const char *propname)
|
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;
|
kbnode_t node = parm->node;
|
||||||
static char numbuf[20];
|
static char numbuf[20];
|
||||||
const char *result;
|
const char *result;
|
||||||
|
const char *s;
|
||||||
|
enum { scpNone = 0, scpPub, scpSub, scpUid, scpSig} scope = 0;
|
||||||
|
|
||||||
log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC);
|
log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC);
|
||||||
|
|
||||||
if (node->pkt->pkttype == PKT_USER_ID
|
/* We allow a prefix delimited by a slash to limit the scope of the
|
||||||
|| node->pkt->pkttype == PKT_ATTRIBUTE)
|
* 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;
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
||||||
|
|
||||||
@ -1473,7 +1495,8 @@ impex_filter_getval (void *cookie, const char *propname)
|
|||||||
else
|
else
|
||||||
result = NULL;
|
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;
|
PKT_signature *sig = node->pkt->pkt.signature;
|
||||||
|
|
||||||
@ -1503,10 +1526,12 @@ impex_filter_getval (void *cookie, const char *propname)
|
|||||||
else
|
else
|
||||||
result = NULL;
|
result = NULL;
|
||||||
}
|
}
|
||||||
else if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
else if (((node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
|| node->pkt->pkttype == PKT_SECRET_KEY
|
|| node->pkt->pkttype == PKT_SECRET_KEY)
|
||||||
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
&& (!scope || scope == scpPub))
|
||||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|| ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||||
|
&& (!scope || scope == scpSub)))
|
||||||
{
|
{
|
||||||
PKT_public_key *pk = node->pkt->pkt.public_key;
|
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);
|
snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo);
|
||||||
result = numbuf;
|
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"))
|
else if (!strcmp (propname, "key_created"))
|
||||||
{
|
{
|
||||||
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp);
|
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);
|
hexfingerprint (pk, parm->hexfpr, sizeof parm->hexfpr);
|
||||||
result = 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
|
else
|
||||||
result = NULL;
|
result = NULL;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
#include "../common/mbox-util.h"
|
#include "../common/mbox-util.h"
|
||||||
#include "../common/zb32.h"
|
#include "../common/zb32.h"
|
||||||
#include "tofu.h"
|
#include "tofu.h"
|
||||||
|
#include "../common/init.h"
|
||||||
|
#include "../common/recsel.h"
|
||||||
#include "../common/compliance.h"
|
#include "../common/compliance.h"
|
||||||
#include "../common/pkscreening.h"
|
#include "../common/pkscreening.h"
|
||||||
|
|
||||||
@ -64,16 +66,26 @@ struct keylist_context
|
|||||||
int no_validity; /* Do not show validity. */
|
int no_validity; /* Do not show validity. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* An object and a global instance to store selectors created from
|
||||||
static void list_keyblock (ctrl_t ctrl,
|
* --list-filter select=EXPR.
|
||||||
kbnode_t keyblock, int secret, int has_secret,
|
*/
|
||||||
int fpr, struct keylist_context *listctx);
|
struct list_filter_s
|
||||||
|
{
|
||||||
|
recsel_expr_t selkey;
|
||||||
|
};
|
||||||
|
struct list_filter_s list_filter;
|
||||||
|
|
||||||
|
|
||||||
/* The stream used to write attribute packets to. */
|
/* The stream used to write attribute packets to. */
|
||||||
static estream_t attrib_fp;
|
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. */
|
/* Release resources from a keylist context. */
|
||||||
static void
|
static void
|
||||||
keylist_context_release (struct keylist_context *listctx)
|
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.
|
/* 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
|
* 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
|
* 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);
|
do_reorder_keyblock (keyblock, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
list_keyblock (ctrl_t ctrl,
|
list_keyblock (ctrl_t ctrl,
|
||||||
KBNODE keyblock, int secret, int has_secret, int fpr,
|
KBNODE keyblock, int secret, int has_secret, int fpr,
|
||||||
@ -2170,6 +2226,24 @@ list_keyblock (ctrl_t ctrl,
|
|||||||
{
|
{
|
||||||
reorder_keyblock (keyblock);
|
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)
|
if (opt.with_colons)
|
||||||
list_keyblock_colon (ctrl, keyblock, secret, has_secret);
|
list_keyblock_colon (ctrl, keyblock, secret, has_secret);
|
||||||
else if ((opt.list_options & LIST_SHOW_ONLY_FPR_MBOX))
|
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,
|
void public_key_list (ctrl_t ctrl, strlist_t list,
|
||||||
int locate_mode, int no_local);
|
int locate_mode, int no_local);
|
||||||
void secret_key_list (ctrl_t ctrl, strlist_t list );
|
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 print_subpackets_colon(PKT_signature *sig);
|
||||||
void reorder_keyblock (KBNODE keyblock);
|
void reorder_keyblock (KBNODE keyblock);
|
||||||
void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,
|
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;
|
*r_comment = NULL;
|
||||||
return 0;
|
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