Release 2.1.21
[gnupg.git] / tools / symcryptrun.c
index d0a8bdd..54976ca 100644 (file)
@@ -1,11 +1,11 @@
 /* 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
- * 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,
@@ -14,8 +14,7 @@
  * 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 <https://www.gnu.org/licenses/>.
  */
 
 
    The possible exit status codes:
 
    0   Success
-   1   Some error occured
+   1   Some error occurred
    2   No valid passphrase was provided
    3   The operation was canceled by the user
 
    Other classes may be added in the future.  */
 
+#define SYMC_BAD_PASSPHRASE    2
+#define SYMC_CANCELED          3
+
 \f
 #include <config.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>
+
+#ifdef HAVE_PTY_H
 #include <pty.h>
+#else
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+#endif
+
+#ifdef HAVE_UTMP_H
 #include <utmp.h>
+#endif
 #include <ctype.h>
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
 #endif
 #include <gpg-error.h>
 
-#define JNLIB_NEED_LOG_LOGV
-#include "i18n.h"
+#include "../common/i18n.h"
 #include "../common/util.h"
+#include "../common/init.h"
+#include "../common/sysutils.h"
 
 /* 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
@@ -124,6 +156,7 @@ enum cmd_and_opt_values
     oKeyfile,
     oDecrypt,
     oEncrypt,
+    oInput
   };
 
 
@@ -132,24 +165,24 @@ static ARGPARSE_OPTS opts[] =
   {
     { 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 ") },
-    
-    { 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") },
-    { 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.  */
-    { oNoVerbose, "no-verbose",  0, "@"},
-    { oHomedir, "homedir", 2, "@" },   
+    { oNoVerbose, "no-verbose",  0, "@" },
+    { oHomedir, "homedir", 2, "@" },
     { oNoOptions, "no-options", 0, "@" },/* shortcut for --options /dev/null */
 
     {0}
@@ -166,10 +199,11 @@ struct
   char *class;
   char *program;
   char *keyfile;
+  char *input;
 } opt;
 
 \f
-/* Print usage information and and provide strings for help.  */
+/* Print usage information and provide strings for help.  */
 static const char *
 my_strusage (int level)
 {
@@ -177,22 +211,22 @@ my_strusage (int level)
 
   switch (level)
     {
-    case 11: p = "symcryptrun (GnuPG)";
+    case 11: p = "symcryptrun (@GNUPG@)";
       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 "
-           "--keyfile KEYFILE [options...] COMMAND\n"
+           "--keyfile KEYFILE [options...] COMMAND [inputfile]\n"
             "Call a simple symmetric encryption tool\n");
       break;
     case 31: p = "\nHome: "; break;
-    case 32: p = opt.homedir; break;
+    case 32: p = gnupg_homedir (); break;
     case 33: p = "\n"; break;
 
     default: p = NULL; break;
@@ -201,19 +235,73 @@ 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
+
+/* 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
@@ -227,32 +315,23 @@ i18n_init(void)
 static char *
 confucius_mktmpdir (void)
 {
-  int res;
-  char *tmpdir;
+  char *name, *p;
 
-  tmpdir = tmpnam (NULL);
-  if (!tmpdir)
-    {
-      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)
+  p = getenv ("TMPDIR");
+  if (!p || !*p)
+    p = "/tmp";
+  if (p[strlen (p) - 1] == '/')
+    name = xstrconcat (p, "gpg-XXXXXX", NULL);
+  else
+    name = xstrconcat (p, "/", "gpg-XXXXXX", NULL);
+  if (!name || !gnupg_mkdtemp (name))
     {
-      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 tmpdir;
+  return name;
 }
 
 
@@ -263,9 +342,11 @@ confucius_mktmpdir (void)
 #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
-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;
@@ -342,7 +423,8 @@ confucius_copy_file (const char *infile, const char *outfile)
 
  copy_err:
   if (!out_is_stdout)
-    unlink (outfile);
+    remove_file (outfile, plain);
+
   return 1;
 }
 
@@ -350,50 +432,25 @@ confucius_copy_file (const char *infile, const char *outfile)
 /* Get a passphrase in secure storage (if possible).  If AGAIN is
    true, then this is a repeated attempt.  If CANCELED is not a null
    pointer, it will be set to true or false, depending on if the user
-   canceled the operation or not.  On error (including cancelation), a
+   canceled the operation or not.  On error (including cancellation), 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 *
-confucius_get_pass (int again, int *canceled)
+confucius_get_pass (const char *cacheid, int again, int *canceled)
 {
   int err;
   char *pw;
-#ifdef HAVE_LANGINFO_CODESET
-  char *orig_codeset = NULL;
-#endif
+  char *orig_codeset;
 
   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,
-                       _("Passphrase:"), NULL, &err);
-
-#ifdef ENABLE_NLS
-  if (orig_codeset)
-    {
-      bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
-      xfree (orig_codeset);
-    }
-#endif
+                       _("Passphrase:"), NULL, 0, &err);
+  i18n_switchback (orig_codeset);
 
   if (!pw)
     {
@@ -405,7 +462,7 @@ confucius_get_pass (int again, int *canceled)
          log_info (_("cancelled\n"));
          if (canceled)
            *canceled = 1;
-       }      
+       }
     }
 
   return pw;
@@ -425,15 +482,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
-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;
@@ -441,6 +493,7 @@ confucius_process (int mode, char *infile, char *outfile)
   pid_t pid;
   pid_t wpid;
   int tries = 0;
+  char cacheid[40];
 
   signal (SIGPIPE, SIG_IGN);
 
@@ -462,9 +515,33 @@ confucius_process (int mode, char *infile, char *outfile)
       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));
+      free (args);
       return 1;
     }
 
@@ -473,6 +550,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]);
+      free (args);
       return -1;
     }
 
@@ -490,9 +568,10 @@ confucius_process (int mode, char *infile, char *outfile)
       close (slave);
       close (cstderr[0]);
       close (cstderr[1]);
+      free (args);
       return 1;
     }
-  else if (pid == 0) 
+  else if (pid == 0)
     {
       /* Child.  */
 
@@ -526,6 +605,7 @@ confucius_process (int mode, char *infile, char *outfile)
 
       close (slave);
       close (cstderr[1]);
+      free (args);
 
       /* Listen on the output FDs.  */
       do
@@ -564,7 +644,7 @@ confucius_process (int mode, char *infile, char *outfile)
                  close (cstderr[0]);
                  return 1;
                }
-             else  
+             else
                {
                  char *newline;
 
@@ -629,13 +709,20 @@ confucius_process (int mode, char *infile, char *outfile)
                      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]);
-                         return canceled ? 3 : 1;
+                         return canceled ? SYMC_CANCELED : 1;
                        }
                      write (master, pass, strlen (pass));
                      write (master, "\n", 1);
@@ -657,6 +744,8 @@ confucius_process (int mode, char *infile, char *outfile)
          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
@@ -667,15 +756,22 @@ confucius_process (int mode, char *infile, char *outfile)
          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))
            {
+             /* 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)
-               return 2;
+               return SYMC_BAD_PASSPHRASE;
              else
                return 1;
            }
@@ -692,27 +788,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
-confucius_main (int mode)
+confucius_main (int mode, int argc, char *argv[])
 {
   int res;
   char *tmpdir;
   char *infile;
+  int infile_from_stdin = 0;
   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);
@@ -726,23 +831,27 @@ confucius_main (int mode)
   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.  */
-  res = confucius_process (mode, infile, outfile);
+  res = confucius_process (mode, infile, outfile, argc, argv);
   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);
@@ -750,19 +859,21 @@ confucius_main (int mode)
     }
 
   /* Dump the output file to stdout.  */
-  res = confucius_copy_file (outfile, "-");
+  res = confucius_copy_file (outfile, "-", mode == oDecrypt);
   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;
     }
-  
-  unlink (outfile);
-  unlink (infile);
+
+  remove_file (outfile, mode == oDecrypt);
+  if (infile_from_stdin)
+    remove_file (infile, mode == oEncrypt);
   free (outfile);
   free (infile);
   rmdir (tmpdir);
@@ -779,21 +890,19 @@ main (int argc, char **argv)
   char **orig_argv;
   FILE *configfp = NULL;
   char *configname = NULL;
-  unsigned configlineno; 
+  unsigned configlineno;
   int mode = 0;
   int res;
   char *logfile = NULL;
   int default_config = 1;
 
+  early_system_init ();
   set_strusage (my_strusage);
-  log_set_prefix ("symcryptrun", 1);
-
-  /* Try to auto set the character set.  */
-  set_native_charset (NULL); 
+  log_set_prefix ("symcryptrun", GPGRT_LOG_WITH_PREFIX);
 
+  /* Make sure that our subsystems are ready.  */
   i18n_init();
-
-  opt.homedir = default_homedir ();
+  init_common_subsystems (&argc, &argv);
 
   /* Check whether we have a config file given on the commandline */
   orig_argc = argc;
@@ -812,12 +921,12 @@ main (int argc, char **argv)
       else if (pargs.r_opt == oNoOptions)
         default_config = 0; /* --no-options */
       else if (pargs.r_opt == oHomedir)
-       opt.homedir = pargs.r.ret_str;
+       gnupg_set_homedir (pargs.r.ret_str);
     }
 
   if (default_config)
-    configname = make_filename (opt.homedir, "symcryptrun.conf", NULL );
-  
+    configname = make_filename (gnupg_homedir (), "symcryptrun.conf", NULL );
+
   argc = orig_argc;
   argv = orig_argv;
   pargs.argc = &argc;
@@ -832,11 +941,11 @@ main (int argc, char **argv)
         {
           if (!default_config)
             {
-              log_error (_("option file `%s': %s\n"),
+              log_error (_("option file '%s': %s\n"),
                          configname, strerror(errno) );
               exit(1);
            }
-          xfree (configname); 
+          xfree (configname);
           configname = NULL;
        }
       default_config = 0;
@@ -853,10 +962,11 @@ main (int argc, char **argv)
        case oQuiet:     opt.quiet = 1; break;
         case oVerbose:   opt.verbose++; break;
         case oNoVerbose: opt.verbose = 0; 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;
 
@@ -896,21 +1006,25 @@ main (int argc, char **argv)
     log_set_file (logfile);
 
   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
-  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
-    {
-      log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
-                 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);
 
+  /* Tell simple-pwquery about the standard socket name.  */
+  {
+    char *tmp = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, 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"))
-    res = confucius_main (mode);
+    {
+      res = confucius_main (mode, argc, argv);
+    }
   else
     {
       log_error (_("class %s is not supported\n"), opt.class);