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