gpg: New option --export-filter

* g10/gpg.c (oExportFilter): New.
(opts): Add --export-filter.
(main): Handle option.
* g10/export.c: Include recsel.h, init.h, and mbox-util.h.
(export_keep_uid): New global var.
(cleanup_export_globals): New.
(parse_and_set_export_filter): New.
(filter_getval): New.
(apply_keep_uid_filter): New.
(do_export_stream): Apply filter if set.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2016-07-01 16:50:12 +02:00
parent 5137bf73cc
commit 7bfc86c938
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
4 changed files with 141 additions and 5 deletions

View File

@ -2219,12 +2219,14 @@ opposite meaning. The options are:
@end table
@item --import-filter @code{@var{name}=@var{expr}}
@itemx --export-filter @code{@var{name}=@var{expr}}
@opindex import-filter
This option defines an import filter which is implied to the imported
keyblock right before it will be stored. @var{name} defines the type
of filter to use, @var{expr} the expression to evaluate. The option
can be used several times which then appends more expression to the
same @var{name}.
@opindex export-filter
These options define an import/export filter which are applied to the
imported/exported keyblock right before it will be stored/written.
@var{name} defines the type of filter to use, @var{expr} the
expression to evaluate. The option can be used several times which
then appends more expression to the same @var{name}.
@noindent
The available filter types are:

View File

@ -35,6 +35,9 @@
#include "i18n.h"
#include "membuf.h"
#include "host2net.h"
#include "recsel.h"
#include "mbox-util.h"
#include "init.h"
#include "trustdb.h"
#include "call-agent.h"
@ -56,6 +59,16 @@ struct export_stats_s
};
/* A global variable to store the selector created from
* --export-filter keep-uid=EXPR.
*
* FIXME: We should put this into the CTRL object but that requires a
* lot more changes right now.
*/
static recsel_expr_t export_keep_uid;
/* Local prototypes. */
static int do_export (ctrl_t ctrl, strlist_t users, int secret,
unsigned int options, export_stats_t stats);
@ -65,6 +78,12 @@ static int do_export_stream (ctrl_t ctrl, iobuf_t out,
export_stats_t stats, int *any);
static void
cleanup_export_globals (void)
{
recsel_release (export_keep_uid);
export_keep_uid = NULL;
}
/* Option parser for export options. See parse_options fro
@ -100,6 +119,38 @@ parse_export_options(char *str,unsigned int *options,int noisy)
}
/* Parse and set an export 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 called several
* times all expressions for the same NAME are concatenated.
* Supported filter names are:
*
* - keep-uid :: If the expression evaluates to true for a certain
* user ID packet, that packet and all it dependencies
* will be exported. The expression may use these
* variables:
*
* - uid :: The entire user ID.
* - mbox :: The mail box part of the user ID.
* - primary :: Evaluate to true for the primary user ID.
*/
gpg_error_t
parse_and_set_export_filter (const char *string)
{
gpg_error_t err;
/* Auto register the cleanup function. */
register_mem_cleanup_func (cleanup_export_globals);
if (!strncmp (string, "keep-uid=", 9))
err = recsel_parse_expr (&export_keep_uid, string+9);
else
err = gpg_error (GPG_ERR_INV_NAME);
return err;
}
/* Create a new export stats object initialized to zero. On error
returns NULL and sets ERRNO. */
export_stats_t
@ -1147,6 +1198,74 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
}
/* Helper for apply_keep_uid_filter. */
static const char *
filter_getval (void *cookie, const char *propname)
{
kbnode_t node = cookie;
const char *result;
if (node->pkt->pkttype == PKT_USER_ID)
{
if (!strcmp (propname, "uid"))
result = node->pkt->pkt.user_id->name;
else if (!strcmp (propname, "mbox"))
{
if (!node->pkt->pkt.user_id->mbox)
{
node->pkt->pkt.user_id->mbox
= mailbox_from_userid (node->pkt->pkt.user_id->name);
}
return node->pkt->pkt.user_id->mbox;
}
else if (!strcmp (propname, "primary"))
result = node->pkt->pkt.user_id->is_primary? "1":"0";
else
result = NULL;
}
else
result = NULL;
return result;
}
/*
* Apply the keep-uid filter to the keyblock. The deleted nodes are
* marked and thus the caller should call commit_kbnode afterwards.
* KEYBLOCK must not have any blocks marked as deleted.
*/
static void
apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
{
kbnode_t node;
for (node = keyblock->next; node; node = node->next )
{
if (node->pkt->pkttype == PKT_USER_ID)
{
if (!recsel_select (selector, filter_getval, node))
{
log_debug ("keep-uid: deleting '%s'\n",
node->pkt->pkt.user_id->name);
/* The UID packet and all following packets up to the
* next UID or a subkey. */
delete_kbnode (node);
for (; node->next
&& node->next->pkt->pkttype != PKT_USER_ID
&& node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
&& node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
node = node->next)
delete_kbnode (node->next);
}
else
log_debug ("keep-uid: keeping '%s'\n",
node->pkt->pkt.user_id->name);
}
}
}
/* Export the keys identified by the list of strings in USERS to the
stream OUT. If Secret is false public keys will be exported. With
secret true secret keys will be exported; in this case 1 means the
@ -1326,6 +1445,13 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
if ((options & EXPORT_CLEAN))
clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL);
if (export_keep_uid)
{
commit_kbnode (&keyblock);
apply_keep_uid_filter (keyblock, export_keep_uid);
commit_kbnode (&keyblock);
}
/* And write it. */
xfree (cache_nonce);
cache_nonce = NULL;

View File

@ -302,6 +302,7 @@ enum cmd_and_opt_values
oImportOptions,
oImportFilter,
oExportOptions,
oExportFilter,
oListOptions,
oVerifyOptions,
oTempDir,
@ -575,6 +576,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oImportOptions, "import-options", "@"),
ARGPARSE_s_s (oImportFilter, "import-filter", "@"),
ARGPARSE_s_s (oExportOptions, "export-options", "@"),
ARGPARSE_s_s (oExportFilter, "export-filter", "@"),
ARGPARSE_s_s (oListOptions, "list-options", "@"),
ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"),
@ -3049,6 +3051,11 @@ main (int argc, char **argv)
log_error(_("invalid export options\n"));
}
break;
case oExportFilter:
rc = parse_and_set_export_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))
{

View File

@ -379,6 +379,7 @@ void export_release_stats (export_stats_t stats);
void export_print_stats (export_stats_t stats);
int parse_export_options(char *str,unsigned int *options,int noisy);
gpg_error_t parse_and_set_export_filter (const char *string);
int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
export_stats_t stats);