[svn] GnuPG - r5176 - trunk/g13
svn author wk
cvs at cvs.gnupg.org
Wed Oct 14 19:06:10 CEST 2009
Author: wk
Date: 2009-10-14 19:06:10 +0200 (Wed, 14 Oct 2009)
New Revision: 5176
Added:
trunk/g13/server.c
trunk/g13/server.h
Modified:
trunk/g13/Makefile.am
trunk/g13/be-encfs.c
trunk/g13/create.c
trunk/g13/g13.c
trunk/g13/g13.h
trunk/g13/runner.c
trunk/g13/runner.h
Log:
mount does now work in server and standalone mode.
Implemented a signal handler.
Modified: trunk/g13/Makefile.am
===================================================================
--- trunk/g13/Makefile.am 2009-10-13 19:17:24 UTC (rev 5175)
+++ trunk/g13/Makefile.am 2009-10-14 17:06:10 UTC (rev 5176)
@@ -30,6 +30,7 @@
g13.c g13.h \
keyblob.h \
utils.c utils.h \
+ server.c server.h \
create.c create.h \
mount.c mount.h \
call-gpg.c call-gpg.h \
Modified: trunk/g13/be-encfs.c
===================================================================
--- trunk/g13/be-encfs.c 2009-10-13 19:17:24 UTC (rev 5175)
+++ trunk/g13/be-encfs.c 2009-10-14 17:06:10 UTC (rev 5176)
@@ -262,7 +262,8 @@
pgmname = "/usr/bin/encfs";
idx = 0;
argv[idx++] = "-f";
- argv[idx++] = "-v";
+ if (opt.verbose)
+ argv[idx++] = "-v";
argv[idx++] = "--stdinpass";
argv[idx++] = "--annotate";
argv[idx++] = rawdir;
Modified: trunk/g13/create.c
===================================================================
--- trunk/g13/create.c 2009-10-13 19:17:24 UTC (rev 5175)
+++ trunk/g13/create.c 2009-10-14 17:06:10 UTC (rev 5176)
@@ -39,7 +39,7 @@
/* Create a new blob with all the session keys and other meta
information which are to be stored encrypted in the crypto
container header. On success the malloced blob is stored at R_BLOB
- and its length at R_BLOBLEN. On error en error ocde is returned
+ and its length at R_BLOBLEN. On error an error code is returned
and (R_BLOB,R_BLOBLEN) are set to (NULL,0).
The format of this blob is a sequence of tag-length-value tuples.
Modified: trunk/g13/g13.c
===================================================================
--- trunk/g13/g13.c 2009-10-13 19:17:24 UTC (rev 5175)
+++ trunk/g13/g13.c 2009-10-14 17:06:10 UTC (rev 5176)
@@ -36,8 +36,9 @@
#include "sysutils.h"
#include "gc-opt-flags.h"
#include "keyblob.h"
-#include "./runner.h"
-#include "./create.h"
+#include "server.h"
+#include "runner.h"
+#include "create.h"
#include "./mount.h"
@@ -51,6 +52,7 @@
aCreate,
aMount,
aUmount,
+ aServer,
oOptions,
oDebug,
@@ -102,6 +104,7 @@
ARGPARSE_c (aCreate, "create", N_("Create a new file system container")),
ARGPARSE_c (aMount, "mount", N_("Mount a file system container") ),
ARGPARSE_c (aUmount, "umount", N_("Unmount a file system container") ),
+ ARGPARSE_c (aServer, "server", N_("Run in server mode")),
ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"),
@@ -168,6 +171,10 @@
};
+/* The timer tick interval used by the idle task. */
+#define TIMERTICK_INTERVAL_SEC (1)
+
+
/* Global variable to keep an error count. */
int g13_errors_seen = 0;
@@ -178,11 +185,23 @@
static const char *debug_level;
static unsigned int debug_value;
+/* Flag to indicate that a shutdown was requested. */
+static int shutdown_pending;
+
+/* The thread id of the idle task. */
+static pth_t idle_task_tid;
+
+
+
static void set_cmd (enum cmd_and_opt_values *ret_cmd,
enum cmd_and_opt_values new_cmd );
static void emergency_cleanup (void);
+static void start_idle_task (void);
+static void join_idle_task (void);
+
+
/* Begin Pth wrapper functions. */
GCRY_THREAD_OPTION_PTH_IMPL;
static int fixed_gcry_pth_init (void)
@@ -475,6 +494,7 @@
nokeysetup = 1;
break;
+ case aServer:
case aMount:
case aUmount:
nokeysetup = 1;
@@ -591,9 +611,9 @@
if (greeting)
{
- fprintf(stderr, "%s %s; %s\n",
- strusage(11), strusage(13), strusage(14) );
- fprintf(stderr, "%s\n", strusage(15) );
+ fprintf (stderr, "%s %s; %s\n",
+ strusage(11), strusage(13), strusage(14) );
+ fprintf (stderr, "%s\n", strusage(15) );
}
if (may_coredump && !opt.quiet)
@@ -680,24 +700,25 @@
configuration file is valid. */
break;
+ case aServer:
+ {
+ start_idle_task ();
+ err = g13_server (&ctrl);
+ if (err)
+ log_error ("server exited with error: %s <%s>\n",
+ gpg_strerror (err), gpg_strsource (err));
+ }
+ break;
+
case aCreate: /* Create a new container. */
{
if (argc != 1)
wrong_args ("--create filename");
+ start_idle_task ();
err = g13_create_container (&ctrl, argv[0]);
if (err)
log_error ("error creating a new container: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
- else
- {
- unsigned int n;
-
- while ((n = runner_get_threads ()))
- {
- log_info ("number of running threads: %u\n", n);
- pth_sleep (5);
- }
- }
}
break;
@@ -705,20 +726,11 @@
{
if (argc != 1 && argc != 2 )
wrong_args ("--mount filename [mountpoint]");
+ start_idle_task ();
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;
@@ -727,6 +739,9 @@
break;
}
+ if (!err)
+ join_idle_task ();
+
/* Print the audit result if needed. */
if (auditlog && auditfp)
{
@@ -741,6 +756,7 @@
return 8; /*NOTREACHED*/
}
+
/* Note: This function is used by signal handlers!. */
static void
emergency_cleanup (void)
@@ -766,6 +782,7 @@
}
+/* Store defaults into the per-connection CTRL object. */
void
g13_init_default_ctrl (struct server_control_s *ctrl)
{
@@ -773,84 +790,179 @@
}
-/* static void */
-/* daemonize (int nodetach) */
-/* { */
-/* gnupg_fd_t fd; */
-/* gnupg_fd_t fd_ssh; */
-/* pid_t pid; */
+/* This function is called for each signal we catch. It is run in the
+ main context or the one of a Pth thread and thus it is not
+ restricted in what it may do. */
+static void
+handle_signal (int signo)
+{
+ switch (signo)
+ {
+#ifndef HAVE_W32_SYSTEM
+ case SIGHUP:
+ log_info ("SIGHUP received - re-reading configuration\n");
+ /* Fixme: Not yet implemented. */
+ break;
+
+ case SIGUSR1:
+ log_info ("SIGUSR1 received - printing internal information:\n");
+ pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
+ break;
-/* 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 *\/ */
+ case SIGUSR2:
+ log_info ("SIGUSR2 received - no action defined\n");
+ break;
-/* /\* */
-/* This is the child */
-/* *\/ */
-
-/* /\* Detach from tty and put process into a new session *\/ */
-/* if (!nodetach ) */
-/* { */
-/* int i; */
-/* unsigned int oldflags; */
+ case SIGTERM:
+ if (!shutdown_pending)
+ log_info ("SIGTERM received - shutting down ...\n");
+ else
+ log_info ("SIGTERM received - still %u runners active\n",
+ runner_get_threads ());
+ shutdown_pending++;
+ if (shutdown_pending > 2)
+ {
+ log_info ("shutdown forced\n");
+ log_info ("%s %s stopped\n", strusage(11), strusage(13) );
+ g13_exit (0);
+ }
+ break;
-/* /\* 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); */
-/* } */
+ case SIGINT:
+ log_info ("SIGINT received - immediate shutdown\n");
+ log_info( "%s %s stopped\n", strusage(11), strusage(13));
+ g13_exit (0);
+ break;
+#endif /*!HAVE_W32_SYSTEM*/
+
+ default:
+ log_info ("signal %d received - no action defined\n", signo);
+ }
+}
-/* log_get_prefix (&oldflags); */
-/* log_set_prefix (NULL, oldflags | JNLIB_LOG_RUN_DETACHED); */
-/* opt.running_detached = 1; */
-/* } */
+
+/* This ticker function is called about every TIMERTICK_INTERVAL_SEC
+ seconds. */
+static void
+handle_tick (void)
+{
+ /* log_debug ("TICK\n"); */
+}
+
+
+/* The idle task. We use a separate thread to do idle stuff and to
+ catch signals. */
+static void *
+idle_task (void *dummy_arg)
+{
+ sigset_t sigs; /* The set of signals we want to catch. */
+ pth_event_t ev; /* The main event to catch signals. */
+ pth_event_t time_ev; /* The time event. */
+ int signo; /* The number of a raised signal is stored here. */
+
+ (void)dummy_arg;
+
+ /* Create the event to catch the signals. */
+#ifndef HAVE_W32_SYSTEM
+ sigemptyset (&sigs );
+ sigaddset (&sigs, SIGHUP);
+ sigaddset (&sigs, SIGUSR1);
+ sigaddset (&sigs, SIGUSR2);
+ sigaddset (&sigs, SIGINT);
+ sigaddset (&sigs, SIGTERM);
+ pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
+#else
+ sigs = 0;
+#endif
+ ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
+
+ /* The time event neds to computed n tghe fly. */
+ time_ev = NULL;
+
+ for (;;)
+ {
+ /* The shutdown flag allows us to terminate the idle task. */
+ if (shutdown_pending)
+ {
+ runner_cancel_all ();
+
+ if (!runner_get_threads ())
+ break; /* ready */
+ }
+
+ /* Create a timeout event if needed. To help with power saving
+ we syncronize the ticks to the next full second. */
+ if (!time_ev)
+ {
+ pth_time_t nexttick;
+
+ nexttick = pth_timeout (TIMERTICK_INTERVAL_SEC, 0);
+ if (nexttick.tv_usec > 10) /* Use a 10 usec threshhold. */
+ {
+ nexttick.tv_sec++;
+ nexttick.tv_usec = 0;
+ }
+ time_ev = pth_event (PTH_EVENT_TIME, nexttick);
+ }
+
+ pth_event_concat (ev, time_ev, NULL);
+ pth_wait (ev);
+ pth_event_isolate (time_ev);
+
+ if (pth_event_occurred (ev))
+ {
+ handle_signal (signo);
+ }
+
+ if (time_ev && pth_event_occurred (time_ev))
+ {
+ pth_event_free (time_ev, PTH_FREE_ALL);
+ time_ev = NULL;
+ handle_tick ();
+ }
+ }
+
+ pth_event_free (ev, PTH_FREE_ALL);
+ if (time_ev)
+ pth_event_free (time_ev, PTH_FREE_ALL);
+ log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
+ return NULL;
+}
+
+
+/* Start the idle task. */
+static void
+start_idle_task (void)
+{
+ pth_attr_t tattr;
+ pth_t tid;
-/* if (chdir("/")) */
-/* { */
-/* log_error ("chdir to / failed: %s\n", strerror (errno)); */
-/* exit (1); */
-/* } */
+ tattr = pth_attr_new ();
+ pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
+ pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
+ pth_attr_set (tattr, PTH_ATTR_NAME, "idle-task");
+
+ tid = pth_spawn (tattr, idle_task, NULL);
+ if (!tid)
+ {
+ log_fatal ("error starting idle task: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ return; /*NOTREACHED*/
+ }
+ idle_task_tid = tid;
+ pth_attr_destroy (tattr);
+}
-/* { */
-/* 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); */
-/* } */
+/* Wait for the idle task to finish. */
+static void
+join_idle_task (void)
+{
+ if (idle_task_tid)
+ {
+ if (!pth_join (idle_task_tid, NULL))
+ log_error ("waiting for idle task thread failed: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ }
+}
+
Modified: trunk/g13/g13.h
===================================================================
--- trunk/g13/g13.h 2009-10-13 19:17:24 UTC (rev 5175)
+++ trunk/g13/g13.h 2009-10-14 17:06:10 UTC (rev 5176)
@@ -30,6 +30,7 @@
#include "../common/status.h"
#include "../common/estream.h"
#include "../common/audit.h"
+#include "../common/session-env.h"
/* A large struct named "opt" to keep global flags. */
struct
@@ -58,6 +59,7 @@
char *lc_messages;
char *xauthority;
char *pinentry_user_data;
+ session_env_t session_env;
/* Name of the output file - FIXME: what is this? */
const char *outfile;
Modified: trunk/g13/runner.c
===================================================================
--- trunk/g13/runner.c 2009-10-13 19:17:24 UTC (rev 5175)
+++ trunk/g13/runner.c 2009-10-14 17:06:10 UTC (rev 5176)
@@ -40,9 +40,12 @@
int spawned; /* True if runner_spawn has been called. */
pth_t threadid; /* The TID of the runner thread. */
+ runner_t next_running; /* Builds a list of all running threads. */
+ int canceled; /* Set if a cancel has already been send once. */
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:
@@ -66,10 +69,11 @@
};
-/* Avariabale to track the number of active runner threads. */
-static unsigned int thread_count;
+/* The head of the list of all running threads. */
+static runner_t running_threads;
+
/* Write NBYTES of BUF to file descriptor FD. */
static int
@@ -114,7 +118,12 @@
unsigned int
runner_get_threads (void)
{
- return thread_count;
+ unsigned int n = 0;
+ runner_t r;
+
+ for (r = running_threads; r; r = r->next_running)
+ n++;
+ return n;
}
@@ -240,7 +249,7 @@
runner_thread (void *arg)
{
runner_t runner = arg;
- gpg_error_t err;
+ gpg_error_t err = 0;
log_debug ("starting runner thread\n");
/* If a status_fp is available, the thread's main task is to read
@@ -257,7 +266,6 @@
estream_t fp = runner->status_fp;
pos = 0;
- err = 0;
cont_line = 0;
while (!err && !runner->cancel_flag && (c=es_getc (fp)) != EOF)
{
@@ -322,9 +330,22 @@
/* Get rid of the runner object (note: it is refcounted). */
log_debug ("runner thread releasing runner ...\n");
+ {
+ runner_t r, rprev;
+
+ for (r = running_threads, rprev = NULL; r; rprev = r, r = r->next_running)
+ if (r == runner)
+ {
+ if (!rprev)
+ running_threads = r->next_running;
+ else
+ rprev->next_running = r->next_running;
+ r->next_running = NULL;
+ break;
+ }
+ }
runner_release (runner);
log_debug ("runner thread runner released\n");
- thread_count--;
return NULL;
}
@@ -374,14 +395,14 @@
}
/* 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;
+ runner->next_running = running_threads;
+ running_threads = runner;
+
pth_attr_destroy (tattr);
/* The runner thread is now runnable. */
-
-
return 0;
}
@@ -391,8 +412,10 @@
void
runner_cancel (runner_t runner)
{
+ /* Warning: runner_cancel_all has knowledge of this code. */
if (runner->spawned)
{
+ runner->canceled = 1; /* Mark that we canceled this one already. */
/* 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;
@@ -402,6 +425,25 @@
}
+/* Cancel all runner threads. */
+void
+runner_cancel_all (void)
+{
+ runner_t r;
+
+ do
+ {
+ for (r = running_threads; r; r = r->next_running)
+ if (r->spawned && !r->canceled)
+ {
+ runner_cancel (r);
+ break;
+ }
+ }
+ while (r);
+}
+
+
/* 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. */
Modified: trunk/g13/runner.h
===================================================================
--- trunk/g13/runner.h 2009-10-13 19:17:24 UTC (rev 5175)
+++ trunk/g13/runner.h 2009-10-14 17:06:10 UTC (rev 5176)
@@ -57,6 +57,9 @@
/* Cancel a runner. */
void runner_cancel (runner_t runner);
+/* Cancel all runner. */
+void runner_cancel_all (void);
+
/* Send data back to the engine. This function is used by the
engine's handler. */
gpg_error_t runner_send_line (runner_t runner,
Added: trunk/g13/server.c
===================================================================
--- trunk/g13/server.c (rev 0)
+++ trunk/g13/server.c 2009-10-14 17:06:10 UTC (rev 5176)
@@ -0,0 +1,709 @@
+/* server.c - The G13 Assuan server
+ * 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 <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "g13.h"
+#include <assuan.h>
+#include "i18n.h"
+#include "keyblob.h"
+#include "./server.h"
+#include "./mount.h"
+
+
+/* Local data for this server module. A pointer to this is stored in
+ the CTRL object of each connection. */
+struct server_local_s
+{
+ /* The Assuan contect we are working on. */
+ assuan_context_t assuan_ctx;
+
+ char *mountpoint; /* Malloced current mountpoint. */
+
+};
+
+
+/* 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; */
+
+
+
+
+static int command_has_option (const char *cmd, const char *cmdopt);
+
+
+
+
+#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
+
+
+
+
+/* Skip over options.
+ Blanks after the options are also removed. */
+static char *
+skip_options (const char *line)
+{
+ while (spacep (line))
+ line++;
+ while ( *line == '-' && line[1] == '-' )
+ {
+ while (*line && !spacep (line))
+ line++;
+ while (spacep (line))
+ line++;
+ }
+ return (char*)line;
+}
+
+
+/* Check whether the option NAME appears in LINE. */
+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)));
+}
+
+
+/* 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))
+ {
+ errno = EIO;
+ return -1;
+ }
+
+ 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;
+}
+
+
+/* The handler for Assuan OPTION commands. */
+static gpg_error_t
+option_handler (assuan_context_t ctx, const char *key, const char *value)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err = 0;
+
+ if (!strcmp (key, "putenv"))
+ {
+ /* Change the session's environment to be used for the
+ Pinentry. Valid values are:
+ <NAME> Delete envvar NAME
+ <KEY>= Set envvar NAME to the empty string
+ <KEY>=<VALUE> Set envvar NAME to VALUE
+ */
+ err = session_env_putenv (opt.session_env, value);
+ }
+ else if (!strcmp (key, "display"))
+ {
+ err = session_env_setenv (opt.session_env, "DISPLAY", value);
+ }
+ else if (!strcmp (key, "ttyname"))
+ {
+ err = session_env_setenv (opt.session_env, "GPG_TTY", value);
+ }
+ else if (!strcmp (key, "ttytype"))
+ {
+ err = session_env_setenv (opt.session_env, "TERM", value);
+ }
+ else if (!strcmp (key, "lc-ctype"))
+ {
+ xfree (opt.lc_ctype);
+ opt.lc_ctype = xtrystrdup (value);
+ if (!opt.lc_ctype)
+ err = gpg_error_from_syserror ();
+ }
+ else if (!strcmp (key, "lc-messages"))
+ {
+ xfree (opt.lc_messages);
+ opt.lc_messages = xtrystrdup (value);
+ if (!opt.lc_messages)
+ err = gpg_error_from_syserror ();
+ }
+ else if (!strcmp (key, "xauthority"))
+ {
+ err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
+ }
+ else if (!strcmp (key, "pinentry-user-data"))
+ {
+ err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
+ }
+ else if (!strcmp (key, "enable-audit-log"))
+ {
+ /* This is not yet used. */
+ /* int i = *value? atoi (value) : 0; */
+ /* ctrl->server_local->enable_audit_log = i; */
+ }
+ else if (!strcmp (key, "allow-pinentry-notify"))
+ {
+ ; /* We always allow it. */
+ }
+ else
+ err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
+
+ return err;
+}
+
+
+/* The handler for an Assuan RESET command. */
+static void
+reset_notify (assuan_context_t ctx)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+
+ xfree (ctrl->server_local->mountpoint);
+ ctrl->server_local->mountpoint = NULL;
+
+ assuan_close_input_fd (ctx);
+ assuan_close_output_fd (ctx);
+}
+
+
+/* Helper to print a message while leaving a command. */
+static gpg_error_t
+leave_cmd (assuan_context_t ctx, gpg_error_t err)
+{
+ if (err)
+ {
+ 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 err;
+}
+
+
+
+/* RECIPIENT <userID>
+
+ FIXME - description.
+ All RECIPIENT commands are cumulative until a RESET or an
+ successful CREATE command.
+ */
+static gpg_error_t
+cmd_recipient (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+
+ (void)ctrl;
+ err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ /* err = gpgsm_add_to_certlist (ctrl, line, 0, */
+ /* &ctrl->server_local->recplist, 0); */
+ /* if (err) */
+ /* { */
+ /* gpgsm_status2 (ctrl, STATUS_INV_RECP, */
+ /* get_inv_recpsgnr_code (rc), line, NULL); */
+ /* } */
+
+ return leave_cmd (ctx, err);
+}
+
+
+/* SIGNER <userID>
+
+ FIXME - description.
+ */
+static gpg_error_t
+cmd_signer (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+
+ (void)ctrl;
+
+ err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ return leave_cmd (ctx, err);
+}
+
+
+/* SETMOUNTPOINT [options] [<dirname>]
+
+ Set DIRNAME as the new mount point for future operations.
+ */
+static gpg_error_t
+cmd_setmountpoint (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;
+ }
+
+ 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);
+}
+
+
+/* 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:
+ return leave_cmd (ctx, err);
+}
+
+
+/* GETINFO <what>
+
+ Multipurpose function to return a variety of information.
+ Supported values for WHAT are:
+
+ version - Return the version of the program.
+ pid - Return the process id of the server.
+ cmd_has_option CMD OPT
+ - Returns OK if the command CMD implements the option OPT.
+
+ */
+static gpg_error_t
+cmd_getinfo (assuan_context_t ctx, char *line)
+{
+ gpg_error_t err = 0;
+
+ if (!strcmp (line, "version"))
+ {
+ const char *s = PACKAGE_VERSION;
+ err = assuan_send_data (ctx, s, strlen (s));
+ }
+ else if (!strcmp (line, "pid"))
+ {
+ char numbuf[50];
+
+ snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
+ err = assuan_send_data (ctx, numbuf, strlen (numbuf));
+ }
+ else if (!strncmp (line, "cmd_has_option", 14)
+ && (line[14] == ' ' || line[14] == '\t' || !line[14]))
+ {
+ char *cmd, *cmdopt;
+ line += 14;
+ while (*line == ' ' || *line == '\t')
+ line++;
+ if (!*line)
+ err = gpg_error (GPG_ERR_MISSING_VALUE);
+ else
+ {
+ cmd = line;
+ while (*line && (*line != ' ' && *line != '\t'))
+ line++;
+ if (!*line)
+ err = gpg_error (GPG_ERR_MISSING_VALUE);
+ else
+ {
+ *line++ = 0;
+ while (*line == ' ' || *line == '\t')
+ line++;
+ if (!*line)
+ err = gpg_error (GPG_ERR_MISSING_VALUE);
+ else
+ {
+ cmdopt = line;
+ if (!command_has_option (cmd, cmdopt))
+ err = gpg_error (GPG_ERR_GENERAL);
+ }
+ }
+ }
+ }
+ else
+ err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
+
+ return leave_cmd (ctx, err);
+}
+
+
+
+/* Return true if the command CMD implements the option CMDOPT. */
+static int
+command_has_option (const char *cmd, const char *cmdopt)
+{
+ (void)cmd;
+ (void)cmdopt;
+
+ return 0;
+}
+
+
+/* Tell the Assuan library about our commands. */
+static int
+register_commands (assuan_context_t ctx)
+{
+ static struct {
+ const char *name;
+ gpg_error_t (*handler)(assuan_context_t, char *line);
+ } table[] = {
+ { "RECIPIENT", cmd_recipient },
+ { "SIGNER", cmd_signer },
+ { "MOUNT", cmd_mount },
+ { "SETMOUNTPOINT", cmd_setmountpoint },
+ { "INPUT", NULL },
+ { "OUTPUT", NULL },
+ { "GETINFO", cmd_getinfo },
+ { NULL }
+ };
+ gpg_error_t err;
+ int i;
+
+ for (i=0; table[i].name; i++)
+ {
+ err = assuan_register_command (ctx, table[i].name, table[i].handler);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+
+/* Startup the server. DEFAULT_RECPLIST is the list of recipients as
+ set from the command line or config file. We only require those
+ marked as encrypt-to. */
+gpg_error_t
+g13_server (ctrl_t ctrl)
+{
+ gpg_error_t err;
+ int filedes[2];
+ assuan_context_t ctx = NULL;
+ static const char hello[] = ("GNU Privacy Guard's G13 server "
+ PACKAGE_VERSION " ready");
+
+ /* We use a pipe based server so that we can work from scripts.
+ assuan_init_pipe_server will automagically detect when we are
+ called with a socketpair and ignore FIELDES in this case. */
+ filedes[0] = 0;
+ filedes[1] = 1;
+ err = assuan_new (&ctx);
+ if (err)
+ {
+ log_error ("failed to allocate an Assuan context: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+
+ err = assuan_init_pipe_server (ctx, filedes);
+ if (err)
+ {
+ log_error ("failed to initialize the server: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ err = register_commands (ctx);
+ if (err)
+ {
+ log_error ("failed to the register commands with Assuan: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+
+ assuan_set_pointer (ctx, ctrl);
+
+ if (opt.verbose || opt.debug)
+ {
+ char *tmp = NULL;
+ const char *s1 = getenv ("GPG_AGENT_INFO");
+
+ tmp = xtryasprintf ("Home: %s\n"
+ "Config: %s\n"
+ "AgentInfo: %s\n"
+ "%s",
+ opt.homedir,
+ opt.config_filename,
+ s1?s1:"[not set]",
+ hello);
+ if (tmp)
+ {
+ assuan_set_hello_line (ctx, tmp);
+ xfree (tmp);
+ }
+ }
+ else
+ assuan_set_hello_line (ctx, hello);
+
+ assuan_register_reset_notify (ctx, reset_notify);
+ assuan_register_option_handler (ctx, option_handler);
+
+ ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
+ if (!ctrl->server_local)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ ctrl->server_local->assuan_ctx = ctx;
+
+ if (DBG_ASSUAN)
+ assuan_set_log_stream (ctx, log_get_stream ());
+
+ while ( !(err = assuan_accept (ctx)) )
+ {
+ err = assuan_process (ctx);
+ if (err)
+ log_info ("Assuan processing failed: %s\n", gpg_strerror (err));
+ }
+ if (err == -1)
+ err = 0;
+ else
+ log_info ("Assuan accept problem: %s\n", gpg_strerror (err));
+
+ leave:
+ if (ctrl->server_local)
+ {
+ xfree (ctrl->server_local);
+ ctrl->server_local = NULL;
+ }
+
+ assuan_release (ctx);
+ return err;
+}
+
+
+
+/* gpg_error_t */
+/* gpgsm_status2 (ctrl_t ctrl, int no, ...) */
+/* { */
+/* gpg_error_t err = 0; */
+/* va_list arg_ptr; */
+/* const char *text; */
+
+/* va_start (arg_ptr, no); */
+
+/* if (ctrl->no_server && ctrl->status_fd == -1) */
+/* ; /\* No status wanted. *\/ */
+/* else if (ctrl->no_server) */
+/* { */
+/* if (!statusfp) */
+/* { */
+/* if (ctrl->status_fd == 1) */
+/* statusfp = stdout; */
+/* else if (ctrl->status_fd == 2) */
+/* statusfp = stderr; */
+/* else */
+/* statusfp = fdopen (ctrl->status_fd, "w"); */
+
+/* if (!statusfp) */
+/* { */
+/* log_fatal ("can't open fd %d for status output: %s\n", */
+/* ctrl->status_fd, strerror(errno)); */
+/* } */
+/* } */
+
+/* fputs ("[GNUPG:] ", statusfp); */
+/* fputs (get_status_string (no), statusfp); */
+
+/* while ( (text = va_arg (arg_ptr, const char*) )) */
+/* { */
+/* putc ( ' ', statusfp ); */
+/* for (; *text; text++) */
+/* { */
+/* if (*text == '\n') */
+/* fputs ( "\\n", statusfp ); */
+/* else if (*text == '\r') */
+/* fputs ( "\\r", statusfp ); */
+/* else */
+/* putc ( *(const byte *)text, statusfp ); */
+/* } */
+/* } */
+/* putc ('\n', statusfp); */
+/* fflush (statusfp); */
+/* } */
+/* else */
+/* { */
+/* assuan_context_t ctx = ctrl->server_local->assuan_ctx; */
+/* char buf[950], *p; */
+/* size_t n; */
+
+/* p = buf; */
+/* n = 0; */
+/* while ( (text = va_arg (arg_ptr, const char *)) ) */
+/* { */
+/* if (n) */
+/* { */
+/* *p++ = ' '; */
+/* n++; */
+/* } */
+/* for ( ; *text && n < DIM (buf)-2; n++) */
+/* *p++ = *text++; */
+/* } */
+/* *p = 0; */
+/* err = assuan_write_status (ctx, get_status_string (no), buf); */
+/* } */
+
+/* va_end (arg_ptr); */
+/* return err; */
+/* } */
+
+/* gpg_error_t */
+/* gpgsm_status (ctrl_t ctrl, int no, const char *text) */
+/* { */
+/* return gpgsm_status2 (ctrl, no, text, NULL); */
+/* } */
+
+/* gpg_error_t */
+/* gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text, */
+/* gpg_err_code_t ec) */
+/* { */
+/* char buf[30]; */
+
+/* sprintf (buf, "%u", (unsigned int)ec); */
+/* if (text) */
+/* return gpgsm_status2 (ctrl, no, text, buf, NULL); */
+/* else */
+/* return gpgsm_status2 (ctrl, no, buf, NULL); */
+/* } */
+
+
+/* Helper to notify the client about Pinentry events. Returns an gpg
+ error code. */
+gpg_error_t
+g13_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
+{
+ if (!ctrl || !ctrl->server_local)
+ return 0;
+ return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
+}
+
+
+
+
Added: trunk/g13/server.h
===================================================================
--- trunk/g13/server.h (rev 0)
+++ trunk/g13/server.h 2009-10-14 17:06:10 UTC (rev 5176)
@@ -0,0 +1,29 @@
+/* server.h - The G13 Assuan server
+ * 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_SERVER_H
+#define G13_SERVER_H
+
+
+gpg_error_t g13_server (ctrl_t ctrl);
+
+gpg_error_t g13_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line);
+
+#endif /*G13_SERVER_H*/
+
More information about the Gnupg-commits
mailing list