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