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