Updated FSF's address.
[gnupg.git] / tools / symcryptrun.c
index 6771ab9..406cbb2 100644 (file)
@@ -15,7 +15,8 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 
@@ -56,6 +57,9 @@
 
    Other classes may be added in the future.  */
 
+#define SYMC_BAD_PASSPHRASE    2
+#define SYMC_CANCELED          3
+
 \f
 #include <config.h>
 
@@ -82,6 +86,7 @@
 #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
@@ -107,6 +112,37 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
 }
 
 \f
+/* 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 )
+{
+    unsigned long int hval, g;
+    const char *str = str_param;
+
+    hval = 0;
+    while (*str != '\0')
+    {
+       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
 /* Constants to identify the commands and options. */
 enum cmd_and_opt_values
   {
@@ -412,9 +448,10 @@ confucius_copy_file (char *infile, char *outfile, int plain)
    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 *
-confucius_get_pass (int again, int *canceled)
+confucius_get_pass (const char *cacheid, int again, int *canceled)
 {
   int err;
   char *pw;
@@ -443,7 +480,7 @@ confucius_get_pass (int again, int *canceled)
     }
 #endif
 
-  pw = simple_pwquery (NULL,
+  pw = simple_pwquery (cacheid,
                        again ? _("does not match - try again"):NULL,
                        _("Passphrase:"), NULL, &err);
 
@@ -485,15 +522,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;
@@ -501,6 +533,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);
 
@@ -522,9 +555,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;
     }
 
@@ -533,6 +590,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;
     }
 
@@ -550,6 +608,7 @@ confucius_process (int mode, char *infile, char *outfile)
       close (slave);
       close (cstderr[0]);
       close (cstderr[1]);
+      free (args);
       return 1;
     }
   else if (pid == 0) 
@@ -586,6 +645,7 @@ confucius_process (int mode, char *infile, char *outfile)
 
       close (slave);
       close (cstderr[1]);
+      free (args);
 
       /* Listen on the output FDs.  */
       do
@@ -689,13 +749,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);
@@ -717,6 +784,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
@@ -727,15 +796,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;
            }
@@ -752,7 +828,7 @@ 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;
@@ -810,7 +886,7 @@ confucius_main (int mode)
 
   /* 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)
     {
       remove_file (outfile, mode == oDecrypt);
@@ -961,20 +1037,6 @@ main (int argc, char **argv)
   xfree (configname);
   configname = NULL;
 
-  /* With --inputfile an argument is not allowed, without only one
-     optional argument is allowed. */
-  if (argc > 1)
-    log_error (_("too many arguments\n"));
-  else if (opt.input && argc)
-    log_error (_("no argument allowed when using option \"%s\"\n"),
-               "--inputfile");
-
-  if (argc)
-    {
-      opt.input = *argv;
-      argv++; argc--;
-    }
-
   if (!mode)
     log_error (_("either %s or %s must be given\n"),
                "--decrypt", "--encrypt");
@@ -1000,7 +1062,7 @@ main (int argc, char **argv)
       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);