1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

gpg: First rough implementation of keyboxd access for key lookup.

* g10/Makefile.am: Add nPth flags.
* g10/gpg.c: Include npth.h.
(gpg_deinit_default_ctrl): Deinit call-keyboxd local data.
(main): Init nPth.
* g10/keydb-private.h (struct keydb_handle_s): Add field 'kbl' and
remove the search result and the assuan context.
* g10/call-keyboxd.c (struct keyboxd_local_s): Add more fields.
(lock_datastream, unlock_datastream): New.
(gpg_keyboxd_deinit_session_data): Adjust for changed data structures.
(prepare_data_pipe): New.
(open_context): Return kbl instead of an Assuan context.  Init mutexes
etc.
(close_context): Merge into ...
(keydb_release): here.  Adjust for changed data structures.
(datastream_thread): New.
(keydb_get_keyblock): Implement datastream stuff.
(keydb_search): Ditto.

* common/asshelp.c (wait_for_sock): Add arg connect_flags.
(start_new_service): Set FDPASSING flag for the keyboxd.
--

This code as a lot of rough edges, in particular it relies on a well
behaving keyboxd.  We need to add code to shutdown the datastream
reader thread in case of errors and to properly get it up again.  We
also need to make really sure that both threads run in lockstep so
that the datastream thread is only active while we are sending a
command to the keyboxd.

We should also see whether we can depend nPth initialization on the
--use-keyboxd option to avoid any problems with nPth.

And we need to test on Windows.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-09-10 16:05:54 +02:00
parent 6c327b4dd6
commit ce9906b008
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
6 changed files with 382 additions and 106 deletions

View File

@ -310,14 +310,15 @@ unlock_spawning (lock_spawn_t *lock, const char *name)
} }
/* Helper to start a service. /* Helper to start a service. SECS gives the number of seconds to
* SECS gives the number of seconds to wait. SOCKNAME is the name of * wait. SOCKNAME is the name of the socket to connect. VERBOSE is
* the socket to connect. VERBOSE is the usual verbose flag. CTX is * the usual verbose flag. CTX is the assuan context. CONNECT_FLAGS
* the assuan context. DID_SUCCESS_MSG will be set to 1 if a success * are the assuan connect flags. DID_SUCCESS_MSG will be set to 1 if
* messages has been printed. * a success messages has been printed.
*/ */
static gpg_error_t static gpg_error_t
wait_for_sock (int secs, int module_name_id, const char *sockname, wait_for_sock (int secs, int module_name_id, const char *sockname,
unsigned int connect_flags,
int verbose, assuan_context_t ctx, int *did_success_msg) int verbose, assuan_context_t ctx, int *did_success_msg)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
@ -353,7 +354,7 @@ wait_for_sock (int secs, int module_name_id, const char *sockname,
} }
gnupg_usleep (next_sleep_us); gnupg_usleep (next_sleep_us);
elapsed_us += next_sleep_us; elapsed_us += next_sleep_us;
err = assuan_socket_connect (ctx, sockname, 0, 0); err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
if (!err) if (!err)
{ {
if (verbose) if (verbose)
@ -403,6 +404,7 @@ start_new_service (assuan_context_t *r_ctx,
const char *status_start_line; const char *status_start_line;
int no_service_err; int no_service_err;
int seconds_to_wait; int seconds_to_wait;
unsigned int connect_flags = 0;
const char *argv[6]; const char *argv[6];
*r_ctx = NULL; *r_ctx = NULL;
@ -439,6 +441,7 @@ start_new_service (assuan_context_t *r_ctx,
status_start_line = "starting_keyboxd ? 0 0"; status_start_line = "starting_keyboxd ? 0 0";
no_service_err = GPG_ERR_NO_KEYBOXD; no_service_err = GPG_ERR_NO_KEYBOXD;
seconds_to_wait = SECS_TO_WAIT_FOR_KEYBOXD; seconds_to_wait = SECS_TO_WAIT_FOR_KEYBOXD;
connect_flags |= ASSUAN_SOCKET_CONNECT_FDPASSING;
break; break;
default: default:
err = gpg_error (GPG_ERR_INV_ARG); err = gpg_error (GPG_ERR_INV_ARG);
@ -446,7 +449,7 @@ start_new_service (assuan_context_t *r_ctx,
return err; return err;
} }
err = assuan_socket_connect (ctx, sockname, 0, 0); err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
if (err && autostart) if (err && autostart)
{ {
char *abs_homedir; char *abs_homedir;
@ -522,7 +525,7 @@ start_new_service (assuan_context_t *r_ctx,
argv[i++] = NULL; argv[i++] = NULL;
if (!(err = lock_spawning (&lock, gnupg_homedir (), lock_name, verbose)) if (!(err = lock_spawning (&lock, gnupg_homedir (), lock_name, verbose))
&& assuan_socket_connect (ctx, sockname, 0, 0)) && assuan_socket_connect (ctx, sockname, 0, connect_flags))
{ {
err = gnupg_spawn_process_detached (program? program : program_name, err = gnupg_spawn_process_detached (program? program : program_name,
argv, NULL); argv, NULL);
@ -532,7 +535,8 @@ start_new_service (assuan_context_t *r_ctx,
gpg_strerror (err)); gpg_strerror (err));
else else
err = wait_for_sock (seconds_to_wait, module_name_id, err = wait_for_sock (seconds_to_wait, module_name_id,
sockname, verbose, ctx, &did_success_msg); sockname, connect_flags,
verbose, ctx, &did_success_msg);
} }
unlock_spawning (&lock, lock_name); unlock_spawning (&lock, lock_name);

View File

@ -29,9 +29,9 @@ AM_CPPFLAGS =
include $(top_srcdir)/am/cmacros.am include $(top_srcdir)/am/cmacros.am
AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \ AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \
$(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) $(GPG_ERROR_CFLAGS)
needed_libs = ../kbx/libkeybox.a $(libcommon) needed_libs = ../kbx/libkeybox.a $(libcommonpth)
# Because there are no program specific transform macros we need to # Because there are no program specific transform macros we need to
# work around that to allow installing gpg as gpg2. # work around that to allow installing gpg as gpg2.
@ -178,11 +178,11 @@ gpgv_SOURCES = gpgv.c \
LDADD = $(needed_libs) ../common/libgpgrl.a \ LDADD = $(needed_libs) ../common/libgpgrl.a \
$(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS)
gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(resource_objs) $(extra_sys_libs) $(LIBICONV) $(resource_objs) $(extra_sys_libs)
gpg_LDFLAGS = $(extra_bin_ldflags) gpg_LDFLAGS = $(extra_bin_ldflags)
gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(resource_objs) $(extra_sys_libs) $(LIBICONV) $(resource_objs) $(extra_sys_libs)
gpgv_LDFLAGS = $(extra_bin_ldflags) gpgv_LDFLAGS = $(extra_bin_ldflags)
@ -197,17 +197,17 @@ t_rmd160_SOURCES = t-rmd160.c rmd160.c
t_rmd160_LDADD = $(t_common_ldadd) t_rmd160_LDADD = $(t_common_ldadd)
t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source) t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source)
t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(t_common_ldadd) $(LIBICONV) $(t_common_ldadd)
t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \ t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \
$(common_source) $(common_source)
t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(t_common_ldadd) $(LIBICONV) $(t_common_ldadd)
t_stutter_SOURCES = t-stutter.c test-stubs.c \ t_stutter_SOURCES = t-stutter.c test-stubs.c \
$(common_source) $(common_source)
t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \
$(LIBICONV) $(t_common_ldadd) $(LIBICONV) $(t_common_ldadd)

View File

@ -28,6 +28,7 @@
#ifdef HAVE_LOCALE_H #ifdef HAVE_LOCALE_H
# include <locale.h> # include <locale.h>
#endif #endif
#include <npth.h>
#include "gpg.h" #include "gpg.h"
#include <assuan.h> #include <assuan.h>
@ -36,6 +37,8 @@
#include "options.h" #include "options.h"
#include "../common/i18n.h" #include "../common/i18n.h"
#include "../common/asshelp.h" #include "../common/asshelp.h"
#include "../common/host2net.h"
#include "../common/exechelp.h"
#include "../common/status.h" #include "../common/status.h"
#include "keydb.h" #include "keydb.h"
@ -54,17 +57,63 @@ struct keyboxd_local_s
/* The active Assuan context. */ /* The active Assuan context. */
assuan_context_t ctx; assuan_context_t ctx;
/* This object is used if fd-passing is used to convey the
* keyblocks. */
struct {
/* NULL or a stream used to receive data. */
estream_t fp;
/* Condition variable to sync the datastream with the command. */
npth_mutex_t mutex;
npth_cond_t cond;
/* The found keyblock or the parsing error. */
kbnode_t found_keyblock;
gpg_error_t found_err;
} datastream;
/* I/O buffer with the last search result or NULL. Used if
* D-lines are used to convey the keyblocks. */
iobuf_t search_result;
/* This flag set while an operation is running on this context. */ /* This flag set while an operation is running on this context. */
unsigned int is_active : 1; unsigned int is_active : 1;
/* This flag is set to record that the standard per session init has /* This flag is set to record that the standard per session init has
* been done. */ * been done. */
unsigned int per_session_init_done : 1; unsigned int per_session_init_done : 1;
/* Flag indicating that a search reset is required. */
unsigned int need_search_reset : 1;
}; };
/* Local prototypes. */
static void *datastream_thread (void *arg);
static void
lock_datastream (keyboxd_local_t kbl)
{
int rc = npth_mutex_lock (&kbl->datastream.mutex);
if (rc)
log_fatal ("%s: failed to acquire mutex: %s\n", __func__,
gpg_strerror (gpg_error_from_errno (rc)));
}
static void
unlock_datastream (keyboxd_local_t kbl)
{
int rc = npth_mutex_unlock (&kbl->datastream.mutex);
if (rc)
log_fatal ("%s: failed to release mutex: %s\n", __func__,
gpg_strerror (gpg_error_from_errno (rc)));
}
/* Deinitialize all session resources pertaining to the keyboxd. */ /* Deinitialize all session resources pertaining to the keyboxd. */
void void
gpg_keyboxd_deinit_session_data (ctrl_t ctrl) gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
@ -77,7 +126,12 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
if (kbl->is_active) if (kbl->is_active)
log_error ("oops: trying to cleanup an active keyboxd context\n"); log_error ("oops: trying to cleanup an active keyboxd context\n");
else else
assuan_release (kbl->ctx); {
es_fclose (kbl->datastream.fp);
kbl->datastream.fp = NULL;
assuan_release (kbl->ctx);
kbl->ctx = NULL;
}
xfree (kbl); xfree (kbl);
} }
} }
@ -165,18 +219,86 @@ create_new_context (ctrl_t ctrl, assuan_context_t *r_ctx)
} }
/* Get a context for accessing keyboxd. If no context is available a
* new one is created and if necessary keyboxd is started. On success /* Setup the pipe used for receiving data from the keyboxd. Store the
* an assuan context is stored at R_CTX. This context may only be * info on KBL. */
* released by means of close_context. Note that NULL is stored at
* R_CTX on error. */
static gpg_error_t static gpg_error_t
open_context (ctrl_t ctrl, assuan_context_t *r_ctx) prepare_data_pipe (keyboxd_local_t kbl)
{ {
gpg_error_t err; gpg_error_t err;
int rc;
int inpipe[2];
estream_t infp;
npth_t thread;
npth_attr_t tattr;
err = gnupg_create_inbound_pipe (inpipe, &infp, 0);
if (err)
{
log_error ("error creating inbound pipe: %s\n", gpg_strerror (err));
return err; /* That should not happen. */
}
err = assuan_sendfd (kbl->ctx, INT2FD (inpipe[1]));
if (err)
{
log_error ("sending sending fd %d to keyboxd: %s <%s>\n",
inpipe[1], gpg_strerror (err), gpg_strsource (err));
es_fclose (infp);
close (inpipe[1]);
return 0; /* Server may not support fd-passing. */
}
err = assuan_transact (kbl->ctx, "OUTPUT FD",
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
log_info ("keyboxd does not accept our fd: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
es_fclose (infp);
return 0;
}
kbl->datastream.fp = infp;
kbl->datastream.found_keyblock = NULL;
kbl->datastream.found_err = 0;
rc = npth_attr_init (&tattr);
if (rc)
{
err = gpg_error_from_errno (rc);
log_error ("error preparing thread for keyboxd: %s\n",gpg_strerror (err));
es_fclose (infp);
kbl->datastream.fp = NULL;
return err;
}
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
rc = npth_create (&thread, &tattr, datastream_thread, kbl);
if (rc)
{
err = gpg_error_from_errno (rc);
log_error ("error spawning thread for keyboxd: %s\n", gpg_strerror (err));
npth_attr_destroy (&tattr);
es_fclose (infp);
kbl->datastream.fp = NULL;
return err;
}
return 0;
}
/* Get a context for accessing keyboxd. If no context is available a
* new one is created and if necessary keyboxd is started. R_KBL
* receives a pointer to the local context object. */
static gpg_error_t
open_context (ctrl_t ctrl, keyboxd_local_t *r_kbl)
{
gpg_error_t err;
int rc;
keyboxd_local_t kbl; keyboxd_local_t kbl;
*r_ctx = NULL; *r_kbl = NULL;
for (;;) for (;;)
{ {
for (kbl = ctrl->keyboxd_local; kbl && kbl->is_active; kbl = kbl->next) for (kbl = ctrl->keyboxd_local; kbl && kbl->is_active; kbl = kbl->next)
@ -189,12 +311,16 @@ open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
/* But first do the per session init if not yet done. */ /* But first do the per session init if not yet done. */
if (!kbl->per_session_init_done) if (!kbl->per_session_init_done)
{ {
err = prepare_data_pipe (kbl);
if (err)
return err;
kbl->per_session_init_done = 1; kbl->per_session_init_done = 1;
} }
kbl->is_active = 1; kbl->is_active = 1;
kbl->need_search_reset = 1;
*r_ctx = kbl->ctx; *r_kbl = kbl;
return 0; return 0;
} }
@ -202,43 +328,40 @@ open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
kbl = xtrycalloc (1, sizeof *kbl); kbl = xtrycalloc (1, sizeof *kbl);
if (!kbl) if (!kbl)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
err = create_new_context (ctrl, &kbl->ctx);
if (err) rc = npth_mutex_init (&kbl->datastream.mutex, NULL);
if (rc)
{ {
err = gpg_error_from_errno (rc);
log_error ("error initializing mutex: %s\n", gpg_strerror (err));
xfree (kbl);
return err;
}
rc = npth_cond_init (&kbl->datastream.cond, NULL);
if (rc)
{
err = gpg_error_from_errno (rc);
log_error ("error initializing condition: %s\n", gpg_strerror (err));
npth_mutex_destroy (&kbl->datastream.mutex);
xfree (kbl); xfree (kbl);
return err; return err;
} }
/* Although we are not yet using nPth in gpg we better prepare err = create_new_context (ctrl, &kbl->ctx);
* to be nPth thread safe. Thus we add it to the list and if (err)
* retry; this is easier than to employ a lock. */ {
npth_cond_destroy (&kbl->datastream.cond);
npth_mutex_destroy (&kbl->datastream.mutex);
xfree (kbl);
return err;
}
/* For thread-saftey we add it to the list and retry; this is
* easier than to employ a lock. */
kbl->next = ctrl->keyboxd_local; kbl->next = ctrl->keyboxd_local;
ctrl->keyboxd_local = kbl; ctrl->keyboxd_local = kbl;
} }
} /*NOTREACHED*/
/* Close the assuan context CTX and return it to a pool of unused
* contexts. If CTX is NULL, the function does nothing. */
static void
close_context (ctrl_t ctrl, assuan_context_t ctx)
{
keyboxd_local_t kbl;
if (!ctx)
return;
for (kbl = ctrl->keyboxd_local; kbl; kbl = kbl->next)
{
if (kbl->ctx == ctx)
{
if (!kbl->is_active)
log_fatal ("closing inactive keyboxd context %p\n", ctx);
kbl->is_active = 0;
return;
}
}
log_fatal ("closing unknown keyboxd ctx %p\n", ctx);
} }
@ -275,11 +398,8 @@ keydb_new (ctrl_t ctrl)
} }
hd->use_keyboxd = 1; hd->use_keyboxd = 1;
hd->ctrl = ctrl; hd->ctrl = ctrl;
hd->need_search_reset = 1;
err = open_context (ctrl, &hd->assuan_context); err = open_context (ctrl, &hd->kbl);
if (err)
goto leave;
leave: leave:
if (err) if (err)
@ -300,14 +420,25 @@ keydb_new (ctrl_t ctrl)
void void
keydb_release (KEYDB_HANDLE hd) keydb_release (KEYDB_HANDLE hd)
{ {
keyboxd_local_t kbl;
if (!hd) if (!hd)
return; return;
if (DBG_CLOCK)
log_clock ("keydb_release");
if (!hd->use_keyboxd) if (!hd->use_keyboxd)
internal_keydb_deinit (hd); internal_keydb_deinit (hd);
else else
{ {
close_context (hd->ctrl, hd->assuan_context); kbl = hd->kbl;
if (DBG_CLOCK)
log_clock ("close_context (found)");
if (!kbl->is_active)
log_fatal ("closing inactive keyboxd context %p\n", kbl);
kbl->is_active = 0;
hd->kbl = NULL;
hd->ctrl = NULL;
} }
xfree (hd); xfree (hd);
} }
@ -465,6 +596,86 @@ keydb_get_keyblock_do_parse (iobuf_t iobuf, int pk_no, int uid_no,
} }
/* The thread used to read from the data stream. This is running as
* long as the connection and its datastream exists. */
static void *
datastream_thread (void *arg)
{
keyboxd_local_t kbl = arg;
gpg_error_t err;
int rc;
unsigned char lenbuf[4];
size_t nread, datalen;
iobuf_t iobuf;
int pk_no, uid_no;
kbnode_t keyblock, tmpkeyblock;
log_debug ("Datastream_thread started\n");
while (kbl->datastream.fp)
{
/* log_debug ("Datastream_thread waiting ...\n"); */
if (es_read (kbl->datastream.fp, lenbuf, 4, &nread))
{
err = gpg_error_from_syserror ();
if (gpg_err_code (err) == GPG_ERR_EAGAIN)
continue;
log_error ("error reading data length from keyboxd: %s\n",
gpg_strerror (err));
gnupg_sleep (1);
continue;
}
if (nread != 4)
{
err = gpg_error (GPG_ERR_EIO);
log_error ("error reading data length from keyboxd: %s\n",
"short read");
continue;
}
datalen = buf32_to_size_t (lenbuf);
/* log_debug ("keyboxd announced %zu bytes\n", datalen); */
iobuf = iobuf_esopen (kbl->datastream.fp, "rb", 1, datalen);
pk_no = uid_no = 0; /* FIXME: Get this from the keyboxd. */
err = keydb_get_keyblock_do_parse (iobuf, pk_no, uid_no, &keyblock);
iobuf_close (iobuf);
if (!err)
{
/* log_debug ("parsing datastream succeeded\n"); */
/* Thread-safe assignment to the result var: */
tmpkeyblock = kbl->datastream.found_keyblock;
kbl->datastream.found_keyblock = keyblock;
release_kbnode (tmpkeyblock);
}
else
{
/* log_debug ("parsing datastream failed: %s <%s>\n", */
/* gpg_strerror (err), gpg_strsource (err)); */
tmpkeyblock = kbl->datastream.found_keyblock;
kbl->datastream.found_keyblock = NULL;
kbl->datastream.found_err = err;
release_kbnode (tmpkeyblock);
}
/* Tell the main thread. */
lock_datastream (kbl);
rc = npth_cond_signal (&kbl->datastream.cond);
if (rc)
{
err = gpg_error_from_errno (rc);
log_error ("%s: signaling condition failed: %s\n",
__func__, gpg_strerror (err));
}
unlock_datastream (kbl);
}
log_debug ("Datastream_thread finished\n");
return NULL;
}
/* Return the keyblock last found by keydb_search() in *RET_KB. /* Return the keyblock last found by keydb_search() in *RET_KB.
* *
* On success, the function returns 0 and the caller must free *RET_KB * On success, the function returns 0 and the caller must free *RET_KB
@ -494,20 +705,28 @@ keydb_get_keyblock (KEYDB_HANDLE hd, kbnode_t *ret_kb)
goto leave; goto leave;
} }
if (!hd->search_result) if (hd->kbl->search_result)
{
pk_no = uid_no = 0; /*FIXME: Get this from the keyboxd. */
err = keydb_get_keyblock_do_parse (hd->kbl->search_result,
pk_no, uid_no, ret_kb);
/* In contrast to the old code we close the iobuf here and thus
* this function may be called only once to get a keyblock. */
iobuf_close (hd->kbl->search_result);
hd->kbl->search_result = NULL;
}
else if (hd->kbl->datastream.found_keyblock)
{
*ret_kb = hd->kbl->datastream.found_keyblock;
hd->kbl->datastream.found_keyblock = NULL;
err = 0;
}
else
{ {
err = gpg_error (GPG_ERR_VALUE_NOT_FOUND); err = gpg_error (GPG_ERR_VALUE_NOT_FOUND);
goto leave; goto leave;
} }
pk_no = uid_no = 0; /*FIXME: Get this from the keyboxd. */
err = keydb_get_keyblock_do_parse (hd->search_result, pk_no, uid_no, ret_kb);
/* In contrast to the old code we close the iobuf here and thus this
* function may be called only once to get a keyblock. */
iobuf_close (hd->search_result);
hd->search_result = NULL;
leave: leave:
if (DBG_CLOCK) if (DBG_CLOCK)
log_clock ("%s leave%s", __func__, err? " (failed)":""); log_clock ("%s leave%s", __func__, err? " (failed)":"");
@ -636,7 +855,7 @@ keydb_search_reset (KEYDB_HANDLE hd)
/* All we need todo is to tell search that a reset is pending. Noet /* All we need todo is to tell search that a reset is pending. Noet
* that keydb_new sets this flag as well. */ * that keydb_new sets this flag as well. */
hd->need_search_reset = 1; hd->kbl->need_search_reset = 1;
err = 0; err = 0;
leave: leave:
@ -697,14 +916,20 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
goto leave; goto leave;
} }
/* Clear the result objects. */
if (hd->search_result) if (hd->kbl->search_result)
{ {
iobuf_close (hd->search_result); iobuf_close (hd->kbl->search_result);
hd->search_result = NULL; hd->kbl->search_result = NULL;
}
if (hd->kbl->datastream.found_keyblock)
{
release_kbnode (hd->kbl->datastream.found_keyblock);
hd->kbl->datastream.found_keyblock = NULL;
} }
if (!hd->need_search_reset) /* Check whether this is a NEXT search. */
if (!hd->kbl->need_search_reset)
{ {
/* No reset requested thus continue the search. The keyboxd /* No reset requested thus continue the search. The keyboxd
* keeps the context of the search and thus the NEXT operates on * keeps the context of the search and thus the NEXT operates on
@ -717,7 +942,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
goto do_search; goto do_search;
} }
hd->need_search_reset = 0; hd->kbl->need_search_reset = 0;
if (!ndesc) if (!ndesc)
{ {
@ -807,31 +1032,68 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
} }
do_search: do_search:
{ if (hd->kbl->datastream.fp)
membuf_t data; {
void *buffer; /* log_debug ("Sending command '%s'\n", line); */
size_t len; err = assuan_transact (hd->kbl->ctx, line,
NULL, NULL,
NULL, NULL,
NULL, NULL);
if (err)
{
/* log_debug ("Finished command with error: %s\n", gpg_strerror (err)); */
/* Fixme: On unexpected errors we need a way to cancek the
* data stream. Probly it will be best to closeand reopen
* it. */
}
else
{
int rc;
init_membuf (&data, 8192); /* log_debug ("Finished command .. telling data stream\n"); */
err = assuan_transact (hd->assuan_context, line, lock_datastream (hd->kbl);
put_membuf_cb, &data, if (!hd->kbl->datastream.found_keyblock)
NULL, NULL, {
NULL, NULL); /* log_debug ("%s: waiting on datastream_cond ...\n", __func__); */
if (err) rc = npth_cond_wait (&hd->kbl->datastream.cond,
{ &hd->kbl->datastream.mutex);
xfree (get_membuf (&data, &len)); /* log_debug ("%s: waiting on datastream.cond done\n", __func__); */
goto leave; if (rc)
} {
err = gpg_error_from_errno (rc);
log_error ("%s: waiting on condition failed: %s\n",
__func__, gpg_strerror (err));
}
}
unlock_datastream (hd->kbl);
}
}
else /* Slower D-line version if fd-passing was not successful. */
{
membuf_t data;
void *buffer;
size_t len;
buffer = get_membuf (&data, &len); init_membuf (&data, 8192);
if (!buffer) err = assuan_transact (hd->kbl->ctx, line,
{ put_membuf_cb, &data,
err = gpg_error_from_syserror (); NULL, NULL,
goto leave; NULL, NULL);
} if (err)
{
xfree (get_membuf (&data, &len));
goto leave;
}
/* Fixme: Avoid double allocation. */ buffer = get_membuf (&data, &len);
hd->search_result = iobuf_temp_with_content (buffer, len); if (!buffer)
{
err = gpg_error_from_syserror ();
goto leave;
}
hd->kbl->search_result = iobuf_temp_with_content (buffer, len);
xfree (buffer);
} }

View File

@ -36,6 +36,7 @@
# endif # endif
# include <windows.h> # include <windows.h>
#endif #endif
#include <npth.h>
#define INCLUDED_BY_MAIN_MODULE 1 #define INCLUDED_BY_MAIN_MODULE 1
#include "gpg.h" #include "gpg.h"
@ -979,6 +980,9 @@ static void add_keyserver_url( const char *string, int which );
static void emergency_cleanup (void); static void emergency_cleanup (void);
static void read_sessionkey_from_fd (int fd); static void read_sessionkey_from_fd (int fd);
/* NPth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
static char * static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*)) make_libversion (const char *libname, const char *(*getfnc)(const char*))
@ -2246,6 +2250,7 @@ gpg_deinit_default_ctrl (ctrl_t ctrl)
gpg_dirmngr_deinit_session_data (ctrl); gpg_dirmngr_deinit_session_data (ctrl);
keydb_release (ctrl->cached_getkey_kdb); keydb_release (ctrl->cached_getkey_kdb);
gpg_keyboxd_deinit_session_data (ctrl);
} }
@ -3736,6 +3741,11 @@ main (int argc, char **argv)
} }
#endif #endif
/* Init threading which is used by some helper functions. */
npth_init ();
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* FIXME: We should use logging to a file only in server mode; /* FIXME: We should use logging to a file only in server mode;
however we have not yet implemetyed that. Thus we try to get however we have not yet implemetyed that. Thus we try to get
away with --batch as indication for logging to file away with --batch as indication for logging to file
@ -3743,7 +3753,9 @@ main (int argc, char **argv)
if (logfile && opt.batch) if (logfile && opt.batch)
{ {
log_set_file (logfile); log_set_file (logfile);
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID); log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
| GPGRT_LOG_WITH_TIME
| GPGRT_LOG_WITH_PID ));
} }
if (opt.verbose > 2) if (opt.verbose > 2)

View File

@ -92,14 +92,9 @@ struct keydb_handle_s
/* A shallow pointer with the CTRL used to create this handle. */ /* A shallow pointer with the CTRL used to create this handle. */
ctrl_t ctrl; ctrl_t ctrl;
/* The context used to communicate with the keyboxd. */ /* Connection info which also keep the local state. (This is points
assuan_context_t assuan_context; * into the CTRL->keybox_local list.) */
keyboxd_local_t kbl;
/* I/O buffer with the last search result or NULL. */
iobuf_t search_result;
/* Flag indicating that a search reset is required. */
unsigned int need_search_reset : 1;
/* END USE_KEYBOXD */ /* END USE_KEYBOXD */

View File

@ -165,6 +165,9 @@ is_in_klist (struct key_item *k, PKT_signature *sig)
/*-- call-keyboxd.c --*/ /*-- 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, /* Create a new database handle. Returns NULL on error, sets ERRNO,
* and prints an error diagnostic. */ * and prints an error diagnostic. */
KEYDB_HANDLE keydb_new (ctrl_t ctrl); KEYDB_HANDLE keydb_new (ctrl_t ctrl);