Add per-ctx custom engine options.

* src/gpgme.h.in (gpgme_ctx_set_engine_options): New prototype.
(gpgme_ctx_get_engine_options): Ditto.
* src/engine-backend.h (engine_ops): Add set_options and get_options.
* src/engine.c (gpgme_ctx_set_engine_options): New.
(gpgme_ctx_get_engine_options): Ditto.
* src/engine-gpg.c (gpg_set_options): New.
(gpg_get_options): Ditto.
* src/op-support.c (_gpgme_op_reset): Keep custom options.
* src/engine-gpg.c (_gpgme_engine_ops_gpg): Adjust for new members.
* src/engine-assuan.c (_gpgme_engine_ops_assuan): Ditto.
* src/engine-g13.c (_gpgme_engine_ops_g13): Ditto.
* src/engine-gpgconf.c (_gpgme_engine_ops_gpgconf): Ditto.
* src/engine-gpgsm.c (_gpgme_engine_ops_gpgsm): Ditto.
* src/engine-spawn.c (_gpgme_engine_ops_spawn): Ditto.
* src/engine-uiserver.c (_gpgme_engine_ops_uiserver): Ditto.
* src/gpgme.def: Export new symbols.
* src/libgpgme.vers: Ditto.
* doc/gpgme.texi: Document these new functions.

--
Not all of gpg2's features are exposed to libgpgme and adding these
functions makes it possible to do things like specify an --s2k-count,
etc.
This commit is contained in:
Ben Kibbey 2015-07-15 21:41:15 -04:00
parent a5d9e018b8
commit 259b61f73c
14 changed files with 186 additions and 1 deletions

View File

@ -187,6 +187,7 @@ Context Attributes
* Protocol Selection:: Selecting the protocol used by a context. * Protocol Selection:: Selecting the protocol used by a context.
* Crypto Engine:: Configuring the crypto engine. * Crypto Engine:: Configuring the crypto engine.
* Custom Engine Options:: Adding command line options to an engine.
* ASCII Armor:: Requesting @acronym{ASCII} armored output. * ASCII Armor:: Requesting @acronym{ASCII} armored output.
* Text Mode:: Choosing canonical text mode. * Text Mode:: Choosing canonical text mode.
* Included Certificates:: Including a number of certificates. * Included Certificates:: Including a number of certificates.
@ -2283,6 +2284,7 @@ started. In fact, these references are accessed through the
@menu @menu
* Protocol Selection:: Selecting the protocol used by a context. * Protocol Selection:: Selecting the protocol used by a context.
* Crypto Engine:: Configuring the crypto engine. * Crypto Engine:: Configuring the crypto engine.
* Custom Engine Options:: Adding command line options to an engine.
* ASCII Armor:: Requesting @acronym{ASCII} armored output. * ASCII Armor:: Requesting @acronym{ASCII} armored output.
* Text Mode:: Choosing canonical text mode. * Text Mode:: Choosing canonical text mode.
* Included Certificates:: Including a number of certificates. * Included Certificates:: Including a number of certificates.
@ -2362,6 +2364,29 @@ successful, or an eror code on failure.
@end deftypefun @end deftypefun
@node Custom Engine Options
@subsection Custom Engine Options
@cindex context, configuring engine
@cindex engine, configuration per context
Since not all features of all engines may be exposed by @acronym{GPGME},
additional command line arguments may be needed to allow the wanted
functionality.
@deftypefun gpgme_error_t gpgme_ctx_set_engine_options (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{options}})
The function @code{gpgme_ctx_set_engine_options} sets command line options for
the configured engine in context @var{ctx} to @var{options}. The options are
passed upon each op call and may be reset by setting @var{options} to
@code{NULL}. This function returns @code{0} on success or an error on failure.
@end deftypefun
@deftypefun gpgme_error_t gpgme_ctx_get_engine_options (@w{gpgme_ctx_t @var{ctx}}, @w{char ** @var{result}})
The function @code{gpgme_ctx_get_engine_options} returns the previously set
engine options in @var{result}. This function returns @code{0} on success or
an error on failure.
@end deftypefun
@c FIXME: Unfortunately, using @acronym here breaks texi2dvi. @c FIXME: Unfortunately, using @acronym here breaks texi2dvi.
@node ASCII Armor @node ASCII Armor
@subsection @acronym{ASCII} Armor @subsection @acronym{ASCII} Armor

View File

@ -759,6 +759,8 @@ struct engine_ops _gpgme_engine_ops_assuan =
NULL, /* set_colon_line_handler */ NULL, /* set_colon_line_handler */
llass_set_locale, llass_set_locale,
NULL, /* set_protocol */ NULL, /* set_protocol */
NULL, /* set_options */
NULL, /* get_options */
NULL, /* decrypt */ NULL, /* decrypt */
NULL, /* decrypt_verify */ NULL, /* decrypt_verify */
NULL, /* delete */ NULL, /* delete */

View File

@ -59,6 +59,8 @@ struct engine_ops
void *fnc_value); void *fnc_value);
gpgme_error_t (*set_locale) (void *engine, int category, const char *value); gpgme_error_t (*set_locale) (void *engine, int category, const char *value);
gpgme_error_t (*set_protocol) (void *engine, gpgme_protocol_t protocol); gpgme_error_t (*set_protocol) (void *engine, gpgme_protocol_t protocol);
gpgme_error_t (*set_options) (void *engine, const char *options);
const char *(*get_options) (void *engine);
gpgme_error_t (*decrypt) (void *engine, gpgme_data_t ciph, gpgme_error_t (*decrypt) (void *engine, gpgme_data_t ciph,
gpgme_data_t plain); gpgme_data_t plain);
gpgme_error_t (*decrypt_verify) (void *engine, gpgme_data_t ciph, gpgme_error_t (*decrypt_verify) (void *engine, gpgme_data_t ciph,

View File

@ -775,6 +775,8 @@ struct engine_ops _gpgme_engine_ops_g13 =
NULL, /* set_colon_line_handler */ NULL, /* set_colon_line_handler */
g13_set_locale, g13_set_locale,
NULL, /* set_protocol */ NULL, /* set_protocol */
NULL, /* set_options */
NULL, /* get_options */
NULL, /* decrypt */ NULL, /* decrypt */
NULL, /* decrypt_verify */ NULL, /* decrypt_verify */
NULL, /* delete */ NULL, /* delete */

View File

@ -115,6 +115,7 @@ struct engine_gpg
char **argv; char **argv;
struct fd_data_map_s *fd_data_map; struct fd_data_map_s *fd_data_map;
char *options; /* gpgme_ctx_set_engine_options() */
/* stuff needed for interactive (command) mode */ /* stuff needed for interactive (command) mode */
struct struct
@ -404,6 +405,7 @@ gpg_release (void *engine)
free (gpg->status.buffer); free (gpg->status.buffer);
if (gpg->colon.buffer) if (gpg->colon.buffer)
free (gpg->colon.buffer); free (gpg->colon.buffer);
free (gpg->options);
if (gpg->argv) if (gpg->argv)
free_argv (gpg->argv); free_argv (gpg->argv);
if (gpg->cmd.keyword) if (gpg->cmd.keyword)
@ -716,6 +718,43 @@ gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
} }
/* Custom command line options set with gpgme_ctx_set_engine_options() */
static gpgme_error_t
build_custom_argv (engine_gpg_t gpg, size_t *argc, char ***result)
{
char *s, *options = gpg->options;
char **argv = NULL;
int total = 0;
if (!options)
return 0;
while ((s = strsep (&options, " ")))
{
char **tmp = realloc (argv, (total+2) * sizeof (char *));
if (!tmp)
{
free_argv (argv);
return GPG_ERR_ENOMEM;
}
argv = tmp;
argv[total] = strdup (s);
if (!argv[total++])
{
free_argv (argv);
return GPG_ERR_ENOMEM;
}
argv[total] = NULL;
(*argc)++;
}
*result = argv;
return 0;
}
static gpgme_error_t static gpgme_error_t
build_argv (engine_gpg_t gpg, const char *pgmname) build_argv (engine_gpg_t gpg, const char *pgmname)
{ {
@ -723,7 +762,7 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
struct arg_and_data_s *a; struct arg_and_data_s *a;
struct fd_data_map_s *fd_data_map; struct fd_data_map_s *fd_data_map;
size_t datac=0, argc=0; size_t datac=0, argc=0;
char **argv; char **argv, **custom_argv = NULL, **pp;
int need_special = 0; int need_special = 0;
int use_agent = 0; int use_agent = 0;
char *p; char *p;
@ -780,6 +819,10 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
argc++; /* --batch */ argc++; /* --batch */
argc += 1; /* --no-sk-comments */ argc += 1; /* --no-sk-comments */
err = build_custom_argv (gpg, &argc, &custom_argv);
if (err)
return err;
argv = calloc (argc + 1, sizeof *argv); argv = calloc (argc + 1, sizeof *argv);
if (!argv) if (!argv)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
@ -801,6 +844,14 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
return saved_err; return saved_err;
} }
argc++; argc++;
if (custom_argv)
{
for (pp = custom_argv; pp && *pp; pp++)
argv[argc++] = *pp;
free (custom_argv);
}
if (need_special) if (need_special)
{ {
argv[argc] = strdup ("--enable-special-filenames"); argv[argc] = strdup ("--enable-special-filenames");
@ -2449,6 +2500,30 @@ gpg_set_pinentry_mode (void *engine, gpgme_pinentry_mode_t mode)
return 0; return 0;
} }
static gpgme_error_t
gpg_set_options (void *engine, const char *options)
{
engine_gpg_t gpg = engine;
free (gpg->options);
gpg->options = NULL;
if (options)
{
gpg->options = strdup (options);
if (!gpg->options)
return GPG_ERR_ENOMEM;
}
return 0;
}
static const char *
gpg_get_options (void *engine)
{
engine_gpg_t gpg = engine;
return gpg->options;
}
struct engine_ops _gpgme_engine_ops_gpg = struct engine_ops _gpgme_engine_ops_gpg =
@ -2468,6 +2543,8 @@ struct engine_ops _gpgme_engine_ops_gpg =
gpg_set_colon_line_handler, gpg_set_colon_line_handler,
gpg_set_locale, gpg_set_locale,
NULL, /* set_protocol */ NULL, /* set_protocol */
gpg_set_options,
gpg_get_options,
gpg_decrypt, gpg_decrypt,
gpg_decrypt, /* decrypt_verify */ gpg_decrypt, /* decrypt_verify */
gpg_delete, gpg_delete,

View File

@ -939,6 +939,8 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
NULL, /* set_colon_line_handler */ NULL, /* set_colon_line_handler */
NULL, /* set_locale */ NULL, /* set_locale */
NULL, /* set_protocol */ NULL, /* set_protocol */
NULL, /* set_options */
NULL, /* get_options */
NULL, /* decrypt */ NULL, /* decrypt */
NULL, /* decrypt_verify */ NULL, /* decrypt_verify */
NULL, /* delete */ NULL, /* delete */

View File

@ -1988,6 +1988,8 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
gpgsm_set_colon_line_handler, gpgsm_set_colon_line_handler,
gpgsm_set_locale, gpgsm_set_locale,
NULL, /* set_protocol */ NULL, /* set_protocol */
NULL, /* set_options */
NULL, /* get_options */
gpgsm_decrypt, gpgsm_decrypt,
gpgsm_decrypt, gpgsm_decrypt,
gpgsm_delete, /* decrypt_verify */ gpgsm_delete, /* decrypt_verify */

View File

@ -445,6 +445,8 @@ struct engine_ops _gpgme_engine_ops_spawn =
NULL, /* set_colon_line_handler */ NULL, /* set_colon_line_handler */
NULL, /* set_locale */ NULL, /* set_locale */
NULL, /* set_protocol */ NULL, /* set_protocol */
NULL, /* set_options */
NULL, /* get_options */
NULL, /* decrypt */ NULL, /* decrypt */
NULL, /* decrypt_verify */ NULL, /* decrypt_verify */
NULL, /* delete */ NULL, /* delete */

View File

@ -1316,6 +1316,8 @@ struct engine_ops _gpgme_engine_ops_uiserver =
uiserver_set_colon_line_handler, uiserver_set_colon_line_handler,
uiserver_set_locale, uiserver_set_locale,
uiserver_set_protocol, uiserver_set_protocol,
NULL, /* set_options */
NULL, /* get_options */
uiserver_decrypt, uiserver_decrypt,
uiserver_decrypt_verify, uiserver_decrypt_verify,
NULL, /* delete */ NULL, /* delete */

View File

@ -445,6 +445,37 @@ gpgme_set_engine_info (gpgme_protocol_t proto,
return err; return err;
} }
/* Set custom command line options for the engine associated with a
context. */
gpgme_error_t
gpgme_ctx_set_engine_options (gpgme_ctx_t ctx, const char *options)
{
if (!ctx || !ctx->engine)
return gpg_error (GPG_ERR_INV_VALUE);
if (!ctx->engine->ops->set_options)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return (*ctx->engine->ops->set_options) (ctx->engine->engine, options);
}
/* Return previously set custom engine command line options. */
gpgme_error_t
gpgme_ctx_get_engine_options (gpgme_ctx_t ctx, const char **result)
{
if (!ctx || !ctx->engine)
return gpg_error (GPG_ERR_INV_VALUE);
if (!result)
return gpg_error (GPG_ERR_INV_ARG);
if (!ctx->engine->ops->get_options)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
*result = (*ctx->engine->ops->get_options) (ctx->engine->engine);
return 0;
}
gpgme_error_t gpgme_error_t
_gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine) _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine)

View File

@ -217,5 +217,7 @@ EXPORTS
gpgme_op_spawn_start @163 gpgme_op_spawn_start @163
gpgme_op_spawn @164 gpgme_op_spawn @164
gpgme_ctx_set_engine_options @165
gpgme_ctx_get_engine_options @166
; END ; END

View File

@ -947,6 +947,15 @@ gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx,
const char *file_name, const char *file_name,
const char *home_dir); const char *home_dir);
/* Set custom command line options for the engine associated with a
context. */
gpgme_error_t gpgme_ctx_set_engine_options (gpgme_ctx_t ctx,
const char *options);
/* Return previously set custom engine command line options. */
gpgme_error_t gpgme_ctx_get_engine_options (gpgme_ctx_t ctx,
const char **result);
/* Return a statically allocated string with the name of the public /* Return a statically allocated string with the name of the public
key algorithm ALGO, or NULL if that name is not known. */ key algorithm ALGO, or NULL if that name is not known. */

View File

@ -92,6 +92,9 @@ GPGME_1.1 {
gpgme_op_spawn_start; gpgme_op_spawn_start;
gpgme_op_spawn; gpgme_op_spawn;
gpgme_ctx_set_engine_options;
gpgme_ctx_get_engine_options;
}; };

View File

@ -83,9 +83,19 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
struct gpgme_io_cbs io_cbs; struct gpgme_io_cbs io_cbs;
int no_reset = (type & 256); int no_reset = (type & 256);
int reuse_engine = 0; int reuse_engine = 0;
char *options = NULL;
const char *tmp = NULL;
type &= 255; type &= 255;
err = gpgme_ctx_get_engine_options (ctx, &tmp);
if (tmp)
{
options = strdup (tmp);
if (!options)
return GPG_ERR_ENOMEM;
}
_gpgme_release_result (ctx); _gpgme_release_result (ctx);
LOCK (ctx->lock); LOCK (ctx->lock);
ctx->canceled = 0; ctx->canceled = 0;
@ -119,7 +129,21 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
err = _gpgme_engine_new (info, &ctx->engine); err = _gpgme_engine_new (info, &ctx->engine);
if (err) if (err)
return err; return err;
if (options)
{
err = gpgme_ctx_set_engine_options (ctx, options);
if (err && gpg_err_code (err) != GPG_ERR_NOT_IMPLEMENTED)
{
free (options);
_gpgme_engine_release (ctx->engine);
ctx->engine = NULL;
return err;
} }
}
}
free (options);
if (!reuse_engine) if (!reuse_engine)
{ {