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