diff --git a/Makefile.am b/Makefile.am index 064ea88ef..9daeccc6f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,7 +30,7 @@ RELEASE_ARCHIVE_SUFFIX = gnupg/v2.3 # Autoconf flags. ACLOCAL_AMFLAGS = -I m4 AM_DISTCHECK_CONFIGURE_FLAGS = --enable-gnupg-builddir-envvar \ - --enable-all-tests --enable-symcryptrun --enable-g13 \ + --enable-all-tests --enable-g13 \ --enable-gpgtar --enable-wks-tools --disable-ntbtls GITLOG_TO_CHANGELOG=gitlog-to-changelog diff --git a/configure.ac b/configure.ac index ea64ce19a..171847a33 100644 --- a/configure.ac +++ b/configure.ac @@ -126,7 +126,6 @@ GNUPG_BUILD_PROGRAM(g13, no) GNUPG_BUILD_PROGRAM(dirmngr, yes) GNUPG_BUILD_PROGRAM(keyboxd, yes) GNUPG_BUILD_PROGRAM(doc, yes) -GNUPG_BUILD_PROGRAM(symcryptrun, no) # We use gpgtar to unpack test data, hence we always build it. If the # user opts out, we simply don't install it. GNUPG_BUILD_PROGRAM(gpgtar, yes) @@ -982,26 +981,6 @@ AC_DEFINE_UNQUOTED(FUSERMOUNT, "${FUSERMOUNT}", [defines the filename of the fusermount program]) -# Checks for dirmngr - - -# -# Checks for symcryptrun: -# - -# libutil has openpty() and login_tty(). -AC_CHECK_LIB(util, openpty, - [ LIBUTIL_LIBS="$LIBUTIL_LIBS -lutil" - AC_DEFINE(HAVE_LIBUTIL,1, - [defined if libutil is available]) - ]) -AC_SUBST(LIBUTIL_LIBS) - -# shred is used to clean temporary plain text files. -AC_PATH_PROG(SHRED, shred, /usr/bin/shred) -AC_DEFINE_UNQUOTED(SHRED, - "${SHRED}", [defines the filename of the shred program]) - # # Check whether the nPth library is available @@ -1798,7 +1777,6 @@ AM_CONDITIONAL(BUILD_G13, test "$build_g13" = "yes") AM_CONDITIONAL(BUILD_DIRMNGR, test "$build_dirmngr" = "yes") AM_CONDITIONAL(BUILD_KEYBOXD, test "$build_keyboxd" = "yes") AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes") -AM_CONDITIONAL(BUILD_SYMCRYPTRUN, test "$build_symcryptrun" = "yes") AM_CONDITIONAL(BUILD_GPGTAR, test "$build_gpgtar" = "yes") AM_CONDITIONAL(BUILD_WKS_TOOLS, test "$build_wks_tools" = "yes") diff --git a/doc/Makefile.am b/doc/Makefile.am index 1ad86e5b7..cf5563142 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -96,7 +96,7 @@ myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \ gpg-card.texi myman_pages = gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 \ watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \ - gpg-connect-agent.1 gpgparsemail.1 symcryptrun.1 gpgtar.1 \ + gpg-connect-agent.1 gpgparsemail.1 gpgtar.1 \ applygnupgdefaults.8 gpg-wks-client.1 gpg-wks-server.1 \ dirmngr-client.1 gpg-card.1 gpg-check-pattern.1 if USE_GPG2_HACK diff --git a/doc/tools.texi b/doc/tools.texi index 8eb77401e..c48ba4b4a 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -19,7 +19,6 @@ GnuPG comes with a couple of smaller tools: * gpg-connect-agent:: Communicate with a running agent. * dirmngr-client:: How to use the Dirmngr client tool. * gpgparsemail:: Parse a mail message into an annotated format -* symcryptrun:: Call a simple symmetric encryption tool. * gpgtar:: Encrypt or sign files into an archive. * gpg-check-pattern:: Check a passphrase on stdin against the patternfile. @end menu @@ -1842,128 +1841,6 @@ The @command{gpgparsemail} is a utility currently only useful for debugging. Run it with @code{--help} for usage information. - -@c -@c SYMCRYPTRUN -@c -@node symcryptrun -@section Call a simple symmetric encryption tool -@manpage symcryptrun.1 -@ifset manverb -.B symcryptrun -\- Call a simple symmetric encryption tool -@end ifset - -@mansect synopsis -@ifset manverb -.B symcryptrun -.B \-\-class -.I class -.B \-\-program -.I program -.B \-\-keyfile -.I keyfile -.RB [ --decrypt | --encrypt ] -.RI [ inputfile ] -@end ifset - -@mansect description -Sometimes simple encryption tools are already in use for a long time -and there might be a desire to integrate them into the GnuPG -framework. The protocols and encryption methods might be non-standard -or not even properly documented, so that a full-fledged encryption -tool with an interface like @command{gpg} is not doable. -@command{symcryptrun} provides a solution: It operates by calling the -external encryption/decryption module and provides a passphrase for a -key using the standard @command{pinentry} based mechanism through -@command{gpg-agent}. - -Note, that @command{symcryptrun} is only available if GnuPG has been -configured with @samp{--enable-symcryptrun} at build time. - -@menu -* Invoking symcryptrun:: List of all commands and options. -@end menu - -@manpause -@node Invoking symcryptrun -@subsection List of all commands and options - -@noindent -@command{symcryptrun} is invoked this way: - -@example -symcryptrun --class CLASS --program PROGRAM --keyfile KEYFILE - [--decrypt | --encrypt] [inputfile] -@end example -@mancont - -For encryption, the plain text must be provided on STDIN or as the -argument @var{inputfile}, and the ciphertext will be output to STDOUT. -For decryption vice versa. - -@var{CLASS} describes the calling conventions of the external tool. -Currently it must be given as @samp{confucius}. @var{PROGRAM} is -the full filename of that external tool. - -For the class @samp{confucius} the option @option{--keyfile} is -required; @var{keyfile} is the name of a file containing the secret key, -which may be protected by a passphrase. For detailed calling -conventions, see the source code. - -@noindent -Note, that @command{gpg-agent} must be running before starting -@command{symcryptrun}. - -@noindent -The following additional options may be used: - -@table @gnupgtabopt -@item -v -@itemx --verbose -@opindex verbose -Output additional information while running. - -@item -q -@item --quiet -@opindex q -@opindex quiet -Try to be as quiet as possible. - -@include opt-homedir.texi - - -@item --log-file @var{file} -@opindex log-file -Append all logging output to @var{file}. Use @file{socket://} to log -to socket. Default is to write logging information to STDERR. - -@end table - -@noindent -The possible exit status codes of @command{symcryptrun} are: - -@table @code -@item 0 - Success. -@item 1 - Some error occurred. -@item 2 - No valid passphrase was provided. -@item 3 - The operation was canceled by the user. - -@end table - -@mansect see also -@ifset isman -@command{gpg}(1), -@command{gpgsm}(1), -@command{gpg-agent}(1), -@end ifset -@include see-also-note.texi - - @c @c GPGTAR @c diff --git a/po/POTFILES.in b/po/POTFILES.in index a5a23398e..f299fac32 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -126,7 +126,6 @@ tools/gpg-connect-agent.c tools/gpgconf-comp.c tools/gpgconf.c tools/no-libgcrypt.c -tools/symcryptrun.c tools/gpg-check-pattern.c tools/gpg-card.c tools/card-misc.c diff --git a/tools/Makefile.am b/tools/Makefile.am index 81e8b43b2..4ece726b3 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -37,12 +37,6 @@ AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS) $(LIBASSUAN_CFLAGS) sbin_SCRIPTS = addgnupghome applygnupgdefaults -if BUILD_SYMCRYPTRUN - symcryptrun = symcryptrun -else - symcryptrun = -endif - if BUILD_WKS_TOOLS gpg_wks_server = gpg-wks-server else @@ -51,7 +45,7 @@ endif libexec_PROGRAMS = gpg-wks-client -bin_PROGRAMS = gpgconf gpg-connect-agent gpg-card ${symcryptrun} +bin_PROGRAMS = gpgconf gpg-connect-agent gpg-card if !HAVE_W32_SYSTEM bin_PROGRAMS += watchgnupg gpgparsemail ${gpg_wks_server} gpgsplit else @@ -115,11 +109,6 @@ gpgconf_w32_LDFLAGS = $(gpgconf_LDFLAGS) -Wl,-subsystem,windows gpgparsemail_SOURCES = gpgparsemail.c rfc822parse.c rfc822parse.h gpgparsemail_LDADD = -symcryptrun_SOURCES = symcryptrun.c -symcryptrun_LDADD = $(LIBUTIL_LIBS) $(common_libs) $(pwquery_libs) \ - $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) \ - $(LIBICONV) $(NETLIBS) $(W32SOCKLIBS) $(LIBASSUAN_LIBS) - watchgnupg_SOURCES = watchgnupg.c watchgnupg_LDADD = $(NETLIBS) diff --git a/tools/symcryptrun.c b/tools/symcryptrun.c deleted file mode 100644 index 59838f6df..000000000 --- a/tools/symcryptrun.c +++ /dev/null @@ -1,1019 +0,0 @@ -/* symcryptrun.c - Tool to call simple symmetric encryption tools. - * Copyright (C) 2005, 2007 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - - -/* Sometimes simple encryption tools are already in use for a long - time and there is a desire to integrate them into the GnuPG - framework. The protocols and encryption methods might be - non-standard or not even properly documented, so that a - full-fledged encryption tool with an interface like gpg is not - doable. This simple wrapper program provides a solution: It - operates by calling the encryption/decryption module and providing - the passphrase for a key (or even the key directly) using the - standard pinentry mechanism through gpg-agent. */ - -/* This program is invoked in the following way: - - symcryptrun --class CLASS --program PROGRAM --keyfile KEYFILE \ - [--decrypt | --encrypt] - - For encryption, the plain text must be provided on STDIN, and the - ciphertext will be output to STDOUT. For decryption vice versa. - - CLASS can currently only be "confucius". - - PROGRAM must be the path to the crypto engine. - - KEYFILE must contain the secret key, which may be protected by a - passphrase. The passphrase is retrieved via the pinentry program. - - - The GPG Agent _must_ be running before starting symcryptrun. - - The possible exit status codes: - - 0 Success - 1 Some error occurred - 2 No valid passphrase was provided - 3 The operation was canceled by the user - - Other classes may be added in the future. */ - -#define SYMC_BAD_PASSPHRASE 2 -#define SYMC_CANCELED 3 - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_PTY_H -#include -#else -#ifdef HAVE_TERMIOS_H -#include -#endif -#ifdef HAVE_UTIL_H -#include -#endif -#ifdef HAVE_LIBUTIL_H -#include -#endif -#endif - -#ifdef HAVE_UTMP_H -#include -#endif -#include -#ifdef HAVE_LOCALE_H -#include -#endif -#ifdef HAVE_LANGINFO_CODESET -#include -#endif -#include - -#include "../common/i18n.h" -#include "../common/util.h" -#include "../common/init.h" -#include "../common/sysutils.h" - -/* FIXME: Bah. For spwq_secure_free. */ -#define SIMPLE_PWQUERY_IMPLEMENTATION 1 -#include "../common/simple-pwquery.h" - - -/* From simple-gettext.c. */ - -/* We assume to have 'unsigned long int' value with at least 32 bits. */ -#define HASHWORDBITS 32 - -/* The so called 'hashpjw' function by P.J. Weinberger - [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, - 1986, 1987 Bell Telephone Laboratories, Inc.] */ - -static __inline__ ulong -hash_string( const char *str_param ) -{ - unsigned long int hval, g; - const char *str = str_param; - - hval = 0; - while (*str != '\0') - { - hval <<= 4; - hval += (unsigned long int) *str++; - g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); - if (g != 0) - { - hval ^= g >> (HASHWORDBITS - 8); - hval ^= g; - } - } - return hval; -} - - -/* Constants to identify the commands and options. */ -enum cmd_and_opt_values - { - aNull = 0, - oQuiet = 'q', - oVerbose = 'v', - - oNoVerbose = 500, - oOptions, - oNoOptions, - oLogFile, - oHomedir, - oClass, - oProgram, - oKeyfile, - oDecrypt, - oEncrypt, - oInput - }; - - -/* The list of commands and options. */ -static gpgrt_opt_t opts[] = { - - ARGPARSE_group(300, N_("@\nCommands:\n ")), - - ARGPARSE_c(oDecrypt, "decrypt", N_("decryption modus")), - ARGPARSE_c(oEncrypt, "encrypt", N_("encryption modus")), - - ARGPARSE_group(301, N_("@\nOptions:\n ")), - - ARGPARSE_s_s(oClass, "class", N_("tool class (confucius)")), - ARGPARSE_s_s(oProgram, "program", N_("program filename")), - - ARGPARSE_s_s(oKeyfile, "keyfile", N_("secret key file (required)")), - ARGPARSE_s_s(oInput, "inputfile", N_("input file name (default stdin)")), - ARGPARSE_s_n(oVerbose, "verbose", N_("verbose")), - ARGPARSE_s_n(oQuiet, "quiet", N_("quiet")), - ARGPARSE_s_s(oLogFile, "log-file", N_("use a log file for the server")), - ARGPARSE_conffile(oOptions, "options", N_("|FILE|read options from FILE")), - - /* Hidden options. */ - ARGPARSE_s_n(oNoVerbose, "no-verbose", "@"), - ARGPARSE_s_s(oHomedir, "homedir", "@"), - ARGPARSE_noconffile(oNoOptions, "no-options", "@"), - - ARGPARSE_end () -}; - - -/* We keep all global options in the structure OPT. */ -struct -{ - int verbose; /* Verbosity level. */ - int quiet; /* Be extra quiet. */ - const char *homedir; /* Configuration directory name */ - - char *class; - char *program; - char *keyfile; - char *input; -} opt; - - -/* Print usage information and provide strings for help. */ -static const char * -my_strusage (int level) -{ - const char *p; - - switch (level) - { - case 9: p = "GPL-3.0-or-later"; break; - case 11: p = "symcryptrun (@GNUPG@)"; - break; - case 13: p = VERSION; break; - case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break; - case 17: p = PRINTABLE_OS_NAME; break; - case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break; - - case 1: - case 40: p = _("Usage: symcryptrun [options] (-h for help)"); - break; - case 41: - p = _("Syntax: symcryptrun --class CLASS --program PROGRAM " - "--keyfile KEYFILE [options...] COMMAND [inputfile]\n" - "Call a simple symmetric encryption tool\n"); - break; - case 31: p = "\nHome: "; break; - case 32: p = gnupg_homedir (); break; - case 33: p = "\n"; break; - - default: p = NULL; break; - } - return p; -} - - - -/* This is in the GNU C library in unistd.h. */ - -#ifndef TEMP_FAILURE_RETRY -/* Evaluate EXPRESSION, and repeat as long as it returns -1 with 'errno' - set to EINTR. */ - -# define TEMP_FAILURE_RETRY(expression) \ - (__extension__ \ - ({ long int __result; \ - do __result = (long int) (expression); \ - while (__result == -1L && errno == EINTR); \ - __result; })) -#endif - -/* Unlink a file, and shred it if SHRED is true. */ -int -remove_file (char *name, int shred) -{ - if (!shred) - return unlink (name); - else - { - int status; - pid_t pid; - - pid = fork (); - if (pid == 0) - { - /* Child. */ - - /* -f forces file to be writable, and -u unlinks it afterwards. */ - char *args[] = { SHRED, "-uf", name, NULL }; - - execv (SHRED, args); - _exit (127); - } - else if (pid < 0) - { - /* Fork failed. */ - status = -1; - } - else - { - /* Parent. */ - - if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) - status = -1; - } - - if (!WIFEXITED (status)) - { - log_error (_("%s on %s aborted with status %i\n"), - SHRED, name, status); - unlink (name); - return 1; - } - else if (WEXITSTATUS (status)) - { - log_error (_("%s on %s failed with status %i\n"), SHRED, name, - WEXITSTATUS (status)); - unlink (name); - return 1; - } - - return 0; - } -} - - -/* Class Confucius. - - "Don't worry that other people don't know you; - worry that you don't know other people." Analects--1.16. */ - -/* Create temporary directory with mode 0700. Returns a dynamically - allocated string with the filename of the directory. */ -static char * -confucius_mktmpdir (void) -{ - char *name, *p; - - p = getenv ("TMPDIR"); - if (!p || !*p) - p = "/tmp"; - if (p[strlen (p) - 1] == '/') - name = xstrconcat (p, "gpg-XXXXXX", NULL); - else - name = xstrconcat (p, "/", "gpg-XXXXXX", NULL); - if (!name || !gnupg_mkdtemp (name)) - { - log_error (_("can't create temporary directory '%s': %s\n"), - name?name:"", strerror (errno)); - return NULL; - } - - return name; -} - - -/* Buffer size for I/O operations. */ -#define CONFUCIUS_BUFSIZE 4096 - -/* Buffer size for output lines. */ -#define CONFUCIUS_LINESIZE 4096 - - -/* Copy the file IN to OUT, either of which may be "-". If PLAIN is - true, and the copying fails, and OUT is not STDOUT, then shred the - file instead unlinking it. */ -static int -confucius_copy_file (char *infile, char *outfile, int plain) -{ - FILE *in; - int in_is_stdin = 0; - FILE *out; - int out_is_stdout = 0; - char data[CONFUCIUS_BUFSIZE]; - ssize_t data_len; - - if (infile[0] == '-' && infile[1] == '\0') - { - /* FIXME: Is stdin in binary mode? */ - in = stdin; - in_is_stdin = 1; - } - else - { - in = fopen (infile, "rb"); - if (!in) - { - log_error (_("could not open %s for writing: %s\n"), - infile, strerror (errno)); - return 1; - } - } - - if (outfile[0] == '-' && outfile[1] == '\0') - { - /* FIXME: Is stdout in binary mode? */ - out = stdout; - out_is_stdout = 1; - } - else - { - out = fopen (outfile, "wb"); - if (!out) - { - log_error (_("could not open %s for writing: %s\n"), - infile, strerror (errno)); - return 1; - } - } - - /* Now copy the data. */ - while ((data_len = fread (data, 1, sizeof (data), in)) > 0) - { - if (fwrite (data, 1, data_len, out) != data_len) - { - log_error (_("error writing to %s: %s\n"), outfile, - strerror (errno)); - goto copy_err; - } - } - if (data_len < 0 || ferror (in)) - { - log_error (_("error reading from %s: %s\n"), infile, strerror (errno)); - goto copy_err; - } - - /* Close IN if appropriate. */ - if (!in_is_stdin && fclose (in) && ferror (in)) - { - log_error (_("error closing %s: %s\n"), infile, strerror (errno)); - goto copy_err; - } - - /* Close OUT if appropriate. */ - if (!out_is_stdout && fclose (out) && ferror (out)) - { - log_error (_("error closing %s: %s\n"), infile, strerror (errno)); - goto copy_err; - } - - return 0; - - copy_err: - if (!out_is_stdout) - remove_file (outfile, plain); - - return 1; -} - - -/* Get a passphrase in secure storage (if possible). If AGAIN is - true, then this is a repeated attempt. If CANCELED is not a null - pointer, it will be set to true or false, depending on if the user - canceled the operation or not. On error (including cancellation), a - null pointer is returned. The passphrase must be deallocated with - confucius_drop_pass. CACHEID is the ID to be used for passphrase - caching and can be NULL to disable caching. */ -char * -confucius_get_pass (const char *cacheid, int again, int *canceled) -{ - int err; - char *pw; - char *orig_codeset; - - if (canceled) - *canceled = 0; - - orig_codeset = i18n_switchto_utf8 (); - pw = simple_pwquery (cacheid, - again ? _("does not match - try again"):NULL, - _("Passphrase:"), NULL, 0, &err); - i18n_switchback (orig_codeset); - - if (!pw) - { - if (err) - log_error (_("error while asking for the passphrase: %s\n"), - gpg_strerror (err)); - else - { - log_info (_("cancelled\n")); - if (canceled) - *canceled = 1; - } - } - - return pw; -} - - -/* Drop a passphrase retrieved with confucius_get_pass. */ -void -confucius_drop_pass (char *pass) -{ - if (pass) - spwq_secure_free (pass); -} - - -/* Run a confucius crypto engine. If MODE is oEncrypt, encryption is - requested. If it is oDecrypt, decryption is requested. INFILE and - OUTFILE are the temporary files used in the process. */ -int -confucius_process (int mode, char *infile, char *outfile, - int argc, char *argv[]) -{ - char **args; - int cstderr[2]; - int master; - int slave; - int res; - pid_t pid; - pid_t wpid; - int tries = 0; - char cacheid[40]; - - signal (SIGPIPE, SIG_IGN); - - if (!opt.program) - { - log_error (_("no --program option provided\n")); - return 1; - } - - if (mode != oDecrypt && mode != oEncrypt) - { - log_error (_("only --decrypt and --encrypt are supported\n")); - return 1; - } - - if (!opt.keyfile) - { - log_error (_("no --keyfile option provided\n")); - return 1; - } - - /* Generate a hash from the keyfile name for caching. */ - snprintf (cacheid, sizeof (cacheid), "confucius:%lu", - hash_string (opt.keyfile)); - cacheid[sizeof (cacheid) - 1] = '\0'; - args = malloc (sizeof (char *) * (10 + argc)); - if (!args) - { - log_error (_("cannot allocate args vector\n")); - return 1; - } - args[0] = opt.program; - args[1] = (mode == oEncrypt) ? "-m1" : "-m2"; - args[2] = "-q"; - args[3] = infile; - args[4] = "-z"; - args[5] = outfile; - args[6] = "-s"; - args[7] = opt.keyfile; - args[8] = (mode == oEncrypt) ? "-af" : "-f"; - args[9 + argc] = NULL; - while (argc--) - args[9 + argc] = argv[argc]; - - if (pipe (cstderr) < 0) - { - log_error (_("could not create pipe: %s\n"), strerror (errno)); - free (args); - return 1; - } - - if (openpty (&master, &slave, NULL, NULL, NULL) == -1) - { - log_error (_("could not create pty: %s\n"), strerror (errno)); - close (cstderr[0]); - close (cstderr[1]); - free (args); - return -1; - } - - /* We don't want to deal with the worst case scenarios. */ - assert (master > 2); - assert (slave > 2); - assert (cstderr[0] > 2); - assert (cstderr[1] > 2); - - pid = fork (); - if (pid < 0) - { - log_error (_("could not fork: %s\n"), strerror (errno)); - close (master); - close (slave); - close (cstderr[0]); - close (cstderr[1]); - free (args); - return 1; - } - else if (pid == 0) - { - /* Child. */ - - /* Close the parent ends. */ - close (master); - close (cstderr[0]); - - /* Change controlling terminal. */ - if (login_tty (slave)) - { - /* It's too early to output a debug message. */ - _exit (1); - } - - dup2 (cstderr[1], 2); - close (cstderr[1]); - - /* Now kick off the engine program. */ - execv (opt.program, args); - log_error (_("execv failed: %s\n"), strerror (errno)); - _exit (1); - } - else - { - /* Parent. */ - char buffer[CONFUCIUS_LINESIZE]; - int buffer_len = 0; - fd_set fds; - int slave_closed = 0; - int stderr_closed = 0; - - close (slave); - close (cstderr[1]); - free (args); - - /* Listen on the output FDs. */ - do - { - FD_ZERO (&fds); - - if (!slave_closed) - FD_SET (master, &fds); - if (!stderr_closed) - FD_SET (cstderr[0], &fds); - - res = select (FD_SETSIZE, &fds, NULL, NULL, NULL); - if (res < 0) - { - log_error (_("select failed: %s\n"), strerror (errno)); - - kill (pid, SIGTERM); - close (master); - close (cstderr[0]); - return 1; - } - - if (FD_ISSET (cstderr[0], &fds)) - { - /* We got some output on stderr. This is just passed - through via the logging facility. */ - - res = read (cstderr[0], &buffer[buffer_len], - sizeof (buffer) - buffer_len - 1); - if (res < 0) - { - log_error (_("read failed: %s\n"), strerror (errno)); - - kill (pid, SIGTERM); - close (master); - close (cstderr[0]); - return 1; - } - else - { - char *newline; - - buffer_len += res; - for (;;) - { - buffer[buffer_len] = '\0'; - newline = strchr (buffer, '\n'); - if (newline) - { - *newline = '\0'; - log_error ("%s\n", buffer); - buffer_len -= newline + 1 - buffer; - memmove (buffer, newline + 1, buffer_len); - } - else if (buffer_len == sizeof (buffer) - 1) - { - /* Overflow. */ - log_error ("%s\n", buffer); - buffer_len = 0; - } - else - break; - } - - if (res == 0) - stderr_closed = 1; - } - } - else if (FD_ISSET (master, &fds)) - { - char data[512]; - - res = read (master, data, sizeof (data)); - if (res < 0) - { - if (errno == EIO) - { - /* Slave-side close leads to readable fd and - EIO. */ - slave_closed = 1; - } - else - { - log_error (_("pty read failed: %s\n"), strerror (errno)); - - kill (pid, SIGTERM); - close (master); - close (cstderr[0]); - return 1; - } - } - else if (res == 0) - /* This never seems to be what happens on slave-side - close. */ - slave_closed = 1; - else - { - /* Check for password prompt. */ - if (data[res - 1] == ':') - { - char *pass; - int canceled; - - /* If this is not the first attempt, the - passphrase seems to be wrong, so clear the - cache. */ - if (tries) - simple_pwclear (cacheid); - - pass = confucius_get_pass (cacheid, - tries ? 1 : 0, &canceled); - if (!pass) - { - kill (pid, SIGTERM); - close (master); - close (cstderr[0]); - return canceled ? SYMC_CANCELED : 1; - } - write (master, pass, strlen (pass)); - write (master, "\n", 1); - confucius_drop_pass (pass); - - tries++; - } - } - } - } - while (!stderr_closed || !slave_closed); - - close (master); - close (cstderr[0]); - - wpid = waitpid (pid, &res, 0); - if (wpid < 0) - { - log_error (_("waitpid failed: %s\n"), strerror (errno)); - - kill (pid, SIGTERM); - /* State of cached password is unclear. Just remove it. */ - simple_pwclear (cacheid); - return 1; - } - else - { - /* Shouldn't happen, as we don't use WNOHANG. */ - assert (wpid != 0); - - if (!WIFEXITED (res)) - { - log_error (_("child aborted with status %i\n"), res); - - /* State of cached password is unclear. Just remove it. */ - simple_pwclear (cacheid); - - return 1; - } - - if (WEXITSTATUS (res)) - { - /* The passphrase was wrong. Remove it from the cache. */ - simple_pwclear (cacheid); - - /* We probably exceeded our number of attempts at guessing - the password. */ - if (tries >= 3) - return SYMC_BAD_PASSPHRASE; - else - return 1; - } - - return 0; - } - } - - /* Not reached. */ -} - - -/* Class confucius main program. If MODE is oEncrypt, encryption is - requested. If it is oDecrypt, decryption is requested. The other - parameters are taken from the global option data. */ -int -confucius_main (int mode, int argc, char *argv[]) -{ - int res; - char *tmpdir; - char *infile; - int infile_from_stdin = 0; - char *outfile; - - tmpdir = confucius_mktmpdir (); - if (!tmpdir) - return 1; - - if (opt.input && !(opt.input[0] == '-' && opt.input[1] == '\0')) - infile = xstrdup (opt.input); - else - { - infile_from_stdin = 1; - - /* TMPDIR + "/" + "in" + "\0". */ - infile = malloc (strlen (tmpdir) + 1 + 2 + 1); - if (!infile) - { - log_error (_("cannot allocate infile string: %s\n"), - strerror (errno)); - rmdir (tmpdir); - return 1; - } - strcpy (infile, tmpdir); - strcat (infile, "/in"); - } - - /* TMPDIR + "/" + "out" + "\0". */ - outfile = malloc (strlen (tmpdir) + 1 + 3 + 1); - if (!outfile) - { - log_error (_("cannot allocate outfile string: %s\n"), strerror (errno)); - free (infile); - rmdir (tmpdir); - return 1; - } - strcpy (outfile, tmpdir); - strcat (outfile, "/out"); - - if (infile_from_stdin) - { - /* Create INFILE and fill it with content. */ - res = confucius_copy_file ("-", infile, mode == oEncrypt); - if (res) - { - free (outfile); - free (infile); - rmdir (tmpdir); - return res; - } - } - - /* Run the engine and thus create the output file, handling - passphrase retrieval. */ - res = confucius_process (mode, infile, outfile, argc, argv); - if (res) - { - remove_file (outfile, mode == oDecrypt); - if (infile_from_stdin) - remove_file (infile, mode == oEncrypt); - free (outfile); - free (infile); - rmdir (tmpdir); - return res; - } - - /* Dump the output file to stdout. */ - res = confucius_copy_file (outfile, "-", mode == oDecrypt); - if (res) - { - remove_file (outfile, mode == oDecrypt); - if (infile_from_stdin) - remove_file (infile, mode == oEncrypt); - free (outfile); - free (infile); - rmdir (tmpdir); - return res; - } - - remove_file (outfile, mode == oDecrypt); - if (infile_from_stdin) - remove_file (infile, mode == oEncrypt); - free (outfile); - free (infile); - rmdir (tmpdir); - return 0; -} - - -/* symcryptrun's entry point. */ -int -main (int argc, char **argv) -{ - gpgrt_argparse_t pargs; - int orig_argc; - char **orig_argv; - char *last_configname = NULL; - const char *configname = NULL; - int mode = 0; - int res; - char *logfile = NULL; - - early_system_init (); - gpgrt_set_strusage (my_strusage); - log_set_prefix ("symcryptrun", GPGRT_LOG_WITH_PREFIX); - - /* Make sure that our subsystems are ready. */ - i18n_init(); - init_common_subsystems (&argc, &argv); - - /* Check whether we have a config file given on the commandline */ - orig_argc = argc; - orig_argv = argv; - pargs.argc = &argc; - pargs.argv = &argv; - pargs.flags= ARGPARSE_FLAG_KEEP|ARGPARSE_FLAG_NOVERSION; - while (gpgrt_argparse (NULL, &pargs, opts)) - { - if (pargs.r_opt == oHomedir) - gnupg_set_homedir (pargs.r.ret_str); - } - /* Reset the flags. */ - pargs.flags &= ~(ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION); - - /* The configuraton directories for use by gpgrt_argparser. */ - gpgrt_set_confdir (GPGRT_CONFDIR_SYS, gnupg_sysconfdir ()); - gpgrt_set_confdir (GPGRT_CONFDIR_USER, gnupg_homedir ()); - - argc = orig_argc; - argv = orig_argv; - pargs.argc = &argc; - pargs.argv = &argv; - /* We are re-using the struct, thus the reset flag. We OR the - * flags so that the internal intialized flag won't be cleared. */ - pargs.flags |= (ARGPARSE_FLAG_RESET - | ARGPARSE_FLAG_KEEP - | ARGPARSE_FLAG_SYS - | ARGPARSE_FLAG_USER); - - /* Parse the command line. */ - while (gpgrt_argparser (&pargs, opts, "symcryptrun.conf")) - { - switch (pargs.r_opt) - { - case ARGPARSE_CONFFILE: - { - if (pargs.r_type) - { - xfree (last_configname); - last_configname = xstrdup (pargs.r.ret_str); - configname = last_configname; - } - else - configname = NULL; - } - break; - - case oDecrypt: mode = oDecrypt; break; - case oEncrypt: mode = oEncrypt; break; - - case oQuiet: opt.quiet = 1; break; - case oVerbose: opt.verbose++; break; - case oNoVerbose: opt.verbose = 0; break; - - case oClass: opt.class = pargs.r.ret_str; break; - case oProgram: opt.program = pargs.r.ret_str; break; - case oKeyfile: opt.keyfile = pargs.r.ret_str; break; - case oInput: opt.input = pargs.r.ret_str; break; - - case oLogFile: logfile = pargs.r.ret_str; break; - - case oHomedir: /* Ignore this option here. */; break; - - default: - if (configname) - pargs.err = ARGPARSE_PRINT_WARNING; - else - pargs.err = ARGPARSE_PRINT_ERROR; - break; - } - } - gpgrt_argparse (NULL, &pargs, NULL); /* Release internal state. */ - - xfree (last_configname); - - if (!mode) - log_error (_("either %s or %s must be given\n"), - "--decrypt", "--encrypt"); - - if (log_get_errorcount (0)) - exit (1); - - if (logfile) - log_set_file (logfile); - - gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); - setup_libgcrypt_logging (); - gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0); - - /* Tell simple-pwquery about the standard socket name. */ - { - char *tmp = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL); - simple_pw_set_socket (tmp); - xfree (tmp); - } - - if (!opt.class) - { - log_error (_("no class provided\n")); - res = 1; - } - else if (!strcmp (opt.class, "confucius")) - { - res = confucius_main (mode, argc, argv); - } - else - { - log_error (_("class %s is not supported\n"), opt.class); - res = 1; - } - - return res; -}