mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-21 14:47:03 +01:00
Keep on hacking on g13. A simple --create and --mount does now work.
A hacked up encfs is required.
This commit is contained in:
parent
9b345f2a8a
commit
536b6ab09f
@ -1,3 +1,8 @@
|
||||
2009-10-12 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac: Use -O3 because newer gcc versions require that
|
||||
for uninitialized variable warnings.
|
||||
|
||||
2009-09-23 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (HAVE_ASSUAN_SET_IO_MONITOR): Remove test.
|
||||
|
3
NEWS
3
NEWS
@ -1,6 +1,9 @@
|
||||
Noteworthy changes in version 2.1 (under development)
|
||||
-------------------------------------------------
|
||||
|
||||
* Encrypted OpenPGP messages with trailing data (e.g. other OpenPGP
|
||||
packets) are now correctly parsed.
|
||||
|
||||
|
||||
Noteworthy changes in version 2.0.13 (2009-09-04)
|
||||
-------------------------------------------------
|
||||
|
@ -1,3 +1,7 @@
|
||||
2009-10-13 Werner Koch <wk@g10code.com>
|
||||
|
||||
* exechelp.c (gnupg_kill_process): New.
|
||||
|
||||
2009-09-29 Werner Koch <wk@g10code.com>
|
||||
|
||||
* exechelp.c (create_inheritable_pipe): Rename to
|
||||
|
@ -1102,3 +1102,28 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
|
||||
return 0;
|
||||
#endif /* !HAVE_W32_SYSTEM*/
|
||||
}
|
||||
|
||||
|
||||
/* Kill a process; that is send an appropriate signal to the process.
|
||||
gnupg_wait_process must be called to actually remove the process
|
||||
from the system. An invalid PID is ignored. */
|
||||
void
|
||||
gnupg_kill_process (pid_t pid)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* Older versions of libassuan set PID to 0 on Windows to indicate
|
||||
an invalid value. */
|
||||
if (pid != (pid_t) INVALID_HANDLE_VALUE && pid != 0)
|
||||
{
|
||||
HANDLE process = (HANDLE) pid;
|
||||
|
||||
/* Arbitrary error code. */
|
||||
TerminateProcess (process, 1);
|
||||
}
|
||||
#else
|
||||
if (pid != (pid_t)(-1))
|
||||
{
|
||||
kill (pid, SIGTERM);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -86,6 +86,12 @@ gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
|
||||
gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode);
|
||||
|
||||
|
||||
/* Kill a process; that is send an appropriate signal to the process.
|
||||
gnupg_wait_process must be called to actually remove the process
|
||||
from the system. An invalid PID is ignored. */
|
||||
void gnupg_kill_process (pid_t pid);
|
||||
|
||||
|
||||
/* Spawn a new process and immediatley detach from it. The name of
|
||||
the program to exec is PGMNAME and its arguments are in ARGV (the
|
||||
programname is automatically passed as first argument).
|
||||
|
@ -1262,22 +1262,22 @@ iobuf_is_pipe_filename (const char *fname)
|
||||
|
||||
|
||||
/* Either open the file specified by the file descriptor FD or - if FD
|
||||
is GNUPG_INVALID_FD - the file with name FNAME. As of now MODE is
|
||||
assumed to be "rb" if FNAME is used. In contrast to iobuf_fdopen
|
||||
the fiel descriptor FD will not be closed during an iobuf_close. */
|
||||
is -1, the file with name FNAME. As of now MODE is assumed to be
|
||||
"rb" if FNAME is used. In contrast to iobuf_fdopen the file
|
||||
descriptor FD will not be closed during an iobuf_close. */
|
||||
iobuf_t
|
||||
iobuf_open_fd_or_name (gnupg_fd_t fd, const char *fname, const char *mode)
|
||||
iobuf_open_fd_or_name (int fd, const char *fname, const char *mode)
|
||||
{
|
||||
iobuf_t a;
|
||||
|
||||
if (fd == GNUPG_INVALID_FD)
|
||||
if (fd == -1)
|
||||
a = iobuf_open (fname);
|
||||
else
|
||||
{
|
||||
gnupg_fd_t fd2;
|
||||
int fd2;
|
||||
|
||||
fd2 = dup (fd);
|
||||
if (fd2 == GNUPG_INVALID_FD)
|
||||
if (fd2 == -1)
|
||||
a = NULL;
|
||||
else
|
||||
a = iobuf_fdopen (fd2, mode);
|
||||
|
@ -1230,7 +1230,7 @@ if test "$GCC" = yes; then
|
||||
# warning options and the user should have a chance of overriding
|
||||
# them.
|
||||
if test "$USE_MAINTAINER_MODE" = "yes"; then
|
||||
CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
|
||||
CFLAGS="$CFLAGS -O3 -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
|
||||
CFLAGS="$CFLAGS -Wformat -Wno-format-y2k -Wformat-security"
|
||||
AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers])
|
||||
_gcc_cflags_save=$CFLAGS
|
||||
|
@ -31,7 +31,9 @@ g13_SOURCES = \
|
||||
keyblob.h \
|
||||
utils.c utils.h \
|
||||
create.c create.h \
|
||||
mount.c mount.h \
|
||||
call-gpg.c call-gpg.h \
|
||||
runner.c runner.h \
|
||||
backend.c backend.h \
|
||||
be-encfs.c be-encfs.h \
|
||||
be-truecrypt.c be-truecrypt.h
|
||||
|
@ -41,6 +41,22 @@ no_such_backend (int conttype)
|
||||
}
|
||||
|
||||
|
||||
/* Return true if CONTTYPE is supported by us. */
|
||||
int
|
||||
be_is_supported_conttype (int conttype)
|
||||
{
|
||||
switch (conttype)
|
||||
{
|
||||
case CONTTYPE_ENCFS:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* If the backend requires a separate file or directory for the
|
||||
container, return its name by computing it from FNAME which gives
|
||||
the g13 filename. The new file name is allocated and stored at
|
||||
@ -81,3 +97,37 @@ be_create_new_keys (int conttype, membuf_t *mb)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Dispatcher to the backend's create function. */
|
||||
gpg_error_t
|
||||
be_create_container (ctrl_t ctrl, int conttype,
|
||||
const char *fname, int fd, tupledesc_t tuples)
|
||||
{
|
||||
(void)fd; /* Not yet used. */
|
||||
|
||||
switch (conttype)
|
||||
{
|
||||
case CONTTYPE_ENCFS:
|
||||
return be_encfs_create_container (ctrl, fname, tuples);
|
||||
|
||||
default:
|
||||
return no_such_backend (conttype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Dispatcher to the backend's mount function. */
|
||||
gpg_error_t
|
||||
be_mount_container (ctrl_t ctrl, int conttype,
|
||||
const char *fname, const char *mountpoint,
|
||||
tupledesc_t tuples)
|
||||
{
|
||||
switch (conttype)
|
||||
{
|
||||
case CONTTYPE_ENCFS:
|
||||
return be_encfs_mount_container (ctrl, fname, mountpoint, tuples);
|
||||
|
||||
default:
|
||||
return no_such_backend (conttype);
|
||||
}
|
||||
}
|
||||
|
@ -21,12 +21,20 @@
|
||||
#define G13_BACKEND_H
|
||||
|
||||
#include "../common/membuf.h"
|
||||
#include "utils.h" /* For tupledesc_t */
|
||||
|
||||
|
||||
int be_is_supported_conttype (int conttype);
|
||||
gpg_error_t be_get_detached_name (int conttype, const char *fname,
|
||||
char **r_name, int *r_isdir);
|
||||
gpg_error_t be_create_new_keys (int conttype, membuf_t *mb);
|
||||
|
||||
gpg_error_t be_create_container (ctrl_t ctrl, int conttype,
|
||||
const char *fname, int fd,
|
||||
tupledesc_t tuples);
|
||||
gpg_error_t be_mount_container (ctrl_t ctrl, int conttype,
|
||||
const char *fname, const char *mountpoint,
|
||||
tupledesc_t tuples);
|
||||
|
||||
|
||||
#endif /*G13_BACKEND_H*/
|
||||
|
||||
|
413
g13/be-encfs.c
413
g13/be-encfs.c
@ -23,12 +23,301 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "g13.h"
|
||||
#include "i18n.h"
|
||||
#include "keyblob.h"
|
||||
#include "be-encfs.h"
|
||||
#include "runner.h"
|
||||
#include "../common/exechelp.h"
|
||||
|
||||
|
||||
/* Command values used to run the encfs tool. */
|
||||
enum encfs_cmds
|
||||
{
|
||||
ENCFS_CMD_CREATE,
|
||||
ENCFS_CMD_MOUNT,
|
||||
ENCFS_CMD_UMOUNT
|
||||
};
|
||||
|
||||
|
||||
/* An object to keep the private state of the encfs tool. It is
|
||||
released by encfs_handler_cleanup. */
|
||||
struct encfs_parm_s
|
||||
{
|
||||
enum encfs_cmds cmd; /* The current command. */
|
||||
tupledesc_t tuples; /* NULL or the tuples object. */
|
||||
char *mountpoint; /* The mountpoint. */
|
||||
};
|
||||
typedef struct encfs_parm_s *encfs_parm_t;
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
send_cmd_bin (runner_t runner, const void *data, size_t datalen)
|
||||
{
|
||||
return runner_send_line (runner, data, datalen);
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
send_cmd (runner_t runner, const char *string)
|
||||
{
|
||||
log_debug ("sending command -->%s<--\n", string);
|
||||
return send_cmd_bin (runner, string, strlen (string));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
run_umount_helper (const char *mountpoint)
|
||||
{
|
||||
gpg_error_t err;
|
||||
const char pgmname[] = "/usr/bin/fusermount";
|
||||
const char *args[3];
|
||||
|
||||
args[0] = "-u";
|
||||
args[1] = mountpoint;
|
||||
args[2] = NULL;
|
||||
|
||||
err = gnupg_spawn_process_detached (pgmname, args, NULL);
|
||||
if (err)
|
||||
log_error ("failed to run `%s': %s\n",
|
||||
pgmname, gpg_strerror (err));
|
||||
}
|
||||
|
||||
|
||||
/* Handle one line of the encfs tool's output. This function is
|
||||
allowed to modify the content of BUFFER. */
|
||||
static gpg_error_t
|
||||
handle_status_line (runner_t runner, const char *line,
|
||||
enum encfs_cmds cmd, tupledesc_t tuples)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
/* Check that encfs understands our new options. */
|
||||
if (!strncmp (line, "$STATUS$", 8))
|
||||
{
|
||||
for (line +=8; *line && spacep (line); line++)
|
||||
;
|
||||
log_info ("got status `%s'\n", line);
|
||||
if (!strcmp (line, "fuse_main_start"))
|
||||
{
|
||||
/* Send a special error code back to let the caller know
|
||||
that everything has been setup by encfs. */
|
||||
err = gpg_error (GPG_ERR_UNFINISHED);
|
||||
}
|
||||
else
|
||||
err = 0;
|
||||
}
|
||||
else if (!strncmp (line, "$PROMPT$", 8))
|
||||
{
|
||||
for (line +=8; *line && spacep (line); line++)
|
||||
;
|
||||
log_info ("got prompt `%s'\n", line);
|
||||
if (!strcmp (line, "create_root_dir"))
|
||||
err = send_cmd (runner, cmd == ENCFS_CMD_CREATE? "y":"n");
|
||||
else if (!strcmp (line, "create_mount_point"))
|
||||
err = send_cmd (runner, "y");
|
||||
else if (!strcmp (line, "passwd")
|
||||
|| !strcmp (line, "new_passwd"))
|
||||
{
|
||||
if (tuples)
|
||||
{
|
||||
size_t n;
|
||||
const void *value;
|
||||
|
||||
value = find_tuple (tuples, KEYBLOB_TAG_ENCKEY, &n);
|
||||
if (!value)
|
||||
err = gpg_error (GPG_ERR_INV_SESSION_KEY);
|
||||
else if ((err = send_cmd_bin (runner, value, n)))
|
||||
{
|
||||
if (gpg_err_code (err) == GPG_ERR_BUG
|
||||
&& gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
|
||||
err = gpg_error (GPG_ERR_INV_SESSION_KEY);
|
||||
}
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
}
|
||||
else
|
||||
err = send_cmd (runner, ""); /* Default to send an empty line. */
|
||||
}
|
||||
else if (strstr (line, "encfs: unrecognized option '"))
|
||||
err = gpg_error (GPG_ERR_INV_ENGINE);
|
||||
else
|
||||
err = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* The main processing function as used by the runner. */
|
||||
static gpg_error_t
|
||||
encfs_handler (void *opaque, runner_t runner, const char *status_line)
|
||||
{
|
||||
encfs_parm_t parm = opaque;
|
||||
gpg_error_t err;
|
||||
|
||||
if (!parm || !runner)
|
||||
return gpg_error (GPG_ERR_BUG);
|
||||
if (!status_line)
|
||||
{
|
||||
/* Runner requested internal flushing - nothing to do here. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = handle_status_line (runner, status_line, parm->cmd, parm->tuples);
|
||||
if (gpg_err_code (err) == GPG_ERR_UNFINISHED
|
||||
&& gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
|
||||
{
|
||||
err = 0;
|
||||
/* No more need for the tuples. */
|
||||
destroy_tupledesc (parm->tuples);
|
||||
parm->tuples = NULL;
|
||||
|
||||
if (parm->cmd == ENCFS_CMD_CREATE)
|
||||
{
|
||||
/* The encfs tool keeps on running after creation of the
|
||||
container. We don't want that and thus need to stop the
|
||||
encfs process. */
|
||||
run_umount_helper (parm->mountpoint);
|
||||
/* In case the umount helper does not work we try to kill
|
||||
the engine. FIXME: We should figure out how to make
|
||||
fusermount work. */
|
||||
runner_cancel (runner);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Called by the runner to cleanup the private data. */
|
||||
static void
|
||||
encfs_handler_cleanup (void *opaque)
|
||||
{
|
||||
encfs_parm_t parm = opaque;
|
||||
|
||||
if (!parm)
|
||||
return;
|
||||
|
||||
destroy_tupledesc (parm->tuples);
|
||||
xfree (parm->mountpoint);
|
||||
xfree (parm);
|
||||
}
|
||||
|
||||
|
||||
/* Run the encfs tool. */
|
||||
static gpg_error_t
|
||||
run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
|
||||
const char *rawdir, const char *mountpoint, tupledesc_t tuples)
|
||||
{
|
||||
gpg_error_t err;
|
||||
encfs_parm_t parm;
|
||||
runner_t runner = NULL;
|
||||
int outbound[2] = { -1, -1 };
|
||||
int inbound[2] = { -1, -1 };
|
||||
const char *pgmname;
|
||||
const char *argv[10];
|
||||
pid_t pid = (pid_t)(-1);
|
||||
int idx;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
parm = xtrycalloc (1, sizeof *parm);
|
||||
if (!parm)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
parm->cmd = cmd;
|
||||
parm->tuples = ref_tupledesc (tuples);
|
||||
parm->mountpoint = xtrystrdup (mountpoint);
|
||||
if (!parm->mountpoint)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
{
|
||||
static int namecounter;
|
||||
char buffer[50];
|
||||
|
||||
snprintf (buffer, sizeof buffer, "encfs-%d", ++namecounter);
|
||||
err = runner_new (&runner, buffer);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = gnupg_create_inbound_pipe (inbound);
|
||||
if (!err)
|
||||
err = gnupg_create_outbound_pipe (outbound);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
pgmname = "/usr/bin/encfs";
|
||||
idx = 0;
|
||||
argv[idx++] = "-f";
|
||||
argv[idx++] = "-v";
|
||||
argv[idx++] = "--stdinpass";
|
||||
argv[idx++] = "--annotate";
|
||||
argv[idx++] = rawdir;
|
||||
argv[idx++] = mountpoint;
|
||||
argv[idx++] = NULL;
|
||||
assert (idx <= DIM (argv));
|
||||
|
||||
err = gnupg_spawn_process_fd (pgmname, argv,
|
||||
outbound[0], -1, inbound[1], &pid);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error spawning `%s': %s\n", pgmname, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
close (outbound[0]); outbound[0] = -1;
|
||||
close ( inbound[1]); inbound[1] = -1;
|
||||
|
||||
runner_set_fds (runner, inbound[0], outbound[1]);
|
||||
inbound[0] = -1; /* Now owned by RUNNER. */
|
||||
outbound[1] = -1; /* Now owned by RUNNER. */
|
||||
|
||||
runner_set_handler (runner, encfs_handler, encfs_handler_cleanup, parm);
|
||||
parm = NULL; /* Now owned by RUNNER. */
|
||||
|
||||
runner_set_pid (runner, pid);
|
||||
pid = (pid_t)(-1); /* The process is now owned by RUNNER. */
|
||||
|
||||
err = runner_spawn (runner);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
log_info ("running `%s' in the background\n", pgmname);
|
||||
|
||||
leave:
|
||||
if (inbound[0] != -1)
|
||||
close (inbound[0]);
|
||||
if (inbound[1] != -1)
|
||||
close (inbound[1]);
|
||||
if (outbound[0] != -1)
|
||||
close (outbound[0]);
|
||||
if (outbound[1] != -1)
|
||||
close (outbound[1]);
|
||||
if (pid != (pid_t)(-1))
|
||||
{
|
||||
gnupg_wait_process (pgmname, pid, NULL);
|
||||
}
|
||||
runner_release (runner);
|
||||
encfs_handler_cleanup (parm);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* See be_get_detached_name for a description. Note that the
|
||||
dispatcher code makes sure that NULL is stored at R_NAME before
|
||||
calling us. */
|
||||
@ -49,10 +338,134 @@ be_encfs_get_detached_name (const char *fname, char **r_name, int *r_isdir)
|
||||
}
|
||||
|
||||
|
||||
/* Create a new session key and append it as a tuple to the memory
|
||||
buffer MB.
|
||||
|
||||
The EncFS daemon takes a passphrase from stdin and internally
|
||||
mangles it by means of some KDF from OpenSSL. We want to store a
|
||||
binary key but we need to make sure that certain characters are not
|
||||
used because the EncFS utility reads it from stdin and obviously
|
||||
acts on some of the characters. This we replace CR (in case of an
|
||||
MSDOS version of EncFS), LF (the delimiter used by EncFS) and Nul
|
||||
(because it is unlikely to work). We use 32 bytes (256 bit)
|
||||
because that is sufficient for the largest cipher (AES-256) and in
|
||||
addition gives enough margin for a possible entropy degradation by
|
||||
the KDF. */
|
||||
gpg_error_t
|
||||
be_encfs_create_new_keys (membuf_t *mb)
|
||||
{
|
||||
char *buffer;
|
||||
int i, j;
|
||||
|
||||
/* Allocate a buffer of 32 bytes plus 8 spare bytes we may need to
|
||||
replace the unwanted values. */
|
||||
buffer = xtrymalloc_secure (32+8);
|
||||
if (!buffer)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
/* Randomize the buffer. STRONG random should be enough as it is a
|
||||
good compromise between security and performance. The
|
||||
anticipated usage of this tool is the quite often creation of new
|
||||
containers and thus this should not deplete the system's entropy
|
||||
tool too much. */
|
||||
gcry_randomize (buffer, 32+8, GCRY_STRONG_RANDOM);
|
||||
for (i=j=0; i < 32; i++)
|
||||
{
|
||||
if (buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == 0 )
|
||||
{
|
||||
/* Replace. */
|
||||
if (j == 8)
|
||||
{
|
||||
/* Need to get more random. */
|
||||
gcry_randomize (buffer+32, 8, GCRY_STRONG_RANDOM);
|
||||
j = 0;
|
||||
}
|
||||
buffer[i] = buffer[32+j];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the key. */
|
||||
append_tuple (mb, KEYBLOB_TAG_ENCKEY, buffer, 32);
|
||||
|
||||
/* Free the temporary buffer. */
|
||||
wipememory (buffer, 32+8); /* A failsafe extra wiping. */
|
||||
xfree (buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Create the container described by the filename FNAME and the keyblob
|
||||
information in TUPLES. */
|
||||
gpg_error_t
|
||||
be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int dummy;
|
||||
char *containername = NULL;
|
||||
char *mountpoint = NULL;
|
||||
|
||||
err = be_encfs_get_detached_name (fname, &containername, &dummy);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
mountpoint = xtrystrdup ("/tmp/.#g13_XXXXXX");
|
||||
if (!mountpoint)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
if (!mkdtemp (mountpoint))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error (_("can't create directory `%s': %s\n"),
|
||||
"/tmp/g13-XXXXXX", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = run_encfs_tool (ctrl, ENCFS_CMD_CREATE, containername, mountpoint,
|
||||
tuples);
|
||||
|
||||
/* In any case remove the temporary mount point. */
|
||||
if (rmdir (mountpoint))
|
||||
log_error ("error removing temporary mount point `%s': %s\n",
|
||||
mountpoint, gpg_strerror (gpg_error_from_syserror ()));
|
||||
|
||||
|
||||
leave:
|
||||
xfree (containername);
|
||||
xfree (mountpoint);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Mount the container described by the filename FNAME and the keyblob
|
||||
information in TUPLES. */
|
||||
gpg_error_t
|
||||
be_encfs_mount_container (ctrl_t ctrl,
|
||||
const char *fname, const char *mountpoint,
|
||||
tupledesc_t tuples)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int dummy;
|
||||
char *containername = NULL;
|
||||
|
||||
if (!mountpoint)
|
||||
{
|
||||
log_error ("the encfs backend requires an explicit mountpoint\n");
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = be_encfs_get_detached_name (fname, &containername, &dummy);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
err = run_encfs_tool (ctrl, ENCFS_CMD_MOUNT, containername, mountpoint,
|
||||
tuples);
|
||||
|
||||
leave:
|
||||
xfree (containername);
|
||||
return err;
|
||||
}
|
||||
|
@ -26,6 +26,15 @@ gpg_error_t be_encfs_get_detached_name (const char *fname,
|
||||
char **r_name, int *r_isdir);
|
||||
gpg_error_t be_encfs_create_new_keys (membuf_t *mb);
|
||||
|
||||
gpg_error_t be_encfs_create_container (ctrl_t ctrl,
|
||||
const char *fname,
|
||||
tupledesc_t tuples);
|
||||
|
||||
gpg_error_t be_encfs_mount_container (ctrl_t ctrl,
|
||||
const char *fname,
|
||||
const char *mountpoint,
|
||||
tupledesc_t tuples);
|
||||
|
||||
|
||||
#endif /*G13_BE_ENCFS_H*/
|
||||
|
||||
|
132
g13/call-gpg.c
132
g13/call-gpg.c
@ -43,7 +43,7 @@ start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
|
||||
gpg_error_t err;
|
||||
assuan_context_t ctx = NULL;
|
||||
const char *pgmname;
|
||||
const char *argv[6];
|
||||
const char *argv[7];
|
||||
int no_close_list[5];
|
||||
int i;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
@ -464,3 +464,133 @@ gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Call GPG to decrypt a block of data.
|
||||
|
||||
|
||||
*/
|
||||
gpg_error_t
|
||||
gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
|
||||
void **r_plain, size_t *r_plainlen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
assuan_context_t ctx;
|
||||
int outbound_fds[2] = { -1, -1 };
|
||||
int inbound_fds[2] = { -1, -1 };
|
||||
pth_t writer_tid = NULL;
|
||||
pth_t reader_tid = NULL;
|
||||
gpg_error_t writer_err, reader_err;
|
||||
membuf_t reader_mb;
|
||||
|
||||
*r_plain = NULL;
|
||||
*r_plainlen = 0;
|
||||
|
||||
/* Init the memory buffer to receive the encrypted stuff. */
|
||||
init_membuf_secure (&reader_mb, 1024);
|
||||
|
||||
/* Create two pipes. */
|
||||
err = gnupg_create_outbound_pipe (outbound_fds);
|
||||
if (!err)
|
||||
err = gnupg_create_inbound_pipe (inbound_fds);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Start GPG and send the INPUT and OUTPUT commands. */
|
||||
err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx);
|
||||
if (err)
|
||||
goto leave;
|
||||
close (outbound_fds[0]); outbound_fds[0] = -1;
|
||||
close (inbound_fds[1]); inbound_fds[1] = -1;
|
||||
|
||||
/* Start a writer thread to feed the INPUT command of the server. */
|
||||
err = start_writer (outbound_fds[1], ciph, ciphlen,
|
||||
&writer_tid, &writer_err);
|
||||
if (err)
|
||||
return err;
|
||||
outbound_fds[1] = -1; /* The thread owns the FD now. */
|
||||
|
||||
/* Start a reader thread to eat from the OUTPUT command of the
|
||||
server. */
|
||||
err = start_reader (inbound_fds[0], &reader_mb,
|
||||
&reader_tid, &reader_err);
|
||||
if (err)
|
||||
return err;
|
||||
outbound_fds[0] = -1; /* The thread owns the FD now. */
|
||||
|
||||
/* Run the decryption. */
|
||||
err = assuan_transact (ctx, "DECRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (err)
|
||||
{
|
||||
log_error ("the engine's DECRYPT command failed: %s <%s>\n",
|
||||
gpg_strerror (err), gpg_strsource (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Wait for reader and return the data. */
|
||||
if (!pth_join (reader_tid, NULL))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
reader_tid = NULL;
|
||||
if (reader_err)
|
||||
{
|
||||
err = reader_err;
|
||||
log_error ("read error in reader thread: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Wait for the writer to catch a writer error. */
|
||||
if (!pth_join (writer_tid, NULL))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
writer_tid = NULL;
|
||||
if (writer_err)
|
||||
{
|
||||
err = writer_err;
|
||||
log_error ("write error in writer thread: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Return the data. */
|
||||
*r_plain = get_membuf (&reader_mb, r_plainlen);
|
||||
if (!*r_plain)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error while storing the data in the reader thread: %s\n",
|
||||
gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
leave:
|
||||
if (reader_tid)
|
||||
{
|
||||
pth_cancel (reader_tid);
|
||||
pth_join (reader_tid, NULL);
|
||||
}
|
||||
if (writer_tid)
|
||||
{
|
||||
pth_cancel (writer_tid);
|
||||
pth_join (writer_tid, NULL);
|
||||
}
|
||||
if (outbound_fds[0] != -1)
|
||||
close (outbound_fds[0]);
|
||||
if (outbound_fds[1] != -1)
|
||||
close (outbound_fds[1]);
|
||||
if (inbound_fds[0] != -1)
|
||||
close (inbound_fds[0]);
|
||||
if (inbound_fds[1] != -1)
|
||||
close (inbound_fds[1]);
|
||||
release_gpg (ctx);
|
||||
xfree (get_membuf (&reader_mb, NULL));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
gpg_error_t gpg_encrypt_blob (ctrl_t ctrl,
|
||||
const void *plain, size_t plainlen,
|
||||
void **r_ciph, size_t *r_ciphlen);
|
||||
gpg_error_t gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen,
|
||||
void **r_plain, size_t *r_plainlen);
|
||||
|
||||
|
||||
|
||||
|
28
g13/create.c
28
g13/create.c
@ -79,9 +79,9 @@ create_new_keyblob (ctrl_t ctrl, int is_detached,
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Just for testing. */
|
||||
append_tuple (&mb, KEYBLOB_TAG_FILLER, "filler", 6);
|
||||
|
||||
|
||||
*r_blob = get_membuf (&mb, r_bloblen);
|
||||
if (!*r_blob)
|
||||
{
|
||||
@ -122,7 +122,7 @@ encrypt_keyblob (ctrl_t ctrl, void *keyblob, size_t keybloblen,
|
||||
appropriate header. This fucntion is called with a lock file in
|
||||
place and after checking that the filename does not exists. */
|
||||
static gpg_error_t
|
||||
write_keyblob (ctrl_t ctrl, const char *filename,
|
||||
write_keyblob (const char *filename,
|
||||
const void *keyblob, size_t keybloblen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
@ -152,7 +152,7 @@ write_keyblob (ctrl_t ctrl, const char *filename,
|
||||
packet[4] = 0;
|
||||
packet[5] = 26;
|
||||
memcpy (packet+6, "GnuPG/G13", 10); /* Packet subtype. */
|
||||
packet[16] = 1; /* G13 packet format. */
|
||||
packet[16] = 1; /* G13 packet format version. */
|
||||
packet[17] = 0; /* Reserved. */
|
||||
packet[18] = 0; /* Reserved. */
|
||||
packet[19] = 0; /* OS Flag. */
|
||||
@ -202,7 +202,7 @@ write_keyblob (ctrl_t ctrl, const char *filename,
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
|
||||
|
||||
writeerr:
|
||||
@ -220,7 +220,7 @@ write_keyblob (ctrl_t ctrl, const char *filename,
|
||||
using the current settings. If the file already exists an error is
|
||||
returned. */
|
||||
gpg_error_t
|
||||
create_new_container (ctrl_t ctrl, const char *filename)
|
||||
g13_create_container (ctrl_t ctrl, const char *filename)
|
||||
{
|
||||
gpg_error_t err;
|
||||
dotlock_t lock;
|
||||
@ -230,6 +230,7 @@ create_new_container (ctrl_t ctrl, const char *filename)
|
||||
size_t enckeybloblen;
|
||||
char *detachedname = NULL;
|
||||
int detachedisdir;
|
||||
tupledesc_t tuples = NULL;
|
||||
|
||||
/* A quick check to see that no container with that name already
|
||||
exists. */
|
||||
@ -286,17 +287,28 @@ create_new_container (ctrl_t ctrl, const char *filename)
|
||||
&enckeyblob, &enckeybloblen);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Put a copy of the keyblob into a tuple structure. */
|
||||
err = create_tupledesc (&tuples, keyblob, keybloblen);
|
||||
if (err)
|
||||
goto leave;
|
||||
keyblob = NULL;
|
||||
/* if (opt.verbose) */
|
||||
/* dump_keyblob (tuples); */
|
||||
|
||||
/* Write out the header, the encrypted keyblob and some padding. */
|
||||
err = write_keyblob (ctrl, filename, enckeyblob, enckeybloblen);
|
||||
err = write_keyblob (filename, enckeyblob, enckeybloblen);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Create and append the container. */
|
||||
|
||||
/* Create and append the container. FIXME: We should pass the
|
||||
estream object in addition to the filename, so that the backend
|
||||
can append the container to the g13 file. */
|
||||
err = be_create_container (ctrl, ctrl->conttype, filename, -1, tuples);
|
||||
|
||||
|
||||
leave:
|
||||
destroy_tupledesc (tuples);
|
||||
xfree (detachedname);
|
||||
xfree (enckeyblob);
|
||||
xfree (keyblob);
|
||||
|
@ -20,7 +20,7 @@
|
||||
#ifndef G13_CREATE_H
|
||||
#define G13_CREATE_H
|
||||
|
||||
gpg_error_t create_new_container (ctrl_t ctrl, const char *filename);
|
||||
gpg_error_t g13_create_container (ctrl_t ctrl, const char *filename);
|
||||
|
||||
|
||||
#endif /*G13_CREATE_H*/
|
||||
|
127
g13/g13.c
127
g13/g13.c
@ -35,8 +35,10 @@
|
||||
#include "i18n.h"
|
||||
#include "sysutils.h"
|
||||
#include "gc-opt-flags.h"
|
||||
#include "create.h"
|
||||
#include "keyblob.h"
|
||||
#include "./runner.h"
|
||||
#include "./create.h"
|
||||
#include "./mount.h"
|
||||
|
||||
|
||||
enum cmd_and_opt_values {
|
||||
@ -84,6 +86,7 @@ enum cmd_and_opt_values {
|
||||
oHomedir,
|
||||
oWithColons,
|
||||
oDryRun,
|
||||
oNoDetach,
|
||||
|
||||
oRecipient,
|
||||
|
||||
@ -111,6 +114,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
|
||||
ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
|
||||
ARGPARSE_s_n (oNoTTY, "no-tty", N_("don't use the terminal at all")),
|
||||
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
|
||||
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write log output to FILE")),
|
||||
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
|
||||
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
|
||||
@ -329,6 +333,7 @@ main ( int argc, char **argv)
|
||||
int nogreeting = 0;
|
||||
int debug_wait = 0;
|
||||
int use_random_seed = 1;
|
||||
int nodetach = 0;
|
||||
int nokeysetup = 0;
|
||||
enum cmd_and_opt_values cmd = 0;
|
||||
struct server_control_s ctrl;
|
||||
@ -499,6 +504,8 @@ main ( int argc, char **argv)
|
||||
|
||||
case oAuditLog: auditlog = pargs.r.ret_str; break;
|
||||
|
||||
case oNoDetach: nodetach = 1; break;
|
||||
|
||||
case oDebug: debug_value |= pargs.r.ret_ulong; break;
|
||||
case oDebugAll: debug_value = ~0; break;
|
||||
case oDebugNone: debug_value = 0; break;
|
||||
@ -677,16 +684,47 @@ main ( int argc, char **argv)
|
||||
{
|
||||
if (argc != 1)
|
||||
wrong_args ("--create filename");
|
||||
err = create_new_container (&ctrl, argv[0]);
|
||||
err = g13_create_container (&ctrl, argv[0]);
|
||||
if (err)
|
||||
log_error ("error creating a new container: %s <%s>\n",
|
||||
gpg_strerror (err), gpg_strsource (err));
|
||||
else
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
while ((n = runner_get_threads ()))
|
||||
{
|
||||
log_info ("number of running threads: %u\n", n);
|
||||
pth_sleep (5);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case aMount: /* Mount a container. */
|
||||
{
|
||||
if (argc != 1 && argc != 2 )
|
||||
wrong_args ("--mount filename [mountpoint]");
|
||||
err = g13_mount_container (&ctrl, argv[0], argc == 2?argv[1]:NULL);
|
||||
if (err)
|
||||
log_error ("error mounting container `%s': %s <%s>\n",
|
||||
*argv, gpg_strerror (err), gpg_strsource (err));
|
||||
else
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
while ((n = runner_get_threads ()))
|
||||
{
|
||||
log_info ("number of running threads: %u\n", n);
|
||||
pth_sleep (5);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error (_("invalid command (there is no implicit command)\n"));
|
||||
break;
|
||||
log_error (_("invalid command (there is no implicit command)\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Print the audit result if needed. */
|
||||
@ -735,3 +773,84 @@ g13_init_default_ctrl (struct server_control_s *ctrl)
|
||||
}
|
||||
|
||||
|
||||
/* static void */
|
||||
/* daemonize (int nodetach) */
|
||||
/* { */
|
||||
/* gnupg_fd_t fd; */
|
||||
/* gnupg_fd_t fd_ssh; */
|
||||
/* pid_t pid; */
|
||||
|
||||
/* fflush (NULL); */
|
||||
/* #ifdef HAVE_W32_SYSTEM */
|
||||
/* pid = getpid (); */
|
||||
/* #else /\*!HAVE_W32_SYSTEM*\/ */
|
||||
/* pid = fork (); */
|
||||
/* if (pid == (pid_t)-1) */
|
||||
/* { */
|
||||
/* log_fatal ("fork failed: %s\n", strerror (errno) ); */
|
||||
/* g13_exit (1); */
|
||||
/* } */
|
||||
/* else if (pid) /\* We are the parent *\/ */
|
||||
/* { */
|
||||
/* /\* We need to clwanup our resources. An gcry_atfork might be */
|
||||
/* needed. *\/ */
|
||||
/* exit (0); */
|
||||
/* /\*NOTREACHED*\/ */
|
||||
/* } /\* End parent *\/ */
|
||||
|
||||
/* /\* */
|
||||
/* This is the child */
|
||||
/* *\/ */
|
||||
|
||||
/* /\* Detach from tty and put process into a new session *\/ */
|
||||
/* if (!nodetach ) */
|
||||
/* { */
|
||||
/* int i; */
|
||||
/* unsigned int oldflags; */
|
||||
|
||||
/* /\* Close stdin, stdout and stderr unless it is the log stream *\/ */
|
||||
/* for (i=0; i <= 2; i++) */
|
||||
/* { */
|
||||
/* if (!log_test_fd (i) && i != fd ) */
|
||||
/* { */
|
||||
/* if ( ! close (i) */
|
||||
/* && open ("/dev/null", i? O_WRONLY : O_RDONLY) == -1) */
|
||||
/* { */
|
||||
/* log_error ("failed to open `%s': %s\n", */
|
||||
/* "/dev/null", strerror (errno)); */
|
||||
/* cleanup (); */
|
||||
/* exit (1); */
|
||||
/* } */
|
||||
/* } */
|
||||
/* } */
|
||||
/* if (setsid() == -1) */
|
||||
/* { */
|
||||
/* log_error ("setsid() failed: %s\n", strerror(errno) ); */
|
||||
/* cleanup (); */
|
||||
/* exit (1); */
|
||||
/* } */
|
||||
|
||||
/* log_get_prefix (&oldflags); */
|
||||
/* log_set_prefix (NULL, oldflags | JNLIB_LOG_RUN_DETACHED); */
|
||||
/* opt.running_detached = 1; */
|
||||
/* } */
|
||||
|
||||
/* if (chdir("/")) */
|
||||
/* { */
|
||||
/* log_error ("chdir to / failed: %s\n", strerror (errno)); */
|
||||
/* exit (1); */
|
||||
/* } */
|
||||
|
||||
/* { */
|
||||
/* struct sigaction sa; */
|
||||
|
||||
/* sa.sa_handler = SIG_IGN; */
|
||||
/* sigemptyset (&sa.sa_mask); */
|
||||
/* sa.sa_flags = 0; */
|
||||
/* sigaction (SIGPIPE, &sa, NULL); */
|
||||
/* } */
|
||||
/* #endif /\*!HAVE_W32_SYSTEM*\/ */
|
||||
|
||||
/* log_info ("%s %s started\n", strusage(11), strusage(13) ); */
|
||||
/* handle_something (fd, opt.ssh_support ? fd_ssh : GNUPG_INVALID_FD); */
|
||||
/* } */
|
||||
|
@ -63,8 +63,9 @@
|
||||
|
||||
#define KEYBLOB_TAG_BLOBVERSION 0
|
||||
/* This tag is used to describe the version of the keyblob. It must
|
||||
be the first tag in a keyblob. Its value is a single byte giving
|
||||
the blob version. The current version is 1. */
|
||||
be the first tag in a keyblob and may only occur once. Its value
|
||||
is a single byte giving the blob version. The only defined version
|
||||
is 1. */
|
||||
|
||||
#define KEYBLOB_TAG_CONTTYPE 1
|
||||
/* This tag gives the type of the container. The value is a two byte
|
||||
|
303
g13/mount.c
Normal file
303
g13/mount.c
Normal file
@ -0,0 +1,303 @@
|
||||
/* mount.c - Mount a crypto container
|
||||
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "g13.h"
|
||||
#include "i18n.h"
|
||||
#include "mount.h"
|
||||
|
||||
#include "keyblob.h"
|
||||
#include "backend.h"
|
||||
#include "utils.h"
|
||||
#include "call-gpg.h"
|
||||
#include "estream.h"
|
||||
|
||||
|
||||
/* Parse the header prefix and return the length of the entire header. */
|
||||
static gpg_error_t
|
||||
parse_header (const char *filename,
|
||||
const unsigned char *packet, size_t packetlen,
|
||||
size_t *r_headerlen)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
if (packetlen != 32)
|
||||
return gpg_error (GPG_ERR_BUG);
|
||||
|
||||
len = ((packet[2] << 24) | (packet[3] << 16)
|
||||
| (packet[4] << 8) | packet[5]);
|
||||
if (packet[0] != (0xc0|61) || len < 26
|
||||
|| memcmp (packet+6, "GnuPG/G13", 10))
|
||||
{
|
||||
log_error ("file `%s' is not valid container\n", filename);
|
||||
return gpg_error (GPG_ERR_INV_OBJ);
|
||||
}
|
||||
if (packet[16] != 1)
|
||||
{
|
||||
log_error ("unknown version %u of container `%s'\n",
|
||||
(unsigned int)packet[16], filename);
|
||||
return gpg_error (GPG_ERR_INV_OBJ);
|
||||
}
|
||||
if (packet[17] || packet[18]
|
||||
|| packet[26] || packet[27] || packet[28] || packet[29]
|
||||
|| packet[30] || packet[31])
|
||||
log_info ("WARNING: unknown meta information in `%s'\n", filename);
|
||||
if (packet[19])
|
||||
log_info ("WARNING: OS flag is not supported in `%s'\n", filename);
|
||||
if (packet[24] != 1 || packet[25] != 0)
|
||||
{
|
||||
log_error ("meta data copies in `%s' are not supported\n", filename);
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
len = ((packet[20] << 24) | (packet[21] << 16)
|
||||
| (packet[22] << 8) | packet[23]);
|
||||
|
||||
/* Do a basic sanity check on the length. */
|
||||
if (len < 32 || len > 1024*1024)
|
||||
{
|
||||
log_error ("bad length given in container `%s'\n", filename);
|
||||
return gpg_error (GPG_ERR_INV_OBJ);
|
||||
}
|
||||
|
||||
*r_headerlen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read the keyblob at FILENAME. The caller should have acquired a
|
||||
lockfile and checked that the file exists. */
|
||||
static gpg_error_t
|
||||
read_keyblob (const char *filename,
|
||||
void **r_enckeyblob, size_t *r_enckeybloblen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
estream_t fp;
|
||||
unsigned char packet[32];
|
||||
size_t headerlen, msglen;
|
||||
void *msg = NULL;
|
||||
|
||||
*r_enckeyblob = NULL;
|
||||
*r_enckeybloblen = 0;
|
||||
|
||||
fp = es_fopen (filename, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error reading `%s': %s\n",
|
||||
filename, gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Read the header. It is defined as 32 bytes thus we read it in one go. */
|
||||
if (es_fread (packet, 32, 1, fp) != 1)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error reading the header of `%s': %s\n",
|
||||
filename, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = parse_header (filename, packet, 32, &headerlen);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("header length of `%s' is %zu\n", filename, headerlen);
|
||||
|
||||
/* Read everything including the padding. We should eventually do a
|
||||
regular OpenPGP parsing to detect the padding packet and pass
|
||||
only the actual used OpenPGP data to the engine. This is in
|
||||
particular required when supporting CMS which will be
|
||||
encapsulated in an OpenPGP packet. */
|
||||
assert (headerlen >= 32);
|
||||
msglen = headerlen - 32;
|
||||
if (!msglen)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
goto leave;
|
||||
}
|
||||
msg = xtrymalloc (msglen);
|
||||
if (!msglen)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
if (es_fread (msg, msglen, 1, fp) != 1)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error reading keyblob of `%s': %s\n",
|
||||
filename, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
*r_enckeyblob = msg;
|
||||
msg = NULL;
|
||||
*r_enckeybloblen = msglen;
|
||||
|
||||
leave:
|
||||
xfree (msg);
|
||||
es_fclose (fp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Decrypt the keyblob (ENCKEYBLOB,ENCKEYBLOBLEN) and store the result at
|
||||
(R_KEYBLOB, R_KEYBLOBLEN). Returns 0 on success or an error code.
|
||||
On error R_KEYBLOB is set to NULL. */
|
||||
static gpg_error_t
|
||||
decrypt_keyblob (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
|
||||
void **r_keyblob, size_t *r_keybloblen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
/* FIXME: For now we only implement OpenPGP. */
|
||||
err = gpg_decrypt_blob (ctrl, enckeyblob, enckeybloblen,
|
||||
r_keyblob, r_keybloblen);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dump_keyblob (tupledesc_t tuples)
|
||||
{
|
||||
size_t n;
|
||||
unsigned int tag;
|
||||
const void *value;
|
||||
|
||||
log_info ("keyblob dump:\n");
|
||||
tag = KEYBLOB_TAG_BLOBVERSION;
|
||||
value = find_tuple (tuples, tag, &n);
|
||||
while (value)
|
||||
{
|
||||
log_info (" tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
|
||||
if (tag == KEYBLOB_TAG_ENCKEY
|
||||
|| tag == KEYBLOB_TAG_MACKEY)
|
||||
log_printf ("[confidential]\n");
|
||||
else if (!n)
|
||||
log_printf ("[none]\n");
|
||||
else
|
||||
log_printhex ("", value, n);
|
||||
value = next_tuple (tuples, &tag, &n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Mount the container with name FILENAME at MOUNTPOINT. */
|
||||
gpg_error_t
|
||||
g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
|
||||
{
|
||||
gpg_error_t err;
|
||||
dotlock_t lock;
|
||||
void *enckeyblob = NULL;
|
||||
size_t enckeybloblen;
|
||||
void *keyblob = NULL;
|
||||
size_t keybloblen;
|
||||
tupledesc_t tuples = NULL;
|
||||
size_t n;
|
||||
const unsigned char *value;
|
||||
int conttype;
|
||||
|
||||
/* A quick check to see whether the container exists. */
|
||||
if (access (filename, R_OK))
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
/* Try to take a lock. */
|
||||
lock = create_dotlock (filename);
|
||||
if (!lock)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
if (make_dotlock (lock, 0))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
else
|
||||
err = 0;
|
||||
|
||||
/* Check again that the file exists. */
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (stat (filename, &sb))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the encrypted keyblob. */
|
||||
err = read_keyblob (filename, &enckeyblob, &enckeybloblen);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* Decrypt that keyblob and store it in a tuple descriptor. */
|
||||
err = decrypt_keyblob (ctrl, enckeyblob, enckeybloblen,
|
||||
&keyblob, &keybloblen);
|
||||
if (err)
|
||||
goto leave;
|
||||
xfree (enckeyblob);
|
||||
enckeyblob = NULL;
|
||||
|
||||
err = create_tupledesc (&tuples, keyblob, keybloblen);
|
||||
if (!err)
|
||||
keyblob = NULL;
|
||||
else
|
||||
{
|
||||
if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
|
||||
log_error ("unknown keyblob version\n");
|
||||
goto leave;
|
||||
}
|
||||
if (opt.verbose)
|
||||
dump_keyblob (tuples);
|
||||
|
||||
value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
|
||||
if (!value || n != 2)
|
||||
conttype = 0;
|
||||
else
|
||||
conttype = (value[0] << 8 | value[1]);
|
||||
if (!be_is_supported_conttype (conttype))
|
||||
{
|
||||
log_error ("content type %d is not supported\n", conttype);
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
goto leave;
|
||||
}
|
||||
err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples);
|
||||
|
||||
leave:
|
||||
destroy_tupledesc (tuples);
|
||||
xfree (keyblob);
|
||||
xfree (enckeyblob);
|
||||
destroy_dotlock (lock);
|
||||
return err;
|
||||
}
|
29
g13/mount.h
Normal file
29
g13/mount.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* mmount.h - Defs to mount a crypto container
|
||||
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef G13_MOUNT_H
|
||||
#define G13_MOUNT_H
|
||||
|
||||
gpg_error_t g13_mount_container (ctrl_t ctrl,
|
||||
const char *filename,
|
||||
const char *mountpoint);
|
||||
|
||||
|
||||
#endif /*G13_MOUNT_H*/
|
||||
|
444
g13/runner.c
Normal file
444
g13/runner.c
Normal file
@ -0,0 +1,444 @@
|
||||
/* runner.c - Run and watch the backend engines
|
||||
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <pth.h>
|
||||
|
||||
#include "g13.h"
|
||||
#include "i18n.h"
|
||||
#include "keyblob.h"
|
||||
#include "runner.h"
|
||||
#include "../common/exechelp.h"
|
||||
|
||||
|
||||
/* The runner object. */
|
||||
struct runner_s
|
||||
{
|
||||
char *name; /* The name of this runner. */
|
||||
|
||||
int spawned; /* True if runner_spawn has been called. */
|
||||
pth_t threadid; /* The TID of the runner thread. */
|
||||
|
||||
int cancel_flag; /* If set the thread should terminate itself. */
|
||||
|
||||
/* We use a reference counter to know when it is safe to remove the
|
||||
object. Lackiong an explicit ref fucntion this counter will take
|
||||
only these two values:
|
||||
|
||||
1 = Thread not running or only the thread is still running.
|
||||
2 = Thread is running and someone is holding a reference. */
|
||||
int refcount;
|
||||
|
||||
pid_t pid; /* PID of the backend's process (the engine). */
|
||||
int in_fd; /* File descriptors to read from the engine. */
|
||||
int out_fd; /* File descriptors to write to the engine. */
|
||||
engine_handler_fnc_t handler; /* The handler functions. */
|
||||
engine_handler_cleanup_fnc_t handler_cleanup;
|
||||
void *handler_data; /* Private data of HANDLER and HANDLER_CLEANUP. */
|
||||
|
||||
/* Instead of IN_FD we use an estream. Note that the runner thread
|
||||
may close the stream and set status_fp to NULL at any time. Thus
|
||||
it won't be a good idea to use it while the runner thread is
|
||||
running. */
|
||||
estream_t status_fp;
|
||||
};
|
||||
|
||||
|
||||
/* Avariabale to track the number of active runner threads. */
|
||||
static unsigned int thread_count;
|
||||
|
||||
|
||||
|
||||
/* Write NBYTES of BUF to file descriptor FD. */
|
||||
static int
|
||||
writen (int fd, const void *buf, size_t nbytes)
|
||||
{
|
||||
size_t nleft = nbytes;
|
||||
int nwritten;
|
||||
|
||||
while (nleft > 0)
|
||||
{
|
||||
nwritten = pth_write (fd, buf, nleft);
|
||||
if (nwritten < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
nwritten = 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
nleft -= nwritten;
|
||||
buf = (const char*)buf + nwritten;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_already_spawned (runner_t runner, const char *funcname)
|
||||
{
|
||||
if (runner->spawned)
|
||||
{
|
||||
log_error ("BUG: runner already spawned - ignoring call to %s\n",
|
||||
funcname);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return the number of active threads. */
|
||||
unsigned int
|
||||
runner_get_threads (void)
|
||||
{
|
||||
return thread_count;
|
||||
}
|
||||
|
||||
|
||||
/* The public release function. */
|
||||
void
|
||||
runner_release (runner_t runner)
|
||||
{
|
||||
if (!runner)
|
||||
return;
|
||||
|
||||
if (!--runner->refcount)
|
||||
return;
|
||||
|
||||
es_fclose (runner->status_fp);
|
||||
if (runner->in_fd != -1)
|
||||
close (runner->in_fd);
|
||||
if (runner->out_fd != -1)
|
||||
close (runner->out_fd);
|
||||
|
||||
/* Fixme: close the process. */
|
||||
|
||||
/* Tell the engine to release its data. */
|
||||
if (runner->handler_cleanup)
|
||||
runner->handler_cleanup (runner->handler_data);
|
||||
|
||||
if (runner->pid != (pid_t)(-1))
|
||||
{
|
||||
/* The process has not been cleaned up - do it now. */
|
||||
gnupg_kill_process (runner->pid);
|
||||
/* (Actually we should use the program name and not the
|
||||
arbitrary NAME of the runner object. However it does not
|
||||
matter because that information is only used for
|
||||
diagnostics.) */
|
||||
gnupg_wait_process (runner->name, runner->pid, NULL);
|
||||
}
|
||||
|
||||
xfree (runner->name);
|
||||
xfree (runner);
|
||||
}
|
||||
|
||||
|
||||
/* Create a new runner context. On success a new runner object is
|
||||
stored at R_RUNNER. On failure NULL is stored at this address and
|
||||
an error code returned. */
|
||||
gpg_error_t
|
||||
runner_new (runner_t *r_runner, const char *name)
|
||||
{
|
||||
runner_t runner;
|
||||
|
||||
*r_runner = NULL;
|
||||
|
||||
runner = xtrycalloc (1, sizeof *runner);
|
||||
if (!runner)
|
||||
return gpg_error_from_syserror ();
|
||||
runner->name = xtrystrdup (name? name: "[unknown]");
|
||||
if (!runner->name)
|
||||
{
|
||||
xfree (runner);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
runner->refcount = 1;
|
||||
runner->pid = (pid_t)(-1);
|
||||
runner->in_fd = -1;
|
||||
runner->out_fd = -1;
|
||||
|
||||
|
||||
*r_runner = runner;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* A runner usually maintaines two file descriptors to control the
|
||||
backend engine. This function is used to set these file
|
||||
descriptors. The function takes ownership of these file
|
||||
descriptors. IN_FD will be used to read from engine and OUT_FD to
|
||||
send data to the engine. */
|
||||
void
|
||||
runner_set_fds (runner_t runner, int in_fd, int out_fd)
|
||||
{
|
||||
if (check_already_spawned (runner, "runner_set_fds"))
|
||||
return;
|
||||
|
||||
if (runner->in_fd != -1)
|
||||
close (runner->in_fd);
|
||||
if (runner->out_fd != -1)
|
||||
close (runner->out_fd);
|
||||
runner->in_fd = in_fd;
|
||||
runner->out_fd = out_fd;
|
||||
}
|
||||
|
||||
|
||||
/* Set the PID of the backend engine. After this call the engine is
|
||||
owned by the runner object. */
|
||||
void
|
||||
runner_set_pid (runner_t runner, pid_t pid)
|
||||
{
|
||||
if (check_already_spawned (runner, "runner_set_fds"))
|
||||
return;
|
||||
|
||||
runner->pid = pid;
|
||||
}
|
||||
|
||||
|
||||
/* Register the engine handler fucntions HANDLER and HANDLER_CLEANUP
|
||||
and its private HANDLER_DATA with RUNNER. */
|
||||
void
|
||||
runner_set_handler (runner_t runner,
|
||||
engine_handler_fnc_t handler,
|
||||
engine_handler_cleanup_fnc_t handler_cleanup,
|
||||
void *handler_data)
|
||||
{
|
||||
if (check_already_spawned (runner, "runner_set_handler"))
|
||||
return;
|
||||
|
||||
runner->handler = handler;
|
||||
runner->handler_cleanup = handler_cleanup;
|
||||
runner->handler_data = handler_data;
|
||||
}
|
||||
|
||||
|
||||
/* The thread spawned by runner_spawn. */
|
||||
static void *
|
||||
runner_thread (void *arg)
|
||||
{
|
||||
runner_t runner = arg;
|
||||
gpg_error_t err;
|
||||
|
||||
log_debug ("starting runner thread\n");
|
||||
/* If a status_fp is available, the thread's main task is to read
|
||||
from that stream and invoke the backend's handler function. This
|
||||
is done on a line by line base and the line length is limited to
|
||||
a reasonable value (about 1000 characters). Other work will
|
||||
continue either due to an EOF of the stream or by demand of the
|
||||
engine. */
|
||||
if (runner->status_fp)
|
||||
{
|
||||
int c, cont_line;
|
||||
unsigned int pos;
|
||||
char buffer[1024];
|
||||
estream_t fp = runner->status_fp;
|
||||
|
||||
pos = 0;
|
||||
err = 0;
|
||||
cont_line = 0;
|
||||
while (!err && !runner->cancel_flag && (c=es_getc (fp)) != EOF)
|
||||
{
|
||||
buffer[pos++] = c;
|
||||
if (pos >= sizeof buffer - 5 || c == '\n')
|
||||
{
|
||||
buffer[pos - (c == '\n')] = 0;
|
||||
if (opt.verbose)
|
||||
log_info ("%s%s: %s\n",
|
||||
runner->name, cont_line? "(cont)":"", buffer);
|
||||
/* We handle only complete lines and ignore any stuff we
|
||||
possibly had to truncate. That is - at least for the
|
||||
encfs engine - not an issue because our changes to
|
||||
the tool make sure that only relatively short prompt
|
||||
lines are of interest. */
|
||||
if (!cont_line && runner->handler)
|
||||
err = runner->handler (runner->handler_data,
|
||||
runner, buffer);
|
||||
pos = 0;
|
||||
cont_line = (c != '\n');
|
||||
}
|
||||
}
|
||||
if (!err && runner->cancel_flag)
|
||||
log_debug ("runner thread noticed cancel flag\n");
|
||||
else
|
||||
log_debug ("runner thread saw EOF\n");
|
||||
if (pos)
|
||||
{
|
||||
buffer[pos] = 0;
|
||||
if (opt.verbose)
|
||||
log_info ("%s%s: %s\n",
|
||||
runner->name, cont_line? "(cont)":"", buffer);
|
||||
if (!cont_line && !err && runner->handler)
|
||||
err = runner->handler (runner->handler_data,
|
||||
runner, buffer);
|
||||
}
|
||||
if (!err && es_ferror (fp))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error reading from %s: %s\n",
|
||||
runner->name, gpg_strerror (err));
|
||||
}
|
||||
|
||||
runner->status_fp = NULL;
|
||||
es_fclose (fp);
|
||||
log_debug ("runner thread closed status fp\n");
|
||||
}
|
||||
|
||||
/* Now wait for the process to finish. */
|
||||
if (!err && runner->pid != (pid_t)(-1))
|
||||
{
|
||||
int exitcode;
|
||||
|
||||
log_debug ("runner thread waiting ...\n");
|
||||
err = gnupg_wait_process (runner->name, runner->pid, &exitcode);
|
||||
runner->pid = (pid_t)(-1);
|
||||
if (err)
|
||||
log_error ("running `%s' failed (exitcode=%d): %s\n",
|
||||
runner->name, exitcode, gpg_strerror (err));
|
||||
log_debug ("runner thread waiting finished\n");
|
||||
}
|
||||
|
||||
/* Get rid of the runner object (note: it is refcounted). */
|
||||
log_debug ("runner thread releasing runner ...\n");
|
||||
runner_release (runner);
|
||||
log_debug ("runner thread runner released\n");
|
||||
thread_count--;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Spawn a new thread to let RUNNER work as a coprocess. */
|
||||
gpg_error_t
|
||||
runner_spawn (runner_t runner)
|
||||
{
|
||||
gpg_error_t err;
|
||||
pth_attr_t tattr;
|
||||
pth_t tid;
|
||||
|
||||
if (check_already_spawned (runner, "runner_spawn"))
|
||||
return gpg_error (GPG_ERR_BUG);
|
||||
|
||||
/* In case we have an input fd, open it as an estream so that the
|
||||
Pth scheduling will work. The stdio functions don't work with
|
||||
Pth because they don't call the pth counterparts of read and
|
||||
write unless linker tricks are used. */
|
||||
if (runner->in_fd != -1)
|
||||
{
|
||||
estream_t fp;
|
||||
|
||||
fp = es_fdopen (runner->in_fd, "r");
|
||||
if (!fp)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("can't fdopen pipe for reading: %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
runner->status_fp = fp;
|
||||
runner->in_fd = -1; /* Now owned by status_fp. */
|
||||
}
|
||||
|
||||
tattr = pth_attr_new ();
|
||||
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
|
||||
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
|
||||
pth_attr_set (tattr, PTH_ATTR_NAME, runner->name);
|
||||
|
||||
tid = pth_spawn (tattr, runner_thread, runner);
|
||||
if (!tid)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
log_error ("error spawning runner thread: %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
/* The scheduler has not yet kicked in, thus we can safely set the
|
||||
spawned flag and the tid. */
|
||||
thread_count++;
|
||||
runner->spawned = 1;
|
||||
runner->threadid = tid;
|
||||
pth_attr_destroy (tattr);
|
||||
|
||||
/* The runner thread is now runnable. */
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Cancel a running thread. */
|
||||
void
|
||||
runner_cancel (runner_t runner)
|
||||
{
|
||||
if (runner->spawned)
|
||||
{
|
||||
/* FIXME: This does only work if the thread emits status lines. We
|
||||
need to change the trhead to wait on an event. */
|
||||
runner->cancel_flag = 1;
|
||||
/* For now we use the brutal way and kill the process. */
|
||||
gnupg_kill_process (runner->pid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Send a line of data down to the engine. This line may not contain
|
||||
a binary Nul or a LF character. This function is used by the
|
||||
engine's handler. */
|
||||
gpg_error_t
|
||||
runner_send_line (runner_t runner, const void *data, size_t datalen)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
|
||||
if (!runner->spawned)
|
||||
{
|
||||
log_error ("BUG: runner for %s not spawned\n", runner->name);
|
||||
err = gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
else if (runner->out_fd == -1)
|
||||
{
|
||||
log_error ("no output file descriptor for runner %s\n", runner->name);
|
||||
err = gpg_error (GPG_ERR_EBADF);
|
||||
}
|
||||
else if (data && datalen)
|
||||
{
|
||||
if (memchr (data, '\n', datalen))
|
||||
{
|
||||
log_error ("LF detected in response data\n");
|
||||
err = gpg_error (GPG_ERR_BUG);
|
||||
}
|
||||
else if (memchr (data, 0, datalen))
|
||||
{
|
||||
log_error ("Nul detected in response data\n");
|
||||
err = gpg_error (GPG_ERR_BUG);
|
||||
}
|
||||
else if (writen (runner->out_fd, data, datalen))
|
||||
err = gpg_error_from_syserror ();
|
||||
}
|
||||
|
||||
if (!err)
|
||||
if (writen (runner->out_fd, "\n", 1))
|
||||
err = gpg_error_from_syserror ();
|
||||
|
||||
return err;
|
||||
}
|
68
g13/runner.h
Normal file
68
g13/runner.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* runner.h - Run and watch the backend engines
|
||||
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef G13_RUNNER_H
|
||||
#define G13_RUNNER_H
|
||||
|
||||
/* The runner object. */
|
||||
struct runner_s;
|
||||
typedef struct runner_s *runner_t;
|
||||
|
||||
/* Prototypes for the handler functions provided by the engine. */
|
||||
typedef gpg_error_t (*engine_handler_fnc_t) (void *opaque,
|
||||
runner_t runner,
|
||||
const char *statusline);
|
||||
typedef void (*engine_handler_cleanup_fnc_t) (void *opaque);
|
||||
|
||||
|
||||
/* Return the number of active threads. */
|
||||
unsigned int runner_get_threads (void);
|
||||
|
||||
/* Create a new runner object. */
|
||||
gpg_error_t runner_new (runner_t *r_runner, const char *name);
|
||||
|
||||
/* Free a runner object. */
|
||||
void runner_release (runner_t runner);
|
||||
|
||||
/* Functions to set properties of the runner. */
|
||||
void runner_set_fds (runner_t runner, int in_fd, int out_fd);
|
||||
|
||||
void runner_set_pid (runner_t runner, pid_t pid);
|
||||
|
||||
/* Register the handler functions with a runner. */
|
||||
void runner_set_handler (runner_t runner,
|
||||
engine_handler_fnc_t handler,
|
||||
engine_handler_cleanup_fnc_t handler_cleanup,
|
||||
void *handler_data);
|
||||
|
||||
/* Start the runner. */
|
||||
gpg_error_t runner_spawn (runner_t runner);
|
||||
|
||||
/* Cancel a runner. */
|
||||
void runner_cancel (runner_t runner);
|
||||
|
||||
/* Send data back to the engine. This function is used by the
|
||||
engine's handler. */
|
||||
gpg_error_t runner_send_line (runner_t runner,
|
||||
const void *data, size_t datalen);
|
||||
|
||||
|
||||
|
||||
#endif /*G13_RUNNER_H*/
|
||||
|
129
g13/utils.c
129
g13/utils.c
@ -28,6 +28,17 @@
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
/* Definition of the tuple descriptor object. */
|
||||
struct tupledesc_s
|
||||
{
|
||||
unsigned char *data; /* The tuple data. */
|
||||
size_t datalen; /* The length of the data. */
|
||||
size_t pos; /* The current position as used by next_tuple. */
|
||||
int refcount; /* Number of references hold. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Append the TAG and the VALUE to the MEMBUF. There is no error
|
||||
checking here; this is instead done while getting the value back
|
||||
from the membuf. */
|
||||
@ -49,3 +60,121 @@ append_tuple (membuf_t *membuf, int tag, const void *value, size_t length)
|
||||
put_membuf (membuf, value, length);
|
||||
}
|
||||
|
||||
|
||||
/* Create a tuple object by moving the ownership of (DATA,DATALEN) to
|
||||
a new object. Returns 0 on success and stores the new object at
|
||||
R_TUPLEHD. The return object must be released using
|
||||
destroy_tuples(). */
|
||||
gpg_error_t
|
||||
create_tupledesc (tupledesc_t *r_desc, void *data, size_t datalen)
|
||||
{
|
||||
if (datalen < 5 || memcmp (data, "\x00\x00\x00\x01\x01", 5))
|
||||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
|
||||
*r_desc = xtrymalloc (sizeof **r_desc);
|
||||
if (!*r_desc)
|
||||
return gpg_error_from_syserror ();
|
||||
(*r_desc)->data = data;
|
||||
(*r_desc)->datalen = datalen;
|
||||
(*r_desc)->pos = 0;
|
||||
(*r_desc)->refcount++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unref a tuple descriptor and if the refcount is down to 0 release
|
||||
its allocated storage. */
|
||||
void
|
||||
destroy_tupledesc (tupledesc_t tupledesc)
|
||||
{
|
||||
if (!tupledesc)
|
||||
return;
|
||||
|
||||
if (!--tupledesc->refcount)
|
||||
{
|
||||
xfree (tupledesc->data);
|
||||
xfree (tupledesc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tupledesc_t
|
||||
ref_tupledesc (tupledesc_t tupledesc)
|
||||
{
|
||||
if (tupledesc)
|
||||
tupledesc->refcount++;
|
||||
return tupledesc;
|
||||
}
|
||||
|
||||
|
||||
/* Find the first tuple with tag TAG. On success return a pointer to
|
||||
its value and store the length of the value at R_LENGTH. If no
|
||||
tuple was return NULL. For future use by next_tupe, the last
|
||||
position is stored in the descriptor. */
|
||||
const void *
|
||||
find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length)
|
||||
{
|
||||
const unsigned char *s;
|
||||
const unsigned char *s_end; /* Points right behind the data. */
|
||||
unsigned int t;
|
||||
size_t n;
|
||||
|
||||
s = tupledesc->data;
|
||||
if (!s)
|
||||
return NULL;
|
||||
s_end = s + tupledesc->datalen;
|
||||
while (s < s_end)
|
||||
{
|
||||
if (s+3 >= s_end || s + 3 < s)
|
||||
break;
|
||||
t = s[0] << 8;
|
||||
t |= s[1];
|
||||
n = s[2] << 8;
|
||||
n |= s[3];
|
||||
s += 4;
|
||||
if (s + n > s_end || s + n < s)
|
||||
break;
|
||||
if (t == tag)
|
||||
{
|
||||
tupledesc->pos = (s + n) - tupledesc->data;
|
||||
*r_length = n;
|
||||
return s;
|
||||
}
|
||||
s += n;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const void *
|
||||
next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
|
||||
{
|
||||
const unsigned char *s;
|
||||
const unsigned char *s_end; /* Points right behind the data. */
|
||||
unsigned int t;
|
||||
size_t n;
|
||||
|
||||
s = tupledesc->data;
|
||||
if (!s)
|
||||
return NULL;
|
||||
s_end = s + tupledesc->datalen;
|
||||
s += tupledesc->pos;
|
||||
if (s < s_end
|
||||
&& !(s+3 >= s_end || s + 3 < s))
|
||||
{
|
||||
t = s[0] << 8;
|
||||
t |= s[1];
|
||||
n = s[2] << 8;
|
||||
n |= s[3];
|
||||
s += 4;
|
||||
if (!(s + n > s_end || s + n < s))
|
||||
{
|
||||
tupledesc->pos = (s + n) - tupledesc->data;
|
||||
*r_tag = t;
|
||||
*r_length = n;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
15
g13/utils.h
15
g13/utils.h
@ -22,10 +22,23 @@
|
||||
|
||||
#include "../common/membuf.h"
|
||||
|
||||
|
||||
/* Append a new tuple to a memory buffer. */
|
||||
void append_tuple (membuf_t *membuf,
|
||||
int tag, const void *value, size_t length);
|
||||
|
||||
/* The tuple descriptor object. */
|
||||
struct tupledesc_s;
|
||||
typedef struct tupledesc_s *tupledesc_t;
|
||||
|
||||
gpg_error_t create_tupledesc (tupledesc_t *r_tupledesc,
|
||||
void *data, size_t datalen);
|
||||
void destroy_tupledesc (tupledesc_t tupledesc);
|
||||
tupledesc_t ref_tupledesc (tupledesc_t tupledesc);
|
||||
const void *find_tuple (tupledesc_t tupledesc,
|
||||
unsigned int tag, size_t *r_length);
|
||||
const void *next_tuple (tupledesc_t tupledesc,
|
||||
unsigned int *r_tag, size_t *r_length);
|
||||
|
||||
|
||||
|
||||
#endif /*G13_UTILS_H*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user