mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01: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:
commit
9698761933
331
common/asshelp.c
331
common/asshelp.c
@ -56,9 +56,11 @@
|
||||
operation after we started them before giving up. */
|
||||
#ifdef HAVE_W32CE_SYSTEM
|
||||
# define SECS_TO_WAIT_FOR_AGENT 30
|
||||
# define SECS_TO_WAIT_FOR_KEYBOXD 30
|
||||
# define SECS_TO_WAIT_FOR_DIRMNGR 30
|
||||
#else
|
||||
# define SECS_TO_WAIT_FOR_AGENT 5
|
||||
# define SECS_TO_WAIT_FOR_KEYBOXD 5
|
||||
# define SECS_TO_WAIT_FOR_DIRMNGR 5
|
||||
#endif
|
||||
|
||||
@ -308,17 +310,15 @@ unlock_spawning (lock_spawn_t *lock, const char *name)
|
||||
}
|
||||
|
||||
|
||||
/* Helper for start_new_gpg_agent and start_new_dirmngr.
|
||||
* Values for WHICH are:
|
||||
* 0 - Start gpg-agent
|
||||
* 1 - Start dirmngr
|
||||
* SECS give the number of seconds to wait. SOCKNAME is the name of
|
||||
* the socket to connect. VERBOSE is the usual verbose flag. CTX is
|
||||
* the assuan context. DID_SUCCESS_MSG will be set to 1 if a success
|
||||
* messages has been printed.
|
||||
/* Helper to start a service. SECS gives the number of seconds to
|
||||
* wait. SOCKNAME is the name of the socket to connect. VERBOSE is
|
||||
* the usual verbose flag. CTX is the assuan context. CONNECT_FLAGS
|
||||
* are the assuan connect flags. DID_SUCCESS_MSG will be set to 1 if
|
||||
* a success messages has been printed.
|
||||
*/
|
||||
static gpg_error_t
|
||||
wait_for_sock (int secs, int which, const char *sockname,
|
||||
wait_for_sock (int secs, int module_name_id, const char *sockname,
|
||||
unsigned int connect_flags,
|
||||
int verbose, assuan_context_t ctx, int *did_success_msg)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
@ -343,8 +343,10 @@ wait_for_sock (int secs, int which, const char *sockname,
|
||||
/* next_sleep_us); */
|
||||
if (secsleft < lastalert)
|
||||
{
|
||||
log_info (which == 1?
|
||||
log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR?
|
||||
_("waiting for the dirmngr to come up ... (%ds)\n"):
|
||||
module_name_id == GNUPG_MODULE_NAME_KEYBOXD?
|
||||
_("waiting for the keyboxd to come up ... (%ds)\n"):
|
||||
_("waiting for the agent to come up ... (%ds)\n"),
|
||||
secsleft);
|
||||
lastalert = secsleft;
|
||||
@ -352,13 +354,15 @@ wait_for_sock (int secs, int which, const char *sockname,
|
||||
}
|
||||
gnupg_usleep (next_sleep_us);
|
||||
elapsed_us += next_sleep_us;
|
||||
err = assuan_socket_connect (ctx, sockname, 0, 0);
|
||||
err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
|
||||
if (!err)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
log_info (which == 1?
|
||||
log_info (module_name_id == GNUPG_MODULE_NAME_DIRMNGR?
|
||||
_("connection to the dirmngr established\n"):
|
||||
module_name_id == GNUPG_MODULE_NAME_KEYBOXD?
|
||||
_("connection to the keyboxd established\n"):
|
||||
_("connection to the agent established\n"));
|
||||
*did_success_msg = 1;
|
||||
}
|
||||
@ -372,25 +376,35 @@ wait_for_sock (int secs, int which, const char *sockname,
|
||||
}
|
||||
|
||||
|
||||
/* Try to connect to the agent via socket or start it if it is not
|
||||
running and AUTOSTART is set. Handle the server's initial
|
||||
greeting. Returns a new assuan context at R_CTX or an error
|
||||
code. */
|
||||
gpg_error_t
|
||||
start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
gpg_err_source_t errsource,
|
||||
const char *agent_program,
|
||||
const char *opt_lc_ctype,
|
||||
const char *opt_lc_messages,
|
||||
session_env_t session_env,
|
||||
int autostart, int verbose, int debug,
|
||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||
ctrl_t status_cb_arg)
|
||||
/* Try to connect to a new service via socket or start it if it is not
|
||||
* running and AUTOSTART is set. Handle the server's initial
|
||||
* greeting. Returns a new assuan context at R_CTX or an error code.
|
||||
* MODULE_NAME_ID is one of:
|
||||
* GNUPG_MODULE_NAME_AGENT
|
||||
* GNUPG_MODULE_NAME_DIRMNGR
|
||||
*/
|
||||
static gpg_error_t
|
||||
start_new_service (assuan_context_t *r_ctx,
|
||||
int module_name_id,
|
||||
gpg_err_source_t errsource,
|
||||
const char *program_name,
|
||||
const char *opt_lc_ctype,
|
||||
const char *opt_lc_messages,
|
||||
session_env_t session_env,
|
||||
int autostart, int verbose, int debug,
|
||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||
ctrl_t status_cb_arg)
|
||||
{
|
||||
gpg_error_t err;
|
||||
assuan_context_t ctx;
|
||||
int did_success_msg = 0;
|
||||
char *sockname;
|
||||
const char *printed_name;
|
||||
const char *lock_name;
|
||||
const char *status_start_line;
|
||||
int no_service_err;
|
||||
int seconds_to_wait;
|
||||
unsigned int connect_flags = 0;
|
||||
const char *argv[6];
|
||||
|
||||
*r_ctx = NULL;
|
||||
@ -402,15 +416,40 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
return err;
|
||||
}
|
||||
|
||||
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
|
||||
if (!sockname)
|
||||
switch (module_name_id)
|
||||
{
|
||||
err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
|
||||
case GNUPG_MODULE_NAME_AGENT:
|
||||
sockname = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
|
||||
lock_name = "agent";
|
||||
printed_name = "gpg-agent";
|
||||
status_start_line = "starting_agent ? 0 0";
|
||||
no_service_err = GPG_ERR_NO_AGENT;
|
||||
seconds_to_wait = SECS_TO_WAIT_FOR_AGENT;
|
||||
break;
|
||||
case GNUPG_MODULE_NAME_DIRMNGR:
|
||||
sockname = make_filename (gnupg_socketdir (), DIRMNGR_SOCK_NAME, NULL);
|
||||
lock_name = "dirmngr";
|
||||
printed_name = "dirmngr";
|
||||
status_start_line = "starting_dirmngr ? 0 0";
|
||||
no_service_err = GPG_ERR_NO_DIRMNGR;
|
||||
seconds_to_wait = SECS_TO_WAIT_FOR_DIRMNGR;
|
||||
break;
|
||||
case GNUPG_MODULE_NAME_KEYBOXD:
|
||||
sockname = make_filename (gnupg_socketdir (), KEYBOXD_SOCK_NAME, NULL);
|
||||
lock_name = "keyboxd";
|
||||
printed_name = "keyboxd";
|
||||
status_start_line = "starting_keyboxd ? 0 0";
|
||||
no_service_err = GPG_ERR_NO_KEYBOXD;
|
||||
seconds_to_wait = SECS_TO_WAIT_FOR_KEYBOXD;
|
||||
connect_flags |= ASSUAN_SOCKET_CONNECT_FDPASSING;
|
||||
break;
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
assuan_release (ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = assuan_socket_connect (ctx, sockname, 0, 0);
|
||||
err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
|
||||
if (err && autostart)
|
||||
{
|
||||
char *abs_homedir;
|
||||
@ -422,12 +461,12 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
int i;
|
||||
|
||||
/* With no success start a new server. */
|
||||
if (!agent_program || !*agent_program)
|
||||
agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
|
||||
else if ((s=strchr (agent_program, '|')) && s[1] == '-' && s[2]=='-')
|
||||
if (!program_name || !*program_name)
|
||||
program_name = gnupg_module_name (module_name_id);
|
||||
else if ((s=strchr (program_name, '|')) && s[1] == '-' && s[2]=='-')
|
||||
{
|
||||
/* Hack to insert an additional option on the command line. */
|
||||
program = xtrystrdup (agent_program);
|
||||
program = xtrystrdup (program_name);
|
||||
if (!program)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_err_make (errsource,
|
||||
@ -442,22 +481,21 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
log_info (_("no running gpg-agent - starting '%s'\n"),
|
||||
agent_program);
|
||||
log_info (_("no running %s - starting '%s'\n"),
|
||||
printed_name, program_name);
|
||||
|
||||
if (status_cb)
|
||||
status_cb (status_cb_arg, STATUS_PROGRESS,
|
||||
"starting_agent ? 0 0", NULL);
|
||||
status_cb (status_cb_arg, STATUS_PROGRESS, status_start_line, NULL);
|
||||
|
||||
/* We better pass an absolute home directory to the agent just
|
||||
in case gpg-agent does not convert the passed name to an
|
||||
absolute one (which it should do). */
|
||||
/* We better pass an absolute home directory to the service just
|
||||
* in case the service does not convert the passed name to an
|
||||
* absolute one (which it should do). */
|
||||
abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
|
||||
if (!abs_homedir)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_err_make (errsource,
|
||||
gpg_err_code_from_syserror ());
|
||||
log_error ("error building filename: %s\n",gpg_strerror (tmperr));
|
||||
log_error ("error building filename: %s\n", gpg_strerror (tmperr));
|
||||
xfree (sockname);
|
||||
assuan_release (ctx);
|
||||
xfree (program);
|
||||
@ -468,8 +506,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
{
|
||||
gpg_error_t tmperr = gpg_err_make (errsource,
|
||||
gpg_err_code_from_syserror ());
|
||||
log_error ("error flushing pending output: %s\n",
|
||||
strerror (errno));
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
xfree (sockname);
|
||||
assuan_release (ctx);
|
||||
xfree (abs_homedir);
|
||||
@ -477,42 +514,42 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
/* If the agent has been configured for use with a standard
|
||||
socket, an environment variable is not required and thus
|
||||
we can safely start the agent here. */
|
||||
i = 0;
|
||||
argv[i++] = "--homedir";
|
||||
argv[i++] = abs_homedir;
|
||||
argv[i++] = "--use-standard-socket";
|
||||
if (module_name_id == GNUPG_MODULE_NAME_AGENT)
|
||||
argv[i++] = "--use-standard-socket";
|
||||
if (program_arg)
|
||||
argv[i++] = program_arg;
|
||||
argv[i++] = "--daemon";
|
||||
argv[i++] = NULL;
|
||||
|
||||
if (!(err = lock_spawning (&lock, gnupg_homedir (), "agent", verbose))
|
||||
&& assuan_socket_connect (ctx, sockname, 0, 0))
|
||||
if (!(err = lock_spawning (&lock, gnupg_homedir (), lock_name, verbose))
|
||||
&& assuan_socket_connect (ctx, sockname, 0, connect_flags))
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
err = gnupg_spawn_process_detached (program? program : agent_program,
|
||||
err = gnupg_spawn_process_detached (program? program : program_name,
|
||||
argv, NULL);
|
||||
#else
|
||||
#else /*!W32*/
|
||||
pid_t pid;
|
||||
|
||||
err = gnupg_spawn_process_fd (program? program : agent_program,
|
||||
err = gnupg_spawn_process_fd (program? program : program_name,
|
||||
argv, -1, -1, -1, &pid);
|
||||
if (!err)
|
||||
err = gnupg_wait_process (program? program : agent_program,
|
||||
err = gnupg_wait_process (program? program : program_name,
|
||||
pid, 1, NULL);
|
||||
#endif
|
||||
#endif /*!W32*/
|
||||
if (err)
|
||||
log_error ("failed to start agent '%s': %s\n",
|
||||
agent_program, gpg_strerror (err));
|
||||
log_error ("failed to start %s '%s': %s\n",
|
||||
printed_name, program? program : program_name,
|
||||
gpg_strerror (err));
|
||||
else
|
||||
err = wait_for_sock (SECS_TO_WAIT_FOR_AGENT, 0,
|
||||
sockname, verbose, ctx, &did_success_msg);
|
||||
err = wait_for_sock (seconds_to_wait, module_name_id,
|
||||
sockname, connect_flags,
|
||||
verbose, ctx, &did_success_msg);
|
||||
}
|
||||
|
||||
unlock_spawning (&lock, "agent");
|
||||
unlock_spawning (&lock, lock_name);
|
||||
xfree (abs_homedir);
|
||||
xfree (program);
|
||||
}
|
||||
@ -520,17 +557,21 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
if (err)
|
||||
{
|
||||
if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
|
||||
log_error ("can't connect to the agent: %s\n", gpg_strerror (err));
|
||||
log_error ("can't connect to the %s: %s\n",
|
||||
printed_name, gpg_strerror (err));
|
||||
assuan_release (ctx);
|
||||
return gpg_err_make (errsource, GPG_ERR_NO_AGENT);
|
||||
return gpg_err_make (errsource, no_service_err);
|
||||
}
|
||||
|
||||
if (debug && !did_success_msg)
|
||||
log_debug ("connection to the agent established\n");
|
||||
log_debug ("connection to the %s established\n", printed_name);
|
||||
|
||||
err = assuan_transact (ctx, "RESET",
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (!err)
|
||||
if (module_name_id == GNUPG_MODULE_NAME_AGENT)
|
||||
err = assuan_transact (ctx, "RESET",
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (!err
|
||||
&& module_name_id == GNUPG_MODULE_NAME_AGENT)
|
||||
{
|
||||
err = send_pinentry_environment (ctx, errsource,
|
||||
opt_lc_ctype, opt_lc_messages,
|
||||
@ -538,7 +579,7 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
if (gpg_err_code (err) == GPG_ERR_FORBIDDEN
|
||||
&& gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT)
|
||||
{
|
||||
/* Check whether we are in restricted mode. */
|
||||
/* Check whether the agent is in restricted mode. */
|
||||
if (!assuan_transact (ctx, "GETINFO restricted",
|
||||
NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
@ -559,6 +600,45 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
}
|
||||
|
||||
|
||||
/* Try to connect tothe agent or start a new one. */
|
||||
gpg_error_t
|
||||
start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
gpg_err_source_t errsource,
|
||||
const char *agent_program,
|
||||
const char *opt_lc_ctype,
|
||||
const char *opt_lc_messages,
|
||||
session_env_t session_env,
|
||||
int autostart, int verbose, int debug,
|
||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||
ctrl_t status_cb_arg)
|
||||
{
|
||||
return start_new_service (r_ctx, GNUPG_MODULE_NAME_AGENT,
|
||||
errsource, agent_program,
|
||||
opt_lc_ctype, opt_lc_messages, session_env,
|
||||
autostart, verbose, debug,
|
||||
status_cb, status_cb_arg);
|
||||
}
|
||||
|
||||
|
||||
/* Try to connect to the dirmngr via a socket. On platforms
|
||||
supporting it, start it up if needed and if AUTOSTART is true.
|
||||
Returns a new assuan context at R_CTX or an error code. */
|
||||
gpg_error_t
|
||||
start_new_keyboxd (assuan_context_t *r_ctx,
|
||||
gpg_err_source_t errsource,
|
||||
const char *keyboxd_program,
|
||||
int autostart, int verbose, int debug,
|
||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||
ctrl_t status_cb_arg)
|
||||
{
|
||||
return start_new_service (r_ctx, GNUPG_MODULE_NAME_KEYBOXD,
|
||||
errsource, keyboxd_program,
|
||||
NULL, NULL, NULL,
|
||||
autostart, verbose, debug,
|
||||
status_cb, status_cb_arg);
|
||||
}
|
||||
|
||||
|
||||
/* Try to connect to the dirmngr via a socket. On platforms
|
||||
supporting it, start it up if needed and if AUTOSTART is true.
|
||||
Returns a new assuan context at R_CTX or an error code. */
|
||||
@ -566,119 +646,18 @@ gpg_error_t
|
||||
start_new_dirmngr (assuan_context_t *r_ctx,
|
||||
gpg_err_source_t errsource,
|
||||
const char *dirmngr_program,
|
||||
int autostart,
|
||||
int verbose, int debug,
|
||||
int autostart, int verbose, int debug,
|
||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||
ctrl_t status_cb_arg)
|
||||
{
|
||||
gpg_error_t err;
|
||||
assuan_context_t ctx;
|
||||
const char *sockname;
|
||||
int did_success_msg = 0;
|
||||
|
||||
*r_ctx = NULL;
|
||||
|
||||
err = assuan_new (&ctx);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error allocating assuan context: %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
sockname = dirmngr_socket_name ();
|
||||
err = assuan_socket_connect (ctx, sockname, 0, 0);
|
||||
|
||||
#ifdef USE_DIRMNGR_AUTO_START
|
||||
if (err && autostart)
|
||||
{
|
||||
lock_spawn_t lock;
|
||||
const char *argv[4];
|
||||
char *abs_homedir;
|
||||
|
||||
/* No connection: Try start a new Dirmngr. */
|
||||
if (!dirmngr_program || !*dirmngr_program)
|
||||
dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
|
||||
|
||||
if (verbose)
|
||||
log_info (_("no running dirmngr - starting '%s'\n"),
|
||||
dirmngr_program);
|
||||
|
||||
if (status_cb)
|
||||
status_cb (status_cb_arg, STATUS_PROGRESS,
|
||||
"starting_dirmngr ? 0 0", NULL);
|
||||
|
||||
abs_homedir = make_absfilename (gnupg_homedir (), NULL);
|
||||
if (!abs_homedir)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_err_make (errsource,
|
||||
gpg_err_code_from_syserror ());
|
||||
log_error ("error building filename: %s\n",gpg_strerror (tmperr));
|
||||
assuan_release (ctx);
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
if (fflush (NULL))
|
||||
{
|
||||
gpg_error_t tmperr = gpg_err_make (errsource,
|
||||
gpg_err_code_from_syserror ());
|
||||
log_error ("error flushing pending output: %s\n",
|
||||
strerror (errno));
|
||||
assuan_release (ctx);
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
argv[0] = "--daemon";
|
||||
/* Try starting the daemon. Versions of dirmngr < 2.1.15 do
|
||||
* this only if the home directory is given on the command line. */
|
||||
argv[1] = "--homedir";
|
||||
argv[2] = abs_homedir;
|
||||
argv[3] = NULL;
|
||||
|
||||
if (!(err = lock_spawning (&lock, gnupg_homedir (), "dirmngr", verbose))
|
||||
&& assuan_socket_connect (ctx, sockname, 0, 0))
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
err = gnupg_spawn_process_detached (dirmngr_program, argv, NULL);
|
||||
#else
|
||||
pid_t pid;
|
||||
|
||||
err = gnupg_spawn_process_fd (dirmngr_program, argv,
|
||||
-1, -1, -1, &pid);
|
||||
if (!err)
|
||||
err = gnupg_wait_process (dirmngr_program, pid, 1, NULL);
|
||||
#ifndef USE_DIRMNGR_AUTO_START
|
||||
autostart = 0;
|
||||
#endif
|
||||
if (err)
|
||||
log_error ("failed to start the dirmngr '%s': %s\n",
|
||||
dirmngr_program, gpg_strerror (err));
|
||||
else
|
||||
err = wait_for_sock (SECS_TO_WAIT_FOR_DIRMNGR, 1,
|
||||
sockname, verbose, ctx, &did_success_msg);
|
||||
}
|
||||
|
||||
unlock_spawning (&lock, "dirmngr");
|
||||
xfree (abs_homedir);
|
||||
}
|
||||
#else
|
||||
(void)dirmngr_program;
|
||||
(void)verbose;
|
||||
(void)status_cb;
|
||||
(void)status_cb_arg;
|
||||
#endif /*USE_DIRMNGR_AUTO_START*/
|
||||
|
||||
if (err)
|
||||
{
|
||||
if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
|
||||
log_error ("connecting dirmngr at '%s' failed: %s\n",
|
||||
sockname, gpg_strerror (err));
|
||||
assuan_release (ctx);
|
||||
return gpg_err_make (errsource, GPG_ERR_NO_DIRMNGR);
|
||||
}
|
||||
|
||||
if (debug && !did_success_msg)
|
||||
log_debug ("connection to the dirmngr established\n");
|
||||
|
||||
*r_ctx = ctx;
|
||||
return 0;
|
||||
return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
|
||||
errsource, dirmngr_program,
|
||||
NULL, NULL, NULL,
|
||||
autostart, verbose, debug,
|
||||
status_cb, status_cb_arg);
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,6 +65,16 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||
ctrl_t status_cb_arg);
|
||||
|
||||
/* This function is used to connect to the keyboxd. If needed the
|
||||
* keyboxd is started. */
|
||||
gpg_error_t
|
||||
start_new_keyboxd (assuan_context_t *r_ctx,
|
||||
gpg_err_source_t errsource,
|
||||
const char *keyboxd_program,
|
||||
int autostart, int verbose, int debug,
|
||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||
ctrl_t status_cb_arg);
|
||||
|
||||
/* This function is used to connect to the dirmngr. On some platforms
|
||||
the function is able starts a dirmngr process if needed. */
|
||||
gpg_error_t
|
||||
@ -82,8 +92,16 @@ gpg_error_t get_assuan_server_version (assuan_context_t ctx,
|
||||
|
||||
/*-- asshelp2.c --*/
|
||||
|
||||
void set_assuan_context_func (assuan_context_t (*func)(ctrl_t ctrl));
|
||||
|
||||
/* Helper function to print an assuan status line using a printf
|
||||
format string. */
|
||||
|
||||
gpg_error_t status_printf (ctrl_t ctrl, const char *keyword, const char *format,
|
||||
...) GPGRT_ATTR_PRINTF(3,4);
|
||||
gpg_error_t status_no_printf (ctrl_t ctrl, int no, const char *format,
|
||||
...) GPGRT_ATTR_PRINTF(3,4);
|
||||
|
||||
gpg_error_t print_assuan_status (assuan_context_t ctx,
|
||||
const char *keyword,
|
||||
const char *format,
|
||||
|
@ -36,6 +36,24 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "asshelp.h"
|
||||
#include "status.h"
|
||||
|
||||
|
||||
/* A variable with a function to be used to return the current assuan
|
||||
* context for a CTRL variable. This needs to be set using the
|
||||
* set_assuan_ctx_func function. */
|
||||
static assuan_context_t (*the_assuan_ctx_func)(ctrl_t ctrl);
|
||||
|
||||
|
||||
/* Set FUNC to be used as a mapping fucntion from CTRL to an assuan
|
||||
* context. Pass NULL for FUNC to disable the use of the assuan
|
||||
* context in this module. */
|
||||
void
|
||||
set_assuan_context_func (assuan_context_t (*func)(ctrl_t ctrl))
|
||||
{
|
||||
the_assuan_ctx_func = func;
|
||||
}
|
||||
|
||||
|
||||
/* Helper function to print an assuan status line using a printf
|
||||
format string. */
|
||||
@ -134,3 +152,41 @@ print_assuan_status_strings (assuan_context_t ctx, const char *keyword, ...)
|
||||
va_end (arg_ptr);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* This function is similar to print_assuan_status but takes a CTRL
|
||||
* arg instead of an assuan context as first argument. */
|
||||
gpg_error_t
|
||||
status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...)
|
||||
{
|
||||
gpg_error_t err;
|
||||
va_list arg_ptr;
|
||||
assuan_context_t ctx;
|
||||
|
||||
if (!ctrl || !the_assuan_ctx_func || !(ctx = the_assuan_ctx_func (ctrl)))
|
||||
return 0;
|
||||
|
||||
va_start (arg_ptr, format);
|
||||
err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
|
||||
va_end (arg_ptr);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Same as sytus_printf but takes a status number instead of a
|
||||
* keyword. */
|
||||
gpg_error_t
|
||||
status_no_printf (ctrl_t ctrl, int no, const char *format, ...)
|
||||
{
|
||||
gpg_error_t err;
|
||||
va_list arg_ptr;
|
||||
assuan_context_t ctx;
|
||||
|
||||
if (!ctrl || !the_assuan_ctx_func || !(ctx = the_assuan_ctx_func (ctrl)))
|
||||
return 0;
|
||||
|
||||
va_start (arg_ptr, format);
|
||||
err = vprint_assuan_status (ctx, get_status_string (no), format, arg_ptr);
|
||||
va_end (arg_ptr);
|
||||
return err;
|
||||
}
|
||||
|
@ -945,6 +945,17 @@ gnupg_cachedir (void)
|
||||
}
|
||||
|
||||
|
||||
/* Return the standard socket name used by gpg-agent. */
|
||||
const char *
|
||||
gpg_agent_socket_name (void)
|
||||
{
|
||||
static char *name;
|
||||
|
||||
if (!name)
|
||||
name = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
|
||||
return name;
|
||||
}
|
||||
|
||||
/* Return the user socket name used by DirMngr. */
|
||||
const char *
|
||||
dirmngr_socket_name (void)
|
||||
@ -1104,6 +1115,13 @@ gnupg_module_name (int which)
|
||||
X(bindir, "dirmngr", DIRMNGR_NAME);
|
||||
#endif
|
||||
|
||||
case GNUPG_MODULE_NAME_KEYBOXD:
|
||||
#ifdef GNUPG_DEFAULT_KEYBOXD
|
||||
return GNUPG_DEFAULT_KEYBOXD;
|
||||
#else
|
||||
X(bindir, "keyboxd", KEYBOXD_NAME);
|
||||
#endif
|
||||
|
||||
case GNUPG_MODULE_NAME_PROTECT_TOOL:
|
||||
#ifdef GNUPG_DEFAULT_PROTECT_TOOL
|
||||
return GNUPG_DEFAULT_PROTECT_TOOL;
|
||||
|
@ -106,6 +106,8 @@ typedef struct
|
||||
int keep_open;
|
||||
int no_cache;
|
||||
int eof_seen;
|
||||
int use_readlimit; /* Take care of the readlimit. */
|
||||
size_t readlimit; /* Number of bytes left to read. */
|
||||
int print_only_name; /* Flags indicating that fname is not a real file. */
|
||||
char fname[1]; /* Name of the file. */
|
||||
} file_es_filter_ctx_t;
|
||||
@ -635,6 +637,34 @@ file_es_filter (void *opaque, int control, iobuf_t chain, byte * buf,
|
||||
rc = -1;
|
||||
*ret_len = 0;
|
||||
}
|
||||
else if (a->use_readlimit)
|
||||
{
|
||||
nbytes = 0;
|
||||
if (!a->readlimit)
|
||||
{ /* eof */
|
||||
a->eof_seen = 1;
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size > a->readlimit)
|
||||
size = a->readlimit;
|
||||
rc = es_read (f, buf, size, &nbytes);
|
||||
if (rc == -1)
|
||||
{ /* error */
|
||||
rc = gpg_error_from_syserror ();
|
||||
log_error ("%s: read error: %s\n", a->fname,strerror (errno));
|
||||
}
|
||||
else if (!nbytes)
|
||||
{ /* eof */
|
||||
a->eof_seen = 1;
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
a->readlimit -= nbytes;
|
||||
}
|
||||
*ret_len = nbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
nbytes = 0;
|
||||
@ -1412,7 +1442,8 @@ iobuf_fdopen_nc (int fd, const char *mode)
|
||||
|
||||
|
||||
iobuf_t
|
||||
iobuf_esopen (estream_t estream, const char *mode, int keep_open)
|
||||
iobuf_esopen (estream_t estream, const char *mode, int keep_open,
|
||||
size_t readlimit)
|
||||
{
|
||||
iobuf_t a;
|
||||
file_es_filter_ctx_t *fcx;
|
||||
@ -1424,7 +1455,9 @@ iobuf_esopen (estream_t estream, const char *mode, int keep_open)
|
||||
fcx->fp = estream;
|
||||
fcx->print_only_name = 1;
|
||||
fcx->keep_open = keep_open;
|
||||
sprintf (fcx->fname, "[fd %p]", estream);
|
||||
fcx->readlimit = readlimit;
|
||||
fcx->use_readlimit = !!readlimit;
|
||||
snprintf (fcx->fname, 30, "[fd %p]", estream);
|
||||
a->filter = file_es_filter;
|
||||
a->filter_ov = fcx;
|
||||
file_es_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
|
||||
|
@ -328,8 +328,10 @@ iobuf_t iobuf_fdopen_nc (int fd, const char *mode);
|
||||
letter 'w', creates an output filter. Otherwise, creates an input
|
||||
filter. If KEEP_OPEN is TRUE, then the stream is not closed when
|
||||
the filter is destroyed. Otherwise, the stream is closed when the
|
||||
filter is destroyed. */
|
||||
iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open);
|
||||
filter is destroyed. If READLIMIT is not 0 this gives a limit on
|
||||
the number of bytes to read from estream. */
|
||||
iobuf_t iobuf_esopen (estream_t estream, const char *mode, int keep_open,
|
||||
size_t readlimit);
|
||||
|
||||
/* Create a filter using an existing socket. On Windows creates a
|
||||
special socket filter. On non-Windows systems simply, this simply
|
||||
|
@ -77,6 +77,12 @@ run_mbox_test (void)
|
||||
{ "<fo()o@example.org> ()", "fo()o@example.org" },
|
||||
{ "fo()o@example.org", NULL},
|
||||
{ "Mr. Foo <foo@example.org><bar@example.net>", "foo@example.org"},
|
||||
{ "Surname, Forename | company <foo@example.org>", "foo@example.org"},
|
||||
/* The next one is for sure not RFC-822 correct but nevertheless
|
||||
* the way gpg does it. We won't change it because the user-id
|
||||
* is only rfc-822 alike and not compliant (think only of our
|
||||
* utf-8 requirement). */
|
||||
{ "\"<foo@example.org>\" <foo@example.net>", "foo@example.org"},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
int idx;
|
||||
|
@ -65,6 +65,9 @@
|
||||
* (note that you can't search for these characters). Compare
|
||||
* is not case sensitive.
|
||||
* - If the userid starts with a '&' a 40 hex digits keygrip is expected.
|
||||
* - If the userid starts with a '^' followed by 40 hex digits it describes
|
||||
* a Unique-Blob-ID (UBID) which is the hash of keyblob or certificate as
|
||||
* stored in the database. This is used in the IPC of the keyboxd.
|
||||
*/
|
||||
|
||||
gpg_error_t
|
||||
@ -251,6 +254,17 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
|
||||
}
|
||||
break;
|
||||
|
||||
case '^': /* UBID */
|
||||
{
|
||||
if (hex2bin (s+1, desc->u.ubid, 20) < 0)
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
|
||||
goto out;
|
||||
}
|
||||
mode = KEYDB_SEARCH_MODE_UBID;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (s[0] == '0' && s[1] == 'x')
|
||||
{
|
||||
|
@ -43,6 +43,10 @@
|
||||
#define GPG_ERR_NO_AUTH 314
|
||||
#define GPG_ERR_BAD_AUTH 315
|
||||
#endif /*GPG_ERROR_VERSION_NUMBER*/
|
||||
#if GPG_ERROR_VERSION_NUMBER < 0x012500 /* 1.37 */
|
||||
#define GPG_ERR_NO_KEYBOXD 316
|
||||
#define GPG_ERR_KEYBOXD 317
|
||||
#endif /*GPG_ERROR_VERSION_NUMBER*/
|
||||
|
||||
/* Hash function used with libksba. */
|
||||
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
|
||||
@ -243,6 +247,7 @@ const char *gnupg_libdir (void);
|
||||
const char *gnupg_datadir (void);
|
||||
const char *gnupg_localedir (void);
|
||||
const char *gnupg_cachedir (void);
|
||||
const char *gpg_agent_socket_name (void);
|
||||
const char *dirmngr_socket_name (void);
|
||||
|
||||
char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
|
||||
@ -261,6 +266,7 @@ char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
|
||||
#define GNUPG_MODULE_NAME_GPGCONF 10
|
||||
#define GNUPG_MODULE_NAME_DIRMNGR_LDAP 11
|
||||
#define GNUPG_MODULE_NAME_GPGV 12
|
||||
#define GNUPG_MODULE_NAME_KEYBOXD 13
|
||||
const char *gnupg_module_name (int which);
|
||||
void gnupg_module_name_flush_some (void);
|
||||
void gnupg_set_builddir (const char *newdir);
|
||||
|
18
configure.ac
18
configure.ac
@ -56,7 +56,7 @@ AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg24", [swdb tag for this branch])
|
||||
NEED_GPG_ERROR_VERSION=1.29
|
||||
|
||||
NEED_LIBGCRYPT_API=1
|
||||
NEED_LIBGCRYPT_VERSION=1.7.0
|
||||
NEED_LIBGCRYPT_VERSION=1.8.0
|
||||
|
||||
NEED_LIBASSUAN_API=2
|
||||
NEED_LIBASSUAN_VERSION=2.5.0
|
||||
@ -191,6 +191,14 @@ AM_CONDITIONAL(GNUPG_DIRMNGR_PGM, test -n "$GNUPG_DIRMNGR_PGM")
|
||||
show_gnupg_dirmngr_pgm="(default)"
|
||||
test -n "$GNUPG_DIRMNGR_PGM" && show_gnupg_dirmngr_pgm="$GNUPG_DIRMNGR_PGM"
|
||||
|
||||
AC_ARG_WITH(keyboxd-pgm,
|
||||
[ --with-keyboxd-pgm=PATH Use PATH as the default for the keyboxd)],
|
||||
GNUPG_KEYBOXD_PGM="$withval", GNUPG_KEYBOXD_PGM="" )
|
||||
AC_SUBST(GNUPG_KEYBOXD_PGM)
|
||||
AM_CONDITIONAL(GNUPG_KEYBOXD_PGM, test -n "$GNUPG_KEYBOXD_PGM")
|
||||
show_gnupg_keyboxd_pgm="(default)"
|
||||
test -n "$GNUPG_KEYBOXD_PGM" && show_gnupg_keyboxd_pgm="$GNUPG_KEYBOXD_PGM"
|
||||
|
||||
AC_ARG_WITH(protect-tool-pgm,
|
||||
[ --with-protect-tool-pgm=PATH Use PATH as the default for the protect-tool)],
|
||||
GNUPG_PROTECT_TOOL_PGM="$withval", GNUPG_PROTECT_TOOL_PGM="" )
|
||||
@ -508,6 +516,7 @@ AH_BOTTOM([
|
||||
#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
|
||||
#endif
|
||||
#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
|
||||
#define GNUPG_PUBLIC_KEYS_DIR "public-keys.d"
|
||||
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
|
||||
#define GNUPG_CACHE_DIR "cache.d"
|
||||
|
||||
@ -1888,6 +1897,10 @@ AC_DEFINE_UNQUOTED(DIRMNGR_NAME, "dirmngr", [The name of the dirmngr])
|
||||
AC_DEFINE_UNQUOTED(DIRMNGR_DISP_NAME, "DirMngr",
|
||||
[The displayed name of dirmngr])
|
||||
|
||||
AC_DEFINE_UNQUOTED(KEYBOXD_NAME, "keyboxd", [The name of the keyboxd])
|
||||
AC_DEFINE_UNQUOTED(KEYBOXD_DISP_NAME, "Keyboxd",
|
||||
[The displayed name of keyboxd])
|
||||
|
||||
AC_DEFINE_UNQUOTED(G13_NAME, "g13", [The name of the g13 tool])
|
||||
AC_DEFINE_UNQUOTED(G13_DISP_NAME, "G13", [The displayed name of g13])
|
||||
|
||||
@ -1909,6 +1922,8 @@ AC_DEFINE_UNQUOTED(DIRMNGR_INFO_NAME, "DIRMNGR_INFO",
|
||||
[The name of the dirmngr info envvar])
|
||||
AC_DEFINE_UNQUOTED(SCDAEMON_SOCK_NAME, "S.scdaemon",
|
||||
[The name of the SCdaemon socket])
|
||||
AC_DEFINE_UNQUOTED(KEYBOXD_SOCK_NAME, "S.keyboxd",
|
||||
[The name of the keyboxd socket])
|
||||
AC_DEFINE_UNQUOTED(DIRMNGR_SOCK_NAME, "S.dirmngr",
|
||||
[The name of the dirmngr socket])
|
||||
AC_DEFINE_UNQUOTED(DIRMNGR_DEFAULT_KEYSERVER,
|
||||
@ -2106,6 +2121,7 @@ echo "
|
||||
Default agent: $show_gnupg_agent_pgm
|
||||
Default pinentry: $show_gnupg_pinentry_pgm
|
||||
Default scdaemon: $show_gnupg_scdaemon_pgm
|
||||
Default keyboxd: $show_gnupg_keyboxd_pgm
|
||||
Default dirmngr: $show_gnupg_dirmngr_pgm
|
||||
|
||||
Dirmngr auto start: $dirmngr_auto_start
|
||||
|
12
doc/DETAILS
12
doc/DETAILS
@ -1138,6 +1138,18 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
|
||||
*** BEGIN_STREAM, END_STREAM
|
||||
Used to issued by the experimental pipemode.
|
||||
|
||||
** Inter-component codes
|
||||
Status codes are also used between the components of the GnuPG
|
||||
system via the Assuan S lines. Some of them are documented here:
|
||||
|
||||
*** PUBKEY_INFO <n> <ubid>
|
||||
The type of the public key in the following D-lines or
|
||||
communicated via a pipe. <n> is the value of =enum pubkey_types=
|
||||
and <ubid> the Unique Blob ID (UBID) which is a SHA-1 digest the
|
||||
entire blob here formatted in hex. The consumer of this status
|
||||
line should be prepared to see a <ubid> of up to 64 characters.
|
||||
Note that the keyboxd SEARCH command can be used to lookup the
|
||||
public key using the <ubid> prefixed with a caret (^).
|
||||
|
||||
* Format of the --attribute-fd output
|
||||
|
||||
|
@ -1328,11 +1328,22 @@ Specify the directory manager (keyserver client) program to be started
|
||||
if none is running. This has only an effect if used together with the
|
||||
option @option{--dirmngr}.
|
||||
|
||||
@item --keyboxd-program @var{file}
|
||||
@opindex keyboxd-program
|
||||
Specify the keybox daemon program to be started if none is running.
|
||||
This has only an effect if used together with the option
|
||||
@option{--keyboxd}.
|
||||
|
||||
@item --dirmngr
|
||||
@opindex dirmngr
|
||||
Connect to a running directory manager (keyserver client) instead of
|
||||
to the gpg-agent. If a dirmngr is not running, start it.
|
||||
|
||||
@item --keyboxd
|
||||
@opindex keyboxd
|
||||
Connect to a running keybox daemon instead of
|
||||
to the gpg-agent. If a keyboxd is not running, start it.
|
||||
|
||||
@item -S
|
||||
@itemx --raw-socket @var{name}
|
||||
@opindex raw-socket
|
||||
|
@ -29,9 +29,9 @@ AM_CPPFLAGS =
|
||||
include $(top_srcdir)/am/cmacros.am
|
||||
|
||||
AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \
|
||||
$(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
|
||||
$(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) $(GPG_ERROR_CFLAGS)
|
||||
|
||||
needed_libs = ../kbx/libkeybox.a $(libcommon)
|
||||
needed_libs = ../kbx/libkeybox.a $(libcommonpth)
|
||||
|
||||
# Because there are no program specific transform macros we need to
|
||||
# work around that to allow installing gpg as gpg2.
|
||||
@ -50,9 +50,9 @@ noinst_PROGRAMS = gpg
|
||||
if !HAVE_W32CE_SYSTEM
|
||||
noinst_PROGRAMS += gpgv
|
||||
endif
|
||||
if MAINTAINER_MODE
|
||||
noinst_PROGRAMS += gpgcompose
|
||||
endif
|
||||
#if MAINTAINER_MODE
|
||||
#noinst_PROGRAMS += gpgcompose
|
||||
#endif
|
||||
noinst_PROGRAMS += $(module_tests)
|
||||
TESTS = $(module_tests)
|
||||
TESTS_ENVIRONMENT = \
|
||||
@ -100,7 +100,10 @@ common_source = \
|
||||
free-packet.c \
|
||||
getkey.c \
|
||||
expand-group.c \
|
||||
keydb.c keydb.h \
|
||||
keydb.h \
|
||||
keydb-private.h \
|
||||
call-keyboxd.c \
|
||||
keydb.c \
|
||||
keyring.c keyring.h \
|
||||
seskey.c \
|
||||
kbnode.c \
|
||||
@ -161,7 +164,7 @@ gpg_SOURCES = gpg.c \
|
||||
keyedit.c keyedit.h \
|
||||
$(gpg_sources)
|
||||
|
||||
gpgcompose_SOURCES = gpgcompose.c $(gpg_sources)
|
||||
#gpgcompose_SOURCES = gpgcompose.c $(gpg_sources)
|
||||
gpgv_SOURCES = gpgv.c \
|
||||
$(common_source) \
|
||||
verify.c
|
||||
@ -176,33 +179,36 @@ gpgv_SOURCES = gpgv.c \
|
||||
LDADD = $(needed_libs) ../common/libgpgrl.a \
|
||||
$(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS)
|
||||
gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
|
||||
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBICONV) $(resource_objs) $(extra_sys_libs)
|
||||
gpg_LDFLAGS = $(extra_bin_ldflags)
|
||||
gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
|
||||
$(GPG_ERROR_LIBS) \
|
||||
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBICONV) $(resource_objs) $(extra_sys_libs)
|
||||
gpgv_LDFLAGS = $(extra_bin_ldflags)
|
||||
|
||||
gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
|
||||
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBICONV) $(resource_objs) $(extra_sys_libs)
|
||||
gpgcompose_LDFLAGS = $(extra_bin_ldflags)
|
||||
#gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
|
||||
# $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
|
||||
# $(LIBICONV) $(resource_objs) $(extra_sys_libs)
|
||||
#gpgcompose_LDFLAGS = $(extra_bin_ldflags)
|
||||
|
||||
t_common_ldadd =
|
||||
module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter
|
||||
t_rmd160_SOURCES = t-rmd160.c rmd160.c
|
||||
t_rmd160_LDADD = $(t_common_ldadd)
|
||||
t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source)
|
||||
t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
|
||||
t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
|
||||
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBICONV) $(t_common_ldadd)
|
||||
t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \
|
||||
$(common_source)
|
||||
t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
|
||||
t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
|
||||
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBICONV) $(t_common_ldadd)
|
||||
t_stutter_SOURCES = t-stutter.c test-stubs.c \
|
||||
$(common_source)
|
||||
t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
|
||||
t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
|
||||
$(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
|
||||
$(LIBICONV) $(t_common_ldadd)
|
||||
|
||||
|
||||
|
1112
g10/call-keyboxd.c
Normal file
1112
g10/call-keyboxd.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -475,7 +475,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
|
||||
rc = get_output_file ("", 0, ed->buf, &filename, &fp);
|
||||
if (! rc)
|
||||
{
|
||||
iobuf_t output = iobuf_esopen (fp, "w", 0);
|
||||
iobuf_t output = iobuf_esopen (fp, "w", 0, 0);
|
||||
armor_filter_context_t *afx = NULL;
|
||||
|
||||
if (opt.armor)
|
||||
|
@ -65,7 +65,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
|
||||
|
||||
*r_sec_avail = 0;
|
||||
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
if (!hd)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
@ -131,7 +131,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
|
||||
|
||||
if (!secret && !force)
|
||||
{
|
||||
if (have_secret_key_with_kid (keyid))
|
||||
if (have_secret_key_with_kid (ctrl, keyid))
|
||||
{
|
||||
*r_sec_avail = 1;
|
||||
err = gpg_error (GPG_ERR_EOF);
|
||||
@ -141,7 +141,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (secret && !have_secret_key_with_kid (keyid))
|
||||
if (secret && !have_secret_key_with_kid (ctrl, keyid))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
log_error (_("key \"%s\" not found\n"), username);
|
||||
|
@ -1877,7 +1877,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
|
||||
stats = &dummystats;
|
||||
*any = 0;
|
||||
init_packet (&pkt);
|
||||
kdbhd = keydb_new ();
|
||||
kdbhd = keydb_new (ctrl);
|
||||
if (!kdbhd)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
|
34
g10/getkey.c
34
g10/getkey.c
@ -403,7 +403,7 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.kr_handle = keydb_new ();
|
||||
ctx.kr_handle = keydb_new (ctrl);
|
||||
if (!ctx.kr_handle)
|
||||
{
|
||||
rc = gpg_error_from_syserror ();
|
||||
@ -448,7 +448,7 @@ leave:
|
||||
* Return the public key in *PK. The resources in *PK should be
|
||||
* released using release_public_key_parts(). */
|
||||
int
|
||||
get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
|
||||
get_pubkey_fast (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
|
||||
{
|
||||
int rc = 0;
|
||||
KEYDB_HANDLE hd;
|
||||
@ -476,7 +476,7 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
|
||||
}
|
||||
#endif
|
||||
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
if (!hd)
|
||||
return gpg_error_from_syserror ();
|
||||
rc = keydb_search_kid (hd, keyid);
|
||||
@ -550,7 +550,7 @@ get_pubkeyblock (ctrl_t ctrl, u32 * keyid)
|
||||
memset (&ctx, 0, sizeof ctx);
|
||||
/* No need to set exact here because we want the entire block. */
|
||||
ctx.not_allocated = 1;
|
||||
ctx.kr_handle = keydb_new ();
|
||||
ctx.kr_handle = keydb_new (ctrl);
|
||||
if (!ctx.kr_handle)
|
||||
return NULL;
|
||||
ctx.nitems = 1;
|
||||
@ -592,7 +592,7 @@ get_seckey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid)
|
||||
memset (&ctx, 0, sizeof ctx);
|
||||
ctx.exact = 1; /* Use the key ID exactly as given. */
|
||||
ctx.not_allocated = 1;
|
||||
ctx.kr_handle = keydb_new ();
|
||||
ctx.kr_handle = keydb_new (ctrl);
|
||||
if (!ctx.kr_handle)
|
||||
return gpg_error_from_syserror ();
|
||||
ctx.nitems = 1;
|
||||
@ -807,7 +807,7 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
|
||||
}
|
||||
|
||||
ctx->want_secret = want_secret;
|
||||
ctx->kr_handle = keydb_new ();
|
||||
ctx->kr_handle = keydb_new (ctrl);
|
||||
if (!ctx->kr_handle)
|
||||
{
|
||||
rc = gpg_error_from_syserror ();
|
||||
@ -1448,7 +1448,7 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
ctx->kr_handle = keydb_new ();
|
||||
ctx->kr_handle = keydb_new (ctrl);
|
||||
if (! ctx->kr_handle)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
@ -1594,7 +1594,7 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
|
||||
ctx.not_allocated = 1;
|
||||
/* FIXME: We should get the handle from the cache like we do in
|
||||
* get_pubkey. */
|
||||
ctx.kr_handle = keydb_new ();
|
||||
ctx.kr_handle = keydb_new (ctrl);
|
||||
if (!ctx.kr_handle)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
@ -1632,13 +1632,14 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
|
||||
* Like get_pubkey_byfprint, PK may be NULL. In that case, this
|
||||
* function effectively just checks for the existence of the key. */
|
||||
gpg_error_t
|
||||
get_pubkey_byfprint_fast (PKT_public_key * pk,
|
||||
get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key * pk,
|
||||
const byte * fprint, size_t fprint_len)
|
||||
{
|
||||
gpg_error_t err;
|
||||
KBNODE keyblock;
|
||||
|
||||
err = get_keyblock_byfprint_fast (&keyblock, NULL, fprint, fprint_len, 0);
|
||||
err = get_keyblock_byfprint_fast (ctrl,
|
||||
&keyblock, NULL, fprint, fprint_len, 0);
|
||||
if (!err)
|
||||
{
|
||||
if (pk)
|
||||
@ -1658,7 +1659,8 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
|
||||
* it may have a value of NULL, though. This allows to do an insert
|
||||
* operation on a locked keydb handle. */
|
||||
gpg_error_t
|
||||
get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
|
||||
get_keyblock_byfprint_fast (ctrl_t ctrl,
|
||||
kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
|
||||
const byte *fprint, size_t fprint_len, int lock)
|
||||
{
|
||||
gpg_error_t err;
|
||||
@ -1675,7 +1677,7 @@ get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
|
||||
for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++)
|
||||
fprbuf[i] = fprint[i];
|
||||
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
if (!hd)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
@ -1757,7 +1759,7 @@ parse_def_secret_key (ctrl_t ctrl)
|
||||
|
||||
if (! hd)
|
||||
{
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
if (!hd)
|
||||
return NULL;
|
||||
}
|
||||
@ -2732,7 +2734,7 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
|
||||
* reason to check that an ultimately trusted key is
|
||||
* still valid - if it has been revoked the user
|
||||
* should also remove the ultimate trust flag. */
|
||||
if (get_pubkey_fast (ultimate_pk, sig->keyid) == 0
|
||||
if (get_pubkey_fast (ctrl, ultimate_pk, sig->keyid) == 0
|
||||
&& check_key_signature2 (ctrl,
|
||||
keyblock, k, ultimate_pk,
|
||||
NULL, NULL, NULL, NULL) == 0
|
||||
@ -4117,7 +4119,7 @@ key_origin_string (int origin)
|
||||
the secret key is valid; this check merely indicates whether there
|
||||
is some secret key with the specified key id. */
|
||||
int
|
||||
have_secret_key_with_kid (u32 *keyid)
|
||||
have_secret_key_with_kid (ctrl_t ctrl, u32 *keyid)
|
||||
{
|
||||
gpg_error_t err;
|
||||
KEYDB_HANDLE kdbhd;
|
||||
@ -4126,7 +4128,7 @@ have_secret_key_with_kid (u32 *keyid)
|
||||
kbnode_t node;
|
||||
int result = 0;
|
||||
|
||||
kdbhd = keydb_new ();
|
||||
kdbhd = keydb_new (ctrl);
|
||||
if (!kdbhd)
|
||||
return 0;
|
||||
memset (&desc, 0, sizeof desc);
|
||||
|
35
g10/gpg.c
35
g10/gpg.c
@ -36,6 +36,7 @@
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#endif
|
||||
#include <npth.h>
|
||||
|
||||
#define INCLUDED_BY_MAIN_MODULE 1
|
||||
#include "gpg.h"
|
||||
@ -361,6 +362,7 @@ enum cmd_and_opt_values
|
||||
oUseAgent,
|
||||
oNoUseAgent,
|
||||
oGpgAgentInfo,
|
||||
oUseKeyboxd,
|
||||
oMergeOnly,
|
||||
oTryAllSecrets,
|
||||
oTrustedKey,
|
||||
@ -378,6 +380,7 @@ enum cmd_and_opt_values
|
||||
oPersonalDigestPreferences,
|
||||
oPersonalCompressPreferences,
|
||||
oAgentProgram,
|
||||
oKeyboxdProgram,
|
||||
oDirmngrProgram,
|
||||
oDisableDirmngr,
|
||||
oDisplay,
|
||||
@ -850,6 +853,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"),
|
||||
|
||||
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
|
||||
ARGPARSE_s_s (oKeyboxdProgram, "keyboxd-program", "@"),
|
||||
ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
|
||||
ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", "@"),
|
||||
ARGPARSE_s_s (oDisplay, "display", "@"),
|
||||
@ -896,6 +900,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"),
|
||||
ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
|
||||
ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
|
||||
ARGPARSE_s_n (oUseKeyboxd, "use-keyboxd", "@"),
|
||||
|
||||
/* Options which can be used in special circumstances. They are not
|
||||
* published and we hope they are never required. */
|
||||
@ -983,6 +988,9 @@ static void add_keyserver_url( const char *string, int which );
|
||||
static void emergency_cleanup (void);
|
||||
static void read_sessionkey_from_fd (int fd);
|
||||
|
||||
/* NPth wrapper function definitions. */
|
||||
ASSUAN_SYSTEM_NPTH_IMPL;
|
||||
|
||||
|
||||
static char *
|
||||
make_libversion (const char *libname, const char *(*getfnc)(const char*))
|
||||
@ -2250,6 +2258,7 @@ gpg_deinit_default_ctrl (ctrl_t ctrl)
|
||||
gpg_dirmngr_deinit_session_data (ctrl);
|
||||
|
||||
keydb_release (ctrl->cached_getkey_kdb);
|
||||
gpg_keyboxd_deinit_session_data (ctrl);
|
||||
}
|
||||
|
||||
|
||||
@ -2742,6 +2751,11 @@ main (int argc, char **argv)
|
||||
case oGpgAgentInfo:
|
||||
obsolete_option (configname, configlineno, "gpg-agent-info");
|
||||
break;
|
||||
|
||||
case oUseKeyboxd:
|
||||
opt.use_keyboxd = 1;
|
||||
break;
|
||||
|
||||
case oReaderPort:
|
||||
obsolete_scdaemon_option (configname, configlineno, "reader-port");
|
||||
break;
|
||||
@ -3499,6 +3513,7 @@ main (int argc, char **argv)
|
||||
pers_compress_list=pargs.r.ret_str;
|
||||
break;
|
||||
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
|
||||
case oKeyboxdProgram: opt.keyboxd_program = pargs.r.ret_str; break;
|
||||
case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
|
||||
case oDisableDirmngr: opt.disable_dirmngr = 1; break;
|
||||
case oWeakDigest:
|
||||
@ -3738,6 +3753,11 @@ main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init threading which is used by some helper functions. */
|
||||
npth_init ();
|
||||
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
|
||||
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
|
||||
|
||||
/* FIXME: We should use logging to a file only in server mode;
|
||||
however we have not yet implemetyed that. Thus we try to get
|
||||
away with --batch as indication for logging to file
|
||||
@ -3745,7 +3765,9 @@ main (int argc, char **argv)
|
||||
if (logfile && opt.batch)
|
||||
{
|
||||
log_set_file (logfile);
|
||||
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
|
||||
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
|
||||
| GPGRT_LOG_WITH_TIME
|
||||
| GPGRT_LOG_WITH_PID ));
|
||||
}
|
||||
|
||||
if (opt.verbose > 2)
|
||||
@ -4120,8 +4142,10 @@ main (int argc, char **argv)
|
||||
/* Add the keyrings, but not for some special commands. We always
|
||||
* need to add the keyrings if we are running under SELinux, this
|
||||
* is so that the rings are added to the list of secured files.
|
||||
* We do not add any keyring if --no-keyring has been used. */
|
||||
if (default_keyring >= 0
|
||||
* We do not add any keyring if --no-keyring or --use-keyboxd has
|
||||
* been used. */
|
||||
if (!opt.use_keyboxd
|
||||
&& default_keyring >= 0
|
||||
&& (ALWAYS_ADD_KEYRINGS
|
||||
|| (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
|
||||
{
|
||||
@ -4133,9 +4157,8 @@ main (int argc, char **argv)
|
||||
}
|
||||
FREE_STRLIST(nrings);
|
||||
|
||||
/* In loopback mode, never ask for the password multiple times. */
|
||||
if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
|
||||
/* In loopback mode, never ask for the password multiple
|
||||
times. */
|
||||
{
|
||||
opt.passphrase_repeat = 0;
|
||||
}
|
||||
@ -5089,7 +5112,7 @@ main (int argc, char **argv)
|
||||
|
||||
policy = parse_tofu_policy (argv[0]);
|
||||
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
if (! hd)
|
||||
{
|
||||
write_status_failure ("tofu-driver", gpg_error(GPG_ERR_GENERAL));
|
||||
|
12
g10/gpg.h
12
g10/gpg.h
@ -60,16 +60,19 @@
|
||||
/* Object used to keep state locally to server.c . */
|
||||
struct server_local_s;
|
||||
|
||||
/* Object used to keep state locally to call-keyboxd.c . */
|
||||
struct keyboxd_local_s;
|
||||
typedef struct keyboxd_local_s *keyboxd_local_t;
|
||||
|
||||
/* Object used to keep state locally to call-dirmngr.c . */
|
||||
struct dirmngr_local_s;
|
||||
typedef struct dirmngr_local_s *dirmngr_local_t;
|
||||
|
||||
/* Object used to describe a keyblock node. */
|
||||
typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */
|
||||
typedef struct kbnode_struct *kbnode_t;
|
||||
typedef struct kbnode_struct *KBNODE; /* Deprecated use kbnode_t. */typedef struct kbnode_struct *kbnode_t;
|
||||
|
||||
/* The handle for keydb operations. */
|
||||
typedef struct keydb_handle *KEYDB_HANDLE;
|
||||
typedef struct keydb_handle_s *KEYDB_HANDLE;
|
||||
|
||||
/* TOFU database meta object. */
|
||||
struct tofu_dbs_s;
|
||||
@ -96,6 +99,9 @@ struct server_control_s
|
||||
/* Local data for call-dirmngr.c */
|
||||
dirmngr_local_t dirmngr_local;
|
||||
|
||||
/* Local data for call-keyboxd.c */
|
||||
keyboxd_local_t keyboxd_local;
|
||||
|
||||
/* Local data for tofu.c */
|
||||
struct {
|
||||
tofu_dbs_t dbs;
|
||||
|
@ -614,7 +614,7 @@ pk_search_terms (const char *option, int argc, char *argv[], void *cookie)
|
||||
if (err)
|
||||
log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
|
||||
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
|
||||
err = keydb_search (hd, &desc, 1, NULL);
|
||||
if (err)
|
||||
@ -810,7 +810,7 @@ sig_issuer (const char *option, int argc, char *argv[], void *cookie)
|
||||
if (err)
|
||||
log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
|
||||
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
|
||||
err = keydb_search (hd, &desc, 1, NULL);
|
||||
if (err)
|
||||
|
17
g10/import.c
17
g10/import.c
@ -550,7 +550,7 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp,
|
||||
gpg_error_t err;
|
||||
iobuf_t inp;
|
||||
|
||||
inp = iobuf_esopen (fp, "rb", 1);
|
||||
inp = iobuf_esopen (fp, "rb", 1, 0);
|
||||
if (!inp)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
@ -2022,7 +2022,7 @@ import_one_real (ctrl_t ctrl,
|
||||
goto leave;
|
||||
|
||||
/* Do we have this key already in one of our pubrings ? */
|
||||
err = get_keyblock_byfprint_fast (&keyblock_orig, &hd,
|
||||
err = get_keyblock_byfprint_fast (ctrl, &keyblock_orig, &hd,
|
||||
fpr2, fpr2len, 1/*locked*/);
|
||||
if ((err
|
||||
&& gpg_err_code (err) != GPG_ERR_NO_PUBKEY
|
||||
@ -2310,13 +2310,13 @@ import_one_real (ctrl_t ctrl,
|
||||
if (mod_key)
|
||||
{
|
||||
revocation_present (ctrl, keyblock_orig);
|
||||
if (!from_sk && have_secret_key_with_kid (keyid))
|
||||
if (!from_sk && have_secret_key_with_kid (ctrl, keyid))
|
||||
check_prefs (ctrl, keyblock_orig);
|
||||
}
|
||||
else if (new_key)
|
||||
{
|
||||
revocation_present (ctrl, keyblock);
|
||||
if (!from_sk && have_secret_key_with_kid (keyid))
|
||||
if (!from_sk && have_secret_key_with_kid (ctrl, keyid))
|
||||
check_prefs (ctrl, keyblock);
|
||||
}
|
||||
|
||||
@ -3372,7 +3372,7 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
|
||||
}
|
||||
|
||||
/* Read the original keyblock. */
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
if (!hd)
|
||||
{
|
||||
rc = gpg_error_from_syserror ();
|
||||
@ -3768,7 +3768,8 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
||||
else if (node->pkt->pkttype == PKT_SIGNATURE
|
||||
&& !node->pkt->pkt.signature->flags.exportable
|
||||
&& !(options&IMPORT_LOCAL_SIGS)
|
||||
&& !have_secret_key_with_kid (node->pkt->pkt.signature->keyid))
|
||||
&& !have_secret_key_with_kid (ctrl,
|
||||
node->pkt->pkt.signature->keyid))
|
||||
{
|
||||
/* here we violate the rfc a bit by still allowing
|
||||
* to import non-exportable signature when we have the
|
||||
@ -4089,7 +4090,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
|
||||
* itself? */
|
||||
gpg_error_t err;
|
||||
|
||||
err = get_pubkey_byfprint_fast (NULL,
|
||||
err = get_pubkey_byfprint_fast (ctrl, NULL,
|
||||
sig->revkey[idx].fpr,
|
||||
sig->revkey[idx].fprlen);
|
||||
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY
|
||||
@ -4111,7 +4112,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
|
||||
opt.keyserver, 0);
|
||||
|
||||
/* Do we have it now? */
|
||||
err = get_pubkey_byfprint_fast (NULL,
|
||||
err = get_pubkey_byfprint_fast (ctrl, NULL,
|
||||
sig->revkey[idx].fpr,
|
||||
sig->revkey[idx].fprlen);
|
||||
}
|
||||
|
171
g10/keydb-private.h
Normal file
171
g10/keydb-private.h
Normal 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*/
|
252
g10/keydb.c
252
g10/keydb.c
@ -37,25 +37,10 @@
|
||||
#include "keydb.h"
|
||||
#include "../common/i18n.h"
|
||||
|
||||
#include "keydb-private.h" /* For struct keydb_handle_s */
|
||||
|
||||
static int active_handles;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KEYDB_RESOURCE_TYPE_NONE = 0,
|
||||
KEYDB_RESOURCE_TYPE_KEYRING,
|
||||
KEYDB_RESOURCE_TYPE_KEYBOX
|
||||
} KeydbResourceType;
|
||||
#define MAX_KEYDB_RESOURCES 40
|
||||
|
||||
struct resource_item
|
||||
{
|
||||
KeydbResourceType type;
|
||||
union {
|
||||
KEYRING_HANDLE kr;
|
||||
KEYBOX_HANDLE kb;
|
||||
} u;
|
||||
void *token;
|
||||
};
|
||||
|
||||
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
|
||||
static int used_resources;
|
||||
@ -67,74 +52,6 @@ static void *primary_keydb;
|
||||
/* Whether we have successfully registered any resource. */
|
||||
static int any_registered;
|
||||
|
||||
/* This is a simple cache used to return the last result of a
|
||||
successful fingerprint search. This works only for keybox resources
|
||||
because (due to lack of a copy_keyblock function) we need to store
|
||||
an image of the keyblock which is fortunately instantly available
|
||||
for keyboxes. */
|
||||
enum keyblock_cache_states {
|
||||
KEYBLOCK_CACHE_EMPTY,
|
||||
KEYBLOCK_CACHE_PREPARED,
|
||||
KEYBLOCK_CACHE_FILLED
|
||||
};
|
||||
|
||||
struct keyblock_cache {
|
||||
enum keyblock_cache_states state;
|
||||
byte fpr[MAX_FINGERPRINT_LEN];
|
||||
byte fprlen;
|
||||
iobuf_t iobuf; /* Image of the keyblock. */
|
||||
int pk_no;
|
||||
int uid_no;
|
||||
/* Offset of the record in the keybox. */
|
||||
int resource;
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
|
||||
struct keydb_handle
|
||||
{
|
||||
/* When we locked all of the resources in ACTIVE (using keyring_lock
|
||||
/ keybox_lock, as appropriate). */
|
||||
int locked;
|
||||
|
||||
/* If this flag is set a lock will only be released by
|
||||
* keydb_release. */
|
||||
int keep_lock;
|
||||
|
||||
/* The index into ACTIVE of the resources in which the last search
|
||||
result was found. Initially -1. */
|
||||
int found;
|
||||
|
||||
/* Initially -1 (invalid). This is used to save a search result and
|
||||
later restore it as the selected result. */
|
||||
int saved_found;
|
||||
|
||||
/* The number of skipped long blobs since the last search
|
||||
(keydb_search_reset). */
|
||||
unsigned long skipped_long_blobs;
|
||||
|
||||
/* If set, this disables the use of the keyblock cache. */
|
||||
int no_caching;
|
||||
|
||||
/* Whether the next search will be from the beginning of the
|
||||
database (and thus consider all records). */
|
||||
int is_reset;
|
||||
|
||||
/* The "file position." In our case, this is index of the current
|
||||
resource in ACTIVE. */
|
||||
int current;
|
||||
|
||||
/* The number of resources in ACTIVE. */
|
||||
int used;
|
||||
|
||||
/* Cache of the last found and parsed key block (only used for
|
||||
keyboxes, not keyrings). */
|
||||
struct keyblock_cache keyblock_cache;
|
||||
|
||||
/* Copy of ALL_RESOURCES when keydb_new is called. */
|
||||
struct resource_item active[MAX_KEYDB_RESOURCES];
|
||||
};
|
||||
|
||||
/* Looking up keys is expensive. To hide the cost, we cache whether
|
||||
keys exist in the key database. Then, if we know a key does not
|
||||
exist, we don't have to spend time looking it up. This
|
||||
@ -273,7 +190,7 @@ kid_not_found_flush (void)
|
||||
|
||||
|
||||
static void
|
||||
keyblock_cache_clear (struct keydb_handle *hd)
|
||||
keyblock_cache_clear (struct keydb_handle_s *hd)
|
||||
{
|
||||
hd->keyblock_cache.state = KEYBLOCK_CACHE_EMPTY;
|
||||
iobuf_close (hd->keyblock_cache.iobuf);
|
||||
@ -448,7 +365,7 @@ maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
rc = _keybox_write_header_blob (fp, 1);
|
||||
rc = _keybox_write_header_blob (fp, NULL, 1);
|
||||
fclose (fp);
|
||||
}
|
||||
if (rc)
|
||||
@ -539,6 +456,10 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
|
||||
char b[MAX_FORMATTED_FINGERPRINT_LEN + 1];
|
||||
char fpr[2 * MAX_FINGERPRINT_LEN + 1];
|
||||
|
||||
#if MAX_FINGERPRINT_LEN < 20
|
||||
#error MAX_FINGERPRINT_LEN shorter than GRIP and UBID length/
|
||||
#endif
|
||||
|
||||
switch (desc->mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_EXACT:
|
||||
@ -578,7 +499,11 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
|
||||
case KEYDB_SEARCH_MODE_SUBJECT:
|
||||
return xasprintf ("SUBJECT: '%s'", desc->u.name);
|
||||
case KEYDB_SEARCH_MODE_KEYGRIP:
|
||||
return xasprintf ("KEYGRIP: %s", desc->u.grip);
|
||||
bin2hex (desc[0].u.grip, 20, fpr);
|
||||
return xasprintf ("KEYGRIP: %s", fpr);
|
||||
case KEYDB_SEARCH_MODE_UBID:
|
||||
bin2hex (desc[0].u.ubid, 20, fpr);
|
||||
return xasprintf ("UBID: %s", fpr);
|
||||
case KEYDB_SEARCH_MODE_FIRST:
|
||||
return xasprintf ("FIRST");
|
||||
case KEYDB_SEARCH_MODE_NEXT:
|
||||
@ -888,26 +813,17 @@ keydb_dump_stats (void)
|
||||
}
|
||||
|
||||
|
||||
/* Create a new database handle. A database handle is similar to a
|
||||
file handle: it contains a local file position. This is used when
|
||||
searching: subsequent searches resume where the previous search
|
||||
left off. To rewind the position, use keydb_search_reset(). This
|
||||
function returns NULL on error, sets ERRNO, and prints an error
|
||||
diagnostic. */
|
||||
KEYDB_HANDLE
|
||||
keydb_new (void)
|
||||
/* keydb_new diverts to here in non-keyboxd mode. HD is just the
|
||||
* calloced structure with the handle type intialized. */
|
||||
gpg_error_t
|
||||
internal_keydb_init (KEYDB_HANDLE hd)
|
||||
{
|
||||
KEYDB_HANDLE hd;
|
||||
gpg_error_t err = 0;
|
||||
int i, j;
|
||||
int die = 0;
|
||||
int reterrno;
|
||||
|
||||
if (DBG_CLOCK)
|
||||
log_clock ("keydb_new");
|
||||
|
||||
hd = xtrycalloc (1, sizeof *hd);
|
||||
if (!hd)
|
||||
goto leave;
|
||||
log_assert (!hd->use_keyboxd);
|
||||
hd->found = -1;
|
||||
hd->saved_found = -1;
|
||||
hd->is_reset = 1;
|
||||
@ -949,28 +865,21 @@ keydb_new (void)
|
||||
keydb_stats.handles++;
|
||||
|
||||
if (die)
|
||||
{
|
||||
keydb_release (hd);
|
||||
gpg_err_set_errno (reterrno);
|
||||
hd = NULL;
|
||||
}
|
||||
err = gpg_error_from_errno (reterrno);
|
||||
|
||||
leave:
|
||||
if (!hd)
|
||||
log_error (_("error opening key DB: %s\n"),
|
||||
gpg_strerror (gpg_error_from_syserror()));
|
||||
|
||||
return hd;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Free all non-keyboxd resources owned by the database handle.
|
||||
* keydb_release diverts to here. */
|
||||
void
|
||||
keydb_release (KEYDB_HANDLE hd)
|
||||
internal_keydb_deinit (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hd)
|
||||
return;
|
||||
log_assert (!hd->use_keyboxd);
|
||||
|
||||
log_assert (active_handles > 0);
|
||||
active_handles--;
|
||||
|
||||
@ -992,19 +901,17 @@ keydb_release (KEYDB_HANDLE hd)
|
||||
}
|
||||
|
||||
keyblock_cache_clear (hd);
|
||||
xfree (hd);
|
||||
}
|
||||
|
||||
|
||||
/* Take a lock on the files immediately and not only during insert or
|
||||
* update. This lock is released with keydb_release. */
|
||||
gpg_error_t
|
||||
keydb_lock (KEYDB_HANDLE hd)
|
||||
internal_keydb_lock (KEYDB_HANDLE hd)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
log_assert (!hd->use_keyboxd);
|
||||
|
||||
err = lock_all (hd);
|
||||
if (!err)
|
||||
@ -1020,7 +927,7 @@ keydb_lock (KEYDB_HANDLE hd)
|
||||
void
|
||||
keydb_disable_caching (KEYDB_HANDLE hd)
|
||||
{
|
||||
if (hd)
|
||||
if (hd && !hd->use_keyboxd)
|
||||
hd->no_caching = 1;
|
||||
}
|
||||
|
||||
@ -1042,6 +949,9 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
|
||||
if (!hd)
|
||||
return NULL;
|
||||
|
||||
if (!hd->use_keyboxd)
|
||||
return "[keyboxd]";
|
||||
|
||||
if ( hd->found >= 0 && hd->found < hd->used)
|
||||
idx = hd->found;
|
||||
else if ( hd->current >= 0 && hd->current < hd->used)
|
||||
@ -1165,6 +1075,8 @@ unlock_all (KEYDB_HANDLE hd)
|
||||
* Note: it is only possible to save a single save state at a time.
|
||||
* In other words, the save stack only has room for a single
|
||||
* instance of the state. */
|
||||
/* FIXME(keyboxd): This function is used only at one place - see how
|
||||
* we can avoid it. */
|
||||
void
|
||||
keydb_push_found_state (KEYDB_HANDLE hd)
|
||||
{
|
||||
@ -1196,6 +1108,8 @@ keydb_push_found_state (KEYDB_HANDLE hd)
|
||||
|
||||
/* Restore the previous save state. If the saved state is NULL or
|
||||
invalid, this is a NOP. */
|
||||
/* FIXME(keyboxd): This function is used only at one place - see how
|
||||
* we can avoid it. */
|
||||
void
|
||||
keydb_pop_found_state (KEYDB_HANDLE hd)
|
||||
{
|
||||
@ -1360,6 +1274,7 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
|
||||
|
||||
|
||||
/* Return the keyblock last found by keydb_search() in *RET_KB.
|
||||
* keydb_get_keyblock divert to here in the non-keyboxd mode.
|
||||
*
|
||||
* On success, the function returns 0 and the caller must free *RET_KB
|
||||
* using release_kbnode(). Otherwise, the function returns an error
|
||||
@ -1369,17 +1284,11 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
|
||||
* with the public key used to locate the keyblock or flag bit 1 set
|
||||
* for the user ID node. */
|
||||
gpg_error_t
|
||||
keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
|
||||
internal_keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
|
||||
*ret_kb = NULL;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
|
||||
if (DBG_CLOCK)
|
||||
log_clock ("keydb_get_keybock enter");
|
||||
log_assert (!hd->use_keyboxd);
|
||||
|
||||
if (hd->keyblock_cache.state == KEYBLOCK_CACHE_FILLED)
|
||||
{
|
||||
@ -1398,8 +1307,7 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
|
||||
if (err)
|
||||
keyblock_cache_clear (hd);
|
||||
if (DBG_CLOCK)
|
||||
log_clock (err? "keydb_get_keyblock leave (cached, failed)"
|
||||
: "keydb_get_keyblock leave (cached)");
|
||||
log_clock ("%s leave (cached mode)", __func__);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@ -1447,9 +1355,6 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
|
||||
if (!err)
|
||||
keydb_stats.get_keyblocks++;
|
||||
|
||||
if (DBG_CLOCK)
|
||||
log_clock (err? "keydb_get_keyblock leave (failed)"
|
||||
: "keydb_get_keyblock leave");
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1498,6 +1403,7 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
|
||||
|
||||
/* Update the keyblock KB (i.e., extract the fingerprint and find the
|
||||
* corresponding keyblock in the keyring).
|
||||
* keydb_update_keyblock diverts to here in the non-keyboxd mode.
|
||||
*
|
||||
* This doesn't do anything if --dry-run was specified.
|
||||
*
|
||||
@ -1512,20 +1418,16 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
|
||||
* you should use keydb_push_found_state and keydb_pop_found_state to
|
||||
* save and restore it. */
|
||||
gpg_error_t
|
||||
keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
|
||||
internal_keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
|
||||
{
|
||||
gpg_error_t err;
|
||||
PKT_public_key *pk;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
size_t len;
|
||||
|
||||
log_assert (kb);
|
||||
log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
|
||||
log_assert (!hd->use_keyboxd);
|
||||
pk = kb->pkt->pkt.public_key;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
|
||||
kid_not_found_flush ();
|
||||
keyblock_cache_clear (hd);
|
||||
|
||||
@ -1588,6 +1490,7 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
|
||||
|
||||
|
||||
/* Insert a keyblock into one of the underlying keyrings or keyboxes.
|
||||
* keydb_insert_keyblock diverts to here in the non-keyboxd mode.
|
||||
*
|
||||
* Be default, the keyring / keybox from which the last search result
|
||||
* came is used. If there was no previous search result (or
|
||||
@ -1598,13 +1501,12 @@ keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb)
|
||||
*
|
||||
* Returns 0 on success. Otherwise, it returns an error code. */
|
||||
gpg_error_t
|
||||
keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
|
||||
internal_keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int idx;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
log_assert (!hd->use_keyboxd);
|
||||
|
||||
kid_not_found_flush ();
|
||||
keyblock_cache_clear (hd);
|
||||
@ -1663,12 +1565,11 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
|
||||
*
|
||||
* Returns 0 on success or an error code, if an error occurs. */
|
||||
gpg_error_t
|
||||
keydb_delete_keyblock (KEYDB_HANDLE hd)
|
||||
internal_keydb_delete_keyblock (KEYDB_HANDLE hd)
|
||||
{
|
||||
gpg_error_t rc;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
log_assert (!hd->use_keyboxd);
|
||||
|
||||
kid_not_found_flush ();
|
||||
keyblock_cache_clear (hd);
|
||||
@ -1721,6 +1622,9 @@ keydb_locate_writable (KEYDB_HANDLE hd)
|
||||
if (!hd)
|
||||
return GPG_ERR_INV_ARG;
|
||||
|
||||
if (hd->use_keyboxd)
|
||||
return 0; /* No need for this here. */
|
||||
|
||||
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -1772,6 +1676,9 @@ keydb_rebuild_caches (ctrl_t ctrl, int noisy)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
if (opt.use_keyboxd)
|
||||
return; /* No need for this here. */
|
||||
|
||||
for (i=0; i < used_resources; i++)
|
||||
{
|
||||
if (!keyring_is_writable (all_resources[i].token))
|
||||
@ -1794,38 +1701,33 @@ keydb_rebuild_caches (ctrl_t ctrl, int noisy)
|
||||
}
|
||||
|
||||
|
||||
/* Return the number of skipped blocks (because they were to large to
|
||||
/* Return the number of skipped blocks (because they were too large to
|
||||
read from a keybox) since the last search reset. */
|
||||
unsigned long
|
||||
keydb_get_skipped_counter (KEYDB_HANDLE hd)
|
||||
{
|
||||
return hd ? hd->skipped_long_blobs : 0;
|
||||
/*FIXME(keyboxd): Do we need this? */
|
||||
return hd && !hd->use_keyboxd? hd->skipped_long_blobs : 0;
|
||||
}
|
||||
|
||||
|
||||
/* Clears the current search result and resets the handle's position
|
||||
* so that the next search starts at the beginning of the database
|
||||
* (the start of the first resource).
|
||||
* keydb_search_reset diverts to here in the non-keyboxd mode.
|
||||
*
|
||||
* Returns 0 on success and an error code if an error occurred.
|
||||
* (Currently, this function always returns 0 if HD is valid.) */
|
||||
gpg_error_t
|
||||
keydb_search_reset (KEYDB_HANDLE hd)
|
||||
internal_keydb_search_reset (KEYDB_HANDLE hd)
|
||||
{
|
||||
gpg_error_t rc = 0;
|
||||
int i;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
log_assert (!hd->use_keyboxd);
|
||||
|
||||
keyblock_cache_clear (hd);
|
||||
|
||||
if (DBG_CLOCK)
|
||||
log_clock ("keydb_search_reset");
|
||||
|
||||
if (DBG_CACHE)
|
||||
log_debug ("keydb_search: reset (hd=%p)", hd);
|
||||
|
||||
hd->skipped_long_blobs = 0;
|
||||
hd->current = 0;
|
||||
hd->found = -1;
|
||||
@ -1853,6 +1755,7 @@ keydb_search_reset (KEYDB_HANDLE hd)
|
||||
|
||||
/* Search the database for keys matching the search description. If
|
||||
* the DB contains any legacy keys, these are silently ignored.
|
||||
* keydb_search diverts to here in the non-keyboxd mode.
|
||||
*
|
||||
* DESC is an array of search terms with NDESC entries. The search
|
||||
* terms are or'd together. That is, the next entry in the DB that
|
||||
@ -1870,21 +1773,16 @@ keydb_search_reset (KEYDB_HANDLE hd)
|
||||
* The returned key is considered to be selected and the raw data can,
|
||||
* for instance, be returned by calling keydb_get_keyblock(). */
|
||||
gpg_error_t
|
||||
keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex)
|
||||
internal_keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex)
|
||||
{
|
||||
int i;
|
||||
gpg_error_t rc;
|
||||
int was_reset = hd->is_reset;
|
||||
/* If an entry is already in the cache, then don't add it again. */
|
||||
int already_in_cache = 0;
|
||||
int fprlen;
|
||||
|
||||
if (descindex)
|
||||
*descindex = 0; /* Make sure it is always set on return. */
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_ARG);
|
||||
log_assert (!hd->use_keyboxd);
|
||||
|
||||
if (!any_registered)
|
||||
{
|
||||
@ -1892,26 +1790,11 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (DBG_CLOCK)
|
||||
log_clock ("keydb_search enter");
|
||||
|
||||
if (DBG_LOOKUP)
|
||||
{
|
||||
log_debug ("%s: %zd search descriptions:\n", __func__, ndesc);
|
||||
for (i = 0; i < ndesc; i ++)
|
||||
{
|
||||
char *t = keydb_search_desc_dump (&desc[i]);
|
||||
log_debug ("%s %d: %s\n", __func__, i, t);
|
||||
xfree (t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID
|
||||
&& (already_in_cache = kid_not_found_p (desc[0].u.kid)) == 1 )
|
||||
{
|
||||
if (DBG_CLOCK)
|
||||
log_clock ("keydb_search leave (not found, cached)");
|
||||
log_clock ("%s leave (not found, cached)", __func__);
|
||||
keydb_stats.notfound_cached++;
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
}
|
||||
@ -1939,7 +1822,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
{
|
||||
/* (DESCINDEX is already set). */
|
||||
if (DBG_CLOCK)
|
||||
log_clock ("keydb_search leave (cached)");
|
||||
log_clock ("%s leave (cached)", __func__);
|
||||
|
||||
hd->current = hd->keyblock_cache.resource;
|
||||
/* HD->KEYBLOCK_CACHE.OFFSET is the last byte in the record.
|
||||
@ -2029,9 +1912,6 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
&& !already_in_cache)
|
||||
kid_not_found_insert (desc[0].u.kid);
|
||||
|
||||
if (DBG_CLOCK)
|
||||
log_clock (rc? "keydb_search leave (not found)"
|
||||
: "keydb_search leave (found)");
|
||||
if (!rc)
|
||||
keydb_stats.found++;
|
||||
else
|
||||
|
74
g10/keydb.h
74
g10/keydb.h
@ -169,6 +169,41 @@ is_in_klist (struct key_item *k, PKT_signature *sig)
|
||||
}
|
||||
|
||||
|
||||
/*-- call-keyboxd.c --*/
|
||||
|
||||
/* Release all open contexts to the keyboxd. */
|
||||
void gpg_keyboxd_deinit_session_data (ctrl_t ctrl);
|
||||
|
||||
/* Create a new database handle. Returns NULL on error, sets ERRNO,
|
||||
* and prints an error diagnostic. */
|
||||
KEYDB_HANDLE keydb_new (ctrl_t ctrl);
|
||||
|
||||
/* Release a keydb handle. */
|
||||
void keydb_release (KEYDB_HANDLE hd);
|
||||
|
||||
/* Take a lock if we are not using the keyboxd. */
|
||||
gpg_error_t keydb_lock (KEYDB_HANDLE hd);
|
||||
|
||||
/* Return the keyblock last found by keydb_search. */
|
||||
gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, kbnode_t *ret_kb);
|
||||
|
||||
/* Update the keyblock KB. */
|
||||
gpg_error_t keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb);
|
||||
|
||||
/* Insert a keyblock into one of the storage system. */
|
||||
gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
|
||||
|
||||
/* Delete the currently selected keyblock. */
|
||||
gpg_error_t keydb_delete_keyblock (KEYDB_HANDLE hd);
|
||||
|
||||
/* Clears the current search result and resets the handle's position. */
|
||||
gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
|
||||
|
||||
/* Search the database for keys matching the search description. */
|
||||
gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex);
|
||||
|
||||
|
||||
|
||||
/*-- keydb.c --*/
|
||||
|
||||
@ -187,17 +222,6 @@ gpg_error_t keydb_add_resource (const char *url, unsigned int flags);
|
||||
/* Dump some statistics to the log. */
|
||||
void keydb_dump_stats (void);
|
||||
|
||||
/* Create a new database handle. Returns NULL on error, sets ERRNO,
|
||||
and prints an error diagnostic. */
|
||||
KEYDB_HANDLE keydb_new (void);
|
||||
|
||||
/* Free all resources owned by the database handle. */
|
||||
void keydb_release (KEYDB_HANDLE hd);
|
||||
|
||||
/* Take a lock on the files immediately and not only during insert or
|
||||
* update. This lock is released with keydb_release. */
|
||||
gpg_error_t keydb_lock (KEYDB_HANDLE hd);
|
||||
|
||||
/* Set a flag on the handle to suppress use of cached results. This
|
||||
is required for updating a keyring and for key listings. Fixme:
|
||||
Using a new parameter for keydb_new might be a better solution. */
|
||||
@ -212,18 +236,6 @@ void keydb_pop_found_state (KEYDB_HANDLE hd);
|
||||
/* Return the file name of the resource. */
|
||||
const char *keydb_get_resource_name (KEYDB_HANDLE hd);
|
||||
|
||||
/* Return the keyblock last found by keydb_search. */
|
||||
gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
|
||||
|
||||
/* Update the keyblock KB. */
|
||||
gpg_error_t keydb_update_keyblock (ctrl_t ctrl, KEYDB_HANDLE hd, kbnode_t kb);
|
||||
|
||||
/* Insert a keyblock into one of the underlying keyrings or keyboxes. */
|
||||
gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
|
||||
|
||||
/* Delete the currently selected keyblock. */
|
||||
gpg_error_t keydb_delete_keyblock (KEYDB_HANDLE hd);
|
||||
|
||||
/* Find the first writable resource. */
|
||||
gpg_error_t keydb_locate_writable (KEYDB_HANDLE hd);
|
||||
|
||||
@ -234,13 +246,6 @@ void keydb_rebuild_caches (ctrl_t ctrl, int noisy);
|
||||
read from a keybox) since the last search reset. */
|
||||
unsigned long keydb_get_skipped_counter (KEYDB_HANDLE hd);
|
||||
|
||||
/* Clears the current search result and resets the handle's position. */
|
||||
gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
|
||||
|
||||
/* Search the database for keys matching the search description. */
|
||||
gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex);
|
||||
|
||||
/* Return the first non-legacy key in the database. */
|
||||
gpg_error_t keydb_search_first (KEYDB_HANDLE hd);
|
||||
|
||||
@ -331,7 +336,7 @@ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
|
||||
/* Similar to get_pubkey, but it does not take PK->REQ_USAGE into
|
||||
account nor does it merge in the self-signed data. This function
|
||||
also only considers primary keys. */
|
||||
int get_pubkey_fast (PKT_public_key *pk, u32 *keyid);
|
||||
int get_pubkey_fast (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
|
||||
|
||||
/* Return the entire keyblock used to create SIG. This is a
|
||||
* specialized version of get_pubkeyblock. */
|
||||
@ -391,13 +396,14 @@ int get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
|
||||
/* This function is similar to get_pubkey_byfprint, but it doesn't
|
||||
merge the self-signed data into the public key and subkeys or into
|
||||
the user ids. */
|
||||
gpg_error_t get_pubkey_byfprint_fast (PKT_public_key *pk,
|
||||
gpg_error_t get_pubkey_byfprint_fast (ctrl_t ctrl, PKT_public_key *pk,
|
||||
const byte *fprint, size_t fprint_len);
|
||||
|
||||
/* This function is similar to get_pubkey_byfprint, but it doesn't
|
||||
merge the self-signed data into the public key and subkeys or into
|
||||
the user ids. */
|
||||
gpg_error_t get_keyblock_byfprint_fast (kbnode_t *r_keyblock,
|
||||
gpg_error_t get_keyblock_byfprint_fast (ctrl_t ctrl,
|
||||
kbnode_t *r_keyblock,
|
||||
KEYDB_HANDLE *r_hd,
|
||||
const byte *fprint, size_t fprint_len,
|
||||
int lock);
|
||||
@ -405,7 +411,7 @@ gpg_error_t get_keyblock_byfprint_fast (kbnode_t *r_keyblock,
|
||||
|
||||
/* Returns true if a secret key is available for the public key with
|
||||
key id KEYID. */
|
||||
int have_secret_key_with_kid (u32 *keyid);
|
||||
int have_secret_key_with_kid (ctrl_t ctrl, u32 *keyid);
|
||||
|
||||
/* Parse the --default-key parameter. Returns the last key (in terms
|
||||
of when the option is given) that is available. */
|
||||
|
@ -2289,7 +2289,7 @@ quick_find_keyblock (ctrl_t ctrl, const char *username,
|
||||
*r_keyblock = NULL;
|
||||
|
||||
/* Search the key; we don't want the whole getkey stuff here. */
|
||||
kdbhd = keydb_new ();
|
||||
kdbhd = keydb_new (ctrl);
|
||||
if (!kdbhd)
|
||||
{
|
||||
/* Note that keydb_new has already used log_error. */
|
||||
@ -5761,7 +5761,7 @@ menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
|
||||
}
|
||||
else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
|
||||
&& ((sig = node->pkt->pkt.signature),
|
||||
have_secret_key_with_kid (sig->keyid)))
|
||||
have_secret_key_with_kid (ctrl, sig->keyid)))
|
||||
{
|
||||
if ((sig->sig_class & ~3) == 0x10)
|
||||
{
|
||||
@ -5800,7 +5800,7 @@ menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
|
||||
}
|
||||
else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
|
||||
&& ((sig = node->pkt->pkt.signature),
|
||||
have_secret_key_with_kid (sig->keyid)))
|
||||
have_secret_key_with_kid (ctrl, sig->keyid)))
|
||||
{
|
||||
if ((sig->sig_class & ~3) == 0x10)
|
||||
{
|
||||
|
@ -4502,7 +4502,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
|
||||
desc.mode = KEYDB_SEARCH_MODE_EXACT;
|
||||
desc.u.name = uid;
|
||||
|
||||
kdbhd = keydb_new ();
|
||||
kdbhd = keydb_new (ctrl);
|
||||
if (!kdbhd)
|
||||
goto leave;
|
||||
|
||||
@ -5371,7 +5371,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
|
||||
{
|
||||
KEYDB_HANDLE pub_hd;
|
||||
|
||||
pub_hd = keydb_new ();
|
||||
pub_hd = keydb_new (ctrl);
|
||||
if (!pub_hd)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
|
@ -524,7 +524,7 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
|
||||
if (opt.check_sigs)
|
||||
listctx.check_sigs = 1;
|
||||
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
if (!hd)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
|
@ -1195,7 +1195,7 @@ keyidlist (ctrl_t ctrl, strlist_t users, KEYDB_SEARCH_DESC **klist,
|
||||
|
||||
*klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
|
||||
|
||||
kdbhd = keydb_new ();
|
||||
kdbhd = keydb_new (ctrl);
|
||||
if (!kdbhd)
|
||||
{
|
||||
rc = gpg_error_from_syserror ();
|
||||
|
@ -157,7 +157,7 @@ struct expando_args
|
||||
const byte *namehash;
|
||||
};
|
||||
|
||||
char *pct_expando(const char *string,struct expando_args *args);
|
||||
char *pct_expando (ctrl_t ctrl, const char *string,struct expando_args *args);
|
||||
void deprecated_warning(const char *configname,unsigned int configlineno,
|
||||
const char *option,const char *repl1,const char *repl2);
|
||||
void deprecated_command (const char *name);
|
||||
|
@ -895,7 +895,7 @@ get_signature_count (PKT_public_key *pk)
|
||||
/* Expand %-strings. Returns a string which must be xfreed. Returns
|
||||
NULL if the string cannot be expanded (too large). */
|
||||
char *
|
||||
pct_expando(const char *string,struct expando_args *args)
|
||||
pct_expando (ctrl_t ctrl, const char *string,struct expando_args *args)
|
||||
{
|
||||
const char *ch=string;
|
||||
int idx=0,maxlen=0,done=0;
|
||||
@ -1017,7 +1017,7 @@ pct_expando(const char *string,struct expando_args *args)
|
||||
PKT_public_key *pk=
|
||||
xmalloc_clear(sizeof(PKT_public_key));
|
||||
|
||||
if (!get_pubkey_fast (pk,args->pksk->main_keyid))
|
||||
if (!get_pubkey_fast (ctrl, pk,args->pksk->main_keyid))
|
||||
fingerprint_from_pk (pk, array, &len);
|
||||
else
|
||||
memset (array, 0, (len=MAX_FINGERPRINT_LEN));
|
||||
|
@ -30,8 +30,8 @@
|
||||
#include "options.h"
|
||||
#include "objcache.h"
|
||||
|
||||
/* Note that max value for uid_items is actually a the threshold when
|
||||
* we start to look for ietms which can be removed. */
|
||||
/* Note that max value for uid_items is actually the threshold when
|
||||
* we start to look for items which can be removed. */
|
||||
#define NO_OF_UID_ITEM_BUCKETS 107
|
||||
#define MAX_UID_ITEMS_PER_BUCKET 20
|
||||
|
||||
|
@ -126,6 +126,7 @@ struct
|
||||
int completes_needed;
|
||||
int max_cert_depth;
|
||||
const char *agent_program;
|
||||
const char *keyboxd_program;
|
||||
const char *dirmngr_program;
|
||||
int disable_dirmngr;
|
||||
|
||||
@ -287,6 +288,8 @@ struct
|
||||
int only_sign_text_ids;
|
||||
|
||||
int no_symkey_cache; /* Disable the cache used for --symmetric. */
|
||||
|
||||
int use_keyboxd; /* Use the external keyboxd as storage backend. */
|
||||
} opt;
|
||||
|
||||
/* CTRL is used to keep some global variables we currently can't
|
||||
|
@ -667,8 +667,8 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
|
||||
int offset = attrs[i].len-len;
|
||||
|
||||
/* make command grow */
|
||||
command = pct_expando (opt.photo_viewer, &args);
|
||||
if (!command)
|
||||
command = pct_expando (ctrl, opt.photo_viewer,&args);
|
||||
if(!command)
|
||||
goto fail;
|
||||
|
||||
name = xmalloc (1 + 16 + strlen(EXTSEP_S)
|
||||
|
@ -217,7 +217,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
|
||||
|
||||
afx = new_armor_context ();
|
||||
|
||||
kdbhd = keydb_new ();
|
||||
kdbhd = keydb_new (ctrl);
|
||||
if (!kdbhd)
|
||||
{
|
||||
rc = gpg_error_from_syserror ();
|
||||
@ -641,7 +641,7 @@ gen_revoke (ctrl_t ctrl, const char *uname)
|
||||
}
|
||||
|
||||
/* Search the userid; we don't want the whole getkey stuff here. */
|
||||
kdbhd = keydb_new ();
|
||||
kdbhd = keydb_new (ctrl);
|
||||
if (!kdbhd)
|
||||
{
|
||||
rc = gpg_error_from_syserror ();
|
||||
|
12
g10/sign.c
12
g10/sign.c
@ -70,7 +70,7 @@ typedef struct pt_extra_hash_data_s *pt_extra_hash_data_t;
|
||||
* a valid NAME=VALUE format.
|
||||
*/
|
||||
static void
|
||||
mk_notation_policy_etc (PKT_signature *sig,
|
||||
mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig,
|
||||
PKT_public_key *pk, PKT_public_key *pksk)
|
||||
{
|
||||
const char *string;
|
||||
@ -99,7 +99,7 @@ mk_notation_policy_etc (PKT_signature *sig,
|
||||
|
||||
for (item = nd; item; item = item->next)
|
||||
{
|
||||
item->altvalue = pct_expando (item->value,&args);
|
||||
item->altvalue = pct_expando (ctrl, item->value,&args);
|
||||
if (!item->altvalue)
|
||||
log_error (_("WARNING: unable to %%-expand notation "
|
||||
"(too large). Using unexpanded.\n"));
|
||||
@ -126,7 +126,7 @@ mk_notation_policy_etc (PKT_signature *sig,
|
||||
{
|
||||
string = pu->d;
|
||||
|
||||
p = pct_expando (string, &args);
|
||||
p = pct_expando (ctrl, string, &args);
|
||||
if (!p)
|
||||
{
|
||||
log_error(_("WARNING: unable to %%-expand policy URL "
|
||||
@ -149,7 +149,7 @@ mk_notation_policy_etc (PKT_signature *sig,
|
||||
{
|
||||
string = pu->d;
|
||||
|
||||
p = pct_expando (string, &args);
|
||||
p = pct_expando (ctrl, string, &args);
|
||||
if (!p)
|
||||
{
|
||||
log_error (_("WARNING: unable to %%-expand preferred keyserver URL"
|
||||
@ -838,7 +838,7 @@ write_signature_packets (ctrl_t ctrl,
|
||||
BUG ();
|
||||
|
||||
build_sig_subpkt_from_sig (sig, pk);
|
||||
mk_notation_policy_etc (sig, NULL, pk);
|
||||
mk_notation_policy_etc (ctrl, sig, NULL, pk);
|
||||
hash_sigversion_to_magic (md, sig, extrahash);
|
||||
gcry_md_final (md);
|
||||
|
||||
@ -1664,7 +1664,7 @@ make_keysig_packet (ctrl_t ctrl,
|
||||
sig->sig_class = sigclass;
|
||||
|
||||
build_sig_subpkt_from_sig (sig, pksk);
|
||||
mk_notation_policy_etc (sig, pk, pksk);
|
||||
mk_notation_policy_etc (ctrl, sig, pk, pksk);
|
||||
|
||||
/* Crucial that the call to mksubpkt comes LAST before the calls
|
||||
* to finalize the sig as that makes it possible for the mksubpkt
|
||||
|
@ -21,9 +21,11 @@
|
||||
|
||||
#include "keydb.h"
|
||||
|
||||
|
||||
static void
|
||||
do_test (int argc, char *argv[])
|
||||
{
|
||||
ctrl_t ctrl;
|
||||
char *fname;
|
||||
int rc;
|
||||
KEYDB_HANDLE hd1;
|
||||
@ -33,6 +35,7 @@ do_test (int argc, char *argv[])
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
ctrl = xcalloc (1, sizeof *ctrl);
|
||||
/* t-keydb-get-keyblock.gpg contains two keys: a modern key followed
|
||||
by a legacy key. If we get the keyblock for the modern key, we
|
||||
shouldn't get
|
||||
@ -44,7 +47,7 @@ do_test (int argc, char *argv[])
|
||||
if (rc)
|
||||
ABORT ("Failed to open keyring.");
|
||||
|
||||
hd1 = keydb_new ();
|
||||
hd1 = keydb_new (ctrl);
|
||||
if (!hd1)
|
||||
ABORT ("");
|
||||
|
||||
@ -62,4 +65,5 @@ do_test (int argc, char *argv[])
|
||||
|
||||
keydb_release (hd1);
|
||||
release_kbnode (kb1);
|
||||
xfree (ctrl);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ static void
|
||||
do_test (int argc, char *argv[])
|
||||
{
|
||||
int rc;
|
||||
ctrl_t ctrl;
|
||||
KEYDB_HANDLE hd1, hd2;
|
||||
KEYDB_SEARCH_DESC desc1, desc2;
|
||||
KBNODE kb1, kb2, p;
|
||||
@ -35,16 +36,17 @@ do_test (int argc, char *argv[])
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
ctrl = xcalloc (1, sizeof *ctrl);
|
||||
fname = prepend_srcdir ("t-keydb-keyring.kbx");
|
||||
rc = keydb_add_resource (fname, 0);
|
||||
test_free (fname);
|
||||
if (rc)
|
||||
ABORT ("Failed to open keyring.");
|
||||
|
||||
hd1 = keydb_new ();
|
||||
hd1 = keydb_new (ctrl);
|
||||
if (!hd1)
|
||||
ABORT ("");
|
||||
hd2 = keydb_new ();
|
||||
hd2 = keydb_new (ctrl);
|
||||
if (!hd2)
|
||||
ABORT ("");
|
||||
|
||||
@ -101,4 +103,5 @@ do_test (int argc, char *argv[])
|
||||
release_kbnode (kb2);
|
||||
keydb_release (hd1);
|
||||
keydb_release (hd2);
|
||||
xfree (ctrl);
|
||||
}
|
||||
|
@ -2131,7 +2131,7 @@ build_conflict_set (ctrl_t ctrl, tofu_dbs_t dbs,
|
||||
/* If two keys have cross signatures, then they are controlled by
|
||||
* the same person and thus are not in conflict. */
|
||||
kb_all = xcalloc (sizeof (kb_all[0]), conflict_set_count);
|
||||
hd = keydb_new ();
|
||||
hd = keydb_new (ctrl);
|
||||
for (i = 0, iter = conflict_set;
|
||||
i < conflict_set_count;
|
||||
i ++, iter = iter->next)
|
||||
|
@ -2017,7 +2017,7 @@ validate_keys (ctrl_t ctrl, int interactive)
|
||||
trust. */
|
||||
keydb_rebuild_caches (ctrl, 0);
|
||||
|
||||
kdb = keydb_new ();
|
||||
kdb = keydb_new (ctrl);
|
||||
if (!kdb)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
|
@ -18,16 +18,20 @@
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
EXTRA_DIST = mkerrors
|
||||
EXTRA_DIST = mkerrors keyboxd-w32info.rc
|
||||
|
||||
AM_CPPFLAGS =
|
||||
|
||||
include $(top_srcdir)/am/cmacros.am
|
||||
if HAVE_W32_SYSTEM
|
||||
resource_objs += keyboxd-w32info.o
|
||||
endif
|
||||
|
||||
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS)
|
||||
|
||||
noinst_LIBRARIES = libkeybox.a libkeybox509.a
|
||||
bin_PROGRAMS = kbxutil
|
||||
libexec_PROGRAMS = keyboxd
|
||||
|
||||
if HAVE_W32CE_SYSTEM
|
||||
extra_libs = $(LIBASSUAN_LIBS)
|
||||
@ -35,6 +39,9 @@ else
|
||||
extra_libs =
|
||||
endif
|
||||
|
||||
common_libs = $(libcommon)
|
||||
commonpth_libs = $(libcommonpth)
|
||||
|
||||
common_sources = \
|
||||
keybox.h keybox-defs.h keybox-search-desc.h \
|
||||
keybox-util.c \
|
||||
@ -59,9 +66,31 @@ libkeybox509_a_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1
|
||||
# to do it this way.
|
||||
kbxutil_SOURCES = kbxutil.c $(common_sources)
|
||||
kbxutil_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1
|
||||
kbxutil_LDADD = ../common/libcommon.a \
|
||||
kbxutil_LDADD = $(common_libs) \
|
||||
$(KSBA_LIBS) $(LIBGCRYPT_LIBS) $(extra_libs) \
|
||||
$(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) $(W32SOCKLIBS) \
|
||||
$(NETLIBS)
|
||||
|
||||
$(PROGRAMS) : ../common/libcommon.a
|
||||
|
||||
keyboxd_SOURCES = \
|
||||
keyboxd.c keyboxd.h \
|
||||
kbxserver.c \
|
||||
frontend.c frontend.h \
|
||||
backend.h backend-support.c \
|
||||
backend-cache.c \
|
||||
backend-kbx.c \
|
||||
$(common_sources)
|
||||
|
||||
keyboxd_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) \
|
||||
$(INCICONV)
|
||||
keyboxd_LDADD = $(commonpth_libs) \
|
||||
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
|
||||
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
|
||||
$(resource_objs)
|
||||
keyboxd_LDFLAGS = $(extra_bin_ldflags)
|
||||
keyboxd_DEPENDENCIES = $(resource_objs)
|
||||
|
||||
|
||||
# Make sure that all libs are build before we use them. This is
|
||||
# important for things like make -j2.
|
||||
$(PROGRAMS): $(common_libs) $(commonpth_libs)
|
||||
|
1190
kbx/backend-cache.c
Normal file
1190
kbx/backend-cache.c
Normal file
File diff suppressed because it is too large
Load Diff
328
kbx/backend-kbx.c
Normal file
328
kbx/backend-kbx.c
Normal 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
171
kbx/backend-support.c
Normal 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
140
kbx/backend.h
Normal 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
385
kbx/frontend.c
Normal 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
36
kbx/frontend.h
Normal 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
775
kbx/kbxserver.c
Normal 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;
|
||||
}
|
||||
}
|
@ -67,6 +67,7 @@
|
||||
- u16 Blob flags
|
||||
bit 0 = contains secret key material (not used)
|
||||
bit 1 = ephemeral blob (e.g. used while querying external resources)
|
||||
bit 2 = blob has an UBID field.
|
||||
- u32 Offset to the OpenPGP keyblock or the X.509 DER encoded
|
||||
certificate
|
||||
- u32 The length of the keyblock or certificate
|
||||
@ -143,7 +144,10 @@
|
||||
IDs go here.
|
||||
- bN Space for the keyblock or certificate.
|
||||
- bN RFU. This is the remaining space after keyblock and before
|
||||
the checksum. It is not covered by the checksum.
|
||||
the checksum. Not part of the SHA-1 checksum.
|
||||
- bN Only if blob flags bit 2 is set: 20 octet Unique Blob-ID (UBID).
|
||||
This is the SHA-1 checksum of the keyblock or certificate.
|
||||
This is not part of the SHA-1 checksum below.
|
||||
- b20 SHA-1 checksum (useful for KS synchronization?)
|
||||
Note, that KBX versions before GnuPG 2.1 used an MD5
|
||||
checksum. However it was only created but never checked.
|
||||
@ -173,6 +177,10 @@
|
||||
|
||||
|
||||
#include "../common/gettime.h"
|
||||
#include "../common/host2net.h"
|
||||
|
||||
|
||||
#define get32(a) buf32_to_ulong ((a))
|
||||
|
||||
|
||||
/* special values of the signature status */
|
||||
@ -559,7 +567,7 @@ create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral,
|
||||
put32 ( a, 0 ); /* blob length, needs fixup */
|
||||
put8 ( a, blobtype);
|
||||
put8 ( a, want_fpr32? 2:1 ); /* blob type version */
|
||||
put16 ( a, as_ephemeral? 2:0 ); /* blob flags */
|
||||
put16 ( a, as_ephemeral? 6:4 ); /* blob flags */
|
||||
|
||||
put32 ( a, 0 ); /* offset to the raw data, needs fixup */
|
||||
put32 ( a, 0 ); /* length of the raw data, needs fixup */
|
||||
@ -686,8 +694,8 @@ create_blob_finish (KEYBOXBLOB blob)
|
||||
unsigned char *pp;
|
||||
size_t n;
|
||||
|
||||
/* Write a placeholder for the checksum */
|
||||
put_membuf (a, NULL, 20);
|
||||
/* Write placeholders for the UBID and the checksum */
|
||||
put_membuf (a, NULL, 40);
|
||||
|
||||
/* get the memory area */
|
||||
n = 0; /* (Just to avoid compiler warning.) */
|
||||
@ -721,8 +729,11 @@ create_blob_finish (KEYBOXBLOB blob)
|
||||
blob->fixups = NULL;
|
||||
}
|
||||
|
||||
/* Compute and store the UBID. (image_off) (image_len) */
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 40, p + get32 (p+8), get32 (p+12));
|
||||
|
||||
/* Compute and store the SHA-1 checksum. */
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 20, p, n - 20);
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 20, p, n - 40);
|
||||
|
||||
pp = xtrymalloc (n);
|
||||
if ( !pp )
|
||||
|
@ -63,6 +63,41 @@ print_string (FILE *fp, const byte *p, size_t n, int delim)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_ubib (const byte *buffer, size_t length, FILE *fp)
|
||||
{
|
||||
const byte *p;
|
||||
int i;
|
||||
size_t image_off, image_len;
|
||||
unsigned char digest[20];
|
||||
|
||||
fprintf (fp, "UBIB: ");
|
||||
if (length < 40)
|
||||
{
|
||||
fputs ("[blob too short for a stored UBIB]\n", fp);
|
||||
return;
|
||||
}
|
||||
|
||||
p = buffer + length - 40;
|
||||
for (i=0; i < 20; p++, i++)
|
||||
fprintf (fp, "%02X", *p);
|
||||
|
||||
image_off = get32 (buffer+8);
|
||||
image_len = get32 (buffer+12);
|
||||
if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
|
||||
{
|
||||
fputs (" [image claims to be longer than the blob]\n", fp);
|
||||
return;
|
||||
}
|
||||
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer+image_off,image_len);
|
||||
if (memcmp (digest, buffer + length - 40, 20))
|
||||
fputs (" [does not match the image]\n", fp);
|
||||
else
|
||||
fputc ('\n', fp);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
print_checksum (const byte *buffer, size_t length, size_t unhashed, FILE *fp)
|
||||
{
|
||||
@ -171,6 +206,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
|
||||
ulong unhashed;
|
||||
const byte *p;
|
||||
int is_fpr32; /* blob ersion 2 */
|
||||
int have_ubib = 0;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
|
||||
@ -237,6 +273,14 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
|
||||
fputs ("ephemeral", fp);
|
||||
any++;
|
||||
}
|
||||
if ((n & 4))
|
||||
{
|
||||
if (any)
|
||||
putc (',', fp);
|
||||
fputs ("ubid", fp);
|
||||
any++;
|
||||
have_ubib = 1;
|
||||
}
|
||||
putc (')', fp);
|
||||
}
|
||||
putc ('\n', fp);
|
||||
@ -422,6 +466,8 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
|
||||
n = get32 ( buffer + length - unhashed);
|
||||
fprintf (fp, "Storage-Flags: %08lx\n", n );
|
||||
}
|
||||
if (have_ubib)
|
||||
print_ubib (buffer, length, fp);
|
||||
print_checksum (buffer, length, unhashed, fp);
|
||||
return 0;
|
||||
}
|
||||
|
@ -146,9 +146,9 @@ _keybox_write_blob (KEYBOXBLOB blob, FILE *fp)
|
||||
}
|
||||
|
||||
|
||||
/* Write a fresh header type blob. */
|
||||
int
|
||||
_keybox_write_header_blob (FILE *fp, int for_openpgp)
|
||||
/* Write a fresh header type blob. Either FP or STREAM must be used. */
|
||||
gpg_error_t
|
||||
_keybox_write_header_blob (FILE *fp, estream_t stream, int for_openpgp)
|
||||
{
|
||||
unsigned char image[32];
|
||||
u32 val;
|
||||
@ -174,7 +174,15 @@ _keybox_write_header_blob (FILE *fp, int for_openpgp)
|
||||
image[20+2] = (val >> 8);
|
||||
image[20+3] = (val );
|
||||
|
||||
if (fwrite (image, 32, 1, fp) != 1)
|
||||
return gpg_error_from_syserror ();
|
||||
if (fp)
|
||||
{
|
||||
if (fwrite (image, 32, 1, fp) != 1)
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (es_fwrite (image, 32, 1, stream) != 1)
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -42,11 +42,21 @@ typedef enum {
|
||||
KEYDB_SEARCH_MODE_SN,
|
||||
KEYDB_SEARCH_MODE_SUBJECT,
|
||||
KEYDB_SEARCH_MODE_KEYGRIP,
|
||||
KEYDB_SEARCH_MODE_UBID,
|
||||
KEYDB_SEARCH_MODE_FIRST,
|
||||
KEYDB_SEARCH_MODE_NEXT
|
||||
} KeydbSearchMode;
|
||||
|
||||
|
||||
/* Identifiers for the public key types we use in GnuPG. */
|
||||
enum pubkey_types
|
||||
{
|
||||
PUBKEY_TYPE_UNKNOWN = 0,
|
||||
PUBKEY_TYPE_OPGP = 1,
|
||||
PUBKEY_TYPE_X509 = 2
|
||||
};
|
||||
|
||||
|
||||
/* Forward declaration. See g10/packet.h. */
|
||||
struct gpg_pkt_user_id_s;
|
||||
typedef struct gpg_pkt_user_id_s *gpg_pkt_user_id_t;
|
||||
@ -70,6 +80,7 @@ struct keydb_search_desc
|
||||
unsigned char fpr[32];
|
||||
u32 kid[2]; /* Note that this is in native endianness. */
|
||||
unsigned char grip[20];
|
||||
unsigned char ubid[20];
|
||||
} u;
|
||||
byte fprlen; /* Only used with KEYDB_SEARCH_MODE_FPR. */
|
||||
int exact; /* Use exactly this key ('!' suffix in gpg). */
|
||||
|
@ -696,6 +696,35 @@ has_keygrip (KEYBOXBLOB blob, const unsigned char *grip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
has_ubid (KEYBOXBLOB blob, const unsigned char *ubid)
|
||||
{
|
||||
size_t length;
|
||||
const unsigned char *buffer;
|
||||
size_t image_off, image_len;
|
||||
unsigned char ubid_blob[20];
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /*GPG_ERR_TOO_SHORT*/
|
||||
|
||||
if ((get16 (buffer + 6) & 4))
|
||||
{
|
||||
/* The blob has a stored UBID. */
|
||||
return !memcmp (ubid, buffer + length - 40, 20);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Need to compute the UBID. */
|
||||
image_off = get32 (buffer+8);
|
||||
image_len = get32 (buffer+12);
|
||||
if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
|
||||
return 0; /*GPG_ERR_TOO_SHORT*/
|
||||
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, ubid_blob, buffer+image_off,image_len);
|
||||
return !memcmp (ubid, ubid_blob, 20);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
has_issuer (KEYBOXBLOB blob, const char *name)
|
||||
@ -1119,6 +1148,10 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
|
||||
if (has_keygrip (blob, desc[n].u.grip))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_UBID:
|
||||
if (has_ubid (blob, desc[n].u.ubid))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FIRST:
|
||||
goto found;
|
||||
break;
|
||||
@ -1180,11 +1213,70 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
|
||||
a successful search operation.
|
||||
*/
|
||||
|
||||
/* Return the raw data from the last found blob. Caller must release
|
||||
* the value stored at R_BUFFER. If called with NULL for R_BUFFER
|
||||
* only the needed length for the buffer and the public key type is
|
||||
* returned. */
|
||||
gpg_error_t
|
||||
keybox_get_data (KEYBOX_HANDLE hd, void **r_buffer, size_t *r_length,
|
||||
enum pubkey_types *r_pubkey_type)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t image_off, image_len;
|
||||
|
||||
if (r_buffer)
|
||||
*r_buffer = NULL;
|
||||
if (r_length)
|
||||
*r_length = 0;
|
||||
if (r_pubkey_type)
|
||||
*r_pubkey_type = PUBKEY_TYPE_UNKNOWN;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (!hd->found.blob)
|
||||
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
||||
|
||||
switch (blob_get_type (hd->found.blob))
|
||||
{
|
||||
case KEYBOX_BLOBTYPE_PGP:
|
||||
if (r_pubkey_type)
|
||||
*r_pubkey_type = PUBKEY_TYPE_OPGP;
|
||||
break;
|
||||
case KEYBOX_BLOBTYPE_X509:
|
||||
if (r_pubkey_type)
|
||||
*r_pubkey_type = PUBKEY_TYPE_X509;
|
||||
break;
|
||||
default:
|
||||
return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
||||
}
|
||||
|
||||
buffer = _keybox_get_blob_image (hd->found.blob, &length);
|
||||
if (length < 40)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
image_off = get32 (buffer+8);
|
||||
image_len = get32 (buffer+12);
|
||||
if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
|
||||
if (r_length)
|
||||
*r_length = image_len;
|
||||
if (r_buffer)
|
||||
{
|
||||
*r_buffer = xtrymalloc (image_len);
|
||||
if (!*r_buffer)
|
||||
return gpg_error_from_syserror ();
|
||||
memcpy (*r_buffer, buffer + image_off, image_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return the last found keyblock. Returns 0 on success and stores a
|
||||
* new iobuf at R_IOBUF. R_UID_NO and R_PK_NO are used to return the
|
||||
* number of the key or user id which was matched the search criteria;
|
||||
* if not known they are set to 0. */
|
||||
* index of the key or user id which matched the search criteria; if
|
||||
* not known they are set to 0. */
|
||||
gpg_error_t
|
||||
keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
|
||||
int *r_pk_no, int *r_uid_no)
|
||||
|
@ -182,7 +182,7 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
|
||||
if (!newfp )
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
rc = _keybox_write_header_blob (newfp, for_openpgp);
|
||||
rc = _keybox_write_header_blob (newfp, NULL, for_openpgp);
|
||||
if (rc)
|
||||
{
|
||||
fclose (newfp);
|
||||
@ -730,7 +730,7 @@ keybox_compress (KEYBOX_HANDLE hd)
|
||||
}
|
||||
|
||||
/* The header blob is missing. Insert it. */
|
||||
rc = _keybox_write_header_blob (newfp, hd->for_openpgp);
|
||||
rc = _keybox_write_header_blob (newfp, NULL, hd->for_openpgp);
|
||||
if (rc)
|
||||
break;
|
||||
any_changes = 1;
|
||||
|
@ -81,9 +81,13 @@ gpg_error_t keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout);
|
||||
/*-- keybox-file.c --*/
|
||||
/* Fixme: This function does not belong here: Provide a better
|
||||
interface to create a new keybox file. */
|
||||
int _keybox_write_header_blob (FILE *fp, int openpgp_flag);
|
||||
gpg_error_t _keybox_write_header_blob (FILE *fp, estream_t stream,
|
||||
int openpgp_flag);
|
||||
|
||||
/*-- keybox-search.c --*/
|
||||
gpg_error_t keybox_get_data (KEYBOX_HANDLE hd,
|
||||
void **r_buffer, size_t *r_length,
|
||||
enum pubkey_types *r_pubkey_type);
|
||||
gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
|
||||
int *r_uid_no, int *r_pk_no);
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
|
50
kbx/keyboxd-w32info.rc
Normal file
50
kbx/keyboxd-w32info.rc
Normal 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
1845
kbx/keyboxd.c
Normal file
File diff suppressed because it is too large
Load Diff
156
kbx/keyboxd.h
Normal file
156
kbx/keyboxd.h
Normal 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*/
|
@ -53,6 +53,7 @@ XGETTEXT_OPTIONS = \
|
||||
--flag=xasprintf:1:c-format \
|
||||
--flag=xtryasprintf:1:c-format \
|
||||
--flag=log_debug_with_string:2:c-format \
|
||||
--flag=status_printf:3:c-format \
|
||||
--flag=print_assuan_status:3:c-format \
|
||||
--flag=vprint_assuan_status:3:c-format \
|
||||
--flag=agent_print_status:3:c-format \
|
||||
|
@ -224,7 +224,7 @@ maybe_create_keybox (char *filename, int force, int *r_created)
|
||||
/* Make sure that at least one record is in a new keybox file, so
|
||||
that the detection magic for OpenPGP keyboxes works the next time
|
||||
it is used. */
|
||||
rc = _keybox_write_header_blob (fp, 0);
|
||||
rc = _keybox_write_header_blob (fp, NULL, 0);
|
||||
if (rc)
|
||||
{
|
||||
fclose (fp);
|
||||
|
@ -60,12 +60,14 @@ enum cmd_and_opt_values
|
||||
oHomedir,
|
||||
oAgentProgram,
|
||||
oDirmngrProgram,
|
||||
oKeyboxdProgram,
|
||||
oHex,
|
||||
oDecode,
|
||||
oNoExtConnect,
|
||||
oDirmngr,
|
||||
oKeyboxd,
|
||||
oUIServer,
|
||||
oNoAutostart,
|
||||
oNoAutostart
|
||||
|
||||
};
|
||||
|
||||
@ -79,6 +81,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_n (oHex, "hex", N_("print data out hex encoded")),
|
||||
ARGPARSE_s_n (oDecode,"decode", N_("decode received data lines")),
|
||||
ARGPARSE_s_n (oDirmngr,"dirmngr", N_("connect to the dirmngr")),
|
||||
ARGPARSE_s_n (oKeyboxd,"keyboxd", N_("connect to the keyboxd")),
|
||||
ARGPARSE_s_n (oUIServer, "uiserver", "@"),
|
||||
ARGPARSE_s_s (oRawSocket, "raw-socket",
|
||||
N_("|NAME|connect to Assuan socket NAME")),
|
||||
@ -97,6 +100,7 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_s (oHomedir, "homedir", "@" ),
|
||||
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
|
||||
ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
|
||||
ARGPARSE_s_s (oKeyboxdProgram, "keyboxd-program", "@"),
|
||||
|
||||
ARGPARSE_end ()
|
||||
};
|
||||
@ -109,11 +113,13 @@ struct
|
||||
int quiet; /* Be extra quiet. */
|
||||
int autostart; /* Start the server if not running. */
|
||||
const char *homedir; /* Configuration directory name */
|
||||
const char *agent_program; /* Value of --agent-program. */
|
||||
const char *agent_program; /* Value of --agent-program. */
|
||||
const char *dirmngr_program; /* Value of --dirmngr-program. */
|
||||
const char *keyboxd_program; /* Value of --keyboxd-program. */
|
||||
int hex; /* Print data lines in hex format. */
|
||||
int decode; /* Decode received data lines. */
|
||||
int use_dirmngr; /* Use the dirmngr and not gpg-agent. */
|
||||
int use_keyboxd; /* Use the keyboxd and not gpg-agent. */
|
||||
int use_uiserver; /* Use the standard UI server. */
|
||||
const char *raw_socket; /* Name of socket to connect in raw mode. */
|
||||
const char *tcp_socket; /* Name of server to connect in tcp mode. */
|
||||
@ -1200,10 +1206,12 @@ main (int argc, char **argv)
|
||||
case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
|
||||
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
|
||||
case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
|
||||
case oKeyboxdProgram: opt.keyboxd_program = pargs.r.ret_str; break;
|
||||
case oNoAutostart: opt.autostart = 0; break;
|
||||
case oHex: opt.hex = 1; break;
|
||||
case oDecode: opt.decode = 1; break;
|
||||
case oDirmngr: opt.use_dirmngr = 1; break;
|
||||
case oKeyboxd: opt.use_keyboxd = 1; break;
|
||||
case oUIServer: opt.use_uiserver = 1; break;
|
||||
case oRawSocket: opt.raw_socket = pargs.r.ret_str; break;
|
||||
case oTcpSocket: opt.tcp_socket = pargs.r.ret_str; break;
|
||||
@ -1879,7 +1887,10 @@ main (int argc, char **argv)
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("closing connection to agent\n");
|
||||
log_info ("closing connection to %s\n",
|
||||
opt.use_dirmngr? "dirmngr" :
|
||||
opt.use_keyboxd? "keyboxd" :
|
||||
"agent");
|
||||
|
||||
/* XXX: We would like to release the context here, but libassuan
|
||||
nicely says good bye to the server, which results in a SIGPIPE if
|
||||
@ -2224,6 +2235,13 @@ start_agent (void)
|
||||
opt.autostart,
|
||||
!opt.quiet, 0,
|
||||
NULL, NULL);
|
||||
else if (opt.use_keyboxd)
|
||||
err = start_new_keyboxd (&ctx,
|
||||
GPG_ERR_SOURCE_DEFAULT,
|
||||
opt.keyboxd_program,
|
||||
opt.autostart,
|
||||
!opt.quiet, 0,
|
||||
NULL, NULL);
|
||||
else
|
||||
err = start_new_gpg_agent (&ctx,
|
||||
GPG_ERR_SOURCE_DEFAULT,
|
||||
@ -2239,12 +2257,15 @@ start_agent (void)
|
||||
{
|
||||
if (!opt.autostart
|
||||
&& (gpg_err_code (err)
|
||||
== (opt.use_dirmngr? GPG_ERR_NO_DIRMNGR : GPG_ERR_NO_AGENT)))
|
||||
== (opt.use_dirmngr? GPG_ERR_NO_DIRMNGR :
|
||||
opt.use_keyboxd? GPG_ERR_NO_KEYBOXD : GPG_ERR_NO_AGENT)))
|
||||
{
|
||||
/* In the no-autostart case we don't make gpg-connect-agent
|
||||
fail on a missing server. */
|
||||
log_info (opt.use_dirmngr?
|
||||
_("no dirmngr running in this session\n"):
|
||||
opt.use_keyboxd?
|
||||
_("no keybox daemon running in this session\n"):
|
||||
_("no gpg-agent running in this session\n"));
|
||||
exit (0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user