* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
/* A global variable to store the selector created from
* --export-filter keep-uid=EXPR.
+ * --export-filter drop-subkey=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;
strlist_t users, int secret,
kbnode_t *keyblock_out, unsigned int options,
export_stats_t stats, int *any);
+static gpg_error_t print_pka_or_dane_records
+/**/ (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk,
+ const void *data, size_t datalen,
+ int print_pka, int print_dane);
\f
static void
{
recsel_release (export_keep_uid);
export_keep_uid = NULL;
+ recsel_release (export_drop_subkey);
+ export_drop_subkey = NULL;
}
* - uid :: The entire user ID.
* - mbox :: The mail box part of the user ID.
* - primary :: Evaluate to true for the primary user ID.
+ *
+ * - drop-subkey :: If the expression evaluates to true for a subkey
+ * packet that subkey and all it dependencies will be
+ * remove from the keyblock. The expression may use these
+ * variables:
+ *
+ * - secret :: 1 for a secret subkey, else 0.
+ * - key_algo :: Public key algorithm id
*/
gpg_error_t
parse_and_set_export_filter (const char *string)
if (!strncmp (string, "keep-uid=", 9))
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
err = gpg_error (GPG_ERR_INV_NAME);
}
-/* Helper for apply_keep_uid_filter. */
-static const char *
-filter_getval (void *cookie, const char *propname)
+/* Write KEYBLOCK either to stdout or to the file set with the
+ * --output option. This is a simplified version of do_export_stream
+ * which supports only a few export options. */
+gpg_error_t
+write_keyblock_to_output (kbnode_t keyblock, int with_armor,
+ unsigned int options)
{
- kbnode_t node = cookie;
- const char *result;
+ gpg_error_t err;
+ const char *fname;
+ iobuf_t out;
+ kbnode_t node;
+ armor_filter_context_t *afx = NULL;
+ iobuf_t out_help = NULL;
+ PKT_public_key *pk = NULL;
- if (node->pkt->pkttype == PKT_USER_ID)
+ fname = opt.outfile? opt.outfile : "-";
+ if (is_secured_filename (fname) )
+ return gpg_error (GPG_ERR_EPERM);
+
+ out = iobuf_create (fname, 0);
+ if (!out)
+ {
+ err = gpg_error_from_syserror ();
+ log_error(_("can't create '%s': %s\n"), fname, gpg_strerror (err));
+ return err;
+ }
+ if (opt.verbose)
+ log_info (_("writing to '%s'\n"), iobuf_get_fname_nonnull (out));
+
+ if ((options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT)))
{
- if (!strcmp (propname, "uid"))
- result = node->pkt->pkt.user_id->name;
- else if (!strcmp (propname, "mbox"))
+ with_armor = 0;
+ out_help = iobuf_temp ();
+ }
+
+ if (with_armor)
+ {
+ afx = new_armor_context ();
+ afx->what = 1;
+ push_armor_filter (afx, out);
+ }
+
+ for (node = keyblock; node; node = node->next)
+ {
+ if (is_deleted_kbnode (node) || node->pkt->pkttype == PKT_RING_TRUST)
+ continue;
+ if (!pk && (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_SECRET_KEY))
+ pk = node->pkt->pkt.public_key;
+
+ err = build_packet (out_help? out_help : out, node->pkt);
+ if (err)
{
- 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;
+ log_error ("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, gpg_strerror (err) );
+ goto leave;
}
- else if (!strcmp (propname, "primary"))
- result = node->pkt->pkt.user_id->is_primary? "1":"0";
- else
- result = NULL;
}
- else
- result = NULL;
+ err = 0;
- return result;
+ if (out_help && pk)
+ {
+ const void *data;
+ size_t datalen;
+
+ iobuf_flush_temp (out_help);
+ data = iobuf_get_temp_buffer (out_help);
+ datalen = iobuf_get_temp_length (out_help);
+
+ err = print_pka_or_dane_records (out,
+ keyblock, pk, data, datalen,
+ (options & EXPORT_PKA_FORMAT),
+ (options & EXPORT_DANE_FORMAT));
+ }
+
+ leave:
+ if (err)
+ iobuf_cancel (out);
+ else
+ iobuf_close (out);
+ iobuf_cancel (out_help);
+ release_armor_context (afx);
+ return err;
}
+
/*
* Apply the keep-uid filter to the keyblock. The deleted nodes are
* marked and thus the caller should call commit_kbnode afterwards.
{
if (node->pkt->pkttype == PKT_USER_ID)
{
- if (!recsel_select (selector, filter_getval, node))
+ if (!recsel_select (selector, impex_filter_getval, node))
{
/* log_debug ("keep-uid: deleting '%s'\n", */
/* node->pkt->pkt.user_id->name); */
}
-/* Print DANE or PKA records for all user IDs in KEYBLOCK to the
- * stream FP. The data for the record is taken from HEXDATA. HEXFPR
- * is the fingerprint of the primary key. */
+/*
+ * Apply the drop-subkey 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_drop_subkey_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+ kbnode_t node;
+
+ for (node = keyblock->next; node; node = node->next )
+ {
+ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+ {
+ if (recsel_select (selector, impex_filter_getval, node))
+ {
+ log_debug ("drop-subkey: deleting a key\n");
+ /* The subkey packet and all following packets up to the
+ * next subkey. */
+ delete_kbnode (node);
+ for (; node->next
+ && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
+ && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
+ node = node->next)
+ delete_kbnode (node->next);
+ }
+ }
+ }
+}
+
+
+/* Print DANE or PKA records for all user IDs in KEYBLOCK to OUT. The
+ * data for the record is taken from (DATA,DATELEN). PK is the public
+ * key packet with the primary key. */
static gpg_error_t
-print_pka_or_dane_records (kbnode_t keyblock, const char *hexdata,
- const char *hexfpr, estream_t fp,
+print_pka_or_dane_records (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk,
+ const void *data, size_t datalen,
int print_pka, int print_dane)
{
gpg_error_t err = 0;
char *domain;
const char *s;
unsigned int len;
+ estream_t fp = NULL;
+ char *hexdata = NULL;
+ char *hexfpr;
+
+ hexfpr = hexfingerprint (pk, NULL, 0);
+ hexdata = bin2hex (data, datalen, NULL);
+ if (!hexdata)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ ascii_strlwr (hexdata);
+ fp = es_fopenmem (0, "rw,samethread");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
{
}
}
+ /* Make sure it is a string and write it. */
+ es_fputc (0, fp);
+ {
+ void *vp;
+
+ if (es_fclose_snatch (fp, &vp, NULL))
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ fp = NULL;
+ iobuf_writestr (out, vp);
+ es_free (vp);
+ }
+ err = 0;
+
leave:
xfree (hash);
xfree (mbox);
+ es_fclose (fp);
+ xfree (hexdata);
+ xfree (hexfpr);
return err;
}
continue;
}
- /* The agent does not yet allow to export v3 packets. It is
+ /* The agent does not yet allow export of v3 packets. It is
actually questionable whether we should allow them at
all. */
if (pk->version == 3)
commit_kbnode (&keyblock);
}
+ if (export_drop_subkey)
+ {
+ commit_kbnode (&keyblock);
+ apply_drop_subkey_filter (keyblock, export_drop_subkey);
+ commit_kbnode (&keyblock);
+ }
+
/* And write it. */
err = do_export_one_keyblock (ctrl, keyblock, keyid,
out_help? out_help : out,
{
/* We want to write PKA or DANE records. OUT_HELP has the
* keyblock and we print a record for each uid to OUT. */
- char *hexdata;
const void *data;
- void *vp;
size_t datalen;
- estream_t fp;
iobuf_flush_temp (out_help);
data = iobuf_get_temp_buffer (out_help);
datalen = iobuf_get_temp_length (out_help);
- hexdata = bin2hex (data, datalen, NULL);
- if (!hexdata)
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
- iobuf_close (out_help);
- out_help = iobuf_temp ();
- ascii_strlwr (hexdata);
- fp = es_fopenmem (0, "rw,samethread");
- if (!fp)
- {
- err = gpg_error_from_syserror ();
- xfree (hexdata);
- goto leave;
- }
- {
- char *hexfpr = hexfingerprint (pk, NULL, 0);
- err = print_pka_or_dane_records (keyblock, hexdata, hexfpr, fp,
- (options & EXPORT_PKA_FORMAT),
- (options & EXPORT_DANE_FORMAT));
- xfree (hexfpr);
- }
- xfree (hexdata);
+ err = print_pka_or_dane_records (out,
+ keyblock, pk, data, datalen,
+ (options & EXPORT_PKA_FORMAT),
+ (options & EXPORT_DANE_FORMAT));
if (err)
- {
- es_fclose (fp);
- goto leave;
- }
- es_fputc (0, fp);
- if (es_fclose_snatch (fp, &vp, NULL))
- {
- err = gpg_error_from_syserror ();
- goto leave;
- }
- iobuf_writestr (out, vp);
+ goto leave;
+
+ iobuf_close (out_help);
+ out_help = iobuf_temp ();
}
}