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