diff options
Diffstat (limited to 'g10/export.c')
-rw-r--r-- | g10/export.c | 144 |
1 files changed, 136 insertions, 8 deletions
diff --git a/g10/export.c b/g10/export.c index e98af59..398b130 100644 --- a/g10/export.c +++ b/g10/export.c @@ -62,15 +62,17 @@ struct export_stats_s }; -/* A global variable to store the selector created from +/* Global variables to store the selectors created from * --export-filter keep-uid=EXPR. * --export-filter drop-subkey=EXPR. + * --export-filter select=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; static recsel_expr_t export_drop_subkey; +static recsel_expr_t export_select_filter; /* An object used for a linked list to implement the @@ -80,6 +82,7 @@ struct export_filter_attic_s struct export_filter_attic_s *next; recsel_expr_t export_keep_uid; recsel_expr_t export_drop_subkey; + recsel_expr_t export_select_filter; }; static struct export_filter_attic_s *export_filter_attic; @@ -105,6 +108,8 @@ cleanup_export_globals (void) export_keep_uid = NULL; recsel_release (export_drop_subkey); export_drop_subkey = NULL; + recsel_release (export_select_filter); + export_select_filter = NULL; } @@ -129,6 +134,9 @@ parse_export_options(char *str,unsigned int *options,int noisy) {"export-pka", EXPORT_PKA_FORMAT, NULL, NULL }, {"export-dane", EXPORT_DANE_FORMAT, NULL, NULL }, + {"export-revocs", EXPORT_REVOCS, NULL, + N_("export only revocation certificates") }, + {"backup", EXPORT_BACKUP, NULL, N_("use the GnuPG key backup format")}, {"export-backup", EXPORT_BACKUP, NULL, NULL }, @@ -181,6 +189,8 @@ parse_export_options(char *str,unsigned int *options,int noisy) * * - secret :: 1 for a secret subkey, else 0. * - key_algo :: Public key algorithm id + * + * - select :: The key is only exported if the filter returns true. */ gpg_error_t parse_and_set_export_filter (const char *string) @@ -194,6 +204,8 @@ parse_and_set_export_filter (const char *string) err = recsel_parse_expr (&export_keep_uid, string+9); else if (!strncmp (string, "drop-subkey=", 12)) err = recsel_parse_expr (&export_drop_subkey, string+12); + else if (!strncmp (string, "select=", 7)) + err = recsel_parse_expr (&export_select_filter, string+7); else err = gpg_error (GPG_ERR_INV_NAME); @@ -214,6 +226,8 @@ push_export_filters (void) export_keep_uid = NULL; item->export_drop_subkey = export_drop_subkey; export_drop_subkey = NULL; + item->export_select_filter = export_select_filter; + export_select_filter = NULL; item->next = export_filter_attic; export_filter_attic = item; } @@ -232,6 +246,7 @@ pop_export_filters (void) cleanup_export_globals (); export_keep_uid = item->export_keep_uid; export_drop_subkey = item->export_drop_subkey; + export_select_filter = item->export_select_filter; } @@ -1812,8 +1827,18 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, hexgrip, pk); if (err) { - if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) + /* If we receive a fully canceled error we stop + * immediately. If we receive a cancel for a public + * key we also stop immediately because a + * public/secret key is always required first + * (right, we could instead write a stub key but + * that is also kind of surprising). If we receive + * a subkey we skip to the next subkey. */ + if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED + || (node->pkt->pkttype == PKT_PUBLIC_KEY + && gpg_err_code (err) == GPG_ERR_CANCELED)) goto leave; + write_status_error ("export_keys.secret", err); skip_until_subkey = 1; err = 0; } @@ -1884,6 +1909,78 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, } +/* Helper for do_export_stream which writes the own revocations + * certificates (if any) from KEYBLOCK to OUT. */ +static gpg_error_t +do_export_revocs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, + iobuf_t out, unsigned int options, int *any) +{ + gpg_error_t err = 0; + kbnode_t kbctx, node; + PKT_signature *sig; + + (void)ctrl; + + /* NB: walk_kbnode skips packets marked as deleted. */ + for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) + { + if (node->pkt->pkttype != PKT_SIGNATURE) + continue; + sig = node->pkt->pkt.signature; + + /* We are only interested in revocation certifcates. */ + if (!(IS_KEY_REV (sig) || IS_UID_REV (sig) || IS_SUBKEY_REV (sig))) + continue; + + if (!(sig->keyid[0] == keyid[0] && sig->keyid[1] == keyid[1])) + continue; /* Not a self-signature. */ + + /* Do not export signature packets which are marked as not + * exportable. */ + if (!(options & EXPORT_LOCAL_SIGS) + && !sig->flags.exportable) + continue; /* not exportable */ + + /* Do not export packets with a "sensitive" revocation key + * unless the user wants us to. */ + if (!(options & EXPORT_SENSITIVE_REVKEYS) + && sig->revkey) + { + int i; + + for (i = 0; i < sig->numrevkeys; i++) + if ((sig->revkey[i].class & 0x40)) + break; + if (i < sig->numrevkeys) + continue; + } + + if (!sig->flags.checked) + { + log_info ("signature not marked as checked - ignored\n"); + continue; + } + if (!sig->flags.valid) + { + log_info ("signature not not valid - ignored\n"); + continue; + } + + err = build_packet (out, node->pkt); + if (err) + { + log_error ("build_packet(%d) failed: %s\n", + node->pkt->pkttype, gpg_strerror (err)); + goto leave; + } + *any = 1; + } + + leave: + return err; +} + + /* 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 @@ -2069,6 +2166,32 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, NULL, NULL); commit_kbnode (&keyblock); } + else if (export_keep_uid || export_drop_subkey || export_select_filter) + { + /* Need to merge so that for example the "usage" property + * has been setup. */ + merge_keys_and_selfsig (ctrl, keyblock); + } + + + if (export_select_filter) + { + 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 (export_select_filter, + impex_filter_getval, &parm)) + { + selected = 1; + break; + } + } + if (!selected) + continue; /* Skip this keyblock. */ + } if (export_keep_uid) { @@ -2085,10 +2208,15 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, } /* And write it. */ - err = do_export_one_keyblock (ctrl, keyblock, keyid, - out_help? out_help : out, - secret, options, stats, any, - desc, ndesc, descindex, cipherhd); + if ((options & EXPORT_REVOCS)) + err = do_export_revocs (ctrl, keyblock, keyid, + out_help? out_help : out, + options, any); + else + err = do_export_one_keyblock (ctrl, keyblock, keyid, + out_help? out_help : out, + secret, options, stats, any, + desc, ndesc, descindex, cipherhd); if (err) break; @@ -2131,8 +2259,8 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, keydb_release (kdbhd); if (err || !keyblock_out) release_kbnode( keyblock ); - if( !*any ) - log_info(_("WARNING: nothing exported\n")); + if( !*any && !opt.quiet) + log_info (_("WARNING: nothing exported\n")); return err; } |