aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2016-07-01 14:50:12 +0000
committerWerner Koch <[email protected]>2016-07-01 14:50:12 +0000
commit7bfc86c938d11c14ea78b196c82ceba2a2f5317d (patch)
tree00e1e8b7b2c1bab6c449ffb396742c034162f585
parentgpg: New option --import-filter (diff)
downloadgnupg-7bfc86c938d11c14ea78b196c82ceba2a2f5317d.tar.gz
gnupg-7bfc86c938d11c14ea78b196c82ceba2a2f5317d.zip
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 <[email protected]>
-rw-r--r--doc/gpg.texi12
-rw-r--r--g10/export.c126
-rw-r--r--g10/gpg.c7
-rw-r--r--g10/main.h1
4 files changed, 141 insertions, 5 deletions
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 9a0622199..7118e0d1c 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -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:
diff --git a/g10/export.c b/g10/export.c
index 413723510..2a50b3232 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -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;
diff --git a/g10/gpg.c b/g10/gpg.c
index 009b84c0b..154d39a23 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -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))
{
diff --git a/g10/main.h b/g10/main.h
index 58f2a73f8..3ee276202 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -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);