gpgme_tool: Support GPG's new pinentry-mode.
* src/gpgme-tool.c (log_error): Do not always print the error source. (gt_set_pinentry_mode): New. (server_passphrase_cb): New. (cmd_pinentry_mode): New. (register_commands): Add cmd_pinentry_mode. (options): Add option --gpg-binary. (struct args): Add field gpg-binary. (parse_options, main): Implement that option.
This commit is contained in:
parent
61a0d92b67
commit
02a2cf0ccb
118
src/gpgme-tool.c
118
src/gpgme-tool.c
@ -1,5 +1,5 @@
|
||||
/* gpgme-tool.c - Assuan server exposing GnuPG Made Easy operations.
|
||||
Copyright (C) 2009, 2010, 2012 g10 Code GmbH
|
||||
Copyright (C) 2009, 2010, 2012, 2013 g10 Code GmbH
|
||||
Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GPGME.
|
||||
@ -645,8 +645,11 @@ log_error (int status, gpg_error_t errnum, const char *fmt, ...)
|
||||
vfprintf (log_stream, fmt, ap);
|
||||
va_end (ap);
|
||||
if (errnum)
|
||||
fprintf (log_stream, ": %s <%s>", gpg_strerror (errnum),
|
||||
gpg_strsource (errnum));
|
||||
{
|
||||
fprintf (log_stream, ": %s", gpg_strerror (errnum));
|
||||
if (gpg_err_source (errnum) != GPG_ERR_SOURCE_GPGME)
|
||||
fprintf (log_stream, " <%s>", gpg_strsource (errnum));
|
||||
}
|
||||
fprintf (log_stream, "\n");
|
||||
if (status)
|
||||
exit (status);
|
||||
@ -1466,6 +1469,10 @@ typedef struct gpgme_tool *gpgme_tool_t;
|
||||
/* Forward declaration. */
|
||||
void gt_write_status (gpgme_tool_t gt,
|
||||
status_t status, ...) GT_GCC_A_SENTINEL(0);
|
||||
static gpg_error_t
|
||||
server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
|
||||
int was_bad, int fd);
|
||||
|
||||
|
||||
void
|
||||
_gt_progress_cb (void *opaque, const char *what,
|
||||
@ -1495,9 +1502,10 @@ _gt_gpgme_new (gpgme_tool_t gt, gpgme_ctx_t *ctx)
|
||||
void
|
||||
gt_init (gpgme_tool_t gt)
|
||||
{
|
||||
memset (gt, '\0', sizeof (*gt));
|
||||
gpg_error_t err;
|
||||
|
||||
memset (gt, '\0', sizeof (*gt));
|
||||
|
||||
err = _gt_gpgme_new (gt, >->ctx);
|
||||
if (err)
|
||||
log_error (1, err, "can't create gpgme context");
|
||||
@ -1776,6 +1784,19 @@ gt_get_sub_protocol (gpgme_tool_t gt)
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
gt_set_pinentry_mode (gpgme_tool_t gt, gpgme_pinentry_mode_t mode, void *opaque)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
gpgme_set_passphrase_cb (gt->ctx, NULL, NULL);
|
||||
err = gpgme_set_pinentry_mode (gt->ctx, mode);
|
||||
if (!err && mode == GPGME_PINENTRY_MODE_LOOPBACK)
|
||||
gpgme_set_passphrase_cb (gt->ctx, server_passphrase_cb, opaque);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
gt_set_armor (gpgme_tool_t gt, int armor)
|
||||
{
|
||||
@ -2151,6 +2172,41 @@ server_write_data (void *hook, const void *buf, size_t len)
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
|
||||
int was_bad, int fd)
|
||||
{
|
||||
struct server *server = opaque;
|
||||
gpg_error_t err;
|
||||
unsigned char *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
|
||||
if (server && server->assuan_ctx)
|
||||
{
|
||||
if (uid_hint)
|
||||
assuan_write_status (server->assuan_ctx, "USERID_HINT", uid_hint);
|
||||
if (info)
|
||||
assuan_write_status (server->assuan_ctx, "NEED_PASSPHRASE", info);
|
||||
|
||||
err = assuan_inquire (server->assuan_ctx, "PASSPHRASE",
|
||||
&buf, &buflen, 100);
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NO_PASSPHRASE);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
/* We take care to always send a LF. */
|
||||
if (gpgme_io_writen (fd, buf, buflen))
|
||||
err = gpg_error_from_syserror ();
|
||||
else if (!memchr (buf, '\n', buflen) && gpgme_io_writen (fd, "\n", 1))
|
||||
err = gpg_error_from_syserror ();
|
||||
}
|
||||
free (buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Wrapper around assuan_command_parse_fd to also handle a
|
||||
"file=FILENAME" argument. On success either a filename is returned
|
||||
at FILENAME or a file descriptor at RFD; the other one is set to
|
||||
@ -2367,6 +2423,39 @@ cmd_sub_protocol (assuan_context_t ctx, char *line)
|
||||
}
|
||||
|
||||
|
||||
static const char hlp_pinentry_mode[] =
|
||||
"PINENTRY_MODE <name>\n"
|
||||
"\n"
|
||||
"Set the pinentry mode to NAME. Allowedvalues for NAME are:\n"
|
||||
" default - reset to the default of the engine,\n"
|
||||
" ask - force the use of the pinentry,\n"
|
||||
" cancel - emulate use of pinentry's cancel button,\n"
|
||||
" error - return a pinentry error,\n"
|
||||
" loopback - redirect pinentry queries to the caller.\n"
|
||||
"Note that only recent versions of GPG support changing the pinentry mode.";
|
||||
static gpg_error_t
|
||||
cmd_pinentry_mode (assuan_context_t ctx, char *line)
|
||||
{
|
||||
struct server *server = assuan_get_pointer (ctx);
|
||||
gpgme_pinentry_mode_t mode;
|
||||
|
||||
if (!line || !*line || !strcmp (line, "default"))
|
||||
mode = GPGME_PINENTRY_MODE_DEFAULT;
|
||||
else if (!strcmp (line, "ask"))
|
||||
mode = GPGME_PINENTRY_MODE_ASK;
|
||||
else if (!strcmp (line, "cancel"))
|
||||
mode = GPGME_PINENTRY_MODE_CANCEL;
|
||||
else if (!strcmp (line, "error"))
|
||||
mode = GPGME_PINENTRY_MODE_ERROR;
|
||||
else if (!strcmp (line, "loopback"))
|
||||
mode = GPGME_PINENTRY_MODE_LOOPBACK;
|
||||
else
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
return gt_set_pinentry_mode (server->gt, mode, server);
|
||||
}
|
||||
|
||||
|
||||
static const char hlp_armor[] =
|
||||
"ARMOR [true|false]\n"
|
||||
"\n"
|
||||
@ -3354,6 +3443,7 @@ register_commands (assuan_context_t ctx)
|
||||
{ "ENGINE", cmd_engine, hlp_engine },
|
||||
{ "PROTOCOL", cmd_protocol, hlp_protocol },
|
||||
{ "SUB_PROTOCOL", cmd_sub_protocol, hlp_sub_protocol },
|
||||
{ "PINENTRY_MODE", cmd_pinentry_mode, hlp_pinentry_mode },
|
||||
{ "ARMOR", cmd_armor, hlp_armor },
|
||||
{ "TEXTMODE", cmd_textmode, hlp_textmode },
|
||||
{ "INCLUDE_CERTS", cmd_include_certs, hlp_include_certs },
|
||||
@ -3410,7 +3500,6 @@ register_commands (assuan_context_t ctx)
|
||||
}
|
||||
|
||||
|
||||
/* TODO: password callback can do INQUIRE. */
|
||||
void
|
||||
gpgme_server (gpgme_tool_t gt)
|
||||
{
|
||||
@ -3495,6 +3584,7 @@ static char args_doc[] = "COMMAND [OPTIONS...]";
|
||||
|
||||
static struct argp_option options[] = {
|
||||
{ "server", 's', 0, 0, "Server mode" },
|
||||
{ "gpg-binary", 501, "FILE", 0, "Use FILE for the GPG backend" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@ -3504,6 +3594,7 @@ static struct argp argp = { options, parse_options, args_doc, doc };
|
||||
struct args
|
||||
{
|
||||
enum { CMD_DEFAULT, CMD_SERVER } cmd;
|
||||
const char *gpg_binary;
|
||||
};
|
||||
|
||||
void
|
||||
@ -3524,6 +3615,10 @@ parse_options (int key, char *arg, struct argp_state *state)
|
||||
case 's':
|
||||
args->cmd = CMD_SERVER;
|
||||
break;
|
||||
|
||||
case 501:
|
||||
args->gpg_binary = arg;
|
||||
break;
|
||||
#if 0
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num >= 2)
|
||||
@ -3548,6 +3643,7 @@ main (int argc, char *argv[])
|
||||
{
|
||||
struct args args;
|
||||
struct gpgme_tool gt;
|
||||
gpg_error_t err;
|
||||
|
||||
#ifdef HAVE_SETLOCALE
|
||||
setlocale (LC_ALL, "");
|
||||
@ -3565,6 +3661,18 @@ main (int argc, char *argv[])
|
||||
argp_parse (&argp, argc, argv, 0, 0, &args);
|
||||
log_init ();
|
||||
|
||||
if (args.gpg_binary)
|
||||
{
|
||||
if (access (args.gpg_binary, X_OK))
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP,
|
||||
args.gpg_binary, NULL);
|
||||
if (err)
|
||||
log_error (1, err, "error witching OpenPGP engine to '%s'",
|
||||
args.gpg_binary);
|
||||
}
|
||||
|
||||
gt_init (>);
|
||||
|
||||
switch (args.cmd)
|
||||
|
@ -205,5 +205,8 @@ EXPORTS
|
||||
gpgme_set_global_flag @156
|
||||
|
||||
gpgme_io_writen @157
|
||||
|
||||
gpgme_set_pinentry_mode @158
|
||||
|
||||
; END
|
||||
|
||||
|
@ -83,6 +83,8 @@ GPGME_1.1 {
|
||||
gpgme_set_global_flag;
|
||||
|
||||
gpgme_io_writen;
|
||||
|
||||
gpgme_set_pinentry_mode;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user