2010-04-23 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / tools / symcryptrun.c
index d0a8bdd..2ef6822 100644 (file)
@@ -1,11 +1,11 @@
 /* symcryptrun.c - Tool to call simple symmetric encryption tools.
 /* symcryptrun.c - Tool to call simple symmetric encryption tools.
- *     Copyright (C) 2005 Free Software Foundation, Inc.
+ *     Copyright (C) 2005, 2007 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
  *
  * 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 2 of the License, or
+ * 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,
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 
  */
 
 
@@ -56,6 +55,9 @@
 
    Other classes may be added in the future.  */
 
 
    Other classes may be added in the future.  */
 
+#define SYMC_BAD_PASSPHRASE    2
+#define SYMC_CANCELED          3
+
 \f
 #include <config.h>
 
 \f
 #include <config.h>
 
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
+#include <signal.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#ifdef HAVE_PTY_H
 #include <pty.h>
 #include <pty.h>
-#include <utmp.h>
+#endif
 #include <ctype.h>
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
 #include <ctype.h>
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
 #define JNLIB_NEED_LOG_LOGV
 #include "i18n.h"
 #include "../common/util.h"
 #define JNLIB_NEED_LOG_LOGV
 #include "i18n.h"
 #include "../common/util.h"
+#include "mkdtemp.h"
 
 /* FIXME: Bah.  For spwq_secure_free.  */
 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
 #include "../common/simple-pwquery.h"
 
 \f
 
 /* FIXME: Bah.  For spwq_secure_free.  */
 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
 #include "../common/simple-pwquery.h"
 
 \f
-/* Used by gcry for logging */
-static void
-my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
+/* From simple-gettext.c.  */
+
+/* We assume to have `unsigned long int' value with at least 32 bits.  */
+#define HASHWORDBITS 32
+
+/* The so called `hashpjw' function by P.J. Weinberger
+   [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+   1986, 1987 Bell Telephone Laboratories, Inc.]  */
+
+static __inline__ ulong
+hash_string( const char *str_param )
 {
 {
-  /* translate the log levels */
-  switch (level)
+    unsigned long int hval, g;
+    const char *str = str_param;
+
+    hval = 0;
+    while (*str != '\0')
     {
     {
-    case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
-    case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
-    case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
-    case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
-    case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
-    case GCRY_LOG_BUG:  level = JNLIB_LOG_BUG; break;
-    case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
-    default:            level = JNLIB_LOG_ERROR; break;      }
-  log_logv (level, fmt, arg_ptr);
+       hval <<= 4;
+       hval += (unsigned long int) *str++;
+       g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
+       if (g != 0)
+       {
+         hval ^= g >> (HASHWORDBITS - 8);
+         hval ^= g;
+       }
+    }
+    return hval;
 }
 
 \f
 }
 
 \f
@@ -124,6 +141,7 @@ enum cmd_and_opt_values
     oKeyfile,
     oDecrypt,
     oEncrypt,
     oKeyfile,
     oDecrypt,
     oEncrypt,
+    oInput
   };
 
 
   };
 
 
@@ -132,23 +150,23 @@ static ARGPARSE_OPTS opts[] =
   {
     { 301, NULL, 0, N_("@\nCommands:\n ") },
 
   {
     { 301, NULL, 0, N_("@\nCommands:\n ") },
 
-    { oDecrypt, "decrypt", 0, N_("decryption modus")},
-    { oEncrypt, "encrypt", 0, N_("encryption modus")},
+    { oDecrypt, "decrypt", 0, N_("decryption modus") },
+    { oEncrypt, "encrypt", 0, N_("encryption modus") },
     
     { 302, NULL, 0, N_("@\nOptions:\n ") },
     
     
     { 302, NULL, 0, N_("@\nOptions:\n ") },
     
-    { oClass, "class", 2, N_("tool class (confucius)")},
-    { oProgram, "program", 2, N_("program filename")},
-
-    { oKeyfile, "keyfile", 2, N_("secret key file (required)")},
+    { oClass, "class", 2, N_("tool class (confucius)") },
+    { oProgram, "program", 2, N_("program filename") },
 
 
+    { oKeyfile, "keyfile", 2, N_("secret key file (required)") },
+    { oInput, "inputfile", 2, N_("input file name (default stdin)") },
     { oVerbose, "verbose",  0, N_("verbose") },
     { oQuiet, "quiet",      0, N_("quiet") },
     { oVerbose, "verbose",  0, N_("verbose") },
     { oQuiet, "quiet",      0, N_("quiet") },
-    { oLogFile, "log-file", 2, N_("use a log file for the server")},
-    { oOptions,  "options"  , 2, N_("|FILE|read options from FILE")},
+    { oLogFile, "log-file", 2, N_("use a log file for the server") },
+    { oOptions,  "options"  , 2, N_("|FILE|read options from FILE") },
 
     /* Hidden options.  */
 
     /* Hidden options.  */
-    { oNoVerbose, "no-verbose",  0, "@"},
+    { oNoVerbose, "no-verbose",  0, "@" },
     { oHomedir, "homedir", 2, "@" },   
     { oNoOptions, "no-options", 0, "@" },/* shortcut for --options /dev/null */
 
     { oHomedir, "homedir", 2, "@" },   
     { oNoOptions, "no-options", 0, "@" },/* shortcut for --options /dev/null */
 
@@ -166,6 +184,7 @@ struct
   char *class;
   char *program;
   char *keyfile;
   char *class;
   char *program;
   char *keyfile;
+  char *input;
 } opt;
 
 \f
 } opt;
 
 \f
@@ -181,14 +200,14 @@ my_strusage (int level)
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
-    case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
-      break;
+    case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
+
     case 1:
     case 40: p = _("Usage: symcryptrun [options] (-h for help)");
       break;
     case 41:
       p = _("Syntax: symcryptrun --class CLASS --program PROGRAM "
     case 1:
     case 40: p = _("Usage: symcryptrun [options] (-h for help)");
       break;
     case 41:
       p = _("Syntax: symcryptrun --class CLASS --program PROGRAM "
-           "--keyfile KEYFILE [options...] COMMAND\n"
+           "--keyfile KEYFILE [options...] COMMAND [inputfile]\n"
             "Call a simple symmetric encryption tool\n");
       break;
     case 31: p = "\nHome: "; break;
             "Call a simple symmetric encryption tool\n");
       break;
     case 31: p = "\nHome: "; break;
@@ -201,19 +220,76 @@ my_strusage (int level)
 }
 
 
 }
 
 
-/* Initialize the gettext system.  */
-static void
-i18n_init(void)
-{
-#ifdef USE_SIMPLE_GETTEXT
-  set_gettext_file (PACKAGE_GT);
-#else
-# ifdef ENABLE_NLS
-  setlocale (LC_ALL, "");
-  bindtextdomain (PACKAGE_GT, LOCALEDIR);
-  textdomain (PACKAGE_GT);
-# endif
+\f
+/* This is in the GNU C library in unistd.h.  */
+
+#ifndef TEMP_FAILURE_RETRY
+/* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno'
+   set to EINTR.  */
+
+# define TEMP_FAILURE_RETRY(expression) \
+  (__extension__                                                              \
+    ({ long int __result;                                                     \
+       do __result = (long int) (expression);                                 \
+       while (__result == -1L && errno == EINTR);                             \
+       __result; }))
 #endif
 #endif
+
+/* Include the implementation of map_spwq_error.  */
+MAP_SPWQ_ERROR_IMPL
+
+/* Unlink a file, and shred it if SHRED is true.  */
+int
+remove_file (char *name, int shred)
+{
+  if (!shred)
+    return unlink (name);
+  else
+    {
+      int status;
+      pid_t pid;
+
+      pid = fork ();
+      if (pid == 0)
+       {
+         /* Child.  */
+         
+         /* -f forces file to be writable, and -u unlinks it afterwards.  */
+         char *args[] = { SHRED, "-uf", name, NULL };
+         
+         execv (SHRED, args);
+         _exit (127);
+       }
+      else if (pid < 0)
+       {
+         /* Fork failed.  */
+         status = -1;
+       }
+      else
+       {
+         /* Parent.  */
+         
+         if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+           status = -1;
+       }
+      
+      if (!WIFEXITED (status))
+       {
+         log_error (_("%s on %s aborted with status %i\n"),
+                    SHRED, name, status);
+         unlink (name);
+         return 1;
+       }
+      else if (WEXITSTATUS (status))
+       {
+         log_error (_("%s on %s failed with status %i\n"), SHRED, name,
+                    WEXITSTATUS (status));
+         unlink (name);
+         return 1;
+       }
+
+      return 0;
+    }
 }
 
 \f
 }
 
 \f
@@ -227,32 +303,17 @@ i18n_init(void)
 static char *
 confucius_mktmpdir (void)
 {
 static char *
 confucius_mktmpdir (void)
 {
-  int res;
-  char *tmpdir;
+  char *name;
 
 
-  tmpdir = tmpnam (NULL);
-  if (!tmpdir)
+  name = strdup ("/tmp/gpg-XXXXXX");
+  if (!name || !mkdtemp (name))
     {
     {
-      log_error (_("cannot create temporary directory name: %s\n"),
-                strerror (errno));
-      return NULL;
-    }
-  tmpdir = strdup (tmpdir);
-  if (!tmpdir)
-    {
-      log_error (_("cannot copy temporary directory name: %s\n"),
-                strerror (errno));
-      return NULL;
-    }
-  res = mkdir (tmpdir, 0700);
-  if (res < 0)
-    {
-      log_error (_("cannot create temporary directory %s: %s\n"),
-                tmpdir, strerror (errno));
+      log_error (_("can't create temporary directory `%s': %s\n"),
+                 name?name:"", strerror (errno));
       return NULL;
     }
 
       return NULL;
     }
 
-  return tmpdir;
+  return name;
 }
 
 
 }
 
 
@@ -263,9 +324,11 @@ confucius_mktmpdir (void)
 #define CONFUCIUS_LINESIZE 4096
 
 
 #define CONFUCIUS_LINESIZE 4096
 
 
-/* Copy the file IN to OUT, either of which may be "-".  */
+/* Copy the file IN to OUT, either of which may be "-".  If PLAIN is
+   true, and the copying fails, and OUT is not STDOUT, then shred the
+   file instead unlinking it.  */
 static int
 static int
-confucius_copy_file (const char *infile, const char *outfile)
+confucius_copy_file (char *infile, char *outfile, int plain)
 {
   FILE *in;
   int in_is_stdin = 0;
 {
   FILE *in;
   int in_is_stdin = 0;
@@ -342,7 +405,8 @@ confucius_copy_file (const char *infile, const char *outfile)
 
  copy_err:
   if (!out_is_stdout)
 
  copy_err:
   if (!out_is_stdout)
-    unlink (outfile);
+    remove_file (outfile, plain);
+
   return 1;
 }
 
   return 1;
 }
 
@@ -352,48 +416,24 @@ confucius_copy_file (const char *infile, const char *outfile)
    pointer, it will be set to true or false, depending on if the user
    canceled the operation or not.  On error (including cancelation), a
    null pointer is returned.  The passphrase must be deallocated with
    pointer, it will be set to true or false, depending on if the user
    canceled the operation or not.  On error (including cancelation), a
    null pointer is returned.  The passphrase must be deallocated with
-   confucius_drop_pass.  */
+   confucius_drop_pass.  CACHEID is the ID to be used for passphrase
+   caching and can be NULL to disable caching.  */
 char *
 char *
-confucius_get_pass (int again, int *canceled)
+confucius_get_pass (const char *cacheid, int again, int *canceled)
 {
   int err;
   char *pw;
 {
   int err;
   char *pw;
-#ifdef HAVE_LANGINFO_CODESET
-  char *orig_codeset = NULL;
-#endif
+  char *orig_codeset;
 
   if (canceled)
     *canceled = 0;
   
 
   if (canceled)
     *canceled = 0;
   
-#ifdef ENABLE_NLS
-  /* The Assuan agent protocol requires us to transmit utf-8 strings */
-  orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
-#ifdef HAVE_LANGINFO_CODESET
-  if (!orig_codeset)
-    orig_codeset = nl_langinfo (CODESET);
-#endif
-  if (orig_codeset && !strcmp (orig_codeset, "UTF-8"))
-    orig_codeset = NULL;
-  if (orig_codeset)
-    {
-      /* We only switch when we are able to restore the codeset later. */
-      orig_codeset = xstrdup (orig_codeset);
-      if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
-        orig_codeset = NULL; 
-    }
-#endif
-
-  pw = simple_pwquery (NULL,
+  orig_codeset = i18n_switchto_utf8 ();
+  pw = simple_pwquery (cacheid,
                        again ? _("does not match - try again"):NULL,
                        again ? _("does not match - try again"):NULL,
-                       _("Passphrase:"), NULL, &err);
-
-#ifdef ENABLE_NLS
-  if (orig_codeset)
-    {
-      bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
-      xfree (orig_codeset);
-    }
-#endif
+                       _("Passphrase:"), NULL, 0, &err);
+  err = map_spwq_error (err);
+  i18n_switchback (orig_codeset);
 
   if (!pw)
     {
 
   if (!pw)
     {
@@ -425,15 +465,10 @@ confucius_drop_pass (char *pass)
    requested.  If it is oDecrypt, decryption is requested.  INFILE and
    OUTFILE are the temporary files used in the process.  */
 int
    requested.  If it is oDecrypt, decryption is requested.  INFILE and
    OUTFILE are the temporary files used in the process.  */
 int
-confucius_process (int mode, char *infile, char *outfile)
+confucius_process (int mode, char *infile, char *outfile,
+                  int argc, char *argv[])
 {
 {
-  char *const args[] = { opt.program,
-                        mode == oEncrypt ? "-m1" : "-m2",
-                        "-q", infile,
-                        "-z", outfile,
-                        "-s", opt.keyfile,
-                        mode == oEncrypt ? "-af" : "-f",
-                        NULL };
+  char **args;
   int cstderr[2];
   int master;
   int slave;
   int cstderr[2];
   int master;
   int slave;
@@ -441,6 +476,7 @@ confucius_process (int mode, char *infile, char *outfile)
   pid_t pid;
   pid_t wpid;
   int tries = 0;
   pid_t pid;
   pid_t wpid;
   int tries = 0;
+  char cacheid[40];
 
   signal (SIGPIPE, SIG_IGN);
 
 
   signal (SIGPIPE, SIG_IGN);
 
@@ -462,9 +498,33 @@ confucius_process (int mode, char *infile, char *outfile)
       return 1;
     }
 
       return 1;
     }
 
+  /* Generate a hash from the keyfile name for caching.  */
+  snprintf (cacheid, sizeof (cacheid), "confucius:%lu",
+           hash_string (opt.keyfile));
+  cacheid[sizeof (cacheid) - 1] = '\0';
+  args = malloc (sizeof (char *) * (10 + argc));
+  if (!args)
+    {
+      log_error (_("cannot allocate args vector\n"));
+      return 1;
+    }
+  args[0] = opt.program;
+  args[1] = (mode == oEncrypt) ? "-m1" : "-m2";
+  args[2] = "-q";
+  args[3] = infile;
+  args[4] = "-z";
+  args[5] = outfile;
+  args[6] = "-s";
+  args[7] = opt.keyfile;
+  args[8] = (mode == oEncrypt) ? "-af" : "-f";
+  args[9 + argc] = NULL;
+  while (argc--)
+    args[9 + argc] = argv[argc];
+
   if (pipe (cstderr) < 0)
     {
       log_error (_("could not create pipe: %s\n"), strerror (errno));
   if (pipe (cstderr) < 0)
     {
       log_error (_("could not create pipe: %s\n"), strerror (errno));
+      free (args);
       return 1;
     }
 
       return 1;
     }
 
@@ -473,6 +533,7 @@ confucius_process (int mode, char *infile, char *outfile)
       log_error (_("could not create pty: %s\n"), strerror (errno));
       close (cstderr[0]);
       close (cstderr[1]);
       log_error (_("could not create pty: %s\n"), strerror (errno));
       close (cstderr[0]);
       close (cstderr[1]);
+      free (args);
       return -1;
     }
 
       return -1;
     }
 
@@ -490,6 +551,7 @@ confucius_process (int mode, char *infile, char *outfile)
       close (slave);
       close (cstderr[0]);
       close (cstderr[1]);
       close (slave);
       close (cstderr[0]);
       close (cstderr[1]);
+      free (args);
       return 1;
     }
   else if (pid == 0) 
       return 1;
     }
   else if (pid == 0) 
@@ -526,6 +588,7 @@ confucius_process (int mode, char *infile, char *outfile)
 
       close (slave);
       close (cstderr[1]);
 
       close (slave);
       close (cstderr[1]);
+      free (args);
 
       /* Listen on the output FDs.  */
       do
 
       /* Listen on the output FDs.  */
       do
@@ -629,13 +692,20 @@ confucius_process (int mode, char *infile, char *outfile)
                      char *pass;
                      int canceled;
 
                      char *pass;
                      int canceled;
 
-                     pass = confucius_get_pass (tries ? 1 : 0, &canceled);
+                     /* If this is not the first attempt, the
+                        passphrase seems to be wrong, so clear the
+                        cache.  */
+                     if (tries)
+                       simple_pwclear (cacheid);
+
+                     pass = confucius_get_pass (cacheid,
+                                                tries ? 1 : 0, &canceled);
                      if (!pass)
                        {
                          kill (pid, SIGTERM);
                          close (master);
                          close (cstderr[0]);
                      if (!pass)
                        {
                          kill (pid, SIGTERM);
                          close (master);
                          close (cstderr[0]);
-                         return canceled ? 3 : 1;
+                         return canceled ? SYMC_CANCELED : 1;
                        }
                      write (master, pass, strlen (pass));
                      write (master, "\n", 1);
                        }
                      write (master, pass, strlen (pass));
                      write (master, "\n", 1);
@@ -657,6 +727,8 @@ confucius_process (int mode, char *infile, char *outfile)
          log_error (_("waitpid failed: %s\n"), strerror (errno));
 
          kill (pid, SIGTERM);
          log_error (_("waitpid failed: %s\n"), strerror (errno));
 
          kill (pid, SIGTERM);
+         /* State of cached password is unclear.  Just remove it.  */
+         simple_pwclear (cacheid);
          return 1;
        }
       else
          return 1;
        }
       else
@@ -667,15 +739,22 @@ confucius_process (int mode, char *infile, char *outfile)
          if (!WIFEXITED (res))
            {
              log_error (_("child aborted with status %i\n"), res);
          if (!WIFEXITED (res))
            {
              log_error (_("child aborted with status %i\n"), res);
+
+             /* State of cached password is unclear.  Just remove it.  */
+             simple_pwclear (cacheid);
+
              return 1;
            }
 
          if (WEXITSTATUS (res))
            {
              return 1;
            }
 
          if (WEXITSTATUS (res))
            {
+             /* The passphrase was wrong.  Remove it from the cache.  */
+             simple_pwclear (cacheid);
+
              /* We probably exceeded our number of attempts at guessing
                 the password.  */
              if (tries >= 3)
              /* We probably exceeded our number of attempts at guessing
                 the password.  */
              if (tries >= 3)
-               return 2;
+               return SYMC_BAD_PASSPHRASE;
              else
                return 1;
            }
              else
                return 1;
            }
@@ -692,27 +771,36 @@ confucius_process (int mode, char *infile, char *outfile)
    requested.  If it is oDecrypt, decryption is requested.  The other
    parameters are taken from the global option data.  */
 int
    requested.  If it is oDecrypt, decryption is requested.  The other
    parameters are taken from the global option data.  */
 int
-confucius_main (int mode)
+confucius_main (int mode, int argc, char *argv[])
 {
   int res;
   char *tmpdir;
   char *infile;
 {
   int res;
   char *tmpdir;
   char *infile;
+  int infile_from_stdin = 0;
   char *outfile;
 
   tmpdir = confucius_mktmpdir ();
   if (!tmpdir)
     return 1;
 
   char *outfile;
 
   tmpdir = confucius_mktmpdir ();
   if (!tmpdir)
     return 1;
 
-  /* TMPDIR + "/" + "in" + "\0".  */
-  infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
-  if (!infile)
+  if (opt.input && !(opt.input[0] == '-' && opt.input[1] == '\0'))
+    infile = xstrdup (opt.input);
+  else
     {
     {
-      log_error (_("cannot allocate infile string: %s\n"), strerror (errno));
-      rmdir (tmpdir);
-      return 1;
+      infile_from_stdin = 1;
+
+      /* TMPDIR + "/" + "in" + "\0".  */
+      infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
+      if (!infile)
+       {
+         log_error (_("cannot allocate infile string: %s\n"),
+                    strerror (errno));
+         rmdir (tmpdir);
+         return 1;
+       }
+      strcpy (infile, tmpdir);
+      strcat (infile, "/in");
     }
     }
-  strcpy (infile, tmpdir);
-  strcat (infile, "/in");
 
   /* TMPDIR + "/" + "out" + "\0".  */
   outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
 
   /* TMPDIR + "/" + "out" + "\0".  */
   outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
@@ -726,23 +814,27 @@ confucius_main (int mode)
   strcpy (outfile, tmpdir);
   strcat (outfile, "/out");
 
   strcpy (outfile, tmpdir);
   strcat (outfile, "/out");
 
-  /* Create INFILE and fill it with content.  */
-  res = confucius_copy_file ("-", infile);
-  if (res)
+  if (infile_from_stdin)
     {
     {
-      free (outfile);
-      free (infile);
-      rmdir (tmpdir);
-      return res;
+      /* Create INFILE and fill it with content.  */
+      res = confucius_copy_file ("-", infile, mode == oEncrypt);
+      if (res)
+       {
+         free (outfile);
+         free (infile);
+         rmdir (tmpdir);
+         return res;
+       }
     }
 
   /* Run the engine and thus create the output file, handling
      passphrase retrieval.  */
     }
 
   /* Run the engine and thus create the output file, handling
      passphrase retrieval.  */
-  res = confucius_process (mode, infile, outfile);
+  res = confucius_process (mode, infile, outfile, argc, argv);
   if (res)
     {
   if (res)
     {
-      unlink (outfile);
-      unlink (infile);
+      remove_file (outfile, mode == oDecrypt);
+      if (infile_from_stdin)
+       remove_file (infile, mode == oEncrypt);
       free (outfile);
       free (infile);
       rmdir (tmpdir);
       free (outfile);
       free (infile);
       rmdir (tmpdir);
@@ -750,19 +842,21 @@ confucius_main (int mode)
     }
 
   /* Dump the output file to stdout.  */
     }
 
   /* Dump the output file to stdout.  */
-  res = confucius_copy_file (outfile, "-");
+  res = confucius_copy_file (outfile, "-", mode == oDecrypt);
   if (res)
     {
   if (res)
     {
-      unlink (outfile);
-      unlink (infile);
+      remove_file (outfile, mode == oDecrypt);
+      if (infile_from_stdin)
+       remove_file (infile, mode == oEncrypt);
       free (outfile);
       free (infile);
       rmdir (tmpdir);
       return res;
     }
   
       free (outfile);
       free (infile);
       rmdir (tmpdir);
       return res;
     }
   
-  unlink (outfile);
-  unlink (infile);
+  remove_file (outfile, mode == oDecrypt);
+  if (infile_from_stdin)
+    remove_file (infile, mode == oEncrypt);
   free (outfile);
   free (infile);
   rmdir (tmpdir);
   free (outfile);
   free (infile);
   rmdir (tmpdir);
@@ -788,10 +882,9 @@ main (int argc, char **argv)
   set_strusage (my_strusage);
   log_set_prefix ("symcryptrun", 1);
 
   set_strusage (my_strusage);
   log_set_prefix ("symcryptrun", 1);
 
-  /* Try to auto set the character set.  */
-  set_native_charset (NULL); 
-
+  /* Make sure that our subsystems are ready.  */
   i18n_init();
   i18n_init();
+  init_common_subsystems (&argc, &argv);
 
   opt.homedir = default_homedir ();
 
 
   opt.homedir = default_homedir ();
 
@@ -857,6 +950,7 @@ main (int argc, char **argv)
        case oClass:    opt.class = pargs.r.ret_str; break;
        case oProgram:  opt.program = pargs.r.ret_str; break;
        case oKeyfile:  opt.keyfile = pargs.r.ret_str; break;
        case oClass:    opt.class = pargs.r.ret_str; break;
        case oProgram:  opt.program = pargs.r.ret_str; break;
        case oKeyfile:  opt.keyfile = pargs.r.ret_str; break;
+       case oInput:    opt.input = pargs.r.ret_str; break;
 
         case oLogFile:  logfile = pargs.r.ret_str; break;
 
 
         case oLogFile:  logfile = pargs.r.ret_str; break;
 
@@ -898,19 +992,28 @@ main (int argc, char **argv)
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
     {
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
     {
-      log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
+      log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
     }
                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
     }
-  gcry_set_log_handler (my_gcry_logger, NULL);
+  setup_libgcrypt_logging ();
   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
 
   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
 
+  /* 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);
+  }
+
   if (!opt.class)
     {
       log_error (_("no class provided\n"));
       res = 1;
     }
   else if (!strcmp (opt.class, "confucius"))
   if (!opt.class)
     {
       log_error (_("no class provided\n"));
       res = 1;
     }
   else if (!strcmp (opt.class, "confucius"))
-    res = confucius_main (mode);
+    {
+      res = confucius_main (mode, argc, argv);
+    }
   else
     {
       log_error (_("class %s is not supported\n"), opt.class);
   else
     {
       log_error (_("class %s is not supported\n"), opt.class);