mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
mount does now work in server and standalone mode.
Implemented a signal handler.
This commit is contained in:
parent
536b6ab09f
commit
1445c15ed1
@ -30,6 +30,7 @@ g13_SOURCES = \
|
||||
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 \
|
||||
|
@ -262,7 +262,8 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
|
||||
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;
|
||||
|
@ -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.
|
||||
|
314
g13/g13.c
314
g13/g13.c
@ -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 @@ enum cmd_and_opt_values {
|
||||
aCreate,
|
||||
aMount,
|
||||
aUmount,
|
||||
aServer,
|
||||
|
||||
oOptions,
|
||||
oDebug,
|
||||
@ -102,6 +104,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
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 @@ static ARGPARSE_OPTS opts[] = {
|
||||
};
|
||||
|
||||
|
||||
/* 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 int maybe_setuid = 1;
|
||||
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 @@ main ( int argc, char **argv)
|
||||
nokeysetup = 1;
|
||||
break;
|
||||
|
||||
case aServer:
|
||||
case aMount:
|
||||
case aUmount:
|
||||
nokeysetup = 1;
|
||||
@ -591,9 +611,9 @@ main ( int argc, char **argv)
|
||||
|
||||
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 @@ main ( int argc, char **argv)
|
||||
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 @@ main ( int argc, char **argv)
|
||||
{
|
||||
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 @@ main ( int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
join_idle_task ();
|
||||
|
||||
/* Print the audit result if needed. */
|
||||
if (auditlog && auditfp)
|
||||
{
|
||||
@ -741,6 +756,7 @@ main ( int argc, char **argv)
|
||||
return 8; /*NOTREACHED*/
|
||||
}
|
||||
|
||||
|
||||
/* Note: This function is used by signal handlers!. */
|
||||
static void
|
||||
emergency_cleanup (void)
|
||||
@ -766,6 +782,7 @@ g13_exit (int rc)
|
||||
}
|
||||
|
||||
|
||||
/* Store defaults into the per-connection CTRL object. */
|
||||
void
|
||||
g13_init_default_ctrl (struct server_control_s *ctrl)
|
||||
{
|
||||
@ -773,84 +790,179 @@ 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; */
|
||||
/* 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;
|
||||
|
||||
/* /\* 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 SIGUSR1:
|
||||
log_info ("SIGUSR1 received - printing internal information:\n");
|
||||
pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ());
|
||||
break;
|
||||
|
||||
/* log_get_prefix (&oldflags); */
|
||||
/* log_set_prefix (NULL, oldflags | JNLIB_LOG_RUN_DETACHED); */
|
||||
/* opt.running_detached = 1; */
|
||||
/* } */
|
||||
case SIGUSR2:
|
||||
log_info ("SIGUSR2 received - no action defined\n");
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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 ()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 @@ struct
|
||||
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;
|
||||
|
60
g13/runner.c
60
g13/runner.c
@ -40,9 +40,12 @@ struct runner_s
|
||||
|
||||
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,8 +69,9 @@ struct runner_s
|
||||
};
|
||||
|
||||
|
||||
/* 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;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -114,7 +118,12 @@ check_already_spawned (runner_t runner, const char *funcname)
|
||||
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 @@ static void *
|
||||
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 @@ runner_thread (void *arg)
|
||||
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 @@ runner_thread (void *arg)
|
||||
|
||||
/* 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 @@ runner_spawn (runner_t runner)
|
||||
}
|
||||
/* 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 @@ runner_spawn (runner_t runner)
|
||||
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 @@ runner_cancel (runner_t runner)
|
||||
}
|
||||
|
||||
|
||||
/* 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. */
|
||||
|
@ -57,6 +57,9 @@ gpg_error_t runner_spawn (runner_t runner);
|
||||
/* 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,
|
||||
|
709
g13/server.c
Normal file
709
g13/server.c
Normal file
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
29
g13/server.h
Normal file
29
g13/server.h
Normal file
@ -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*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user