2005-10-08 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / tools / symcryptrun.c
blob075e0b4444eddc0e66d5af637f506afff94c02c0
1 /* symcryptrun.c - Tool to call simple symmetric encryption tools.
2 * Copyright (C) 2005 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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
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. */
32 /* This program is invoked in the following way:
34 symcryptrun --class CLASS --program PROGRAM --keyfile KEYFILE \
35 [--decrypt | --encrypt]
37 For encryption, the plain text must be provided on STDIN, and the
38 ciphertext will be output to STDOUT. For decryption vice versa.
40 CLASS can currently only be "confucius".
42 PROGRAM must be the path to the crypto engine.
44 KEYFILE must contain the secret key, which may be protected by a
45 passphrase. The passphrase is retrieved via the pinentry program.
48 The GPG Agent _must_ be running before starting symcryptrun.
50 The possible exit status codes:
52 0 Success
53 1 Some error occured
54 2 No valid passphrase was provided
55 3 The operation was canceled by the user
57 Other classes may be added in the future. */
59 #define SYMC_BAD_PASSPHRASE 2
60 #define SYMC_CANCELED 3
63 #include <config.h>
65 #include <unistd.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <errno.h>
70 #include <assert.h>
71 #include <sys/stat.h>
72 #include <sys/types.h>
73 #include <sys/wait.h>
74 #include <pty.h>
75 #include <utmp.h>
76 #include <ctype.h>
77 #ifdef HAVE_LOCALE_H
78 #include <locale.h>
79 #endif
80 #ifdef HAVE_LANGINFO_CODESET
81 #include <langinfo.h>
82 #endif
83 #include <gpg-error.h>
85 #define JNLIB_NEED_LOG_LOGV
86 #include "i18n.h"
87 #include "../common/util.h"
88 #include "mkdtemp.h"
90 /* FIXME: Bah. For spwq_secure_free. */
91 #define SIMPLE_PWQUERY_IMPLEMENTATION 1
92 #include "../common/simple-pwquery.h"
95 /* Used by gcry for logging */
96 static void
97 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
99 /* translate the log levels */
100 switch (level)
102 case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
103 case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
104 case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
105 case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
106 case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
107 case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
108 case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
109 default: level = JNLIB_LOG_ERROR; break; }
110 log_logv (level, fmt, arg_ptr);
114 /* From simple-gettext.c. */
116 /* We assume to have `unsigned long int' value with at least 32 bits. */
117 #define HASHWORDBITS 32
119 /* The so called `hashpjw' function by P.J. Weinberger
120 [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
121 1986, 1987 Bell Telephone Laboratories, Inc.] */
123 static __inline__ ulong
124 hash_string( const char *str_param )
126 unsigned long int hval, g;
127 const char *str = str_param;
129 hval = 0;
130 while (*str != '\0')
132 hval <<= 4;
133 hval += (unsigned long int) *str++;
134 g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
135 if (g != 0)
137 hval ^= g >> (HASHWORDBITS - 8);
138 hval ^= g;
141 return hval;
145 /* Constants to identify the commands and options. */
146 enum cmd_and_opt_values
148 aNull = 0,
149 oQuiet = 'q',
150 oVerbose = 'v',
152 oNoVerbose = 500,
153 oOptions,
154 oNoOptions,
155 oLogFile,
156 oHomedir,
157 oClass,
158 oProgram,
159 oKeyfile,
160 oDecrypt,
161 oEncrypt,
162 oInput
166 /* The list of commands and options. */
167 static ARGPARSE_OPTS opts[] =
169 { 301, NULL, 0, N_("@\nCommands:\n ") },
171 { oDecrypt, "decrypt", 0, N_("decryption modus") },
172 { oEncrypt, "encrypt", 0, N_("encryption modus") },
174 { 302, NULL, 0, N_("@\nOptions:\n ") },
176 { oClass, "class", 2, N_("tool class (confucius)") },
177 { oProgram, "program", 2, N_("program filename") },
179 { oKeyfile, "keyfile", 2, N_("secret key file (required)") },
180 { oInput, "inputfile", 2, N_("input file name (default stdin)") },
181 { oVerbose, "verbose", 0, N_("verbose") },
182 { oQuiet, "quiet", 0, N_("quiet") },
183 { oLogFile, "log-file", 2, N_("use a log file for the server") },
184 { oOptions, "options" , 2, N_("|FILE|read options from FILE") },
186 /* Hidden options. */
187 { oNoVerbose, "no-verbose", 0, "@" },
188 { oHomedir, "homedir", 2, "@" },
189 { oNoOptions, "no-options", 0, "@" },/* shortcut for --options /dev/null */
195 /* We keep all global options in the structure OPT. */
196 struct
198 int verbose; /* Verbosity level. */
199 int quiet; /* Be extra quiet. */
200 const char *homedir; /* Configuration directory name */
202 char *class;
203 char *program;
204 char *keyfile;
205 char *input;
206 } opt;
209 /* Print usage information and and provide strings for help. */
210 static const char *
211 my_strusage (int level)
213 const char *p;
215 switch (level)
217 case 11: p = "symcryptrun (GnuPG)";
218 break;
219 case 13: p = VERSION; break;
220 case 17: p = PRINTABLE_OS_NAME; break;
221 case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
222 break;
223 case 1:
224 case 40: p = _("Usage: symcryptrun [options] (-h for help)");
225 break;
226 case 41:
227 p = _("Syntax: symcryptrun --class CLASS --program PROGRAM "
228 "--keyfile KEYFILE [options...] COMMAND [inputfile]\n"
229 "Call a simple symmetric encryption tool\n");
230 break;
231 case 31: p = "\nHome: "; break;
232 case 32: p = opt.homedir; break;
233 case 33: p = "\n"; break;
235 default: p = NULL; break;
237 return p;
241 /* Initialize the gettext system. */
242 static void
243 i18n_init(void)
245 #ifdef USE_SIMPLE_GETTEXT
246 set_gettext_file (PACKAGE_GT);
247 #else
248 # ifdef ENABLE_NLS
249 setlocale (LC_ALL, "");
250 bindtextdomain (PACKAGE_GT, LOCALEDIR);
251 textdomain (PACKAGE_GT);
252 # endif
253 #endif
257 /* This is in the GNU C library in unistd.h. */
259 #ifndef TEMP_FAILURE_RETRY
260 /* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno'
261 set to EINTR. */
263 # define TEMP_FAILURE_RETRY(expression) \
264 (__extension__ \
265 ({ long int __result; \
266 do __result = (long int) (expression); \
267 while (__result == -1L && errno == EINTR); \
268 __result; }))
269 #endif
272 /* Unlink a file, and shred it if SHRED is true. */
274 remove_file (char *name, int shred)
276 if (!shred)
277 return unlink (name);
278 else
280 int status;
281 pid_t pid;
283 pid = fork ();
284 if (pid == 0)
286 /* Child. */
288 /* -f forces file to be writable, and -u unlinks it afterwards. */
289 char *args[] = { SHRED, "-uf", name, NULL };
291 execv (SHRED, args);
292 _exit (127);
294 else if (pid < 0)
296 /* Fork failed. */
297 status = -1;
299 else
301 /* Parent. */
303 if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
304 status = -1;
307 if (!WIFEXITED (status))
309 log_error (_("%s on %s aborted with status %i\n"),
310 SHRED, name, status);
311 unlink (name);
312 return 1;
314 else if (WEXITSTATUS (status))
316 log_error (_("%s on %s failed with status %i\n"), SHRED, name,
317 WEXITSTATUS (status));
318 unlink (name);
319 return 1;
322 return 0;
327 /* Class Confucius.
329 "Don't worry that other people don't know you;
330 worry that you don't know other people." Analects--1.16. */
332 /* Create temporary directory with mode 0700. Returns a dynamically
333 allocated string with the filename of the directory. */
334 static char *
335 confucius_mktmpdir (void)
337 char *name;
339 name = strdup ("/tmp/gpg-XXXXXX");
340 if (!name || !mkdtemp (name))
342 log_error (_("can't create temporary directory `%s': %s\n"),
343 name?name:"", strerror (errno));
344 return NULL;
347 return name;
351 /* Buffer size for I/O operations. */
352 #define CONFUCIUS_BUFSIZE 4096
354 /* Buffer size for output lines. */
355 #define CONFUCIUS_LINESIZE 4096
358 /* Copy the file IN to OUT, either of which may be "-". If PLAIN is
359 true, and the copying fails, and OUT is not STDOUT, then shred the
360 file instead unlinking it. */
361 static int
362 confucius_copy_file (char *infile, char *outfile, int plain)
364 FILE *in;
365 int in_is_stdin = 0;
366 FILE *out;
367 int out_is_stdout = 0;
368 char data[CONFUCIUS_BUFSIZE];
369 ssize_t data_len;
371 if (infile[0] == '-' && infile[1] == '\0')
373 /* FIXME: Is stdin in binary mode? */
374 in = stdin;
375 in_is_stdin = 1;
377 else
379 in = fopen (infile, "rb");
380 if (!in)
382 log_error (_("could not open %s for writing: %s\n"),
383 infile, strerror (errno));
384 return 1;
388 if (outfile[0] == '-' && outfile[1] == '\0')
390 /* FIXME: Is stdout in binary mode? */
391 out = stdout;
392 out_is_stdout = 1;
394 else
396 out = fopen (outfile, "wb");
397 if (!out)
399 log_error (_("could not open %s for writing: %s\n"),
400 infile, strerror (errno));
401 return 1;
405 /* Now copy the data. */
406 while ((data_len = fread (data, 1, sizeof (data), in)) > 0)
408 if (fwrite (data, 1, data_len, out) != data_len)
410 log_error (_("error writing to %s: %s\n"), outfile,
411 strerror (errno));
412 goto copy_err;
415 if (data_len < 0 || ferror (in))
417 log_error (_("error reading from %s: %s\n"), infile, strerror (errno));
418 goto copy_err;
421 /* Close IN if appropriate. */
422 if (!in_is_stdin && fclose (in) && ferror (in))
424 log_error (_("error closing %s: %s\n"), infile, strerror (errno));
425 goto copy_err;
428 /* Close OUT if appropriate. */
429 if (!out_is_stdout && fclose (out) && ferror (out))
431 log_error (_("error closing %s: %s\n"), infile, strerror (errno));
432 goto copy_err;
435 return 0;
437 copy_err:
438 if (!out_is_stdout)
439 remove_file (outfile, plain);
441 return 1;
445 /* Get a passphrase in secure storage (if possible). If AGAIN is
446 true, then this is a repeated attempt. If CANCELED is not a null
447 pointer, it will be set to true or false, depending on if the user
448 canceled the operation or not. On error (including cancelation), a
449 null pointer is returned. The passphrase must be deallocated with
450 confucius_drop_pass. CACHEID is the ID to be used for passphrase
451 caching and can be NULL to disable caching. */
452 char *
453 confucius_get_pass (const char *cacheid, int again, int *canceled)
455 int err;
456 char *pw;
457 #ifdef HAVE_LANGINFO_CODESET
458 char *orig_codeset = NULL;
459 #endif
461 if (canceled)
462 *canceled = 0;
464 #ifdef ENABLE_NLS
465 /* The Assuan agent protocol requires us to transmit utf-8 strings */
466 orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
467 #ifdef HAVE_LANGINFO_CODESET
468 if (!orig_codeset)
469 orig_codeset = nl_langinfo (CODESET);
470 #endif
471 if (orig_codeset && !strcmp (orig_codeset, "UTF-8"))
472 orig_codeset = NULL;
473 if (orig_codeset)
475 /* We only switch when we are able to restore the codeset later. */
476 orig_codeset = xstrdup (orig_codeset);
477 if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
478 orig_codeset = NULL;
480 #endif
482 pw = simple_pwquery (cacheid,
483 again ? _("does not match - try again"):NULL,
484 _("Passphrase:"), NULL, &err);
486 #ifdef ENABLE_NLS
487 if (orig_codeset)
489 bind_textdomain_codeset (PACKAGE_GT, orig_codeset);
490 xfree (orig_codeset);
492 #endif
494 if (!pw)
496 if (err)
497 log_error (_("error while asking for the passphrase: %s\n"),
498 gpg_strerror (err));
499 else
501 log_info (_("cancelled\n"));
502 if (canceled)
503 *canceled = 1;
507 return pw;
511 /* Drop a passphrase retrieved with confucius_get_pass. */
512 void
513 confucius_drop_pass (char *pass)
515 if (pass)
516 spwq_secure_free (pass);
520 /* Run a confucius crypto engine. If MODE is oEncrypt, encryption is
521 requested. If it is oDecrypt, decryption is requested. INFILE and
522 OUTFILE are the temporary files used in the process. */
524 confucius_process (int mode, char *infile, char *outfile,
525 int argc, char *argv[])
527 char **args;
528 int cstderr[2];
529 int master;
530 int slave;
531 int res;
532 pid_t pid;
533 pid_t wpid;
534 int tries = 0;
535 char cacheid[40];
537 signal (SIGPIPE, SIG_IGN);
539 if (!opt.program)
541 log_error (_("no --program option provided\n"));
542 return 1;
545 if (mode != oDecrypt && mode != oEncrypt)
547 log_error (_("only --decrypt and --encrypt are supported\n"));
548 return 1;
551 if (!opt.keyfile)
553 log_error (_("no --keyfile option provided\n"));
554 return 1;
557 /* Generate a hash from the keyfile name for caching. */
558 snprintf (cacheid, sizeof (cacheid), "confucius:%lu",
559 hash_string (opt.keyfile));
560 cacheid[sizeof (cacheid) - 1] = '\0';
561 args = malloc (sizeof (char *) * (10 + argc));
562 if (!args)
564 log_error (_("cannot allocate args vector\n"));
565 return 1;
567 args[0] = opt.program;
568 args[1] = (mode == oEncrypt) ? "-m1" : "-m2";
569 args[2] = "-q";
570 args[3] = infile;
571 args[4] = "-z";
572 args[5] = outfile;
573 args[6] = "-s";
574 args[7] = opt.keyfile;
575 args[8] = (mode == oEncrypt) ? "-af" : "-f";
576 args[9 + argc] = NULL;
577 while (argc--)
578 args[9 + argc] = argv[argc];
580 if (pipe (cstderr) < 0)
582 log_error (_("could not create pipe: %s\n"), strerror (errno));
583 free (args);
584 return 1;
587 if (openpty (&master, &slave, NULL, NULL, NULL) == -1)
589 log_error (_("could not create pty: %s\n"), strerror (errno));
590 close (cstderr[0]);
591 close (cstderr[1]);
592 free (args);
593 return -1;
596 /* We don't want to deal with the worst case scenarios. */
597 assert (master > 2);
598 assert (slave > 2);
599 assert (cstderr[0] > 2);
600 assert (cstderr[1] > 2);
602 pid = fork ();
603 if (pid < 0)
605 log_error (_("could not fork: %s\n"), strerror (errno));
606 close (master);
607 close (slave);
608 close (cstderr[0]);
609 close (cstderr[1]);
610 free (args);
611 return 1;
613 else if (pid == 0)
615 /* Child. */
617 /* Close the parent ends. */
618 close (master);
619 close (cstderr[0]);
621 /* Change controlling terminal. */
622 if (login_tty (slave))
624 /* It's too early to output a debug message. */
625 _exit (1);
628 dup2 (cstderr[1], 2);
629 close (cstderr[1]);
631 /* Now kick off the engine program. */
632 execv (opt.program, args);
633 log_error (_("execv failed: %s\n"), strerror (errno));
634 _exit (1);
636 else
638 /* Parent. */
639 char buffer[CONFUCIUS_LINESIZE];
640 int buffer_len = 0;
641 fd_set fds;
642 int slave_closed = 0;
643 int stderr_closed = 0;
645 close (slave);
646 close (cstderr[1]);
647 free (args);
649 /* Listen on the output FDs. */
652 FD_ZERO (&fds);
654 if (!slave_closed)
655 FD_SET (master, &fds);
656 if (!stderr_closed)
657 FD_SET (cstderr[0], &fds);
659 res = select (FD_SETSIZE, &fds, NULL, NULL, NULL);
660 if (res < 0)
662 log_error (_("select failed: %s\n"), strerror (errno));
664 kill (pid, SIGTERM);
665 close (master);
666 close (cstderr[0]);
667 return 1;
670 if (FD_ISSET (cstderr[0], &fds))
672 /* We got some output on stderr. This is just passed
673 through via the logging facility. */
675 res = read (cstderr[0], &buffer[buffer_len],
676 sizeof (buffer) - buffer_len - 1);
677 if (res < 0)
679 log_error (_("read failed: %s\n"), strerror (errno));
681 kill (pid, SIGTERM);
682 close (master);
683 close (cstderr[0]);
684 return 1;
686 else
688 char *newline;
690 buffer_len += res;
691 for (;;)
693 buffer[buffer_len] = '\0';
694 newline = strchr (buffer, '\n');
695 if (newline)
697 *newline = '\0';
698 log_error ("%s\n", buffer);
699 buffer_len -= newline + 1 - buffer;
700 memmove (buffer, newline + 1, buffer_len);
702 else if (buffer_len == sizeof (buffer) - 1)
704 /* Overflow. */
705 log_error ("%s\n", buffer);
706 buffer_len = 0;
708 else
709 break;
712 if (res == 0)
713 stderr_closed = 1;
716 else if (FD_ISSET (master, &fds))
718 char data[512];
720 res = read (master, data, sizeof (data));
721 if (res < 0)
723 if (errno == EIO)
725 /* Slave-side close leads to readable fd and
726 EIO. */
727 slave_closed = 1;
729 else
731 log_error (_("pty read failed: %s\n"), strerror (errno));
733 kill (pid, SIGTERM);
734 close (master);
735 close (cstderr[0]);
736 return 1;
739 else if (res == 0)
740 /* This never seems to be what happens on slave-side
741 close. */
742 slave_closed = 1;
743 else
745 /* Check for password prompt. */
746 if (data[res - 1] == ':')
748 char *pass;
749 int canceled;
751 /* If this is not the first attempt, the
752 passphrase seems to be wrong, so clear the
753 cache. */
754 if (tries)
755 simple_pwclear (cacheid);
757 pass = confucius_get_pass (cacheid,
758 tries ? 1 : 0, &canceled);
759 if (!pass)
761 kill (pid, SIGTERM);
762 close (master);
763 close (cstderr[0]);
764 return canceled ? SYMC_CANCELED : 1;
766 write (master, pass, strlen (pass));
767 write (master, "\n", 1);
768 confucius_drop_pass (pass);
770 tries++;
775 while (!stderr_closed || !slave_closed);
777 close (master);
778 close (cstderr[0]);
780 wpid = waitpid (pid, &res, 0);
781 if (wpid < 0)
783 log_error (_("waitpid failed: %s\n"), strerror (errno));
785 kill (pid, SIGTERM);
786 /* State of cached password is unclear. Just remove it. */
787 simple_pwclear (cacheid);
788 return 1;
790 else
792 /* Shouldn't happen, as we don't use WNOHANG. */
793 assert (wpid != 0);
795 if (!WIFEXITED (res))
797 log_error (_("child aborted with status %i\n"), res);
799 /* State of cached password is unclear. Just remove it. */
800 simple_pwclear (cacheid);
802 return 1;
805 if (WEXITSTATUS (res))
807 /* The passphrase was wrong. Remove it from the cache. */
808 simple_pwclear (cacheid);
810 /* We probably exceeded our number of attempts at guessing
811 the password. */
812 if (tries >= 3)
813 return SYMC_BAD_PASSPHRASE;
814 else
815 return 1;
818 return 0;
822 /* Not reached. */
826 /* Class confucius main program. If MODE is oEncrypt, encryption is
827 requested. If it is oDecrypt, decryption is requested. The other
828 parameters are taken from the global option data. */
830 confucius_main (int mode, int argc, char *argv[])
832 int res;
833 char *tmpdir;
834 char *infile;
835 int infile_from_stdin = 0;
836 char *outfile;
838 tmpdir = confucius_mktmpdir ();
839 if (!tmpdir)
840 return 1;
842 if (opt.input && !(opt.input[0] == '-' && opt.input[1] == '\0'))
843 infile = xstrdup (opt.input);
844 else
846 infile_from_stdin = 1;
848 /* TMPDIR + "/" + "in" + "\0". */
849 infile = malloc (strlen (tmpdir) + 1 + 2 + 1);
850 if (!infile)
852 log_error (_("cannot allocate infile string: %s\n"),
853 strerror (errno));
854 rmdir (tmpdir);
855 return 1;
857 strcpy (infile, tmpdir);
858 strcat (infile, "/in");
861 /* TMPDIR + "/" + "out" + "\0". */
862 outfile = malloc (strlen (tmpdir) + 1 + 3 + 1);
863 if (!outfile)
865 log_error (_("cannot allocate outfile string: %s\n"), strerror (errno));
866 free (infile);
867 rmdir (tmpdir);
868 return 1;
870 strcpy (outfile, tmpdir);
871 strcat (outfile, "/out");
873 if (infile_from_stdin)
875 /* Create INFILE and fill it with content. */
876 res = confucius_copy_file ("-", infile, mode == oEncrypt);
877 if (res)
879 free (outfile);
880 free (infile);
881 rmdir (tmpdir);
882 return res;
886 /* Run the engine and thus create the output file, handling
887 passphrase retrieval. */
888 res = confucius_process (mode, infile, outfile, argc, argv);
889 if (res)
891 remove_file (outfile, mode == oDecrypt);
892 if (infile_from_stdin)
893 remove_file (infile, mode == oEncrypt);
894 free (outfile);
895 free (infile);
896 rmdir (tmpdir);
897 return res;
900 /* Dump the output file to stdout. */
901 res = confucius_copy_file (outfile, "-", mode == oDecrypt);
902 if (res)
904 remove_file (outfile, mode == oDecrypt);
905 if (infile_from_stdin)
906 remove_file (infile, mode == oEncrypt);
907 free (outfile);
908 free (infile);
909 rmdir (tmpdir);
910 return res;
913 remove_file (outfile, mode == oDecrypt);
914 if (infile_from_stdin)
915 remove_file (infile, mode == oEncrypt);
916 free (outfile);
917 free (infile);
918 rmdir (tmpdir);
919 return 0;
923 /* symcryptrun's entry point. */
925 main (int argc, char **argv)
927 ARGPARSE_ARGS pargs;
928 int orig_argc;
929 char **orig_argv;
930 FILE *configfp = NULL;
931 char *configname = NULL;
932 unsigned configlineno;
933 int mode = 0;
934 int res;
935 char *logfile = NULL;
936 int default_config = 1;
938 set_strusage (my_strusage);
939 log_set_prefix ("symcryptrun", 1);
941 /* Try to auto set the character set. */
942 set_native_charset (NULL);
944 i18n_init();
946 opt.homedir = default_homedir ();
948 /* Check whether we have a config file given on the commandline */
949 orig_argc = argc;
950 orig_argv = argv;
951 pargs.argc = &argc;
952 pargs.argv = &argv;
953 pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */
954 while (arg_parse( &pargs, opts))
956 if (pargs.r_opt == oOptions)
957 { /* Yes there is one, so we do not try the default one, but
958 read the option file when it is encountered at the
959 commandline */
960 default_config = 0;
962 else if (pargs.r_opt == oNoOptions)
963 default_config = 0; /* --no-options */
964 else if (pargs.r_opt == oHomedir)
965 opt.homedir = pargs.r.ret_str;
968 if (default_config)
969 configname = make_filename (opt.homedir, "symcryptrun.conf", NULL );
971 argc = orig_argc;
972 argv = orig_argv;
973 pargs.argc = &argc;
974 pargs.argv = &argv;
975 pargs.flags= 1; /* do not remove the args */
976 next_pass:
977 if (configname)
979 configlineno = 0;
980 configfp = fopen (configname, "r");
981 if (!configfp)
983 if (!default_config)
985 log_error (_("option file `%s': %s\n"),
986 configname, strerror(errno) );
987 exit(1);
989 xfree (configname);
990 configname = NULL;
992 default_config = 0;
995 /* Parse the command line. */
996 while (optfile_parse (configfp, configname, &configlineno, &pargs, opts))
998 switch (pargs.r_opt)
1000 case oDecrypt: mode = oDecrypt; break;
1001 case oEncrypt: mode = oEncrypt; break;
1003 case oQuiet: opt.quiet = 1; break;
1004 case oVerbose: opt.verbose++; break;
1005 case oNoVerbose: opt.verbose = 0; break;
1007 case oClass: opt.class = pargs.r.ret_str; break;
1008 case oProgram: opt.program = pargs.r.ret_str; break;
1009 case oKeyfile: opt.keyfile = pargs.r.ret_str; break;
1010 case oInput: opt.input = pargs.r.ret_str; break;
1012 case oLogFile: logfile = pargs.r.ret_str; break;
1014 case oOptions:
1015 /* Config files may not be nested (silently ignore them) */
1016 if (!configfp)
1018 xfree(configname);
1019 configname = xstrdup(pargs.r.ret_str);
1020 goto next_pass;
1022 break;
1023 case oNoOptions: break; /* no-options */
1024 case oHomedir: /* Ignore this option here. */; break;
1026 default : pargs.err = configfp? 1:2; break;
1029 if (configfp)
1031 fclose( configfp );
1032 configfp = NULL;
1033 configname = NULL;
1034 goto next_pass;
1036 xfree (configname);
1037 configname = NULL;
1039 if (!mode)
1040 log_error (_("either %s or %s must be given\n"),
1041 "--decrypt", "--encrypt");
1043 if (log_get_errorcount (0))
1044 exit (1);
1046 if (logfile)
1047 log_set_file (logfile);
1049 gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
1050 if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
1052 log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
1053 NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
1055 gcry_set_log_handler (my_gcry_logger, NULL);
1056 gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
1058 if (!opt.class)
1060 log_error (_("no class provided\n"));
1061 res = 1;
1063 else if (!strcmp (opt.class, "confucius"))
1064 res = confucius_main (mode, argc, argv);
1065 else
1067 log_error (_("class %s is not supported\n"), opt.class);
1068 res = 1;
1071 return res;