Cleaned up unused gpgsm and gpg options.
[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   char *orig_codeset;
428
429   if (canceled)
430     *canceled = 0;
431   
432   orig_codeset = i18n_switchto_utf8 ();
433   pw = simple_pwquery (cacheid,
434                        again ? _("does not match - try again"):NULL,
435                        _("Passphrase:"), NULL, 0, &err);
436   err = map_spwq_error (err);
437   i18n_switchback (orig_codeset);
438
439   if (!pw)
440     {
441       if (err)
442         log_error (_("error while asking for the passphrase: %s\n"),
443                    gpg_strerror (err));
444       else
445         {
446           log_info (_("cancelled\n"));
447           if (canceled)
448             *canceled = 1;
449         }      
450     }
451
452   return pw;
453 }
454
455
456 /* Drop a passphrase retrieved with confucius_get_pass.  */
457 void
458 confucius_drop_pass (char *pass)
459 {
460   if (pass)
461     spwq_secure_free (pass);
462 }
463
464
465 /* Run a confucius crypto engine.  If MODE is oEncrypt, encryption is
466    requested.  If it is oDecrypt, decryption is requested.  INFILE and
467    OUTFILE are the temporary files used in the process.  */
468 int
469 confucius_process (int mode, char *infile, char *outfile,
470                    int argc, char *argv[])
471 {
472   char **args;
473   int cstderr[2];
474   int master;
475   int slave;
476   int res;
477   pid_t pid;
478   pid_t wpid;
479   int tries = 0;
480   char cacheid[40];
481
482   signal (SIGPIPE, SIG_IGN);
483
484   if (!opt.program)
485     {
486       log_error (_("no --program option provided\n"));
487       return 1;
488     }
489
490   if (mode != oDecrypt && mode != oEncrypt)
491     {
492       log_error (_("only --decrypt and --encrypt are supported\n"));
493       return 1;
494     }
495
496   if (!opt.keyfile)
497     {
498       log_error (_("no --keyfile option provided\n"));
499       return 1;
500     }
501
502   /* Generate a hash from the keyfile name for caching.  */
503   snprintf (cacheid, sizeof (cacheid), "confucius:%lu",
504             hash_string (opt.keyfile));
505   cacheid[sizeof (cacheid) - 1] = '\0';
506   args = malloc (sizeof (char *) * (10 + argc));
507   if (!args)
508     {
509       log_error (_("cannot allocate args vector\n"));
510       return 1;
511     }
512   args[0] = opt.program;
513   args[1] = (mode == oEncrypt) ? "-m1" : "-m2";
514   args[2] = "-q";
515   args[3] = infile;
516   args[4] = "-z";
517   args[5] = outfile;
518   args[6] = "-s";
519   args[7] = opt.keyfile;
520   args[8] = (mode == oEncrypt) ? "-af" : "-f";
521   args[9 + argc] = NULL;
522   while (argc--)
523     args[9 + argc] = argv[argc];
524
525   if (pipe (cstderr) < 0)
526     {
527       log_error (_("could not create pipe: %s\n"), strerror (errno));
528       free (args);
529       return 1;
530     }
531
532   if (openpty (&master, &slave, NULL, NULL, NULL) == -1)
533     {
534       log_error (_("could not create pty: %s\n"), strerror (errno));
535       close (cstderr[0]);
536       close (cstderr[1]);
537       free (args);
538       return -1;
539     }
540
541   /* We don't want to deal with the worst case scenarios.  */
542   assert (master > 2);
543   assert (slave > 2);
544   assert (cstderr[0] > 2);
545   assert (cstderr[1] > 2);
546
547   pid = fork ();
548   if (pid < 0)
549     {
550       log_error (_("could not fork: %s\n"), strerror (errno));
551       close (master);
552       close (slave);
553       close (cstderr[0]);
554       close (cstderr[1]);
555       free (args);
556       return 1;
557     }
558   else if (pid == 0) 
559     {
560       /* Child.  */
561
562       /* Close the parent ends.  */
563       close (master);
564       close (cstderr[0]);
565
566       /* Change controlling terminal.  */
567       if (login_tty (slave))
568         {
569           /* It's too early to output a debug message.  */
570           _exit (1);
571         }
572
573       dup2 (cstderr[1], 2);
574       close (cstderr[1]);
575
576       /* Now kick off the engine program.  */
577       execv (opt.program, args);
578       log_error (_("execv failed: %s\n"), strerror (errno));
579       _exit (1);
580     }
581   else
582     {
583       /* Parent.  */
584       char buffer[CONFUCIUS_LINESIZE];
585       int buffer_len = 0;
586       fd_set fds;
587       int slave_closed = 0;
588       int stderr_closed = 0;
589
590       close (slave);
591       close (cstderr[1]);
592       free (args);
593
594       /* Listen on the output FDs.  */
595       do
596         {
597           FD_ZERO (&fds);
598
599           if (!slave_closed)
600             FD_SET (master, &fds);
601           if (!stderr_closed)
602             FD_SET (cstderr[0], &fds);
603
604           res = select (FD_SETSIZE, &fds, NULL, NULL, NULL);
605           if (res < 0)
606             {
607               log_error (_("select failed: %s\n"), strerror (errno));
608
609               kill (pid, SIGTERM);
610               close (master);
611               close (cstderr[0]);
612               return 1;
613             }
614
615           if (FD_ISSET (cstderr[0], &fds))
616             {
617               /* We got some output on stderr.  This is just passed
618                  through via the logging facility.  */
619
620               res = read (cstderr[0], &buffer[buffer_len],
621                           sizeof (buffer) - buffer_len - 1);
622               if (res < 0)
623                 {
624                   log_error (_("read failed: %s\n"), strerror (errno));
625
626                   kill (pid, SIGTERM);
627                   close (master);
628                   close (cstderr[0]);
629                   return 1;
630                 }
631               else  
632                 {
633                   char *newline;
634
635                   buffer_len += res;
636                   for (;;)
637                     {
638                       buffer[buffer_len] = '\0';
639                       newline = strchr (buffer, '\n');
640                       if (newline)
641                         {
642                           *newline = '\0';
643                           log_error ("%s\n", buffer);
644                           buffer_len -= newline + 1 - buffer;
645                           memmove (buffer, newline + 1, buffer_len);
646                         }
647                       else if (buffer_len == sizeof (buffer) - 1)
648                         {
649                           /* Overflow.  */
650                           log_error ("%s\n", buffer);
651                           buffer_len = 0;
652                         }
653                       else
654                         break;
655                     }
656
657                   if (res == 0)
658                     stderr_closed = 1;
659                 }
660             }
661           else if (FD_ISSET (master, &fds))
662             {
663               char data[512];
664
665               res = read (master, data, sizeof (data));
666               if (res < 0)
667                 {
668                   if (errno == EIO)
669                     {
670                       /* Slave-side close leads to readable fd and
671                          EIO.  */
672                       slave_closed = 1;
673                     }
674                   else
675                     {
676                       log_error (_("pty read failed: %s\n"), strerror (errno));
677
678                       kill (pid, SIGTERM);
679                       close (master);
680                       close (cstderr[0]);
681                       return 1;
682                     }
683                 }
684               else if (res == 0)
685                 /* This never seems to be what happens on slave-side
686                    close.  */
687                 slave_closed = 1;
688               else
689                 {
690                   /* Check for password prompt.  */
691                   if (data[res - 1] == ':')
692                     {
693                       char *pass;
694                       int canceled;
695
696                       /* If this is not the first attempt, the
697                          passphrase seems to be wrong, so clear the
698                          cache.  */
699                       if (tries)
700                         simple_pwclear (cacheid);
701
702                       pass = confucius_get_pass (cacheid,
703                                                  tries ? 1 : 0, &canceled);
704                       if (!pass)
705                         {
706                           kill (pid, SIGTERM);
707                           close (master);
708                           close (cstderr[0]);
709                           return canceled ? SYMC_CANCELED : 1;
710                         }
711                       write (master, pass, strlen (pass));
712                       write (master, "\n", 1);
713                       confucius_drop_pass (pass);
714
715                       tries++;
716                     }
717                 }
718             }
719         }
720       while (!stderr_closed || !slave_closed);
721
722       close (master);
723       close (cstderr[0]);
724
725       wpid = waitpid (pid, &res, 0);
726       if (wpid < 0)
727         {
728           log_error (_("waitpid failed: %s\n"), strerror (errno));
729
730           kill (pid, SIGTERM);
731           /* State of cached password is unclear.  Just remove it.  */
732           simple_pwclear (cacheid);
733           return 1;
734         }
735       else
736         {
737           /* Shouldn't happen, as we don't use WNOHANG.  */
738           assert (wpid != 0);
739
740           if (!WIFEXITED (res))
741             {
742               log_error (_("child aborted with status %i\n"), res);
743
744               /* State of cached password is unclear.  Just remove it.  */
745               simple_pwclear (cacheid);
746
747               return 1;
748             }
749
750           if (WEXITSTATUS (res))
751             {
752               /* The passphrase was wrong.  Remove it from the cache.  */
753               simple_pwclear (cacheid);
754
755               /* We probably exceeded our number of attempts at guessing
756                  the password.  */
757               if (tries >= 3)
758                 return SYMC_BAD_PASSPHRASE;
759               else
760                 return 1;
761             }
762
763           return 0;
764         }
765     }
766
767   /* Not reached.  */
768 }
769
770
771 /* Class confucius main program.  If MODE is oEncrypt, encryption is
772    requested.  If it is oDecrypt, decryption is requested.  The other
773    parameters are taken from the global option data.  */
774 int
775 confucius_main (int mode, int argc, char *argv[])
776 {
777   int res;
778   char *tmpdir;
779   char *infile;
780   int infile_from_stdin = 0;
781   char *outfile;
782
783   tmpdir = confucius_mktmpdir ();
784   if (!tmpdir)
785     return 1;
786
787   if (opt.input && !(opt.input[0] == '-' && opt.input[1] == '\0'))
788     infile = xstrdup (opt.input);
789   else
790     {
791       infile_from_stdin = 1;
792
793       /* TMPDIR + "/" + "in" + "\0".  */
794       infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
795       if (!infile)
796         {
797           log_error (_("cannot allocate infile string: %s\n"),
798                      strerror (errno));
799           rmdir (tmpdir);
800           return 1;
801         }
802       strcpy (infile, tmpdir);
803       strcat (infile, "/in");
804     }
805
806   /* TMPDIR + "/" + "out" + "\0".  */
807   outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
808   if (!outfile)
809     {
810       log_error (_("cannot allocate outfile string: %s\n"), strerror (errno));
811       free (infile);
812       rmdir (tmpdir);
813       return 1;
814     }
815   strcpy (outfile, tmpdir);
816   strcat (outfile, "/out");
817
818   if (infile_from_stdin)
819     {
820       /* Create INFILE and fill it with content.  */
821       res = confucius_copy_file ("-", infile, mode == oEncrypt);
822       if (res)
823         {
824           free (outfile);
825           free (infile);
826           rmdir (tmpdir);
827           return res;
828         }
829     }
830
831   /* Run the engine and thus create the output file, handling
832      passphrase retrieval.  */
833   res = confucius_process (mode, infile, outfile, argc, argv);
834   if (res)
835     {
836       remove_file (outfile, mode == oDecrypt);
837       if (infile_from_stdin)
838         remove_file (infile, mode == oEncrypt);
839       free (outfile);
840       free (infile);
841       rmdir (tmpdir);
842       return res;
843     }
844
845   /* Dump the output file to stdout.  */
846   res = confucius_copy_file (outfile, "-", mode == oDecrypt);
847   if (res)
848     {
849       remove_file (outfile, mode == oDecrypt);
850       if (infile_from_stdin)
851         remove_file (infile, mode == oEncrypt);
852       free (outfile);
853       free (infile);
854       rmdir (tmpdir);
855       return res;
856     }
857   
858   remove_file (outfile, mode == oDecrypt);
859   if (infile_from_stdin)
860     remove_file (infile, mode == oEncrypt);
861   free (outfile);
862   free (infile);
863   rmdir (tmpdir);
864   return 0;
865 }
866
867 \f
868 /* symcryptrun's entry point.  */
869 int
870 main (int argc, char **argv)
871 {
872   ARGPARSE_ARGS pargs;
873   int orig_argc;
874   char **orig_argv;
875   FILE *configfp = NULL;
876   char *configname = NULL;
877   unsigned configlineno; 
878   int mode = 0;
879   int res;
880   char *logfile = NULL;
881   int default_config = 1;
882
883   set_strusage (my_strusage);
884   log_set_prefix ("symcryptrun", 1);
885
886   /* Make sure that our subsystems are ready.  */
887   init_common_subsystems ();
888
889   i18n_init();
890
891   opt.homedir = default_homedir ();
892
893   /* Check whether we have a config file given on the commandline */
894   orig_argc = argc;
895   orig_argv = argv;
896   pargs.argc = &argc;
897   pargs.argv = &argv;
898   pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
899   while (arg_parse( &pargs, opts))
900     {
901       if (pargs.r_opt == oOptions)
902         { /* Yes there is one, so we do not try the default one, but
903              read the option file when it is encountered at the
904              commandline */
905           default_config = 0;
906         }
907       else if (pargs.r_opt == oNoOptions)
908         default_config = 0; /* --no-options */
909       else if (pargs.r_opt == oHomedir)
910         opt.homedir = pargs.r.ret_str;
911     }
912
913   if (default_config)
914     configname = make_filename (opt.homedir, "symcryptrun.conf", NULL );
915   
916   argc = orig_argc;
917   argv = orig_argv;
918   pargs.argc = &argc;
919   pargs.argv = &argv;
920   pargs.flags= 1;  /* do not remove the args */
921  next_pass:
922   if (configname)
923     {
924       configlineno = 0;
925       configfp = fopen (configname, "r");
926       if (!configfp)
927         {
928           if (!default_config)
929             {
930               log_error (_("option file `%s': %s\n"),
931                          configname, strerror(errno) );
932               exit(1);
933             }
934           xfree (configname); 
935           configname = NULL;
936         }
937       default_config = 0;
938     }
939
940   /* Parse the command line. */
941   while (optfile_parse (configfp, configname, &configlineno, &pargs, opts))
942     {
943       switch (pargs.r_opt)
944         {
945         case oDecrypt:   mode = oDecrypt; break;
946         case oEncrypt:   mode = oEncrypt; break;
947
948         case oQuiet:     opt.quiet = 1; break;
949         case oVerbose:   opt.verbose++; break;
950         case oNoVerbose: opt.verbose = 0; break;
951           
952         case oClass:    opt.class = pargs.r.ret_str; break;
953         case oProgram:  opt.program = pargs.r.ret_str; break;
954         case oKeyfile:  opt.keyfile = pargs.r.ret_str; break;
955         case oInput:    opt.input = pargs.r.ret_str; break;
956
957         case oLogFile:  logfile = pargs.r.ret_str; break;
958
959         case oOptions:
960           /* Config files may not be nested (silently ignore them) */
961           if (!configfp)
962             {
963                 xfree(configname);
964                 configname = xstrdup(pargs.r.ret_str);
965                 goto next_pass;
966             }
967           break;
968         case oNoOptions: break; /* no-options */
969         case oHomedir: /* Ignore this option here. */; break;
970
971         default : pargs.err = configfp? 1:2; break;
972         }
973     }
974   if (configfp)
975     {
976       fclose( configfp );
977       configfp = NULL;
978       configname = NULL;
979       goto next_pass;
980     }
981   xfree (configname);
982   configname = NULL;
983
984   if (!mode)
985     log_error (_("either %s or %s must be given\n"),
986                "--decrypt", "--encrypt");
987
988   if (log_get_errorcount (0))
989     exit (1);
990
991   if (logfile)
992     log_set_file (logfile);
993
994   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
995   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
996     {
997       log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
998                  NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
999     }
1000   setup_libgcrypt_logging ();
1001   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
1002
1003   /* Tell simple-pwquery about the the standard socket name.  */
1004   {
1005     char *tmp = make_filename (opt.homedir, "S.gpg-agent", NULL);
1006     simple_pw_set_socket (tmp);
1007     xfree (tmp);
1008   }
1009
1010   if (!opt.class)
1011     {
1012       log_error (_("no class provided\n"));
1013       res = 1;
1014     }
1015   else if (!strcmp (opt.class, "confucius"))
1016     {
1017       res = confucius_main (mode, argc, argv);
1018     }
1019   else
1020     {
1021       log_error (_("class %s is not supported\n"), opt.class);
1022       res = 1;
1023     }
1024
1025   return res;
1026 }