From f8b4cd76501824d56d3cf78a8ba85291a62f0e6d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 1 Apr 2009 10:51:53 +0000 Subject: [PATCH] Import/export of pkcs#12 now uses the gpg-agent directly. Removed duplicated code (percent unescaping). --- NEWS | 3 + agent/ChangeLog | 18 +++ agent/Makefile.am | 6 +- agent/call-pinentry.c | 1 + agent/call-scd.c | 40 +----- agent/command.c | 38 +----- agent/protect-tool.c | 268 +++++++++++++----------------------- common/ChangeLog | 19 +++ common/Makefile.am | 5 +- common/exechelp.c | 11 ++ common/get-passphrase.c | 277 ++++++++++++++++++++++++++++++++++++++ common/get-passphrase.h | 47 +++++++ common/membuf.c | 14 +- common/percent.c | 155 ++++++++++++++++++++- common/sysutils.c | 8 +- common/t-percent.c | 20 ++- common/util.h | 5 + g10/ChangeLog | 8 ++ g10/call-agent.c | 27 +--- g10/main.h | 1 - g10/misc.c | 33 ----- g10/passphrase.c | 5 +- scd/ChangeLog | 5 + scd/command.c | 37 +---- sm/ChangeLog | 6 + sm/export.c | 12 +- sm/import.c | 12 +- tools/gpg-connect-agent.c | 2 +- tools/gpgconf-comp.c | 2 +- 29 files changed, 716 insertions(+), 369 deletions(-) create mode 100644 common/get-passphrase.c create mode 100644 common/get-passphrase.h diff --git a/NEWS b/NEWS index 015ca1663..f0667eb5e 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,9 @@ Noteworthy changes in version 2.0.12 (not released) * Support for the Telesec Netkey 3 cards. + * The gpg-protect-tool now uses gpg-agent via libassuan. Under + Windows the Pinentry will now be put into the foreground. + Noteworthy changes in version 2.0.11 (2009-03-03) ------------------------------------------------- diff --git a/agent/ChangeLog b/agent/ChangeLog index 10390da3f..e691ad7e6 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,21 @@ +2009-04-01 Werner Koch + + * protect-tool.c (pe_opt): New. + (opts): Add option --agent-program. Use ARGPARSE macros. + (get_new_passphrase): Remove. + (get_passphrase): Use gpg-agent directly. Remove arg OPT_CHECK and + change all callers. + * Makefile.am (gpg_protect_tool_LDADD): Replace pwquery_libs by + LIBASSUAN_LIBS. + (gpg_protect_tool_CFLAGS): New. + + * command.c (percent_plus_unescape): Remove. + (cmd_putval): Use percent_plus_unescape_inplace. + * call-scd.c (unescape_status_string): Remove. + (card_getattr_cb): Use percent_plus_unescape. + * protect-tool.c (main): Use percent_plus_unescape from common/. + (percent_plus_unescape, percent_plus_unescape_string): Remove. + 2009-03-27 Werner Koch * learncard.c (agent_handle_learn): Add new certtype 111. diff --git a/agent/Makefile.am b/agent/Makefile.am index 95ffafeec..c2830a94b 100644 --- a/agent/Makefile.am +++ b/agent/Makefile.am @@ -74,9 +74,9 @@ gpg_protect_tool_SOURCES = \ protect.c \ minip12.c minip12.h -# Needs $(NETLIBS) for libsimple-pwquery.la. -gpg_protect_tool_LDADD = $(pwquery_libs) $(common_libs) \ - $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) +gpg_protect_tool_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) +gpg_protect_tool_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \ + $(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) gpg_preset_passphrase_SOURCES = \ preset-passphrase.c diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 86792d8d7..c840bb68d 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -105,6 +105,7 @@ static void dump_mutex_state (pth_mutex_t *m) { #ifdef _W32_PTH_H + (void)m; log_printf ("unknown under W32"); #else if (!(m->mx_state & PTH_MUTEX_INITIALIZED)) diff --git a/agent/call-scd.c b/agent/call-scd.c index f45e94097..d09812e57 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -136,6 +136,7 @@ static void dump_mutex_state (pth_mutex_t *m) { #ifdef _W32_PTH_H + (void)m; log_printf ("unknown under W32"); #else if (!(m->mx_state & PTH_MUTEX_INITIALIZED)) @@ -561,43 +562,6 @@ agent_reset_scd (ctrl_t ctrl) } - -/* Return a new malloced string by unescaping the string S. Escaping - is percent escaping and '+'/space mapping. A binary Nul will - silently be replaced by a 0xFF. Function returns NULL to indicate - an out of memory status. */ -static char * -unescape_status_string (const unsigned char *s) -{ - char *buffer, *d; - - buffer = d = xtrymalloc (strlen ((const char*)s)+1); - if (!buffer) - return NULL; - while (*s) - { - if (*s == '%' && s[1] && s[2]) - { - s++; - *d = xtoi_2 (s); - if (!*d) - *d = '\xff'; - d++; - s += 2; - } - else if (*s == '+') - { - *d++ = ' '; - s++; - } - else - *d++ = *s++; - } - *d = 0; - return buffer; -} - - static int learn_status_cb (void *opaque, const char *line) @@ -1045,7 +1009,7 @@ card_getattr_cb (void *opaque, const char *line) if (keywordlen == parm->keywordlen && !memcmp (keyword, parm->keyword, keywordlen)) { - parm->data = unescape_status_string ((const unsigned char*)line); + parm->data = percent_plus_unescape ((const unsigned char*)line, 0xff); if (!parm->data) parm->error = errno; } diff --git a/agent/command.c b/agent/command.c index 56d390bd8..728b160a8 100644 --- a/agent/command.c +++ b/agent/command.c @@ -236,42 +236,6 @@ plus_to_blank (char *s) } -/* Do the percent and plus/space unescaping in place and return the - length of the valid buffer. */ -static size_t -percent_plus_unescape (char *string) -{ - unsigned char *p = (unsigned char *)string; - size_t n = 0; - - while (*string) - { - if (*string == '%' && string[1] && string[2]) - { - string++; - *p++ = xtoi_2 (string); - n++; - string+= 2; - } - else if (*string == '+') - { - *p++ = ' '; - n++; - string++; - } - else - { - *p++ = *string++; - n++; - } - } - - return n; -} - - - - /* Parse a hex string. Return an Assuan error code or 0 on success and the length of the parsed string in LEN. */ static int @@ -1494,7 +1458,7 @@ cmd_putval (assuan_context_t ctx, char *line) p = strchr (value, ' '); if (p) *p = 0; - valuelen = percent_plus_unescape (value); + valuelen = percent_plus_unescape_inplace (value, 0); } } if (!key || !*key) diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 848ad9f4b..d0b68a1fa 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -41,13 +41,14 @@ #define JNLIB_NEED_LOG_LOGV #include "agent.h" #include "minip12.h" -#include "simple-pwquery.h" #include "i18n.h" +#include "get-passphrase.h" #include "sysutils.h" enum cmd_and_opt_values -{ aNull = 0, +{ + aNull = 0, oVerbose = 'v', oArmor = 'a', oPassphrase = 'P', @@ -72,17 +73,19 @@ enum cmd_and_opt_values oPrompt, oStatusMsg, -aTest }; + oAgentProgram +}; + struct rsa_secret_key_s - { - gcry_mpi_t n; /* public modulus */ - gcry_mpi_t e; /* public exponent */ - gcry_mpi_t d; /* exponent */ - gcry_mpi_t p; /* prime p. */ - gcry_mpi_t q; /* prime q. */ - gcry_mpi_t u; /* inverse of p mod q. */ - }; +{ + gcry_mpi_t n; /* public modulus */ + gcry_mpi_t e; /* public exponent */ + gcry_mpi_t d; /* exponent */ + gcry_mpi_t p; /* prime p. */ + gcry_mpi_t q; /* prime q. */ + gcry_mpi_t u; /* inverse of p mod q. */ +}; static const char *opt_homedir; @@ -96,41 +99,51 @@ static const char *opt_passphrase; static char *opt_prompt; static int opt_status_msg; static const char *opt_p12_charset; +static const char *opt_agent_program; -static char *get_passphrase (int promptno, int opt_check); -static char *get_new_passphrase (int promptno); +static char *get_passphrase (int promptno); static void release_passphrase (char *pw); static int store_private_key (const unsigned char *grip, const void *buffer, size_t length, int force); static ARGPARSE_OPTS opts[] = { + ARGPARSE_group (300, N_("@Commands:\n ")), + + ARGPARSE_c (oProtect, "protect", "protect a private key"), + ARGPARSE_c (oUnprotect, "unprotect", "unprotect a private key"), + ARGPARSE_c (oShadow, "shadow", "create a shadow entry for a public key"), + ARGPARSE_c (oShowShadowInfo, "show-shadow-info", "return the shadow info"), + ARGPARSE_c (oShowKeygrip, "show-keygrip", "show the \"keygrip\""), + ARGPARSE_c (oP12Import, "p12-import", + "import a pkcs#12 encoded private key"), + ARGPARSE_c (oP12Export, "p12-export", + "export a private key pkcs#12 encoded"), - { 301, NULL, 0, N_("@Options:\n ") }, + ARGPARSE_group (301, N_("@\nOptions:\n ")), - { oVerbose, "verbose", 0, "verbose" }, - { oArmor, "armor", 0, "write output in advanced format" }, - { oCanonical, "canonical", 0, "write output in canonical format" }, - { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" }, - { oProtect, "protect", 256, "protect a private key"}, - { oUnprotect, "unprotect", 256, "unprotect a private key"}, - { oShadow, "shadow", 256, "create a shadow entry for a public key"}, - { oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"}, - { oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""}, + ARGPARSE_s_n (oVerbose, "verbose", "verbose"), + ARGPARSE_s_n (oArmor, "armor", "write output in advanced format"), + ARGPARSE_s_n (oCanonical, "canonical", "write output in canonical format"), - { oP12Import, "p12-import", 256, "import a pkcs#12 encoded private key"}, - { oP12Export, "p12-export", 256, "export a private key pkcs#12 encoded"}, - { oP12Charset,"p12-charset", 2, - "|NAME|set charset for a new PKCS#12 passphrase to NAME" }, - { oHaveCert, "have-cert", 0, "certificate to export provided on STDIN"}, - { oStore, "store", 0, "store the created key in the appropriate place"}, - { oForce, "force", 0, "force overwriting"}, - { oNoFailOnExist, "no-fail-on-exist", 0, "@" }, - { oHomedir, "homedir", 2, "@" }, - { oPrompt, "prompt", 2, "|ESCSTRING|use ESCSTRING as prompt in pinentry"}, - { oStatusMsg, "enable-status-msg", 0, "@"}, + ARGPARSE_s_s (oPassphrase, "passphrase", "|STRING|use passphrase STRING"), + ARGPARSE_s_s (oP12Charset,"p12-charset", + "|NAME|set charset for a new PKCS#12 passphrase to NAME"), + ARGPARSE_s_n (oHaveCert, "have-cert", + "certificate to export provided on STDIN"), + ARGPARSE_s_n (oStore, "store", + "store the created key in the appropriate place"), + ARGPARSE_s_n (oForce, "force", + "force overwriting"), + ARGPARSE_s_n (oNoFailOnExist, "no-fail-on-exist", "@"), + ARGPARSE_s_s (oHomedir, "homedir", "@"), + ARGPARSE_s_s (oPrompt, "prompt", + "|ESCSTRING|use ESCSTRING as prompt in pinentry"), + ARGPARSE_s_n (oStatusMsg, "enable-status-msg", "@"), - {0} + ARGPARSE_s_s (oAgentProgram, "agent-program", "@"), + + ARGPARSE_end () }; static const char * @@ -158,9 +171,6 @@ my_strusage (int level) } -/* Include the implementation of map_spwq_error. */ -MAP_SPWQ_ERROR_IMPL - /* static void */ /* print_mpi (const char *text, gcry_mpi_t a) */ /* { */ @@ -333,7 +343,7 @@ read_and_protect (const char *fname) if (!key) return; - pw = get_passphrase (1, 0); + pw = get_passphrase (1); rc = agent_protect (key, pw, &result, &resultlen); release_passphrase (pw); xfree (key); @@ -372,7 +382,7 @@ read_and_unprotect (const char *fname) if (!key) return; - rc = agent_unprotect (key, (pw=get_passphrase (1, 0)), + rc = agent_unprotect (key, (pw=get_passphrase (1)), protected_at, &result, &resultlen); release_passphrase (pw); xfree (key); @@ -678,7 +688,7 @@ import_p12_file (const char *fname) buf_off = 0; kparms = p12_parse ((unsigned char*)buf+buf_off, buflen-buf_off, - (pw=get_passphrase (2, 0)), + (pw=get_passphrase (2)), import_p12_cert_cb, NULL); release_passphrase (pw); xfree (buf); @@ -753,12 +763,8 @@ import_p12_file (const char *fname) assert (buflen); gcry_sexp_release (s_key); - - pw = get_new_passphrase (4); - if (!pw) - rc = gpg_error (GPG_ERR_CANCELED); - else - rc = agent_protect (key, pw, &result, &resultlen); + pw = get_passphrase (4); + rc = agent_protect (key, pw, &result, &resultlen); release_passphrase (pw); xfree (key); if (rc) @@ -896,7 +902,7 @@ export_p12_file (const char *fname) unsigned char *tmpkey; size_t tmplen; - rc = agent_unprotect (key, (pw=get_passphrase (1, 0)), + rc = agent_unprotect (key, (pw=get_passphrase (1)), NULL, &tmpkey, &tmplen); release_passphrase (pw); if (rc) @@ -985,11 +991,8 @@ export_p12_file (const char *fname) kparms[7] = sk.u; kparms[8] = NULL; - pw = get_new_passphrase (3); - if (!pw) - key = NULL; - else - key = p12_build (kparms, cert, certlen, pw, opt_p12_charset, &keylen); + pw = get_passphrase (3); + key = p12_build (kparms, cert, certlen, pw, opt_p12_charset, &keylen); release_passphrase (pw); xfree (cert); for (i=0; i < 8; i++) @@ -1005,54 +1008,6 @@ export_p12_file (const char *fname) } - -/* Do the percent and plus/space unescaping in place and return the - length of the valid buffer. */ -static size_t -percent_plus_unescape (unsigned char *string) -{ - unsigned char *p = string; - size_t n = 0; - - while (*string) - { - if (*string == '%' && string[1] && string[2]) - { - string++; - *p++ = xtoi_2 (string); - n++; - string+= 2; - } - else if (*string == '+') - { - *p++ = ' '; - n++; - string++; - } - else - { - *p++ = *string++; - n++; - } - } - - return n; -} - -/* Remove percent and plus escaping and make sure that the reuslt is a - string. This is done in place. Returns STRING. */ -static char * -percent_plus_unescape_string (char *string) -{ - unsigned char *p = (unsigned char*)string; - size_t n; - - n = percent_plus_unescape (p); - p[n] = 0; - - return string; -} - int main (int argc, char **argv ) @@ -1094,6 +1049,8 @@ main (int argc, char **argv ) case oCanonical: opt_canonical=1; break; case oHomedir: opt_homedir = pargs.r.ret_str; break; + case oAgentProgram: opt_agent_program = pargs.r.ret_str; break; + case oProtect: cmd = oProtect; break; case oUnprotect: cmd = oUnprotect; break; case oShadow: cmd = oShadow; break; @@ -1111,11 +1068,11 @@ main (int argc, char **argv ) case oPrompt: opt_prompt = pargs.r.ret_str; break; case oStatusMsg: opt_status_msg = 1; break; - default : pargs.err = 2; break; + default: pargs.err = ARGPARSE_PRINT_ERROR; break; } } - if (log_get_errorcount(0)) - exit(2); + if (log_get_errorcount (0)) + exit (2); fname = "-"; if (argc == 1) @@ -1123,15 +1080,15 @@ main (int argc, char **argv ) else if (argc > 1) usage (1); - /* Tell simple-pwquery about the the standard socket name. */ - { - char *tmp = make_filename (opt_homedir, "S.gpg-agent", NULL); - simple_pw_set_socket (tmp); - xfree (tmp); - } + /* Set the information which can't be taken from envvars. */ + gnupg_prepare_get_passphrase (GPG_ERR_SOURCE_DEFAULT, + opt.verbose, + opt_homedir, + opt_agent_program, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (opt_prompt) - opt_prompt = percent_plus_unescape_string (xstrdup (opt_prompt)); + opt_prompt = percent_plus_unescape (opt_prompt, 0); if (cmd == oProtect) read_and_protect (fname); @@ -1169,102 +1126,65 @@ agent_exit (int rc) 2 = for unprotecting a pkcs#12 object 3 = for protecting a new pkcs#12 object 4 = for protecting an imported pkcs#12 in our system - 5 = reenter the passphrase - When adding 100 to the values, a "does not match - try again" error - message is shown. */ static char * -get_passphrase (int promptno, int opt_check) +get_passphrase (int promptno) { char *pw; int err; const char *desc; char *orig_codeset; - int error_msgno; + int repeat = 0; if (opt_passphrase) return xstrdup (opt_passphrase); - error_msgno = promptno / 100; - promptno %= 100; - orig_codeset = i18n_switchto_utf8 (); if (promptno == 1 && opt_prompt) - desc = opt_prompt; + { + desc = opt_prompt; + } else if (promptno == 2) - desc = _("Please enter the passphrase to unprotect the " - "PKCS#12 object."); + { + desc = _("Please enter the passphrase to unprotect the " + "PKCS#12 object."); + } else if (promptno == 3) - desc = _("Please enter the passphrase to protect the " - "new PKCS#12 object."); + { + desc = _("Please enter the passphrase to protect the " + "new PKCS#12 object."); + repeat = 1; + } else if (promptno == 4) - desc = _("Please enter the passphrase to protect the " - "imported object within the GnuPG system."); - else if (promptno == 5) - desc = _("Please re-enter this passphrase"); + { + desc = _("Please enter the passphrase to protect the " + "imported object within the GnuPG system."); + repeat = 1; + } else desc = _("Please enter the passphrase or the PIN\n" "needed to complete this operation."); - pw = simple_pwquery (NULL, - error_msgno == 1? _("does not match - try again"):NULL, - _("Passphrase:"), desc, opt_check, &err); - err = map_spwq_error (err); - i18n_switchback (orig_codeset); - if (!pw) + err = gnupg_get_passphrase (NULL, NULL, _("Passphrase:"), desc, + repeat, repeat, 1, &pw); + if (err) { - if (err) + if (gpg_err_code (err) == GPG_ERR_CANCELED) + log_info (_("cancelled\n")); + else log_error (_("error while asking for the passphrase: %s\n"), gpg_strerror (err)); - else - log_info (_("cancelled\n")); agent_exit (0); } + assert (pw); return pw; } -/* Same as get_passphrase but requests it a second time and compares - it to the one entered the first time. */ -static char * -get_new_passphrase (int promptno) -{ - char *pw; - int i, secondpromptno; - - pw = get_passphrase (promptno, 1); - if (!pw) - return NULL; /* Canceled. */ - if (!*pw) - return pw; /* Empty passphrase - no need to ask for repeating it. */ - - secondpromptno = 5; - for (i=0; i < 3; i++) - { - char *pw2 = get_passphrase (secondpromptno, 0); - if (!pw2) - { - xfree (pw); - return NULL; /* Canceled. */ - } - if (!strcmp (pw, pw2)) - { - xfree (pw2); - return pw; /* Okay. */ - } - secondpromptno = 105; - xfree (pw2); - } - xfree (pw); - return NULL; /* 3 times repeated wrong - cancel. */ -} - - - static void release_passphrase (char *pw) { diff --git a/common/ChangeLog b/common/ChangeLog index 1cf4f50fc..af804f490 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,22 @@ +2009-04-01 Werner Koch + + * exechelp.c (gnupg_spawn_process): Implement new flag bit 6. + * sysutils.c (gnupg_allow_set_foregound_window): Allow the use of + ASFW_ANY. + + * membuf.c (put_membuf, get_membuf): Wipe memory on out of core. + +2009-03-31 Werner Koch + + * percent.c (percent_unescape, percent_plus_unescape): New. + (percent_plus_unescape_inplace, percent_unescape_inplace): New. + (do_plus_or_plain_unescape, count_unescape, do_unescape): New. + (do_unescape_inplace): New. + * t-percent.c (test_percent_plus_escape): Test percent_plus_unescape. + + * get-passphrase.c, get-passphrase.h: New. + * Makefile.am (without_pth_sources): New. + 2009-03-18 Werner Koch * exechelp.c: Include sys/resource.h and sys/stat.h. diff --git a/common/Makefile.am b/common/Makefile.am index 72c7d179f..2ef324e18 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -71,9 +71,12 @@ common_sources = \ localename.c \ helpfile.c +# Sources only useful without PTH. +without_pth_sources = \ + get-passphrase.c get-passphrase.h -libcommon_a_SOURCES = $(common_sources) +libcommon_a_SOURCES = $(common_sources) $(without_pth_sources) if USE_DNS_SRV libcommon_a_SOURCES += srv.c endif diff --git a/common/exechelp.c b/common/exechelp.c index 3d1136609..7019ae7a0 100644 --- a/common/exechelp.c +++ b/common/exechelp.c @@ -52,6 +52,7 @@ #include "util.h" #include "i18n.h" +#include "sysutils.h" #include "exechelp.h" /* Define to 1 do enable debugging. */ @@ -471,6 +472,10 @@ gnupg_create_inbound_pipe (int filedes[2]) This flag is only useful under W32 systems, so that no new console is created and pops up a console window when starting the server + + Bit 6: On W32 run AllowSetForegroundWindow for the child. Due to + error problems this actually allows SetForegroundWindow for + childs of this process. Returns 0 on success or an error code. */ gpg_error_t @@ -568,6 +573,12 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], /* " dwProcessID=%d dwThreadId=%d\n", */ /* pi.hProcess, pi.hThread, */ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ + + /* Fixme: For unknown reasons AllowSetForegroundWindow returns an + invalid argument error if we pass the the correct processID to + it. As a workaround we use -1 (ASFW_ANY). */ + if ( (flags & 64) ) + gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/); /* Process has been created suspended; resume it now. */ ResumeThread (pi.hThread); diff --git a/common/get-passphrase.c b/common/get-passphrase.c new file mode 100644 index 000000000..68d7b706a --- /dev/null +++ b/common/get-passphrase.c @@ -0,0 +1,277 @@ +/* get-passphrase.c - Ask for a passphrase via the agent + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "i18n.h" +#include "asshelp.h" +#include "membuf.h" +#include "sysutils.h" +#include "get-passphrase.h" + +/* The context used by this process to ask for the passphrase. */ +static assuan_context_t agent_ctx; +static struct +{ + gpg_err_source_t errsource; + int verbosity; + const char *homedir; + const char *agent_program; + const char *display; + const char *ttyname; + const char *ttytype; + const char *lc_ctype; + const char *lc_messages; + const char *xauthority; + const char *pinentry_user_data; +} agentargs; + + +/* Set local variable to be used for a possible agent startup. Note + that the strings are just pointers and should not anymore be + modified by the caller. */ +void +gnupg_prepare_get_passphrase (gpg_err_source_t errsource, + int verbosity, + const char *homedir, + const char *agent_program, + const char *opt_display, + const char *opt_ttyname, + const char *opt_ttytype, + const char *opt_lc_ctype, + const char *opt_lc_messages, + const char *opt_xauthority, + const char *opt_pinentry_user_data) +{ + agentargs.errsource = errsource; + agentargs.verbosity = verbosity; + agentargs.homedir = homedir; + agentargs.agent_program = agent_program; + agentargs.display = opt_display; + agentargs.ttyname = opt_ttyname; + agentargs.ttytype = opt_ttytype; + agentargs.lc_ctype = opt_lc_ctype; + agentargs.lc_messages = opt_lc_messages; + agentargs.xauthority = opt_xauthority; + agentargs.pinentry_user_data = opt_pinentry_user_data; +} + + +/* Try to connect to the agent via socket or fork it off and work by + pipes. Handle the server's initial greeting. */ +static gpg_error_t +start_agent (void) +{ + gpg_error_t err; + + /* Fixme: This code is not thread safe, thus we don't build it with + pth. We will need a context for each thread or serialize the + access to the agent. */ + if (agent_ctx) + return 0; + + err = start_new_gpg_agent (&agent_ctx, + agentargs.errsource, + agentargs.homedir, + agentargs.agent_program, + agentargs.display, + agentargs.ttyname, + agentargs.ttytype, + agentargs.lc_ctype, + agentargs.lc_messages, + agentargs.xauthority, + agentargs.pinentry_user_data, + agentargs.verbosity, 0, NULL, NULL); + if (!err) + { + /* Tell the agent that we support Pinentry notifications. No + error checking so that it will work with older agents. */ + assuan_transact (agent_ctx, "OPTION allow-pinentry-notify", + NULL, NULL, NULL, NULL, NULL, NULL); + } + + return err; +} + + +/* This is the default inquiry callback. It merely handles the + Pinentry notification. */ +static int +default_inq_cb (void *opaque, const char *line) +{ + (void)opaque; + + if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) + { + gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10)); + /* We do not return errors to avoid breaking other code. */ + } + else + log_debug ("ignoring gpg-agent inquiry `%s'\n", line); + + return 0; +} + + +static int +membuf_data_cb (void *opaque, const void *buffer, size_t length) +{ + membuf_t *data = opaque; + + if (buffer) + put_membuf (data, buffer, length); + return 0; +} + + +/* Ask for a passphrase via gpg-agent. On success the caller needs to + free the string stored at R_PASSPHRASE. On error NULL will be + stored at R_PASSPHRASE and an appropriate gpg error code is + returned. With REPEAT set to 1, gpg-agent will ask the user to + repeat the just entered passphrase. CACHE_ID is a gpg-agent style + passphrase cache id or NULL. ERR_MSG is a error message to be + presented to the user (e.g. "bad passphrase - try again") or NULL. + PROMPT is the prompt string to label the entry box, it may be NULL + for a default one. DESC_MSG is a longer description to be + displayed above the entry box, if may be NULL for a default one. + If USE_SECMEM is true, the returned passphrase is retruned in + secure memory. The length of all these strings is limited; they + need to fit in their encoded form into a standard Assuan line (i.e + less then about 950 characters). All strings shall be UTF-8. */ +gpg_error_t +gnupg_get_passphrase (const char *cache_id, + const char *err_msg, + const char *prompt, + const char *desc_msg, + int repeat, + int check_quality, + int use_secmem, + char **r_passphrase) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + const char *arg1 = NULL; + char *arg2 = NULL; + char *arg3 = NULL; + char *arg4 = NULL; + membuf_t data; + + *r_passphrase = NULL; + + err = start_agent (); + if (err) + return err; + + /* Check that the gpg-agent understands the repeat option. */ + if (assuan_transact (agent_ctx, + "GETINFO cmd_has_option GET_PASSPHRASE repeat", + NULL, NULL, NULL, NULL, NULL, NULL)) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + arg1 = cache_id && *cache_id? cache_id:NULL; + if (err_msg && *err_msg) + if (!(arg2 = percent_plus_escape (err_msg))) + goto no_mem; + if (prompt && *prompt) + if (!(arg3 = percent_plus_escape (prompt))) + goto no_mem; + if (desc_msg && *desc_msg) + if (!(arg4 = percent_plus_escape (desc_msg))) + goto no_mem; + + snprintf (line, DIM(line)-1, + "GET_PASSPHRASE --data %s--repeat=%d -- %s %s %s %s", + check_quality? "--check ":"", + repeat, + arg1? arg1:"X", + arg2? arg2:"X", + arg3? arg3:"X", + arg4? arg4:"X"); + line[DIM(line)-1] = 0; + xfree (arg2); + xfree (arg3); + xfree (arg4); + + if (use_secmem) + init_membuf_secure (&data, 64); + else + init_membuf (&data, 64); + err = assuan_transact (agent_ctx, line, + membuf_data_cb, &data, + default_inq_cb, NULL, NULL, NULL); + + /* Older Pinentries return the old assuan error code for canceled + which gets translated bt libassuan to GPG_ERR_ASS_CANCELED and + not to the code for a user cancel. Fix this here. */ + if (err && gpg_err_source (err) + && gpg_err_code (err) == GPG_ERR_ASS_CANCELED) + err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED); + + if (err) + { + void *p; + size_t n; + + p = get_membuf (&data, &n); + if (p) + wipememory (p, n); + xfree (p); + } + else + { + put_membuf (&data, "", 1); + *r_passphrase = get_membuf (&data, NULL); + if (!*r_passphrase) + err = gpg_error_from_syserror (); + } + return err; + no_mem: + err = gpg_error_from_syserror (); + xfree (arg2); + xfree (arg3); + xfree (arg4); + return err; +} + + +/* Flush the passphrase cache with Id CACHE_ID. */ +gpg_error_t +gnupg_clear_passphrase (const char *cache_id) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + + if (!cache_id || !*cache_id) + return 0; + + err = start_agent (); + if (err) + return err; + + snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id); + line[DIM(line)-1] = 0; + return assuan_transact (agent_ctx, line, NULL, NULL, + default_inq_cb, NULL, NULL, NULL); +} diff --git a/common/get-passphrase.h b/common/get-passphrase.h new file mode 100644 index 000000000..9457cdd3a --- /dev/null +++ b/common/get-passphrase.h @@ -0,0 +1,47 @@ +/* get-passphrase.h - Definitions to ask for a passphrase via the agent. + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef GNUPG_COMMON_GET_PASSPHRASE_H +#define GNUPG_COMMON_GET_PASSPHRASE_H + +void gnupg_prepare_get_passphrase (gpg_err_source_t errsource, + int verbosity, + const char *homedir, + const char *agent_program, + const char *opt_display, + const char *opt_ttyname, + const char *opt_ttytype, + const char *opt_lc_ctype, + const char *opt_lc_messages, + const char *opt_xauthority, + const char *opt_pinentry_user_data); + +gpg_error_t gnupg_get_passphrase (const char *cache_id, + const char *err_msg, + const char *prompt, + const char *desc_msg, + int repeat, + int check_quality, + int use_secmem, + char **r_passphrase); + +gpg_error_t gnupg_clear_passphrase (const char *cache_id); + + +#endif /*GNUPG_COMMON_GET_PASSPHRASE_H*/ diff --git a/common/membuf.c b/common/membuf.c index 9395eab6d..737930b76 100644 --- a/common/membuf.c +++ b/common/membuf.c @@ -1,5 +1,5 @@ -/* membuf.c - A simple implementation of a dynamic buffer - * Copyright (C) 2001, 2003 Free Software Foundation, Inc. +/* membuf.c - A simple implementation of a dynamic buffer. + * Copyright (C) 2001, 2003, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -75,7 +75,7 @@ put_membuf (membuf_t *mb, const void *buf, size_t len) in case we are storing sensitive data here. The membuf API does not provide another way to cleanup after an error. */ - memset (mb->buf, 0, mb->len); + wipememory (mb->buf, mb->len); return; } mb->buf = p; @@ -99,8 +99,12 @@ get_membuf (membuf_t *mb, size_t *len) if (mb->out_of_core) { - xfree (mb->buf); - mb->buf = NULL; + if (mb->buf) + { + wipememory (mb->buf, mb->len); + xfree (mb->buf); + mb->buf = NULL; + } errno = mb->out_of_core; return NULL; } diff --git a/common/percent.c b/common/percent.c index a0c78ec7b..e0c359289 100644 --- a/common/percent.c +++ b/common/percent.c @@ -1,5 +1,5 @@ /* percent.c - Percent escaping - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -21,6 +21,7 @@ #include #include #include +#include #include "util.h" @@ -74,3 +75,155 @@ percent_plus_escape (const char *string) return buffer; } + + +/* Do the percent and plus/space unescaping from STRING to BUFFER and + return the length of the valid buffer. Plus unescaping is only + done if WITHPLUS is true. An escaped Nul character will be + replaced by NULREPL. */ +static size_t +do_unescape (unsigned char *buffer, const unsigned char *string, + int withplus, int nulrepl) +{ + unsigned char *p = buffer; + + while (*string) + { + if (*string == '%' && string[1] && string[2]) + { + string++; + *p = xtoi_2 (string); + if (!*p) + *p = nulrepl; + string++; + } + else if (*string == '+' && withplus) + *p = ' '; + else + *p = *string; + p++; + string++; + } + + return (p - buffer); +} + + +/* Count space required after unescaping STRING. Note that this will + never be larger than strlen (STRING). */ +static size_t +count_unescape (const unsigned char *string) +{ + size_t n = 0; + + while (*string) + { + if (*string == '%' && string[1] && string[2]) + { + string++; + string++; + } + string++; + n++; + } + + return n; +} + + +/* Helper. */ +static char * +do_plus_or_plain_unescape (const char *string, int withplus, int nulrepl) +{ + size_t nbytes, n; + char *newstring; + + nbytes = count_unescape (string); + newstring = xtrymalloc (nbytes+1); + if (newstring) + { + n = do_unescape (newstring, string, withplus, nulrepl); + assert (n == nbytes); + newstring[n] = 0; + } + return newstring; +} + + +/* Create a new allocated string from STRING with all "%xx" sequences + decoded and all plus signs replaced by a space. Embedded Nul + characters are replaced by the value of NULREPL. The function + returns the new string or NULL in case of a malloc failure. */ +char * +percent_plus_unescape (const char *string, int nulrepl) +{ + return do_plus_or_plain_unescape (string, 1, nulrepl); +} + + +/* Create a new allocated string from STRING with all "%xx" sequences + decoded. Embedded Nul characters are replaced by the value of + NULREPL. The function returns the new string or NULL in case of a + malloc failure. */ +char * +percent_unescape (const char *string, int nulrepl) +{ + return do_plus_or_plain_unescape (string, 0, nulrepl); +} + + +static size_t +do_unescape_inplace (char *string, int withplus, int nulrepl) +{ + unsigned char *p, *p0; + + p = p0 = string; + while (*string) + { + if (*string == '%' && string[1] && string[2]) + { + string++; + *p = xtoi_2 (string); + if (!*p) + *p = nulrepl; + string++; + } + else if (*string == '+' && withplus) + *p = ' '; + else + *p = *string; + p++; + string++; + } + + return (p - p0); +} + + +/* Perform percent and plus unescaping in STRING and return the new + valid length of the string. Embedded Nul characters are replaced + by the value of NULREPL. A terminating Nul character is not + inserted; the caller might want to call this function this way: + + foo[percent_plus_unescape_inplace (foo, 0)] = 0; + */ +size_t +percent_plus_unescape_inplace (char *string, int nulrepl) +{ + return do_unescape_inplace (string, 1, nulrepl); +} + + +/* Perform percent unescaping in STRING and return the new valid + length of the string. Embedded Nul characters are replaced by the + value of NULREPL. A terminating Nul character is not inserted; the + caller might want to call this function this way: + + foo[percent_unescape_inplace (foo, 0)] = 0; + */ +size_t +percent_unescape_inplace (char *string, int nulrepl) +{ + return do_unescape_inplace (string, 0, nulrepl); +} + diff --git a/common/sysutils.c b/common/sysutils.c index 0f1857ee3..8e0c75c1a 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -471,7 +471,9 @@ gnupg_reopen_std (const char *pgmname) if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2) exit (3); -#endif /* HAVE_STAT && !HAVE_W32_SYSTEM */ +#else /* !(HAVE_STAT && !HAVE_W32_SYSTEM) */ + (void)pgmname; +#endif } @@ -479,11 +481,11 @@ gnupg_reopen_std (const char *pgmname) void gnupg_allow_set_foregound_window (pid_t pid) { - if (!pid || pid == (pid_t)(-1)) + if (!pid) log_info ("%s called with invalid pid %lu\n", "gnupg_allow_set_foregound_window", (unsigned long)pid); #ifdef HAVE_W32_SYSTEM - else if (!AllowSetForegroundWindow (pid)) + else if (!AllowSetForegroundWindow ((pid_t)pid == (pid_t)(-1)?ASFW_ANY:pid)) log_info ("AllowSetForegroundWindow(%lu) failed: %s\n", (unsigned long)pid, w32_strerror (-1)); #endif diff --git a/common/t-percent.c b/common/t-percent.c index 93d95f78d..b8641b90b 100644 --- a/common/t-percent.c +++ b/common/t-percent.c @@ -66,8 +66,9 @@ test_percent_plus_escape (void) "%0A+ABC%09" }, { NULL, NULL } }; - char *buf; + char *buf, *buf2; int i; + size_t len; for (i=0; tbl[i].string; i++) { @@ -79,17 +80,34 @@ test_percent_plus_escape (void) } if (strcmp (buf, tbl[i].expect)) fail (i); + buf2 = percent_plus_unescape (buf, 0); + if (!buf2) + { + fprintf (stderr, "out of core: %s\n", strerror (errno)); + exit (2); + } + if (strcmp (buf2, tbl[i].string)) + fail (i); + xfree (buf2); + /* Now test the inplace conversion. */ + len = percent_plus_unescape_inplace (buf, 0); + buf[len] = 0; + if (strcmp (buf, tbl[i].string)) + fail (i); xfree (buf); } } + int main (int argc, char **argv) { (void)argc; (void)argv; + /* FIXME: We escape_unescape is not tested - only + percent_plus_unescape. */ test_percent_plus_escape (); return 0; diff --git a/common/util.h b/common/util.h index 3c664cec7..c64db9f6b 100644 --- a/common/util.h +++ b/common/util.h @@ -204,6 +204,11 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count); /*-- percent.c --*/ char *percent_plus_escape (const char *string); +char *percent_plus_unescape (const char *string, int nulrepl); +char *percent_unescape (const char *string, int nulrepl); + +size_t percent_plus_unescape_inplace (char *string, int nulrepl); +size_t percent_unescape_inplace (char *string, int nulrepl); /*-- homedir.c --*/ diff --git a/g10/ChangeLog b/g10/ChangeLog index d7db690fc..50dca45ca 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,11 @@ +2009-03-31 Werner Koch + + * passphrase.c (ask_passphrase): Use percent_plus_unescape. + * misc.c (unescape_percent_string): Remove. + + * call-agent.c (unescape_status_string): Chnage to use + percent_plus_unescape. + 2009-03-25 Werner Koch * mainproc.c (print_pkenc_list): Use snprintf. diff --git a/g10/call-agent.c b/g10/call-agent.c index b6c61aa0e..444048a47 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -116,32 +116,7 @@ start_agent (void) static char * unescape_status_string (const unsigned char *s) { - char *buffer, *d; - - buffer = d = xtrymalloc (strlen (s)+1); - if (!buffer) - return NULL; - while (*s) - { - if (*s == '%' && s[1] && s[2]) - { - s++; - *d = xtoi_2 (s); - if (!*d) - *d = '\xff'; - d++; - s += 2; - } - else if (*s == '+') - { - *d++ = ' '; - s++; - } - else - *d++ = *s++; - } - *d = 0; - return buffer; + return percent_plus_unescape (s, 0xff); } diff --git a/g10/main.h b/g10/main.h index 706162529..1e5cad4bf 100644 --- a/g10/main.h +++ b/g10/main.h @@ -135,7 +135,6 @@ char *optsep(char **stringp); char *argsplit(char *string); int parse_options(char *str,unsigned int *options, struct parse_options *opts,int noisy); -char *unescape_percent_string (const unsigned char *s); int has_invalid_email_chars (const char *s); int is_valid_mailbox (const char *name); const char *get_libexecdir (void); diff --git a/g10/misc.c b/g10/misc.c index b0e5e2ce1..80a8a74ca 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -1215,39 +1215,6 @@ parse_options(char *str,unsigned int *options, } -/* Return a new malloced string by unescaping the string S. Escaping - is percent escaping and '+'/space mapping. A binary nul will - silently be replaced by a 0xFF. */ -char * -unescape_percent_string (const unsigned char *s) -{ - char *buffer, *d; - - buffer = d = xmalloc (strlen (s)+1); - while (*s) - { - if (*s == '%' && s[1] && s[2]) - { - s++; - *d = xtoi_2 (s); - if (!*d) - *d = '\xff'; - d++; - s += 2; - } - else if (*s == '+') - { - *d++ = ' '; - s++; - } - else - *d++ = *s++; - } - *d = 0; - return buffer; -} - - /* Check whether the string has characters not valid in an RFC-822 address. To cope with OpenPGP we ignore allow non-ascii characters so that for example umlauts are legal in an email address. An diff --git a/g10/passphrase.c b/g10/passphrase.c index 0950581c9..8b952f72a 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -453,8 +453,9 @@ ask_passphrase (const char *description, { if (strchr (description, '%')) { - char *tmp = unescape_percent_string - ((const unsigned char*)description); + char *tmp = percent_plus_unescape (description, 0xff); + if (!tmp) + log_fatal(_("out of core\n")); tty_printf ("\n%s\n", tmp); xfree (tmp); } diff --git a/scd/ChangeLog b/scd/ChangeLog index efd46fea9..534a7092b 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,8 @@ +2009-03-31 Werner Koch + + * command.c (percent_plus_unescape): Remove. + (cmd_setattr): Use percent_plus_unescape_inplace. + 2009-03-30 Werner Koch * app-nks.c (do_decipher): Make it work for TCOS 3. diff --git a/scd/command.c b/scd/command.c index 71081b26f..6c1cdd072 100644 --- a/scd/command.c +++ b/scd/command.c @@ -462,41 +462,6 @@ open_card (ctrl_t ctrl, const char *apptype) } -/* Do the percent and plus/space unescaping in place and return the - length of the valid buffer. */ -static size_t -percent_plus_unescape (unsigned char *string) -{ - unsigned char *p = string; - size_t n = 0; - - while (*string) - { - if (*string == '%' && string[1] && string[2]) - { - string++; - *p++ = xtoi_2 (string); - n++; - string+= 2; - } - else if (*string == '+') - { - *p++ = ' '; - n++; - string++; - } - else - { - *p++ = *string++; - n++; - } - } - - return n; -} - - - /* SERIALNO [APPTYPE] Return the serial number of the card using a status reponse. This @@ -1153,7 +1118,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) *line++ = 0; while (spacep (line)) line++; - nbytes = percent_plus_unescape ((unsigned char*)line); + nbytes = percent_plus_unescape_inplace (line, 0); rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx, (const unsigned char*)line, nbytes); diff --git a/sm/ChangeLog b/sm/ChangeLog index 9f926cfc7..a988a200f 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,9 @@ +2009-04-01 Werner Koch + + * export.c (popen_protect_tool): Add command line option + --agent-program and pass flag bit 6. + * import.c (popen_protect_tool): Ditto. + 2009-03-26 Werner Koch * gpgsm.c (main): s/def_digest_string/forced_digest_algo/ and diff --git a/sm/export.c b/sm/export.c index f8e23cec1..fcf1dccc1 100644 --- a/sm/export.c +++ b/sm/export.c @@ -574,13 +574,14 @@ popen_protect_tool (ctrl_t ctrl, const char *pgmname, const char *prompt, const char *keygrip, pid_t *pid) { - const char *argv[20]; + const char *argv[22]; int i=0; /* Make sure that the agent is running so that the protect tool is able to ask for a passphrase. This has only an effect under W32 where the agent is started on demand; sending a NOP does not harm - on other platforms. */ + on other platforms. This is not really necessary anymore because + the protect tool does this now by itself; it does not harm either.*/ gpgsm_agent_send_nop (ctrl); argv[i++] = "--homedir"; @@ -595,13 +596,18 @@ popen_protect_tool (ctrl_t ctrl, const char *pgmname, argv[i++] = "--p12-charset"; argv[i++] = opt.p12_charset; } + if (opt.agent_program) + { + argv[i++] = "--agent-program"; + argv[i++] = opt.agent_program; + } argv[i++] = "--", argv[i++] = keygrip, argv[i] = NULL; assert (i < sizeof argv); return gnupg_spawn_process (pgmname, argv, infile, outfile, - setup_pinentry_env, 128, + setup_pinentry_env, (128|64), statusfile, pid); } diff --git a/sm/import.c b/sm/import.c index cb1922ed5..5e8b42971 100644 --- a/sm/import.c +++ b/sm/import.c @@ -463,13 +463,14 @@ static gpg_error_t popen_protect_tool (ctrl_t ctrl, const char *pgmname, FILE *infile, FILE *outfile, FILE **statusfile, pid_t *pid) { - const char *argv[20]; + const char *argv[22]; int i=0; /* Make sure that the agent is running so that the protect tool is able to ask for a passphrase. This has only an effect under W32 where the agent is started on demand; sending a NOP does not harm - on other platforms. */ + on other platforms. This is not really necessary anymore because + the protect tool does this now by itself; it does not harm either. */ gpgsm_agent_send_nop (ctrl); argv[i++] = "--homedir"; @@ -483,12 +484,17 @@ popen_protect_tool (ctrl_t ctrl, const char *pgmname, argv[i++] = "--passphrase"; argv[i++] = opt.fixed_passphrase; } + if (opt.agent_program) + { + argv[i++] = "--agent-program"; + argv[i++] = opt.agent_program; + } argv[i++] = "--", argv[i] = NULL; assert (i < sizeof argv); return gnupg_spawn_process (pgmname, argv, infile, outfile, - setup_pinentry_env, 128, + setup_pinentry_env, (128 | 64), statusfile, pid); } diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index ba97c1a10..06dafd5c9 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -215,7 +215,7 @@ gnu_getcwd (void) } -/* Unescale STRING and returned the malloced result. The surrounding +/* Unescape STRING and returned the malloced result. The surrounding quotes must already be removed from STRING. */ static char * unescape_string (const char *string) diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 92016efc4..7ba526f69 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -1141,7 +1141,7 @@ my_dgettext (const char *domain, const char *msgid) /* FIXME: we have no dgettext, thus we can't switch. */ - text = gettext (msgid); + text = (char*)gettext (msgid); return text ? text : msgid; } #elif defined(ENABLE_NLS)