Merge branch 'switch-to-gpgk' into master

--
Resolved Conflicts:

* common/asshelp.c: Keep the new code in master for spawing under
Windows.
* g10/Makefile.am: Keep all new file.
* g10/photoid.c: Pass CTRL to pct_expando.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-09-27 15:44:23 +02:00
commit 9698761933
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
61 changed files with 7194 additions and 507 deletions

View File

@ -56,9 +56,11 @@
operation after we started them before giving up. */
#ifdef HAVE_W32CE_SYSTEM
# define SECS_TO_WAIT_FOR_AGENT 30
# define SECS_TO_WAIT_FOR_KEYBOXD 30
# define SECS_TO_WAIT_FOR_DIRMNGR 30
#else
# define SECS_TO_WAIT_FOR_AGENT 5
# define SECS_TO_WAIT_FOR_KEYBOXD 5
# define SECS_TO_WAIT_FOR_DIRMNGR 5
#endif
@ -308,17 +310,15 @@ unlock_spawning (lock_spawn_t *lock, const char *name)
}
/* Helper for start_new_gpg_agent and start_new_dirmngr.
* Values for WHICH are:
* 0 - Start gpg-agent
* 1 - Start dirmngr
* SECS give the number of seconds to wait. SOCKNAME is the name of
* the socket to connect. VERBOSE is the usual verbose flag. CTX is
* the assuan context. DID_SUCCESS_MSG will be set to 1 if a success
* messages has been printed.
/* Helper to start a service. SECS gives the number of seconds to
* wait. SOCKNAME is the name of the socket to connect. VERBOSE is
* the usual verbose flag. CTX is the assuan context. CONNECT_FLAGS
* are the assuan connect flags. DID_SUCCESS_MSG will be set to 1 if
* a success messages has been printed.
*/
static gpg_error_t
wait_for_sock (int secs, int which, const char *sockname,
wait_for_sock (int secs, int module_name_id, const char *sockname,
unsigned int connect_flags,
int verbose, assuan_context_t ctx, int *did_success_msg)
{
gpg_error_t err = 0;
@ -343,8 +343,10 @@ wait_for_sock (int secs, int which, const char *sockname,
/* next_sleep_us); */
if (secsleft < lastalert)
{
log_info (which == 1?
log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR?
_("waiting for the dirmngr to come up ... (%ds)\n"):
module_name_id == GNUPG_MODULE_NAME_KEYBOXD?
_("waiting for the keyboxd to come up ... (%ds)\n"):
_("waiting for the agent to come up ... (%ds)\n"),
secsleft);
lastalert = secsleft;
@ -352,13 +354,15 @@ wait_for_sock (int secs, int which, const char *sockname,
}
gnupg_usleep (next_sleep_us);
elapsed_us += next_sleep_us;
err = assuan_socket_connect (ctx, sockname, 0, 0);
err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
if (!err)
{
if (verbose)
{
log_info (which == 1?
log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR?
_("connection to the dirmngr established\n"):
module_name_id == GNUPG_MODULE_NAME_KEYBOXD?
_("connection to the keyboxd established\n"):
_("connection to the agent established\n"));
*did_success_msg = 1;
}
@ -372,25 +376,35 @@ wait_for_sock (int secs, int which, const char *sockname,
}
/* Try to connect to the agent via socket or start it if it is not
running and AUTOSTART is set. Handle the server's initial
greeting. Returns a new assuan context at R_CTX or an error
code. */
gpg_error_t
start_new_gpg_agent (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *agent_program,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
int autostart, int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
/* Try to connect to a new service via socket or start it if it is not
* running and AUTOSTART is set. Handle the server's initial
* greeting. Returns a new assuan context at R_CTX or an error code.
* MODULE_NAME_ID is one of:
* GNUPG_MODULE_NAME_AGENT
* GNUPG_MODULE_NAME_DIRMNGR
*/
static gpg_error_t
start_new_service (assuan_context_t *r_ctx,
int module_name_id,
gpg_err_source_t errsource,
const char *program_name,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
int autostart, int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
gpg_error_t err;
assuan_context_t ctx;
int did_success_msg = 0;
char *sockname;
const char *printed_name;
const char *lock_name;
const char *status_start_line;
int no_service_err;
int seconds_to_wait;
unsigned int connect_flags = 0;
const char *argv[6];
*r_ctx = NULL;
@ -402,15 +416,40 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
return err;
}
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
if (!sockname)
switch (module_name_id)
{
err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
case GNUPG_MODULE_NAME_AGENT:
sockname = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
lock_name = "agent";
printed_name = "gpg-agent";
status_start_line = "starting_agent ? 0 0";
no_service_err = GPG_ERR_NO_AGENT;
seconds_to_wait = SECS_TO_WAIT_FOR_AGENT;
break;
case GNUPG_MODULE_NAME_DIRMNGR:
sockname = make_filename (gnupg_socketdir (), DIRMNGR_SOCK_NAME, NULL);
lock_name = "dirmngr";
printed_name = "dirmngr";
status_start_line = "starting_dirmngr ? 0 0";
no_service_err = GPG_ERR_NO_DIRMNGR;
seconds_to_wait = SECS_TO_WAIT_FOR_DIRMNGR;
break;
case GNUPG_MODULE_NAME_KEYBOXD:
sockname = make_filename (gnupg_socketdir (), KEYBOXD_SOCK_NAME, NULL);
lock_name = "keyboxd";
printed_name = "keyboxd";
status_start_line = "starting_keyboxd ? 0 0";
no_service_err = GPG_ERR_NO_KEYBOXD;
seconds_to_wait = SECS_TO_WAIT_FOR_KEYBOXD;
connect_flags |= ASSUAN_SOCKET_CONNECT_FDPASSING;
break;
default:
err = gpg_error (GPG_ERR_INV_ARG);
assuan_release (ctx);
return err;
}
err = assuan_socket_connect (ctx, sockname, 0, 0);
err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
if (err && autostart)
{
char *abs_homedir;
@ -422,12 +461,12 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
int i;
/* With no success start a new server. */
if (!agent_program || !*agent_program)
agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
else if ((s=strchr (agent_program, '|')) && s[1] == '-' && s[2]=='-')
if (!program_name || !*program_name)
program_name = gnupg_module_name (module_name_id);
else if ((s=strchr (program_name, '|')) && s[1] == '-' && s[2]=='-')
{
/* Hack to insert an additional option on the command line. */
program = xtrystrdup (agent_program);
program = xtrystrdup (program_name);
if (!program)
{
gpg_error_t tmperr = gpg_err_make (errsource,
@ -442,22 +481,21 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
}
if (verbose)
log_info (_("no running gpg-agent - starting '%s'\n"),
agent_program);
log_info (_("no running %s - starting '%s'\n"),
printed_name, program_name);
if (status_cb)
status_cb (status_cb_arg, STATUS_PROGRESS,
"starting_agent ? 0 0", NULL);
status_cb (status_cb_arg, STATUS_PROGRESS, status_start_line, NULL);
/* We better pass an absolute home directory to the agent just
in case gpg-agent does not convert the passed name to an
absolute one (which it should do). */
/* We better pass an absolute home directory to the service just
* in case the service does not convert the passed name to an
* absolute one (which it should do). */
abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
if (!abs_homedir)
{
gpg_error_t tmperr = gpg_err_make (errsource,
gpg_err_code_from_syserror ());
log_error ("error building filename: %s\n",gpg_strerror (tmperr));
log_error ("error building filename: %s\n", gpg_strerror (tmperr));
xfree (sockname);
assuan_release (ctx);
xfree (program);
@ -468,8 +506,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
{
gpg_error_t tmperr = gpg_err_make (errsource,
gpg_err_code_from_syserror ());
log_error ("error flushing pending output: %s\n",
strerror (errno));
log_error ("error flushing pending output: %s\n", strerror (errno));
xfree (sockname);
assuan_release (ctx);
xfree (abs_homedir);
@ -477,42 +514,42 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
return tmperr;
}
/* If the agent has been configured for use with a standard
socket, an environment variable is not required and thus
we can safely start the agent here. */
i = 0;
argv[i++] = "--homedir";
argv[i++] = abs_homedir;
argv[i++] = "--use-standard-socket";
if (module_name_id == GNUPG_MODULE_NAME_AGENT)
argv[i++] = "--use-standard-socket";
if (program_arg)
argv[i++] = program_arg;
argv[i++] = "--daemon";
argv[i++] = NULL;
if (!(err = lock_spawning (&lock, gnupg_homedir (), "agent", verbose))
&& assuan_socket_connect (ctx, sockname, 0, 0))
if (!(err = lock_spawning (&lock, gnupg_homedir (), lock_name, verbose))
&& assuan_socket_connect (ctx, sockname, 0, connect_flags))
{
#ifdef HAVE_W32_SYSTEM
err = gnupg_spawn_process_detached (program? program : agent_program,
err = gnupg_spawn_process_detached (program? program : program_name,
argv, NULL);
#else
#else /*!W32*/
pid_t pid;
err = gnupg_spawn_process_fd (program? program : agent_program,
err = gnupg_spawn_process_fd (program? program : program_name,
argv, -1, -1, -1, &pid);
if (!err)
err = gnupg_wait_process (program? program : agent_program,
err = gnupg_wait_process (program? program : program_name,
pid, 1, NULL);
#endif
#endif /*!W32*/
if (err)
log_error ("failed to start agent '%s': %s\n",
agent_program, gpg_strerror (err));
log_error ("failed to start %s '%s': %s\n",
printed_name, program? program : program_name,
gpg_strerror (err));
else
err = wait_for_sock (SECS_TO_WAIT_FOR_AGENT, 0,
sockname, verbose, ctx, &did_success_msg);
err = wait_for_sock (seconds_to_wait, module_name_id,
sockname, connect_flags,
verbose, ctx, &did_success_msg);
}
unlock_spawning (&lock, "agent");
unlock_spawning (&lock, lock_name);
xfree (abs_homedir);
xfree (program);
}
@ -520,17 +557,21 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
if (err)
{
if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
log_error ("can't connect to the %s: %s\n",
printed_name, gpg_strerror (err));
assuan_release (ctx);
return gpg_err_make (errsource, GPG_ERR_NO_AGENT);
return gpg_err_make (errsource, no_service_err);
}
if (debug && !did_success_msg)
log_debug ("connection to the agent established\n");
log_debug ("connection to the %s established\n", printed_name);
err = assuan_transact (ctx, "RESET",
NULL, NULL, NULL, NULL, NULL, NULL);
if (!err)
if (module_name_id == GNUPG_MODULE_NAME_AGENT)
err = assuan_transact (ctx, "RESET",
NULL, NULL, NULL, NULL, NULL, NULL);
if (!err
&& module_name_id == GNUPG_MODULE_NAME_AGENT)
{
err = send_pinentry_environment (ctx, errsource,
opt_lc_ctype, opt_lc_messages,
@ -538,7 +579,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
if (gpg_err_code (err) == GPG_ERR_FORBIDDEN
&& gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT)
{
/* Check whether we are in restricted mode. */
/* Check whether the agent is in restricted mode. */
if (!assuan_transact (ctx, "GETINFO restricted",
NULL, NULL, NULL, NULL, NULL, NULL))
{
@ -559,6 +600,45 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
}
/* Try to connect tothe agent or start a new one. */
gpg_error_t
start_new_gpg_agent (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *agent_program,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
int autostart, int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
return start_new_service (r_ctx, GNUPG_MODULE_NAME_AGENT,
errsource, agent_program,
opt_lc_ctype, opt_lc_messages, session_env,
autostart, verbose, debug,
status_cb, status_cb_arg);
}
/* Try to connect to the dirmngr via a socket. On platforms
supporting it, start it up if needed and if AUTOSTART is true.
Returns a new assuan context at R_CTX or an error code. */
gpg_error_t
start_new_keyboxd (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *keyboxd_program,
int autostart, int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
return start_new_service (r_ctx, GNUPG_MODULE_NAME_KEYBOXD,
errsource, keyboxd_program,
NULL, NULL, NULL,
autostart, verbose, debug,
status_cb, status_cb_arg);
}
/* Try to connect to the dirmngr via a socket. On platforms
supporting it, start it up if needed and if AUTOSTART is true.
Returns a new assuan context at R_CTX or an error code. */
@ -566,119 +646,18 @@ gpg_error_t
start_new_dirmngr (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *dirmngr_program,
int autostart,
int verbose, int debug,
int autostart, int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
gpg_error_t err;
assuan_context_t ctx;
const char *sockname;
int did_success_msg = 0;
*r_ctx = NULL;
err = assuan_new (&ctx);
if (err)
{
log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
return err;
}
sockname = dirmngr_socket_name ();
err = assuan_socket_connect (ctx, sockname, 0, 0);
#ifdef USE_DIRMNGR_AUTO_START
if (err && autostart)
{
lock_spawn_t lock;
const char *argv[4];
char *abs_homedir;
/* No connection: Try start a new Dirmngr. */
if (!dirmngr_program || !*dirmngr_program)
dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
if (verbose)
log_info (_("no running dirmngr - starting '%s'\n"),
dirmngr_program);
if (status_cb)
status_cb (status_cb_arg, STATUS_PROGRESS,
"starting_dirmngr ? 0 0", NULL);
abs_homedir = make_absfilename (gnupg_homedir (), NULL);
if (!abs_homedir)
{
gpg_error_t tmperr = gpg_err_make (errsource,
gpg_err_code_from_syserror ());
log_error ("error building filename: %s\n",gpg_strerror (tmperr));
assuan_release (ctx);
return tmperr;
}
if (fflush (NULL))
{
gpg_error_t tmperr = gpg_err_make (errsource,
gpg_err_code_from_syserror ());
log_error ("error flushing pending output: %s\n",
strerror (errno));
assuan_release (ctx);
return tmperr;
}
argv[0] = "--daemon";
/* Try starting the daemon. Versions of dirmngr < 2.1.15 do
* this only if the home directory is given on the command line. */
argv[1] = "--homedir";
argv[2] = abs_homedir;
argv[3] = NULL;
if (!(err = lock_spawning (&lock, gnupg_homedir (), "dirmngr", verbose))
&& assuan_socket_connect (ctx, sockname, 0, 0))
{
#ifdef HAVE_W32_SYSTEM
err = gnupg_spawn_process_detached (dirmngr_program, argv, NULL);
#else
pid_t pid;
err = gnupg_spawn_process_fd (dirmngr_program, argv,
-1, -1, -1, &pid);
if (!err)
err = gnupg_wait_process (dirmngr_program, pid, 1, NULL);
#ifndef USE_DIRMNGR_AUTO_START
autostart = 0;
#endif
if (err)
log_error ("failed to start the dirmngr '%s': %s\n",
dirmngr_program, gpg_strerror (err));
else
err = wait_for_sock (SECS_TO_WAIT_FOR_DIRMNGR, 1,
sockname, verbose, ctx, &did_success_msg);
}
unlock_spawning (&lock, "dirmngr");
xfree (abs_homedir);
}
#else
(void)dirmngr_program;
(void)verbose;
(void)status_cb;
(void)status_cb_arg;
#endif /*USE_DIRMNGR_AUTO_START*/
if (err)
{
if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
log_error ("connecting dirmngr at '%s' failed: %s\n",
sockname, gpg_strerror (err));
assuan_release (ctx);
return gpg_err_make (errsource, GPG_ERR_NO_DIRMNGR);
}
if (debug && !did_success_msg)
log_debug ("connection to the dirmngr established\n");
*r_ctx = ctx;
return 0;
return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
errsource, dirmngr_program,
NULL, NULL, NULL,
autostart, verbose, debug,
status_cb, status_cb_arg);
}

View File

@ -65,6 +65,16 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);
/* This function is used to connect to the keyboxd. If needed the
* keyboxd is started. */
gpg_error_t
start_new_keyboxd (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *keyboxd_program,
int autostart, int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);
/* This function is used to connect to the dirmngr. On some platforms
the function is able starts a dirmngr process if needed. */
gpg_error_t
@ -82,8 +92,16 @@ gpg_error_t get_assuan_server_version (assuan_context_t ctx,
/*-- asshelp2.c --*/
void set_assuan_context_func (assuan_context_t (*func)(ctrl_t ctrl));
/* Helper function to print an assuan status line using a printf
format string. */
gpg_error_t status_printf (ctrl_t ctrl, const char *keyword, const char *format,
...) GPGRT_ATTR_PRINTF(3,4);
gpg_error_t status_no_printf (ctrl_t ctrl, int no, const char *format,
...) GPGRT_ATTR_PRINTF(3,4);
gpg_error_t print_assuan_status (assuan_context_t ctx,
const char *keyword,
const char *format,

View File

@ -36,6 +36,24 @@
#include "util.h"
#include "asshelp.h"
#include "status.h"
/* A variable with a function to be used to return the current assuan
* context for a CTRL variable. This needs to be set using the
* set_assuan_ctx_func function. */
static assuan_context_t (*the_assuan_ctx_func)(ctrl_t ctrl);
/* Set FUNC to be used as a mapping fucntion from CTRL to an assuan
* context. Pass NULL for FUNC to disable the use of the assuan
* context in this module. */
void
set_assuan_context_func (assuan_context_t (*func)(ctrl_t ctrl))
{
the_assuan_ctx_func = func;
}
/* Helper function to print an assuan status line using a printf
format string. */
@ -134,3 +152,41 @@ print_assuan_status_strings (assuan_context_t ctx, const char *keyword, ...)
va_end (arg_ptr);
return err;
}
/* This function is similar to print_assuan_status but takes a CTRL
* arg instead of an assuan context as first argument. */
gpg_error_t
status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...)
{
gpg_error_t err;
va_list arg_ptr;
assuan_context_t ctx;
if (!ctrl || !the_assuan_ctx_func || !(ctx = the_assuan_ctx_func (ctrl)))
return 0;
va_start (arg_ptr, format);
err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
va_end (arg_ptr);
return err;
}
/* Same as sytus_printf but takes a status number instead of a
* keyword. */
gpg_error_t
status_no_printf (ctrl_t ctrl, int no, const char *format, ...)
{
gpg_error_t err;
va_list arg_ptr;
assuan_context_t ctx;
if (!ctrl || !the_assuan_ctx_func || !(ctx = the_assuan_ctx_func (ctrl)))
return 0;
va_start (arg_ptr, format);
err = vprint_assuan_status (ctx, get_status_string (no), format, arg_ptr);
va_end (arg_ptr);
return err;
}

View File

@ -945,6 +945,17 @@ gnupg_cachedir (void)
}
/* Return the standard socket name used by gpg-agent. */
const char *
gpg_agent_socket_name (void)
{
static char *name;
if (!name)
name = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
return name;
}
/* Return the user socket name used by DirMngr. */
const char *
dirmngr_socket_name (void)
@ -1104,6 +1115,13 @@ gnupg_module_name (int which)
X(bindir, "dirmngr", DIRMNGR_NAME);
#endif
case GNUPG_MODULE_NAME_KEYBOXD:
#ifdef GNUPG_DEFAULT_KEYBOXD
return GNUPG_DEFAULT_KEYBOXD;
#else
X(bindir, "keyboxd", KEYBOXD_NAME);
#endif
case GNUPG_MODULE_NAME_PROTECT_TOOL:
#ifdef GNUPG_DEFAULT_PROTECT_TOOL
return GNUPG_DEFAULT_PROTECT_TOOL;

View File

@ -106,6 +106,8 @@ typedef struct
int keep_open;
int no_cache;
int eof_seen;
int use_readlimit; /* Take care of the readlimit. */
size_t readlimit; /* Number of bytes left to read. */
int print_only_name; /* Flags indicating that fname is not a real file. */
char fname[1]; /* Name of the file. */
} file_es_filter_ctx_t;
@ -635,6 +637,34 @@ file_es_filter (void *opaque, int control, iobuf_t chain, byte * buf,
rc = -1;
*ret_len = 0;
}
else if (a->use_readlimit)
{
nbytes = 0;
if (!a->readlimit)
{ /* eof */
a->eof_seen = 1;
rc = -1;
}
else
{
if (size > a->readlimit)
size = a->readlimit;
rc = es_read (f, buf, size, &nbytes);
if (rc == -1)
{ /* error */
rc = gpg_error_from_syserror ();
log_error ("%s: read error: %s\n", a->fname,strerror (errno));
}
else if (!nbytes)
{ /* eof */
a->eof_seen = 1;
rc = -1;
}
else
a->readlimit -= nbytes;
}
*ret_len = nbytes;
}
else
{
nbytes = 0;
@ -1412,7 +1442,8 @@ iobuf_fdopen_nc (int fd, const char *mode)
iobuf_t
iobuf_esopen (estream_t estream, const char *mode, int keep_open)
iobuf_esopen (estream_t estream, const char *mode, int keep_open,
size_t readlimit)
{
iobuf_t a;
file_es_filter_ctx_t *fcx;
@ -1424,7 +1455,9 @@ iobuf_esopen (estream_t estream, const char *mode, int keep_open)
fcx->fp = estream;
fcx->print_only_name = 1;
fcx->keep_open = keep_open;
sprintf (fcx->fname, "[fd %p]", estream);
fcx->readlimit = readlimit;
fcx->use_readlimit = !!readlimit;
snprintf (fcx->fname, 30, "[fd %p]", estream);
a->filter = file_es_filter;
a->filter_ov = fcx;
file_es_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);

View File

@ -328,8 +328,10 @@ iobuf_t iobuf_fdopen_nc (int fd, const char *mode);
letter 'w', creates an output filter. Otherwise, creates an input
filter. If KEEP_OPEN is TRUE, then the stream is not closed when
the filter is destroyed. Otherwise, the stream is closed when the
filter is destroyed. */
iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open);
filter is destroyed. If READLIMIT is not 0 this gives a limit on
the number of bytes to read from estream. */
iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open,
size_t readlimit);
/* Create a filter using an existing socket. On Windows creates a
special socket filter. On non-Windows systems simply, this simply

View File

@ -77,6 +77,12 @@ run_mbox_test (void)
{ "<fo()o@example.org> ()", "fo()o@example.org" },
{ "fo()o@example.org", NULL},
{ "Mr. Foo <foo@example.org><bar@example.net>", "foo@example.org"},
{ "Surname, Forename | company <foo@example.org>", "foo@example.org"},
/* The next one is for sure not RFC-822 correct but nevertheless
* the way gpg does it. We won't change it because the user-id
* is only rfc-822 alike and not compliant (think only of our
* utf-8 requirement). */
{ "\"<foo@example.org>\" <foo@example.net>", "foo@example.org"},
{ NULL, NULL }
};
int idx;

View File

@ -65,6 +65,9 @@
* (note that you can't search for these characters). Compare
* is not case sensitive.
* - If the userid starts with a '&' a 40 hex digits keygrip is expected.
* - If the userid starts with a '^' followed by 40 hex digits it describes
* a Unique-Blob-ID (UBID) which is the hash of keyblob or certificate as
* stored in the database. This is used in the IPC of the keyboxd.
*/
gpg_error_t
@ -251,6 +254,17 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
}
break;
case '^': /* UBID */
{
if (hex2bin (s+1, desc->u.ubid, 20) < 0)
{
rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
goto out;
}
mode = KEYDB_SEARCH_MODE_UBID;
}
break;
default:
if (s[0] == '0' && s[1] == 'x')
{

View File

@ -43,6 +43,10 @@
#define GPG_ERR_NO_AUTH 314
#define GPG_ERR_BAD_AUTH 315
#endif /*GPG_ERROR_VERSION_NUMBER*/
#if GPG_ERROR_VERSION_NUMBER < 0x012500 /* 1.37 */
#define GPG_ERR_NO_KEYBOXD 316
#define GPG_ERR_KEYBOXD 317
#endif /*GPG_ERROR_VERSION_NUMBER*/
/* Hash function used with libksba. */
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
@ -243,6 +247,7 @@ const char *gnupg_libdir (void);
const char *gnupg_datadir (void);
const char *gnupg_localedir (void);
const char *gnupg_cachedir (void);
const char *gpg_agent_socket_name (void);
const char *dirmngr_socket_name (void);
char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
@ -261,6 +266,7 @@ char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
#define GNUPG_MODULE_NAME_GPGCONF 10
#define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11
#define GNUPG_MODULE_NAME_GPGV 12
#define GNUPG_MODULE_NAME_KEYBOXD 13
const char *gnupg_module_name (int which);
void gnupg_module_name_flush_some (void);
void gnupg_set_builddir (const char *newdir);

View File

@ -56,7 +56,7 @@ AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg24", [swdb tag for this branch])
NEED_GPG_ERROR_VERSION=1.29
NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.7.0
NEED_LIBGCRYPT_VERSION=1.8.0
NEED_LIBASSUAN_API=2
NEED_LIBASSUAN_VERSION=2.5.0
@ -191,6 +191,14 @@ AM_CONDITIONAL(GNUPG_DIRMNGR_PGM, test -n "$GNUPG_DIRMNGR_PGM")
show_gnupg_dirmngr_pgm="(default)"
test -n "$GNUPG_DIRMNGR_PGM" && show_gnupg_dirmngr_pgm="$GNUPG_DIRMNGR_PGM"
AC_ARG_WITH(keyboxd-pgm,
[ --with-keyboxd-pgm=PATH Use PATH as the default for the keyboxd)],
GNUPG_KEYBOXD_PGM="$withval", GNUPG_KEYBOXD_PGM="" )
AC_SUBST(GNUPG_KEYBOXD_PGM)
AM_CONDITIONAL(GNUPG_KEYBOXD_PGM, test -n "$GNUPG_KEYBOXD_PGM")
show_gnupg_keyboxd_pgm="(default)"
test -n "$GNUPG_KEYBOXD_PGM" && show_gnupg_keyboxd_pgm="$GNUPG_KEYBOXD_PGM"
AC_ARG_WITH(protect-tool-pgm,
[ --with-protect-tool-pgm=PATH Use PATH as the default for the protect-tool)],
GNUPG_PROTECT_TOOL_PGM="$withval", GNUPG_PROTECT_TOOL_PGM="" )
@ -508,6 +516,7 @@ AH_BOTTOM([
#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
#endif
#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
#define GNUPG_PUBLIC_KEYS_DIR "public-keys.d"
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
#define GNUPG_CACHE_DIR "cache.d"
@ -1888,6 +1897,10 @@ AC_DEFINE_UNQUOTED(DIRMNGR_NAME, "dirmngr", [The name of the dirmngr])
AC_DEFINE_UNQUOTED(DIRMNGR_DISP_NAME, "DirMngr",
[The displayed name of dirmngr])
AC_DEFINE_UNQUOTED(KEYBOXD_NAME, "keyboxd", [The name of the keyboxd])
AC_DEFINE_UNQUOTED(KEYBOXD_DISP_NAME, "Keyboxd",
[The displayed name of keyboxd])
AC_DEFINE_UNQUOTED(G13_NAME, "g13", [The name of the g13 tool])
AC_DEFINE_UNQUOTED(G13_DISP_NAME, "G13", [The displayed name of g13])
@ -1909,6 +1922,8 @@ AC_DEFINE_UNQUOTED(DIRMNGR_INFO_NAME, "DIRMNGR_INFO",
[The name of the dirmngr info envvar])
AC_DEFINE_UNQUOTED(SCDAEMON_SOCK_NAME, "S.scdaemon",
[The name of the SCdaemon socket])
AC_DEFINE_UNQUOTED(KEYBOXD_SOCK_NAME, "S.keyboxd",
[The name of the keyboxd socket])
AC_DEFINE_UNQUOTED(DIRMNGR_SOCK_NAME, "S.dirmngr",
[The name of the dirmngr socket])
AC_DEFINE_UNQUOTED(DIRMNGR_DEFAULT_KEYSERVER,
@ -2106,6 +2121,7 @@ echo "
Default agent: $show_gnupg_agent_pgm
Default pinentry: $show_gnupg_pinentry_pgm
Default scdaemon: $show_gnupg_scdaemon_pgm
Default keyboxd: $show_gnupg_keyboxd_pgm
Default dirmngr: $show_gnupg_dirmngr_pgm
Dirmngr auto start: $dirmngr_auto_start

View File

@ -1138,6 +1138,18 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
*** BEGIN_STREAM, END_STREAM
Used to issued by the experimental pipemode.
** Inter-component codes
Status codes are also used between the components of the GnuPG
system via the Assuan S lines. Some of them are documented here:
*** PUBKEY_INFO <n> <ubid>
The type of the public key in the following D-lines or
communicated via a pipe. <n> is the value of =enum pubkey_types=
and <ubid> the Unique Blob ID (UBID) which is a SHA-1 digest the
entire blob here formatted in hex. The consumer of this status
line should be prepared to see a <ubid> of up to 64 characters.
Note that the keyboxd SEARCH command can be used to lookup the
public key using the <ubid> prefixed with a caret (^).
* Format of the --attribute-fd output

View File

@ -1328,11 +1328,22 @@ Specify the directory manager (keyserver client) program to be started
if none is running. This has only an effect if used together with the
option @option{--dirmngr}.
@item --keyboxd-program @var{file}
@opindex keyboxd-program
Specify the keybox daemon program to be started if none is running.
This has only an effect if used together with the option
@option{--keyboxd}.
@item --dirmngr
@opindex dirmngr
Connect to a running directory manager (keyserver client) instead of
to the gpg-agent. If a dirmngr is not running, start it.
@item --keyboxd
@opindex keyboxd
Connect to a running keybox daemon instead of
to the gpg-agent. If a keyboxd is not running, start it.
@item -S
@itemx --raw-socket @var{name}
@opindex raw-socket

View File

@ -29,9 +29,9 @@ AM_CPPFLAGS =
include $(top_srcdir)/am/cmacros.am
AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \
$(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
$(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) $(GPG_ERROR_CFLAGS)
needed_libs = ../kbx/libkeybox.a $(libcommon)
needed_libs = ../kbx/libkeybox.a $(libcommonpth)
# Because there are no program specific transform macros we need to
# work around that to allow installing gpg as gpg2.
@ -50,9 +50,9 @@ noinst_PROGRAMS = gpg
if !HAVE_W32CE_SYSTEM
noinst_PROGRAMS += gpgv
endif
if MAINTAINER_MODE
noinst_PROGRAMS += gpgcompose
endif
#if MAINTAINER_MODE
#noinst_PROGRAMS += gpgcompose
#endif
noinst_PROGRAMS += $(module_tests)
TESTS = $(module_tests)
TESTS_ENVIRONMENT = \
@ -100,7 +100,10 @@ common_source = \
free-packet.c \
getkey.c \
expand-group.c \
keydb.c keydb.h \
keydb.h \
keydb-private.h \
call-keyboxd.c \
keydb.c \
keyring.c keyring.h \
seskey.c \
kbnode.c \
@ -161,7 +164,7 @@ gpg_SOURCES = gpg.c \
keyedit.c keyedit.h \
$(gpg_sources)
gpgcompose_SOURCES = gpgcompose.c $(gpg_sources)
#gpgcompose_SOURCES = gpgcompose.c $(gpg_sources)
gpgv_SOURCES = gpgv.c \
$(common_source) \
verify.c
@ -176,33 +179,36 @@ gpgv_SOURCES = gpgv.c \
LDADD = $(needed_libs) ../common/libgpgrl.a \
$(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS)
gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(resource_objs) $(extra_sys_libs)
gpg_LDFLAGS = $(extra_bin_ldflags)
gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(GPG_ERROR_LIBS) \
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(resource_objs) $(extra_sys_libs)
gpgv_LDFLAGS = $(extra_bin_ldflags)
gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(resource_objs) $(extra_sys_libs)
gpgcompose_LDFLAGS = $(extra_bin_ldflags)
#gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
# $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
# $(LIBICONV) $(resource_objs) $(extra_sys_libs)
#gpgcompose_LDFLAGS = $(extra_bin_ldflags)
t_common_ldadd =
module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter
t_rmd160_SOURCES = t-rmd160.c rmd160.c
t_rmd160_LDADD = $(t_common_ldadd)
t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source)
t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(t_common_ldadd)
t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \
$(common_source)
t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(t_common_ldadd)
t_stutter_SOURCES = t-stutter.c test-stubs.c \
$(common_source)
t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(t_common_ldadd)

1112
g10/call-keyboxd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -475,7 +475,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
rc = get_output_file ("", 0, ed->buf, &filename, &fp);
if (! rc)
{
iobuf_t output = iobuf_esopen (fp, "w", 0);
iobuf_t output = iobuf_esopen (fp, "w", 0, 0);
armor_filter_context_t *afx = NULL;
if (opt.armor)

View File

@ -65,7 +65,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
*r_sec_avail = 0;
hd = keydb_new ();
hd = keydb_new (ctrl);
if (!hd)
return gpg_error_from_syserror ();
@ -131,7 +131,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
if (!secret && !force)
{
if (have_secret_key_with_kid (keyid))
if (have_secret_key_with_kid (ctrl, keyid))
{
*r_sec_avail = 1;
err = gpg_error (GPG_ERR_EOF);
@ -141,7 +141,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
err = 0;
}
if (secret && !have_secret_key_with_kid (keyid))
if (secret && !have_secret_key_with_kid (ctrl, keyid))
{
err = gpg_error (GPG_ERR_NOT_FOUND);
log_error (_("key \"%s\" not found\n"), username);

View File

@ -1877,7 +1877,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
stats = &dummystats;
*any = 0;
init_packet (&pkt);
kdbhd = keydb_new ();
kdbhd = keydb_new (ctrl);
if (!kdbhd)
return gpg_error_from_syserror ();

View File

@ -403,7 +403,7 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
}
else
{
ctx.kr_handle = keydb_new ();
ctx.kr_handle = keydb_new (ctrl);
if (!ctx.kr_handle)
{
rc = gpg_error_from_syserror ();
@ -448,7 +448,7 @@ leave:
* Return the public key in *PK. The resources in *PK should be
* released using release_public_key_parts(). */
int
get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
get_pubkey_fast (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
{
int rc = 0;
KEYDB_HANDLE hd;
@ -476,7 +476,7 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
}
#endif
hd = keydb_new ();
hd = keydb_new (ctrl);
if (!hd)
return gpg_error_from_syserror ();
rc = keydb_search_kid (hd, keyid);
@ -550,7 +550,7 @@ get_pubkeyblock (ctrl_t ctrl, u32 * keyid)
memset (&ctx, 0, sizeof ctx);
/* No need to set exact here because we want the entire block. */
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
ctx.kr_handle = keydb_new (ctrl);
if (!ctx.kr_handle)
return NULL;
ctx.nitems = 1;
@ -592,7 +592,7 @@ get_seckey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid)
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1; /* Use the key ID exactly as given. */
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
ctx.kr_handle = keydb_new (ctrl);
if (!ctx.kr_handle)
return gpg_error_from_syserror ();
ctx.nitems = 1;
@ -807,7 +807,7 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
}
ctx->want_secret = want_secret;
ctx->kr_handle = keydb_new ();
ctx->kr_handle = keydb_new (ctrl);
if (!ctx->kr_handle)
{
rc = gpg_error_from_syserror ();
@ -1448,7 +1448,7 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
err = gpg_error_from_syserror ();
else
{
ctx->kr_handle = keydb_new ();
ctx->kr_handle = keydb_new (ctrl);
if (! ctx->kr_handle)
{
err = gpg_error_from_syserror ();
@ -1594,7 +1594,7 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
ctx.not_allocated = 1;
/* FIXME: We should get the handle from the cache like we do in
* get_pubkey. */
ctx.kr_handle = keydb_new ();
ctx.kr_handle = keydb_new (ctrl);
if (!ctx.kr_handle)
return gpg_error_from_syserror ();
@ -1632,13 +1632,14 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
* Like get_pubkey_byfprint, PK may be NULL. In that case, this
* function effectively just checks for the existence of the key. */
gpg_error_t
get_pubkey_byfprint_fast (PKT_public_key * pk,
get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key * pk,
const byte * fprint, size_t fprint_len)
{
gpg_error_t err;
KBNODE keyblock;
err = get_keyblock_byfprint_fast (&keyblock, NULL, fprint, fprint_len, 0);
err = get_keyblock_byfprint_fast (ctrl,
&keyblock, NULL, fprint, fprint_len, 0);
if (!err)
{
if (pk)
@ -1658,7 +1659,8 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
* it may have a value of NULL, though. This allows to do an insert
* operation on a locked keydb handle. */
gpg_error_t
get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
get_keyblock_byfprint_fast (ctrl_t ctrl,
kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
const byte *fprint, size_t fprint_len, int lock)
{
gpg_error_t err;
@ -1675,7 +1677,7 @@ get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++)
fprbuf[i] = fprint[i];
hd = keydb_new ();
hd = keydb_new (ctrl);
if (!hd)
return gpg_error_from_syserror ();
@ -1757,7 +1759,7 @@ parse_def_secret_key (ctrl_t ctrl)
if (! hd)
{
hd = keydb_new ();
hd = keydb_new (ctrl);
if (!hd)
return NULL;
}
@ -2732,7 +2734,7 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
* reason to check that an ultimately trusted key is
* still valid - if it has been revoked the user
* should also remove the ultimate trust flag. */
if (get_pubkey_fast (ultimate_pk, sig->keyid) == 0
if (get_pubkey_fast (ctrl, ultimate_pk, sig->keyid) == 0
&& check_key_signature2 (ctrl,
keyblock, k, ultimate_pk,
NULL, NULL, NULL, NULL) == 0
@ -4117,7 +4119,7 @@ key_origin_string (int origin)
the secret key is valid; this check merely indicates whether there
is some secret key with the specified key id. */
int
have_secret_key_with_kid (u32 *keyid)
have_secret_key_with_kid (ctrl_t ctrl, u32 *keyid)
{
gpg_error_t err;
KEYDB_HANDLE kdbhd;
@ -4126,7 +4128,7 @@ have_secret_key_with_kid (u32 *keyid)
kbnode_t node;
int result = 0;
kdbhd = keydb_new ();
kdbhd = keydb_new (ctrl);
if (!kdbhd)
return 0;
memset (&desc, 0, sizeof desc);

View File

@ -36,6 +36,7 @@
# endif
# include <windows.h>
#endif
#include <npth.h>
#define INCLUDED_BY_MAIN_MODULE 1
#include "gpg.h"
@ -361,6 +362,7 @@ enum cmd_and_opt_values
oUseAgent,
oNoUseAgent,
oGpgAgentInfo,
oUseKeyboxd,
oMergeOnly,
oTryAllSecrets,
oTrustedKey,
@ -378,6 +380,7 @@ enum cmd_and_opt_values
oPersonalDigestPreferences,
oPersonalCompressPreferences,
oAgentProgram,
oKeyboxdProgram,
oDirmngrProgram,
oDisableDirmngr,
oDisplay,
@ -850,6 +853,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"),
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
ARGPARSE_s_s (oKeyboxdProgram, "keyboxd-program", "@"),
ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", "@"),
ARGPARSE_s_s (oDisplay, "display", "@"),
@ -896,6 +900,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"),
ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
ARGPARSE_s_n (oUseKeyboxd, "use-keyboxd", "@"),
/* Options which can be used in special circumstances. They are not
* published and we hope they are never required. */
@ -983,6 +988,9 @@ static void add_keyserver_url( const char *string, int which );
static void emergency_cleanup (void);
static void read_sessionkey_from_fd (int fd);
/* NPth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
@ -2250,6 +2258,7 @@ gpg_deinit_default_ctrl (ctrl_t ctrl)
gpg_dirmngr_deinit_session_data (ctrl);
keydb_release (ctrl->cached_getkey_kdb);
gpg_keyboxd_deinit_session_data (ctrl);
}
@ -2742,6 +2751,11 @@ main (int argc, char **argv)
case oGpgAgentInfo:
obsolete_option (configname, configlineno, "gpg-agent-info");
break;
case oUseKeyboxd:
opt.use_keyboxd = 1;
break;
case oReaderPort:
obsolete_scdaemon_option (configname, configlineno, "reader-port");
break;
@ -3499,6 +3513,7 @@ main (int argc, char **argv)
pers_compress_list=pargs.r.ret_str;
break;
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
case oKeyboxdProgram: opt.keyboxd_program = pargs.r.ret_str; break;
case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
case oDisableDirmngr: opt.disable_dirmngr = 1; break;
case oWeakDigest:
@ -3738,6 +3753,11 @@ main (int argc, char **argv)
}
#endif
/* Init threading which is used by some helper functions. */
npth_init ();
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* FIXME: We should use logging to a file only in server mode;
however we have not yet implemetyed that. Thus we try to get
away with --batch as indication for logging to file
@ -3745,7 +3765,9 @@ main (int argc, char **argv)
if (logfile && opt.batch)
{
log_set_file (logfile);
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
| GPGRT_LOG_WITH_TIME
| GPGRT_LOG_WITH_PID ));
}
if (opt.verbose > 2)
@ -4120,8 +4142,10 @@ main (int argc, char **argv)
/* Add the keyrings, but not for some special commands. We always
* need to add the keyrings if we are running under SELinux, this
* is so that the rings are added to the list of secured files.
* We do not add any keyring if --no-keyring has been used. */
if (default_keyring >= 0
* We do not add any keyring if --no-keyring or --use-keyboxd has
* been used. */
if (!opt.use_keyboxd
&& default_keyring >= 0
&& (ALWAYS_ADD_KEYRINGS
|| (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
{
@ -4133,9 +4157,8 @@ main (int argc, char **argv)
}
FREE_STRLIST(nrings);
/* In loopback mode, never ask for the password multiple times. */
if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
/* In loopback mode, never ask for the password multiple
times. */
{
opt.passphrase_repeat = 0;
}
@ -5089,7 +5112,7 @@ main (int argc, char **argv)
policy = parse_tofu_policy (argv[0]);
hd = keydb_new ();
hd = keydb_new (ctrl);
if (! hd)
{
write_status_failure ("tofu-driver", gpg_error(GPG_ERR_GENERAL));

View File

@ -60,16 +60,19 @@
/* Object used to keep state locally to server.c . */
struct server_local_s;
/* Object used to keep state locally to call-keyboxd.c . */
struct keyboxd_local_s;
typedef struct keyboxd_local_s *keyboxd_local_t;
/* Object used to keep state locally to call-dirmngr.c . */
struct dirmngr_local_s;
typedef struct dirmngr_local_s *dirmngr_local_t;
/* Object used to describe a keyblock node. */
typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */
typedef struct kbnode_struct *kbnode_t;
typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */typedef struct kbnode_struct *kbnode_t;
/* The handle for keydb operations. */
typedef struct keydb_handle *KEYDB_HANDLE;
typedef struct keydb_handle_s *KEYDB_HANDLE;
/* TOFU database meta object. */
struct tofu_dbs_s;
@ -96,6 +99,9 @@ struct server_control_s
/* Local data for call-dirmngr.c */
dirmngr_local_t dirmngr_local;
/* Local data for call-keyboxd.c */
keyboxd_local_t keyboxd_local;
/* Local data for tofu.c */
struct {
tofu_dbs_t dbs;

View File

@ -614,7 +614,7 @@ pk_search_terms (const char *option, int argc, char *argv[], void *cookie)
if (err)
log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
hd = keydb_new ();
hd = keydb_new (ctrl);
err = keydb_search (hd, &desc, 1, NULL);
if (err)
@ -810,7 +810,7 @@ sig_issuer (const char *option, int argc, char *argv[], void *cookie)
if (err)
log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
hd = keydb_new ();
hd = keydb_new (ctrl);
err = keydb_search (hd, &desc, 1, NULL);
if (err)

View File

@ -550,7 +550,7 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp,
gpg_error_t err;
iobuf_t inp;
inp = iobuf_esopen (fp, "rb", 1);
inp = iobuf_esopen (fp, "rb", 1, 0);
if (!inp)
{
err = gpg_error_from_syserror ();
@ -2022,7 +2022,7 @@ import_one_real (ctrl_t ctrl,
goto leave;
/* Do we have this key already in one of our pubrings ? */
err = get_keyblock_byfprint_fast (&keyblock_orig, &hd,
err = get_keyblock_byfprint_fast (ctrl, &keyblock_orig, &hd,
fpr2, fpr2len, 1/*locked*/);
if ((err
&& gpg_err_code (err) != GPG_ERR_NO_PUBKEY
@ -2310,13 +2310,13 @@ import_one_real (ctrl_t ctrl,
if (mod_key)
{
revocation_present (ctrl, keyblock_orig);
if (!from_sk && have_secret_key_with_kid (keyid))
if (!from_sk && have_secret_key_with_kid (ctrl, keyid))
check_prefs (ctrl, keyblock_orig);
}
else if (new_key)
{
revocation_present (ctrl, keyblock);
if (!from_sk && have_secret_key_with_kid (keyid))
if (!from_sk && have_secret_key_with_kid (ctrl, keyid))
check_prefs (ctrl, keyblock);
}
@ -3372,7 +3372,7 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
}
/* Read the original keyblock. */
hd = keydb_new ();
hd = keydb_new (ctrl);
if (!hd)
{
rc = gpg_error_from_syserror ();
@ -3768,7 +3768,8 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
else if (node->pkt->pkttype == PKT_SIGNATURE
&& !node->pkt->pkt.signature->flags.exportable
&& !(options&IMPORT_LOCAL_SIGS)
&& !have_secret_key_with_kid (node->pkt->pkt.signature->keyid))
&& !have_secret_key_with_kid (ctrl,
node->pkt->pkt.signature->keyid))
{
/* here we violate the rfc a bit by still allowing
* to import non-exportable signature when we have the
@ -4089,7 +4090,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
* itself? */
gpg_error_t err;
err = get_pubkey_byfprint_fast (NULL,
err = get_pubkey_byfprint_fast (ctrl, NULL,
sig->revkey[idx].fpr,
sig->revkey[idx].fprlen);
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY
@ -4111,7 +4112,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
opt.keyserver, 0);
/* Do we have it now? */
err = get_pubkey_byfprint_fast (NULL,
err = get_pubkey_byfprint_fast (ctrl, NULL,
sig->revkey[idx].fpr,
sig->revkey[idx].fprlen);
}

171
g10/keydb-private.h Normal file
View File

@ -0,0 +1,171 @@
/* keydb-private.h - Common definitions for keydb.c and call-keyboxd.c
* Copyright (C) 2019 g10 Code GmbH
*
* 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 <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef G10_KEYDB_PRIVATE_H
#define G10_KEYDB_PRIVATE_H
#include <assuan.h>
#include "../common/membuf.h"
/* Ugly forward declarations. */
struct keyring_handle;
typedef struct keyring_handle *KEYRING_HANDLE;
struct keybox_handle;
typedef struct keybox_handle *KEYBOX_HANDLE;
/* This is for keydb.c and only used in non-keyboxd mode. */
#define MAX_KEYDB_RESOURCES 40
/* This is for keydb.c and only used in non-keyboxd mode. */
typedef enum
{
KEYDB_RESOURCE_TYPE_NONE = 0,
KEYDB_RESOURCE_TYPE_KEYRING,
KEYDB_RESOURCE_TYPE_KEYBOX
} KeydbResourceType;
/* This is for keydb.c and only used in non-keyboxd mode. */
struct resource_item
{
KeydbResourceType type;
union {
KEYRING_HANDLE kr;
KEYBOX_HANDLE kb;
} u;
void *token;
};
/* This is a simple cache used to return the last result of a
* successful fingerprint search. This works only for keybox
* resources because (due to lack of a copy_keyblock function) we need
* to store an image of the keyblock which is fortunately instantly
* available for keyboxes. Only used in non-keyboxd mode. */
enum keyblock_cache_states {
KEYBLOCK_CACHE_EMPTY,
KEYBLOCK_CACHE_PREPARED,
KEYBLOCK_CACHE_FILLED
};
struct keyblock_cache {
enum keyblock_cache_states state;
byte fpr[MAX_FINGERPRINT_LEN];
byte fprlen;
iobuf_t iobuf; /* Image of the keyblock. */
int pk_no;
int uid_no;
/* Offset of the record in the keybox. */
int resource;
off_t offset;
};
/* The definition of the KEYDB_HANDLE as used internally by keydb.c and
* the newer call-keyboxd. */
struct keydb_handle_s
{
/* Flag set if this handles pertains to call-keyboxd.c. */
int use_keyboxd;
/* BEGIN USE_KEYBOXD */
/* (These fields are only valid if USE_KEYBOXD is set.) */
/* A shallow pointer with the CTRL used to create this handle. */
ctrl_t ctrl;
/* Connection info which also keep the local state. (This is points
* into the CTRL->keybox_local list.) */
keyboxd_local_t kbl;
/* END USE_KEYBOXD */
/* BEGIN !USE_KEYBOXD */
/* (The remaining fields are only valid if USE_KEYBOXD is cleared.) */
/* When we locked all of the resources in ACTIVE (using keyring_lock
* / keybox_lock, as appropriate). */
int locked;
/* If this flag is set a lock will only be released by
* keydb_release. */
int keep_lock;
/* The index into ACTIVE of the resources in which the last search
result was found. Initially -1. */
int found;
/* Initially -1 (invalid). This is used to save a search result and
later restore it as the selected result. */
int saved_found;
/* The number of skipped long blobs since the last search
(keydb_search_reset). */
unsigned long skipped_long_blobs;
/* If set, this disables the use of the keyblock cache. */
int no_caching;
/* Whether the next search will be from the beginning of the
database (and thus consider all records). */
int is_reset;
/* The "file position." In our case, this is index of the current
resource in ACTIVE. */
int current;
/* The number of resources in ACTIVE. */
int used;
/* Cache of the last found and parsed key block (only used for
keyboxes, not keyrings). */
struct keyblock_cache keyblock_cache;
/* Copy of ALL_RESOURCES when keydb_new is called. */
struct resource_item active[MAX_KEYDB_RESOURCES];
/* END !USE_KEYBOXD */
};
/*-- keydb.c --*/
/* These are the functions call-keyboxd diverts to if the keyboxd is
* not used. */
gpg_error_t internal_keydb_init (KEYDB_HANDLE hd);
void internal_keydb_deinit (KEYDB_HANDLE hd);
gpg_error_t internal_keydb_lock (KEYDB_HANDLE hd);
gpg_error_t internal_keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
gpg_error_t internal_keydb_update_keyblock (ctrl_t ctrl,
KEYDB_HANDLE hd, kbnode_t kb);
gpg_error_t internal_keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
gpg_error_t internal_keydb_delete_keyblock (KEYDB_HANDLE hd);
gpg_error_t internal_keydb_search_reset (KEYDB_HANDLE hd);
gpg_error_t internal_keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex);
#endif /*G10_KEYDB_PRIVATE_H*/

View File

@ -37,25 +37,10 @@
#include "keydb.h"
#include "../common/i18n.h"
#include "keydb-private.h" /* For struct keydb_handle_s */
static int active_handles;
typedef enum
{
KEYDB_RESOURCE_TYPE_NONE = 0,
KEYDB_RESOURCE_TYPE_KEYRING,
KEYDB_RESOURCE_TYPE_KEYBOX
} KeydbResourceType;
#define MAX_KEYDB_RESOURCES 40
struct resource_item
{
KeydbResourceType type;
union {
KEYRING_HANDLE kr;
KEYBOX_HANDLE kb;
} u;
void *token;
};
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
static int used_resources;
@ -67,74 +52,6 @@ static void *primary_keydb;
/* Whether we have successfully registered any resource. */
static int any_registered;
/* This is a simple cache used to return the last result of a
successful fingerprint search. This works only for keybox resources
because (due to lack of a copy_keyblock function) we need to store
an image of the keyblock which is fortunately instantly available
for keyboxes. */
enum keyblock_cache_states {
KEYBLOCK_CACHE_EMPTY,
KEYBLOCK_CACHE_PREPARED,
KEYBLOCK_CACHE_FILLED
};
struct keyblock_cache {
enum keyblock_cache_states state;
byte fpr[MAX_FINGERPRINT_LEN];
byte fprlen;
iobuf_t iobuf; /* Image of the keyblock. */
int pk_no;
int uid_no;
/* Offset of the record in the keybox. */
int resource;
off_t offset;
};
struct keydb_handle
{
/* When we locked all of the resources in ACTIVE (using keyring_lock
/ keybox_lock, as appropriate). */
int locked;
/* If this flag is set a lock will only be released by
* keydb_release. */
int keep_lock;
/* The index into ACTIVE of the resources in which the last search
result was found. Initially -1. */
int found;
/* Initially -1 (invalid). This is used to save a search result and
later restore it as the selected result. */
int saved_found;
/* The number of skipped long blobs since the last search
(keydb_search_reset). */
unsigned long skipped_long_blobs;
/* If set, this disables the use of the keyblock cache. */
int no_caching;
/* Whether the next search will be from the beginning of the
database (and thus consider all records). */
int is_reset;
/* The "file position." In our case, this is index of the current
resource in ACTIVE. */
int current;
/* The number of resources in ACTIVE. */
int used;
/* Cache of the last found and parsed key block (only used for
keyboxes, not keyrings). */
struct keyblock_cache keyblock_cache;
/* Copy of ALL_RESOURCES when keydb_new is called. */
struct resource_item active[MAX_KEYDB_RESOURCES];
};
/* Looking up keys is expensive. To hide the cost, we cache whether
keys exist in the key database. Then, if we know a key does not
exist, we don't have to spend time looking it up. This
@ -273,7 +190,7 @@ kid_not_found_flush (void)
static void
keyblock_cache_clear (struct keydb_handle *hd)
keyblock_cache_clear (struct keydb_handle_s *hd)
{
hd->keyblock_cache.state = KEYBLOCK_CACHE_EMPTY;
iobuf_close (hd->keyblock_cache.iobuf);
@ -448,7 +365,7 @@ maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
rc = gpg_error_from_syserror ();
else
{
rc = _keybox_write_header_blob (fp, 1);
rc = _keybox_write_header_blob (fp, NULL, 1);
fclose (fp);
}
if (rc)
@ -539,6 +456,10 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
char b[MAX_FORMATTED_FINGERPRINT_LEN + 1];
char fpr[2 * MAX_FINGERPRINT_LEN + 1];
#if MAX_FINGERPRINT_LEN < 20
#error MAX_FINGERPRINT_LEN shorter than GRIP and UBID length/
#endif
switch (desc->mode)
{
case KEYDB_SEARCH_MODE_EXACT:
@ -578,7 +499,11 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
case KEYDB_SEARCH_MODE_SUBJECT:
return xasprintf ("SUBJECT: '%s'", desc->u.name);
case KEYDB_SEARCH_MODE_KEYGRIP:
return xasprintf ("KEYGRIP: %s", desc->u.grip);
bin2hex (desc[0].u.grip, 20, fpr);
return xasprintf ("KEYGRIP: %s", fpr);
case KEYDB_SEARCH_MODE_UBID:
bin2hex (desc[0].u.ubid, 20, fpr);
return xasprintf ("UBID: %s", fpr);
case KEYDB_SEARCH_MODE_FIRST:
return xasprintf ("FIRST");
case KEYDB_SEARCH_MODE_NEXT:
@ -888,26 +813,17 @@ keydb_dump_stats (void)
}
/* Create a new database handle. A database handle is similar to a
file handle: it contains a local file position. This is used when
searching: subsequent searches resume where the previous search
left off. To rewind the position, use keydb_search_reset(). This
function returns NULL on error, sets ERRNO, and prints an error
diagnostic. */
KEYDB_HANDLE
keydb_new (void)
/* keydb_new diverts to here in non-keyboxd mode. HD is just the
* calloced structure with the handle type intialized. */
gpg_error_t
internal_keydb_init (KEYDB_HANDLE hd)
{
KEYDB_HANDLE hd;
gpg_error_t err = 0;
int i, j;
int die = 0;
int reterrno;
if (DBG_CLOCK)
log_clock ("keydb_new");
hd = xtrycalloc (1, sizeof *hd);
if (!hd)
goto leave;
log_assert (!hd->use_keyboxd);
hd->found = -1;
hd->saved_found = -1;
hd->is_reset = 1;
@ -949,28 +865,21 @@ keydb_new (void)
keydb_stats.handles++;
if (die)
{
keydb_release (hd);
gpg_err_set_errno (reterrno);
hd = NULL;
}
err = gpg_error_from_errno (reterrno);
leave:
if (!hd)
log_error (_("error opening key DB: %s\n"),
gpg_strerror (gpg_error_from_syserror()));
return hd;
return err;
}
/* Free all non-keyboxd resources owned by the database handle.
* keydb_release diverts to here. */
void
keydb_release (KEYDB_HANDLE hd)
internal_keydb_deinit (KEYDB_HANDLE hd)
{
int i;
if (!hd)
return;
log_assert (!hd->use_keyboxd);
log_assert (active_handles > 0);
active_handles--;
@ -992,19 +901,17 @@ keydb_release (KEYDB_HANDLE hd)
}
keyblock_cache_clear (hd);
xfree (hd);
}
/* Take a lock on the files immediately and not only during insert or
* update. This lock is released with keydb_release. */
gpg_error_t
keydb_lock (KEYDB_HANDLE hd)
internal_keydb_lock (KEYDB_HANDLE hd)
{
gpg_error_t err;
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
log_assert (!hd->use_keyboxd);
err = lock_all (hd);
if (!err)
@ -1020,7 +927,7 @@ keydb_lock (KEYDB_HANDLE hd)
void
keydb_disable_caching (KEYDB_HANDLE hd)
{
if (hd)
if (hd && !hd->use_keyboxd)
hd->no_caching = 1;
}
@ -1042,6 +949,9 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
if (!hd)
return NULL;
if (!hd->use_keyboxd)
return "[keyboxd]";
if ( hd->found >= 0 && hd->found < hd->used)
idx = hd->found;
else if ( hd->current >= 0 && hd->current < hd->used)
@ -1165,6 +1075,8 @@ unlock_all (KEYDB_HANDLE hd)
* Note: it is only possible to save a single save state at a time.
* In other words, the save stack only has room for a single
* instance of the state. */
/* FIXME(keyboxd): This function is used only at one place - see how
* we can avoid it. */
void
keydb_push_found_state (KEYDB_HANDLE hd)
{
@ -1196,6 +1108,8 @@ keydb_push_found_state (KEYDB_HANDLE hd)
/* Restore the previous save state. If the saved state is NULL or
invalid, this is a NOP. */
/* FIXME(keyboxd): This function is used only at one place - see how
* we can avoid it. */
void
keydb_pop_found_state (KEYDB_HANDLE hd)
{
@ -1360,6 +1274,7 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
/* Return the keyblock last found by keydb_search() in *RET_KB.
* keydb_get_keyblock divert to here in the non-keyboxd mode.
*
* On success, the function returns 0 and the caller must free *RET_KB
* using release_kbnode(). Otherwise, the function returns an error
@ -1369,17 +1284,11 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
* with the public key used to locate the keyblock or flag bit 1 set
* for the user ID node. */
gpg_error_t
keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
internal_keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
{
gpg_error_t err = 0;
*ret_kb = NULL;
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
if (DBG_CLOCK)
log_clock ("keydb_get_keybock enter");
log_assert (!hd->use_keyboxd);
if (hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED)
{
@ -1398,8 +1307,7 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
if (err)
keyblock_cache_clear (hd);
if (DBG_CLOCK)
log_clock (err? "keydb_get_keyblock leave (cached, failed)"
: "keydb_get_keyblock leave (cached)");
log_clock ("%s leave (cached mode)", __func__);
return err;
}
}
@ -1447,9 +1355,6 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
if (!err)
keydb_stats.get_keyblocks++;
if (DBG_CLOCK)
log_clock (err? "keydb_get_keyblock leave (failed)"
: "keydb_get_keyblock leave");
return err;
}
@ -1498,6 +1403,7 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
/* Update the keyblock KB (i.e., extract the fingerprint and find the
* corresponding keyblock in the keyring).
* keydb_update_keyblock diverts to here in the non-keyboxd mode.
*
* This doesn't do anything if --dry-run was specified.
*
@ -1512,20 +1418,16 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
* you should use keydb_push_found_state and keydb_pop_found_state to
* save and restore it. */
gpg_error_t
keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
internal_keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
{
gpg_error_t err;
PKT_public_key *pk;
KEYDB_SEARCH_DESC desc;
size_t len;
log_assert (kb);
log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
log_assert (!hd->use_keyboxd);
pk = kb->pkt->pkt.public_key;
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
kid_not_found_flush ();
keyblock_cache_clear (hd);
@ -1588,6 +1490,7 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
/* Insert a keyblock into one of the underlying keyrings or keyboxes.
* keydb_insert_keyblock diverts to here in the non-keyboxd mode.
*
* Be default, the keyring / keybox from which the last search result
* came is used. If there was no previous search result (or
@ -1598,13 +1501,12 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
*
* Returns 0 on success. Otherwise, it returns an error code. */
gpg_error_t
keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
internal_keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
{
gpg_error_t err;
int idx;
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
log_assert (!hd->use_keyboxd);
kid_not_found_flush ();
keyblock_cache_clear (hd);
@ -1663,12 +1565,11 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
*
* Returns 0 on success or an error code, if an error occurs. */
gpg_error_t
keydb_delete_keyblock (KEYDB_HANDLE hd)
internal_keydb_delete_keyblock (KEYDB_HANDLE hd)
{
gpg_error_t rc;
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
log_assert (!hd->use_keyboxd);
kid_not_found_flush ();
keyblock_cache_clear (hd);
@ -1721,6 +1622,9 @@ keydb_locate_writable (KEYDB_HANDLE hd)
if (!hd)
return GPG_ERR_INV_ARG;
if (hd->use_keyboxd)
return 0; /* No need for this here. */
rc = keydb_search_reset (hd); /* this does reset hd->current */
if (rc)
return rc;
@ -1772,6 +1676,9 @@ keydb_rebuild_caches (ctrl_t ctrl, int noisy)
{
int i, rc;
if (opt.use_keyboxd)
return; /* No need for this here. */
for (i=0; i < used_resources; i++)
{
if (!keyring_is_writable (all_resources[i].token))
@ -1794,38 +1701,33 @@ keydb_rebuild_caches (ctrl_t ctrl, int noisy)
}
/* Return the number of skipped blocks (because they were to large to
/* Return the number of skipped blocks (because they were too large to
read from a keybox) since the last search reset. */
unsigned long
keydb_get_skipped_counter (KEYDB_HANDLE hd)
{
return hd ? hd->skipped_long_blobs : 0;
/*FIXME(keyboxd): Do we need this? */
return hd && !hd->use_keyboxd? hd->skipped_long_blobs : 0;
}
/* Clears the current search result and resets the handle's position
* so that the next search starts at the beginning of the database
* (the start of the first resource).
* keydb_search_reset diverts to here in the non-keyboxd mode.
*
* Returns 0 on success and an error code if an error occurred.
* (Currently, this function always returns 0 if HD is valid.) */
gpg_error_t
keydb_search_reset (KEYDB_HANDLE hd)
internal_keydb_search_reset (KEYDB_HANDLE hd)
{
gpg_error_t rc = 0;
int i;
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
log_assert (!hd->use_keyboxd);
keyblock_cache_clear (hd);
if (DBG_CLOCK)
log_clock ("keydb_search_reset");
if (DBG_CACHE)
log_debug ("keydb_search: reset (hd=%p)", hd);
hd->skipped_long_blobs = 0;
hd->current = 0;
hd->found = -1;
@ -1853,6 +1755,7 @@ keydb_search_reset (KEYDB_HANDLE hd)
/* Search the database for keys matching the search description. If
* the DB contains any legacy keys, these are silently ignored.
* keydb_search diverts to here in the non-keyboxd mode.
*
* DESC is an array of search terms with NDESC entries. The search
* terms are or'd together. That is, the next entry in the DB that
@ -1870,21 +1773,16 @@ keydb_search_reset (KEYDB_HANDLE hd)
* The returned key is considered to be selected and the raw data can,
* for instance, be returned by calling keydb_get_keyblock(). */
gpg_error_t
keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex)
internal_keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex)
{
int i;
gpg_error_t rc;
int was_reset = hd->is_reset;
/* If an entry is already in the cache, then don't add it again. */
int already_in_cache = 0;
int fprlen;
if (descindex)
*descindex = 0; /* Make sure it is always set on return. */
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
log_assert (!hd->use_keyboxd);
if (!any_registered)
{
@ -1892,26 +1790,11 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
return gpg_error (GPG_ERR_NOT_FOUND);
}
if (DBG_CLOCK)
log_clock ("keydb_search enter");
if (DBG_LOOKUP)
{
log_debug ("%s: %zd search descriptions:\n", __func__, ndesc);
for (i = 0; i < ndesc; i ++)
{
char *t = keydb_search_desc_dump (&desc[i]);
log_debug ("%s %d: %s\n", __func__, i, t);
xfree (t);
}
}
if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID
&& (already_in_cache = kid_not_found_p (desc[0].u.kid)) == 1 )
{
if (DBG_CLOCK)
log_clock ("keydb_search leave (not found, cached)");
log_clock ("%s leave (not found, cached)", __func__);
keydb_stats.notfound_cached++;
return gpg_error (GPG_ERR_NOT_FOUND);
}
@ -1939,7 +1822,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
{
/* (DESCINDEX is already set). */
if (DBG_CLOCK)
log_clock ("keydb_search leave (cached)");
log_clock ("%s leave (cached)", __func__);
hd->current = hd->keyblock_cache.resource;
/* HD->KEYBLOCK_CACHE.OFFSET is the last byte in the record.
@ -2029,9 +1912,6 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
&& !already_in_cache)
kid_not_found_insert (desc[0].u.kid);
if (DBG_CLOCK)
log_clock (rc? "keydb_search leave (not found)"
: "keydb_search leave (found)");
if (!rc)
keydb_stats.found++;
else

View File

@ -169,6 +169,41 @@ is_in_klist (struct key_item *k, PKT_signature *sig)
}
/*-- call-keyboxd.c --*/
/* Release all open contexts to the keyboxd. */
void gpg_keyboxd_deinit_session_data (ctrl_t ctrl);
/* Create a new database handle. Returns NULL on error, sets ERRNO,
* and prints an error diagnostic. */
KEYDB_HANDLE keydb_new (ctrl_t ctrl);
/* Release a keydb handle. */
void keydb_release (KEYDB_HANDLE hd);
/* Take a lock if we are not using the keyboxd. */
gpg_error_t keydb_lock (KEYDB_HANDLE hd);
/* Return the keyblock last found by keydb_search. */
gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, kbnode_t *ret_kb);
/* Update the keyblock KB. */
gpg_error_t keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb);
/* Insert a keyblock into one of the storage system. */
gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
/* Delete the currently selected keyblock. */
gpg_error_t keydb_delete_keyblock (KEYDB_HANDLE hd);
/* Clears the current search result and resets the handle's position. */
gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
/* Search the database for keys matching the search description. */
gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex);
/*-- keydb.c --*/
@ -187,17 +222,6 @@ gpg_error_t keydb_add_resource (const char *url, unsigned int flags);
/* Dump some statistics to the log. */
void keydb_dump_stats (void);
/* Create a new database handle. Returns NULL on error, sets ERRNO,
and prints an error diagnostic. */
KEYDB_HANDLE keydb_new (void);
/* Free all resources owned by the database handle. */
void keydb_release (KEYDB_HANDLE hd);
/* Take a lock on the files immediately and not only during insert or
* update. This lock is released with keydb_release. */
gpg_error_t keydb_lock (KEYDB_HANDLE hd);
/* Set a flag on the handle to suppress use of cached results. This
is required for updating a keyring and for key listings. Fixme:
Using a new parameter for keydb_new might be a better solution. */
@ -212,18 +236,6 @@ void keydb_pop_found_state (KEYDB_HANDLE hd);
/* Return the file name of the resource. */
const char *keydb_get_resource_name (KEYDB_HANDLE hd);
/* Return the keyblock last found by keydb_search. */
gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
/* Update the keyblock KB. */
gpg_error_t keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb);
/* Insert a keyblock into one of the underlying keyrings or keyboxes. */
gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
/* Delete the currently selected keyblock. */
gpg_error_t keydb_delete_keyblock (KEYDB_HANDLE hd);
/* Find the first writable resource. */
gpg_error_t keydb_locate_writable (KEYDB_HANDLE hd);
@ -234,13 +246,6 @@ void keydb_rebuild_caches (ctrl_t ctrl, int noisy);
read from a keybox) since the last search reset. */
unsigned long keydb_get_skipped_counter (KEYDB_HANDLE hd);
/* Clears the current search result and resets the handle's position. */
gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
/* Search the database for keys matching the search description. */
gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex);
/* Return the first non-legacy key in the database. */
gpg_error_t keydb_search_first (KEYDB_HANDLE hd);
@ -331,7 +336,7 @@ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
/* Similar to get_pubkey, but it does not take PK->REQ_USAGE into
account nor does it merge in the self-signed data. This function
also only considers primary keys. */
int get_pubkey_fast (PKT_public_key *pk, u32 *keyid);
int get_pubkey_fast (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
/* Return the entire keyblock used to create SIG. This is a
* specialized version of get_pubkeyblock. */
@ -391,13 +396,14 @@ int get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
/* This function is similar to get_pubkey_byfprint, but it doesn't
merge the self-signed data into the public key and subkeys or into
the user ids. */
gpg_error_t get_pubkey_byfprint_fast (PKT_public_key *pk,
gpg_error_t get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key *pk,
const byte *fprint, size_t fprint_len);
/* This function is similar to get_pubkey_byfprint, but it doesn't
merge the self-signed data into the public key and subkeys or into
the user ids. */
gpg_error_t get_keyblock_byfprint_fast (kbnode_t *r_keyblock,
gpg_error_t get_keyblock_byfprint_fast (ctrl_t ctrl,
kbnode_t *r_keyblock,
KEYDB_HANDLE *r_hd,
const byte *fprint, size_t fprint_len,
int lock);
@ -405,7 +411,7 @@ gpg_error_t get_keyblock_byfprint_fast (kbnode_t *r_keyblock,
/* Returns true if a secret key is available for the public key with
key id KEYID. */
int have_secret_key_with_kid (u32 *keyid);
int have_secret_key_with_kid (ctrl_t ctrl, u32 *keyid);
/* Parse the --default-key parameter. Returns the last key (in terms
of when the option is given) that is available. */

View File

@ -2289,7 +2289,7 @@ quick_find_keyblock (ctrl_t ctrl, const char *username,
*r_keyblock = NULL;
/* Search the key; we don't want the whole getkey stuff here. */
kdbhd = keydb_new ();
kdbhd = keydb_new (ctrl);
if (!kdbhd)
{
/* Note that keydb_new has already used log_error. */
@ -5761,7 +5761,7 @@ menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
}
else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
&& ((sig = node->pkt->pkt.signature),
have_secret_key_with_kid (sig->keyid)))
have_secret_key_with_kid (ctrl, sig->keyid)))
{
if ((sig->sig_class & ~3) == 0x10)
{
@ -5800,7 +5800,7 @@ menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
}
else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
&& ((sig = node->pkt->pkt.signature),
have_secret_key_with_kid (sig->keyid)))
have_secret_key_with_kid (ctrl, sig->keyid)))
{
if ((sig->sig_class & ~3) == 0x10)
{

View File

@ -4502,7 +4502,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
desc.mode = KEYDB_SEARCH_MODE_EXACT;
desc.u.name = uid;
kdbhd = keydb_new ();
kdbhd = keydb_new (ctrl);
if (!kdbhd)
goto leave;
@ -5371,7 +5371,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
{
KEYDB_HANDLE pub_hd;
pub_hd = keydb_new ();
pub_hd = keydb_new (ctrl);
if (!pub_hd)
err = gpg_error_from_syserror ();
else

View File

@ -524,7 +524,7 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
if (opt.check_sigs)
listctx.check_sigs = 1;
hd = keydb_new ();
hd = keydb_new (ctrl);
if (!hd)
rc = gpg_error_from_syserror ();
else

View File

@ -1195,7 +1195,7 @@ keyidlist (ctrl_t ctrl, strlist_t users, KEYDB_SEARCH_DESC **klist,
*klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
kdbhd = keydb_new ();
kdbhd = keydb_new (ctrl);
if (!kdbhd)
{
rc = gpg_error_from_syserror ();

View File

@ -157,7 +157,7 @@ struct expando_args
const byte *namehash;
};
char *pct_expando(const char *string,struct expando_args *args);
char *pct_expando (ctrl_t ctrl, const char *string,struct expando_args *args);
void deprecated_warning(const char *configname,unsigned int configlineno,
const char *option,const char *repl1,const char *repl2);
void deprecated_command (const char *name);

View File

@ -895,7 +895,7 @@ get_signature_count (PKT_public_key *pk)
/* Expand %-strings. Returns a string which must be xfreed. Returns
NULL if the string cannot be expanded (too large). */
char *
pct_expando(const char *string,struct expando_args *args)
pct_expando (ctrl_t ctrl, const char *string,struct expando_args *args)
{
const char *ch=string;
int idx=0,maxlen=0,done=0;
@ -1017,7 +1017,7 @@ pct_expando(const char *string,struct expando_args *args)
PKT_public_key *pk=
xmalloc_clear(sizeof(PKT_public_key));
if (!get_pubkey_fast (pk,args->pksk->main_keyid))
if (!get_pubkey_fast (ctrl, pk,args->pksk->main_keyid))
fingerprint_from_pk (pk, array, &len);
else
memset (array, 0, (len=MAX_FINGERPRINT_LEN));

View File

@ -30,8 +30,8 @@
#include "options.h"
#include "objcache.h"
/* Note that max value for uid_items is actually a the threshold when
* we start to look for ietms which can be removed. */
/* Note that max value for uid_items is actually the threshold when
* we start to look for items which can be removed. */
#define NO_OF_UID_ITEM_BUCKETS 107
#define MAX_UID_ITEMS_PER_BUCKET 20

View File

@ -126,6 +126,7 @@ struct
int completes_needed;
int max_cert_depth;
const char *agent_program;
const char *keyboxd_program;
const char *dirmngr_program;
int disable_dirmngr;
@ -287,6 +288,8 @@ struct
int only_sign_text_ids;
int no_symkey_cache; /* Disable the cache used for --symmetric. */
int use_keyboxd; /* Use the external keyboxd as storage backend. */
} opt;
/* CTRL is used to keep some global variables we currently can't

View File

@ -667,8 +667,8 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
int offset = attrs[i].len-len;
/* make command grow */
command = pct_expando (opt.photo_viewer, &args);
if (!command)
command = pct_expando (ctrl, opt.photo_viewer,&args);
if(!command)
goto fail;
name = xmalloc (1 + 16 + strlen(EXTSEP_S)

View File

@ -217,7 +217,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
afx = new_armor_context ();
kdbhd = keydb_new ();
kdbhd = keydb_new (ctrl);
if (!kdbhd)
{
rc = gpg_error_from_syserror ();
@ -641,7 +641,7 @@ gen_revoke (ctrl_t ctrl, const char *uname)
}
/* Search the userid; we don't want the whole getkey stuff here. */
kdbhd = keydb_new ();
kdbhd = keydb_new (ctrl);
if (!kdbhd)
{
rc = gpg_error_from_syserror ();

View File

@ -70,7 +70,7 @@ typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t;
* a valid NAME=VALUE format.
*/
static void
mk_notation_policy_etc (PKT_signature *sig,
mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig,
PKT_public_key *pk, PKT_public_key *pksk)
{
const char *string;
@ -99,7 +99,7 @@ mk_notation_policy_etc (PKT_signature *sig,
for (item = nd; item; item = item->next)
{
item->altvalue = pct_expando (item->value,&args);
item->altvalue = pct_expando (ctrl, item->value,&args);
if (!item->altvalue)
log_error (_("WARNING: unable to %%-expand notation "
"(too large). Using unexpanded.\n"));
@ -126,7 +126,7 @@ mk_notation_policy_etc (PKT_signature *sig,
{
string = pu->d;
p = pct_expando (string, &args);
p = pct_expando (ctrl, string, &args);
if (!p)
{
log_error(_("WARNING: unable to %%-expand policy URL "
@ -149,7 +149,7 @@ mk_notation_policy_etc (PKT_signature *sig,
{
string = pu->d;
p = pct_expando (string, &args);
p = pct_expando (ctrl, string, &args);
if (!p)
{
log_error (_("WARNING: unable to %%-expand preferred keyserver URL"
@ -838,7 +838,7 @@ write_signature_packets (ctrl_t ctrl,
BUG ();
build_sig_subpkt_from_sig (sig, pk);
mk_notation_policy_etc (sig, NULL, pk);
mk_notation_policy_etc (ctrl, sig, NULL, pk);
hash_sigversion_to_magic (md, sig, extrahash);
gcry_md_final (md);
@ -1664,7 +1664,7 @@ make_keysig_packet (ctrl_t ctrl,
sig->sig_class = sigclass;
build_sig_subpkt_from_sig (sig, pksk);
mk_notation_policy_etc (sig, pk, pksk);
mk_notation_policy_etc (ctrl, sig, pk, pksk);
/* Crucial that the call to mksubpkt comes LAST before the calls
* to finalize the sig as that makes it possible for the mksubpkt

View File

@ -21,9 +21,11 @@
#include "keydb.h"
static void
do_test (int argc, char *argv[])
{
ctrl_t ctrl;
char *fname;
int rc;
KEYDB_HANDLE hd1;
@ -33,6 +35,7 @@ do_test (int argc, char *argv[])
(void) argc;
(void) argv;
ctrl = xcalloc (1, sizeof *ctrl);
/* t-keydb-get-keyblock.gpg contains two keys: a modern key followed
by a legacy key. If we get the keyblock for the modern key, we
shouldn't get
@ -44,7 +47,7 @@ do_test (int argc, char *argv[])
if (rc)
ABORT ("Failed to open keyring.");
hd1 = keydb_new ();
hd1 = keydb_new (ctrl);
if (!hd1)
ABORT ("");
@ -62,4 +65,5 @@ do_test (int argc, char *argv[])
keydb_release (hd1);
release_kbnode (kb1);
xfree (ctrl);
}

View File

@ -25,6 +25,7 @@ static void
do_test (int argc, char *argv[])
{
int rc;
ctrl_t ctrl;
KEYDB_HANDLE hd1, hd2;
KEYDB_SEARCH_DESC desc1, desc2;
KBNODE kb1, kb2, p;
@ -35,16 +36,17 @@ do_test (int argc, char *argv[])
(void) argc;
(void) argv;
ctrl = xcalloc (1, sizeof *ctrl);
fname = prepend_srcdir ("t-keydb-keyring.kbx");
rc = keydb_add_resource (fname, 0);
test_free (fname);
if (rc)
ABORT ("Failed to open keyring.");
hd1 = keydb_new ();
hd1 = keydb_new (ctrl);
if (!hd1)
ABORT ("");
hd2 = keydb_new ();
hd2 = keydb_new (ctrl);
if (!hd2)
ABORT ("");
@ -101,4 +103,5 @@ do_test (int argc, char *argv[])
release_kbnode (kb2);
keydb_release (hd1);
keydb_release (hd2);
xfree (ctrl);
}

View File

@ -2131,7 +2131,7 @@ build_conflict_set (ctrl_t ctrl, tofu_dbs_t dbs,
/* If two keys have cross signatures, then they are controlled by
* the same person and thus are not in conflict. */
kb_all = xcalloc (sizeof (kb_all[0]), conflict_set_count);
hd = keydb_new ();
hd = keydb_new (ctrl);
for (i = 0, iter = conflict_set;
i < conflict_set_count;
i ++, iter = iter->next)

View File

@ -2017,7 +2017,7 @@ validate_keys (ctrl_t ctrl, int interactive)
trust. */
keydb_rebuild_caches (ctrl, 0);
kdb = keydb_new ();
kdb = keydb_new (ctrl);
if (!kdb)
return gpg_error_from_syserror ();

View File

@ -18,16 +18,20 @@
## Process this file with automake to produce Makefile.in
EXTRA_DIST = mkerrors
EXTRA_DIST = mkerrors keyboxd-w32info.rc
AM_CPPFLAGS =
include $(top_srcdir)/am/cmacros.am
if HAVE_W32_SYSTEM
resource_objs += keyboxd-w32info.o
endif
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS)
noinst_LIBRARIES = libkeybox.a libkeybox509.a
bin_PROGRAMS = kbxutil
libexec_PROGRAMS = keyboxd
if HAVE_W32CE_SYSTEM
extra_libs = $(LIBASSUAN_LIBS)
@ -35,6 +39,9 @@ else
extra_libs =
endif
common_libs = $(libcommon)
commonpth_libs = $(libcommonpth)
common_sources = \
keybox.h keybox-defs.h keybox-search-desc.h \
keybox-util.c \
@ -59,9 +66,31 @@ libkeybox509_a_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1
# to do it this way.
kbxutil_SOURCES = kbxutil.c $(common_sources)
kbxutil_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1
kbxutil_LDADD = ../common/libcommon.a \
kbxutil_LDADD = $(common_libs) \
$(KSBA_LIBS) $(LIBGCRYPT_LIBS) $(extra_libs) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) $(W32SOCKLIBS) \
$(NETLIBS)
$(PROGRAMS) : ../common/libcommon.a
keyboxd_SOURCES = \
keyboxd.c keyboxd.h \
kbxserver.c \
frontend.c frontend.h \
backend.h backend-support.c \
backend-cache.c \
backend-kbx.c \
$(common_sources)
keyboxd_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) \
$(INCICONV)
keyboxd_LDADD = $(commonpth_libs) \
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
$(resource_objs)
keyboxd_LDFLAGS = $(extra_bin_ldflags)
keyboxd_DEPENDENCIES = $(resource_objs)
# Make sure that all libs are build before we use them. This is
# important for things like make -j2.
$(PROGRAMS): $(common_libs) $(commonpth_libs)

1190
kbx/backend-cache.c Normal file

File diff suppressed because it is too large Load Diff

328
kbx/backend-kbx.c Normal file
View File

@ -0,0 +1,328 @@
/* backend-kbx.c - Keybox format backend for keyboxd
* Copyright (C) 2019 g10 Code GmbH
*
* 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 <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "keyboxd.h"
#include "../common/i18n.h"
#include "backend.h"
#include "keybox.h"
/* Our definition of the backend handle. */
struct backend_handle_s
{
enum database_types db_type; /* Always DB_TYPE_KBX. */
unsigned int backend_id; /* Always the id of the backend. */
void *token; /* Used to create a new KEYBOX_HANDLE. */
char filename[1];
};
/* Check that the file FILENAME is a valid keybox file which can be
* used here. Common return codes:
*
* 0 := Valid keybox file
* GPG_ERR_ENOENT := No such file
* GPG_ERR_NO_OBJ := File exists with size zero.
* GPG_ERR_INV_OBJ:= File exists but is not a keybox file.
*/
static gpg_error_t
check_kbx_file_magic (const char *filename)
{
gpg_error_t err;
u32 magic;
unsigned char verbuf[4];
estream_t fp;
fp = es_fopen (filename, "rb");
if (!fp)
return gpg_error_from_syserror ();
err = gpg_error (GPG_ERR_INV_OBJ);
if (es_fread (&magic, 4, 1, fp) == 1 )
{
if (es_fread (&verbuf, 4, 1, fp) == 1
&& verbuf[0] == 1
&& es_fread (&magic, 4, 1, fp) == 1
&& !memcmp (&magic, "KBXf", 4))
{
err = 0;
}
}
else /* Maybe empty: Let's create it. */
err = gpg_error (GPG_ERR_NO_OBJ);
es_fclose (fp);
return err;
}
/* Create new keybox file. This can also be used if the keybox
* already exists but has a length of zero. Do not use it in any
* other cases. */
static gpg_error_t
create_keybox (const char *filename)
{
gpg_error_t err;
dotlock_t lockhd = NULL;
estream_t fp;
/* To avoid races with other temporary instances of keyboxd trying
* to create or update the keybox, we do the next stuff in a locked
* state. */
lockhd = dotlock_create (filename, 0);
if (!lockhd)
{
err = gpg_error_from_syserror ();
/* A reason for this to fail is that the directory is not
* writable. However, this whole locking stuff does not make
* sense if this is the case. An empty non-writable directory
* with no keybox is not really useful at all. */
if (opt.verbose)
log_info ("can't allocate lock for '%s': %s\n",
filename, gpg_strerror (err));
return err;
}
if ( dotlock_take (lockhd, -1) )
{
err = gpg_error_from_syserror ();
/* This is something bad. Probably a stale lockfile. */
log_info ("can't lock '%s': %s\n", filename, gpg_strerror (err));
goto leave;
}
/* Make sure that at least one record is in a new keybox file, so
* that the detection magic will work the next time it is used.
* We always set the OpenPGP blobs maybe availabale flag. */
fp = es_fopen (filename, "w+b,mode=-rw-------");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error (_("error creating keybox '%s': %s\n"),
filename, gpg_strerror (err));
goto leave;
}
err = _keybox_write_header_blob (NULL, fp, 1);
es_fclose (fp);
if (err)
{
log_error (_("error creating keybox '%s': %s\n"),
filename, gpg_strerror (err));
goto leave;
}
if (!opt.quiet)
log_info (_("keybox '%s' created\n"), filename);
err = 0;
leave:
if (lockhd)
{
dotlock_release (lockhd);
dotlock_destroy (lockhd);
}
return err;
}
/* Install a new resource and return a handle for that backend. */
gpg_error_t
be_kbx_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
const char *filename, int readonly)
{
gpg_error_t err;
backend_handle_t hd;
void *token;
(void)ctrl;
*r_hd = NULL;
hd = xtrycalloc (1, sizeof *hd + strlen (filename));
if (!hd)
return gpg_error_from_syserror ();
hd->db_type = DB_TYPE_KBX;
strcpy (hd->filename, filename);
err = check_kbx_file_magic (filename);
switch (gpg_err_code (err))
{
case 0:
break;
case GPG_ERR_ENOENT:
case GPG_ERR_NO_OBJ:
if (readonly)
{
err = gpg_error (GPG_ERR_ENOENT);
goto leave;
}
err = create_keybox (filename);
if (err)
goto leave;
break;
default:
goto leave;
}
err = keybox_register_file (filename, 0, &token);
if (err)
goto leave;
hd->backend_id = be_new_backend_id ();
hd->token = token;
*r_hd = hd;
hd = NULL;
leave:
xfree (hd);
return err;
}
/* Release the backend handle HD and all its resources. HD is not
* valid after a call to this function. */
void
be_kbx_release_resource (ctrl_t ctrl, backend_handle_t hd)
{
(void)ctrl;
if (!hd)
return;
hd->db_type = DB_TYPE_NONE;
xfree (hd);
}
void
be_kbx_release_kbx_hd (KEYBOX_HANDLE kbx_hd)
{
keybox_release (kbx_hd);
}
/* Helper for be_find_request_part to initialize a kbx request part. */
gpg_error_t
be_kbx_init_request_part (backend_handle_t backend_hd, db_request_part_t part)
{
part->kbx_hd = keybox_new_openpgp (backend_hd->token, 0);
if (!part->kbx_hd)
return gpg_error_from_syserror ();
return 0;
}
/* Search for the keys described by (DESC,NDESC) and return them to
* the caller. BACKEND_HD is the handle for this backend and REQUEST
* is the current database request object. */
gpg_error_t
be_kbx_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
KEYDB_SEARCH_DESC *desc, unsigned int ndesc)
{
gpg_error_t err;
db_request_part_t part;
size_t descindex;
unsigned long skipped_long_blobs;
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_KBX);
log_assert (request);
/* Find the specific request part or allocate it. */
err = be_find_request_part (backend_hd, request, &part);
if (err)
goto leave;
if (!desc)
err = keybox_search_reset (part->kbx_hd);
else
err = keybox_search (part->kbx_hd, desc, ndesc, KEYBOX_BLOBTYPE_PGP,
&descindex, &skipped_long_blobs);
if (err == -1)
err = gpg_error (GPG_ERR_EOF);
if (desc && !err)
{
/* Successful search operation. */
void *buffer;
size_t buflen;
enum pubkey_types pubkey_type;
unsigned char blobid[20];
err = keybox_get_data (part->kbx_hd, &buffer, &buflen, &pubkey_type);
if (err)
goto leave;
gcry_md_hash_buffer (GCRY_MD_SHA1, blobid, buffer, buflen);
err = be_return_pubkey (ctrl, buffer, buflen, pubkey_type, blobid);
if (!err)
be_cache_pubkey (ctrl, blobid, buffer, buflen, pubkey_type);
xfree (buffer);
}
leave:
return err;
}
/* Seek in the keybox to the given UBID. BACKEND_HD is the handle for
* this backend and REQUEST is the current database request object.
* This does a dummy read so that the next search operation starts
* right after that UBID. */
gpg_error_t
be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
db_request_t request, unsigned char *ubid)
{
gpg_error_t err;
db_request_part_t part;
size_t descindex;
unsigned long skipped_long_blobs;
KEYDB_SEARCH_DESC desc;
(void)ctrl;
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_KBX);
log_assert (request);
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_UBID;
memcpy (desc.u.ubid, ubid, 20);
/* Find the specific request part or allocate it. */
err = be_find_request_part (backend_hd, request, &part);
if (err)
goto leave;
err = keybox_search_reset (part->kbx_hd);
if (!err)
err = keybox_search (part->kbx_hd, &desc, 1, 0,
&descindex, &skipped_long_blobs);
if (err == -1)
err = gpg_error (GPG_ERR_EOF);
leave:
return err;
}

171
kbx/backend-support.c Normal file
View File

@ -0,0 +1,171 @@
/* backend-support.c - Supporting functions for the backend.
* Copyright (C) 2019 g10 Code GmbH
*
* 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 <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0+
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "keyboxd.h"
#include "../common/i18n.h"
#include "../common/asshelp.h"
#include "backend.h"
#include "keybox.h"
/* Common definition part of all backend handle. All definitions of
* this structure must start with these fields. */
struct backend_handle_s
{
enum database_types db_type;
unsigned int backend_id;
};
/* Return a string with the name of the database type T. */
const char *
strdbtype (enum database_types t)
{
switch (t)
{
case DB_TYPE_NONE: return "none";
case DB_TYPE_CACHE:return "cache";
case DB_TYPE_KBX: return "keybox";
}
return "?";
}
/* Return a new backend ID. Backend IDs are used to identify backends
* without using the actual object. The number of backend resources
* is limited because they are specified in the config file. Thus an
* overflow check is not required. */
unsigned int
be_new_backend_id (void)
{
static unsigned int last;
return ++last;
}
/* Release the backend described by HD. This is a generic function
* which dispatches to the the actual backend. */
void
be_generic_release_backend (ctrl_t ctrl, backend_handle_t hd)
{
if (!hd)
return;
switch (hd->db_type)
{
case DB_TYPE_NONE:
xfree (hd);
break;
case DB_TYPE_CACHE:
be_cache_release_resource (ctrl, hd);
break;
case DB_TYPE_KBX:
be_kbx_release_resource (ctrl, hd);
break;
default:
log_error ("%s: faulty backend handle of type %d given\n",
__func__, hd->db_type);
}
}
/* Release the request object REQ. */
void
be_release_request (db_request_t req)
{
db_request_part_t part, partn;
if (!req)
return;
for (part = req->part; part; part = partn)
{
partn = part->next;
be_kbx_release_kbx_hd (part->kbx_hd);
xfree (part);
}
}
/* Given the backend handle BACKEND_HD and the REQUEST find or
* allocate a request part for that backend and store it at R_PART.
* On error R_PART is set to NULL and an error returned. */
gpg_error_t
be_find_request_part (backend_handle_t backend_hd, db_request_t request,
db_request_part_t *r_part)
{
gpg_error_t err;
db_request_part_t part;
for (part = request->part; part; part = part->next)
if (part->backend_id == backend_hd->backend_id)
break;
if (!part)
{
part = xtrycalloc (1, sizeof *part);
if (!part)
return gpg_error_from_syserror ();
part->backend_id = backend_hd->backend_id;
if (backend_hd->db_type == DB_TYPE_KBX)
{
err = be_kbx_init_request_part (backend_hd, part);
if (err)
{
xfree (part);
return err;
}
}
part->next = request->part;
request->part = part;
}
*r_part = part;
return 0;
}
/* Return the public key (BUFFER,BUFLEN) which has the type
* PUBKEY_TYPE to the caller. */
gpg_error_t
be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
enum pubkey_types pubkey_type, const unsigned char *ubid)
{
gpg_error_t err;
char hexubid[41];
bin2hex (ubid, 20, hexubid);
err = status_printf (ctrl, "PUBKEY_INFO", "%d %s", pubkey_type, hexubid);
if (err)
goto leave;
if (ctrl->no_data_return)
err = 0;
else
err = kbxd_write_data_line(ctrl, buffer, buflen);
leave:
return err;
}

140
kbx/backend.h Normal file
View File

@ -0,0 +1,140 @@
/* backend.h - Definitions for keyboxd backends
* Copyright (C) 2019 g10 Code GmbH
*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef KBX_BACKEND_H
#define KBX_BACKEND_H
#include "keybox-search-desc.h"
/* Forward declaration of the keybox handle type. */
struct keybox_handle;
typedef struct keybox_handle *KEYBOX_HANDLE;
/* The types of the backends. */
enum database_types
{
DB_TYPE_NONE, /* No database at all (unitialized etc.). */
DB_TYPE_CACHE, /* The cache backend (backend-cache.c). */
DB_TYPE_KBX /* Keybox type database (backend-kbx.c). */
};
/* Declaration of the backend handle. Each backend uses its own
* hidden handle structure with the only common thing being that the
* first field is the database_type to help with debugging. */
struct backend_handle_s;
typedef struct backend_handle_s *backend_handle_t;
/* Object to store backend specific database information per database
* handle. */
struct db_request_part_s
{
struct db_request_part_s *next;
/* Id of the backend instance this object pertains to. */
unsigned int backend_id;
/* The handle used for a KBX backend or NULL. */
KEYBOX_HANDLE kbx_hd;
/* For the CACHE backend the indices into the bloblist for each
* index type. */
struct {
unsigned int fpr;
unsigned int kid;
unsigned int grip;
unsigned int ubid;
} cache_seqno;
};
typedef struct db_request_part_s *db_request_part_t;
/* A database request handle. This keeps per session search
* information as well as a list of per-backend infos. */
struct db_request_s
{
unsigned int any_search:1; /* Any search has been done. */
unsigned int any_found:1; /* Any object has been found. */
unsigned int last_cached_valid:1; /* see below */
unsigned int last_cached_final:1; /* see below */
unsigned int last_cached_fprlen:8;/* see below */
db_request_part_t part;
/* Counter to track the next to be searched database index. */
unsigned int next_dbidx;
/* The last UBID found in the cache and the corresponding keyid and,
* if found via fpr, the fingerprint. For the LAST_CACHE_FPRLEN see
* above. The entry here is only valid if LAST_CACHE_VALID is set;
* if LAST_CACHE_FINAL is also set, this indicates that no further
* database searches are required. */
unsigned char last_cached_ubid[20];
u32 last_cached_kid_h;
u32 last_cached_kid_l;
unsigned char last_cached_fpr[32];
};
/*-- backend-support.c --*/
const char *strdbtype (enum database_types t);
unsigned int be_new_backend_id (void);
void be_generic_release_backend (ctrl_t ctrl, backend_handle_t hd);
void be_release_request (db_request_t req);
gpg_error_t be_find_request_part (backend_handle_t backend_hd,
db_request_t request,
db_request_part_t *r_part);
gpg_error_t be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
enum pubkey_types pubkey_type,
const unsigned char *ubid);
/*-- backend-cache.c --*/
gpg_error_t be_cache_add_resource (ctrl_t ctrl, backend_handle_t *r_hd);
void be_cache_release_resource (ctrl_t ctrl, backend_handle_t hd);
gpg_error_t be_cache_search (ctrl_t ctrl, backend_handle_t backend_hd,
db_request_t request,
KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
void be_cache_mark_final (ctrl_t ctrl, db_request_t request);
void be_cache_pubkey (ctrl_t ctrl, const unsigned char *ubid,
const void *blob, unsigned int bloblen,
enum pubkey_types pubkey_type);
void be_cache_not_found (ctrl_t ctrl, enum pubkey_types pubkey_type,
KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
/*-- backend-kbx.c --*/
gpg_error_t be_kbx_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
const char *filename, int readonly);
void be_kbx_release_resource (ctrl_t ctrl, backend_handle_t hd);
void be_kbx_release_kbx_hd (KEYBOX_HANDLE kbx_hd);
gpg_error_t be_kbx_init_request_part (backend_handle_t backend_hd,
db_request_part_t part);
gpg_error_t be_kbx_search (ctrl_t ctrl, backend_handle_t hd,
db_request_t request,
KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
gpg_error_t be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
db_request_t request, unsigned char *ubid);
#endif /*KBX_BACKEND_H*/

385
kbx/frontend.c Normal file
View File

@ -0,0 +1,385 @@
/* frontend.c - Database fronend code for keyboxd
* Copyright (C) 2019 g10 Code GmbH
*
* 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 <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0+
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "keyboxd.h"
#include <assuan.h>
#include "../common/i18n.h"
#include "../common/userids.h"
#include "backend.h"
#include "frontend.h"
/* An object to describe a single database. */
struct db_desc_s
{
enum database_types db_type;
backend_handle_t backend_handle;
};
typedef struct db_desc_s *db_desc_t;
/* The table of databases and the size of that table. */
static db_desc_t databases;
static unsigned int no_of_databases;
/* Take a lock for reading the databases. */
static void
take_read_lock (ctrl_t ctrl)
{
/* FIXME */
(void)ctrl;
}
/* Take a lock for reading and writing the databases. */
/* static void */
/* take_read_write_lock (ctrl_t ctrl) */
/* { */
/* /\* FIXME *\/ */
/* (void)ctrl; */
/* } */
/* Release a lock. It is valid to call this even if no lock has been
* taken in which case this is a nop. */
static void
release_lock (ctrl_t ctrl)
{
/* FIXME */
(void)ctrl;
}
/* Add a new resource to the database. Depending on the FILENAME
* suffix we decide which one to use. This function must be called at
* daemon startup because it employs no locking. If FILENAME has no
* directory separator, the file is expected or created below
* "$GNUPGHOME/public-keys-v1.d/". In READONLY mode the file must
* exists; otherwise it is created. */
gpg_error_t
kbxd_add_resource (ctrl_t ctrl, const char *filename_arg, int readonly)
{
gpg_error_t err;
char *filename;
enum database_types db_type = 0;
backend_handle_t handle = NULL;
unsigned int n, dbidx;
/* Do tilde expansion etc. */
if (!strcmp (filename_arg, "[cache]"))
{
filename = xstrdup (filename_arg);
db_type = DB_TYPE_CACHE;
}
else if (strchr (filename_arg, DIRSEP_C)
#ifdef HAVE_W32_SYSTEM
|| strchr (filename_arg, '/') /* Windows also accepts a slash. */
#endif
)
filename = make_filename (filename_arg, NULL);
else
filename = make_filename (gnupg_homedir (), GNUPG_PUBLIC_KEYS_DIR,
filename_arg, NULL);
/* If this is the first call to the function and the request is not
* for the cache backend, add the cache backend so that it will
* always be the first to be queried. */
if (!no_of_databases && !db_type)
{
err = kbxd_add_resource (ctrl, "[cache]", 0);
if (err)
goto leave;
}
n = strlen (filename);
if (db_type)
; /* We already know it. */
else if (n > 4 && !strcmp (filename + n - 4, ".kbx"))
db_type = DB_TYPE_KBX;
else
{
log_error (_("can't use file '%s': %s\n"), filename, _("unknown suffix"));
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
goto leave;
}
err = gpg_error (GPG_ERR_BUG);
switch (db_type)
{
case DB_TYPE_NONE: /* NOTREACHED */
break;
case DB_TYPE_CACHE:
err = be_cache_add_resource (ctrl, &handle);
break;
case DB_TYPE_KBX:
err = be_kbx_add_resource (ctrl, &handle, filename, readonly);
break;
}
if (err)
goto leave;
/* All good, create an entry in the table. */
for (dbidx = 0; dbidx < no_of_databases; dbidx++)
if (!databases[dbidx].db_type)
break;
if (dbidx == no_of_databases)
{
/* No table yet or table is full. */
if (!databases)
{
/* Create first set of databases. Note that the initial
* type for all entries is DB_TYPE_NONE. */
dbidx = 4;
databases = xtrycalloc (dbidx, sizeof *databases);
if (!databases)
{
err = gpg_error_from_syserror ();
goto leave;
}
no_of_databases = dbidx;
dbidx = 0; /* Put into first slot. */
}
else
{
db_desc_t newdb;
dbidx = no_of_databases + (no_of_databases == 4? 12 : 16);
newdb = xtrycalloc (dbidx, sizeof *databases);
if (!databases)
{
err = gpg_error_from_syserror ();
goto leave;
}
for (n=0; n < no_of_databases; n++)
newdb[n] = databases[n];
xfree (databases);
databases = newdb;
n = no_of_databases;
no_of_databases = dbidx;
dbidx = n; /* Put into first new slot. */
}
}
databases[dbidx].db_type = db_type;
databases[dbidx].backend_handle = handle;
handle = NULL;
leave:
if (err)
{
log_error ("error adding resource '%s': %s\n",
filename, gpg_strerror (err));
be_generic_release_backend (ctrl, handle);
}
xfree (filename);
return err;
}
/* Release all per session objects. */
void
kbxd_release_session_info (ctrl_t ctrl)
{
if (!ctrl)
return;
be_release_request (ctrl->opgp_req);
ctrl->opgp_req = NULL;
be_release_request (ctrl->x509_req);
ctrl->x509_req = NULL;
}
/* Search for the keys described by (DESC,NDESC) and return them to
* the caller. If RESET is set, the search state is first reset. */
gpg_error_t
kbxd_search (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
int reset)
{
gpg_error_t err;
int i;
unsigned int dbidx;
db_desc_t db;
db_request_t request;
int start_at_ubid = 0;
if (DBG_CLOCK)
log_clock ("%s: enter", __func__);
if (DBG_LOOKUP)
{
log_debug ("%s: %u search descriptions:\n", __func__, ndesc);
for (i = 0; i < ndesc; i ++)
{
/* char *t = keydb_search_desc_dump (&desc[i]); */
/* log_debug ("%s %d: %s\n", __func__, i, t); */
/* xfree (t); */
}
}
take_read_lock (ctrl);
/* Allocate a handle object if none exists for this context. */
if (!ctrl->opgp_req)
{
ctrl->opgp_req = xtrycalloc (1, sizeof *ctrl->opgp_req);
if (!ctrl->opgp_req)
{
err = gpg_error_from_syserror ();
goto leave;
}
}
request = ctrl->opgp_req;
/* If requested do a reset. Using the reset flag is faster than
* letting the caller do a separate call for an intial reset. */
if (!desc || reset)
{
for (dbidx=0; dbidx < no_of_databases; dbidx++)
{
db = databases + dbidx;
if (!db->db_type)
continue; /* Empty slot. */
switch (db->db_type)
{
case DB_TYPE_NONE: /* NOTREACHED */
break;
case DB_TYPE_CACHE:
err = 0; /* Nothing to do. */
break;
case DB_TYPE_KBX:
err = be_kbx_search (ctrl, db->backend_handle, request, NULL, 0);
break;
}
if (err)
{
log_error ("error during the %ssearch reset: %s\n",
reset? "initial ":"", gpg_strerror (err));
goto leave;
}
}
request->any_search = 0;
request->any_found = 0;
request->next_dbidx = 0;
if (!desc) /* Reset only mode */
{
err = 0;
goto leave;
}
}
/* Move to the next non-empty slot. */
next_db:
for (dbidx=request->next_dbidx; (dbidx < no_of_databases
&& !databases[dbidx].db_type); dbidx++)
;
request->next_dbidx = dbidx;
if (!(dbidx < no_of_databases))
{
/* All databases have been searched. Put the non-found mark
* into the cache for all descriptors.
* FIXME: We need to see which pubkey type we need to insert. */
be_cache_not_found (ctrl, PUBKEY_TYPE_UNKNOWN, desc, ndesc);
err = gpg_error (GPG_ERR_NOT_FOUND);
goto leave;
}
db = databases + dbidx;
/* Divert to the backend for the actual search. */
switch (db->db_type)
{
case DB_TYPE_NONE:
/* NOTREACHED */
err = gpg_error (GPG_ERR_INTERNAL);
break;
case DB_TYPE_CACHE:
err = be_cache_search (ctrl, db->backend_handle, request,
desc, ndesc);
/* Expected error codes from the cache lookup are:
* 0 - found and returned via the cache
* GPG_ERR_NOT_FOUND - marked in the cache as not available
* GPG_ERR_EOF - cache miss. */
break;
case DB_TYPE_KBX:
if (start_at_ubid)
{
/* We need to set the startpoint for the search. */
err = be_kbx_seek (ctrl, db->backend_handle, request,
request->last_cached_ubid);
if (err)
{
log_debug ("%s: seeking %s to an UBID failed: %s\n",
__func__, strdbtype (db->db_type), gpg_strerror (err));
break;
}
}
err = be_kbx_search (ctrl, db->backend_handle, request,
desc, ndesc);
if (start_at_ubid && gpg_err_code (err) == GPG_ERR_EOF)
be_cache_mark_final (ctrl, request);
break;
}
if (DBG_LOOKUP)
log_debug ("%s: searched %s (db %u of %u) => %s\n",
__func__, strdbtype (db->db_type), dbidx, no_of_databases,
gpg_strerror (err));
request->any_search = 1;
start_at_ubid = 0;
if (!err)
{
request->any_found = 1;
}
else if (gpg_err_code (err) == GPG_ERR_EOF)
{
if (db->db_type == DB_TYPE_CACHE && request->last_cached_valid)
{
if (request->last_cached_final)
goto leave;
start_at_ubid = 1;
}
request->next_dbidx++;
goto next_db;
}
leave:
release_lock (ctrl);
if (DBG_CLOCK)
log_clock ("%s: leave (%s)", __func__, err? "not found" : "found");
return err;
}

36
kbx/frontend.h Normal file
View File

@ -0,0 +1,36 @@
/* frontend.h - Definitions for the keyboxd frontend
* Copyright (C) 2019 g10 Code GmbH
*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef KBX_FRONTEND_H
#define KBX_FRONTEND_H
#include "keybox-search-desc.h"
gpg_error_t kbxd_add_resource (ctrl_t ctrl,
const char *filename_arg, int readonly);
void kbxd_release_session_info (ctrl_t ctrl);
gpg_error_t kbxd_search (ctrl_t ctrl,
KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
int reset);
#endif /*KBX_FRONTEND_H*/

775
kbx/kbxserver.c Normal file
View File

@ -0,0 +1,775 @@
/* kbxserver.c - Handle Assuan commands send to the keyboxd
* Copyright (C) 2019 g10 Code GmbH
*
* 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 <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0+
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include "keyboxd.h"
#include <assuan.h>
#include "../common/i18n.h"
#include "../common/server-help.h"
#include "../common/userids.h"
#include "../common/asshelp.h"
#include "../common/host2net.h"
#include "frontend.h"
#define PARM_ERROR(t) assuan_set_error (ctx, \
gpg_error (GPG_ERR_ASS_PARAMETER), (t))
#define set_error(e,t) (ctx ? assuan_set_error (ctx, gpg_error (e), (t)) \
/**/: gpg_error (e))
/* Control structure per connection. */
struct server_local_s
{
/* Data used to associate an Assuan context with local server data */
assuan_context_t assuan_ctx;
/* The session id (a counter). */
unsigned int session_id;
/* If this flag is set to true this process will be terminated after
* the end of this session. */
int stopme;
/* If the first both flags are set the assuan logging of data lines
* is suppressed. The count variable is used to show the number of
* non-logged bytes. */
size_t inhibit_data_logging_count;
unsigned int inhibit_data_logging : 1;
unsigned int inhibit_data_logging_now : 1;
/* This flag is set if the last search command was called with --more. */
unsigned int search_expecting_more : 1;
/* This flag is set if the last search command was successful. */
unsigned int search_any_found : 1;
/* The first is the current search description as parsed by the
* cmd_search. If more than one pattern is required, cmd_search
* also allocates and sets multi_search_desc and
* multi_search_desc_len. If a search description has ever been
* allocated the allocated size is stored at
* multi_search_desc_size. */
KEYBOX_SEARCH_DESC search_desc;
KEYBOX_SEARCH_DESC *multi_search_desc;
unsigned int multi_search_desc_size;
unsigned int multi_search_desc_len;
/* If not NULL write output to this stream instead of using D lines. */
estream_t outstream;
};
/* Return the assuan contxt from the local server info in CTRL. */
static assuan_context_t
get_assuan_ctx_from_ctrl (ctrl_t ctrl)
{
if (!ctrl || !ctrl->server_local)
return NULL;
return ctrl->server_local->assuan_ctx;
}
/* If OUTPUT has been used prepare the output FD for use. This needs
* to be called by all functions which will in any way use
* kbxd_write_data_line later. Whether the output goes to the output
* stream is decided by this function. */
static gpg_error_t
prepare_outstream (ctrl_t ctrl)
{
int fd;
log_assert (ctrl && ctrl->server_local);
if (ctrl->server_local->outstream)
return 0; /* Already enabled. */
fd = translate_sys2libc_fd
(assuan_get_output_fd (get_assuan_ctx_from_ctrl (ctrl)), 1);
if (fd == -1)
return 0; /* No Output command active. */
ctrl->server_local->outstream = es_fdopen_nc (fd, "w");
if (!ctrl->server_local->outstream)
return gpg_err_code_from_syserror ();
return 0;
}
/* The usual writen function; here with diagnostic output. */
static gpg_error_t
kbxd_writen (estream_t fp, const void *buffer, size_t length)
{
gpg_error_t err;
size_t nwritten;
if (es_write (fp, buffer, length, &nwritten))
{
err = gpg_error_from_syserror ();
log_error ("error writing OUTPUT: %s\n", gpg_strerror (err));
}
else if (length != nwritten)
{
err = gpg_error (GPG_ERR_EIO);
log_error ("error writing OUTPUT: %s\n", "short write");
}
else
err = 0;
return err;
}
/* A wrapper around assuan_send_data which makes debugging the output
* in verbose mode easier. It also takes CTRL as argument. */
gpg_error_t
kbxd_write_data_line (ctrl_t ctrl, const void *buffer_arg, size_t size)
{
const char *buffer = buffer_arg;
assuan_context_t ctx = get_assuan_ctx_from_ctrl (ctrl);
gpg_error_t err;
if (!ctx) /* Oops - no assuan context. */
return gpg_error (GPG_ERR_NOT_PROCESSED);
/* Write toa file descriptor if enabled. */
if (ctrl && ctrl->server_local && ctrl->server_local->outstream)
{
unsigned char lenbuf[4];
ulongtobuf (lenbuf, size);
err = kbxd_writen (ctrl->server_local->outstream, lenbuf, 4);
if (!err)
err = kbxd_writen (ctrl->server_local->outstream, buffer, size);
if (!err && es_fflush (ctrl->server_local->outstream))
{
err = gpg_error_from_syserror ();
log_error ("error writing OUTPUT: %s\n", gpg_strerror (err));
}
goto leave;
}
/* If we do not want logging, enable it here. */
if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
ctrl->server_local->inhibit_data_logging_now = 1;
if (0 && opt.verbose && buffer && size)
{
/* Ease reading of output by limiting the line length. */
size_t n, nbytes;
nbytes = size;
do
{
n = nbytes > 64? 64 : nbytes;
err = assuan_send_data (ctx, buffer, n);
if (err)
{
gpg_err_set_errno (EIO);
goto leave;
}
buffer += n;
nbytes -= n;
if (nbytes && (err=assuan_send_data (ctx, NULL, 0))) /* Flush line. */
{
gpg_err_set_errno (EIO);
goto leave;
}
}
while (nbytes);
}
else
{
err = assuan_send_data (ctx, buffer, size);
if (err)
{
gpg_err_set_errno (EIO); /* For use by data_line_cookie_write. */
goto leave;
}
}
leave:
if (ctrl && ctrl->server_local && ctrl->server_local->inhibit_data_logging)
{
ctrl->server_local->inhibit_data_logging_count += size;
ctrl->server_local->inhibit_data_logging_now = 0;
}
return err;
}
/* 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 && opt.verbose)
{
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;
}
/* Handle 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, "lc-messages"))
{
if (ctrl->lc_messages)
xfree (ctrl->lc_messages);
ctrl->lc_messages = xtrystrdup (value);
if (!ctrl->lc_messages)
return out_of_core ();
}
else
err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
return err;
}
static const char hlp_search[] =
"SEARCH [--no-data] [[--more] PATTERN]\n"
"\n"
"Search for the keys identified by PATTERN. With --more more\n"
"patterns to be used for the search are expected with the next\n"
"command. With --no-data only the search status is returned but\n"
"not the actual data. See also \"NEXT\".";
static gpg_error_t
cmd_search (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int opt_more, opt_no_data;
gpg_error_t err;
unsigned int n, k;
opt_no_data = has_option (line, "--no-data");
opt_more = has_option (line, "--more");
line = skip_options (line);
ctrl->server_local->search_any_found = 0;
if (!*line)
{
if (opt_more)
{
err = set_error (GPG_ERR_INV_ARG, "--more but no pattern");
goto leave;
}
else if (!*line && ctrl->server_local->search_expecting_more)
{
/* It would be too surprising to first set a pattern but
* finally add no pattern to search the entire DB. */
err = set_error (GPG_ERR_INV_ARG, "--more pending but no pattern");
goto leave;
}
else /* No pattern - return the first item. */
{
memset (&ctrl->server_local->search_desc, 0,
sizeof ctrl->server_local->search_desc);
ctrl->server_local->search_desc.mode = KEYDB_SEARCH_MODE_FIRST;
}
}
else
{
err = classify_user_id (line, &ctrl->server_local->search_desc, 0);
if (err)
goto leave;
}
if (opt_more || ctrl->server_local->search_expecting_more)
{
/* More pattern are expected - store the current one and return
* success. */
if (!ctrl->server_local->multi_search_desc_size)
{
n = 10;
ctrl->server_local->multi_search_desc
= xtrycalloc (n, sizeof *ctrl->server_local->multi_search_desc);
if (!ctrl->server_local->multi_search_desc)
{
err = gpg_error_from_syserror ();
goto leave;
}
ctrl->server_local->multi_search_desc_size = n;
}
if (ctrl->server_local->multi_search_desc_len
== ctrl->server_local->multi_search_desc_size)
{
KEYBOX_SEARCH_DESC *desc;
n = ctrl->server_local->multi_search_desc_size + 10;
desc = xtrycalloc (n, sizeof *desc);
if (!desc)
{
err = gpg_error_from_syserror ();
goto leave;
}
for (k=0; k < ctrl->server_local->multi_search_desc_size; k++)
desc[k] = ctrl->server_local->multi_search_desc[k];
xfree (ctrl->server_local->multi_search_desc);
ctrl->server_local->multi_search_desc = desc;
ctrl->server_local->multi_search_desc_size = n;
}
/* Actually store. */
ctrl->server_local->multi_search_desc
[ctrl->server_local->multi_search_desc_len++]
= ctrl->server_local->search_desc;
if (opt_more)
{
/* We need to be called aagain with more pattern. */
ctrl->server_local->search_expecting_more = 1;
goto leave;
}
ctrl->server_local->search_expecting_more = 0;
/* Continue with the actual search. */
}
else
ctrl->server_local->multi_search_desc_len = 0;
ctrl->server_local->inhibit_data_logging = 1;
ctrl->server_local->inhibit_data_logging_now = 0;
ctrl->server_local->inhibit_data_logging_count = 0;
ctrl->no_data_return = opt_no_data;
err = prepare_outstream (ctrl);
if (err)
;
else if (ctrl->server_local->multi_search_desc_len)
err = kbxd_search (ctrl, ctrl->server_local->multi_search_desc,
ctrl->server_local->multi_search_desc_len, 1);
else
err = kbxd_search (ctrl, &ctrl->server_local->search_desc, 1, 1);
if (err)
goto leave;
/* Set a flag for use by NEXT. */
ctrl->server_local->search_any_found = 1;
leave:
if (err)
ctrl->server_local->multi_search_desc_len = 0;
ctrl->no_data_return = 0;
ctrl->server_local->inhibit_data_logging = 0;
return leave_cmd (ctx, err);
}
static const char hlp_next[] =
"NEXT [--no-data]\n"
"\n"
"Get the next search result from a previus search.";
static gpg_error_t
cmd_next (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int opt_no_data;
gpg_error_t err;
opt_no_data = has_option (line, "--no-data");
line = skip_options (line);
if (*line)
{
err = set_error (GPG_ERR_INV_ARG, "no args expected");
goto leave;
}
if (!ctrl->server_local->search_any_found)
{
err = set_error (GPG_ERR_NOTHING_FOUND, "no previous SEARCH");
goto leave;
}
ctrl->server_local->inhibit_data_logging = 1;
ctrl->server_local->inhibit_data_logging_now = 0;
ctrl->server_local->inhibit_data_logging_count = 0;
ctrl->no_data_return = opt_no_data;
err = prepare_outstream (ctrl);
if (err)
;
else if (ctrl->server_local->multi_search_desc_len)
{
/* The next condition should never be tru but we better handle
* the first/next transition anyway. */
if (ctrl->server_local->multi_search_desc[0].mode
== KEYDB_SEARCH_MODE_FIRST)
ctrl->server_local->multi_search_desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
err = kbxd_search (ctrl, ctrl->server_local->multi_search_desc,
ctrl->server_local->multi_search_desc_len, 0);
}
else
{
/* We need to do the transition from first to next here. */
if (ctrl->server_local->search_desc.mode == KEYDB_SEARCH_MODE_FIRST)
ctrl->server_local->search_desc.mode = KEYDB_SEARCH_MODE_NEXT;
err = kbxd_search (ctrl, &ctrl->server_local->search_desc, 1, 0);
}
if (err)
goto leave;
leave:
ctrl->no_data_return = 0;
ctrl->server_local->inhibit_data_logging = 0;
return leave_cmd (ctx, err);
}
static const char hlp_getinfo[] =
"GETINFO <what>\n"
"\n"
"Multi purpose command to return certain information. \n"
"Supported values of WHAT are:\n"
"\n"
"version - Return the version of the program.\n"
"pid - Return the process id of the server.\n"
"socket_name - Return the name of the socket.\n"
"session_id - Return the current session_id.\n"
"getenv NAME - Return value of envvar NAME\n";
static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
char numbuf[50];
if (!strcmp (line, "version"))
{
const char *s = VERSION;
err = assuan_send_data (ctx, s, strlen (s));
}
else if (!strcmp (line, "pid"))
{
snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
err = assuan_send_data (ctx, numbuf, strlen (numbuf));
}
else if (!strcmp (line, "socket_name"))
{
const char *s = get_kbxd_socket_name ();
if (!s)
s = "[none]";
err = assuan_send_data (ctx, s, strlen (s));
}
else if (!strcmp (line, "session_id"))
{
snprintf (numbuf, sizeof numbuf, "%u", ctrl->server_local->session_id);
err = assuan_send_data (ctx, numbuf, strlen (numbuf));
}
else if (!strncmp (line, "getenv", 6)
&& (line[6] == ' ' || line[6] == '\t' || !line[6]))
{
line += 6;
while (*line == ' ' || *line == '\t')
line++;
if (!*line)
err = gpg_error (GPG_ERR_MISSING_VALUE);
else
{
const char *s = getenv (line);
if (!s)
err = set_error (GPG_ERR_NOT_FOUND, "No such envvar");
else
err = assuan_send_data (ctx, s, strlen (s));
}
}
else
err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
return leave_cmd (ctx, err);
}
static const char hlp_killkeyboxd[] =
"KILLKEYBOXD\n"
"\n"
"This command allows a user - given sufficient permissions -\n"
"to kill this keyboxd process.\n";
static gpg_error_t
cmd_killkeyboxd (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
(void)line;
ctrl->server_local->stopme = 1;
assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
return gpg_error (GPG_ERR_EOF);
}
static const char hlp_reloadkeyboxd[] =
"RELOADKEYBOXD\n"
"\n"
"This command is an alternative to SIGHUP\n"
"to reload the configuration.";
static gpg_error_t
cmd_reloadkeyboxd (assuan_context_t ctx, char *line)
{
(void)ctx;
(void)line;
kbxd_sighup_action ();
return 0;
}
static const char hlp_output[] =
"OUTPUT FD[=<n>]\n"
"\n"
"Set the file descriptor to write the output data to N. If N is not\n"
"given and the operating system supports file descriptor passing, the\n"
"file descriptor currently in flight will be used.";
/* Tell the assuan library about our commands. */
static int
register_commands (assuan_context_t ctx)
{
static struct {
const char *name;
assuan_handler_t handler;
const char * const help;
} table[] = {
{ "SEARCH", cmd_search, hlp_search },
{ "NEXT", cmd_next, hlp_next },
{ "GETINFO", cmd_getinfo, hlp_getinfo },
{ "OUTPUT", NULL, hlp_output },
{ "KILLKEYBOXD",cmd_killkeyboxd,hlp_killkeyboxd },
{ "RELOADKEYBOXD",cmd_reloadkeyboxd,hlp_reloadkeyboxd },
{ NULL, NULL }
};
int i, j, rc;
for (i=j=0; table[i].name; i++)
{
rc = assuan_register_command (ctx, table[i].name, table[i].handler,
table[i].help);
if (rc)
return rc;
}
return 0;
}
/* Note that we do not reset the list of configured keyservers. */
static gpg_error_t
reset_notify (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
(void)line;
(void)ctrl;
return 0;
}
/* This function is called by our assuan log handler to test whether a
* log message shall really be printed. The function must return
* false to inhibit the logging of MSG. CAT gives the requested log
* category. MSG might be NULL. */
int
kbxd_assuan_log_monitor (assuan_context_t ctx, unsigned int cat,
const char *msg)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
(void)cat;
(void)msg;
if (!ctrl || !ctrl->server_local)
return 1; /* Can't decide - allow logging. */
if (!ctrl->server_local->inhibit_data_logging)
return 1; /* Not requested - allow logging. */
/* Disallow logging if *_now is true. */
return !ctrl->server_local->inhibit_data_logging_now;
}
/* Startup the server and run the main command loop. With FD = -1,
* use stdin/stdout. SESSION_ID is either 0 or a unique number
* identifying a session. */
void
kbxd_start_command_handler (ctrl_t ctrl, gnupg_fd_t fd, unsigned int session_id)
{
static const char hello[] = "Keyboxd " VERSION " at your service";
static char *hello_line;
int rc;
assuan_context_t ctx;
ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
if (!ctrl->server_local)
{
log_error (_("can't allocate control structure: %s\n"),
gpg_strerror (gpg_error_from_syserror ()));
xfree (ctrl);
return;
}
rc = assuan_new (&ctx);
if (rc)
{
log_error (_("failed to allocate assuan context: %s\n"),
gpg_strerror (rc));
kbxd_exit (2);
}
if (fd == GNUPG_INVALID_FD)
{
assuan_fd_t filedes[2];
filedes[0] = assuan_fdopen (0);
filedes[1] = assuan_fdopen (1);
rc = assuan_init_pipe_server (ctx, filedes);
}
else
{
rc = assuan_init_socket_server (ctx, fd,
(ASSUAN_SOCKET_SERVER_ACCEPTED
|ASSUAN_SOCKET_SERVER_FDPASSING));
}
if (rc)
{
assuan_release (ctx);
log_error (_("failed to initialize the server: %s\n"),
gpg_strerror (rc));
kbxd_exit (2);
}
rc = register_commands (ctx);
if (rc)
{
log_error (_("failed to the register commands with Assuan: %s\n"),
gpg_strerror(rc));
kbxd_exit (2);
}
if (!hello_line)
{
hello_line = xtryasprintf
("Home: %s\n"
"Config: %s\n"
"%s",
gnupg_homedir (),
/*opt.config_filename? opt.config_filename :*/ "[none]",
hello);
}
ctrl->server_local->assuan_ctx = ctx;
assuan_set_pointer (ctx, ctrl);
assuan_set_hello_line (ctx, hello_line);
assuan_register_option_handler (ctx, option_handler);
assuan_register_reset_notify (ctx, reset_notify);
ctrl->server_local->session_id = session_id;
/* The next call enable the use of status_printf. */
set_assuan_context_func (get_assuan_ctx_from_ctrl);
for (;;)
{
rc = assuan_accept (ctx);
if (rc == -1)
break;
if (rc)
{
log_info (_("Assuan accept problem: %s\n"), gpg_strerror (rc));
break;
}
#ifndef HAVE_W32_SYSTEM
if (opt.verbose)
{
assuan_peercred_t peercred;
if (!assuan_get_peercred (ctx, &peercred))
log_info ("connection from process %ld (%ld:%ld)\n",
(long)peercred->pid, (long)peercred->uid,
(long)peercred->gid);
}
#endif
rc = assuan_process (ctx);
if (rc)
{
log_info (_("Assuan processing failed: %s\n"), gpg_strerror (rc));
continue;
}
}
assuan_close_output_fd (ctx);
set_assuan_context_func (NULL);
ctrl->server_local->assuan_ctx = NULL;
assuan_release (ctx);
if (ctrl->server_local->stopme)
kbxd_exit (0);
if (ctrl->refcount)
log_error ("oops: connection control structure still referenced (%d)\n",
ctrl->refcount);
else
{
xfree (ctrl->server_local->multi_search_desc);
xfree (ctrl->server_local);
ctrl->server_local = NULL;
}
}

View File

@ -67,6 +67,7 @@
- u16 Blob flags
bit 0 = contains secret key material (not used)
bit 1 = ephemeral blob (e.g. used while querying external resources)
bit 2 = blob has an UBID field.
- u32 Offset to the OpenPGP keyblock or the X.509 DER encoded
certificate
- u32 The length of the keyblock or certificate
@ -143,7 +144,10 @@
IDs go here.
- bN Space for the keyblock or certificate.
- bN RFU. This is the remaining space after keyblock and before
the checksum. It is not covered by the checksum.
the checksum. Not part of the SHA-1 checksum.
- bN Only if blob flags bit 2 is set: 20 octet Unique Blob-ID (UBID).
This is the SHA-1 checksum of the keyblock or certificate.
This is not part of the SHA-1 checksum below.
- b20 SHA-1 checksum (useful for KS synchronization?)
Note, that KBX versions before GnuPG 2.1 used an MD5
checksum. However it was only created but never checked.
@ -173,6 +177,10 @@
#include "../common/gettime.h"
#include "../common/host2net.h"
#define get32(a) buf32_to_ulong ((a))
/* special values of the signature status */
@ -559,7 +567,7 @@ create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral,
put32 ( a, 0 ); /* blob length, needs fixup */
put8 ( a, blobtype);
put8 ( a, want_fpr32? 2:1 ); /* blob type version */
put16 ( a, as_ephemeral? 2:0 ); /* blob flags */
put16 ( a, as_ephemeral? 6:4 ); /* blob flags */
put32 ( a, 0 ); /* offset to the raw data, needs fixup */
put32 ( a, 0 ); /* length of the raw data, needs fixup */
@ -686,8 +694,8 @@ create_blob_finish (KEYBOXBLOB blob)
unsigned char *pp;
size_t n;
/* Write a placeholder for the checksum */
put_membuf (a, NULL, 20);
/* Write placeholders for the UBID and the checksum */
put_membuf (a, NULL, 40);
/* get the memory area */
n = 0; /* (Just to avoid compiler warning.) */
@ -721,8 +729,11 @@ create_blob_finish (KEYBOXBLOB blob)
blob->fixups = NULL;
}
/* Compute and store the UBID. (image_off) (image_len) */
gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 40, p + get32 (p+8), get32 (p+12));
/* Compute and store the SHA-1 checksum. */
gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 20, p, n - 20);
gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 20, p, n - 40);
pp = xtrymalloc (n);
if ( !pp )

View File

@ -63,6 +63,41 @@ print_string (FILE *fp, const byte *p, size_t n, int delim)
}
static void
print_ubib (const byte *buffer, size_t length, FILE *fp)
{
const byte *p;
int i;
size_t image_off, image_len;
unsigned char digest[20];
fprintf (fp, "UBIB: ");
if (length < 40)
{
fputs ("[blob too short for a stored UBIB]\n", fp);
return;
}
p = buffer + length - 40;
for (i=0; i < 20; p++, i++)
fprintf (fp, "%02X", *p);
image_off = get32 (buffer+8);
image_len = get32 (buffer+12);
if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
{
fputs (" [image claims to be longer than the blob]\n", fp);
return;
}
gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer+image_off,image_len);
if (memcmp (digest, buffer + length - 40, 20))
fputs (" [does not match the image]\n", fp);
else
fputc ('\n', fp);
}
static int
print_checksum (const byte *buffer, size_t length, size_t unhashed, FILE *fp)
{
@ -171,6 +206,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
ulong unhashed;
const byte *p;
int is_fpr32; /* blob ersion 2 */
int have_ubib = 0;
buffer = _keybox_get_blob_image (blob, &length);
@ -237,6 +273,14 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
fputs ("ephemeral", fp);
any++;
}
if ((n & 4))
{
if (any)
putc (',', fp);
fputs ("ubid", fp);
any++;
have_ubib = 1;
}
putc (')', fp);
}
putc ('\n', fp);
@ -422,6 +466,8 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
n = get32 ( buffer + length - unhashed);
fprintf (fp, "Storage-Flags: %08lx\n", n );
}
if (have_ubib)
print_ubib (buffer, length, fp);
print_checksum (buffer, length, unhashed, fp);
return 0;
}

View File

@ -146,9 +146,9 @@ _keybox_write_blob (KEYBOXBLOB blob, FILE *fp)
}
/* Write a fresh header type blob. */
int
_keybox_write_header_blob (FILE *fp, int for_openpgp)
/* Write a fresh header type blob. Either FP or STREAM must be used. */
gpg_error_t
_keybox_write_header_blob (FILE *fp, estream_t stream, int for_openpgp)
{
unsigned char image[32];
u32 val;
@ -174,7 +174,15 @@ _keybox_write_header_blob (FILE *fp, int for_openpgp)
image[20+2] = (val >> 8);
image[20+3] = (val );
if (fwrite (image, 32, 1, fp) != 1)
return gpg_error_from_syserror ();
if (fp)
{
if (fwrite (image, 32, 1, fp) != 1)
return gpg_error_from_syserror ();
}
else
{
if (es_fwrite (image, 32, 1, stream) != 1)
return gpg_error_from_syserror ();
}
return 0;
}

View File

@ -42,11 +42,21 @@ typedef enum {
KEYDB_SEARCH_MODE_SN,
KEYDB_SEARCH_MODE_SUBJECT,
KEYDB_SEARCH_MODE_KEYGRIP,
KEYDB_SEARCH_MODE_UBID,
KEYDB_SEARCH_MODE_FIRST,
KEYDB_SEARCH_MODE_NEXT
} KeydbSearchMode;
/* Identifiers for the public key types we use in GnuPG. */
enum pubkey_types
{
PUBKEY_TYPE_UNKNOWN = 0,
PUBKEY_TYPE_OPGP = 1,
PUBKEY_TYPE_X509 = 2
};
/* Forward declaration. See g10/packet.h. */
struct gpg_pkt_user_id_s;
typedef struct gpg_pkt_user_id_s *gpg_pkt_user_id_t;
@ -70,6 +80,7 @@ struct keydb_search_desc
unsigned char fpr[32];
u32 kid[2]; /* Note that this is in native endianness. */
unsigned char grip[20];
unsigned char ubid[20];
} u;
byte fprlen; /* Only used with KEYDB_SEARCH_MODE_FPR. */
int exact; /* Use exactly this key ('!' suffix in gpg). */

View File

@ -696,6 +696,35 @@ has_keygrip (KEYBOXBLOB blob, const unsigned char *grip)
return 0;
}
static inline int
has_ubid (KEYBOXBLOB blob, const unsigned char *ubid)
{
size_t length;
const unsigned char *buffer;
size_t image_off, image_len;
unsigned char ubid_blob[20];
buffer = _keybox_get_blob_image (blob, &length);
if (length < 40)
return 0; /*GPG_ERR_TOO_SHORT*/
if ((get16 (buffer + 6) & 4))
{
/* The blob has a stored UBID. */
return !memcmp (ubid, buffer + length - 40, 20);
}
else
{
/* Need to compute the UBID. */
image_off = get32 (buffer+8);
image_len = get32 (buffer+12);
if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
return 0; /*GPG_ERR_TOO_SHORT*/
gcry_md_hash_buffer (GCRY_MD_SHA1, ubid_blob, buffer+image_off,image_len);
return !memcmp (ubid, ubid_blob, 20);
}
}
static inline int
has_issuer (KEYBOXBLOB blob, const char *name)
@ -1119,6 +1148,10 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
if (has_keygrip (blob, desc[n].u.grip))
goto found;
break;
case KEYDB_SEARCH_MODE_UBID:
if (has_ubid (blob, desc[n].u.ubid))
goto found;
break;
case KEYDB_SEARCH_MODE_FIRST:
goto found;
break;
@ -1180,11 +1213,70 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
a successful search operation.
*/
/* Return the raw data from the last found blob. Caller must release
* the value stored at R_BUFFER. If called with NULL for R_BUFFER
* only the needed length for the buffer and the public key type is
* returned. */
gpg_error_t
keybox_get_data (KEYBOX_HANDLE hd, void **r_buffer, size_t *r_length,
enum pubkey_types *r_pubkey_type)
{
const unsigned char *buffer;
size_t length;
size_t image_off, image_len;
if (r_buffer)
*r_buffer = NULL;
if (r_length)
*r_length = 0;
if (r_pubkey_type)
*r_pubkey_type = PUBKEY_TYPE_UNKNOWN;
if (!hd)
return gpg_error (GPG_ERR_INV_VALUE);
if (!hd->found.blob)
return gpg_error (GPG_ERR_NOTHING_FOUND);
switch (blob_get_type (hd->found.blob))
{
case KEYBOX_BLOBTYPE_PGP:
if (r_pubkey_type)
*r_pubkey_type = PUBKEY_TYPE_OPGP;
break;
case KEYBOX_BLOBTYPE_X509:
if (r_pubkey_type)
*r_pubkey_type = PUBKEY_TYPE_X509;
break;
default:
return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
}
buffer = _keybox_get_blob_image (hd->found.blob, &length);
if (length < 40)
return gpg_error (GPG_ERR_TOO_SHORT);
image_off = get32 (buffer+8);
image_len = get32 (buffer+12);
if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
return gpg_error (GPG_ERR_TOO_SHORT);
if (r_length)
*r_length = image_len;
if (r_buffer)
{
*r_buffer = xtrymalloc (image_len);
if (!*r_buffer)
return gpg_error_from_syserror ();
memcpy (*r_buffer, buffer + image_off, image_len);
}
return 0;
}
/* Return the last found keyblock. Returns 0 on success and stores a
* new iobuf at R_IOBUF. R_UID_NO and R_PK_NO are used to return the
* number of the key or user id which was matched the search criteria;
* if not known they are set to 0. */
* index of the key or user id which matched the search criteria; if
* not known they are set to 0. */
gpg_error_t
keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
int *r_pk_no, int *r_uid_no)

View File

@ -182,7 +182,7 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
if (!newfp )
return gpg_error_from_syserror ();
rc = _keybox_write_header_blob (newfp, for_openpgp);
rc = _keybox_write_header_blob (newfp, NULL, for_openpgp);
if (rc)
{
fclose (newfp);
@ -730,7 +730,7 @@ keybox_compress (KEYBOX_HANDLE hd)
}
/* The header blob is missing. Insert it. */
rc = _keybox_write_header_blob (newfp, hd->for_openpgp);
rc = _keybox_write_header_blob (newfp, NULL, hd->for_openpgp);
if (rc)
break;
any_changes = 1;

View File

@ -81,9 +81,13 @@ gpg_error_t keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout);
/*-- keybox-file.c --*/
/* Fixme: This function does not belong here: Provide a better
interface to create a new keybox file. */
int _keybox_write_header_blob (FILE *fp, int openpgp_flag);
gpg_error_t _keybox_write_header_blob (FILE *fp, estream_t stream,
int openpgp_flag);
/*-- keybox-search.c --*/
gpg_error_t keybox_get_data (KEYBOX_HANDLE hd,
void **r_buffer, size_t *r_length,
enum pubkey_types *r_pubkey_type);
gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
int *r_uid_no, int *r_pk_no);
#ifdef KEYBOX_WITH_X509

50
kbx/keyboxd-w32info.rc Normal file
View File

@ -0,0 +1,50 @@
/* keyboxd-w32info.rc -*- c -*-
* Copyright (C) 2018 g10 Code GmbH
*
* This file is free software; as a special exception the author gives
* unlimited permission to copy and/or distribute it, with or without
* modifications, as long as this notice is preserved.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "afxres.h"
#include "../common/w32info-rc.h"
1 ICON "../common/gnupg.ico"
1 VERSIONINFO
FILEVERSION W32INFO_VI_FILEVERSION
PRODUCTVERSION W32INFO_VI_PRODUCTVERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/
#else
FILEFLAGS 0x00L
#endif
FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */
FILETYPE 0x1L /* VFT_APP (0x1) */
FILESUBTYPE 0x0L /* VFT2_UNKNOWN */
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" /* US English (0409), Unicode (04b0) */
BEGIN
VALUE "FileDescription", L"GnuPG\x2019s public key daemon\0"
VALUE "InternalName", "keyboxd\0"
VALUE "OriginalFilename", "keyboxd.exe\0"
VALUE "ProductName", W32INFO_PRODUCTNAME
VALUE "ProductVersion", W32INFO_PRODUCTVERSION
VALUE "CompanyName", W32INFO_COMPANYNAME
VALUE "FileVersion", W32INFO_FILEVERSION
VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT
VALUE "Comments", W32INFO_COMMENTS
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END

1845
kbx/keyboxd.c Normal file

File diff suppressed because it is too large Load Diff

156
kbx/keyboxd.h Normal file
View File

@ -0,0 +1,156 @@
/* keyboxd.h - Global definitions for keyboxd
* Copyright (C) 2018 Werner Koch
*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef KEYBOXD_H
#define KEYBOXD_H
#ifdef GPG_ERR_SOURCE_DEFAULT
#error GPG_ERR_SOURCE_DEFAULT already defined
#endif
#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_KEYBOX
#include <gpg-error.h>
#include <gcrypt.h>
#include "../common/util.h"
#include "../common/membuf.h"
#include "../common/sysutils.h" /* (gnupg_fd_t) */
/* A large struct name "opt" to keep global flags */
struct
{
unsigned int debug; /* Debug flags (DBG_foo_VALUE) */
int verbose; /* Verbosity level */
int quiet; /* Be as quiet as possible */
int dry_run; /* Don't change any persistent data */
int batch; /* Batch mode */
/* True if we are running detached from the tty. */
int running_detached;
} opt;
/* Bit values for the --debug option. */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
#define DBG_IPC_VALUE 1024 /* Enable Assuan debugging. */
#define DBG_CLOCK_VALUE 4096 /* debug timings (required build option). */
#define DBG_LOOKUP_VALUE 8192 /* debug the key lookup */
/* Test macros for the debug option. */
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
#define DBG_CLOCK (opt.debug & DBG_CLOCK_VALUE)
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
/* Declaration of a database request object. This is used for all
* database operation (search, insert, update, delete). */
struct db_request_s;
typedef struct db_request_s *db_request_t;
/* Forward reference for local definitions in command.c. */
struct server_local_s;
#if SIZEOF_UNSIGNED_LONG == 8
# define SERVER_CONTROL_MAGIC 0x6b6579626f786420
#else
# define SERVER_CONTROL_MAGIC 0x6b627864
#endif
/* Collection of data per session (aka connection). */
struct server_control_s
{
unsigned long magic;/* Always has SERVER_CONTROL_MAGIC. */
int refcount; /* Count additional references to this object. */
/* Private data used to fire up the connection thread. We use this
* structure do avoid an extra allocation for only a few bytes while
* spawning a new connection thread. */
struct {
gnupg_fd_t fd;
} thread_startup;
/* Private data of the server (kbxserver.c). */
struct server_local_s *server_local;
/* Environment settings for the connection. */
char *lc_messages;
/* Miscellaneous info on the connection. */
unsigned long client_pid;
int client_uid;
/* Two database request objects used with a connection. They are
* auto-created as needed. */
db_request_t opgp_req;
db_request_t x509_req;
/* Flags for the current request. */
unsigned int no_data_return : 1; /* Used by SEARCH and NEXT. */
};
/* This is a special version of the usual _() gettext macro. It
* assumes a server connection control variable with the name "ctrl"
* and uses that to translate a string according to the locale set for
* the connection. The macro LunderscoreIMPL is used by i18n to
* actually define the inline function when needed. */
#if defined (ENABLE_NLS) || defined (USE_SIMPLE_GETTEXT)
#define L_(a) keyboxd_Lunderscore (ctrl, (a))
#define LunderscorePROTO \
static inline const char *keyboxd_Lunderscore (ctrl_t ctrl, \
const char *string) \
GNUPG_GCC_ATTR_FORMAT_ARG(2);
#define LunderscoreIMPL \
static inline const char * \
keyboxd_Lunderscore (ctrl_t ctrl, const char *string) \
{ \
return ctrl? i18n_localegettext (ctrl->lc_messages, string) \
/* */: gettext (string); \
}
#else
#define L_(a) (a)
#endif
/*-- keyboxd.c --*/
void kbxd_exit (int rc) GPGRT_ATTR_NORETURN;
void kbxd_set_progress_cb (void (*cb)(ctrl_t ctrl, const char *what,
int printchar, int current, int total),
ctrl_t ctrl);
const char *get_kbxd_socket_name (void);
int get_kbxd_active_connection_count (void);
void kbxd_sighup_action (void);
/*-- kbxserver.c --*/
gpg_error_t kbxd_write_data_line (ctrl_t ctrl,
const void *buffer_arg, size_t size);
void kbxd_start_command_handler (ctrl_t, gnupg_fd_t, unsigned int);
#endif /*KEYBOXD_H*/

View File

@ -53,6 +53,7 @@ XGETTEXT_OPTIONS = \
--flag=xasprintf:1:c-format \
--flag=xtryasprintf:1:c-format \
--flag=log_debug_with_string:2:c-format \
--flag=status_printf:3:c-format \
--flag=print_assuan_status:3:c-format \
--flag=vprint_assuan_status:3:c-format \
--flag=agent_print_status:3:c-format \

View File

@ -224,7 +224,7 @@ maybe_create_keybox (char *filename, int force, int *r_created)
/* Make sure that at least one record is in a new keybox file, so
that the detection magic for OpenPGP keyboxes works the next time
it is used. */
rc = _keybox_write_header_blob (fp, 0);
rc = _keybox_write_header_blob (fp, NULL, 0);
if (rc)
{
fclose (fp);

View File

@ -60,12 +60,14 @@ enum cmd_and_opt_values
oHomedir,
oAgentProgram,
oDirmngrProgram,
oKeyboxdProgram,
oHex,
oDecode,
oNoExtConnect,
oDirmngr,
oKeyboxd,
oUIServer,
oNoAutostart,
oNoAutostart
};
@ -79,6 +81,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oHex, "hex", N_("print data out hex encoded")),
ARGPARSE_s_n (oDecode,"decode", N_("decode received data lines")),
ARGPARSE_s_n (oDirmngr,"dirmngr", N_("connect to the dirmngr")),
ARGPARSE_s_n (oKeyboxd,"keyboxd", N_("connect to the keyboxd")),
ARGPARSE_s_n (oUIServer, "uiserver", "@"),
ARGPARSE_s_s (oRawSocket, "raw-socket",
N_("|NAME|connect to Assuan socket NAME")),
@ -97,6 +100,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oHomedir, "homedir", "@" ),
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
ARGPARSE_s_s (oKeyboxdProgram, "keyboxd-program", "@"),
ARGPARSE_end ()
};
@ -109,11 +113,13 @@ struct
int quiet; /* Be extra quiet. */
int autostart; /* Start the server if not running. */
const char *homedir; /* Configuration directory name */
const char *agent_program; /* Value of --agent-program. */
const char *agent_program; /* Value of --agent-program. */
const char *dirmngr_program; /* Value of --dirmngr-program. */
const char *keyboxd_program; /* Value of --keyboxd-program. */
int hex; /* Print data lines in hex format. */
int decode; /* Decode received data lines. */
int use_dirmngr; /* Use the dirmngr and not gpg-agent. */
int use_keyboxd; /* Use the keyboxd and not gpg-agent. */
int use_uiserver; /* Use the standard UI server. */
const char *raw_socket; /* Name of socket to connect in raw mode. */
const char *tcp_socket; /* Name of server to connect in tcp mode. */
@ -1200,10 +1206,12 @@ main (int argc, char **argv)
case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
case oKeyboxdProgram: opt.keyboxd_program = pargs.r.ret_str; break;
case oNoAutostart: opt.autostart = 0; break;
case oHex: opt.hex = 1; break;
case oDecode: opt.decode = 1; break;
case oDirmngr: opt.use_dirmngr = 1; break;
case oKeyboxd: opt.use_keyboxd = 1; break;
case oUIServer: opt.use_uiserver = 1; break;
case oRawSocket: opt.raw_socket = pargs.r.ret_str; break;
case oTcpSocket: opt.tcp_socket = pargs.r.ret_str; break;
@ -1879,7 +1887,10 @@ main (int argc, char **argv)
}
if (opt.verbose)
log_info ("closing connection to agent\n");
log_info ("closing connection to %s\n",
opt.use_dirmngr? "dirmngr" :
opt.use_keyboxd? "keyboxd" :
"agent");
/* XXX: We would like to release the context here, but libassuan
nicely says good bye to the server, which results in a SIGPIPE if
@ -2224,6 +2235,13 @@ start_agent (void)
opt.autostart,
!opt.quiet, 0,
NULL, NULL);
else if (opt.use_keyboxd)
err = start_new_keyboxd (&ctx,
GPG_ERR_SOURCE_DEFAULT,
opt.keyboxd_program,
opt.autostart,
!opt.quiet, 0,
NULL, NULL);
else
err = start_new_gpg_agent (&ctx,
GPG_ERR_SOURCE_DEFAULT,
@ -2239,12 +2257,15 @@ start_agent (void)
{
if (!opt.autostart
&& (gpg_err_code (err)
== (opt.use_dirmngr? GPG_ERR_NO_DIRMNGR : GPG_ERR_NO_AGENT)))
== (opt.use_dirmngr? GPG_ERR_NO_DIRMNGR :
opt.use_keyboxd? GPG_ERR_NO_KEYBOXD : GPG_ERR_NO_AGENT)))
{
/* In the no-autostart case we don't make gpg-connect-agent
fail on a missing server. */
log_info (opt.use_dirmngr?
_("no dirmngr running in this session\n"):
opt.use_keyboxd?
_("no keybox daemon running in this session\n"):
_("no gpg-agent running in this session\n"));
exit (0);
}