First steps towards supporting W32.
[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
242 /* Unlink a file, and shred it if SHRED is true.  */
243 int
244 remove_file (char *name, int shred)
245 {
246   if (!shred)
247     return unlink (name);
248   else
249     {
250       int status;
251       pid_t pid;
252
253       pid = fork ();
254       if (pid == 0)
255         {
256           /* Child.  */
257           
258           /* -f forces file to be writable, and -u unlinks it afterwards.  */
259           char *args[] = { SHRED, "-uf", name, NULL };
260           
261           execv (SHRED, args);
262           _exit (127);
263         }
264       else if (pid < 0)
265         {
266           /* Fork failed.  */
267           status = -1;
268         }
269       else
270         {
271           /* Parent.  */
272           
273           if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
274             status = -1;
275         }
276       
277       if (!WIFEXITED (status))
278         {
279           log_error (_("%s on %s aborted with status %i\n"),
280                      SHRED, name, status);
281           unlink (name);
282           return 1;
283         }
284       else if (WEXITSTATUS (status))
285         {
286           log_error (_("%s on %s failed with status %i\n"), SHRED, name,
287                      WEXITSTATUS (status));
288           unlink (name);
289           return 1;
290         }
291
292       return 0;
293     }
294 }
295
296 \f
297 /* Class Confucius.
298
299    "Don't worry that other people don't know you;
300    worry that you don't know other people."            Analects--1.16.  */
301
302 /* Create temporary directory with mode 0700.  Returns a dynamically
303    allocated string with the filename of the directory.  */
304 static char *
305 confucius_mktmpdir (void)
306 {
307   char *name;
308
309   name = strdup ("/tmp/gpg-XXXXXX");
310   if (!name || !mkdtemp (name))
311     {
312       log_error (_("can't create temporary directory `%s': %s\n"),
313                  name?name:"", strerror (errno));
314       return NULL;
315     }
316
317   return name;
318 }
319
320
321 /* Buffer size for I/O operations.  */
322 #define CONFUCIUS_BUFSIZE 4096
323
324 /* Buffer size for output lines.  */
325 #define CONFUCIUS_LINESIZE 4096
326
327
328 /* Copy the file IN to OUT, either of which may be "-".  If PLAIN is
329    true, and the copying fails, and OUT is not STDOUT, then shred the
330    file instead unlinking it.  */
331 static int
332 confucius_copy_file (char *infile, char *outfile, int plain)
333 {
334   FILE *in;
335   int in_is_stdin = 0;
336   FILE *out;
337   int out_is_stdout = 0;
338   char data[CONFUCIUS_BUFSIZE];
339   ssize_t data_len;
340
341   if (infile[0] == '-' && infile[1] == '\0')
342     {
343       /* FIXME: Is stdin in binary mode?  */
344       in = stdin;
345       in_is_stdin = 1;
346     }
347   else
348     {
349       in = fopen (infile, "rb");
350       if (!in)
351         {
352           log_error (_("could not open %s for writing: %s\n"),
353                      infile, strerror (errno));
354           return 1;
355         }
356     }
357
358   if (outfile[0] == '-' && outfile[1] == '\0')
359     {
360       /* FIXME: Is stdout in binary mode?  */
361       out = stdout;
362       out_is_stdout = 1;
363     }
364   else
365     {
366       out = fopen (outfile, "wb");
367       if (!out)
368         {
369           log_error (_("could not open %s for writing: %s\n"),
370                      infile, strerror (errno));
371           return 1;
372         }
373     }
374
375   /* Now copy the data.  */
376   while ((data_len = fread (data, 1, sizeof (data), in)) > 0)
377     {
378       if (fwrite (data, 1, data_len, out) != data_len)
379         {
380           log_error (_("error writing to %s: %s\n"), outfile,
381                      strerror (errno));
382           goto copy_err;
383         }
384     }
385   if (data_len < 0 || ferror (in))
386     {
387       log_error (_("error reading from %s: %s\n"), infile, strerror (errno));
388       goto copy_err;
389     }
390
391   /* Close IN if appropriate.  */
392   if (!in_is_stdin && fclose (in) && ferror (in))
393     {
394       log_error (_("error closing %s: %s\n"), infile, strerror (errno));
395       goto copy_err;
396     }
397
398   /* Close OUT if appropriate.  */
399   if (!out_is_stdout && fclose (out) && ferror (out))
400     {
401       log_error (_("error closing %s: %s\n"), infile, strerror (errno));
402       goto copy_err;
403     }
404
405   return 0;
406
407  copy_err:
408   if (!out_is_stdout)
409     remove_file (outfile, plain);
410
411   return 1;
412 }
413
414
415 /* Get a passphrase in secure storage (if possible).  If AGAIN is
416    true, then this is a repeated attempt.  If CANCELED is not a null
417    pointer, it will be set to true or false, depending on if the user
418    canceled the operation or not.  On error (including cancelation), a
419    null pointer is returned.  The passphrase must be deallocated with
420    confucius_drop_pass.  CACHEID is the ID to be used for passphrase
421    caching and can be NULL to disable caching.  */
422 char *
423 confucius_get_pass (const char *cacheid, int again, int *canceled)
424 {
425   int err;
426   char *pw;
427 #ifdef HAVE_LANGINFO_CODESET
428   char *orig_codeset = NULL;
429 #endif
430
431   if (canceled)
432     *canceled = 0;
433   
434 #ifdef ENABLE_NLS
435   /* The Assuan agent protocol requires us to transmit utf-8 strings */
436   orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
437 #ifdef HAVE_LANGINFO_CODESET
438   if (!orig_codeset)
439     orig_codeset = nl_langinfo (CODESET);
440 #endif
441   if (orig_codeset && !strcmp (orig_codeset, "UTF-8"))
442     orig_codeset = NULL;
443   if (orig_codeset)
444     {
445       /* We only switch when we are able to restore the codeset later. */
446       orig_codeset = xstrdup (orig_codeset);
447       if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
448         {
449           xfree (orig_codeset);
450           orig_codeset = NULL; 
451         }
452     }
453 #endif
454
455   pw = simple_pwquery (cacheid,
456                        again ? _("does not match - try again"):NULL,
457                        _("Passphrase:"), NULL, 0, &err);
458
459 #ifdef ENABLE_NLS
460   if (orig_codeset)
461     {
462       bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
463       xfree (orig_codeset);
464     }
465 #endif
466
467   if (!pw)
468     {
469       if (err)
470         log_error (_("error while asking for the passphrase: %s\n"),
471                    gpg_strerror (err));
472       else
473         {
474           log_info (_("cancelled\n"));
475           if (canceled)
476             *canceled = 1;
477         }      
478     }
479
480   return pw;
481 }
482
483
484 /* Drop a passphrase retrieved with confucius_get_pass.  */
485 void
486 confucius_drop_pass (char *pass)
487 {
488   if (pass)
489     spwq_secure_free (pass);
490 }
491
492
493 /* Run a confucius crypto engine.  If MODE is oEncrypt, encryption is
494    requested.  If it is oDecrypt, decryption is requested.  INFILE and
495    OUTFILE are the temporary files used in the process.  */
496 int
497 confucius_process (int mode, char *infile, char *outfile,
498                    int argc, char *argv[])
499 {
500   char **args;
501   int cstderr[2];
502   int master;
503   int slave;
504   int res;
505   pid_t pid;
506   pid_t wpid;
507   int tries = 0;
508   char cacheid[40];
509
510   signal (SIGPIPE, SIG_IGN);
511
512   if (!opt.program)
513     {
514       log_error (_("no --program option provided\n"));
515       return 1;
516     }
517
518   if (mode != oDecrypt && mode != oEncrypt)
519     {
520       log_error (_("only --decrypt and --encrypt are supported\n"));
521       return 1;
522     }
523
524   if (!opt.keyfile)
525     {
526       log_error (_("no --keyfile option provided\n"));
527       return 1;
528     }
529
530   /* Generate a hash from the keyfile name for caching.  */
531   snprintf (cacheid, sizeof (cacheid), "confucius:%lu",
532             hash_string (opt.keyfile));
533   cacheid[sizeof (cacheid) - 1] = '\0';
534   args = malloc (sizeof (char *) * (10 + argc));
535   if (!args)
536     {
537       log_error (_("cannot allocate args vector\n"));
538       return 1;
539     }
540   args[0] = opt.program;
541   args[1] = (mode == oEncrypt) ? "-m1" : "-m2";
542   args[2] = "-q";
543   args[3] = infile;
544   args[4] = "-z";
545   args[5] = outfile;
546   args[6] = "-s";
547   args[7] = opt.keyfile;
548   args[8] = (mode == oEncrypt) ? "-af" : "-f";
549   args[9 + argc] = NULL;
550   while (argc--)
551     args[9 + argc] = argv[argc];
552
553   if (pipe (cstderr) < 0)
554     {
555       log_error (_("could not create pipe: %s\n"), strerror (errno));
556       free (args);
557       return 1;
558     }
559
560   if (openpty (&master, &slave, NULL, NULL, NULL) == -1)
561     {
562       log_error (_("could not create pty: %s\n"), strerror (errno));
563       close (cstderr[0]);
564       close (cstderr[1]);
565       free (args);
566       return -1;
567     }
568
569   /* We don't want to deal with the worst case scenarios.  */
570   assert (master > 2);
571   assert (slave > 2);
572   assert (cstderr[0] > 2);
573   assert (cstderr[1] > 2);
574
575   pid = fork ();
576   if (pid < 0)
577     {
578       log_error (_("could not fork: %s\n"), strerror (errno));
579       close (master);
580       close (slave);
581       close (cstderr[0]);
582       close (cstderr[1]);
583       free (args);
584       return 1;
585     }
586   else if (pid == 0) 
587     {
588       /* Child.  */
589
590       /* Close the parent ends.  */
591       close (master);
592       close (cstderr[0]);
593
594       /* Change controlling terminal.  */
595       if (login_tty (slave))
596         {
597           /* It's too early to output a debug message.  */
598           _exit (1);
599         }
600
601       dup2 (cstderr[1], 2);
602       close (cstderr[1]);
603
604       /* Now kick off the engine program.  */
605       execv (opt.program, args);
606       log_error (_("execv failed: %s\n"), strerror (errno));
607       _exit (1);
608     }
609   else
610     {
611       /* Parent.  */
612       char buffer[CONFUCIUS_LINESIZE];
613       int buffer_len = 0;
614       fd_set fds;
615       int slave_closed = 0;
616       int stderr_closed = 0;
617
618       close (slave);
619       close (cstderr[1]);
620       free (args);
621
622       /* Listen on the output FDs.  */
623       do
624         {
625           FD_ZERO (&fds);
626
627           if (!slave_closed)
628             FD_SET (master, &fds);
629           if (!stderr_closed)
630             FD_SET (cstderr[0], &fds);
631
632           res = select (FD_SETSIZE, &fds, NULL, NULL, NULL);
633           if (res < 0)
634             {
635               log_error (_("select failed: %s\n"), strerror (errno));
636
637               kill (pid, SIGTERM);
638               close (master);
639               close (cstderr[0]);
640               return 1;
641             }
642
643           if (FD_ISSET (cstderr[0], &fds))
644             {
645               /* We got some output on stderr.  This is just passed
646                  through via the logging facility.  */
647
648               res = read (cstderr[0], &buffer[buffer_len],
649                           sizeof (buffer) - buffer_len - 1);
650               if (res < 0)
651                 {
652                   log_error (_("read failed: %s\n"), strerror (errno));
653
654                   kill (pid, SIGTERM);
655                   close (master);
656                   close (cstderr[0]);
657                   return 1;
658                 }
659               else  
660                 {
661                   char *newline;
662
663                   buffer_len += res;
664                   for (;;)
665                     {
666                       buffer[buffer_len] = '\0';
667                       newline = strchr (buffer, '\n');
668                       if (newline)
669                         {
670                           *newline = '\0';
671                           log_error ("%s\n", buffer);
672                           buffer_len -= newline + 1 - buffer;
673                           memmove (buffer, newline + 1, buffer_len);
674                         }
675                       else if (buffer_len == sizeof (buffer) - 1)
676                         {
677                           /* Overflow.  */
678                           log_error ("%s\n", buffer);
679                           buffer_len = 0;
680                         }
681                       else
682                         break;
683                     }
684
685                   if (res == 0)
686                     stderr_closed = 1;
687                 }
688             }
689           else if (FD_ISSET (master, &fds))
690             {
691               char data[512];
692
693               res = read (master, data, sizeof (data));
694               if (res < 0)
695                 {
696                   if (errno == EIO)
697                     {
698                       /* Slave-side close leads to readable fd and
699                          EIO.  */
700                       slave_closed = 1;
701                     }
702                   else
703                     {
704                       log_error (_("pty read failed: %s\n"), strerror (errno));
705
706                       kill (pid, SIGTERM);
707                       close (master);
708                       close (cstderr[0]);
709                       return 1;
710                     }
711                 }
712               else if (res == 0)
713                 /* This never seems to be what happens on slave-side
714                    close.  */
715                 slave_closed = 1;
716               else
717                 {
718                   /* Check for password prompt.  */
719                   if (data[res - 1] == ':')
720                     {
721                       char *pass;
722                       int canceled;
723
724                       /* If this is not the first attempt, the
725                          passphrase seems to be wrong, so clear the
726                          cache.  */
727                       if (tries)
728                         simple_pwclear (cacheid);
729
730                       pass = confucius_get_pass (cacheid,
731                                                  tries ? 1 : 0, &canceled);
732                       if (!pass)
733                         {
734                           kill (pid, SIGTERM);
735                           close (master);
736                           close (cstderr[0]);
737                           return canceled ? SYMC_CANCELED : 1;
738                         }
739                       write (master, pass, strlen (pass));
740                       write (master, "\n", 1);
741                       confucius_drop_pass (pass);
742
743                       tries++;
744                     }
745                 }
746             }
747         }
748       while (!stderr_closed || !slave_closed);
749
750       close (master);
751       close (cstderr[0]);
752
753       wpid = waitpid (pid, &res, 0);
754       if (wpid < 0)
755         {
756           log_error (_("waitpid failed: %s\n"), strerror (errno));
757
758           kill (pid, SIGTERM);
759           /* State of cached password is unclear.  Just remove it.  */
760           simple_pwclear (cacheid);
761           return 1;
762         }
763       else
764         {
765           /* Shouldn't happen, as we don't use WNOHANG.  */
766           assert (wpid != 0);
767
768           if (!WIFEXITED (res))
769             {
770               log_error (_("child aborted with status %i\n"), res);
771
772               /* State of cached password is unclear.  Just remove it.  */
773               simple_pwclear (cacheid);
774
775               return 1;
776             }
777
778           if (WEXITSTATUS (res))
779             {
780               /* The passphrase was wrong.  Remove it from the cache.  */
781               simple_pwclear (cacheid);
782
783               /* We probably exceeded our number of attempts at guessing
784                  the password.  */
785               if (tries >= 3)
786                 return SYMC_BAD_PASSPHRASE;
787               else
788                 return 1;
789             }
790
791           return 0;
792         }
793     }
794
795   /* Not reached.  */
796 }
797
798
799 /* Class confucius main program.  If MODE is oEncrypt, encryption is
800    requested.  If it is oDecrypt, decryption is requested.  The other
801    parameters are taken from the global option data.  */
802 int
803 confucius_main (int mode, int argc, char *argv[])
804 {
805   int res;
806   char *tmpdir;
807   char *infile;
808   int infile_from_stdin = 0;
809   char *outfile;
810
811   tmpdir = confucius_mktmpdir ();
812   if (!tmpdir)
813     return 1;
814
815   if (opt.input && !(opt.input[0] == '-' && opt.input[1] == '\0'))
816     infile = xstrdup (opt.input);
817   else
818     {
819       infile_from_stdin = 1;
820
821       /* TMPDIR + "/" + "in" + "\0".  */
822       infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
823       if (!infile)
824         {
825           log_error (_("cannot allocate infile string: %s\n"),
826                      strerror (errno));
827           rmdir (tmpdir);
828           return 1;
829         }
830       strcpy (infile, tmpdir);
831       strcat (infile, "/in");
832     }
833
834   /* TMPDIR + "/" + "out" + "\0".  */
835   outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
836   if (!outfile)
837     {
838       log_error (_("cannot allocate outfile string: %s\n"), strerror (errno));
839       free (infile);
840       rmdir (tmpdir);
841       return 1;
842     }
843   strcpy (outfile, tmpdir);
844   strcat (outfile, "/out");
845
846   if (infile_from_stdin)
847     {
848       /* Create INFILE and fill it with content.  */
849       res = confucius_copy_file ("-", infile, mode == oEncrypt);
850       if (res)
851         {
852           free (outfile);
853           free (infile);
854           rmdir (tmpdir);
855           return res;
856         }
857     }
858
859   /* Run the engine and thus create the output file, handling
860      passphrase retrieval.  */
861   res = confucius_process (mode, infile, outfile, argc, argv);
862   if (res)
863     {
864       remove_file (outfile, mode == oDecrypt);
865       if (infile_from_stdin)
866         remove_file (infile, mode == oEncrypt);
867       free (outfile);
868       free (infile);
869       rmdir (tmpdir);
870       return res;
871     }
872
873   /* Dump the output file to stdout.  */
874   res = confucius_copy_file (outfile, "-", mode == oDecrypt);
875   if (res)
876     {
877       remove_file (outfile, mode == oDecrypt);
878       if (infile_from_stdin)
879         remove_file (infile, mode == oEncrypt);
880       free (outfile);
881       free (infile);
882       rmdir (tmpdir);
883       return res;
884     }
885   
886   remove_file (outfile, mode == oDecrypt);
887   if (infile_from_stdin)
888     remove_file (infile, mode == oEncrypt);
889   free (outfile);
890   free (infile);
891   rmdir (tmpdir);
892   return 0;
893 }
894
895 \f
896 /* symcryptrun's entry point.  */
897 int
898 main (int argc, char **argv)
899 {
900   ARGPARSE_ARGS pargs;
901   int orig_argc;
902   char **orig_argv;
903   FILE *configfp = NULL;
904   char *configname = NULL;
905   unsigned configlineno; 
906   int mode = 0;
907   int res;
908   char *logfile = NULL;
909   int default_config = 1;
910
911   set_strusage (my_strusage);
912   log_set_prefix ("symcryptrun", 1);
913
914   /* Try to auto set the character set.  */
915   set_native_charset (NULL); 
916
917   i18n_init();
918
919   opt.homedir = default_homedir ();
920
921   /* Check whether we have a config file given on the commandline */
922   orig_argc = argc;
923   orig_argv = argv;
924   pargs.argc = &argc;
925   pargs.argv = &argv;
926   pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
927   while (arg_parse( &pargs, opts))
928     {
929       if (pargs.r_opt == oOptions)
930         { /* Yes there is one, so we do not try the default one, but
931              read the option file when it is encountered at the
932              commandline */
933           default_config = 0;
934         }
935       else if (pargs.r_opt == oNoOptions)
936         default_config = 0; /* --no-options */
937       else if (pargs.r_opt == oHomedir)
938         opt.homedir = pargs.r.ret_str;
939     }
940
941   if (default_config)
942     configname = make_filename (opt.homedir, "symcryptrun.conf", NULL );
943   
944   argc = orig_argc;
945   argv = orig_argv;
946   pargs.argc = &argc;
947   pargs.argv = &argv;
948   pargs.flags= 1;  /* do not remove the args */
949  next_pass:
950   if (configname)
951     {
952       configlineno = 0;
953       configfp = fopen (configname, "r");
954       if (!configfp)
955         {
956           if (!default_config)
957             {
958               log_error (_("option file `%s': %s\n"),
959                          configname, strerror(errno) );
960               exit(1);
961             }
962           xfree (configname); 
963           configname = NULL;
964         }
965       default_config = 0;
966     }
967
968   /* Parse the command line. */
969   while (optfile_parse (configfp, configname, &configlineno, &pargs, opts))
970     {
971       switch (pargs.r_opt)
972         {
973         case oDecrypt:   mode = oDecrypt; break;
974         case oEncrypt:   mode = oEncrypt; break;
975
976         case oQuiet:     opt.quiet = 1; break;
977         case oVerbose:   opt.verbose++; break;
978         case oNoVerbose: opt.verbose = 0; break;
979           
980         case oClass:    opt.class = pargs.r.ret_str; break;
981         case oProgram:  opt.program = pargs.r.ret_str; break;
982         case oKeyfile:  opt.keyfile = pargs.r.ret_str; break;
983         case oInput:    opt.input = pargs.r.ret_str; break;
984
985         case oLogFile:  logfile = pargs.r.ret_str; break;
986
987         case oOptions:
988           /* Config files may not be nested (silently ignore them) */
989           if (!configfp)
990             {
991                 xfree(configname);
992                 configname = xstrdup(pargs.r.ret_str);
993                 goto next_pass;
994             }
995           break;
996         case oNoOptions: break; /* no-options */
997         case oHomedir: /* Ignore this option here. */; break;
998
999         default : pargs.err = configfp? 1:2; break;
1000         }
1001     }
1002   if (configfp)
1003     {
1004       fclose( configfp );
1005       configfp = NULL;
1006       configname = NULL;
1007       goto next_pass;
1008     }
1009   xfree (configname);
1010   configname = NULL;
1011
1012   if (!mode)
1013     log_error (_("either %s or %s must be given\n"),
1014                "--decrypt", "--encrypt");
1015
1016   if (log_get_errorcount (0))
1017     exit (1);
1018
1019   if (logfile)
1020     log_set_file (logfile);
1021
1022   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
1023   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
1024     {
1025       log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
1026                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
1027     }
1028   setup_libgcrypt_logging ();
1029   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
1030
1031   if (!opt.class)
1032     {
1033       log_error (_("no class provided\n"));
1034       res = 1;
1035     }
1036   else if (!strcmp (opt.class, "confucius"))
1037     res = confucius_main (mode, argc, argv);
1038   else
1039     {
1040       log_error (_("class %s is not supported\n"), opt.class);
1041       res = 1;
1042     }
1043
1044   return res;
1045 }