2007-07-05 Marcus Brinkmann <marcus@g10code.de>
[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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 /* Sometimes simple encryption tools are already in use for a long
22    time and there is a desire to integrate them into the GnuPG
23    framework.  The protocols and encryption methods might be
24    non-standard or not even properly documented, so that a
25    full-fledged encryption tool with an interface like gpg is not
26    doable.  This simple wrapper program provides a solution: It
27    operates by calling the encryption/decryption module and providing
28    the passphrase for a key (or even the key directly) using the
29    standard pinentry mechanism through gpg-agent.  */
30
31 /* This program is invoked in the following way:
32
33    symcryptrun --class CLASS --program PROGRAM --keyfile KEYFILE \
34      [--decrypt | --encrypt]
35
36    For encryption, the plain text must be provided on STDIN, and the
37    ciphertext will be output to STDOUT.  For decryption vice versa.
38
39    CLASS can currently only be "confucius".
40
41    PROGRAM must be the path to the crypto engine.
42
43    KEYFILE must contain the secret key, which may be protected by a
44    passphrase.  The passphrase is retrieved via the pinentry program.
45
46
47    The GPG Agent _must_ be running before starting symcryptrun.
48
49    The possible exit status codes:
50
51    0    Success
52    1    Some error occured
53    2    No valid passphrase was provided
54    3    The operation was canceled by the user
55
56    Other classes may be added in the future.  */
57
58 #define SYMC_BAD_PASSPHRASE     2
59 #define SYMC_CANCELED           3
60
61 \f
62 #include <config.h>
63
64 #include <unistd.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <errno.h>
69 #include <assert.h>
70 #include <signal.h>
71 #include <sys/stat.h>
72 #include <sys/types.h>
73 #include <sys/wait.h>
74 #ifdef HAVE_PTY_H
75 #include <pty.h>
76 #endif
77 #include <utmp.h>
78 #include <ctype.h>
79 #ifdef HAVE_LOCALE_H
80 #include <locale.h>
81 #endif
82 #ifdef HAVE_LANGINFO_CODESET
83 #include <langinfo.h>
84 #endif
85 #include <gpg-error.h>
86
87 #define JNLIB_NEED_LOG_LOGV
88 #include "i18n.h"
89 #include "../common/util.h"
90 #include "mkdtemp.h"
91
92 /* FIXME: Bah.  For spwq_secure_free.  */
93 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
94 #include "../common/simple-pwquery.h"
95
96 \f
97 /* From simple-gettext.c.  */
98
99 /* We assume to have `unsigned long int' value with at least 32 bits.  */
100 #define HASHWORDBITS 32
101
102 /* The so called `hashpjw' function by P.J. Weinberger
103    [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
104    1986, 1987 Bell Telephone Laboratories, Inc.]  */
105
106 static __inline__ ulong
107 hash_string( const char *str_param )
108 {
109     unsigned long int hval, g;
110     const char *str = str_param;
111
112     hval = 0;
113     while (*str != '\0')
114     {
115         hval <<= 4;
116         hval += (unsigned long int) *str++;
117         g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
118         if (g != 0)
119         {
120           hval ^= g >> (HASHWORDBITS - 8);
121           hval ^= g;
122         }
123     }
124     return hval;
125 }
126
127 \f
128 /* Constants to identify the commands and options. */
129 enum cmd_and_opt_values
130   {
131     aNull = 0,
132     oQuiet      = 'q',
133     oVerbose    = 'v',
134
135     oNoVerbose  = 500,
136     oOptions,
137     oNoOptions,
138     oLogFile,
139     oHomedir,
140     oClass,
141     oProgram,
142     oKeyfile,
143     oDecrypt,
144     oEncrypt,
145     oInput
146   };
147
148
149 /* The list of commands and options.  */
150 static ARGPARSE_OPTS opts[] =
151   {
152     { 301, NULL, 0, N_("@\nCommands:\n ") },
153
154     { oDecrypt, "decrypt", 0, N_("decryption modus") },
155     { oEncrypt, "encrypt", 0, N_("encryption modus") },
156     
157     { 302, NULL, 0, N_("@\nOptions:\n ") },
158     
159     { oClass, "class", 2, N_("tool class (confucius)") },
160     { oProgram, "program", 2, N_("program filename") },
161
162     { oKeyfile, "keyfile", 2, N_("secret key file (required)") },
163     { oInput, "inputfile", 2, N_("input file name (default stdin)") },
164     { oVerbose, "verbose",  0, N_("verbose") },
165     { oQuiet, "quiet",      0, N_("quiet") },
166     { oLogFile, "log-file", 2, N_("use a log file for the server") },
167     { oOptions,  "options"  , 2, N_("|FILE|read options from FILE") },
168
169     /* Hidden options.  */
170     { oNoVerbose, "no-verbose",  0, "@" },
171     { oHomedir, "homedir", 2, "@" },   
172     { oNoOptions, "no-options", 0, "@" },/* shortcut for --options /dev/null */
173
174     {0}
175   };
176
177
178 /* We keep all global options in the structure OPT.  */
179 struct
180 {
181   int verbose;          /* Verbosity level.  */
182   int quiet;            /* Be extra quiet.  */
183   const char *homedir;  /* Configuration directory name */
184
185   char *class;
186   char *program;
187   char *keyfile;
188   char *input;
189 } opt;
190
191 \f
192 /* Print usage information and and provide strings for help.  */
193 static const char *
194 my_strusage (int level)
195 {
196   const char *p;
197
198   switch (level)
199     {
200     case 11: p = "symcryptrun (GnuPG)";
201       break;
202     case 13: p = VERSION; break;
203     case 17: p = PRINTABLE_OS_NAME; break;
204     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
205       break;
206     case 1:
207     case 40: p = _("Usage: symcryptrun [options] (-h for help)");
208       break;
209     case 41:
210       p = _("Syntax: symcryptrun --class CLASS --program PROGRAM "
211             "--keyfile KEYFILE [options...] COMMAND [inputfile]\n"
212             "Call a simple symmetric encryption tool\n");
213       break;
214     case 31: p = "\nHome: "; break;
215     case 32: p = opt.homedir; break;
216     case 33: p = "\n"; break;
217
218     default: p = NULL; break;
219     }
220   return p;
221 }
222
223
224 \f
225 /* This is in the GNU C library in unistd.h.  */
226
227 #ifndef TEMP_FAILURE_RETRY
228 /* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno'
229    set to EINTR.  */
230
231 # define TEMP_FAILURE_RETRY(expression) \
232   (__extension__                                                              \
233     ({ long int __result;                                                     \
234        do __result = (long int) (expression);                                 \
235        while (__result == -1L && errno == EINTR);                             \
236        __result; }))
237 #endif
238
239 /* Include the implementation of map_spwq_error.  */
240 MAP_SPWQ_ERROR_IMPL
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 ENABLE_NLS
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   err = map_spwq_error (err);
459
460 #ifdef ENABLE_NLS
461   if (orig_codeset)
462     {
463       bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
464       xfree (orig_codeset);
465     }
466 #endif
467
468   if (!pw)
469     {
470       if (err)
471         log_error (_("error while asking for the passphrase: %s\n"),
472                    gpg_strerror (err));
473       else
474         {
475           log_info (_("cancelled\n"));
476           if (canceled)
477             *canceled = 1;
478         }      
479     }
480
481   return pw;
482 }
483
484
485 /* Drop a passphrase retrieved with confucius_get_pass.  */
486 void
487 confucius_drop_pass (char *pass)
488 {
489   if (pass)
490     spwq_secure_free (pass);
491 }
492
493
494 /* Run a confucius crypto engine.  If MODE is oEncrypt, encryption is
495    requested.  If it is oDecrypt, decryption is requested.  INFILE and
496    OUTFILE are the temporary files used in the process.  */
497 int
498 confucius_process (int mode, char *infile, char *outfile,
499                    int argc, char *argv[])
500 {
501   char **args;
502   int cstderr[2];
503   int master;
504   int slave;
505   int res;
506   pid_t pid;
507   pid_t wpid;
508   int tries = 0;
509   char cacheid[40];
510
511   signal (SIGPIPE, SIG_IGN);
512
513   if (!opt.program)
514     {
515       log_error (_("no --program option provided\n"));
516       return 1;
517     }
518
519   if (mode != oDecrypt && mode != oEncrypt)
520     {
521       log_error (_("only --decrypt and --encrypt are supported\n"));
522       return 1;
523     }
524
525   if (!opt.keyfile)
526     {
527       log_error (_("no --keyfile option provided\n"));
528       return 1;
529     }
530
531   /* Generate a hash from the keyfile name for caching.  */
532   snprintf (cacheid, sizeof (cacheid), "confucius:%lu",
533             hash_string (opt.keyfile));
534   cacheid[sizeof (cacheid) - 1] = '\0';
535   args = malloc (sizeof (char *) * (10 + argc));
536   if (!args)
537     {
538       log_error (_("cannot allocate args vector\n"));
539       return 1;
540     }
541   args[0] = opt.program;
542   args[1] = (mode == oEncrypt) ? "-m1" : "-m2";
543   args[2] = "-q";
544   args[3] = infile;
545   args[4] = "-z";
546   args[5] = outfile;
547   args[6] = "-s";
548   args[7] = opt.keyfile;
549   args[8] = (mode == oEncrypt) ? "-af" : "-f";
550   args[9 + argc] = NULL;
551   while (argc--)
552     args[9 + argc] = argv[argc];
553
554   if (pipe (cstderr) < 0)
555     {
556       log_error (_("could not create pipe: %s\n"), strerror (errno));
557       free (args);
558       return 1;
559     }
560
561   if (openpty (&master, &slave, NULL, NULL, NULL) == -1)
562     {
563       log_error (_("could not create pty: %s\n"), strerror (errno));
564       close (cstderr[0]);
565       close (cstderr[1]);
566       free (args);
567       return -1;
568     }
569
570   /* We don't want to deal with the worst case scenarios.  */
571   assert (master > 2);
572   assert (slave > 2);
573   assert (cstderr[0] > 2);
574   assert (cstderr[1] > 2);
575
576   pid = fork ();
577   if (pid < 0)
578     {
579       log_error (_("could not fork: %s\n"), strerror (errno));
580       close (master);
581       close (slave);
582       close (cstderr[0]);
583       close (cstderr[1]);
584       free (args);
585       return 1;
586     }
587   else if (pid == 0) 
588     {
589       /* Child.  */
590
591       /* Close the parent ends.  */
592       close (master);
593       close (cstderr[0]);
594
595       /* Change controlling terminal.  */
596       if (login_tty (slave))
597         {
598           /* It's too early to output a debug message.  */
599           _exit (1);
600         }
601
602       dup2 (cstderr[1], 2);
603       close (cstderr[1]);
604
605       /* Now kick off the engine program.  */
606       execv (opt.program, args);
607       log_error (_("execv failed: %s\n"), strerror (errno));
608       _exit (1);
609     }
610   else
611     {
612       /* Parent.  */
613       char buffer[CONFUCIUS_LINESIZE];
614       int buffer_len = 0;
615       fd_set fds;
616       int slave_closed = 0;
617       int stderr_closed = 0;
618
619       close (slave);
620       close (cstderr[1]);
621       free (args);
622
623       /* Listen on the output FDs.  */
624       do
625         {
626           FD_ZERO (&fds);
627
628           if (!slave_closed)
629             FD_SET (master, &fds);
630           if (!stderr_closed)
631             FD_SET (cstderr[0], &fds);
632
633           res = select (FD_SETSIZE, &fds, NULL, NULL, NULL);
634           if (res < 0)
635             {
636               log_error (_("select failed: %s\n"), strerror (errno));
637
638               kill (pid, SIGTERM);
639               close (master);
640               close (cstderr[0]);
641               return 1;
642             }
643
644           if (FD_ISSET (cstderr[0], &fds))
645             {
646               /* We got some output on stderr.  This is just passed
647                  through via the logging facility.  */
648
649               res = read (cstderr[0], &buffer[buffer_len],
650                           sizeof (buffer) - buffer_len - 1);
651               if (res < 0)
652                 {
653                   log_error (_("read failed: %s\n"), strerror (errno));
654
655                   kill (pid, SIGTERM);
656                   close (master);
657                   close (cstderr[0]);
658                   return 1;
659                 }
660               else  
661                 {
662                   char *newline;
663
664                   buffer_len += res;
665                   for (;;)
666                     {
667                       buffer[buffer_len] = '\0';
668                       newline = strchr (buffer, '\n');
669                       if (newline)
670                         {
671                           *newline = '\0';
672                           log_error ("%s\n", buffer);
673                           buffer_len -= newline + 1 - buffer;
674                           memmove (buffer, newline + 1, buffer_len);
675                         }
676                       else if (buffer_len == sizeof (buffer) - 1)
677                         {
678                           /* Overflow.  */
679                           log_error ("%s\n", buffer);
680                           buffer_len = 0;
681                         }
682                       else
683                         break;
684                     }
685
686                   if (res == 0)
687                     stderr_closed = 1;
688                 }
689             }
690           else if (FD_ISSET (master, &fds))
691             {
692               char data[512];
693
694               res = read (master, data, sizeof (data));
695               if (res < 0)
696                 {
697                   if (errno == EIO)
698                     {
699                       /* Slave-side close leads to readable fd and
700                          EIO.  */
701                       slave_closed = 1;
702                     }
703                   else
704                     {
705                       log_error (_("pty read failed: %s\n"), strerror (errno));
706
707                       kill (pid, SIGTERM);
708                       close (master);
709                       close (cstderr[0]);
710                       return 1;
711                     }
712                 }
713               else if (res == 0)
714                 /* This never seems to be what happens on slave-side
715                    close.  */
716                 slave_closed = 1;
717               else
718                 {
719                   /* Check for password prompt.  */
720                   if (data[res - 1] == ':')
721                     {
722                       char *pass;
723                       int canceled;
724
725                       /* If this is not the first attempt, the
726                          passphrase seems to be wrong, so clear the
727                          cache.  */
728                       if (tries)
729                         simple_pwclear (cacheid);
730
731                       pass = confucius_get_pass (cacheid,
732                                                  tries ? 1 : 0, &canceled);
733                       if (!pass)
734                         {
735                           kill (pid, SIGTERM);
736                           close (master);
737                           close (cstderr[0]);
738                           return canceled ? SYMC_CANCELED : 1;
739                         }
740                       write (master, pass, strlen (pass));
741                       write (master, "\n", 1);
742                       confucius_drop_pass (pass);
743
744                       tries++;
745                     }
746                 }
747             }
748         }
749       while (!stderr_closed || !slave_closed);
750
751       close (master);
752       close (cstderr[0]);
753
754       wpid = waitpid (pid, &res, 0);
755       if (wpid < 0)
756         {
757           log_error (_("waitpid failed: %s\n"), strerror (errno));
758
759           kill (pid, SIGTERM);
760           /* State of cached password is unclear.  Just remove it.  */
761           simple_pwclear (cacheid);
762           return 1;
763         }
764       else
765         {
766           /* Shouldn't happen, as we don't use WNOHANG.  */
767           assert (wpid != 0);
768
769           if (!WIFEXITED (res))
770             {
771               log_error (_("child aborted with status %i\n"), res);
772
773               /* State of cached password is unclear.  Just remove it.  */
774               simple_pwclear (cacheid);
775
776               return 1;
777             }
778
779           if (WEXITSTATUS (res))
780             {
781               /* The passphrase was wrong.  Remove it from the cache.  */
782               simple_pwclear (cacheid);
783
784               /* We probably exceeded our number of attempts at guessing
785                  the password.  */
786               if (tries >= 3)
787                 return SYMC_BAD_PASSPHRASE;
788               else
789                 return 1;
790             }
791
792           return 0;
793         }
794     }
795
796   /* Not reached.  */
797 }
798
799
800 /* Class confucius main program.  If MODE is oEncrypt, encryption is
801    requested.  If it is oDecrypt, decryption is requested.  The other
802    parameters are taken from the global option data.  */
803 int
804 confucius_main (int mode, int argc, char *argv[])
805 {
806   int res;
807   char *tmpdir;
808   char *infile;
809   int infile_from_stdin = 0;
810   char *outfile;
811
812   tmpdir = confucius_mktmpdir ();
813   if (!tmpdir)
814     return 1;
815
816   if (opt.input && !(opt.input[0] == '-' && opt.input[1] == '\0'))
817     infile = xstrdup (opt.input);
818   else
819     {
820       infile_from_stdin = 1;
821
822       /* TMPDIR + "/" + "in" + "\0".  */
823       infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
824       if (!infile)
825         {
826           log_error (_("cannot allocate infile string: %s\n"),
827                      strerror (errno));
828           rmdir (tmpdir);
829           return 1;
830         }
831       strcpy (infile, tmpdir);
832       strcat (infile, "/in");
833     }
834
835   /* TMPDIR + "/" + "out" + "\0".  */
836   outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
837   if (!outfile)
838     {
839       log_error (_("cannot allocate outfile string: %s\n"), strerror (errno));
840       free (infile);
841       rmdir (tmpdir);
842       return 1;
843     }
844   strcpy (outfile, tmpdir);
845   strcat (outfile, "/out");
846
847   if (infile_from_stdin)
848     {
849       /* Create INFILE and fill it with content.  */
850       res = confucius_copy_file ("-", infile, mode == oEncrypt);
851       if (res)
852         {
853           free (outfile);
854           free (infile);
855           rmdir (tmpdir);
856           return res;
857         }
858     }
859
860   /* Run the engine and thus create the output file, handling
861      passphrase retrieval.  */
862   res = confucius_process (mode, infile, outfile, argc, argv);
863   if (res)
864     {
865       remove_file (outfile, mode == oDecrypt);
866       if (infile_from_stdin)
867         remove_file (infile, mode == oEncrypt);
868       free (outfile);
869       free (infile);
870       rmdir (tmpdir);
871       return res;
872     }
873
874   /* Dump the output file to stdout.  */
875   res = confucius_copy_file (outfile, "-", mode == oDecrypt);
876   if (res)
877     {
878       remove_file (outfile, mode == oDecrypt);
879       if (infile_from_stdin)
880         remove_file (infile, mode == oEncrypt);
881       free (outfile);
882       free (infile);
883       rmdir (tmpdir);
884       return res;
885     }
886   
887   remove_file (outfile, mode == oDecrypt);
888   if (infile_from_stdin)
889     remove_file (infile, mode == oEncrypt);
890   free (outfile);
891   free (infile);
892   rmdir (tmpdir);
893   return 0;
894 }
895
896 \f
897 /* symcryptrun's entry point.  */
898 int
899 main (int argc, char **argv)
900 {
901   ARGPARSE_ARGS pargs;
902   int orig_argc;
903   char **orig_argv;
904   FILE *configfp = NULL;
905   char *configname = NULL;
906   unsigned configlineno; 
907   int mode = 0;
908   int res;
909   char *logfile = NULL;
910   int default_config = 1;
911
912   set_strusage (my_strusage);
913   log_set_prefix ("symcryptrun", 1);
914
915   /* Make sure that our subsystems are ready.  */
916   init_common_subsystems ();
917
918   i18n_init();
919
920   opt.homedir = default_homedir ();
921
922   /* Check whether we have a config file given on the commandline */
923   orig_argc = argc;
924   orig_argv = argv;
925   pargs.argc = &argc;
926   pargs.argv = &argv;
927   pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
928   while (arg_parse( &pargs, opts))
929     {
930       if (pargs.r_opt == oOptions)
931         { /* Yes there is one, so we do not try the default one, but
932              read the option file when it is encountered at the
933              commandline */
934           default_config = 0;
935         }
936       else if (pargs.r_opt == oNoOptions)
937         default_config = 0; /* --no-options */
938       else if (pargs.r_opt == oHomedir)
939         opt.homedir = pargs.r.ret_str;
940     }
941
942   if (default_config)
943     configname = make_filename (opt.homedir, "symcryptrun.conf", NULL );
944   
945   argc = orig_argc;
946   argv = orig_argv;
947   pargs.argc = &argc;
948   pargs.argv = &argv;
949   pargs.flags= 1;  /* do not remove the args */
950  next_pass:
951   if (configname)
952     {
953       configlineno = 0;
954       configfp = fopen (configname, "r");
955       if (!configfp)
956         {
957           if (!default_config)
958             {
959               log_error (_("option file `%s': %s\n"),
960                          configname, strerror(errno) );
961               exit(1);
962             }
963           xfree (configname); 
964           configname = NULL;
965         }
966       default_config = 0;
967     }
968
969   /* Parse the command line. */
970   while (optfile_parse (configfp, configname, &configlineno, &pargs, opts))
971     {
972       switch (pargs.r_opt)
973         {
974         case oDecrypt:   mode = oDecrypt; break;
975         case oEncrypt:   mode = oEncrypt; break;
976
977         case oQuiet:     opt.quiet = 1; break;
978         case oVerbose:   opt.verbose++; break;
979         case oNoVerbose: opt.verbose = 0; break;
980           
981         case oClass:    opt.class = pargs.r.ret_str; break;
982         case oProgram:  opt.program = pargs.r.ret_str; break;
983         case oKeyfile:  opt.keyfile = pargs.r.ret_str; break;
984         case oInput:    opt.input = pargs.r.ret_str; break;
985
986         case oLogFile:  logfile = pargs.r.ret_str; break;
987
988         case oOptions:
989           /* Config files may not be nested (silently ignore them) */
990           if (!configfp)
991             {
992                 xfree(configname);
993                 configname = xstrdup(pargs.r.ret_str);
994                 goto next_pass;
995             }
996           break;
997         case oNoOptions: break; /* no-options */
998         case oHomedir: /* Ignore this option here. */; break;
999
1000         default : pargs.err = configfp? 1:2; break;
1001         }
1002     }
1003   if (configfp)
1004     {
1005       fclose( configfp );
1006       configfp = NULL;
1007       configname = NULL;
1008       goto next_pass;
1009     }
1010   xfree (configname);
1011   configname = NULL;
1012
1013   if (!mode)
1014     log_error (_("either %s or %s must be given\n"),
1015                "--decrypt", "--encrypt");
1016
1017   if (log_get_errorcount (0))
1018     exit (1);
1019
1020   if (logfile)
1021     log_set_file (logfile);
1022
1023   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
1024   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
1025     {
1026       log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
1027                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
1028     }
1029   setup_libgcrypt_logging ();
1030   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
1031
1032   /* Tell simple-pwquery about the the standard socket name.  */
1033   {
1034     char *tmp = make_filename (opt.homedir, "S.gpg-agent", NULL);
1035     simple_pw_set_socket (tmp);
1036     xfree (tmp);
1037   }
1038
1039   if (!opt.class)
1040     {
1041       log_error (_("no class provided\n"));
1042       res = 1;
1043     }
1044   else if (!strcmp (opt.class, "confucius"))
1045     {
1046       res = confucius_main (mode, argc, argv);
1047     }
1048   else
1049     {
1050       log_error (_("class %s is not supported\n"), opt.class);
1051       res = 1;
1052     }
1053
1054   return res;
1055 }