Import/export of pkcs#12 now uses the gpg-agent directly.
authorWerner Koch <wk@gnupg.org>
Wed, 1 Apr 2009 10:51:53 +0000 (10:51 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 1 Apr 2009 10:51:53 +0000 (10:51 +0000)
Removed duplicated code (percent unescaping).

29 files changed:
NEWS
agent/ChangeLog
agent/Makefile.am
agent/call-pinentry.c
agent/call-scd.c
agent/command.c
agent/protect-tool.c
common/ChangeLog
common/Makefile.am
common/exechelp.c
common/get-passphrase.c [new file with mode: 0644]
common/get-passphrase.h [new file with mode: 0644]
common/membuf.c
common/percent.c
common/sysutils.c
common/t-percent.c
common/util.h
g10/ChangeLog
g10/call-agent.c
g10/main.h
g10/misc.c
g10/passphrase.c
scd/ChangeLog
scd/command.c
sm/ChangeLog
sm/export.c
sm/import.c
tools/gpg-connect-agent.c
tools/gpgconf-comp.c

diff --git a/NEWS b/NEWS
index 015ca16..f0667eb 100644 (file)
--- 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)
 -------------------------------------------------
index 10390da..e691ad7 100644 (file)
@@ -1,3 +1,21 @@
+2009-04-01  Werner Koch  <wk@g10code.com>
+
+       * 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  <wk@g10code.com>
 
        * learncard.c (agent_handle_learn): Add new certtype 111.
index 95ffafe..c2830a9 100644 (file)
@@ -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
index 86792d8..c840bb6 100644 (file)
@@ -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))
index f45e940..d09812e 100644 (file)
@@ -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))
@@ -562,43 +563,6 @@ agent_reset_scd (ctrl_t ctrl)
 
 
 \f
-/* 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;
-}
-
-
-\f
 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;
     }
index 56d390b..728b160 100644 (file)
@@ -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)
index 848ad9f..d0b68a1 100644 (file)
 #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 ") },
-
-  { 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\""},
-
-  { 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, "@"},
-
-  {0}
+  ARGPARSE_group (301, N_("@\nOptions:\n ")),
+
+  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"),
+
+  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", "@"),
+
+  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;
-}
-
 \f
 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)
 {
index 1cf4f50..af804f4 100644 (file)
@@ -1,3 +1,22 @@
+2009-04-01  Werner Koch  <wk@g10code.com>
+
+       * 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  <wk@g10code.com>
+
+       * 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  <wk@g10code.com>
 
        * exechelp.c: Include sys/resource.h and sys/stat.h.
index 72c7d17..2ef324e 100644 (file)
@@ -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
index 3d11366..7019ae7 100644 (file)
@@ -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 (file)
index 0000000..68d7b70
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <assuan.h>
+
+#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 (file)
index 0000000..9457cdd
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+
+#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*/
index 9395eab..737930b 100644 (file)
@@ -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;
     }
index a0c78ec..e0c3592 100644 (file)
@@ -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 <stdlib.h>
 #include <errno.h>
 #include <ctype.h>
+#include <assert.h>
 
 #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);
+}
+
index 0f1857e..8e0c75c 100644 (file)
@@ -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
index 93d95f7..b8641b9 100644 (file)
@@ -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;
index 3c664ce..c64db9f 100644 (file)
@@ -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 --*/
index d7db690..50dca45 100644 (file)
@@ -1,3 +1,11 @@
+2009-03-31  Werner Koch  <wk@g10code.com>
+
+       * 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  <wk@g10code.com>
 
        * mainproc.c (print_pkenc_list): Use snprintf.
index b6c61aa..444048a 100644 (file)
@@ -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);
 }
 
 
index 7061625..1e5cad4 100644 (file)
@@ -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);
index b0e5e2c..80a8a74 100644 (file)
@@ -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
index 0950581..8b952f7 100644 (file)
@@ -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);
         }
index efd46fe..534a709 100644 (file)
@@ -1,3 +1,8 @@
+2009-03-31  Werner Koch  <wk@g10code.com>
+
+       * command.c (percent_plus_unescape): Remove.
+       (cmd_setattr): Use percent_plus_unescape_inplace.
+
 2009-03-30  Werner Koch  <wk@g10code.com>
 
        * app-nks.c (do_decipher): Make it work for TCOS 3.
index 71081b2..6c1cdd0 100644 (file)
@@ -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);
index 9f926cf..a988a20 100644 (file)
@@ -1,3 +1,9 @@
+2009-04-01  Werner Koch  <wk@g10code.com>
+
+       * 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  <wk@g10code.com>
 
        * gpgsm.c (main): s/def_digest_string/forced_digest_algo/ and
index f8e23ce..fcf1dcc 100644 (file)
@@ -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);
 }
 
index cb1922e..5e8b429 100644 (file)
@@ -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);
 }
 
index ba97c1a..06dafd5 100644 (file)
@@ -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)
index 92016ef..7ba526f 100644 (file)
@@ -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)