chiark / gitweb /
agent: Allow threads to interrupt main select loop with SIGCONT.
[gnupg2.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 <https://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 occurred
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 #ifdef HAVE_UTMP_H
78 #include <utmp.h>
79 #endif
80 #include <ctype.h>
81 #ifdef HAVE_LOCALE_H
82 #include <locale.h>
83 #endif
84 #ifdef HAVE_LANGINFO_CODESET
85 #include <langinfo.h>
86 #endif
87 #include <gpg-error.h>
88
89 #include "i18n.h"
90 #include "../common/util.h"
91 #include "../common/init.h"
92 #include "../common/sysutils.h"
93
94 /* FIXME: Bah.  For spwq_secure_free.  */
95 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
96 #include "../common/simple-pwquery.h"
97
98 \f
99 /* From simple-gettext.c.  */
100
101 /* We assume to have 'unsigned long int' value with at least 32 bits.  */
102 #define HASHWORDBITS 32
103
104 /* The so called 'hashpjw' function by P.J. Weinberger
105    [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
106    1986, 1987 Bell Telephone Laboratories, Inc.]  */
107
108 static __inline__ ulong
109 hash_string( const char *str_param )
110 {
111     unsigned long int hval, g;
112     const char *str = str_param;
113
114     hval = 0;
115     while (*str != '\0')
116     {
117         hval <<= 4;
118         hval += (unsigned long int) *str++;
119         g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
120         if (g != 0)
121         {
122           hval ^= g >> (HASHWORDBITS - 8);
123           hval ^= g;
124         }
125     }
126     return hval;
127 }
128
129 \f
130 /* Constants to identify the commands and options. */
131 enum cmd_and_opt_values
132   {
133     aNull = 0,
134     oQuiet      = 'q',
135     oVerbose    = 'v',
136
137     oNoVerbose  = 500,
138     oOptions,
139     oNoOptions,
140     oLogFile,
141     oHomedir,
142     oClass,
143     oProgram,
144     oKeyfile,
145     oDecrypt,
146     oEncrypt,
147     oInput
148   };
149
150
151 /* The list of commands and options.  */
152 static ARGPARSE_OPTS opts[] =
153   {
154     { 301, NULL, 0, N_("@\nCommands:\n ") },
155
156     { oDecrypt, "decrypt", 0, N_("decryption modus") },
157     { oEncrypt, "encrypt", 0, N_("encryption modus") },
158
159     { 302, NULL, 0, N_("@\nOptions:\n ") },
160
161     { oClass, "class", 2, N_("tool class (confucius)") },
162     { oProgram, "program", 2, N_("program filename") },
163
164     { oKeyfile, "keyfile", 2, N_("secret key file (required)") },
165     { oInput, "inputfile", 2, N_("input file name (default stdin)") },
166     { oVerbose, "verbose",  0, N_("verbose") },
167     { oQuiet, "quiet",      0, N_("quiet") },
168     { oLogFile, "log-file", 2, N_("use a log file for the server") },
169     { oOptions,  "options"  , 2, N_("|FILE|read options from FILE") },
170
171     /* Hidden options.  */
172     { oNoVerbose, "no-verbose",  0, "@" },
173     { oHomedir, "homedir", 2, "@" },
174     { oNoOptions, "no-options", 0, "@" },/* shortcut for --options /dev/null */
175
176     {0}
177   };
178
179
180 /* We keep all global options in the structure OPT.  */
181 struct
182 {
183   int verbose;          /* Verbosity level.  */
184   int quiet;            /* Be extra quiet.  */
185   const char *homedir;  /* Configuration directory name */
186
187   char *class;
188   char *program;
189   char *keyfile;
190   char *input;
191 } opt;
192
193 \f
194 /* Print usage information and and provide strings for help.  */
195 static const char *
196 my_strusage (int level)
197 {
198   const char *p;
199
200   switch (level)
201     {
202     case 11: p = "symcryptrun (@GNUPG@)";
203       break;
204     case 13: p = VERSION; break;
205     case 17: p = PRINTABLE_OS_NAME; break;
206     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
207
208     case 1:
209     case 40: p = _("Usage: symcryptrun [options] (-h for help)");
210       break;
211     case 41:
212       p = _("Syntax: symcryptrun --class CLASS --program PROGRAM "
213             "--keyfile KEYFILE [options...] COMMAND [inputfile]\n"
214             "Call a simple symmetric encryption tool\n");
215       break;
216     case 31: p = "\nHome: "; break;
217     case 32: p = gnupg_homedir (); break;
218     case 33: p = "\n"; break;
219
220     default: p = NULL; break;
221     }
222   return p;
223 }
224
225
226 \f
227 /* This is in the GNU C library in unistd.h.  */
228
229 #ifndef TEMP_FAILURE_RETRY
230 /* Evaluate EXPRESSION, and repeat as long as it returns -1 with 'errno'
231    set to EINTR.  */
232
233 # define TEMP_FAILURE_RETRY(expression) \
234   (__extension__                                                              \
235     ({ long int __result;                                                     \
236        do __result = (long int) (expression);                                 \
237        while (__result == -1L && errno == EINTR);                             \
238        __result; }))
239 #endif
240
241 /* Unlink a file, and shred it if SHRED is true.  */
242 int
243 remove_file (char *name, int shred)
244 {
245   if (!shred)
246     return unlink (name);
247   else
248     {
249       int status;
250       pid_t pid;
251
252       pid = fork ();
253       if (pid == 0)
254         {
255           /* Child.  */
256
257           /* -f forces file to be writable, and -u unlinks it afterwards.  */
258           char *args[] = { SHRED, "-uf", name, NULL };
259
260           execv (SHRED, args);
261           _exit (127);
262         }
263       else if (pid < 0)
264         {
265           /* Fork failed.  */
266           status = -1;
267         }
268       else
269         {
270           /* Parent.  */
271
272           if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
273             status = -1;
274         }
275
276       if (!WIFEXITED (status))
277         {
278           log_error (_("%s on %s aborted with status %i\n"),
279                      SHRED, name, status);
280           unlink (name);
281           return 1;
282         }
283       else if (WEXITSTATUS (status))
284         {
285           log_error (_("%s on %s failed with status %i\n"), SHRED, name,
286                      WEXITSTATUS (status));
287           unlink (name);
288           return 1;
289         }
290
291       return 0;
292     }
293 }
294
295 \f
296 /* Class Confucius.
297
298    "Don't worry that other people don't know you;
299    worry that you don't know other people."            Analects--1.16.  */
300
301 /* Create temporary directory with mode 0700.  Returns a dynamically
302    allocated string with the filename of the directory.  */
303 static char *
304 confucius_mktmpdir (void)
305 {
306   char *name, *p;
307
308   p = getenv ("TMPDIR");
309   if (!p || !*p)
310     p = "/tmp";
311   if (p[strlen (p) - 1] == '/')
312     name = xstrconcat (p, "gpg-XXXXXX", NULL);
313   else
314     name = xstrconcat (p, "/", "gpg-XXXXXX", NULL);
315   if (!name || !gnupg_mkdtemp (name))
316     {
317       log_error (_("can't create temporary directory '%s': %s\n"),
318                  name?name:"", strerror (errno));
319       return NULL;
320     }
321
322   return name;
323 }
324
325
326 /* Buffer size for I/O operations.  */
327 #define CONFUCIUS_BUFSIZE 4096
328
329 /* Buffer size for output lines.  */
330 #define CONFUCIUS_LINESIZE 4096
331
332
333 /* Copy the file IN to OUT, either of which may be "-".  If PLAIN is
334    true, and the copying fails, and OUT is not STDOUT, then shred the
335    file instead unlinking it.  */
336 static int
337 confucius_copy_file (char *infile, char *outfile, int plain)
338 {
339   FILE *in;
340   int in_is_stdin = 0;
341   FILE *out;
342   int out_is_stdout = 0;
343   char data[CONFUCIUS_BUFSIZE];
344   ssize_t data_len;
345
346   if (infile[0] == '-' && infile[1] == '\0')
347     {
348       /* FIXME: Is stdin in binary mode?  */
349       in = stdin;
350       in_is_stdin = 1;
351     }
352   else
353     {
354       in = fopen (infile, "rb");
355       if (!in)
356         {
357           log_error (_("could not open %s for writing: %s\n"),
358                      infile, strerror (errno));
359           return 1;
360         }
361     }
362
363   if (outfile[0] == '-' && outfile[1] == '\0')
364     {
365       /* FIXME: Is stdout in binary mode?  */
366       out = stdout;
367       out_is_stdout = 1;
368     }
369   else
370     {
371       out = fopen (outfile, "wb");
372       if (!out)
373         {
374           log_error (_("could not open %s for writing: %s\n"),
375                      infile, strerror (errno));
376           return 1;
377         }
378     }
379
380   /* Now copy the data.  */
381   while ((data_len = fread (data, 1, sizeof (data), in)) > 0)
382     {
383       if (fwrite (data, 1, data_len, out) != data_len)
384         {
385           log_error (_("error writing to %s: %s\n"), outfile,
386                      strerror (errno));
387           goto copy_err;
388         }
389     }
390   if (data_len < 0 || ferror (in))
391     {
392       log_error (_("error reading from %s: %s\n"), infile, strerror (errno));
393       goto copy_err;
394     }
395
396   /* Close IN if appropriate.  */
397   if (!in_is_stdin && fclose (in) && ferror (in))
398     {
399       log_error (_("error closing %s: %s\n"), infile, strerror (errno));
400       goto copy_err;
401     }
402
403   /* Close OUT if appropriate.  */
404   if (!out_is_stdout && fclose (out) && ferror (out))
405     {
406       log_error (_("error closing %s: %s\n"), infile, strerror (errno));
407       goto copy_err;
408     }
409
410   return 0;
411
412  copy_err:
413   if (!out_is_stdout)
414     remove_file (outfile, plain);
415
416   return 1;
417 }
418
419
420 /* Get a passphrase in secure storage (if possible).  If AGAIN is
421    true, then this is a repeated attempt.  If CANCELED is not a null
422    pointer, it will be set to true or false, depending on if the user
423    canceled the operation or not.  On error (including cancelation), a
424    null pointer is returned.  The passphrase must be deallocated with
425    confucius_drop_pass.  CACHEID is the ID to be used for passphrase
426    caching and can be NULL to disable caching.  */
427 char *
428 confucius_get_pass (const char *cacheid, int again, int *canceled)
429 {
430   int err;
431   char *pw;
432   char *orig_codeset;
433
434   if (canceled)
435     *canceled = 0;
436
437   orig_codeset = i18n_switchto_utf8 ();
438   pw = simple_pwquery (cacheid,
439                        again ? _("does not match - try again"):NULL,
440                        _("Passphrase:"), NULL, 0, &err);
441   i18n_switchback (orig_codeset);
442
443   if (!pw)
444     {
445       if (err)
446         log_error (_("error while asking for the passphrase: %s\n"),
447                    gpg_strerror (err));
448       else
449         {
450           log_info (_("cancelled\n"));
451           if (canceled)
452             *canceled = 1;
453         }
454     }
455
456   return pw;
457 }
458
459
460 /* Drop a passphrase retrieved with confucius_get_pass.  */
461 void
462 confucius_drop_pass (char *pass)
463 {
464   if (pass)
465     spwq_secure_free (pass);
466 }
467
468
469 /* Run a confucius crypto engine.  If MODE is oEncrypt, encryption is
470    requested.  If it is oDecrypt, decryption is requested.  INFILE and
471    OUTFILE are the temporary files used in the process.  */
472 int
473 confucius_process (int mode, char *infile, char *outfile,
474                    int argc, char *argv[])
475 {
476   char **args;
477   int cstderr[2];
478   int master;
479   int slave;
480   int res;
481   pid_t pid;
482   pid_t wpid;
483   int tries = 0;
484   char cacheid[40];
485
486   signal (SIGPIPE, SIG_IGN);
487
488   if (!opt.program)
489     {
490       log_error (_("no --program option provided\n"));
491       return 1;
492     }
493
494   if (mode != oDecrypt && mode != oEncrypt)
495     {
496       log_error (_("only --decrypt and --encrypt are supported\n"));
497       return 1;
498     }
499
500   if (!opt.keyfile)
501     {
502       log_error (_("no --keyfile option provided\n"));
503       return 1;
504     }
505
506   /* Generate a hash from the keyfile name for caching.  */
507   snprintf (cacheid, sizeof (cacheid), "confucius:%lu",
508             hash_string (opt.keyfile));
509   cacheid[sizeof (cacheid) - 1] = '\0';
510   args = malloc (sizeof (char *) * (10 + argc));
511   if (!args)
512     {
513       log_error (_("cannot allocate args vector\n"));
514       return 1;
515     }
516   args[0] = opt.program;
517   args[1] = (mode == oEncrypt) ? "-m1" : "-m2";
518   args[2] = "-q";
519   args[3] = infile;
520   args[4] = "-z";
521   args[5] = outfile;
522   args[6] = "-s";
523   args[7] = opt.keyfile;
524   args[8] = (mode == oEncrypt) ? "-af" : "-f";
525   args[9 + argc] = NULL;
526   while (argc--)
527     args[9 + argc] = argv[argc];
528
529   if (pipe (cstderr) < 0)
530     {
531       log_error (_("could not create pipe: %s\n"), strerror (errno));
532       free (args);
533       return 1;
534     }
535
536   if (openpty (&master, &slave, NULL, NULL, NULL) == -1)
537     {
538       log_error (_("could not create pty: %s\n"), strerror (errno));
539       close (cstderr[0]);
540       close (cstderr[1]);
541       free (args);
542       return -1;
543     }
544
545   /* We don't want to deal with the worst case scenarios.  */
546   assert (master > 2);
547   assert (slave > 2);
548   assert (cstderr[0] > 2);
549   assert (cstderr[1] > 2);
550
551   pid = fork ();
552   if (pid < 0)
553     {
554       log_error (_("could not fork: %s\n"), strerror (errno));
555       close (master);
556       close (slave);
557       close (cstderr[0]);
558       close (cstderr[1]);
559       free (args);
560       return 1;
561     }
562   else if (pid == 0)
563     {
564       /* Child.  */
565
566       /* Close the parent ends.  */
567       close (master);
568       close (cstderr[0]);
569
570       /* Change controlling terminal.  */
571       if (login_tty (slave))
572         {
573           /* It's too early to output a debug message.  */
574           _exit (1);
575         }
576
577       dup2 (cstderr[1], 2);
578       close (cstderr[1]);
579
580       /* Now kick off the engine program.  */
581       execv (opt.program, args);
582       log_error (_("execv failed: %s\n"), strerror (errno));
583       _exit (1);
584     }
585   else
586     {
587       /* Parent.  */
588       char buffer[CONFUCIUS_LINESIZE];
589       int buffer_len = 0;
590       fd_set fds;
591       int slave_closed = 0;
592       int stderr_closed = 0;
593
594       close (slave);
595       close (cstderr[1]);
596       free (args);
597
598       /* Listen on the output FDs.  */
599       do
600         {
601           FD_ZERO (&fds);
602
603           if (!slave_closed)
604             FD_SET (master, &fds);
605           if (!stderr_closed)
606             FD_SET (cstderr[0], &fds);
607
608           res = select (FD_SETSIZE, &fds, NULL, NULL, NULL);
609           if (res < 0)
610             {
611               log_error (_("select failed: %s\n"), strerror (errno));
612
613               kill (pid, SIGTERM);
614               close (master);
615               close (cstderr[0]);
616               return 1;
617             }
618
619           if (FD_ISSET (cstderr[0], &fds))
620             {
621               /* We got some output on stderr.  This is just passed
622                  through via the logging facility.  */
623
624               res = read (cstderr[0], &buffer[buffer_len],
625                           sizeof (buffer) - buffer_len - 1);
626               if (res < 0)
627                 {
628                   log_error (_("read failed: %s\n"), strerror (errno));
629
630                   kill (pid, SIGTERM);
631                   close (master);
632                   close (cstderr[0]);
633                   return 1;
634                 }
635               else
636                 {
637                   char *newline;
638
639                   buffer_len += res;
640                   for (;;)
641                     {
642                       buffer[buffer_len] = '\0';
643                       newline = strchr (buffer, '\n');
644                       if (newline)
645                         {
646                           *newline = '\0';
647                           log_error ("%s\n", buffer);
648                           buffer_len -= newline + 1 - buffer;
649                           memmove (buffer, newline + 1, buffer_len);
650                         }
651                       else if (buffer_len == sizeof (buffer) - 1)
652                         {
653                           /* Overflow.  */
654                           log_error ("%s\n", buffer);
655                           buffer_len = 0;
656                         }
657                       else
658                         break;
659                     }
660
661                   if (res == 0)
662                     stderr_closed = 1;
663                 }
664             }
665           else if (FD_ISSET (master, &fds))
666             {
667               char data[512];
668
669               res = read (master, data, sizeof (data));
670               if (res < 0)
671                 {
672                   if (errno == EIO)
673                     {
674                       /* Slave-side close leads to readable fd and
675                          EIO.  */
676                       slave_closed = 1;
677                     }
678                   else
679                     {
680                       log_error (_("pty read failed: %s\n"), strerror (errno));
681
682                       kill (pid, SIGTERM);
683                       close (master);
684                       close (cstderr[0]);
685                       return 1;
686                     }
687                 }
688               else if (res == 0)
689                 /* This never seems to be what happens on slave-side
690                    close.  */
691                 slave_closed = 1;
692               else
693                 {
694                   /* Check for password prompt.  */
695                   if (data[res - 1] == ':')
696                     {
697                       char *pass;
698                       int canceled;
699
700                       /* If this is not the first attempt, the
701                          passphrase seems to be wrong, so clear the
702                          cache.  */
703                       if (tries)
704                         simple_pwclear (cacheid);
705
706                       pass = confucius_get_pass (cacheid,
707                                                  tries ? 1 : 0, &canceled);
708                       if (!pass)
709                         {
710                           kill (pid, SIGTERM);
711                           close (master);
712                           close (cstderr[0]);
713                           return canceled ? SYMC_CANCELED : 1;
714                         }
715                       write (master, pass, strlen (pass));
716                       write (master, "\n", 1);
717                       confucius_drop_pass (pass);
718
719                       tries++;
720                     }
721                 }
722             }
723         }
724       while (!stderr_closed || !slave_closed);
725
726       close (master);
727       close (cstderr[0]);
728
729       wpid = waitpid (pid, &res, 0);
730       if (wpid < 0)
731         {
732           log_error (_("waitpid failed: %s\n"), strerror (errno));
733
734           kill (pid, SIGTERM);
735           /* State of cached password is unclear.  Just remove it.  */
736           simple_pwclear (cacheid);
737           return 1;
738         }
739       else
740         {
741           /* Shouldn't happen, as we don't use WNOHANG.  */
742           assert (wpid != 0);
743
744           if (!WIFEXITED (res))
745             {
746               log_error (_("child aborted with status %i\n"), res);
747
748               /* State of cached password is unclear.  Just remove it.  */
749               simple_pwclear (cacheid);
750
751               return 1;
752             }
753
754           if (WEXITSTATUS (res))
755             {
756               /* The passphrase was wrong.  Remove it from the cache.  */
757               simple_pwclear (cacheid);
758
759               /* We probably exceeded our number of attempts at guessing
760                  the password.  */
761               if (tries >= 3)
762                 return SYMC_BAD_PASSPHRASE;
763               else
764                 return 1;
765             }
766
767           return 0;
768         }
769     }
770
771   /* Not reached.  */
772 }
773
774
775 /* Class confucius main program.  If MODE is oEncrypt, encryption is
776    requested.  If it is oDecrypt, decryption is requested.  The other
777    parameters are taken from the global option data.  */
778 int
779 confucius_main (int mode, int argc, char *argv[])
780 {
781   int res;
782   char *tmpdir;
783   char *infile;
784   int infile_from_stdin = 0;
785   char *outfile;
786
787   tmpdir = confucius_mktmpdir ();
788   if (!tmpdir)
789     return 1;
790
791   if (opt.input && !(opt.input[0] == '-' && opt.input[1] == '\0'))
792     infile = xstrdup (opt.input);
793   else
794     {
795       infile_from_stdin = 1;
796
797       /* TMPDIR + "/" + "in" + "\0".  */
798       infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
799       if (!infile)
800         {
801           log_error (_("cannot allocate infile string: %s\n"),
802                      strerror (errno));
803           rmdir (tmpdir);
804           return 1;
805         }
806       strcpy (infile, tmpdir);
807       strcat (infile, "/in");
808     }
809
810   /* TMPDIR + "/" + "out" + "\0".  */
811   outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
812   if (!outfile)
813     {
814       log_error (_("cannot allocate outfile string: %s\n"), strerror (errno));
815       free (infile);
816       rmdir (tmpdir);
817       return 1;
818     }
819   strcpy (outfile, tmpdir);
820   strcat (outfile, "/out");
821
822   if (infile_from_stdin)
823     {
824       /* Create INFILE and fill it with content.  */
825       res = confucius_copy_file ("-", infile, mode == oEncrypt);
826       if (res)
827         {
828           free (outfile);
829           free (infile);
830           rmdir (tmpdir);
831           return res;
832         }
833     }
834
835   /* Run the engine and thus create the output file, handling
836      passphrase retrieval.  */
837   res = confucius_process (mode, infile, outfile, argc, argv);
838   if (res)
839     {
840       remove_file (outfile, mode == oDecrypt);
841       if (infile_from_stdin)
842         remove_file (infile, mode == oEncrypt);
843       free (outfile);
844       free (infile);
845       rmdir (tmpdir);
846       return res;
847     }
848
849   /* Dump the output file to stdout.  */
850   res = confucius_copy_file (outfile, "-", mode == oDecrypt);
851   if (res)
852     {
853       remove_file (outfile, mode == oDecrypt);
854       if (infile_from_stdin)
855         remove_file (infile, mode == oEncrypt);
856       free (outfile);
857       free (infile);
858       rmdir (tmpdir);
859       return res;
860     }
861
862   remove_file (outfile, mode == oDecrypt);
863   if (infile_from_stdin)
864     remove_file (infile, mode == oEncrypt);
865   free (outfile);
866   free (infile);
867   rmdir (tmpdir);
868   return 0;
869 }
870
871 \f
872 /* symcryptrun's entry point.  */
873 int
874 main (int argc, char **argv)
875 {
876   ARGPARSE_ARGS pargs;
877   int orig_argc;
878   char **orig_argv;
879   FILE *configfp = NULL;
880   char *configname = NULL;
881   unsigned configlineno;
882   int mode = 0;
883   int res;
884   char *logfile = NULL;
885   int default_config = 1;
886
887   early_system_init ();
888   set_strusage (my_strusage);
889   log_set_prefix ("symcryptrun", GPGRT_LOG_WITH_PREFIX);
890
891   /* Make sure that our subsystems are ready.  */
892   i18n_init();
893   init_common_subsystems (&argc, &argv);
894
895   /* Check whether we have a config file given on the commandline */
896   orig_argc = argc;
897   orig_argv = argv;
898   pargs.argc = &argc;
899   pargs.argv = &argv;
900   pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
901   while (arg_parse( &pargs, opts))
902     {
903       if (pargs.r_opt == oOptions)
904         { /* Yes there is one, so we do not try the default one, but
905              read the option file when it is encountered at the
906              commandline */
907           default_config = 0;
908         }
909       else if (pargs.r_opt == oNoOptions)
910         default_config = 0; /* --no-options */
911       else if (pargs.r_opt == oHomedir)
912         gnupg_set_homedir (pargs.r.ret_str);
913     }
914
915   if (default_config)
916     configname = make_filename (gnupg_homedir (), "symcryptrun.conf", NULL );
917
918   argc = orig_argc;
919   argv = orig_argv;
920   pargs.argc = &argc;
921   pargs.argv = &argv;
922   pargs.flags= 1;  /* do not remove the args */
923  next_pass:
924   if (configname)
925     {
926       configlineno = 0;
927       configfp = fopen (configname, "r");
928       if (!configfp)
929         {
930           if (!default_config)
931             {
932               log_error (_("option file '%s': %s\n"),
933                          configname, strerror(errno) );
934               exit(1);
935             }
936           xfree (configname);
937           configname = NULL;
938         }
939       default_config = 0;
940     }
941
942   /* Parse the command line. */
943   while (optfile_parse (configfp, configname, &configlineno, &pargs, opts))
944     {
945       switch (pargs.r_opt)
946         {
947         case oDecrypt:   mode = oDecrypt; break;
948         case oEncrypt:   mode = oEncrypt; break;
949
950         case oQuiet:     opt.quiet = 1; break;
951         case oVerbose:   opt.verbose++; break;
952         case oNoVerbose: opt.verbose = 0; break;
953
954         case oClass:    opt.class = pargs.r.ret_str; break;
955         case oProgram:  opt.program = pargs.r.ret_str; break;
956         case oKeyfile:  opt.keyfile = pargs.r.ret_str; break;
957         case oInput:    opt.input = pargs.r.ret_str; break;
958
959         case oLogFile:  logfile = pargs.r.ret_str; break;
960
961         case oOptions:
962           /* Config files may not be nested (silently ignore them) */
963           if (!configfp)
964             {
965                 xfree(configname);
966                 configname = xstrdup(pargs.r.ret_str);
967                 goto next_pass;
968             }
969           break;
970         case oNoOptions: break; /* no-options */
971         case oHomedir: /* Ignore this option here. */; break;
972
973         default : pargs.err = configfp? 1:2; break;
974         }
975     }
976   if (configfp)
977     {
978       fclose( configfp );
979       configfp = NULL;
980       configname = NULL;
981       goto next_pass;
982     }
983   xfree (configname);
984   configname = NULL;
985
986   if (!mode)
987     log_error (_("either %s or %s must be given\n"),
988                "--decrypt", "--encrypt");
989
990   if (log_get_errorcount (0))
991     exit (1);
992
993   if (logfile)
994     log_set_file (logfile);
995
996   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
997   setup_libgcrypt_logging ();
998   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
999
1000   /* Tell simple-pwquery about the the standard socket name.  */
1001   {
1002     char *tmp = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
1003     simple_pw_set_socket (tmp);
1004     xfree (tmp);
1005   }
1006
1007   if (!opt.class)
1008     {
1009       log_error (_("no class provided\n"));
1010       res = 1;
1011     }
1012   else if (!strcmp (opt.class, "confucius"))
1013     {
1014       res = confucius_main (mode, argc, argv);
1015     }
1016   else
1017     {
1018       log_error (_("class %s is not supported\n"), opt.class);
1019       res = 1;
1020     }
1021
1022   return res;
1023 }