From 97932b102af882a37c2613b0f50dc39369c48723 Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Tue, 3 Nov 2009 19:15:35 +0000 Subject: [PATCH] 2009-11-03 Marcus Brinkmann * Makefile.am (main_sources): Change g13.c to vfs-mount.c. Add vfs-create.c * vfs-create.c: New file. * g13.c: Renamed to ... * vfs-mount.c: ... this new file. * gpgme.h.in (gpgme_op_vfs_create): New prototype. * gpgme.def, libgpgme.vers: Add gpgme_op_vfs_create. * gpgme-tool.c (gt_vfs_create, cmd_vfs_create): New functions. (register_commands): Add VFS_CREATE and CREAET. --- src/ChangeLog | 12 +++ src/Makefile.am | 2 +- src/gpgme-tool.c | 122 ++++++++++++++++++++++- src/gpgme.def | 1 + src/gpgme.h.in | 6 +- src/libgpgme.vers | 2 + src/vfs-create.c | 193 +++++++++++++++++++++++++++++++++++++ src/{g13.c => vfs-mount.c} | 5 +- 8 files changed, 337 insertions(+), 6 deletions(-) create mode 100644 src/vfs-create.c rename src/{g13.c => vfs-mount.c} (97%) diff --git a/src/ChangeLog b/src/ChangeLog index 8c3689e..bcfaa72 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,15 @@ +2009-11-03 Marcus Brinkmann + + * Makefile.am (main_sources): Change g13.c to vfs-mount.c. Add + vfs-create.c + * vfs-create.c: New file. + * g13.c: Renamed to ... + * vfs-mount.c: ... this new file. + * gpgme.h.in (gpgme_op_vfs_create): New prototype. + * gpgme.def, libgpgme.vers: Add gpgme_op_vfs_create. + * gpgme-tool.c (gt_vfs_create, cmd_vfs_create): New functions. + (register_commands): Add VFS_CREATE and CREAET. + 2009-11-02 Marcus Brinkmann * debug.h (_gpgme_debug_buffer): Make TAG argument const const. diff --git a/src/Makefile.am b/src/Makefile.am index 677a896..b1d93d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -111,7 +111,7 @@ main_sources = \ opassuan.c \ engine.h engine-backend.h engine.c engine-gpg.c status-table.h \ $(gpgsm_components) $(assuan_components) $(gpgconf_components) \ - $(g13_components) g13.c \ + $(g13_components) vfs-mount.c vfs-create.c \ gpgconf.c \ sema.h priv-io.h $(system_components) dirinfo.c \ debug.c debug.h gpgme.c version.c error.c diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index e4948e2..7a41be0 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -483,6 +483,7 @@ typedef enum status STATUS_TEXTMODE, STATUS_INCLUDE_CERTS, STATUS_KEYLIST_MODE, + STATUS_RECIPIENT, STATUS_ENCRYPT_RESULT } status_t; @@ -495,6 +496,7 @@ const char *status_string[] = "TEXTMODE", "INCLUDE_CERTS", "KEYLIST_MODE", + "RECIPIENT", "ENCRYPT_RESULT" }; @@ -574,7 +576,88 @@ gt_signers_clear (gpgme_tool_t gt) gpg_error_t -gt_recipients_add (gpgme_tool_t gt, const char *fpr) +gt_get_key (gpgme_tool_t gt, const char *pattern, gpgme_key_t *r_key) +{ + gpgme_ctx_t ctx; + gpgme_ctx_t listctx; + gpgme_error_t err; + gpgme_key_t key; + + if (!gt || !r_key || !pattern) + return gpg_error (GPG_ERR_INV_VALUE); + + ctx = gt->ctx; + + err = gpgme_new (&listctx); + if (err) + return err; + + { + gpgme_protocol_t proto; + gpgme_engine_info_t info; + + /* Clone the relevant state. */ + proto = gpgme_get_protocol (ctx); + /* The g13 protocol does not allow keylisting, we need to choose + something else. */ + if (proto == GPGME_PROTOCOL_G13) + proto = GPGME_PROTOCOL_OpenPGP; + + gpgme_set_protocol (listctx, proto); + gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx)); + info = gpgme_ctx_get_engine_info (ctx); + while (info && info->protocol != proto) + info = info->next; + if (info) + gpgme_ctx_set_engine_info (listctx, proto, + info->file_name, info->home_dir); + } + + err = gpgme_op_keylist_start (listctx, pattern, 0); + if (!err) + err = gpgme_op_keylist_next (listctx, r_key); + if (!err) + { + try_next_key: + err = gpgme_op_keylist_next (listctx, &key); + if (gpgme_err_code (err) == GPG_ERR_EOF) + err = 0; + else + { + if (!err + && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr + && key && key->subkeys && key->subkeys->fpr + && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr)) + { + /* The fingerprint is identical. We assume that this is + the same key and don't mark it as an ambiguous. This + problem may occur with corrupted keyrings and has + been noticed often with gpgsm. In fact gpgsm uses a + similar hack to sort out such duplicates but it can't + do that while listing keys. */ + gpgme_key_unref (key); + goto try_next_key; + } + if (!err) + { + gpgme_key_unref (key); + err = gpg_error (GPG_ERR_AMBIGUOUS_NAME); + } + gpgme_key_unref (*r_key); + } + } + gpgme_release (listctx); + + if (! err) + gt_write_status (gt, STATUS_RECIPIENT, + ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ? + (*r_key)->subkeys->fpr : "invalid", NULL); + return err; +} + + +gpg_error_t +gt_recipients_add (gpgme_tool_t gt, const char *pattern) { gpg_error_t err; gpgme_key_t key; @@ -582,7 +665,7 @@ gt_recipients_add (gpgme_tool_t gt, const char *fpr) if (gt->recipients_nr >= MAX_RECIPIENTS) return gpg_error_from_errno (ENOMEM); - err = gpgme_get_key (gt->ctx, fpr, &key, 0); + err = gt_get_key (gt, pattern, &key); if (err) return err; @@ -962,6 +1045,18 @@ gt_vfs_mount (gpgme_tool_t gt, const char *container_file, } +gpg_error_t +gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags) +{ + gpg_error_t err; + gpg_error_t op_err; + err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file, + flags, &op_err); + gt_recipients_clear (gt); + return err || op_err; +} + + // TODO #define GT_RESULT_ENCRYPT 0x1 #define GT_RESULT_DECRYPT 0x2 @@ -1742,6 +1837,27 @@ cmd_vfs_mount (assuan_context_t ctx, char *line) } +static gpg_error_t +cmd_vfs_create (assuan_context_t ctx, char *line) +{ + struct server *server = assuan_get_pointer (ctx); + gpg_error_t err; + char *end; + + end = strchr (line, ' '); + if (end) + { + *(end++) = '\0'; + while (*end == ' ') + end++; + } + + err = gt_vfs_create (server->gt, line, 0); + + return err; +} + + static gpg_error_t cmd_result (assuan_context_t ctx, char *line) { @@ -1835,6 +1951,8 @@ register_commands (assuan_context_t ctx) // TODO: ASSUAN { "VFS_MOUNT", cmd_vfs_mount }, { "MOUNT", cmd_vfs_mount }, + { "VFS_CREATE", cmd_vfs_create }, + { "CREATE", cmd_vfs_create }, // TODO: GPGCONF { "RESULT", cmd_result }, { "STRERROR", cmd_strerror }, diff --git a/src/gpgme.def b/src/gpgme.def index 6d223f4..816da31 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -190,6 +190,7 @@ EXPORTS gpgme_wait_ext @145 gpgme_op_vfs_mount_result @146 gpgme_op_vfs_mount @147 + gpgme_op_vfs_create @148 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 42b9237..f0a61d7 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1808,9 +1808,13 @@ gpgme_vfs_mount_result_t gpgme_op_vfs_mount_result (gpgme_ctx_t ctx); or destroyed. Transmission errors are returned directly, operational errors are returned in OP_ERR. */ gpgme_error_t gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file, - const char *mount_dir, int flags, + const char *mount_dir, unsigned int flags, gpgme_error_t *op_err); +gpgme_error_t gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *container_file, + unsigned int flags, gpgme_error_t *op_err); + /* Interface to gpgconf(1). */ diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 9989c75..24107d4 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -71,6 +71,8 @@ GPGME_1.1 { gpgme_op_vfs_mount_result; gpgme_op_vfs_mount; + gpgme_op_vfs_create; + }; diff --git a/src/vfs-create.c b/src/vfs-create.c new file mode 100644 index 0000000..a965a96 --- /dev/null +++ b/src/vfs-create.c @@ -0,0 +1,193 @@ +/* vfs-create.c - vfs create support in GPGME + Copyright (C) 2009 g10 Code GmbH + + This file is part of GPGME. + + GPGME is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + GPGME is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include + +#include "gpgme.h" +#include "debug.h" +#include "context.h" +#include "ops.h" +#include "util.h" + +static gpgme_error_t +vfs_start (gpgme_ctx_t ctx, int synchronous, + const char *command, + gpgme_assuan_data_cb_t data_cb, + void *data_cb_value, + gpgme_assuan_inquire_cb_t inq_cb, + void *inq_cb_value, + gpgme_assuan_status_cb_t status_cb, + void *status_cb_value) +{ + gpgme_error_t err; + + if (!command || !*command) + return gpg_error (GPG_ERR_INV_VALUE); + + /* The flag value 256 is used to suppress an engine reset. This is + required to keep the connection running. */ + err = _gpgme_op_reset (ctx, ((synchronous & 255) | 256)); + if (err) + return err; + + return _gpgme_engine_op_assuan_transact (ctx->engine, command, + data_cb, data_cb_value, + inq_cb, inq_cb_value, + status_cb, status_cb_value); +} + + + +/* XXXX. This is the asynchronous variant. */ +static gpgme_error_t +gpgme_op_vfs_transact_start (gpgme_ctx_t ctx, + const char *command, + gpgme_assuan_data_cb_t data_cb, + void *data_cb_value, + gpgme_assuan_inquire_cb_t inq_cb, + void *inq_cb_value, + gpgme_assuan_status_cb_t status_cb, + void *status_cb_value) +{ + return vfs_start (ctx, 0, command, data_cb, data_cb_value, + inq_cb, inq_cb_value, status_cb, status_cb_value); +} + + +/* XXXX. This is the synchronous variant. */ +static gpgme_error_t +gpgme_op_vfs_transact (gpgme_ctx_t ctx, + const char *command, + gpgme_assuan_data_cb_t data_cb, + void *data_cb_value, + gpgme_assuan_inquire_cb_t inq_cb, + void *inq_cb_value, + gpgme_assuan_status_cb_t status_cb, + void *status_cb_value, + gpgme_error_t *op_err) +{ + gpgme_error_t err; + + err = vfs_start (ctx, 1, command, data_cb, data_cb_value, + inq_cb, inq_cb_value, status_cb, status_cb_value); + if (!err) + err = _gpgme_wait_one_ext (ctx, op_err); + return err; +} + + +/* The actual exported interface follows. */ + +/* The container is automatically uncreateed when the context is reset + or destroyed. This is a synchronous convenience interface, which + automatically returns an operation error if there is no + transmission error. */ +static gpgme_error_t +_gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *container_file, unsigned int flags, + gpgme_error_t *op_err) +{ + gpg_error_t err; + char *cmd; + char *container_file_esc = NULL; + int i; + + /* We want to encourage people to check error values, so not getting + them is discouraged here. Also makes our code easier. */ + if (! op_err) + return gpg_error (GPG_ERR_INV_VALUE); + + err = _gpgme_encode_percent_string (container_file, &container_file_esc, 0); + if (err) + return err; + + i = 0; + while (!err && recp[i]) + { + if (!recp[i]->subkeys || !recp[i]->subkeys->fpr) + { + free (container_file_esc); + return gpg_error (GPG_ERR_UNUSABLE_PUBKEY); + } + + if (asprintf (&cmd, "RECIPIENT %s", recp[i]->subkeys->fpr) < 0) + { + err = gpg_error_from_syserror (); + free (container_file_esc); + return err; + } + + err = gpgme_op_vfs_transact (ctx, cmd, NULL, NULL, NULL, NULL, + NULL, NULL, op_err); + free (cmd); + if (err || *op_err) + { + free (container_file_esc); + return err; + } + recp++; + } + + if (asprintf (&cmd, "CREATE -- %s", container_file_esc) < 0) + { + err = gpg_error_from_syserror (); + free (container_file_esc); + return err; + } + free (container_file_esc); + + err = gpgme_op_vfs_transact (ctx, cmd, NULL, NULL, NULL, NULL, + NULL, NULL, op_err); + free (cmd); + + return err; +} + + +gpgme_error_t +gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[], + const char *container_file, unsigned int flags, + gpgme_error_t *op_err) +{ + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_vfs_create", ctx, + "container_file=%s, flags=0x%x, op_err=%p", + container_file, flags, op_err); + + if (_gpgme_debug_trace () && recp) + { + int i = 0; + + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + (recp[i]->subkeys && recp[i]->subkeys->fpr) ? + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + + return TRACE_ERR (_gpgme_op_vfs_create (ctx, recp, container_file, + flags, op_err)); +} + diff --git a/src/g13.c b/src/vfs-mount.c similarity index 97% rename from src/g13.c rename to src/vfs-mount.c index a2ab675..3c0b6f2 100644 --- a/src/g13.c +++ b/src/vfs-mount.c @@ -1,4 +1,4 @@ -/* g13.c - g13 support in GPGME +/* vfs-mount.c - vfs mount support in GPGME Copyright (C) 2009 g10 Code GmbH This file is part of GPGME. @@ -198,7 +198,8 @@ _gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file, gpgme_error_t gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file, - const char *mount_dir, int flags, gpgme_error_t *op_err) + const char *mount_dir, unsigned int flags, + gpgme_error_t *op_err) { TRACE_BEG4 (DEBUG_CTX, "gpgme_op_vfs_mount", ctx, "container=%s, mount_dir=%s, flags=0x%x, op_err=%p", -- 2.26.2