A whole bunch of changes to allow building for Windows.
[gnupg.git] / tools / symcryptrun.c
1 /* symcryptrun.c - Tool to call simple symmetric encryption tools.
2  *      Copyright (C) 2005, 2007 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22
23 /* Sometimes simple encryption tools are already in use for a long
24    time and there is a desire to integrate them into the GnuPG
25    framework.  The protocols and encryption methods might be
26    non-standard or not even properly documented, so that a
27    full-fledged encryption tool with an interface like gpg is not
28    doable.  This simple wrapper program provides a solution: It
29    operates by calling the encryption/decryption module and providing
30    the passphrase for a key (or even the key directly) using the
31    standard pinentry mechanism through gpg-agent.  */
32
33 /* This program is invoked in the following way:
34
35    symcryptrun --class CLASS --program PROGRAM --keyfile KEYFILE \
36      [--decrypt | --encrypt]
37
38    For encryption, the plain text must be provided on STDIN, and the
39    ciphertext will be output to STDOUT.  For decryption vice versa.
40
41    CLASS can currently only be "confucius".
42
43    PROGRAM must be the path to the crypto engine.
44
45    KEYFILE must contain the secret key, which may be protected by a
46    passphrase.  The passphrase is retrieved via the pinentry program.
47
48
49    The GPG Agent _must_ be running before starting symcryptrun.
50
51    The possible exit status codes:
52
53    0    Success
54    1    Some error occured
55    2    No valid passphrase was provided
56    3    The operation was canceled by the user
57
58    Other classes may be added in the future.  */
59
60 #define SYMC_BAD_PASSPHRASE     2
61 #define SYMC_CANCELED           3
62
63 \f
64 #include <config.h>
65
66 #include <unistd.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <errno.h>
71 #include <assert.h>
72 #include <signal.h>
73 #include <sys/stat.h>
74 #include <sys/types.h>
75 #include <sys/wait.h>
76 #ifdef HAVE_PTY_H
77 #include <pty.h>
78 #endif
79 #include <utmp.h>
80 #include <ctype.h>
81 #ifdef HAVE_LOCALE_H
82 #include <locale.h>
83 #endif
84 #ifdef HAVE_LANGINFO_CODESET
85 #include <langinfo.h>
86 #endif
87 #include <gpg-error.h>
88
89 #define JNLIB_NEED_LOG_LOGV
90 #include "i18n.h"
91 #include "../common/util.h"
92 #include "mkdtemp.h"
93
94 /* FIXME: Bah.  For spwq_secure_free.  */
95 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
96 #include "../common/simple-pwquery.h"
97
98 \f
99 /* From simple-gettext.c.  */
100
101 /* We assume to have `unsigned long int' value with at least 32 bits.  */
102 #define HASHWORDBITS 32
103
104 /* The so called `hashpjw' function by P.J. Weinberger
105    [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
106    1986, 1987 Bell Telephone Laboratories, Inc.]  */
107
108 static __inline__ ulong
109 hash_string( const char *str_param )
110 {
111     unsigned long int hval, g;
112     const char *str = str_param;
113
114     hval = 0;
115     while (*str != '\0')
116     {
117         hval <<= 4;
118         hval += (unsigned long int) *str++;
119         g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
120         if (g != 0)
121         {
122           hval ^= g >> (HASHWORDBITS - 8);
123           hval ^= g;
124         }
125     }
126     return hval;
127 }
128
129 \f
130 /* Constants to identify the commands and options. */
131 enum cmd_and_opt_values
132   {
133     aNull = 0,
134     oQuiet      = 'q',
135     oVerbose    = 'v',
136
137     oNoVerbose  = 500,
138     oOptions,
139     oNoOptions,
140     oLogFile,
141     oHomedir,
142     oClass,
143     oProgram,
144     oKeyfile,
145     oDecrypt,
146     oEncrypt,
147     oInput
148   };
149
150
151 /* The list of commands and options.  */
152 static ARGPARSE_OPTS opts[] =
153   {
154     { 301, NULL, 0, N_("@\nCommands:\n ") },
155
156     { oDecrypt, "decrypt", 0, N_("decryption modus") },
157     { oEncrypt, "encrypt", 0, N_("encryption modus") },
158     
159     { 302, NULL, 0, N_("@\nOptions:\n ") },
160     
161     { oClass, "class", 2, N_("tool class (confucius)") },
162     { oProgram, "program", 2, N_("program filename") },
163
164     { oKeyfile, "keyfile", 2, N_("secret key file (required)") },
165     { oInput, "inputfile", 2, N_("input file name (default stdin)") },
166     { oVerbose, "verbose",  0, N_("verbose") },
167     { oQuiet, "quiet",      0, N_("quiet") },
168     { oLogFile, "log-file", 2, N_("use a log file for the server") },
169     { oOptions,  "options"  , 2, N_("|FILE|read options from FILE") },
170
171     /* Hidden options.  */
172     { oNoVerbose, "no-verbose",  0, "@" },
173     { oHomedir, "homedir", 2, "@" },   
174     { oNoOptions, "no-options", 0, "@" },/* shortcut for --options /dev/null */
175
176     {0}
177   };
178
179
180 /* We keep all global options in the structure OPT.  */
181 struct
182 {
183   int verbose;          /* Verbosity level.  */
184   int quiet;            /* Be extra quiet.  */
185   const char *homedir;  /* Configuration directory name */
186
187   char *class;
188   char *program;
189   char *keyfile;
190   char *input;
191 } opt;
192
193 \f
194 /* Print usage information and and provide strings for help.  */
195 static const char *
196 my_strusage (int level)
197 {
198   const char *p;
199
200   switch (level)
201     {
202     case 11: p = "symcryptrun (GnuPG)";
203       break;
204     case 13: p = VERSION; break;
205     case 17: p = PRINTABLE_OS_NAME; break;
206     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
207       break;
208     case 1:
209     case 40: p = _("Usage: symcryptrun [options] (-h for help)");
210       break;
211     case 41:
212       p = _("Syntax: symcryptrun --class CLASS --program PROGRAM "
213             "--keyfile KEYFILE [options...] COMMAND [inputfile]\n"
214             "Call a simple symmetric encryption tool\n");
215       break;
216     case 31: p = "\nHome: "; break;
217     case 32: p = opt.homedir; break;
218     case 33: p = "\n"; break;
219
220     default: p = NULL; break;
221     }
222   return p;
223 }
224
225
226 \f
227 /* This is in the GNU C library in unistd.h.  */
228
229 #ifndef TEMP_FAILURE_RETRY
230 /* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno'
231    set to EINTR.  */
232
233 # define TEMP_FAILURE_RETRY(expression) \
234   (__extension__                                                              \
235     ({ long int __result;                                                     \
236        do __result = (long int) (expression);                                 \
237        while (__result == -1L && errno == EINTR);                             \
238        __result; }))
239 #endif
240
241 /* Include the implementation of map_spwq_error.  */
242 MAP_SPWQ_ERROR_IMPL
243
244 /* Unlink a file, and shred it if SHRED is true.  */
245 int
246 remove_file (char *name, int shred)
247 {
248   if (!shred)
249     return unlink (name);
250   else
251     {
252       int status;
253       pid_t pid;
254
255       pid = fork ();
256       if (pid == 0)
257         {
258           /* Child.  */
259           
260           /* -f forces file to be writable, and -u unlinks it afterwards.  */
261           char *args[] = { SHRED, "-uf", name, NULL };
262           
263           execv (SHRED, args);
264           _exit (127);
265         }
266       else if (pid < 0)
267         {
268           /* Fork failed.  */
269           status = -1;
270         }
271       else
272         {
273           /* Parent.  */
274           
275           if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
276             status = -1;
277         }
278       
279       if (!WIFEXITED (status))
280         {
281           log_error (_("%s on %s aborted with status %i\n"),
282                      SHRED, name, status);
283           unlink (name);
284           return 1;
285         }
286       else if (WEXITSTATUS (status))
287         {
288           log_error (_("%s on %s failed with status %i\n"), SHRED, name,
289                      WEXITSTATUS (status));
290           unlink (name);
291           return 1;
292         }
293
294       return 0;
295     }
296 }
297
298 \f
299 /* Class Confucius.
300
301    "Don't worry that other people don't know you;
302    worry that you don't know other people."            Analects--1.16.  */
303
304 /* Create temporary directory with mode 0700.  Returns a dynamically
305    allocated string with the filename of the directory.  */
306 static char *
307 confucius_mktmpdir (void)
308 {
309   char *name;
310
311   name = strdup ("/tmp/gpg-XXXXXX");
312   if (!name || !mkdtemp (name))
313     {
314       log_error (_("can't create temporary directory `%s': %s\n"),
315                  name?name:"", strerror (errno));
316       return NULL;
317     }
318
319   return name;
320 }
321
322
323 /* Buffer size for I/O operations.  */
324 #define CONFUCIUS_BUFSIZE 4096
325
326 /* Buffer size for output lines.  */
327 #define CONFUCIUS_LINESIZE 4096
328
329
330 /* Copy the file IN to OUT, either of which may be "-".  If PLAIN is
331    true, and the copying fails, and OUT is not STDOUT, then shred the
332    file instead unlinking it.  */
333 static int
334 confucius_copy_file (char *infile, char *outfile, int plain)
335 {
336   FILE *in;
337   int in_is_stdin = 0;
338   FILE *out;
339   int out_is_stdout = 0;
340   char data[CONFUCIUS_BUFSIZE];
341   ssize_t data_len;
342
343   if (infile[0] == '-' && infile[1] == '\0')
344     {
345       /* FIXME: Is stdin in binary mode?  */
346       in = stdin;
347       in_is_stdin = 1;
348     }
349   else
350     {
351       in = fopen (infile, "rb");
352       if (!in)
353         {
354           log_error (_("could not open %s for writing: %s\n"),
355                      infile, strerror (errno));
356           return 1;
357         }
358     }
359
360   if (outfile[0] == '-' && outfile[1] == '\0')
361     {
362       /* FIXME: Is stdout in binary mode?  */
363       out = stdout;
364       out_is_stdout = 1;
365     }
366   else
367     {
368       out = fopen (outfile, "wb");
369       if (!out)
370         {
371           log_error (_("could not open %s for writing: %s\n"),
372                      infile, strerror (errno));
373           return 1;
374         }
375     }
376
377   /* Now copy the data.  */
378   while ((data_len = fread (data, 1, sizeof (data), in)) > 0)
379     {
380       if (fwrite (data, 1, data_len, out) != data_len)
381         {
382           log_error (_("error writing to %s: %s\n"), outfile,
383                      strerror (errno));
384           goto copy_err;
385         }
386     }
387   if (data_len < 0 || ferror (in))
388     {
389       log_error (_("error reading from %s: %s\n"), infile, strerror (errno));
390       goto copy_err;
391     }
392
393   /* Close IN if appropriate.  */
394   if (!in_is_stdin && fclose (in) && ferror (in))
395     {
396       log_error (_("error closing %s: %s\n"), infile, strerror (errno));
397       goto copy_err;
398     }
399
400   /* Close OUT if appropriate.  */
401   if (!out_is_stdout && fclose (out) && ferror (out))
402     {
403       log_error (_("error closing %s: %s\n"), infile, strerror (errno));
404       goto copy_err;
405     }
406
407   return 0;
408
409  copy_err:
410   if (!out_is_stdout)
411     remove_file (outfile, plain);
412
413   return 1;
414 }
415
416
417 /* Get a passphrase in secure storage (if possible).  If AGAIN is
418    true, then this is a repeated attempt.  If CANCELED is not a null
419    pointer, it will be set to true or false, depending on if the user
420    canceled the operation or not.  On error (including cancelation), a
421    null pointer is returned.  The passphrase must be deallocated with
422    confucius_drop_pass.  CACHEID is the ID to be used for passphrase
423    caching and can be NULL to disable caching.  */
424 char *
425 confucius_get_pass (const char *cacheid, int again, int *canceled)
426 {
427   int err;
428   char *pw;
429 #ifdef HAVE_LANGINFO_CODESET
430   char *orig_codeset = NULL;
431 #endif
432
433   if (canceled)
434     *canceled = 0;
435   
436 #ifdef ENABLE_NLS
437   /* The Assuan agent protocol requires us to transmit utf-8 strings */
438   orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
439 #ifdef HAVE_LANGINFO_CODESET
440   if (!orig_codeset)
441     orig_codeset = nl_langinfo (CODESET);
442 #endif
443   if (orig_codeset && !strcmp (orig_codeset, "UTF-8"))
444     orig_codeset = NULL;
445   if (orig_codeset)
446     {
447       /* We only switch when we are able to restore the codeset later. */
448       orig_codeset = xstrdup (orig_codeset);
449       if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
450         {
451           xfree (orig_codeset);
452           orig_codeset = NULL; 
453         }
454     }
455 #endif
456
457   pw = simple_pwquery (cacheid,
458                        again ? _("does not match - try again"):NULL,
459                        _("Passphrase:"), NULL, 0, &err);
460   err = map_spwq_error (err);
461
462 #ifdef ENABLE_NLS
463   if (orig_codeset)
464     {
465       bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
466       xfree (orig_codeset);
467     }
468 #endif
469
470   if (!pw)
471     {
472       if (err)
473         log_error (_("error while asking for the passphrase: %s\n"),
474                    gpg_strerror (err));
475       else
476         {
477           log_info (_("cancelled\n"));
478           if (canceled)
479             *canceled = 1;
480         }      
481     }
482
483   return pw;
484 }
485
486
487 /* Drop a passphrase retrieved with confucius_get_pass.  */
488 void
489 confucius_drop_pass (char *pass)
490 {
491   if (pass)
492     spwq_secure_free (pass);
493 }
494
495
496 /* Run a confucius crypto engine.  If MODE is oEncrypt, encryption is
497    requested.  If it is oDecrypt, decryption is requested.  INFILE and
498    OUTFILE are the temporary files used in the process.  */
499 int
500 confucius_process (int mode, char *infile, char *outfile,
501                    int argc, char *argv[])
502 {
503   char **args;
504   int cstderr[2];
505   int master;
506   int slave;
507   int res;
508   pid_t pid;
509   pid_t wpid;
510   int tries = 0;
511   char cacheid[40];
512
513   signal (SIGPIPE, SIG_IGN);
514
515   if (!opt.program)
516     {
517       log_error (_("no --program option provided\n"));
518       return 1;
519     }
520
521   if (mode != oDecrypt && mode != oEncrypt)
522     {
523       log_error (_("only --decrypt and --encrypt are supported\n"));
524       return 1;
525     }
526
527   if (!opt.keyfile)
528     {
529       log_error (_("no --keyfile option provided\n"));
530       return 1;
531     }
532
533   /* Generate a hash from the keyfile name for caching.  */
534   snprintf (cacheid, sizeof (cacheid), "confucius:%lu",
535             hash_string (opt.keyfile));
536   cacheid[sizeof (cacheid) - 1] = '\0';
537   args = malloc (sizeof (char *) * (10 + argc));
538   if (!args)
539     {
540       log_error (_("cannot allocate args vector\n"));
541       return 1;
542     }
543   args[0] = opt.program;
544   args[1] = (mode == oEncrypt) ? "-m1" : "-m2";
545   args[2] = "-q";
546   args[3] = infile;
547   args[4] = "-z";
548   args[5] = outfile;
549   args[6] = "-s";
550   args[7] = opt.keyfile;
551   args[8] = (mode == oEncrypt) ? "-af" : "-f";
552   args[9 + argc] = NULL;
553   while (argc--)
554     args[9 + argc] = argv[argc];
555
556   if (pipe (cstderr) < 0)
557     {
558       log_error (_("could not create pipe: %s\n"), strerror (errno));
559       free (args);
560       return 1;
561     }
562
563   if (openpty (&master, &slave, NULL, NULL, NULL) == -1)
564     {
565       log_error (_("could not create pty: %s\n"), strerror (errno));
566       close (cstderr[0]);
567       close (cstderr[1]);
568       free (args);
569       return -1;
570     }
571
572   /* We don't want to deal with the worst case scenarios.  */
573   assert (master > 2);
574   assert (slave > 2);
575   assert (cstderr[0] > 2);
576   assert (cstderr[1] > 2);
577
578   pid = fork ();
579   if (pid < 0)
580     {
581       log_error (_("could not fork: %s\n"), strerror (errno));
582       close (master);
583       close (slave);
584       close (cstderr[0]);
585       close (cstderr[1]);
586       free (args);
587       return 1;
588     }
589   else if (pid == 0) 
590     {
591       /* Child.  */
592
593       /* Close the parent ends.  */
594       close (master);
595       close (cstderr[0]);
596
597       /* Change controlling terminal.  */
598       if (login_tty (slave))
599         {
600           /* It's too early to output a debug message.  */
601           _exit (1);
602         }
603
604       dup2 (cstderr[1], 2);
605       close (cstderr[1]);
606
607       /* Now kick off the engine program.  */
608       execv (opt.program, args);
609       log_error (_("execv failed: %s\n"), strerror (errno));
610       _exit (1);
611     }
612   else
613     {
614       /* Parent.  */
615       char buffer[CONFUCIUS_LINESIZE];
616       int buffer_len = 0;
617       fd_set fds;
618       int slave_closed = 0;
619       int stderr_closed = 0;
620
621       close (slave);
622       close (cstderr[1]);
623       free (args);
624
625       /* Listen on the output FDs.  */
626       do
627         {
628           FD_ZERO (&fds);
629
630           if (!slave_closed)
631             FD_SET (master, &fds);
632           if (!stderr_closed)
633             FD_SET (cstderr[0], &fds);
634
635           res = select (FD_SETSIZE, &fds, NULL, NULL, NULL);
636           if (res < 0)
637             {
638               log_error (_("select failed: %s\n"), strerror (errno));
639
640               kill (pid, SIGTERM);
641               close (master);
642               close (cstderr[0]);
643               return 1;
644             }
645
646           if (FD_ISSET (cstderr[0], &fds))
647             {
648               /* We got some output on stderr.  This is just passed
649                  through via the logging facility.  */
650
651               res = read (cstderr[0], &buffer[buffer_len],
652                           sizeof (buffer) - buffer_len - 1);
653               if (res < 0)
654                 {
655                   log_error (_("read failed: %s\n"), strerror (errno));
656
657                   kill (pid, SIGTERM);
658                   close (master);
659                   close (cstderr[0]);
660                   return 1;
661                 }
662               else  
663                 {
664                   char *newline;
665
666                   buffer_len += res;
667                   for (;;)
668                     {
669                       buffer[buffer_len] = '\0';
670                       newline = strchr (buffer, '\n');
671                       if (newline)
672                         {
673                           *newline = '\0';
674                           log_error ("%s\n", buffer);
675                           buffer_len -= newline + 1 - buffer;
676                           memmove (buffer, newline + 1, buffer_len);
677                         }
678                       else if (buffer_len == sizeof (buffer) - 1)
679                         {
680                           /* Overflow.  */
681                           log_error ("%s\n", buffer);
682                           buffer_len = 0;
683                         }
684                       else
685                         break;
686                     }
687
688                   if (res == 0)
689                     stderr_closed = 1;
690                 }
691             }
692           else if (FD_ISSET (master, &fds))
693             {
694               char data[512];
695
696               res = read (master, data, sizeof (data));
697               if (res < 0)
698                 {
699                   if (errno == EIO)
700                     {
701                       /* Slave-side close leads to readable fd and
702                          EIO.  */
703                       slave_closed = 1;
704                     }
705                   else
706                     {
707                       log_error (_("pty read failed: %s\n"), strerror (errno));
708
709                       kill (pid, SIGTERM);
710                       close (master);
711                       close (cstderr[0]);
712                       return 1;
713                     }
714                 }
715               else if (res == 0)
716                 /* This never seems to be what happens on slave-side
717                    close.  */
718                 slave_closed = 1;
719               else
720                 {
721                   /* Check for password prompt.  */
722                   if (data[res - 1] == ':')
723                     {
724                       char *pass;
725                       int canceled;
726
727                       /* If this is not the first attempt, the
728                          passphrase seems to be wrong, so clear the
729                          cache.  */
730                       if (tries)
731                         simple_pwclear (cacheid);
732
733                       pass = confucius_get_pass (cacheid,
734                                                  tries ? 1 : 0, &canceled);
735                       if (!pass)
736                         {
737                           kill (pid, SIGTERM);
738                           close (master);
739                           close (cstderr[0]);
740                           return canceled ? SYMC_CANCELED : 1;
741                         }
742                       write (master, pass, strlen (pass));
743                       write (master, "\n", 1);
744                       confucius_drop_pass (pass);
745
746                       tries++;
747                     }
748                 }
749             }
750         }
751       while (!stderr_closed || !slave_closed);
752
753       close (master);
754       close (cstderr[0]);
755
756       wpid = waitpid (pid, &res, 0);
757       if (wpid < 0)
758         {
759           log_error (_("waitpid failed: %s\n"), strerror (errno));
760
761           kill (pid, SIGTERM);
762           /* State of cached password is unclear.  Just remove it.  */
763           simple_pwclear (cacheid);
764           return 1;
765         }
766       else
767         {
768           /* Shouldn't happen, as we don't use WNOHANG.  */
769           assert (wpid != 0);
770
771           if (!WIFEXITED (res))
772             {
773               log_error (_("child aborted with status %i\n"), res);
774
775               /* State of cached password is unclear.  Just remove it.  */
776               simple_pwclear (cacheid);
777
778               return 1;
779             }
780
781           if (WEXITSTATUS (res))
782             {
783               /* The passphrase was wrong.  Remove it from the cache.  */
784               simple_pwclear (cacheid);
785
786               /* We probably exceeded our number of attempts at guessing
787                  the password.  */
788               if (tries >= 3)
789                 return SYMC_BAD_PASSPHRASE;
790               else
791                 return 1;
792             }
793
794           return 0;
795         }
796     }
797
798   /* Not reached.  */
799 }
800
801
802 /* Class confucius main program.  If MODE is oEncrypt, encryption is
803    requested.  If it is oDecrypt, decryption is requested.  The other
804    parameters are taken from the global option data.  */
805 int
806 confucius_main (int mode, int argc, char *argv[])
807 {
808   int res;
809   char *tmpdir;
810   char *infile;
811   int infile_from_stdin = 0;
812   char *outfile;
813
814   tmpdir = confucius_mktmpdir ();
815   if (!tmpdir)
816     return 1;
817
818   if (opt.input && !(opt.input[0] == '-' && opt.input[1] == '\0'))
819     infile = xstrdup (opt.input);
820   else
821     {
822       infile_from_stdin = 1;
823
824       /* TMPDIR + "/" + "in" + "\0".  */
825       infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
826       if (!infile)
827         {
828           log_error (_("cannot allocate infile string: %s\n"),
829                      strerror (errno));
830           rmdir (tmpdir);
831           return 1;
832         }
833       strcpy (infile, tmpdir);
834       strcat (infile, "/in");
835     }
836
837   /* TMPDIR + "/" + "out" + "\0".  */
838   outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
839   if (!outfile)
840     {
841       log_error (_("cannot allocate outfile string: %s\n"), strerror (errno));
842       free (infile);
843       rmdir (tmpdir);
844       return 1;
845     }
846   strcpy (outfile, tmpdir);
847   strcat (outfile, "/out");
848
849   if (infile_from_stdin)
850     {
851       /* Create INFILE and fill it with content.  */
852       res = confucius_copy_file ("-", infile, mode == oEncrypt);
853       if (res)
854         {
855           free (outfile);
856           free (infile);
857           rmdir (tmpdir);
858           return res;
859         }
860     }
861
862   /* Run the engine and thus create the output file, handling
863      passphrase retrieval.  */
864   res = confucius_process (mode, infile, outfile, argc, argv);
865   if (res)
866     {
867       remove_file (outfile, mode == oDecrypt);
868       if (infile_from_stdin)
869         remove_file (infile, mode == oEncrypt);
870       free (outfile);
871       free (infile);
872       rmdir (tmpdir);
873       return res;
874     }
875
876   /* Dump the output file to stdout.  */
877   res = confucius_copy_file (outfile, "-", mode == oDecrypt);
878   if (res)
879     {
880       remove_file (outfile, mode == oDecrypt);
881       if (infile_from_stdin)
882         remove_file (infile, mode == oEncrypt);
883       free (outfile);
884       free (infile);
885       rmdir (tmpdir);
886       return res;
887     }
888   
889   remove_file (outfile, mode == oDecrypt);
890   if (infile_from_stdin)
891     remove_file (infile, mode == oEncrypt);
892   free (outfile);
893   free (infile);
894   rmdir (tmpdir);
895   return 0;
896 }
897
898 \f
899 /* symcryptrun's entry point.  */
900 int
901 main (int argc, char **argv)
902 {
903   ARGPARSE_ARGS pargs;
904   int orig_argc;
905   char **orig_argv;
906   FILE *configfp = NULL;
907   char *configname = NULL;
908   unsigned configlineno; 
909   int mode = 0;
910   int res;
911   char *logfile = NULL;
912   int default_config = 1;
913
914   set_strusage (my_strusage);
915   log_set_prefix ("symcryptrun", 1);
916
917   /* Make sure that our subsystems are ready.  */
918   init_common_subsystems ();
919
920   i18n_init();
921
922   opt.homedir = default_homedir ();
923
924   /* Check whether we have a config file given on the commandline */
925   orig_argc = argc;
926   orig_argv = argv;
927   pargs.argc = &argc;
928   pargs.argv = &argv;
929   pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
930   while (arg_parse( &pargs, opts))
931     {
932       if (pargs.r_opt == oOptions)
933         { /* Yes there is one, so we do not try the default one, but
934              read the option file when it is encountered at the
935              commandline */
936           default_config = 0;
937         }
938       else if (pargs.r_opt == oNoOptions)
939         default_config = 0; /* --no-options */
940       else if (pargs.r_opt == oHomedir)
941         opt.homedir = pargs.r.ret_str;
942     }
943
944   if (default_config)
945     configname = make_filename (opt.homedir, "symcryptrun.conf", NULL );
946   
947   argc = orig_argc;
948   argv = orig_argv;
949   pargs.argc = &argc;
950   pargs.argv = &argv;
951   pargs.flags= 1;  /* do not remove the args */
952  next_pass:
953   if (configname)
954     {
955       configlineno = 0;
956       configfp = fopen (configname, "r");
957       if (!configfp)
958         {
959           if (!default_config)
960             {
961               log_error (_("option file `%s': %s\n"),
962                          configname, strerror(errno) );
963               exit(1);
964             }
965           xfree (configname); 
966           configname = NULL;
967         }
968       default_config = 0;
969     }
970
971   /* Parse the command line. */
972   while (optfile_parse (configfp, configname, &configlineno, &pargs, opts))
973     {
974       switch (pargs.r_opt)
975         {
976         case oDecrypt:   mode = oDecrypt; break;
977         case oEncrypt:   mode = oEncrypt; break;
978
979         case oQuiet:     opt.quiet = 1; break;
980         case oVerbose:   opt.verbose++; break;
981         case oNoVerbose: opt.verbose = 0; break;
982           
983         case oClass:    opt.class = pargs.r.ret_str; break;
984         case oProgram:  opt.program = pargs.r.ret_str; break;
985         case oKeyfile:  opt.keyfile = pargs.r.ret_str; break;
986         case oInput:    opt.input = pargs.r.ret_str; break;
987
988         case oLogFile:  logfile = pargs.r.ret_str; break;
989
990         case oOptions:
991           /* Config files may not be nested (silently ignore them) */
992           if (!configfp)
993             {
994                 xfree(configname);
995                 configname = xstrdup(pargs.r.ret_str);
996                 goto next_pass;
997             }
998           break;
999         case oNoOptions: break; /* no-options */
1000         case oHomedir: /* Ignore this option here. */; break;
1001
1002         default : pargs.err = configfp? 1:2; break;
1003         }
1004     }
1005   if (configfp)
1006     {
1007       fclose( configfp );
1008       configfp = NULL;
1009       configname = NULL;
1010       goto next_pass;
1011     }
1012   xfree (configname);
1013   configname = NULL;
1014
1015   if (!mode)
1016     log_error (_("either %s or %s must be given\n"),
1017                "--decrypt", "--encrypt");
1018
1019   if (log_get_errorcount (0))
1020     exit (1);
1021
1022   if (logfile)
1023     log_set_file (logfile);
1024
1025   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
1026   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
1027     {
1028       log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
1029                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
1030     }
1031   setup_libgcrypt_logging ();
1032   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
1033
1034   /* Tell simple-pwquery about the the standard socket name.  */
1035   {
1036     char *tmp = make_filename (opt.homedir, "S.gpg-agent", NULL);
1037     simple_pw_set_socket (tmp);
1038     xfree (tmp);
1039   }
1040
1041   if (!opt.class)
1042     {
1043       log_error (_("no class provided\n"));
1044       res = 1;
1045     }
1046   else if (!strcmp (opt.class, "confucius"))
1047     {
1048       res = confucius_main (mode, argc, argv);
1049     }
1050   else
1051     {
1052       log_error (_("class %s is not supported\n"), opt.class);
1053       res = 1;
1054     }
1055
1056   return res;
1057 }