Reworked the server commands.

Track mounts.
--create does now work as expected.
This commit is contained in:
Werner Koch 2009-10-15 17:20:41 +00:00
parent 1445c15ed1
commit 598bf9199e
14 changed files with 629 additions and 217 deletions

View File

@ -33,6 +33,7 @@ g13_SOURCES = \
server.c server.h \
create.c create.h \
mount.c mount.h \
mountinfo.c mountinfo.h \
call-gpg.c call-gpg.h \
runner.c runner.h \
backend.c backend.h \

View File

@ -101,14 +101,15 @@ 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)
const char *fname, int fd, tupledesc_t tuples,
unsigned int *r_id)
{
(void)fd; /* Not yet used. */
switch (conttype)
{
case CONTTYPE_ENCFS:
return be_encfs_create_container (ctrl, fname, tuples);
return be_encfs_create_container (ctrl, fname, tuples, r_id);
default:
return no_such_backend (conttype);
@ -120,12 +121,12 @@ be_create_container (ctrl_t ctrl, int conttype,
gpg_error_t
be_mount_container (ctrl_t ctrl, int conttype,
const char *fname, const char *mountpoint,
tupledesc_t tuples)
tupledesc_t tuples, unsigned int *r_id)
{
switch (conttype)
{
case CONTTYPE_ENCFS:
return be_encfs_mount_container (ctrl, fname, mountpoint, tuples);
return be_encfs_mount_container (ctrl, fname, mountpoint, tuples, r_id);
default:
return no_such_backend (conttype);

View File

@ -30,10 +30,12 @@ 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);
tupledesc_t tuples,
unsigned int *r_id);
gpg_error_t be_mount_container (ctrl_t ctrl, int conttype,
const char *fname, const char *mountpoint,
tupledesc_t tuples);
tupledesc_t tuples,
unsigned int *r_id);
#endif /*G13_BACKEND_H*/

View File

@ -211,7 +211,8 @@ encfs_handler_cleanup (void *opaque)
/* 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)
const char *rawdir, const char *mountpoint, tupledesc_t tuples,
unsigned int *r_id)
{
gpg_error_t err;
encfs_parm_t parm;
@ -240,15 +241,9 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
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 = runner_new (&runner, "encfs");
if (err)
goto leave;
err = gnupg_create_inbound_pipe (inbound);
if (!err)
@ -295,6 +290,7 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
if (err)
goto leave;
*r_id = runner_get_rid (runner);
log_info ("running `%s' in the background\n", pgmname);
leave:
@ -400,7 +396,8 @@ be_encfs_create_new_keys (membuf_t *mb)
/* 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)
be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples,
unsigned int *r_id)
{
gpg_error_t err;
int dummy;
@ -426,7 +423,7 @@ be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples)
}
err = run_encfs_tool (ctrl, ENCFS_CMD_CREATE, containername, mountpoint,
tuples);
tuples, r_id);
/* In any case remove the temporary mount point. */
if (rmdir (mountpoint))
@ -442,11 +439,11 @@ be_encfs_create_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples)
/* Mount the container described by the filename FNAME and the keyblob
information in TUPLES. */
information in TUPLES. On success the runner id is stored at R_ID. */
gpg_error_t
be_encfs_mount_container (ctrl_t ctrl,
const char *fname, const char *mountpoint,
tupledesc_t tuples)
tupledesc_t tuples, unsigned int *r_id)
{
gpg_error_t err;
int dummy;
@ -464,7 +461,7 @@ be_encfs_mount_container (ctrl_t ctrl,
goto leave;
err = run_encfs_tool (ctrl, ENCFS_CMD_MOUNT, containername, mountpoint,
tuples);
tuples, r_id);
leave:
xfree (containername);

View File

@ -28,12 +28,14 @@ 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);
tupledesc_t tuples,
unsigned int *r_id);
gpg_error_t be_encfs_mount_container (ctrl_t ctrl,
const char *fname,
const char *mountpoint,
tupledesc_t tuples);
tupledesc_t tuples,
unsigned int *r_id);
#endif /*G13_BE_ENCFS_H*/

View File

@ -231,6 +231,7 @@ g13_create_container (ctrl_t ctrl, const char *filename)
char *detachedname = NULL;
int detachedisdir;
tupledesc_t tuples = NULL;
unsigned int dummy_rid;
/* A quick check to see that no container with that name already
exists. */
@ -304,7 +305,8 @@ g13_create_container (ctrl_t ctrl, const char *filename)
/* 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);
err = be_create_container (ctrl, ctrl->conttype, filename, -1, tuples,
&dummy_rid);
leave:

View File

@ -39,7 +39,8 @@
#include "server.h"
#include "runner.h"
#include "create.h"
#include "./mount.h"
#include "mount.h"
#include "mountinfo.h"
enum cmd_and_opt_values {
@ -707,6 +708,8 @@ main ( int argc, char **argv)
if (err)
log_error ("server exited with error: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
else
shutdown_pending++;
}
break;
@ -719,6 +722,8 @@ main ( int argc, char **argv)
if (err)
log_error ("error creating a new container: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
else
shutdown_pending++;
}
break;
@ -807,6 +812,7 @@ handle_signal (int signo)
case SIGUSR1:
log_info ("SIGUSR1 received - printing internal information:\n");
pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
mountinfo_dump_all ();
break;
case SIGUSR2:

View File

@ -35,6 +35,8 @@
#include "utils.h"
#include "call-gpg.h"
#include "estream.h"
#include "mountinfo.h"
#include "runner.h"
/* Parse the header prefix and return the length of the entire header. */
@ -89,28 +91,23 @@ parse_header (const char *filename,
}
/* Read the keyblob at FILENAME. The caller should have acquired a
lockfile and checked that the file exists. */
/* Read the prefix of the keyblob and do some basic parsing. On
success returns an open estream file at R_FP and the length of the
header at R_HEADERLEN. */
static gpg_error_t
read_keyblob (const char *filename,
void **r_enckeyblob, size_t *r_enckeybloblen)
read_keyblob_prefix (const char *filename, estream_t *r_fp, size_t *r_headerlen)
{
gpg_error_t err;
estream_t fp;
unsigned char packet[32];
size_t headerlen, msglen;
void *msg = NULL;
*r_enckeyblob = NULL;
*r_enckeybloblen = 0;
*r_fp = NULL;
fp = es_fopen (filename, "rb");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error ("error reading `%s': %s\n",
filename, gpg_strerror (err));
log_error ("error reading `%s': %s\n", filename, gpg_strerror (err));
return err;
}
@ -120,10 +117,35 @@ read_keyblob (const char *filename,
err = gpg_error_from_syserror ();
log_error ("error reading the header of `%s': %s\n",
filename, gpg_strerror (err));
goto leave;
es_fclose (fp);
return err;
}
err = parse_header (filename, packet, 32, &headerlen);
err = parse_header (filename, packet, 32, r_headerlen);
if (err)
es_fclose (fp);
else
*r_fp = fp;
return err;
}
/* 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 = NULL;
size_t headerlen, msglen;
void *msg = NULL;
*r_enckeyblob = NULL;
*r_enckeybloblen = 0;
err = read_keyblob_prefix (filename, &fp, &headerlen);
if (err)
goto leave;
@ -227,6 +249,7 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
size_t n;
const unsigned char *value;
int conttype;
unsigned int rid;
/* A quick check to see whether the container exists. */
if (access (filename, R_OK))
@ -292,7 +315,13 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
goto leave;
}
err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples);
err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
if (!err)
{
err = mountinfo_add_mount (filename, mountpoint, conttype, rid);
/* Fixme: What shall we do if this fails? Add a provisional
mountinfo entry first and remove it on error? */
}
leave:
destroy_tupledesc (tuples);
@ -301,3 +330,56 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
destroy_dotlock (lock);
return err;
}
/* Unmount the container with name FILENAME or the one mounted at
MOUNTPOINT. If both are given the FILENAME takes precedence. */
gpg_error_t
g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
{
gpg_error_t err;
unsigned int rid;
runner_t runner;
(void)ctrl;
if (!filename && !mountpoint)
return gpg_error (GPG_ERR_ENOENT);
err = mountinfo_find_mount (filename, mountpoint, &rid);
if (err)
return err;
runner = runner_find_by_rid (rid);
if (!runner)
{
log_error ("runner %u not found\n", rid);
return gpg_error (GPG_ERR_NOT_FOUND);
}
runner_cancel (runner);
runner_release (runner);
return 0;
}
/* Test whether the container with name FILENAME is a suitable G13
container. This function may even be called on a mounted
container. */
gpg_error_t
g13_is_container (ctrl_t ctrl, const char *filename)
{
gpg_error_t err;
estream_t fp = NULL;
size_t dummy;
(void)ctrl;
/* Read just the prefix of the header. */
err = read_keyblob_prefix (filename, &fp, &dummy);
if (!err)
es_fclose (fp);
return err;
}

View File

@ -1,4 +1,4 @@
/* mmount.h - Defs to mount a crypto container
/* mount.h - Defs to mount a crypto container
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
@ -23,6 +23,11 @@
gpg_error_t g13_mount_container (ctrl_t ctrl,
const char *filename,
const char *mountpoint);
gpg_error_t g13_umount_container (ctrl_t ctrl,
const char *filename,
const char *mountpoint);
gpg_error_t g13_is_container (ctrl_t ctrl, const char *filename);
#endif /*G13_MOUNT_H*/

183
g13/mountinfo.c Normal file
View File

@ -0,0 +1,183 @@
/* mountinfo.c - Track infos about mounts
* 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 "mountinfo.h"
#include "keyblob.h"
#include "utils.h"
/* The object to keep track of mount information. */
struct mounttable_s
{
int in_use; /* The slot is in use. */
char *container; /* Name of the container. */
char *mountpoint; /* Name of the mounttype. */
int conttype; /* Type of the container. */
unsigned int rid; /* Identifier of the runner task. */
};
/* The allocated table of mounts and its size. */
static mtab_t mounttable;
size_t mounttable_size;
/* Add CONTAINER,MOUNTPOINT,CONTTYPE,RID to the mounttable. */
gpg_error_t
mountinfo_add_mount (const char *container, const char *mountpoint,
int conttype, unsigned int rid)
{
size_t idx;
mtab_t m;
for (idx=0; idx < mounttable_size; idx++)
if (!mounttable[idx].in_use)
break;
if (!(idx < mounttable_size))
{
size_t nslots = mounttable_size;
mounttable_size += 10;
m = xtrycalloc (mounttable_size, sizeof *mounttable);
if (!m)
return gpg_error_from_syserror ();
if (mounttable)
{
for (idx=0; idx < nslots; idx++)
m[idx] = mounttable[idx];
xfree (mounttable);
}
mounttable = m;
m = mounttable + nslots;
assert (!m->in_use);
}
else
m = mounttable + idx;
m->container = xtrystrdup (container);
if (!m->container)
return gpg_error_from_syserror ();
m->mountpoint = xtrystrdup (mountpoint);
if (!m->mountpoint)
{
xfree (m->container);
m->container = NULL;
return gpg_error_from_syserror ();
}
m->conttype = conttype;
m->rid = rid;
m->in_use = 1;
return 0;
}
/* Remove a mount info. Either the CONTAINER, the MOUNTPOINT or the
RID must be given. The first argument given is used. */
gpg_error_t
mountinfo_del_mount (const char *container, const char *mountpoint,
unsigned int rid)
{
gpg_error_t err;
size_t idx;
mtab_t m;
/* If a container or mountpint is givem search the RID via the
standard find fucntion. */
if (container || mountpoint)
{
err = mountinfo_find_mount (container, mountpoint, &rid);
if (err)
return err;
}
/* Find via RID and delete. */
for (idx=0, m = mounttable; idx < mounttable_size; idx++, m++)
if (m->in_use && m->rid == rid)
{
m->in_use = 0;
xfree (m->container);
m->container = NULL;
xfree (m->mountpoint);
m->mountpoint = NULL;
return 0;
}
return gpg_error (GPG_ERR_NOT_FOUND);
}
/* Find a mount and return its rid at R_RID. If CONTAINER is given,
the search is done by the container name, if it is not given the
search is done by MOUNTPOINT. */
gpg_error_t
mountinfo_find_mount (const char *container, const char *mountpoint,
unsigned int *r_rid)
{
size_t idx;
mtab_t m;
if (container)
{
for (idx=0, m = mounttable; idx < mounttable_size; idx++, m++)
if (m->in_use && !strcmp (m->container, container))
break;
}
else if (mountpoint)
{
for (idx=0, m = mounttable; idx < mounttable_size; idx++, m++)
if (m->in_use && !strcmp (m->mountpoint, mountpoint))
break;
}
else
idx = mounttable_size;
if (!(idx < mounttable_size))
return gpg_error (GPG_ERR_NOT_FOUND);
*r_rid = m->rid;
return 0;
}
/* Dump all info to the log stream. */
void
mountinfo_dump_all (void)
{
size_t idx;
mtab_t m;
for (idx=0, m = mounttable; idx < mounttable_size; idx++, m++)
if (m->in_use)
log_info ("mtab[%d] %s on %s type %d rid %u\n",
idx, m->container, m->mountpoint, m->conttype, m->rid);
}

40
g13/mountinfo.h Normal file
View File

@ -0,0 +1,40 @@
/* mountinfo.h - Track infos about mounts
* 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_MOUNTINFO_H
#define G13_MOUNTINFO_H
struct mounttable_s;
typedef struct mounttable_s *mtab_t;
gpg_error_t mountinfo_add_mount (const char *container,
const char *mountpoint,
int conttype, unsigned int rid);
gpg_error_t mountinfo_del_mount (const char *container,
const char *mountpoint,
unsigned int rid);
gpg_error_t mountinfo_find_mount (const char *container,
const char *mountpoint,
unsigned int *r_rid);
void mountinfo_dump_all (void);
#endif /*G13_MOUNTINFO_H*/

View File

@ -31,12 +31,13 @@
#include "keyblob.h"
#include "runner.h"
#include "../common/exechelp.h"
#include "mountinfo.h"
/* The runner object. */
struct runner_s
{
char *name; /* The name of this runner. */
char *name; /* The name of this runner. */
unsigned int identifier; /* The runner identifier. */
int spawned; /* True if runner_spawn has been called. */
pth_t threadid; /* The TID of the runner thread. */
@ -131,12 +132,19 @@ runner_get_threads (void)
void
runner_release (runner_t runner)
{
gpg_error_t err;
if (!runner)
return;
if (!--runner->refcount)
return;
err = mountinfo_del_mount (NULL, NULL, runner->identifier);
if (err)
log_error ("failed to remove mount with rid %u from mtab: %s\n",
runner->identifier, gpg_strerror (err));
es_fclose (runner->status_fp);
if (runner->in_fd != -1)
close (runner->in_fd);
@ -171,14 +179,32 @@ runner_release (runner_t runner)
gpg_error_t
runner_new (runner_t *r_runner, const char *name)
{
runner_t runner;
static unsigned int namecounter; /* Global name counter. */
char *namebuffer;
runner_t runner, r;
*r_runner = NULL;
runner = xtrycalloc (1, sizeof *runner);
if (!runner)
return gpg_error_from_syserror ();
runner->name = xtrystrdup (name? name: "[unknown]");
/* Bump up the namecounter. In case we ever had an overflow we
check that this number is currently not in use. The algorithm is
a bit lame but should be sufficient because such an wrap is not
very likely: Assuming that we do a mount 10 times a second, then
we would overwrap on a 32 bit system after 13 years. */
do
{
namecounter++;
for (r = running_threads; r; r = r->next_running)
if (r->identifier == namecounter)
break;
}
while (r);
runner->identifier = namecounter;
runner->name = namebuffer = xtryasprintf ("%s-%d", name, namecounter);
if (!runner->name)
{
xfree (runner);
@ -189,13 +215,37 @@ runner_new (runner_t *r_runner, const char *name)
runner->in_fd = -1;
runner->out_fd = -1;
*r_runner = runner;
return 0;
}
/* A runner usually maintaines two file descriptors to control the
/* Return the identifier of RUNNER. */
unsigned int
runner_get_rid (runner_t runner)
{
return runner->identifier;
}
/* Find a runner by its rid. Returns the runner object. The caller
must release the runner object. */
runner_t
runner_find_by_rid (unsigned int rid)
{
runner_t r;
for (r = running_threads; r; r = r->next_running)
if (r->identifier == rid)
{
r->refcount++;
return r;
}
return NULL;
}
/* A runner usually maintains 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
@ -382,8 +432,8 @@ runner_spawn (runner_t runner)
}
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_JOINABLE, 0);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 128*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, runner->name);
tid = pth_spawn (tattr, runner_thread, runner);

View File

@ -40,6 +40,12 @@ gpg_error_t runner_new (runner_t *r_runner, const char *name);
/* Free a runner object. */
void runner_release (runner_t runner);
/* Return the identifier of RUNNER. */
unsigned int runner_get_rid (runner_t runner);
/* Find a runner by its rid. */
runner_t runner_find_by_rid (unsigned int rid);
/* Functions to set properties of the runner. */
void runner_set_fds (runner_t runner, int in_fd, int out_fd);

View File

@ -40,42 +40,28 @@ struct server_local_s
/* The Assuan contect we are working on. */
assuan_context_t assuan_ctx;
char *mountpoint; /* Malloced current mountpoint. */
char *containername; /* Malloced active containername. */
};
/* Cookie definition for assuan data line output. */
static ssize_t data_line_cookie_write (void *cookie,
const void *buffer, size_t size);
static int data_line_cookie_close (void *cookie);
static es_cookie_io_functions_t data_line_cookie_functions =
{
NULL,
data_line_cookie_write,
NULL,
data_line_cookie_close
};
/* The filepointer for status message used in non-server mode. */
/* static FILE *statusfp; FIXME; */
/* Local prototypes. */
static int command_has_option (const char *cmd, const char *cmdopt);
/*
Helper functions.
*/
/* Set an error and a description. */
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
/* Skip over options.
Blanks after the options are also removed. */
/* Skip over options. Blanks after the options are also removed. */
static char *
skip_options (const char *line)
{
@ -93,52 +79,41 @@ skip_options (const char *line)
/* Check whether the option NAME appears in LINE. */
static int
has_option (const char *line, const char *name)
/* static int */
/* has_option (const char *line, const char *name) */
/* { */
/* const char *s; */
/* int n = strlen (name); */
/* s = strstr (line, name); */
/* if (s && s >= skip_options (line)) */
/* return 0; */
/* return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
/* } */
/* Helper to print a message while leaving a command. */
static gpg_error_t
leave_cmd (assuan_context_t ctx, gpg_error_t err)
{
const char *s;
int n = strlen (name);
s = strstr (line, name);
if (s && s >= skip_options (line))
return 0;
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
}
/* A write handler used by es_fopencookie to write Assuan data
lines. */
static ssize_t
data_line_cookie_write (void *cookie, const void *buffer, size_t size)
{
assuan_context_t ctx = cookie;
if (assuan_send_data (ctx, buffer, size))
if (err)
{
errno = EIO;
return -1;
const char *name = assuan_get_command_name (ctx);
if (!name)
name = "?";
if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
log_error ("command '%s' failed: %s\n", name,
gpg_strerror (err));
else
log_error ("command '%s' failed: %s <%s>\n", name,
gpg_strerror (err), gpg_strsource (err));
}
return size;
}
/* A close handler used by es_fopencookie to write Assuan data
lines. */
static int
data_line_cookie_close (void *cookie)
{
assuan_context_t ctx = cookie;
if (assuan_send_data (ctx, NULL, 0))
{
errno = EIO;
return -1;
}
return 0;
return err;
}
/* The handler for Assuan OPTION commands. */
static gpg_error_t
option_handler (assuan_context_t ctx, const char *key, const char *value)
@ -146,6 +121,8 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
(void)ctrl;
if (!strcmp (key, "putenv"))
{
/* Change the session's environment to be used for the
@ -213,31 +190,167 @@ reset_notify (assuan_context_t ctx)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
xfree (ctrl->server_local->mountpoint);
ctrl->server_local->mountpoint = NULL;
xfree (ctrl->server_local->containername);
ctrl->server_local->containername = NULL;
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
}
/* Helper to print a message while leaving a command. */
/* OPEN [options] <filename>
Open the container FILENAME. FILENAME must be percent-plus
escaped. A quick check to see whether this is a suitable G13
container file is done. However no cryptographic check or any
other check is done. This command is used to define the target for
further commands. The filename is reset with the RESET command,
another OPEN or the CREATE command.
*/
static gpg_error_t
leave_cmd (assuan_context_t ctx, gpg_error_t err)
cmd_open (assuan_context_t ctx, char *line)
{
if (err)
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
char *p, *pend;
size_t len;
/* In any case reset the active container. */
xfree (ctrl->server_local->containername);
ctrl->server_local->containername = NULL;
/* Parse the line. */
line = skip_options (line);
for (p=line; *p && !spacep (p); p++)
;
pend = p;
while (spacep(p))
p++;
if (*p || pend == line)
{
const char *name = assuan_get_command_name (ctx);
if (!name)
name = "?";
if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
log_error ("command '%s' failed: %s\n", name,
gpg_strerror (err));
else
log_error ("command '%s' failed: %s <%s>\n", name,
gpg_strerror (err), gpg_strsource (err));
err = gpg_error (GPG_ERR_ASS_SYNTAX);
goto leave;
}
return err;
*pend = 0;
/* Unescape the line and check for embedded Nul bytes. */
len = percent_plus_unescape_inplace (line, 0);
line[len] = 0;
if (!len || memchr (line, 0, len))
{
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
/* Do a basic check. */
err = g13_is_container (ctrl, line);
if (err)
goto leave;
/* Store the filename. */
ctrl->server_local->containername = xtrystrdup (line);
if (!ctrl->server_local->containername)
err = gpg_error_from_syserror ();
leave:
return leave_cmd (ctx, err);
}
/* MOUNT [options] [<mountpoint>]
Mount the currently open file onto MOUNTPOINT. If MOUNTPOINT is
not given the system picks an unused mountpoint. MOUNTPOINT must
be percent-plus escaped to allow for arbitrary names.
*/
static gpg_error_t
cmd_mount (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
char *p, *pend;
size_t len;
line = skip_options (line);
for (p=line; *p && !spacep (p); p++)
;
pend = p;
while (spacep(p))
p++;
if (*p)
{
err = gpg_error (GPG_ERR_ASS_SYNTAX);
goto leave;
}
*pend = 0;
/* Unescape the line and check for embedded Nul bytes. */
len = percent_plus_unescape_inplace (line, 0);
line[len] = 0;
if (memchr (line, 0, len))
{
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
if (!ctrl->server_local->containername)
{
err = gpg_error (GPG_ERR_MISSING_ACTION);
goto leave;
}
/* Perform the mount. */
err = g13_mount_container (ctrl, ctrl->server_local->containername,
*line? line : NULL);
leave:
return leave_cmd (ctx, err);
}
/* UMOUNT [options] [<mountpoint>]
Unmount the currently open file or the one opened at MOUNTPOINT.
MOUNTPOINT must be percent-plus escaped.
*/
static gpg_error_t
cmd_umount (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
char *p, *pend;
size_t len;
line = skip_options (line);
for (p=line; *p && !spacep (p); p++)
;
pend = p;
while (spacep(p))
p++;
if (*p)
{
err = gpg_error (GPG_ERR_ASS_SYNTAX);
goto leave;
}
*pend = 0;
/* Unescape the line and check for embedded Nul bytes. */
len = percent_plus_unescape_inplace (line, 0);
line[len] = 0;
if (memchr (line, 0, len))
{
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
/* Perform the unmount. */
err = g13_umount_container (ctrl, ctrl->server_local->containername,
*line? line : NULL);
leave:
return leave_cmd (ctx, err);
}
@ -285,106 +398,26 @@ cmd_signer (assuan_context_t ctx, char *line)
}
/* SETMOUNTPOINT [options] [<dirname>]
/* CREATE [options] filename
Set DIRNAME as the new mount point for future operations.
Create a new container. On success the OPEN command is done
implictly for the new container.
*/
static gpg_error_t
cmd_setmountpoint (assuan_context_t ctx, char *line)
cmd_create (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
char *p, *pend;
size_t len;
gpg_error_t err;
line = skip_options (line);
for (p=line; *p && !spacep (p); p++)
;
pend = p;
while (spacep(p))
p++;
if (*p)
{
err = gpg_error (GPG_ERR_ASS_SYNTAX);
goto leave;
}
*pend = 0;
(void)ctrl;
/* Unescape the line and check for embedded Nul bytes. */
len = percent_plus_unescape_inplace (line, 0);
line[len] = 0;
if (memchr (line, 0, len))
{
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
xfree (ctrl->server_local->mountpoint);
if (!len) /* Reset mountpoint. */
ctrl->server_local->mountpoint = NULL;
else
{
ctrl->server_local->mountpoint = xtrystrdup (line);
if (!ctrl->server_local->mountpoint)
err = gpg_error_from_syserror ();
}
if (!err)
log_debug ("mountpoint is now `%s'\n",
ctrl->server_local->mountpoint
? ctrl->server_local->mountpoint: "[none]");
leave:
return leave_cmd (ctx, err);
}
/* First we close the active container. */
xfree (ctrl->server_local->containername);
ctrl->server_local->containername = NULL;
/* MOUNT [options] <containername>
Mount CONTAINERNAME onto the current mount point. CONTAINERNAME is
the name of a file in the g13 format and must be percent-plus
escaped to allow for arbitrary names. The mount poiunt must have
been set already.
A reason why we use a separate command for the mount point is to
allow for longer filenames (an assuan command line is limited to
~1000 byte.
*/
static gpg_error_t
cmd_mount (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
char *p, *pend;
size_t len;
line = skip_options (line);
for (p=line; *p && !spacep (p); p++)
;
pend = p;
while (spacep(p))
p++;
if (*p || pend == line)
{
err = gpg_error (GPG_ERR_ASS_SYNTAX);
goto leave;
}
*pend = 0;
/* Unescape the line and check for embedded Nul bytes. */
len = percent_plus_unescape_inplace (line, 0);
line[len] = 0;
if (!len || memchr (line, 0, len))
{
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
/* Perform the mount. */
err = g13_mount_container (ctrl, line, ctrl->server_local->mountpoint);
leave:
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return leave_cmd (ctx, err);
}
@ -476,10 +509,12 @@ register_commands (assuan_context_t ctx)
const char *name;
gpg_error_t (*handler)(assuan_context_t, char *line);
} table[] = {
{ "OPEN", cmd_open },
{ "MOUNT", cmd_mount },
{ "UMOUNT", cmd_umount },
{ "RECIPIENT", cmd_recipient },
{ "SIGNER", cmd_signer },
{ "MOUNT", cmd_mount },
{ "SETMOUNTPOINT", cmd_setmountpoint },
{ "CREATE", cmd_create },
{ "INPUT", NULL },
{ "OUTPUT", NULL },
{ "GETINFO", cmd_getinfo },