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>
|
2009-09-23 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* configure.ac (HAVE_ASSUAN_SET_IO_MONITOR): Remove test.
|
* 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)
|
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)
|
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>
|
2009-09-29 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* exechelp.c (create_inheritable_pipe): Rename to
|
* exechelp.c (create_inheritable_pipe): Rename to
|
||||||
|
@ -1102,3 +1102,28 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
|
|||||||
return 0;
|
return 0;
|
||||||
#endif /* !HAVE_W32_SYSTEM*/
|
#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);
|
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
|
/* 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
|
the program to exec is PGMNAME and its arguments are in ARGV (the
|
||||||
programname is automatically passed as first argument).
|
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
|
/* 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
|
is -1, the file with name FNAME. As of now MODE is assumed to be
|
||||||
assumed to be "rb" if FNAME is used. In contrast to iobuf_fdopen
|
"rb" if FNAME is used. In contrast to iobuf_fdopen the file
|
||||||
the fiel descriptor FD will not be closed during an iobuf_close. */
|
descriptor FD will not be closed during an iobuf_close. */
|
||||||
iobuf_t
|
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;
|
iobuf_t a;
|
||||||
|
|
||||||
if (fd == GNUPG_INVALID_FD)
|
if (fd == -1)
|
||||||
a = iobuf_open (fname);
|
a = iobuf_open (fname);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gnupg_fd_t fd2;
|
int fd2;
|
||||||
|
|
||||||
fd2 = dup (fd);
|
fd2 = dup (fd);
|
||||||
if (fd2 == GNUPG_INVALID_FD)
|
if (fd2 == -1)
|
||||||
a = NULL;
|
a = NULL;
|
||||||
else
|
else
|
||||||
a = iobuf_fdopen (fd2, mode);
|
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
|
# warning options and the user should have a chance of overriding
|
||||||
# them.
|
# them.
|
||||||
if test "$USE_MAINTAINER_MODE" = "yes"; then
|
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"
|
CFLAGS="$CFLAGS -Wformat -Wno-format-y2k -Wformat-security"
|
||||||
AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers])
|
AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers])
|
||||||
_gcc_cflags_save=$CFLAGS
|
_gcc_cflags_save=$CFLAGS
|
||||||
|
@ -31,7 +31,9 @@ g13_SOURCES = \
|
|||||||
keyblob.h \
|
keyblob.h \
|
||||||
utils.c utils.h \
|
utils.c utils.h \
|
||||||
create.c create.h \
|
create.c create.h \
|
||||||
|
mount.c mount.h \
|
||||||
call-gpg.c call-gpg.h \
|
call-gpg.c call-gpg.h \
|
||||||
|
runner.c runner.h \
|
||||||
backend.c backend.h \
|
backend.c backend.h \
|
||||||
be-encfs.c be-encfs.h \
|
be-encfs.c be-encfs.h \
|
||||||
be-truecrypt.c be-truecrypt.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
|
/* If the backend requires a separate file or directory for the
|
||||||
container, return its name by computing it from FNAME which gives
|
container, return its name by computing it from FNAME which gives
|
||||||
the g13 filename. The new file name is allocated and stored at
|
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
|
#define G13_BACKEND_H
|
||||||
|
|
||||||
#include "../common/membuf.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,
|
gpg_error_t be_get_detached_name (int conttype, const char *fname,
|
||||||
char **r_name, int *r_isdir);
|
char **r_name, int *r_isdir);
|
||||||
gpg_error_t be_create_new_keys (int conttype, membuf_t *mb);
|
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*/
|
#endif /*G13_BACKEND_H*/
|
||||||
|
|
||||||
|
413
g13/be-encfs.c
413
g13/be-encfs.c
@ -23,12 +23,301 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "g13.h"
|
#include "g13.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "keyblob.h"
|
#include "keyblob.h"
|
||||||
#include "be-encfs.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
|
/* See be_get_detached_name for a description. Note that the
|
||||||
dispatcher code makes sure that NULL is stored at R_NAME before
|
dispatcher code makes sure that NULL is stored at R_NAME before
|
||||||
calling us. */
|
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
|
gpg_error_t
|
||||||
be_encfs_create_new_keys (membuf_t *mb)
|
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;
|
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);
|
char **r_name, int *r_isdir);
|
||||||
gpg_error_t be_encfs_create_new_keys (membuf_t *mb);
|
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*/
|
#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;
|
gpg_error_t err;
|
||||||
assuan_context_t ctx = NULL;
|
assuan_context_t ctx = NULL;
|
||||||
const char *pgmname;
|
const char *pgmname;
|
||||||
const char *argv[6];
|
const char *argv[7];
|
||||||
int no_close_list[5];
|
int no_close_list[5];
|
||||||
int i;
|
int i;
|
||||||
char line[ASSUAN_LINELENGTH];
|
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,
|
gpg_error_t gpg_encrypt_blob (ctrl_t ctrl,
|
||||||
const void *plain, size_t plainlen,
|
const void *plain, size_t plainlen,
|
||||||
void **r_ciph, size_t *r_ciphlen);
|
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)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
/* Just for testing. */
|
||||||
append_tuple (&mb, KEYBLOB_TAG_FILLER, "filler", 6);
|
append_tuple (&mb, KEYBLOB_TAG_FILLER, "filler", 6);
|
||||||
|
|
||||||
|
|
||||||
*r_blob = get_membuf (&mb, r_bloblen);
|
*r_blob = get_membuf (&mb, r_bloblen);
|
||||||
if (!*r_blob)
|
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
|
appropriate header. This fucntion is called with a lock file in
|
||||||
place and after checking that the filename does not exists. */
|
place and after checking that the filename does not exists. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
write_keyblob (ctrl_t ctrl, const char *filename,
|
write_keyblob (const char *filename,
|
||||||
const void *keyblob, size_t keybloblen)
|
const void *keyblob, size_t keybloblen)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
@ -152,7 +152,7 @@ write_keyblob (ctrl_t ctrl, const char *filename,
|
|||||||
packet[4] = 0;
|
packet[4] = 0;
|
||||||
packet[5] = 26;
|
packet[5] = 26;
|
||||||
memcpy (packet+6, "GnuPG/G13", 10); /* Packet subtype. */
|
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[17] = 0; /* Reserved. */
|
||||||
packet[18] = 0; /* Reserved. */
|
packet[18] = 0; /* Reserved. */
|
||||||
packet[19] = 0; /* OS Flag. */
|
packet[19] = 0; /* OS Flag. */
|
||||||
@ -202,7 +202,7 @@ write_keyblob (ctrl_t ctrl, const char *filename,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
writeerr:
|
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
|
using the current settings. If the file already exists an error is
|
||||||
returned. */
|
returned. */
|
||||||
gpg_error_t
|
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;
|
gpg_error_t err;
|
||||||
dotlock_t lock;
|
dotlock_t lock;
|
||||||
@ -230,6 +230,7 @@ create_new_container (ctrl_t ctrl, const char *filename)
|
|||||||
size_t enckeybloblen;
|
size_t enckeybloblen;
|
||||||
char *detachedname = NULL;
|
char *detachedname = NULL;
|
||||||
int detachedisdir;
|
int detachedisdir;
|
||||||
|
tupledesc_t tuples = NULL;
|
||||||
|
|
||||||
/* A quick check to see that no container with that name already
|
/* A quick check to see that no container with that name already
|
||||||
exists. */
|
exists. */
|
||||||
@ -286,17 +287,28 @@ create_new_container (ctrl_t ctrl, const char *filename)
|
|||||||
&enckeyblob, &enckeybloblen);
|
&enckeyblob, &enckeybloblen);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
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. */
|
/* 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)
|
if (err)
|
||||||
goto leave;
|
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:
|
leave:
|
||||||
|
destroy_tupledesc (tuples);
|
||||||
xfree (detachedname);
|
xfree (detachedname);
|
||||||
xfree (enckeyblob);
|
xfree (enckeyblob);
|
||||||
xfree (keyblob);
|
xfree (keyblob);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#ifndef G13_CREATE_H
|
#ifndef G13_CREATE_H
|
||||||
#define 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*/
|
#endif /*G13_CREATE_H*/
|
||||||
|
127
g13/g13.c
127
g13/g13.c
@ -35,8 +35,10 @@
|
|||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "sysutils.h"
|
#include "sysutils.h"
|
||||||
#include "gc-opt-flags.h"
|
#include "gc-opt-flags.h"
|
||||||
#include "create.h"
|
|
||||||
#include "keyblob.h"
|
#include "keyblob.h"
|
||||||
|
#include "./runner.h"
|
||||||
|
#include "./create.h"
|
||||||
|
#include "./mount.h"
|
||||||
|
|
||||||
|
|
||||||
enum cmd_and_opt_values {
|
enum cmd_and_opt_values {
|
||||||
@ -84,6 +86,7 @@ enum cmd_and_opt_values {
|
|||||||
oHomedir,
|
oHomedir,
|
||||||
oWithColons,
|
oWithColons,
|
||||||
oDryRun,
|
oDryRun,
|
||||||
|
oNoDetach,
|
||||||
|
|
||||||
oRecipient,
|
oRecipient,
|
||||||
|
|
||||||
@ -111,6 +114,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
|
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
|
||||||
ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
|
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 (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_s (oLogFile, "log-file", N_("|FILE|write log output to FILE")),
|
||||||
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
|
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
|
||||||
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
|
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
|
||||||
@ -329,6 +333,7 @@ main ( int argc, char **argv)
|
|||||||
int nogreeting = 0;
|
int nogreeting = 0;
|
||||||
int debug_wait = 0;
|
int debug_wait = 0;
|
||||||
int use_random_seed = 1;
|
int use_random_seed = 1;
|
||||||
|
int nodetach = 0;
|
||||||
int nokeysetup = 0;
|
int nokeysetup = 0;
|
||||||
enum cmd_and_opt_values cmd = 0;
|
enum cmd_and_opt_values cmd = 0;
|
||||||
struct server_control_s ctrl;
|
struct server_control_s ctrl;
|
||||||
@ -499,6 +504,8 @@ main ( int argc, char **argv)
|
|||||||
|
|
||||||
case oAuditLog: auditlog = pargs.r.ret_str; break;
|
case oAuditLog: auditlog = pargs.r.ret_str; break;
|
||||||
|
|
||||||
|
case oNoDetach: nodetach = 1; break;
|
||||||
|
|
||||||
case oDebug: debug_value |= pargs.r.ret_ulong; break;
|
case oDebug: debug_value |= pargs.r.ret_ulong; break;
|
||||||
case oDebugAll: debug_value = ~0; break;
|
case oDebugAll: debug_value = ~0; break;
|
||||||
case oDebugNone: debug_value = 0; break;
|
case oDebugNone: debug_value = 0; break;
|
||||||
@ -677,16 +684,47 @@ main ( int argc, char **argv)
|
|||||||
{
|
{
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
wrong_args ("--create filename");
|
wrong_args ("--create filename");
|
||||||
err = create_new_container (&ctrl, argv[0]);
|
err = g13_create_container (&ctrl, argv[0]);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("error creating a new container: %s <%s>\n",
|
log_error ("error creating a new container: %s <%s>\n",
|
||||||
gpg_strerror (err), gpg_strsource (err));
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_error (_("invalid command (there is no implicit command)\n"));
|
log_error (_("invalid command (there is no implicit command)\n"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the audit result if needed. */
|
/* 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
|
#define KEYBLOB_TAG_BLOBVERSION 0
|
||||||
/* This tag is used to describe the version of the keyblob. It must
|
/* 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
|
be the first tag in a keyblob and may only occur once. Its value
|
||||||
the blob version. The current version is 1. */
|
is a single byte giving the blob version. The only defined version
|
||||||
|
is 1. */
|
||||||
|
|
||||||
#define KEYBLOB_TAG_CONTTYPE 1
|
#define KEYBLOB_TAG_CONTTYPE 1
|
||||||
/* This tag gives the type of the container. The value is a two byte
|
/* 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"
|
#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
|
/* Append the TAG and the VALUE to the MEMBUF. There is no error
|
||||||
checking here; this is instead done while getting the value back
|
checking here; this is instead done while getting the value back
|
||||||
from the membuf. */
|
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);
|
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"
|
#include "../common/membuf.h"
|
||||||
|
|
||||||
|
/* Append a new tuple to a memory buffer. */
|
||||||
void append_tuple (membuf_t *membuf,
|
void append_tuple (membuf_t *membuf,
|
||||||
int tag, const void *value, size_t length);
|
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*/
|
#endif /*G13_UTILS_H*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user