From b9000bc293164ff62efa7e91e5cf6d5fc19d482f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 23 Mar 2018 15:27:32 +0100 Subject: [PATCH] core: New gpgme_set_ctx_flag "request-origin". * src/context.h (gpgme_context): Add 'request_origin'. * src/gpgme.c (gpgme_release): Free that field. (gpgme_set_ctx_flag, gpgme_get_ctx_flag): Add "request-origin". * src/engine-backend.h (engine_ops): Add 'set_engine_ops' func ptr and adjust all users. * src/engine.c (_gpgme_engine_set_engine_flags): New. * src/op-support.c (_gpgme_op_reset): Call that func. * src/engine-gpg.c (struct engine_gpg): Add 'request_origin'. (gpg_set_engine_flags): New. (_gpgme_engine_ops_gpg): Hook it. (build_argv): Use command line option --request-origin. * src/engine-gpgsm.c (struct engine_gpgsm): Add 'request_origin'. (gpgsm_set_engine_flags): New. (_gpgme_engine_ops_gpgsm): Hook it. (start): Send OPTION "request-origin". * src/engine-assuan.c (struct engine_llass): Add 'request_origin'. (gpgsm_set_engine_flags): New. (_gpgme_engine_ops_assuan): Hook it. (start): Send OPTION "pretend-request-origin". Signed-off-by: Werner Koch --- doc/gpgme.texi | 5 +++++ src/context.h | 3 +++ src/engine-assuan.c | 35 +++++++++++++++++++++++++++++++++++ src/engine-backend.h | 1 + src/engine-g13.c | 1 + src/engine-gpg.c | 34 ++++++++++++++++++++++++++++++++++ src/engine-gpgconf.c | 1 + src/engine-gpgsm.c | 35 +++++++++++++++++++++++++++++++++++ src/engine-spawn.c | 1 + src/engine-uiserver.c | 1 + src/engine.c | 20 ++++++++++++++++++++ src/engine.h | 1 + src/gpgme.c | 21 ++++++++++++++------- src/op-support.c | 2 ++ tests/run-decrypt.c | 23 ++++++++++++++++++++++- 15 files changed, 176 insertions(+), 8 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 37cf16ac..ab554d86 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3065,6 +3065,11 @@ a message signed by a brand new key (which you naturally will not have on your local keyring), the operator can tell both your IP address and the time when you verified the signature. +@item "request-origin" +The string given in @var{value} is passed to the GnuPG engines to +request restrictions based on the origin of the request. Valid values +are documented in the GnuPG manual and the gpg man page under the +option ``--request-origin''. @end table diff --git a/src/context.h b/src/context.h index 1e763d2a..202cf168 100644 --- a/src/context.h +++ b/src/context.h @@ -145,6 +145,9 @@ struct gpgme_context /* The gpg specific override session key or NULL. */ char *override_session_key; + /* The optional request origin. */ + char *request_origin; + /* The locale for the pinentry. */ char *lc_ctype; char *lc_messages; diff --git a/src/engine-assuan.c b/src/engine-assuan.c index bb2290ac..6e603d9d 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -96,6 +96,7 @@ struct engine_llass int gpg_agent:1; /* Assume this is a gpg-agent connection. */ } opt; + char request_origin[10]; /* Copy from the CTX. */ }; typedef struct engine_llass *engine_llass_t; @@ -365,6 +366,24 @@ llass_new (void **engine, const char *file_name, const char *home_dir, } +/* Copy flags from CTX into the engine object. */ +static void +llass_set_engine_flags (void *engine, const gpgme_ctx_t ctx) +{ + engine_llass_t llass = engine; + + if (ctx->request_origin) + { + if (strlen (ctx->request_origin) + 1 > sizeof llass->request_origin) + strcpy (llass->request_origin, "xxx"); /* Too long - force error */ + else + strcpy (llass->request_origin, ctx->request_origin); + } + else + *llass->request_origin = 0; +} + + static gpgme_error_t llass_set_locale (void *engine, int category, const char *value) { @@ -660,6 +679,21 @@ start (engine_llass_t llass, const char *command) int nfds; int i; + if (*llass->request_origin && llass->opt.gpg_agent) + { + char *cmd; + + cmd = _gpgme_strconcat ("OPTION pretend-request-origin=", + llass->request_origin, NULL); + if (!cmd) + return gpg_error_from_syserror (); + err = assuan_transact (llass->assuan_ctx, cmd, NULL, NULL, NULL, + NULL, NULL, NULL); + free (cmd); + if (err && gpg_err_code (err) != GPG_ERR_UNKNOWN_OPTION) + return err; + } + /* We need to know the fd used by assuan for reads. We do this by using the assumption that the first returned fd from assuan_get_active_fds() is always this one. */ @@ -775,6 +809,7 @@ struct engine_ops _gpgme_engine_ops_assuan = NULL, /* set_colon_line_handler */ llass_set_locale, NULL, /* set_protocol */ + llass_set_engine_flags, NULL, /* decrypt */ NULL, /* delete */ NULL, /* edit */ diff --git a/src/engine-backend.h b/src/engine-backend.h index 421eb166..97cf6a10 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -61,6 +61,7 @@ struct engine_ops void *fnc_value); gpgme_error_t (*set_locale) (void *engine, int category, const char *value); gpgme_error_t (*set_protocol) (void *engine, gpgme_protocol_t protocol); + void (*set_engine_flags) (void *engine, gpgme_ctx_t ctx); gpgme_error_t (*decrypt) (void *engine, gpgme_decrypt_flags_t flags, gpgme_data_t ciph, diff --git a/src/engine-g13.c b/src/engine-g13.c index f8f31780..ec2f7af4 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -790,6 +790,7 @@ struct engine_ops _gpgme_engine_ops_g13 = NULL, /* set_colon_line_handler */ g13_set_locale, NULL, /* set_protocol */ + NULL, /* set_engine_flags */ NULL, /* decrypt */ NULL, /* delete */ NULL, /* edit */ diff --git a/src/engine-gpg.c b/src/engine-gpg.c index bfe7d131..22d327e0 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -143,6 +143,7 @@ struct engine_gpg struct gpgme_io_cbs io_cbs; gpgme_pinentry_mode_t pinentry_mode; + char request_origin[10]; /* NULL or the data object fed to --override_session_key-fd. */ gpgme_data_t override_session_key; @@ -628,6 +629,24 @@ gpg_new (void **engine, const char *file_name, const char *home_dir, } +/* Copy flags from CTX into the engine object. */ +static void +gpg_set_engine_flags (void *engine, const gpgme_ctx_t ctx) +{ + engine_gpg_t gpg = engine; + + if (ctx->request_origin && have_gpg_version (gpg, "2.2.6")) + { + if (strlen (ctx->request_origin) + 1 > sizeof gpg->request_origin) + strcpy (gpg->request_origin, "xxx"); /* Too long - force error */ + else + strcpy (gpg->request_origin, ctx->request_origin); + } + else + *gpg->request_origin = 0; +} + + static gpgme_error_t gpg_set_locale (void *engine, int category, const char *value) { @@ -904,6 +923,20 @@ build_argv (engine_gpg_t gpg, const char *pgmname) argc++; } + if (*gpg->request_origin) + { + argv[argc] = _gpgme_strconcat ("--request-origin=", + gpg->request_origin, NULL); + if (!argv[argc]) + { + int saved_err = gpg_error_from_syserror (); + free (fd_data_map); + free_argv (argv); + return saved_err; + } + argc++; + } + if (gpg->pinentry_mode && have_gpg_version (gpg, "2.1.0")) { const char *s = NULL; @@ -3090,6 +3123,7 @@ struct engine_ops _gpgme_engine_ops_gpg = gpg_set_colon_line_handler, gpg_set_locale, NULL, /* set_protocol */ + gpg_set_engine_flags, /* set_engine_flags */ gpg_decrypt, gpg_delete, gpg_edit, diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c index 94ae67f0..24867c74 100644 --- a/src/engine-gpgconf.c +++ b/src/engine-gpgconf.c @@ -1287,6 +1287,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf = NULL, /* set_colon_line_handler */ NULL, /* set_locale */ NULL, /* set_protocol */ + NULL, /* set_engine_flags */ NULL, /* decrypt */ NULL, /* delete */ NULL, /* edit */ diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index e337fedd..b8e44e7c 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -107,6 +107,8 @@ struct engine_gpgsm gpgme_data_t inline_data; /* Used to collect D lines. */ + char request_origin[10]; + struct gpgme_io_cbs io_cbs; }; @@ -521,6 +523,24 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir, } +/* Copy flags from CTX into the engine object. */ +static void +gpgsm_set_engine_flags (void *engine, const gpgme_ctx_t ctx) +{ + engine_gpgsm_t gpgsm = engine; + + if (ctx->request_origin) + { + if (strlen (ctx->request_origin) + 1 > sizeof gpgsm->request_origin) + strcpy (gpgsm->request_origin, "xxx"); /* Too long - force error */ + else + strcpy (gpgsm->request_origin, ctx->request_origin); + } + else + *gpgsm->request_origin = 0; +} + + static gpgme_error_t gpgsm_set_locale (void *engine, int category, const char *value) { @@ -1058,6 +1078,20 @@ start (engine_gpgsm_t gpgsm, const char *command) int nfds; int i; + if (*gpgsm->request_origin) + { + char *cmd; + + cmd = _gpgme_strconcat ("OPTION request-origin=", + gpgsm->request_origin, NULL); + if (!cmd) + return gpg_error_from_syserror (); + err = gpgsm_assuan_simple_command (gpgsm, cmd, NULL, NULL); + free (cmd); + if (err && gpg_err_code (err) != GPG_ERR_UNKNOWN_OPTION) + return err; + } + /* We need to know the fd used by assuan for reads. We do this by using the assumption that the first returned fd from assuan_get_active_fds() is always this one. */ @@ -2102,6 +2136,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm = gpgsm_set_colon_line_handler, gpgsm_set_locale, NULL, /* set_protocol */ + gpgsm_set_engine_flags, gpgsm_decrypt, gpgsm_delete, /* decrypt_verify */ NULL, /* edit */ diff --git a/src/engine-spawn.c b/src/engine-spawn.c index 7f78bb50..7b7a9cdf 100644 --- a/src/engine-spawn.c +++ b/src/engine-spawn.c @@ -449,6 +449,7 @@ struct engine_ops _gpgme_engine_ops_spawn = NULL, /* set_colon_line_handler */ NULL, /* set_locale */ NULL, /* set_protocol */ + NULL, /* set_engine_flags */ NULL, /* decrypt */ NULL, /* delete */ NULL, /* edit */ diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index bc3f3fbd..fd5ac174 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -1368,6 +1368,7 @@ struct engine_ops _gpgme_engine_ops_uiserver = uiserver_set_colon_line_handler, uiserver_set_locale, uiserver_set_protocol, + NULL, /* set_engine_flags */ uiserver_decrypt, NULL, /* delete */ NULL, /* edit */ diff --git a/src/engine.c b/src/engine.c index 28ba9fdf..e51384f0 100644 --- a/src/engine.c +++ b/src/engine.c @@ -651,6 +651,26 @@ _gpgme_engine_set_protocol (engine_t engine, gpgme_protocol_t protocol) } +/* Pass information about the current context to the engine. The + * engine may use this context to retrieve context specific flags. + * Important: The engine is required to immediately copy the required + * flags to its own context! + * + * This function will eventually be used to reduce the number of + * explicit passed flags. */ +void +_gpgme_engine_set_engine_flags (engine_t engine, gpgme_ctx_t ctx) +{ + if (!engine) + return; + + if (!engine->ops->set_engine_flags) + return; + + (*engine->ops->set_engine_flags) (engine->engine, ctx); +} + + gpgme_error_t _gpgme_engine_op_decrypt (engine_t engine, gpgme_decrypt_flags_t flags, diff --git a/src/engine.h b/src/engine.h index 0bf1bb27..34bf8e90 100644 --- a/src/engine.h +++ b/src/engine.h @@ -69,6 +69,7 @@ gpgme_error_t _gpgme_engine_set_locale (engine_t engine, int category, const char *value); gpgme_error_t _gpgme_engine_set_protocol (engine_t engine, gpgme_protocol_t protocol); +void _gpgme_engine_set_engine_flags (engine_t engine, gpgme_ctx_t ctx); void _gpgme_engine_release (engine_t engine); void _gpgme_engine_set_status_cb (engine_t engine, gpgme_status_cb_t cb, void *cb_value); diff --git a/src/gpgme.c b/src/gpgme.c index d0a5afee..9e65c50a 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -248,6 +248,7 @@ gpgme_release (gpgme_ctx_t ctx) free (ctx->lc_ctype); free (ctx->lc_messages); free (ctx->override_session_key); + free (ctx->request_origin); _gpgme_engine_info_release (ctx->engine_info); ctx->engine_info = NULL; DESTROY_LOCK (ctx->lock); @@ -486,13 +487,8 @@ gpgme_get_armor (gpgme_ctx_t ctx) } -/* Set the flag NAME for CTX to VALUE. The supported flags are: - * - * - full-status :: With a value of "1" the status callback set by - * gpgme_set_status_cb returns all status lines - * except for PROGRESS lines. With the default of - * "0" the status callback is only called in certain - * situations. +/* Set the flag NAME for CTX to VALUE. Please consult the manual for + * a description of the flags. */ gpgme_error_t gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value) @@ -535,6 +531,13 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value) { ctx->auto_key_retrieve = abool; } + else if (!strcmp (name, "request-origin")) + { + free (ctx->request_origin); + ctx->request_origin = strdup (value); + if (!ctx->request_origin) + err = gpg_error_from_syserror (); + } else err = gpg_error (GPG_ERR_UNKNOWN_NAME); @@ -576,6 +579,10 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name) { return ctx->auto_key_retrieve? "1":""; } + else if (!strcmp (name, "request-origin")) + { + return ctx->request_origin? ctx->request_origin : ""; + } else return NULL; } diff --git a/src/op-support.c b/src/op-support.c index 817c5691..43cb1c76 100644 --- a/src/op-support.c +++ b/src/op-support.c @@ -141,6 +141,8 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type) if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED) err = 0; + _gpgme_engine_set_engine_flags (ctx->engine, ctx); + if (!err) { err = _gpgme_engine_set_pinentry_mode (ctx->engine, diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index e961293a..f4c47544 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -81,6 +81,7 @@ show_usage (int ex) " --cms use the CMS protocol\n" " --export-session-key show the session key\n" " --override-session-key STRING use STRING as session key\n" + " --request-origin STRING use STRING as request origin\n" " --unwrap remove only the encryption layer\n" , stderr); exit (ex); @@ -102,6 +103,7 @@ main (int argc, char **argv) int print_status = 0; int export_session_key = 0; const char *override_session_key = NULL; + const char *request_origin = NULL; int raw_output = 0; if (argc) @@ -150,6 +152,14 @@ main (int argc, char **argv) override_session_key = *argv; argc--; argv++; } + else if (!strcmp (*argv, "--request-origin")) + { + argc--; argv++; + if (!argc) + show_usage (1); + request_origin = *argv; + argc--; argv++; + } else if (!strcmp (*argv, "--unwrap")) { flags |= GPGME_DECRYPT_UNWRAP; @@ -199,7 +209,18 @@ main (int argc, char **argv) override_session_key); if (err) { - fprintf (stderr, PGM ": error overriding session key: %s\n", + fprintf (stderr, PGM ": error setting overriding session key: %s\n", + gpgme_strerror (err)); + exit (1); + } + } + + if (request_origin) + { + err = gpgme_set_ctx_flag (ctx, "request-origin", request_origin); + if (err) + { + fprintf (stderr, PGM ": error setting request_origin: %s\n", gpgme_strerror (err)); exit (1); }