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     oLogFile,
119     oHomedir,
120     oClass,
121     oProgram,
122     oKeyfile,
123     oDecrypt,
124     oEncrypt,
125   };
126
127
128 /* The list of commands and options.  */
129 static ARGPARSE_OPTS opts[] =
130   {
131     { 301, NULL, 0, N_("@\nCommands:\n ") },
132
133     { oDecrypt, "decrypt", 0, N_("decryption modus")},
134     { oEncrypt, "encrypt", 0, N_("encryption modus")},
135     
136     { 302, NULL, 0, N_("@\nOptions:\n ") },
137     
138     { oClass, "class", 2, N_("tool class (confucius)")},
139     { oProgram, "program", 2, N_("program filename")},
140
141     { oKeyfile, "keyfile", 2, N_("secret key file (required)")},
142
143     { oVerbose, "verbose",  0, N_("verbose") },
144     { oQuiet, "quiet",      0, N_("quiet") },
145     { oLogFile, "log-file", 2, N_("use a log file for the server")},
146
147     /* Hidden options.  */
148     { oNoVerbose, "no-verbose",  0, "@"},
149     { oHomedir, "homedir", 2, "@" },   
150
151     {0}
152   };
153
154
155 /* We keep all global options in the structure OPT.  */
156 struct
157 {
158   int verbose;          /* Verbosity level.  */
159   int quiet;            /* Be extra quiet.  */
160   const char *homedir;  /* Configuration directory name */
161
162   char *class;
163   char *program;
164   char *keyfile;
165 } opt;
166
167 \f
168 /* Print usage information and and provide strings for help.  */
169 static const char *
170 my_strusage (int level)
171 {
172   const char *p;
173
174   switch (level)
175     {
176     case 11: p = "symcryptrun (GnuPG)";
177       break;
178     case 13: p = VERSION; break;
179     case 17: p = PRINTABLE_OS_NAME; break;
180     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
181       break;
182     case 1:
183     case 40: p = _("Usage: symcryptrun [options] (-h for help)");
184       break;
185     case 41:
186       p = _("Syntax: symcryptrun --class CLASS --program PROGRAM "
187             "--keyfile KEYFILE [options...] COMMAND\n"
188             "Call a simple symmetric encryption tool\n");
189       break;
190     case 31: p = "\nHome: "; break;
191     case 32: p = opt.homedir; break;
192     case 33: p = "\n"; break;
193
194     default: p = NULL; break;
195     }
196   return p;
197 }
198
199
200 /* Initialize the gettext system.  */
201 static void
202 i18n_init(void)
203 {
204 #ifdef USE_SIMPLE_GETTEXT
205   set_gettext_file (PACKAGE_GT);
206 #else
207 # ifdef ENABLE_NLS
208   setlocale (LC_ALL, "");
209   bindtextdomain (PACKAGE_GT, LOCALEDIR);
210   textdomain (PACKAGE_GT);
211 # endif
212 #endif
213 }
214
215 \f
216 /* Class Confucius.
217
218    "Don't worry that other people don't know you;
219    worry that you don't know other people."            Analects--1.16.  */
220
221 /* Create temporary directory with mode 0700.  Returns a dynamically
222    allocated string with the filename of the directory.  */
223 static char *
224 confucius_mktmpdir (void)
225 {
226   int res;
227   char *tmpdir;
228
229   tmpdir = tmpnam (NULL);
230   if (!tmpdir)
231     {
232       log_error (_("cannot create temporary directory name: %s\n"),
233                  strerror (errno));
234       return NULL;
235     }
236   tmpdir = strdup (tmpdir);
237   if (!tmpdir)
238     {
239       log_error (_("cannot copy temporary directory name: %s\n"),
240                  strerror (errno));
241       return NULL;
242     }
243   res = mkdir (tmpdir, 0700);
244   if (res < 0)
245     {
246       log_error (_("cannot create temporary directory %s: %s\n"),
247                  tmpdir, strerror (errno));
248       return NULL;
249     }
250
251   return tmpdir;
252 }
253
254
255 /* Buffer size for I/O operations.  */
256 #define CONFUCIUS_BUFSIZE 4096
257
258 /* Buffer size for output lines.  */
259 #define CONFUCIUS_LINESIZE 4096
260
261
262 /* Copy the file IN to OUT, either of which may be "-".  */
263 static int
264 confucius_copy_file (const char *infile, const char *outfile)
265 {
266   FILE *in;
267   int in_is_stdin = 0;
268   FILE *out;
269   int out_is_stdout = 0;
270   char data[CONFUCIUS_BUFSIZE];
271   ssize_t data_len;
272
273   if (infile[0] == '-' && infile[1] == '\0')
274     {
275       /* FIXME: Is stdin in binary mode?  */
276       in = stdin;
277       in_is_stdin = 1;
278     }
279   else
280     {
281       in = fopen (infile, "rb");
282       if (!in)
283         {
284           log_error (_("could not open %s for writing: %s\n"),
285                      infile, strerror (errno));
286           return 1;
287         }
288     }
289
290   if (outfile[0] == '-' && outfile[1] == '\0')
291     {
292       /* FIXME: Is stdout in binary mode?  */
293       out = stdout;
294       out_is_stdout = 1;
295     }
296   else
297     {
298       out = fopen (outfile, "wb");
299       if (!out)
300         {
301           log_error (_("could not open %s for writing: %s\n"),
302                      infile, strerror (errno));
303           return 1;
304         }
305     }
306
307   /* Now copy the data.  */
308   while ((data_len = fread (data, 1, sizeof (data), in)) > 0)
309     {
310       if (fwrite (data, 1, data_len, out) != data_len)
311         {
312           log_error (_("error writing to %s: %s\n"), outfile,
313                      strerror (errno));
314           goto copy_err;
315         }
316     }
317   if (data_len < 0 || ferror (in))
318     {
319       log_error (_("error reading from %s: %s\n"), infile, strerror (errno));
320       goto copy_err;
321     }
322
323   /* Close IN if appropriate.  */
324   if (!in_is_stdin && fclose (in) && ferror (in))
325     {
326       log_error (_("error closing %s: %s\n"), infile, strerror (errno));
327       goto copy_err;
328     }
329
330   /* Close OUT if appropriate.  */
331   if (!out_is_stdout && fclose (out) && ferror (out))
332     {
333       log_error (_("error closing %s: %s\n"), infile, strerror (errno));
334       goto copy_err;
335     }
336
337   return 0;
338
339  copy_err:
340   if (!out_is_stdout)
341     unlink (outfile);
342   return 1;
343 }
344
345
346 /* Get a passphrase in secure storage (if possible).  If AGAIN is
347    true, then this is a repeated attempt.  If CANCELED is not a null
348    pointer, it will be set to true or false, depending on if the user
349    canceled the operation or not.  On error (including cancelation), a
350    null pointer is returned.  The passphrase must be deallocated with
351    confucius_drop_pass.  */
352 char *
353 confucius_get_pass (int again, int *canceled)
354 {
355   int err;
356   char *pw;
357 #ifdef HAVE_LANGINFO_CODESET
358   char *orig_codeset = NULL;
359 #endif
360
361   if (canceled)
362     *canceled = 0;
363   
364 #ifdef ENABLE_NLS
365   /* The Assuan agent protocol requires us to transmit utf-8 strings */
366   orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
367 #ifdef HAVE_LANGINFO_CODESET
368   if (!orig_codeset)
369     orig_codeset = nl_langinfo (CODESET);
370 #endif
371   if (orig_codeset && !strcmp (orig_codeset, "UTF-8"))
372     orig_codeset = NULL;
373   if (orig_codeset)
374     {
375       /* We only switch when we are able to restore the codeset later. */
376       orig_codeset = xstrdup (orig_codeset);
377       if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
378         orig_codeset = NULL; 
379     }
380 #endif
381
382   pw = simple_pwquery (NULL,
383                        again ? _("does not match - try again"):NULL,
384                        _("Passphrase:"), NULL, &err);
385
386 #ifdef ENABLE_NLS
387   if (orig_codeset)
388     {
389       bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
390       xfree (orig_codeset);
391     }
392 #endif
393
394   if (!pw)
395     {
396       if (err)
397         log_error (_("error while asking for the passphrase: %s\n"),
398                    gpg_strerror (err));
399       else
400         {
401           log_info (_("cancelled\n"));
402           if (canceled)
403             *canceled = 1;
404         }      
405     }
406
407   return pw;
408 }
409
410
411 /* Drop a passphrase retrieved with confucius_get_pass.  */
412 void
413 confucius_drop_pass (char *pass)
414 {
415   if (pass)
416     spwq_secure_free (pass);
417 }
418
419
420 /* Run a confucius crypto engine.  If MODE is oEncrypt, encryption is
421    requested.  If it is oDecrypt, decryption is requested.  INFILE and
422    OUTFILE are the temporary files used in the process.  */
423 int
424 confucius_process (int mode, char *infile, char *outfile)
425 {
426   char *const args[] = { opt.program,
427                          mode == oEncrypt ? "-m1" : "-m2",
428                          "-q", infile,
429                          "-z", outfile,
430                          "-s", opt.keyfile,
431                          mode == oEncrypt ? "-af" : "-f",
432                          NULL };
433   int cstderr[2];
434   int master;
435   int slave;
436   int res;
437   pid_t pid;
438   pid_t wpid;
439   int tries = 0;
440
441   signal (SIGPIPE, SIG_IGN);
442
443   if (!opt.program)
444     {
445       log_error (_("no --program option provided\n"));
446       return 1;
447     }
448
449   if (mode != oDecrypt && mode != oEncrypt)
450     {
451       log_error (_("only --decrypt and --encrypt are supported\n"));
452       return 1;
453     }
454
455   if (!opt.keyfile)
456     {
457       log_error (_("no --keyfile option provided\n"));
458       return 1;
459     }
460
461   if (pipe (cstderr) < 0)
462     {
463       log_error (_("could not create pipe: %s\n"), strerror (errno));
464       return 1;
465     }
466
467   if (openpty (&master, &slave, NULL, NULL, NULL) == -1)
468     {
469       log_error (_("could not create pty: %s\n"), strerror (errno));
470       close (cstderr[0]);
471       close (cstderr[1]);
472       return -1;
473     }
474
475   /* We don't want to deal with the worst case scenarios.  */
476   assert (master > 2);
477   assert (slave > 2);
478   assert (cstderr[0] > 2);
479   assert (cstderr[1] > 2);
480
481   pid = fork ();
482   if (pid < 0)
483     {
484       log_error (_("could not fork: %s\n"), strerror (errno));
485       close (master);
486       close (slave);
487       close (cstderr[0]);
488       close (cstderr[1]);
489       return 1;
490     }
491   else if (pid == 0) 
492     {
493       /* Child.  */
494
495       /* Close the parent ends.  */
496       close (master);
497       close (cstderr[0]);
498
499       /* Change controlling terminal.  */
500       if (login_tty (slave))
501         {
502           /* It's too early to output a debug message.  */
503           _exit (1);
504         }
505
506       dup2 (cstderr[1], 2);
507       close (cstderr[1]);
508
509       /* Now kick off the engine program.  */
510       execv (opt.program, args);
511       log_error (_("execv failed: %s\n"), strerror (errno));
512       _exit (1);
513     }
514   else
515     {
516       /* Parent.  */
517       char buffer[CONFUCIUS_LINESIZE];
518       int buffer_len = 0;
519       fd_set fds;
520       int slave_closed = 0;
521       int stderr_closed = 0;
522
523       close (slave);
524       close (cstderr[1]);
525
526       /* Listen on the output FDs.  */
527       do
528         {
529           FD_ZERO (&fds);
530
531           if (!slave_closed)
532             FD_SET (master, &fds);
533           if (!stderr_closed)
534             FD_SET (cstderr[0], &fds);
535
536           res = select (FD_SETSIZE, &fds, NULL, NULL, NULL);
537           if (res < 0)
538             {
539               log_error (_("select failed: %s\n"), strerror (errno));
540
541               kill (pid, SIGTERM);
542               close (master);
543               close (cstderr[0]);
544               return 1;
545             }
546
547           if (FD_ISSET (cstderr[0], &fds))
548             {
549               /* We got some output on stderr.  This is just passed
550                  through via the logging facility.  */
551
552               res = read (cstderr[0], &buffer[buffer_len],
553                           sizeof (buffer) - buffer_len - 1);
554               if (res < 0)
555                 {
556                   log_error (_("read failed: %s\n"), strerror (errno));
557
558                   kill (pid, SIGTERM);
559                   close (master);
560                   close (cstderr[0]);
561                   return 1;
562                 }
563               else  
564                 {
565                   char *newline;
566
567                   buffer_len += res;
568                   for (;;)
569                     {
570                       buffer[buffer_len] = '\0';
571                       newline = strchr (buffer, '\n');
572                       if (newline)
573                         {
574                           *newline = '\0';
575                           log_error ("%s\n", buffer);
576                           buffer_len -= newline + 1 - buffer;
577                           memmove (buffer, newline + 1, buffer_len);
578                         }
579                       else if (buffer_len == sizeof (buffer) - 1)
580                         {
581                           /* Overflow.  */
582                           log_error ("%s\n", buffer);
583                           buffer_len = 0;
584                         }
585                       else
586                         break;
587                     }
588
589                   if (res == 0)
590                     stderr_closed = 1;
591                 }
592             }
593           else if (FD_ISSET (master, &fds))
594             {
595               char data[512];
596
597               res = read (master, data, sizeof (data));
598               if (res < 0)
599                 {
600                   if (errno == EIO)
601                     {
602                       /* Slave-side close leads to readable fd and
603                          EIO.  */
604                       slave_closed = 1;
605                     }
606                   else
607                     {
608                       log_error (_("pty read failed: %s\n"), strerror (errno));
609
610                       kill (pid, SIGTERM);
611                       close (master);
612                       close (cstderr[0]);
613                       return 1;
614                     }
615                 }
616               else if (res == 0)
617                 /* This never seems to be what happens on slave-side
618                    close.  */
619                 slave_closed = 1;
620               else
621                 {
622                   /* Check for password prompt.  */
623                   if (data[res - 1] == ':')
624                     {
625                       char *pass;
626                       int canceled;
627
628                       pass = confucius_get_pass (tries ? 1 : 0, &canceled);
629                       if (!pass)
630                         {
631                           kill (pid, SIGTERM);
632                           close (master);
633                           close (cstderr[0]);
634                           return canceled ? 3 : 1;
635                         }
636                       write (master, pass, strlen (pass));
637                       write (master, "\n", 1);
638                       confucius_drop_pass (pass);
639
640                       tries++;
641                     }
642                 }
643             }
644         }
645       while (!stderr_closed || !slave_closed);
646
647       close (master);
648       close (cstderr[0]);
649
650       wpid = waitpid (pid, &res, 0);
651       if (wpid < 0)
652         {
653           log_error (_("waitpid failed: %s\n"), strerror (errno));
654
655           kill (pid, SIGTERM);
656           return 1;
657         }
658       else
659         {
660           /* Shouldn't happen, as we don't use WNOHANG.  */
661           assert (wpid != 0);
662
663           if (!WIFEXITED (res))
664             {
665               log_error (_("child aborted with status %i\n"), res);
666               return 1;
667             }
668
669           if (WEXITSTATUS (res))
670             {
671               /* We probably exceeded our number of attempts at guessing
672                  the password.  */
673               if (tries >= 3)
674                 return 2;
675               else
676                 return 1;
677             }
678
679           return 0;
680         }
681     }
682
683   /* Not reached.  */
684 }
685
686
687 /* Class confucius main program.  If MODE is oEncrypt, encryption is
688    requested.  If it is oDecrypt, decryption is requested.  The other
689    parameters are taken from the global option data.  */
690 int
691 confucius_main (int mode)
692 {
693   int res;
694   char *tmpdir;
695   char *infile;
696   char *outfile;
697
698   tmpdir = confucius_mktmpdir ();
699   if (!tmpdir)
700     return 1;
701
702   /* TMPDIR + "/" + "in" + "\0".  */
703   infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
704   if (!infile)
705     {
706       log_error (_("cannot allocate infile string: %s\n"), strerror (errno));
707       rmdir (tmpdir);
708       return 1;
709     }
710   strcpy (infile, tmpdir);
711   strcat (infile, "/in");
712
713   /* TMPDIR + "/" + "out" + "\0".  */
714   outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
715   if (!outfile)
716     {
717       log_error (_("cannot allocate outfile string: %s\n"), strerror (errno));
718       free (infile);
719       rmdir (tmpdir);
720       return 1;
721     }
722   strcpy (outfile, tmpdir);
723   strcat (outfile, "/out");
724
725   /* Create INFILE and fill it with content.  */
726   res = confucius_copy_file ("-", infile);
727   if (res)
728     {
729       free (outfile);
730       free (infile);
731       rmdir (tmpdir);
732       return res;
733     }
734
735   /* Run the engine and thus create the output file, handling
736      passphrase retrieval.  */
737   res = confucius_process (mode, infile, outfile);
738   if (res)
739     {
740       unlink (outfile);
741       unlink (infile);
742       free (outfile);
743       free (infile);
744       rmdir (tmpdir);
745       return res;
746     }
747
748   /* Dump the output file to stdout.  */
749   res = confucius_copy_file (outfile, "-");
750   if (res)
751     {
752       unlink (outfile);
753       unlink (infile);
754       free (outfile);
755       free (infile);
756       rmdir (tmpdir);
757       return res;
758     }
759   
760   unlink (outfile);
761   unlink (infile);
762   free (outfile);
763   free (infile);
764   rmdir (tmpdir);
765   return 0;
766 }
767
768 \f
769 /* symcryptrun's entry point.  */
770 int
771 main (int argc, char **argv)
772 {
773   ARGPARSE_ARGS pargs;
774   int no_more_options = 0;
775   int mode = 0;
776   int res;
777   char *logfile = NULL;
778
779   set_strusage (my_strusage);
780   log_set_prefix ("symcryptrun", 1);
781
782   /* Try to auto set the character set.  */
783   set_native_charset (NULL); 
784
785   i18n_init();
786
787   opt.homedir = default_homedir ();
788
789   /* Parse the command line. */
790   pargs.argc  = &argc;
791   pargs.argv  = &argv;
792   pargs.flags =  1;  /* Do not remove the args.  */
793   while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts))
794     {
795       switch (pargs.r_opt)
796         {
797         case oDecrypt:   mode = oDecrypt; break;
798         case oEncrypt:   mode = oEncrypt; break;
799
800         case oQuiet:     opt.quiet = 1; break;
801         case oVerbose:   opt.verbose++; break;
802         case oNoVerbose: opt.verbose = 0; break;
803         case oHomedir:   opt.homedir = pargs.r.ret_str; break;
804           
805         case oClass:    opt.class = pargs.r.ret_str; break;
806         case oProgram:  opt.program = pargs.r.ret_str; break;
807         case oKeyfile:  opt.keyfile = pargs.r.ret_str; break;
808
809         case oLogFile:  logfile = pargs.r.ret_str; break;
810
811         default: pargs.err = 2; break;
812         }
813     }
814
815   if (!mode)
816     log_error (_("either %s or %s must be given\n"),
817                "--decrypt", "--encrypt");
818
819   if (log_get_errorcount (0))
820     exit (1);
821
822   if (logfile)
823     log_set_file (logfile);
824
825   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
826   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
827     {
828       log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
829                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
830     }
831   gcry_set_log_handler (my_gcry_logger, NULL);
832   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
833
834   if (!opt.class)
835     {
836       log_error (_("no class provided\n"));
837       res = 1;
838     }
839   else if (!strcmp (opt.class, "confucius"))
840     res = confucius_main (mode);
841   else
842     {
843       log_error (_("class %s is not supported\n"), opt.class);
844       res = 1;
845     }
846
847   return res;
848 }