From 35023f313622fb1b34108dd934e84831c58b81aa Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Tue, 21 Mar 2017 09:38:11 +0100 Subject: [PATCH] core: New public API gpgme_op_keylist_from_data_start. * src/gpgme.h.in: New API gpgme_op_keylist_from_data_start. * src/libgpgme.vers, src/gpgme.def: Add it. * src/keylist.c (gpgme_op_keylist_from_data_start): New. * src/engine-backend.h (engine_ops): Add field 'keylist_data'. Change all engines to pass NULL for it. * src/engine.c (_gpgme_engine_op_keylist_data): New. * src/engine-gpg.c (gpg_keylist_data): New. (_gpgme_engine_ops_gpg): Register gpg_keylist_data. * tests/run-keylist.c (main): New option --from-file. -- Co-authored-by: Werner Koch GnuPG-bug-id: 2819 --- NEWS | 3 ++- doc/gpgme.texi | 34 +++++++++++++++++++++++++++++++++- src/engine-assuan.c | 1 + src/engine-backend.h | 1 + src/engine-g13.c | 1 + src/engine-gpg.c | 33 +++++++++++++++++++++++++++++++++ src/engine-gpgconf.c | 1 + src/engine-gpgsm.c | 1 + src/engine-spawn.c | 1 + src/engine-uiserver.c | 1 + src/engine.c | 13 +++++++++++++ src/engine.h | 2 ++ src/gpgme.def | 7 +++++-- src/gpgme.h.in | 15 +++++++++++++-- src/keylist.c | 36 ++++++++++++++++++++++++++++++++++++ src/libgpgme.vers | 1 + tests/run-keylist.c | 24 ++++++++++++++++++++++-- 17 files changed, 167 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index f2ab0bf3..cf02fc2f 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ Noteworthy changes in version 1.8.1 (unreleased) gpgme_op_createsubkey CHANGED: Meaning of 'expire' parameter. GPGME_CREATE_NOEXPIRE NEW. gpgme_subkey_t EXTENDED: New field is_de_vs. + gpgme_op_keylist_from_data_start NEW. + gpgme_data_rewind UN-DEPRECATE. cpp: Context::revUid(const Key&, const char*) NEW. cpp: Context::startRevUid(const Key&, const char*) NEW. cpp: Context::addUid(const Key&, const char*) NEW. @@ -22,7 +24,6 @@ Noteworthy changes in version 1.8.1 (unreleased) cpp: Subkey::keyGrip NEW. cpp: Subkey::isDeVs NEW. qt: CryptoConfig::stringValueList() NEW. - gpgme_data_rewind UN-DEPRECATE. py: Context.__init__ EXTENDED: New keyword arg home_dir. py: Context.home_dir NEW. py: Context.keylist EXTENDED: New keyword arg mode. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 337053fb..edcbb98c 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3342,6 +3342,7 @@ This is a linked list with the notation data and policy URLs. @cindex key ring, search @deftypefun gpgme_error_t gpgme_op_keylist_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{int @var{secret_only}}) + The function @code{gpgme_op_keylist_start} initiates a key listing operation inside the context @var{ctx}. It sets everything up so that subsequent invocations of @code{gpgme_op_keylist_next} return the keys @@ -3369,6 +3370,7 @@ are reported by the crypto engine support routines. @end deftypefun @deftypefun gpgme_error_t gpgme_op_keylist_ext_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{int @var{secret_only}}, @w{int @var{reserved}}) + The function @code{gpgme_op_keylist_ext_start} initiates an extended key listing operation inside the context @var{ctx}. It sets everything up so that subsequent invocations of @@ -3399,7 +3401,36 @@ The function returns the error code @code{GPG_ERR_INV_VALUE} if are reported by the crypto engine support routines. @end deftypefun +@deftypefun gpgme_error_t gpgme_op_keylist_from_data @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{gpgme_data_t @var{data}}, @ + @w{int @var{reserved}}) + +The function @code{gpgme_op_keylist_from_data_start} initiates a key +listing operation inside the context @var{ctx}. In contrast to the +other key listing operation the keys are read from the supplied +@var{data} and not from the local key database. The keys are also not +imported into the local ley database. The function sets everything up +so that subsequent invocations of @code{gpgme_op_keylist_next} return +the keys from @var{data}. + +The value of @var{reserved} must be @code{0}. + +This function requires at least GnuPG version 2.1.14 and currently +works only with OpenPGP keys. + +The context will be busy until either all keys are received (and +@code{gpgme_op_keylist_next} returns @code{GPG_ERR_EOF}), or +@code{gpgme_op_keylist_end} is called to finish the operation. +While the context is busy @var{data} may not be released. + +The function returns the error code @code{GPG_ERR_INV_VALUE} if +@var{ctx} is not a valid pointer, and passes through any errors that +are reported by the crypto engine support routines. +@end deftypefun + @deftypefun gpgme_error_t gpgme_op_keylist_next (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t *@var{r_key}}) + The function @code{gpgme_op_keylist_next} returns the next key in the list created by a previous @code{gpgme_op_keylist_start} operation in the context @var{ctx}. The key will have one reference for the user. @@ -3417,6 +3448,7 @@ The function returns the error code @code{GPG_ERR_INV_VALUE} if @end deftypefun @deftypefun gpgme_error_t gpgme_op_keylist_end (@w{gpgme_ctx_t @var{ctx}}) + The function @code{gpgme_op_keylist_end} ends a pending key list operation in the context @var{ctx}. @@ -3431,7 +3463,7 @@ time during the operation there was not enough memory available. The following example illustrates how all keys containing a certain string (@code{g10code}) can be listed with their key ID and the name -and e-mail address of the main user ID: +and email address of the main user ID: @example gpgme_ctx_t ctx; diff --git a/src/engine-assuan.c b/src/engine-assuan.c index 78efb4cb..4beb41d7 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -787,6 +787,7 @@ struct engine_ops _gpgme_engine_ops_assuan = NULL, /* import */ NULL, /* keylist */ NULL, /* keylist_ext */ + NULL, /* keylist_data */ NULL, /* keysign */ NULL, /* tofu_policy */ NULL, /* sign */ diff --git a/src/engine-backend.h b/src/engine-backend.h index a8457afd..635acb06 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -100,6 +100,7 @@ struct engine_ops int secret_only, int reserved, gpgme_keylist_mode_t mode, int engine_flags); + gpgme_error_t (*keylist_data) (void *engine, gpgme_data_t data); gpgme_error_t (*keysign) (void *engine, gpgme_key_t key, const char *userid, unsigned long expires, unsigned int flags, diff --git a/src/engine-g13.c b/src/engine-g13.c index bb06d356..593177c2 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -802,6 +802,7 @@ struct engine_ops _gpgme_engine_ops_g13 = NULL, /* import */ NULL, /* keylist */ NULL, /* keylist_ext */ + NULL, /* keylist_data */ NULL, /* keysign */ NULL, /* tofu_policy */ NULL, /* sign */ diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 59cf405a..4b87a8a0 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2730,6 +2730,38 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only, } +static gpgme_error_t +gpg_keylist_data (void *engine, gpgme_data_t data) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + if (!have_gpg_version (gpg, "2.1.14")) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + err = add_arg (gpg, "--with-colons"); + if (!err) + err = add_arg (gpg, "--with-fingerprint"); + if (!err) + err = add_arg (gpg, "--import-options"); + if (!err) + err = add_arg (gpg, "import-show"); + if (!err) + err = add_arg (gpg, "--dry-run"); + if (!err) + err = add_arg (gpg, "--import"); + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, data, -1, 0); + + if (!err) + err = start (gpg); + + return err; +} + + static gpgme_error_t gpg_keysign (void *engine, gpgme_key_t key, const char *userid, unsigned long expire, unsigned int flags, @@ -3013,6 +3045,7 @@ struct engine_ops _gpgme_engine_ops_gpg = gpg_import, gpg_keylist, gpg_keylist_ext, + gpg_keylist_data, gpg_keysign, gpg_tofu_policy, /* tofu_policy */ gpg_sign, diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c index 3e463105..48919775 100644 --- a/src/engine-gpgconf.c +++ b/src/engine-gpgconf.c @@ -1244,6 +1244,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf = NULL, /* import */ NULL, /* keylist */ NULL, /* keylist_ext */ + NULL, /* keylist_data */ NULL, /* keysign */ NULL, /* tofu_policy */ NULL, /* sign */ diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index d5d29010..7652363a 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -2106,6 +2106,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm = gpgsm_import, gpgsm_keylist, gpgsm_keylist_ext, + NULL, /* keylist_data */ NULL, /* keysign */ NULL, /* tofu_policy */ gpgsm_sign, diff --git a/src/engine-spawn.c b/src/engine-spawn.c index 1cd4421e..fa406d4c 100644 --- a/src/engine-spawn.c +++ b/src/engine-spawn.c @@ -460,6 +460,7 @@ struct engine_ops _gpgme_engine_ops_spawn = NULL, /* import */ NULL, /* keylist */ NULL, /* keylist_ext */ + NULL, /* keylist_data */ NULL, /* keysign */ NULL, /* tofu_policy */ NULL, /* sign */ diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index ff5227ee..12efd270 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -1394,6 +1394,7 @@ struct engine_ops _gpgme_engine_ops_uiserver = NULL, /* import */ NULL, /* keylist */ NULL, /* keylist_ext */ + NULL, /* keylist_data */ NULL, /* keysign */ NULL, /* tofu_policy */ uiserver_sign, diff --git a/src/engine.c b/src/engine.c index 75d9ff7b..a918a50d 100644 --- a/src/engine.c +++ b/src/engine.c @@ -875,6 +875,19 @@ _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[], } +gpgme_error_t +_gpgme_engine_op_keylist_data (engine_t engine, gpgme_data_t data) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->keylist_data) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->keylist_data) (engine->engine, data); +} + + gpgme_error_t _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out, gpgme_sig_mode_t mode, int use_armor, diff --git a/src/engine.h b/src/engine.h index 29d2f259..f456812e 100644 --- a/src/engine.h +++ b/src/engine.h @@ -148,6 +148,8 @@ gpgme_error_t _gpgme_engine_op_keylist_ext (engine_t engine, int reserved, gpgme_keylist_mode_t mode, int engine_flags); +gpgme_error_t _gpgme_engine_op_keylist_data (engine_t engine, + gpgme_data_t data); gpgme_error_t _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out, gpgme_sig_mode_t mode, int use_armor, int use_textmode, diff --git a/src/gpgme.def b/src/gpgme.def index 0d3ce74f..ddd57d35 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -177,8 +177,8 @@ EXPORTS gpgme_io_read @136 gpgme_io_write @137 - gpgme_result_ref @138 - gpgme_result_unref @139 + gpgme_result_ref @138 + gpgme_result_unref @139 gpgme_op_import_keys @140 gpgme_op_import_keys_start @141 @@ -253,5 +253,8 @@ EXPORTS gpgme_op_query_swdb_result @190 gpgme_get_ctx_flag @191 + + gpgme_op_keylist_from_data_start @192 + ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index b660cb51..2cf096b6 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1817,20 +1817,31 @@ typedef struct _gpgme_op_keylist_result *gpgme_keylist_result_t; gpgme_keylist_result_t gpgme_op_keylist_result (gpgme_ctx_t ctx); /* Start a keylist operation within CTX, searching for keys which - match PATTERN. If SECRET_ONLY is true, only secret keys are - returned. */ + * match PATTERN. If SECRET_ONLY is true, only secret keys are + * returned. */ gpgme_error_t gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only); gpgme_error_t gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[], int secret_only, int reserved); +/* List the keys contained in DATA. */ +gpgme_error_t gpgme_op_keylist_from_data_start (gpgme_ctx_t ctx, + gpgme_data_t data, + int reserved); + /* Return the next key from the keylist in R_KEY. */ gpgme_error_t gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key); /* Terminate a pending keylist operation within CTX. */ gpgme_error_t gpgme_op_keylist_end (gpgme_ctx_t ctx); + + +/* + * Protecting keys + */ + /* Change the passphrase for KEY. FLAGS is reserved for future use and must be passed as 0. */ gpgme_error_t gpgme_op_passwd_start (gpgme_ctx_t ctx, gpgme_key_t key, diff --git a/src/keylist.c b/src/keylist.c index de9bbb2f..c88a7ca5 100644 --- a/src/keylist.c +++ b/src/keylist.c @@ -1142,6 +1142,42 @@ gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[], } +/* Start a keylist operation within CTX to show keys contained + * in DATA. */ +gpgme_error_t +gpgme_op_keylist_from_data_start (gpgme_ctx_t ctx, gpgme_data_t data, + int reserved) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + TRACE_BEG (DEBUG_CTX, "gpgme_op_keylist_from_data_start", ctx); + + if (!ctx || !data || reserved) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = _gpgme_op_reset (ctx, 2); + if (err) + return TRACE_ERR (err); + + err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return TRACE_ERR (err); + + _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx); + err = _gpgme_engine_set_colon_line_handler (ctx->engine, + keylist_colon_handler, ctx); + if (err) + return TRACE_ERR (err); + + err = _gpgme_engine_op_keylist_data (ctx->engine, data); + return TRACE_ERR (err); +} + + /* Return the next key from the keylist in R_KEY. */ gpgme_error_t gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key) diff --git a/src/libgpgme.vers b/src/libgpgme.vers index a55cd10a..9344a752 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -223,6 +223,7 @@ GPGME_1.0 { gpgme_op_import_start; gpgme_op_keylist_end; gpgme_op_keylist_ext_start; + gpgme_op_keylist_from_data_start; gpgme_op_keylist_next; gpgme_op_keylist_result; gpgme_op_keylist_start; diff --git a/tests/run-keylist.c b/tests/run-keylist.c index fd9c7c20..aab4bb64 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -41,7 +41,7 @@ static int verbose; static int show_usage (int ex) { - fputs ("usage: " PGM " [options] [USERID]\n\n" + fputs ("usage: " PGM " [options] [USERID_or_FILE]\n\n" "Options:\n" " --verbose run in verbose mode\n" " --openpgp use the OpenPGP protocol (default)\n" @@ -56,6 +56,7 @@ show_usage (int ex) " --validate use GPGME_KEYLIST_MODE_VALIDATE\n" " --import import all keys\n" " --offline use offline mode\n" + " --from-file list all keys in the given file\n" " --require-gnupg required at least the given GnuPG version\n" , stderr); exit (ex); @@ -98,6 +99,9 @@ main (int argc, char **argv) gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP; int only_secret = 0; int offline = 0; + int from_file = 0; + gpgme_data_t data = NULL; + if (argc) { argc--; argv++; } @@ -177,6 +181,11 @@ main (int argc, char **argv) offline = 1; argc--; argv++; } + else if (!strcmp (*argv, "--from-file")) + { + from_file = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--require-gnupg")) { argc--; argv++; @@ -191,6 +200,8 @@ main (int argc, char **argv) if (argc > 1) show_usage (1); + else if (from_file && !argc) + show_usage (1); init_gpgme (protocol); @@ -202,7 +213,15 @@ main (int argc, char **argv) gpgme_set_offline (ctx, offline); - err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret); + if (from_file) + { + err = gpgme_data_new_from_file (&data, *argv, 1); + fail_if_err (err); + + err = gpgme_op_keylist_from_data_start (ctx, data, 0); + } + else + err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret); fail_if_err (err); while (!(err = gpgme_op_keylist_next (ctx, &key))) @@ -322,6 +341,7 @@ main (int argc, char **argv) err = gpgme_op_keylist_end (ctx); fail_if_err (err); keyarray[keyidx] = NULL; + gpgme_data_release (data); result = gpgme_op_keylist_result (ctx); if (result->truncated)