1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-20 01:02:44 +02:00

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. */ operation after we started them before giving up. */
#ifdef HAVE_W32CE_SYSTEM #ifdef HAVE_W32CE_SYSTEM
# define SECS_TO_WAIT_FOR_AGENT 30 # define SECS_TO_WAIT_FOR_AGENT 30
# define SECS_TO_WAIT_FOR_KEYBOXD 30
# define SECS_TO_WAIT_FOR_DIRMNGR 30 # define SECS_TO_WAIT_FOR_DIRMNGR 30
#else #else
# define SECS_TO_WAIT_FOR_AGENT 5 # define SECS_TO_WAIT_FOR_AGENT 5
# define SECS_TO_WAIT_FOR_KEYBOXD 5
# define SECS_TO_WAIT_FOR_DIRMNGR 5 # define SECS_TO_WAIT_FOR_DIRMNGR 5
#endif #endif
@ -308,17 +310,15 @@ unlock_spawning (lock_spawn_t *lock, const char *name)
} }
/* Helper for start_new_gpg_agent and start_new_dirmngr. /* Helper to start a service. SECS gives the number of seconds to
* Values for WHICH are: * wait. SOCKNAME is the name of the socket to connect. VERBOSE is
* 0 - Start gpg-agent * the usual verbose flag. CTX is the assuan context. CONNECT_FLAGS
* 1 - Start dirmngr * are the assuan connect flags. DID_SUCCESS_MSG will be set to 1 if
* SECS give the number of seconds to wait. SOCKNAME is the name of * a success messages has been printed.
* 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.
*/ */
static gpg_error_t 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) int verbose, assuan_context_t ctx, int *did_success_msg)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
@ -343,8 +343,10 @@ wait_for_sock (int secs, int which, const char *sockname,
/* next_sleep_us); */ /* next_sleep_us); */
if (secsleft < lastalert) 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"): _("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"), _("waiting for the agent to come up ... (%ds)\n"),
secsleft); secsleft);
lastalert = secsleft; lastalert = secsleft;
@ -352,13 +354,15 @@ wait_for_sock (int secs, int which, const char *sockname,
} }
gnupg_usleep (next_sleep_us); gnupg_usleep (next_sleep_us);
elapsed_us += 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 (!err)
{ {
if (verbose) if (verbose)
{ {
log_info (which == 1? log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR?
_("connection to the dirmngr established\n"): _("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")); _("connection to the agent established\n"));
*did_success_msg = 1; *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 /* 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 * running and AUTOSTART is set. Handle the server's initial
greeting. Returns a new assuan context at R_CTX or an error * greeting. Returns a new assuan context at R_CTX or an error code.
code. */ * MODULE_NAME_ID is one of:
gpg_error_t * GNUPG_MODULE_NAME_AGENT
start_new_gpg_agent (assuan_context_t *r_ctx, * GNUPG_MODULE_NAME_DIRMNGR
gpg_err_source_t errsource, */
const char *agent_program, static gpg_error_t
const char *opt_lc_ctype, start_new_service (assuan_context_t *r_ctx,
const char *opt_lc_messages, int module_name_id,
session_env_t session_env, gpg_err_source_t errsource,
int autostart, int verbose, int debug, const char *program_name,
gpg_error_t (*status_cb)(ctrl_t, int, ...), const char *opt_lc_ctype,
ctrl_t status_cb_arg) 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; gpg_error_t err;
assuan_context_t ctx; assuan_context_t ctx;
int did_success_msg = 0; int did_success_msg = 0;
char *sockname; 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]; const char *argv[6];
*r_ctx = NULL; *r_ctx = NULL;
@ -402,15 +416,40 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
return err; return err;
} }
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL); switch (module_name_id)
if (!sockname)
{ {
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); assuan_release (ctx);
return err; return err;
} }
err = assuan_socket_connect (ctx, sockname, 0, 0); err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
if (err && autostart) if (err && autostart)
{ {
char *abs_homedir; char *abs_homedir;
@ -422,12 +461,12 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
int i; int i;
/* With no success start a new server. */ /* With no success start a new server. */
if (!agent_program || !*agent_program) if (!program_name || !*program_name)
agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT); program_name = gnupg_module_name (module_name_id);
else if ((s=strchr (agent_program, '|')) && s[1] == '-' && s[2]=='-') else if ((s=strchr (program_name, '|')) && s[1] == '-' && s[2]=='-')
{ {
/* Hack to insert an additional option on the command line. */ /* Hack to insert an additional option on the command line. */
program = xtrystrdup (agent_program); program = xtrystrdup (program_name);
if (!program) if (!program)
{ {
gpg_error_t tmperr = gpg_err_make (errsource, gpg_error_t tmperr = gpg_err_make (errsource,
@ -442,22 +481,21 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
} }
if (verbose) if (verbose)
log_info (_("no running gpg-agent - starting '%s'\n"), log_info (_("no running %s - starting '%s'\n"),
agent_program); printed_name, program_name);
if (status_cb) if (status_cb)
status_cb (status_cb_arg, STATUS_PROGRESS, status_cb (status_cb_arg, STATUS_PROGRESS, status_start_line, NULL);
"starting_agent ? 0 0", NULL);
/* We better pass an absolute home directory to the agent just /* We better pass an absolute home directory to the service just
in case gpg-agent does not convert the passed name to an * in case the service does not convert the passed name to an
absolute one (which it should do). */ * absolute one (which it should do). */
abs_homedir = make_absfilename_try (gnupg_homedir (), NULL); abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
if (!abs_homedir) if (!abs_homedir)
{ {
gpg_error_t tmperr = gpg_err_make (errsource, gpg_error_t tmperr = gpg_err_make (errsource,
gpg_err_code_from_syserror ()); 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); xfree (sockname);
assuan_release (ctx); assuan_release (ctx);
xfree (program); xfree (program);
@ -468,8 +506,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
{ {
gpg_error_t tmperr = gpg_err_make (errsource, gpg_error_t tmperr = gpg_err_make (errsource,
gpg_err_code_from_syserror ()); gpg_err_code_from_syserror ());
log_error ("error flushing pending output: %s\n", log_error ("error flushing pending output: %s\n", strerror (errno));
strerror (errno));
xfree (sockname); xfree (sockname);
assuan_release (ctx); assuan_release (ctx);
xfree (abs_homedir); xfree (abs_homedir);
@ -477,42 +514,42 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
return tmperr; 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; i = 0;
argv[i++] = "--homedir"; argv[i++] = "--homedir";
argv[i++] = abs_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) if (program_arg)
argv[i++] = program_arg; argv[i++] = program_arg;
argv[i++] = "--daemon"; argv[i++] = "--daemon";
argv[i++] = NULL; argv[i++] = NULL;
if (!(err = lock_spawning (&lock, gnupg_homedir (), "agent", verbose)) if (!(err = lock_spawning (&lock, gnupg_homedir (), lock_name, verbose))
&& assuan_socket_connect (ctx, sockname, 0, 0)) && assuan_socket_connect (ctx, sockname, 0, connect_flags))
{ {
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
err = gnupg_spawn_process_detached (program? program : agent_program, err = gnupg_spawn_process_detached (program? program : program_name,
argv, NULL); argv, NULL);
#else #else /*!W32*/
pid_t pid; 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); argv, -1, -1, -1, &pid);
if (!err) if (!err)
err = gnupg_wait_process (program? program : agent_program, err = gnupg_wait_process (program? program : program_name,
pid, 1, NULL); pid, 1, NULL);
#endif #endif /*!W32*/
if (err) if (err)
log_error ("failed to start agent '%s': %s\n", log_error ("failed to start %s '%s': %s\n",
agent_program, gpg_strerror (err)); printed_name, program? program : program_name,
gpg_strerror (err));
else else
err = wait_for_sock (SECS_TO_WAIT_FOR_AGENT, 0, err = wait_for_sock (seconds_to_wait, module_name_id,
sockname, verbose, ctx, &did_success_msg); sockname, connect_flags,
verbose, ctx, &did_success_msg);
} }
unlock_spawning (&lock, "agent"); unlock_spawning (&lock, lock_name);
xfree (abs_homedir); xfree (abs_homedir);
xfree (program); xfree (program);
} }
@ -520,17 +557,21 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
if (err) if (err)
{ {
if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED) 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); 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) 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", if (module_name_id == GNUPG_MODULE_NAME_AGENT)
NULL, NULL, NULL, NULL, NULL, NULL); err = assuan_transact (ctx, "RESET",
if (!err) NULL, NULL, NULL, NULL, NULL, NULL);
if (!err
&& module_name_id == GNUPG_MODULE_NAME_AGENT)
{ {
err = send_pinentry_environment (ctx, errsource, err = send_pinentry_environment (ctx, errsource,
opt_lc_ctype, opt_lc_messages, 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 if (gpg_err_code (err) == GPG_ERR_FORBIDDEN
&& gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT) && 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", if (!assuan_transact (ctx, "GETINFO restricted",
NULL, NULL, NULL, NULL, NULL, NULL)) 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 /* Try to connect to the dirmngr via a socket. On platforms
supporting it, start it up if needed and if AUTOSTART is true. supporting it, start it up if needed and if AUTOSTART is true.
Returns a new assuan context at R_CTX or an error code. */ 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, start_new_dirmngr (assuan_context_t *r_ctx,
gpg_err_source_t errsource, gpg_err_source_t errsource,
const char *dirmngr_program, const char *dirmngr_program,
int autostart, int autostart, int verbose, int debug,
int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...), gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg) ctrl_t status_cb_arg)
{ {
gpg_error_t err; #ifndef USE_DIRMNGR_AUTO_START
assuan_context_t ctx; autostart = 0;
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);
#endif #endif
if (err) return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
log_error ("failed to start the dirmngr '%s': %s\n", errsource, dirmngr_program,
dirmngr_program, gpg_strerror (err)); NULL, NULL, NULL,
else autostart, verbose, debug,
err = wait_for_sock (SECS_TO_WAIT_FOR_DIRMNGR, 1, status_cb, status_cb_arg);
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;
} }

View File

@ -65,6 +65,16 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
gpg_error_t (*status_cb)(ctrl_t, int, ...), gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg); 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 /* This function is used to connect to the dirmngr. On some platforms
the function is able starts a dirmngr process if needed. */ the function is able starts a dirmngr process if needed. */
gpg_error_t gpg_error_t
@ -82,8 +92,16 @@ gpg_error_t get_assuan_server_version (assuan_context_t ctx,
/*-- asshelp2.c --*/ /*-- 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 /* Helper function to print an assuan status line using a printf
format string. */ 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, gpg_error_t print_assuan_status (assuan_context_t ctx,
const char *keyword, const char *keyword,
const char *format, const char *format,

View File

@ -36,6 +36,24 @@
#include "util.h" #include "util.h"
#include "asshelp.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 /* Helper function to print an assuan status line using a printf
format string. */ format string. */
@ -134,3 +152,41 @@ print_assuan_status_strings (assuan_context_t ctx, const char *keyword, ...)
va_end (arg_ptr); va_end (arg_ptr);
return err; 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. */ /* Return the user socket name used by DirMngr. */
const char * const char *
dirmngr_socket_name (void) dirmngr_socket_name (void)
@ -1104,6 +1115,13 @@ gnupg_module_name (int which)
X(bindir, "dirmngr", DIRMNGR_NAME); X(bindir, "dirmngr", DIRMNGR_NAME);
#endif #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: case GNUPG_MODULE_NAME_PROTECT_TOOL:
#ifdef GNUPG_DEFAULT_PROTECT_TOOL #ifdef GNUPG_DEFAULT_PROTECT_TOOL
return GNUPG_DEFAULT_PROTECT_TOOL; return GNUPG_DEFAULT_PROTECT_TOOL;

View File

@ -106,6 +106,8 @@ typedef struct
int keep_open; int keep_open;
int no_cache; int no_cache;
int eof_seen; 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. */ int print_only_name; /* Flags indicating that fname is not a real file. */
char fname[1]; /* Name of the file. */ char fname[1]; /* Name of the file. */
} file_es_filter_ctx_t; } file_es_filter_ctx_t;
@ -635,6 +637,34 @@ file_es_filter (void *opaque, int control, iobuf_t chain, byte * buf,
rc = -1; rc = -1;
*ret_len = 0; *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 else
{ {
nbytes = 0; nbytes = 0;
@ -1412,7 +1442,8 @@ iobuf_fdopen_nc (int fd, const char *mode)
iobuf_t 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; iobuf_t a;
file_es_filter_ctx_t *fcx; 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->fp = estream;
fcx->print_only_name = 1; fcx->print_only_name = 1;
fcx->keep_open = keep_open; 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 = file_es_filter;
a->filter_ov = fcx; a->filter_ov = fcx;
file_es_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len); 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 letter 'w', creates an output filter. Otherwise, creates an input
filter. If KEEP_OPEN is TRUE, then the stream is not closed when filter. If KEEP_OPEN is TRUE, then the stream is not closed when
the filter is destroyed. Otherwise, the stream is closed when the the filter is destroyed. Otherwise, the stream is closed when the
filter is destroyed. */ filter is destroyed. If READLIMIT is not 0 this gives a limit on
iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open); 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 /* Create a filter using an existing socket. On Windows creates a
special socket filter. On non-Windows systems simply, this simply 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> ()", "fo()o@example.org" },
{ "fo()o@example.org", NULL}, { "fo()o@example.org", NULL},
{ "Mr. Foo <foo@example.org><bar@example.net>", "foo@example.org"}, { "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 } { NULL, NULL }
}; };
int idx; int idx;

View File

@ -65,6 +65,9 @@
* (note that you can't search for these characters). Compare * (note that you can't search for these characters). Compare
* is not case sensitive. * is not case sensitive.
* - If the userid starts with a '&' a 40 hex digits keygrip is expected. * - 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 gpg_error_t
@ -251,6 +254,17 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
} }
break; 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: default:
if (s[0] == '0' && s[1] == 'x') if (s[0] == '0' && s[1] == 'x')
{ {

View File

@ -43,6 +43,10 @@
#define GPG_ERR_NO_AUTH 314 #define GPG_ERR_NO_AUTH 314
#define GPG_ERR_BAD_AUTH 315 #define GPG_ERR_BAD_AUTH 315
#endif /*GPG_ERROR_VERSION_NUMBER*/ #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. */ /* Hash function used with libksba. */
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) #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_datadir (void);
const char *gnupg_localedir (void); const char *gnupg_localedir (void);
const char *gnupg_cachedir (void); const char *gnupg_cachedir (void);
const char *gpg_agent_socket_name (void);
const char *dirmngr_socket_name (void); const char *dirmngr_socket_name (void);
char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info); 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_GPGCONF 10
#define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11 #define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11
#define GNUPG_MODULE_NAME_GPGV 12 #define GNUPG_MODULE_NAME_GPGV 12
#define GNUPG_MODULE_NAME_KEYBOXD 13
const char *gnupg_module_name (int which); const char *gnupg_module_name (int which);
void gnupg_module_name_flush_some (void); void gnupg_module_name_flush_some (void);
void gnupg_set_builddir (const char *newdir); 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_GPG_ERROR_VERSION=1.29
NEED_LIBGCRYPT_API=1 NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.7.0 NEED_LIBGCRYPT_VERSION=1.8.0
NEED_LIBASSUAN_API=2 NEED_LIBASSUAN_API=2
NEED_LIBASSUAN_VERSION=2.5.0 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)" show_gnupg_dirmngr_pgm="(default)"
test -n "$GNUPG_DIRMNGR_PGM" && show_gnupg_dirmngr_pgm="$GNUPG_DIRMNGR_PGM" 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, AC_ARG_WITH(protect-tool-pgm,
[ --with-protect-tool-pgm=PATH Use PATH as the default for the protect-tool)], [ --with-protect-tool-pgm=PATH Use PATH as the default for the protect-tool)],
GNUPG_PROTECT_TOOL_PGM="$withval", GNUPG_PROTECT_TOOL_PGM="" ) GNUPG_PROTECT_TOOL_PGM="$withval", GNUPG_PROTECT_TOOL_PGM="" )
@ -508,6 +516,7 @@ AH_BOTTOM([
#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg" #define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
#endif #endif
#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d" #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_OPENPGP_REVOC_DIR "openpgp-revocs.d"
#define GNUPG_CACHE_DIR "cache.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", AC_DEFINE_UNQUOTED(DIRMNGR_DISP_NAME, "DirMngr",
[The displayed name of 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_NAME, "g13", [The name of the g13 tool])
AC_DEFINE_UNQUOTED(G13_DISP_NAME, "G13", [The displayed name of g13]) 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]) [The name of the dirmngr info envvar])
AC_DEFINE_UNQUOTED(SCDAEMON_SOCK_NAME, "S.scdaemon", AC_DEFINE_UNQUOTED(SCDAEMON_SOCK_NAME, "S.scdaemon",
[The name of the SCdaemon socket]) [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", AC_DEFINE_UNQUOTED(DIRMNGR_SOCK_NAME, "S.dirmngr",
[The name of the dirmngr socket]) [The name of the dirmngr socket])
AC_DEFINE_UNQUOTED(DIRMNGR_DEFAULT_KEYSERVER, AC_DEFINE_UNQUOTED(DIRMNGR_DEFAULT_KEYSERVER,
@ -2106,6 +2121,7 @@ echo "
Default agent: $show_gnupg_agent_pgm Default agent: $show_gnupg_agent_pgm
Default pinentry: $show_gnupg_pinentry_pgm Default pinentry: $show_gnupg_pinentry_pgm
Default scdaemon: $show_gnupg_scdaemon_pgm Default scdaemon: $show_gnupg_scdaemon_pgm
Default keyboxd: $show_gnupg_keyboxd_pgm
Default dirmngr: $show_gnupg_dirmngr_pgm Default dirmngr: $show_gnupg_dirmngr_pgm
Dirmngr auto start: $dirmngr_auto_start Dirmngr auto start: $dirmngr_auto_start

View File

@ -1138,6 +1138,18 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
*** BEGIN_STREAM, END_STREAM *** BEGIN_STREAM, END_STREAM
Used to issued by the experimental pipemode. 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 * 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 if none is running. This has only an effect if used together with the
option @option{--dirmngr}. 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 @item --dirmngr
@opindex dirmngr @opindex dirmngr
Connect to a running directory manager (keyserver client) instead of Connect to a running directory manager (keyserver client) instead of
to the gpg-agent. If a dirmngr is not running, start it. 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 @item -S
@itemx --raw-socket @var{name} @itemx --raw-socket @var{name}
@opindex raw-socket @opindex raw-socket

View File

@ -29,9 +29,9 @@ AM_CPPFLAGS =
include $(top_srcdir)/am/cmacros.am include $(top_srcdir)/am/cmacros.am
AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \ 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 # Because there are no program specific transform macros we need to
# work around that to allow installing gpg as gpg2. # work around that to allow installing gpg as gpg2.
@ -50,9 +50,9 @@ noinst_PROGRAMS = gpg
if !HAVE_W32CE_SYSTEM if !HAVE_W32CE_SYSTEM
noinst_PROGRAMS += gpgv noinst_PROGRAMS += gpgv
endif endif
if MAINTAINER_MODE #if MAINTAINER_MODE
noinst_PROGRAMS += gpgcompose #noinst_PROGRAMS += gpgcompose
endif #endif
noinst_PROGRAMS += $(module_tests) noinst_PROGRAMS += $(module_tests)
TESTS = $(module_tests) TESTS = $(module_tests)
TESTS_ENVIRONMENT = \ TESTS_ENVIRONMENT = \
@ -100,7 +100,10 @@ common_source = \
free-packet.c \ free-packet.c \
getkey.c \ getkey.c \
expand-group.c \ expand-group.c \
keydb.c keydb.h \ keydb.h \
keydb-private.h \
call-keyboxd.c \
keydb.c \
keyring.c keyring.h \ keyring.c keyring.h \
seskey.c \ seskey.c \
kbnode.c \ kbnode.c \
@ -161,7 +164,7 @@ gpg_SOURCES = gpg.c \
keyedit.c keyedit.h \ keyedit.c keyedit.h \
$(gpg_sources) $(gpg_sources)
gpgcompose_SOURCES = gpgcompose.c $(gpg_sources) #gpgcompose_SOURCES = gpgcompose.c $(gpg_sources)
gpgv_SOURCES = gpgv.c \ gpgv_SOURCES = gpgv.c \
$(common_source) \ $(common_source) \
verify.c verify.c
@ -176,33 +179,36 @@ gpgv_SOURCES = gpgv.c \
LDADD = $(needed_libs) ../common/libgpgrl.a \ LDADD = $(needed_libs) ../common/libgpgrl.a \
$(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS)
gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ 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) $(LIBICONV) $(resource_objs) $(extra_sys_libs)
gpg_LDFLAGS = $(extra_bin_ldflags) gpg_LDFLAGS = $(extra_bin_ldflags)
gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(GPG_ERROR_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(resource_objs) $(extra_sys_libs) $(LIBICONV) $(resource_objs) $(extra_sys_libs)
gpgv_LDFLAGS = $(extra_bin_ldflags) gpgv_LDFLAGS = $(extra_bin_ldflags)
gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ #gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ # $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(resource_objs) $(extra_sys_libs) # $(LIBICONV) $(resource_objs) $(extra_sys_libs)
gpgcompose_LDFLAGS = $(extra_bin_ldflags) #gpgcompose_LDFLAGS = $(extra_bin_ldflags)
t_common_ldadd = t_common_ldadd =
module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter
t_rmd160_SOURCES = t-rmd160.c rmd160.c t_rmd160_SOURCES = t-rmd160.c rmd160.c
t_rmd160_LDADD = $(t_common_ldadd) t_rmd160_LDADD = $(t_common_ldadd)
t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source) 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) $(LIBICONV) $(t_common_ldadd)
t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \ t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \
$(common_source) $(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) $(LIBICONV) $(t_common_ldadd)
t_stutter_SOURCES = t-stutter.c test-stubs.c \ t_stutter_SOURCES = t-stutter.c test-stubs.c \
$(common_source) $(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) $(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); rc = get_output_file ("", 0, ed->buf, &filename, &fp);
if (! rc) 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; armor_filter_context_t *afx = NULL;
if (opt.armor) 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; *r_sec_avail = 0;
hd = keydb_new (); hd = keydb_new (ctrl);
if (!hd) if (!hd)
return gpg_error_from_syserror (); 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 (!secret && !force)
{ {
if (have_secret_key_with_kid (keyid)) if (have_secret_key_with_kid (ctrl, keyid))
{ {
*r_sec_avail = 1; *r_sec_avail = 1;
err = gpg_error (GPG_ERR_EOF); 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; 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); err = gpg_error (GPG_ERR_NOT_FOUND);
log_error (_("key \"%s\" not found\n"), username); 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; stats = &dummystats;
*any = 0; *any = 0;
init_packet (&pkt); init_packet (&pkt);
kdbhd = keydb_new (); kdbhd = keydb_new (ctrl);
if (!kdbhd) if (!kdbhd)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();

View File

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

View File

@ -36,6 +36,7 @@
# endif # endif
# include <windows.h> # include <windows.h>
#endif #endif
#include <npth.h>
#define INCLUDED_BY_MAIN_MODULE 1 #define INCLUDED_BY_MAIN_MODULE 1
#include "gpg.h" #include "gpg.h"
@ -361,6 +362,7 @@ enum cmd_and_opt_values
oUseAgent, oUseAgent,
oNoUseAgent, oNoUseAgent,
oGpgAgentInfo, oGpgAgentInfo,
oUseKeyboxd,
oMergeOnly, oMergeOnly,
oTryAllSecrets, oTryAllSecrets,
oTrustedKey, oTrustedKey,
@ -378,6 +380,7 @@ enum cmd_and_opt_values
oPersonalDigestPreferences, oPersonalDigestPreferences,
oPersonalCompressPreferences, oPersonalCompressPreferences,
oAgentProgram, oAgentProgram,
oKeyboxdProgram,
oDirmngrProgram, oDirmngrProgram,
oDisableDirmngr, oDisableDirmngr,
oDisplay, oDisplay,
@ -850,6 +853,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"), ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"),
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"), ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
ARGPARSE_s_s (oKeyboxdProgram, "keyboxd-program", "@"),
ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"), ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", "@"), ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", "@"),
ARGPARSE_s_s (oDisplay, "display", "@"), ARGPARSE_s_s (oDisplay, "display", "@"),
@ -896,6 +900,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"), ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"),
ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"), ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
ARGPARSE_s_n (oUseKeyboxd, "use-keyboxd", "@"),
/* Options which can be used in special circumstances. They are not /* Options which can be used in special circumstances. They are not
* published and we hope they are never required. */ * 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 emergency_cleanup (void);
static void read_sessionkey_from_fd (int fd); static void read_sessionkey_from_fd (int fd);
/* NPth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
static char * static char *
make_libversion (const char *libname, const char *(*getfnc)(const 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); gpg_dirmngr_deinit_session_data (ctrl);
keydb_release (ctrl->cached_getkey_kdb); keydb_release (ctrl->cached_getkey_kdb);
gpg_keyboxd_deinit_session_data (ctrl);
} }
@ -2742,6 +2751,11 @@ main (int argc, char **argv)
case oGpgAgentInfo: case oGpgAgentInfo:
obsolete_option (configname, configlineno, "gpg-agent-info"); obsolete_option (configname, configlineno, "gpg-agent-info");
break; break;
case oUseKeyboxd:
opt.use_keyboxd = 1;
break;
case oReaderPort: case oReaderPort:
obsolete_scdaemon_option (configname, configlineno, "reader-port"); obsolete_scdaemon_option (configname, configlineno, "reader-port");
break; break;
@ -3499,6 +3513,7 @@ main (int argc, char **argv)
pers_compress_list=pargs.r.ret_str; pers_compress_list=pargs.r.ret_str;
break; break;
case oAgentProgram: opt.agent_program = 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 oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
case oDisableDirmngr: opt.disable_dirmngr = 1; break; case oDisableDirmngr: opt.disable_dirmngr = 1; break;
case oWeakDigest: case oWeakDigest:
@ -3738,6 +3753,11 @@ main (int argc, char **argv)
} }
#endif #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; /* FIXME: We should use logging to a file only in server mode;
however we have not yet implemetyed that. Thus we try to get however we have not yet implemetyed that. Thus we try to get
away with --batch as indication for logging to file away with --batch as indication for logging to file
@ -3745,7 +3765,9 @@ main (int argc, char **argv)
if (logfile && opt.batch) if (logfile && opt.batch)
{ {
log_set_file (logfile); 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) if (opt.verbose > 2)
@ -4120,8 +4142,10 @@ main (int argc, char **argv)
/* Add the keyrings, but not for some special commands. We always /* Add the keyrings, but not for some special commands. We always
* need to add the keyrings if we are running under SELinux, this * 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. * 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. */ * We do not add any keyring if --no-keyring or --use-keyboxd has
if (default_keyring >= 0 * been used. */
if (!opt.use_keyboxd
&& default_keyring >= 0
&& (ALWAYS_ADD_KEYRINGS && (ALWAYS_ADD_KEYRINGS
|| (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest))) || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
{ {
@ -4133,9 +4157,8 @@ main (int argc, char **argv)
} }
FREE_STRLIST(nrings); FREE_STRLIST(nrings);
/* In loopback mode, never ask for the password multiple times. */
if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK) if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
/* In loopback mode, never ask for the password multiple
times. */
{ {
opt.passphrase_repeat = 0; opt.passphrase_repeat = 0;
} }
@ -5089,7 +5112,7 @@ main (int argc, char **argv)
policy = parse_tofu_policy (argv[0]); policy = parse_tofu_policy (argv[0]);
hd = keydb_new (); hd = keydb_new (ctrl);
if (! hd) if (! hd)
{ {
write_status_failure ("tofu-driver", gpg_error(GPG_ERR_GENERAL)); 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 . */ /* Object used to keep state locally to server.c . */
struct server_local_s; 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 . */ /* Object used to keep state locally to call-dirmngr.c . */
struct dirmngr_local_s; struct dirmngr_local_s;
typedef struct dirmngr_local_s *dirmngr_local_t; typedef struct dirmngr_local_s *dirmngr_local_t;
/* Object used to describe a keyblock node. */ /* Object used to describe a keyblock node. */
typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */ typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */typedef struct kbnode_struct *kbnode_t;
typedef struct kbnode_struct *kbnode_t;
/* The handle for keydb operations. */ /* The handle for keydb operations. */
typedef struct keydb_handle *KEYDB_HANDLE; typedef struct keydb_handle_s *KEYDB_HANDLE;
/* TOFU database meta object. */ /* TOFU database meta object. */
struct tofu_dbs_s; struct tofu_dbs_s;
@ -96,6 +99,9 @@ struct server_control_s
/* Local data for call-dirmngr.c */ /* Local data for call-dirmngr.c */
dirmngr_local_t dirmngr_local; dirmngr_local_t dirmngr_local;
/* Local data for call-keyboxd.c */
keyboxd_local_t keyboxd_local;
/* Local data for tofu.c */ /* Local data for tofu.c */
struct { struct {
tofu_dbs_t dbs; tofu_dbs_t dbs;

View File

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

View File

@ -550,7 +550,7 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp,
gpg_error_t err; gpg_error_t err;
iobuf_t inp; iobuf_t inp;
inp = iobuf_esopen (fp, "rb", 1); inp = iobuf_esopen (fp, "rb", 1, 0);
if (!inp) if (!inp)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
@ -2022,7 +2022,7 @@ import_one_real (ctrl_t ctrl,
goto leave; goto leave;
/* Do we have this key already in one of our pubrings ? */ /* 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*/); fpr2, fpr2len, 1/*locked*/);
if ((err if ((err
&& gpg_err_code (err) != GPG_ERR_NO_PUBKEY && gpg_err_code (err) != GPG_ERR_NO_PUBKEY
@ -2310,13 +2310,13 @@ import_one_real (ctrl_t ctrl,
if (mod_key) if (mod_key)
{ {
revocation_present (ctrl, keyblock_orig); 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); check_prefs (ctrl, keyblock_orig);
} }
else if (new_key) else if (new_key)
{ {
revocation_present (ctrl, keyblock); 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); check_prefs (ctrl, keyblock);
} }
@ -3372,7 +3372,7 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
} }
/* Read the original keyblock. */ /* Read the original keyblock. */
hd = keydb_new (); hd = keydb_new (ctrl);
if (!hd) if (!hd)
{ {
rc = gpg_error_from_syserror (); 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 else if (node->pkt->pkttype == PKT_SIGNATURE
&& !node->pkt->pkt.signature->flags.exportable && !node->pkt->pkt.signature->flags.exportable
&& !(options&IMPORT_LOCAL_SIGS) && !(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 /* here we violate the rfc a bit by still allowing
* to import non-exportable signature when we have the * to import non-exportable signature when we have the
@ -4089,7 +4090,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
* itself? */ * itself? */
gpg_error_t err; gpg_error_t err;
err = get_pubkey_byfprint_fast (NULL, err = get_pubkey_byfprint_fast (ctrl, NULL,
sig->revkey[idx].fpr, sig->revkey[idx].fpr,
sig->revkey[idx].fprlen); sig->revkey[idx].fprlen);
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY
@ -4111,7 +4112,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
opt.keyserver, 0); opt.keyserver, 0);
/* Do we have it now? */ /* 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].fpr,
sig->revkey[idx].fprlen); 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 "keydb.h"
#include "../common/i18n.h" #include "../common/i18n.h"
#include "keydb-private.h" /* For struct keydb_handle_s */
static int active_handles; 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 struct resource_item all_resources[MAX_KEYDB_RESOURCES];
static int used_resources; static int used_resources;
@ -67,74 +52,6 @@ static void *primary_keydb;
/* Whether we have successfully registered any resource. */ /* Whether we have successfully registered any resource. */
static int any_registered; 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 /* 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 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 exist, we don't have to spend time looking it up. This
@ -273,7 +190,7 @@ kid_not_found_flush (void)
static 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; hd->keyblock_cache.state = KEYBLOCK_CACHE_EMPTY;
iobuf_close (hd->keyblock_cache.iobuf); 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 (); rc = gpg_error_from_syserror ();
else else
{ {
rc = _keybox_write_header_blob (fp, 1); rc = _keybox_write_header_blob (fp, NULL, 1);
fclose (fp); fclose (fp);
} }
if (rc) if (rc)
@ -539,6 +456,10 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
char b[MAX_FORMATTED_FINGERPRINT_LEN + 1]; char b[MAX_FORMATTED_FINGERPRINT_LEN + 1];
char fpr[2 * MAX_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) switch (desc->mode)
{ {
case KEYDB_SEARCH_MODE_EXACT: case KEYDB_SEARCH_MODE_EXACT:
@ -578,7 +499,11 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
case KEYDB_SEARCH_MODE_SUBJECT: case KEYDB_SEARCH_MODE_SUBJECT:
return xasprintf ("SUBJECT: '%s'", desc->u.name); return xasprintf ("SUBJECT: '%s'", desc->u.name);
case KEYDB_SEARCH_MODE_KEYGRIP: 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: case KEYDB_SEARCH_MODE_FIRST:
return xasprintf ("FIRST"); return xasprintf ("FIRST");
case KEYDB_SEARCH_MODE_NEXT: 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 /* keydb_new diverts to here in non-keyboxd mode. HD is just the
file handle: it contains a local file position. This is used when * calloced structure with the handle type intialized. */
searching: subsequent searches resume where the previous search gpg_error_t
left off. To rewind the position, use keydb_search_reset(). This internal_keydb_init (KEYDB_HANDLE hd)
function returns NULL on error, sets ERRNO, and prints an error
diagnostic. */
KEYDB_HANDLE
keydb_new (void)
{ {
KEYDB_HANDLE hd; gpg_error_t err = 0;
int i, j; int i, j;
int die = 0; int die = 0;
int reterrno; int reterrno;
if (DBG_CLOCK) log_assert (!hd->use_keyboxd);
log_clock ("keydb_new");
hd = xtrycalloc (1, sizeof *hd);
if (!hd)
goto leave;
hd->found = -1; hd->found = -1;
hd->saved_found = -1; hd->saved_found = -1;
hd->is_reset = 1; hd->is_reset = 1;
@ -949,28 +865,21 @@ keydb_new (void)
keydb_stats.handles++; keydb_stats.handles++;
if (die) if (die)
{ err = gpg_error_from_errno (reterrno);
keydb_release (hd);
gpg_err_set_errno (reterrno);
hd = NULL;
}
leave: return err;
if (!hd)
log_error (_("error opening key DB: %s\n"),
gpg_strerror (gpg_error_from_syserror()));
return hd;
} }
/* Free all non-keyboxd resources owned by the database handle.
* keydb_release diverts to here. */
void void
keydb_release (KEYDB_HANDLE hd) internal_keydb_deinit (KEYDB_HANDLE hd)
{ {
int i; int i;
if (!hd) log_assert (!hd->use_keyboxd);
return;
log_assert (active_handles > 0); log_assert (active_handles > 0);
active_handles--; active_handles--;
@ -992,19 +901,17 @@ keydb_release (KEYDB_HANDLE hd)
} }
keyblock_cache_clear (hd); keyblock_cache_clear (hd);
xfree (hd);
} }
/* Take a lock on the files immediately and not only during insert or /* Take a lock on the files immediately and not only during insert or
* update. This lock is released with keydb_release. */ * update. This lock is released with keydb_release. */
gpg_error_t gpg_error_t
keydb_lock (KEYDB_HANDLE hd) internal_keydb_lock (KEYDB_HANDLE hd)
{ {
gpg_error_t err; gpg_error_t err;
if (!hd) log_assert (!hd->use_keyboxd);
return gpg_error (GPG_ERR_INV_ARG);
err = lock_all (hd); err = lock_all (hd);
if (!err) if (!err)
@ -1020,7 +927,7 @@ keydb_lock (KEYDB_HANDLE hd)
void void
keydb_disable_caching (KEYDB_HANDLE hd) keydb_disable_caching (KEYDB_HANDLE hd)
{ {
if (hd) if (hd && !hd->use_keyboxd)
hd->no_caching = 1; hd->no_caching = 1;
} }
@ -1042,6 +949,9 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
if (!hd) if (!hd)
return NULL; return NULL;
if (!hd->use_keyboxd)
return "[keyboxd]";
if ( hd->found >= 0 && hd->found < hd->used) if ( hd->found >= 0 && hd->found < hd->used)
idx = hd->found; idx = hd->found;
else if ( hd->current >= 0 && hd->current < hd->used) 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. * 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 * In other words, the save stack only has room for a single
* instance of the state. */ * instance of the state. */
/* FIXME(keyboxd): This function is used only at one place - see how
* we can avoid it. */
void void
keydb_push_found_state (KEYDB_HANDLE hd) 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 /* Restore the previous save state. If the saved state is NULL or
invalid, this is a NOP. */ invalid, this is a NOP. */
/* FIXME(keyboxd): This function is used only at one place - see how
* we can avoid it. */
void void
keydb_pop_found_state (KEYDB_HANDLE hd) 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. /* 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 * On success, the function returns 0 and the caller must free *RET_KB
* using release_kbnode(). Otherwise, the function returns an error * 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 * with the public key used to locate the keyblock or flag bit 1 set
* for the user ID node. */ * for the user ID node. */
gpg_error_t 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; gpg_error_t err = 0;
*ret_kb = NULL; log_assert (!hd->use_keyboxd);
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
if (DBG_CLOCK)
log_clock ("keydb_get_keybock enter");
if (hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED) if (hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED)
{ {
@ -1398,8 +1307,7 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
if (err) if (err)
keyblock_cache_clear (hd); keyblock_cache_clear (hd);
if (DBG_CLOCK) if (DBG_CLOCK)
log_clock (err? "keydb_get_keyblock leave (cached, failed)" log_clock ("%s leave (cached mode)", __func__);
: "keydb_get_keyblock leave (cached)");
return err; return err;
} }
} }
@ -1447,9 +1355,6 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
if (!err) if (!err)
keydb_stats.get_keyblocks++; keydb_stats.get_keyblocks++;
if (DBG_CLOCK)
log_clock (err? "keydb_get_keyblock leave (failed)"
: "keydb_get_keyblock leave");
return err; 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 /* Update the keyblock KB (i.e., extract the fingerprint and find the
* corresponding keyblock in the keyring). * 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. * 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 * you should use keydb_push_found_state and keydb_pop_found_state to
* save and restore it. */ * save and restore it. */
gpg_error_t 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; gpg_error_t err;
PKT_public_key *pk; PKT_public_key *pk;
KEYDB_SEARCH_DESC desc; KEYDB_SEARCH_DESC desc;
size_t len; size_t len;
log_assert (kb); log_assert (!hd->use_keyboxd);
log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
pk = kb->pkt->pkt.public_key; pk = kb->pkt->pkt.public_key;
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
kid_not_found_flush (); kid_not_found_flush ();
keyblock_cache_clear (hd); 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. /* 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 * Be default, the keyring / keybox from which the last search result
* came is used. If there was no previous search result (or * 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. */ * Returns 0 on success. Otherwise, it returns an error code. */
gpg_error_t 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; gpg_error_t err;
int idx; int idx;
if (!hd) log_assert (!hd->use_keyboxd);
return gpg_error (GPG_ERR_INV_ARG);
kid_not_found_flush (); kid_not_found_flush ();
keyblock_cache_clear (hd); 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. */ * Returns 0 on success or an error code, if an error occurs. */
gpg_error_t gpg_error_t
keydb_delete_keyblock (KEYDB_HANDLE hd) internal_keydb_delete_keyblock (KEYDB_HANDLE hd)
{ {
gpg_error_t rc; gpg_error_t rc;
if (!hd) log_assert (!hd->use_keyboxd);
return gpg_error (GPG_ERR_INV_ARG);
kid_not_found_flush (); kid_not_found_flush ();
keyblock_cache_clear (hd); keyblock_cache_clear (hd);
@ -1721,6 +1622,9 @@ keydb_locate_writable (KEYDB_HANDLE hd)
if (!hd) if (!hd)
return GPG_ERR_INV_ARG; 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 */ rc = keydb_search_reset (hd); /* this does reset hd->current */
if (rc) if (rc)
return rc; return rc;
@ -1772,6 +1676,9 @@ keydb_rebuild_caches (ctrl_t ctrl, int noisy)
{ {
int i, rc; int i, rc;
if (opt.use_keyboxd)
return; /* No need for this here. */
for (i=0; i < used_resources; i++) for (i=0; i < used_resources; i++)
{ {
if (!keyring_is_writable (all_resources[i].token)) 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. */ read from a keybox) since the last search reset. */
unsigned long unsigned long
keydb_get_skipped_counter (KEYDB_HANDLE hd) 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 /* Clears the current search result and resets the handle's position
* so that the next search starts at the beginning of the database * so that the next search starts at the beginning of the database
* (the start of the first resource). * (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. * Returns 0 on success and an error code if an error occurred.
* (Currently, this function always returns 0 if HD is valid.) */ * (Currently, this function always returns 0 if HD is valid.) */
gpg_error_t gpg_error_t
keydb_search_reset (KEYDB_HANDLE hd) internal_keydb_search_reset (KEYDB_HANDLE hd)
{ {
gpg_error_t rc = 0; gpg_error_t rc = 0;
int i; int i;
if (!hd) log_assert (!hd->use_keyboxd);
return gpg_error (GPG_ERR_INV_ARG);
keyblock_cache_clear (hd); 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->skipped_long_blobs = 0;
hd->current = 0; hd->current = 0;
hd->found = -1; hd->found = -1;
@ -1853,6 +1755,7 @@ keydb_search_reset (KEYDB_HANDLE hd)
/* Search the database for keys matching the search description. If /* Search the database for keys matching the search description. If
* the DB contains any legacy keys, these are silently ignored. * 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 * 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 * 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, * The returned key is considered to be selected and the raw data can,
* for instance, be returned by calling keydb_get_keyblock(). */ * for instance, be returned by calling keydb_get_keyblock(). */
gpg_error_t gpg_error_t
keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, internal_keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex) size_t ndesc, size_t *descindex)
{ {
int i;
gpg_error_t rc; gpg_error_t rc;
int was_reset = hd->is_reset; int was_reset = hd->is_reset;
/* If an entry is already in the cache, then don't add it again. */ /* If an entry is already in the cache, then don't add it again. */
int already_in_cache = 0; int already_in_cache = 0;
int fprlen; int fprlen;
if (descindex) log_assert (!hd->use_keyboxd);
*descindex = 0; /* Make sure it is always set on return. */
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
if (!any_registered) if (!any_registered)
{ {
@ -1892,26 +1790,11 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
return gpg_error (GPG_ERR_NOT_FOUND); 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 if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID
&& (already_in_cache = kid_not_found_p (desc[0].u.kid)) == 1 ) && (already_in_cache = kid_not_found_p (desc[0].u.kid)) == 1 )
{ {
if (DBG_CLOCK) if (DBG_CLOCK)
log_clock ("keydb_search leave (not found, cached)"); log_clock ("%s leave (not found, cached)", __func__);
keydb_stats.notfound_cached++; keydb_stats.notfound_cached++;
return gpg_error (GPG_ERR_NOT_FOUND); return gpg_error (GPG_ERR_NOT_FOUND);
} }
@ -1939,7 +1822,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
{ {
/* (DESCINDEX is already set). */ /* (DESCINDEX is already set). */
if (DBG_CLOCK) if (DBG_CLOCK)
log_clock ("keydb_search leave (cached)"); log_clock ("%s leave (cached)", __func__);
hd->current = hd->keyblock_cache.resource; hd->current = hd->keyblock_cache.resource;
/* HD->KEYBLOCK_CACHE.OFFSET is the last byte in the record. /* 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) && !already_in_cache)
kid_not_found_insert (desc[0].u.kid); 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) if (!rc)
keydb_stats.found++; keydb_stats.found++;
else 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 --*/ /*-- keydb.c --*/
@ -187,17 +222,6 @@ gpg_error_t keydb_add_resource (const char *url, unsigned int flags);
/* Dump some statistics to the log. */ /* Dump some statistics to the log. */
void keydb_dump_stats (void); 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 /* Set a flag on the handle to suppress use of cached results. This
is required for updating a keyring and for key listings. Fixme: is required for updating a keyring and for key listings. Fixme:
Using a new parameter for keydb_new might be a better solution. */ 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. */ /* Return the file name of the resource. */
const char *keydb_get_resource_name (KEYDB_HANDLE hd); 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. */ /* Find the first writable resource. */
gpg_error_t keydb_locate_writable (KEYDB_HANDLE hd); 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. */ read from a keybox) since the last search reset. */
unsigned long keydb_get_skipped_counter (KEYDB_HANDLE hd); 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. */ /* Return the first non-legacy key in the database. */
gpg_error_t keydb_search_first (KEYDB_HANDLE hd); 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 /* 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 account nor does it merge in the self-signed data. This function
also only considers primary keys. */ 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 /* Return the entire keyblock used to create SIG. This is a
* specialized version of get_pubkeyblock. */ * 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 /* 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 merge the self-signed data into the public key and subkeys or into
the user ids. */ 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); const byte *fprint, size_t fprint_len);
/* This function is similar to get_pubkey_byfprint, but it doesn't /* 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 merge the self-signed data into the public key and subkeys or into
the user ids. */ 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, KEYDB_HANDLE *r_hd,
const byte *fprint, size_t fprint_len, const byte *fprint, size_t fprint_len,
int lock); 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 /* Returns true if a secret key is available for the public key with
key id KEYID. */ 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 /* Parse the --default-key parameter. Returns the last key (in terms
of when the option is given) that is available. */ 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; *r_keyblock = NULL;
/* Search the key; we don't want the whole getkey stuff here. */ /* Search the key; we don't want the whole getkey stuff here. */
kdbhd = keydb_new (); kdbhd = keydb_new (ctrl);
if (!kdbhd) if (!kdbhd)
{ {
/* Note that keydb_new has already used log_error. */ /* 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 else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
&& ((sig = node->pkt->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) 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 else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
&& ((sig = node->pkt->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) 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.mode = KEYDB_SEARCH_MODE_EXACT;
desc.u.name = uid; desc.u.name = uid;
kdbhd = keydb_new (); kdbhd = keydb_new (ctrl);
if (!kdbhd) if (!kdbhd)
goto leave; goto leave;
@ -5371,7 +5371,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
{ {
KEYDB_HANDLE pub_hd; KEYDB_HANDLE pub_hd;
pub_hd = keydb_new (); pub_hd = keydb_new (ctrl);
if (!pub_hd) if (!pub_hd)
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
else else

View File

@ -524,7 +524,7 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
if (opt.check_sigs) if (opt.check_sigs)
listctx.check_sigs = 1; listctx.check_sigs = 1;
hd = keydb_new (); hd = keydb_new (ctrl);
if (!hd) if (!hd)
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
else 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); *klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
kdbhd = keydb_new (); kdbhd = keydb_new (ctrl);
if (!kdbhd) if (!kdbhd)
{ {
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();

View File

@ -157,7 +157,7 @@ struct expando_args
const byte *namehash; 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, void deprecated_warning(const char *configname,unsigned int configlineno,
const char *option,const char *repl1,const char *repl2); const char *option,const char *repl1,const char *repl2);
void deprecated_command (const char *name); 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 /* Expand %-strings. Returns a string which must be xfreed. Returns
NULL if the string cannot be expanded (too large). */ NULL if the string cannot be expanded (too large). */
char * 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; const char *ch=string;
int idx=0,maxlen=0,done=0; int idx=0,maxlen=0,done=0;
@ -1017,7 +1017,7 @@ pct_expando(const char *string,struct expando_args *args)
PKT_public_key *pk= PKT_public_key *pk=
xmalloc_clear(sizeof(PKT_public_key)); 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); fingerprint_from_pk (pk, array, &len);
else else
memset (array, 0, (len=MAX_FINGERPRINT_LEN)); memset (array, 0, (len=MAX_FINGERPRINT_LEN));

View File

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

View File

@ -126,6 +126,7 @@ struct
int completes_needed; int completes_needed;
int max_cert_depth; int max_cert_depth;
const char *agent_program; const char *agent_program;
const char *keyboxd_program;
const char *dirmngr_program; const char *dirmngr_program;
int disable_dirmngr; int disable_dirmngr;
@ -287,6 +288,8 @@ struct
int only_sign_text_ids; int only_sign_text_ids;
int no_symkey_cache; /* Disable the cache used for --symmetric. */ int no_symkey_cache; /* Disable the cache used for --symmetric. */
int use_keyboxd; /* Use the external keyboxd as storage backend. */
} opt; } opt;
/* CTRL is used to keep some global variables we currently can't /* 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; int offset = attrs[i].len-len;
/* make command grow */ /* make command grow */
command = pct_expando (opt.photo_viewer, &args); command = pct_expando (ctrl, opt.photo_viewer,&args);
if (!command) if(!command)
goto fail; goto fail;
name = xmalloc (1 + 16 + strlen(EXTSEP_S) 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 (); afx = new_armor_context ();
kdbhd = keydb_new (); kdbhd = keydb_new (ctrl);
if (!kdbhd) if (!kdbhd)
{ {
rc = gpg_error_from_syserror (); 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. */ /* Search the userid; we don't want the whole getkey stuff here. */
kdbhd = keydb_new (); kdbhd = keydb_new (ctrl);
if (!kdbhd) if (!kdbhd)
{ {
rc = gpg_error_from_syserror (); 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. * a valid NAME=VALUE format.
*/ */
static void 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) PKT_public_key *pk, PKT_public_key *pksk)
{ {
const char *string; const char *string;
@ -99,7 +99,7 @@ mk_notation_policy_etc (PKT_signature *sig,
for (item = nd; item; item = item->next) 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) if (!item->altvalue)
log_error (_("WARNING: unable to %%-expand notation " log_error (_("WARNING: unable to %%-expand notation "
"(too large). Using unexpanded.\n")); "(too large). Using unexpanded.\n"));
@ -126,7 +126,7 @@ mk_notation_policy_etc (PKT_signature *sig,
{ {
string = pu->d; string = pu->d;
p = pct_expando (string, &args); p = pct_expando (ctrl, string, &args);
if (!p) if (!p)
{ {
log_error(_("WARNING: unable to %%-expand policy URL " log_error(_("WARNING: unable to %%-expand policy URL "
@ -149,7 +149,7 @@ mk_notation_policy_etc (PKT_signature *sig,
{ {
string = pu->d; string = pu->d;
p = pct_expando (string, &args); p = pct_expando (ctrl, string, &args);
if (!p) if (!p)
{ {
log_error (_("WARNING: unable to %%-expand preferred keyserver URL" log_error (_("WARNING: unable to %%-expand preferred keyserver URL"
@ -838,7 +838,7 @@ write_signature_packets (ctrl_t ctrl,
BUG (); BUG ();
build_sig_subpkt_from_sig (sig, pk); 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); hash_sigversion_to_magic (md, sig, extrahash);
gcry_md_final (md); gcry_md_final (md);
@ -1664,7 +1664,7 @@ make_keysig_packet (ctrl_t ctrl,
sig->sig_class = sigclass; sig->sig_class = sigclass;
build_sig_subpkt_from_sig (sig, pksk); 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 /* Crucial that the call to mksubpkt comes LAST before the calls
* to finalize the sig as that makes it possible for the mksubpkt * to finalize the sig as that makes it possible for the mksubpkt

View File

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

View File

@ -25,6 +25,7 @@ static void
do_test (int argc, char *argv[]) do_test (int argc, char *argv[])
{ {
int rc; int rc;
ctrl_t ctrl;
KEYDB_HANDLE hd1, hd2; KEYDB_HANDLE hd1, hd2;
KEYDB_SEARCH_DESC desc1, desc2; KEYDB_SEARCH_DESC desc1, desc2;
KBNODE kb1, kb2, p; KBNODE kb1, kb2, p;
@ -35,16 +36,17 @@ do_test (int argc, char *argv[])
(void) argc; (void) argc;
(void) argv; (void) argv;
ctrl = xcalloc (1, sizeof *ctrl);
fname = prepend_srcdir ("t-keydb-keyring.kbx"); fname = prepend_srcdir ("t-keydb-keyring.kbx");
rc = keydb_add_resource (fname, 0); rc = keydb_add_resource (fname, 0);
test_free (fname); test_free (fname);
if (rc) if (rc)
ABORT ("Failed to open keyring."); ABORT ("Failed to open keyring.");
hd1 = keydb_new (); hd1 = keydb_new (ctrl);
if (!hd1) if (!hd1)
ABORT (""); ABORT ("");
hd2 = keydb_new (); hd2 = keydb_new (ctrl);
if (!hd2) if (!hd2)
ABORT (""); ABORT ("");
@ -101,4 +103,5 @@ do_test (int argc, char *argv[])
release_kbnode (kb2); release_kbnode (kb2);
keydb_release (hd1); keydb_release (hd1);
keydb_release (hd2); 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 /* If two keys have cross signatures, then they are controlled by
* the same person and thus are not in conflict. */ * the same person and thus are not in conflict. */
kb_all = xcalloc (sizeof (kb_all[0]), conflict_set_count); kb_all = xcalloc (sizeof (kb_all[0]), conflict_set_count);
hd = keydb_new (); hd = keydb_new (ctrl);
for (i = 0, iter = conflict_set; for (i = 0, iter = conflict_set;
i < conflict_set_count; i < conflict_set_count;
i ++, iter = iter->next) i ++, iter = iter->next)

View File

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

View File

@ -18,16 +18,20 @@
## Process this file with automake to produce Makefile.in ## Process this file with automake to produce Makefile.in
EXTRA_DIST = mkerrors EXTRA_DIST = mkerrors keyboxd-w32info.rc
AM_CPPFLAGS = AM_CPPFLAGS =
include $(top_srcdir)/am/cmacros.am include $(top_srcdir)/am/cmacros.am
if HAVE_W32_SYSTEM
resource_objs += keyboxd-w32info.o
endif
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS)
noinst_LIBRARIES = libkeybox.a libkeybox509.a noinst_LIBRARIES = libkeybox.a libkeybox509.a
bin_PROGRAMS = kbxutil bin_PROGRAMS = kbxutil
libexec_PROGRAMS = keyboxd
if HAVE_W32CE_SYSTEM if HAVE_W32CE_SYSTEM
extra_libs = $(LIBASSUAN_LIBS) extra_libs = $(LIBASSUAN_LIBS)
@ -35,6 +39,9 @@ else
extra_libs = extra_libs =
endif endif
common_libs = $(libcommon)
commonpth_libs = $(libcommonpth)
common_sources = \ common_sources = \
keybox.h keybox-defs.h keybox-search-desc.h \ keybox.h keybox-defs.h keybox-search-desc.h \
keybox-util.c \ keybox-util.c \
@ -59,9 +66,31 @@ libkeybox509_a_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1
# to do it this way. # to do it this way.
kbxutil_SOURCES = kbxutil.c $(common_sources) kbxutil_SOURCES = kbxutil.c $(common_sources)
kbxutil_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1 kbxutil_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1
kbxutil_LDADD = ../common/libcommon.a \ kbxutil_LDADD = $(common_libs) \
$(KSBA_LIBS) $(LIBGCRYPT_LIBS) $(extra_libs) \ $(KSBA_LIBS) $(LIBGCRYPT_LIBS) $(extra_libs) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) $(W32SOCKLIBS) \ $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) $(W32SOCKLIBS) \
$(NETLIBS) $(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 - u16 Blob flags
bit 0 = contains secret key material (not used) bit 0 = contains secret key material (not used)
bit 1 = ephemeral blob (e.g. used while querying external resources) 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 - u32 Offset to the OpenPGP keyblock or the X.509 DER encoded
certificate certificate
- u32 The length of the keyblock or certificate - u32 The length of the keyblock or certificate
@ -143,7 +144,10 @@
IDs go here. IDs go here.
- bN Space for the keyblock or certificate. - bN Space for the keyblock or certificate.
- bN RFU. This is the remaining space after keyblock and before - 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?) - b20 SHA-1 checksum (useful for KS synchronization?)
Note, that KBX versions before GnuPG 2.1 used an MD5 Note, that KBX versions before GnuPG 2.1 used an MD5
checksum. However it was only created but never checked. checksum. However it was only created but never checked.
@ -173,6 +177,10 @@
#include "../common/gettime.h" #include "../common/gettime.h"
#include "../common/host2net.h"
#define get32(a) buf32_to_ulong ((a))
/* special values of the signature status */ /* 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 */ put32 ( a, 0 ); /* blob length, needs fixup */
put8 ( a, blobtype); put8 ( a, blobtype);
put8 ( a, want_fpr32? 2:1 ); /* blob type version */ 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 ); /* offset to the raw data, needs fixup */
put32 ( a, 0 ); /* length of 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; unsigned char *pp;
size_t n; size_t n;
/* Write a placeholder for the checksum */ /* Write placeholders for the UBID and the checksum */
put_membuf (a, NULL, 20); put_membuf (a, NULL, 40);
/* get the memory area */ /* get the memory area */
n = 0; /* (Just to avoid compiler warning.) */ n = 0; /* (Just to avoid compiler warning.) */
@ -721,8 +729,11 @@ create_blob_finish (KEYBOXBLOB blob)
blob->fixups = NULL; 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. */ /* 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); pp = xtrymalloc (n);
if ( !pp ) 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 static int
print_checksum (const byte *buffer, size_t length, size_t unhashed, FILE *fp) 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; ulong unhashed;
const byte *p; const byte *p;
int is_fpr32; /* blob ersion 2 */ int is_fpr32; /* blob ersion 2 */
int have_ubib = 0;
buffer = _keybox_get_blob_image (blob, &length); buffer = _keybox_get_blob_image (blob, &length);
@ -237,6 +273,14 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
fputs ("ephemeral", fp); fputs ("ephemeral", fp);
any++; any++;
} }
if ((n & 4))
{
if (any)
putc (',', fp);
fputs ("ubid", fp);
any++;
have_ubib = 1;
}
putc (')', fp); putc (')', fp);
} }
putc ('\n', fp); putc ('\n', fp);
@ -422,6 +466,8 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
n = get32 ( buffer + length - unhashed); n = get32 ( buffer + length - unhashed);
fprintf (fp, "Storage-Flags: %08lx\n", n ); fprintf (fp, "Storage-Flags: %08lx\n", n );
} }
if (have_ubib)
print_ubib (buffer, length, fp);
print_checksum (buffer, length, unhashed, fp); print_checksum (buffer, length, unhashed, fp);
return 0; return 0;
} }

View File

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

View File

@ -42,11 +42,21 @@ typedef enum {
KEYDB_SEARCH_MODE_SN, KEYDB_SEARCH_MODE_SN,
KEYDB_SEARCH_MODE_SUBJECT, KEYDB_SEARCH_MODE_SUBJECT,
KEYDB_SEARCH_MODE_KEYGRIP, KEYDB_SEARCH_MODE_KEYGRIP,
KEYDB_SEARCH_MODE_UBID,
KEYDB_SEARCH_MODE_FIRST, KEYDB_SEARCH_MODE_FIRST,
KEYDB_SEARCH_MODE_NEXT KEYDB_SEARCH_MODE_NEXT
} KeydbSearchMode; } 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. */ /* Forward declaration. See g10/packet.h. */
struct gpg_pkt_user_id_s; struct gpg_pkt_user_id_s;
typedef struct gpg_pkt_user_id_s *gpg_pkt_user_id_t; typedef struct gpg_pkt_user_id_s *gpg_pkt_user_id_t;
@ -70,6 +80,7 @@ struct keydb_search_desc
unsigned char fpr[32]; unsigned char fpr[32];
u32 kid[2]; /* Note that this is in native endianness. */ u32 kid[2]; /* Note that this is in native endianness. */
unsigned char grip[20]; unsigned char grip[20];
unsigned char ubid[20];
} u; } u;
byte fprlen; /* Only used with KEYDB_SEARCH_MODE_FPR. */ byte fprlen; /* Only used with KEYDB_SEARCH_MODE_FPR. */
int exact; /* Use exactly this key ('!' suffix in gpg). */ 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; 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 static inline int
has_issuer (KEYBOXBLOB blob, const char *name) 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)) if (has_keygrip (blob, desc[n].u.grip))
goto found; goto found;
break; break;
case KEYDB_SEARCH_MODE_UBID:
if (has_ubid (blob, desc[n].u.ubid))
goto found;
break;
case KEYDB_SEARCH_MODE_FIRST: case KEYDB_SEARCH_MODE_FIRST:
goto found; goto found;
break; break;
@ -1180,11 +1213,70 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
a successful search operation. 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 /* 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 * 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; * index of the key or user id which matched the search criteria; if
* if not known they are set to 0. */ * not known they are set to 0. */
gpg_error_t gpg_error_t
keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf, keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
int *r_pk_no, int *r_uid_no) 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 ) if (!newfp )
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
rc = _keybox_write_header_blob (newfp, for_openpgp); rc = _keybox_write_header_blob (newfp, NULL, for_openpgp);
if (rc) if (rc)
{ {
fclose (newfp); fclose (newfp);
@ -730,7 +730,7 @@ keybox_compress (KEYBOX_HANDLE hd)
} }
/* The header blob is missing. Insert it. */ /* 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) if (rc)
break; break;
any_changes = 1; any_changes = 1;

View File

@ -81,9 +81,13 @@ gpg_error_t keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout);
/*-- keybox-file.c --*/ /*-- keybox-file.c --*/
/* Fixme: This function does not belong here: Provide a better /* Fixme: This function does not belong here: Provide a better
interface to create a new keybox file. */ 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 --*/ /*-- 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, gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
int *r_uid_no, int *r_pk_no); int *r_uid_no, int *r_pk_no);
#ifdef KEYBOX_WITH_X509 #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=xasprintf:1:c-format \
--flag=xtryasprintf:1:c-format \ --flag=xtryasprintf:1:c-format \
--flag=log_debug_with_string:2:c-format \ --flag=log_debug_with_string:2:c-format \
--flag=status_printf:3:c-format \
--flag=print_assuan_status:3:c-format \ --flag=print_assuan_status:3:c-format \
--flag=vprint_assuan_status:3:c-format \ --flag=vprint_assuan_status:3:c-format \
--flag=agent_print_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 /* 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 that the detection magic for OpenPGP keyboxes works the next time
it is used. */ it is used. */
rc = _keybox_write_header_blob (fp, 0); rc = _keybox_write_header_blob (fp, NULL, 0);
if (rc) if (rc)
{ {
fclose (fp); fclose (fp);

View File

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