diff options
Diffstat (limited to '')
-rw-r--r-- | g10/call-keyboxd.c | 451 |
1 files changed, 19 insertions, 432 deletions
diff --git a/g10/call-keyboxd.c b/g10/call-keyboxd.c index e09fa20e3..31bccefec 100644 --- a/g10/call-keyboxd.c +++ b/g10/call-keyboxd.c @@ -40,6 +40,7 @@ #include "../common/host2net.h" #include "../common/exechelp.h" #include "../common/status.h" +#include "../kbx/kbx-client-util.h" #include "keydb.h" #include "keydb-private.h" /* For struct keydb_handle_s */ @@ -57,20 +58,8 @@ struct keyboxd_local_s /* The active Assuan context. */ 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; + /* The client data helper context. */ + kbx_client_data_t kcd; /* I/O buffer with the last search result or NULL. Used if * D-lines are used to convey the keyblocks. */ @@ -79,41 +68,14 @@ struct keyboxd_local_s /* This flag set while an operation is running on this context. */ unsigned int is_active : 1; - /* This flag is set to record that the standard per session init has - * been done. */ - 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. */ void gpg_keyboxd_deinit_session_data (ctrl_t ctrl) @@ -127,8 +89,8 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl) log_error ("oops: trying to cleanup an active keyboxd context\n"); else { - es_fclose (kbl->datastream.fp); - kbl->datastream.fp = NULL; + kbx_client_data_release (kbl->kcd); + kbl->kcd = NULL; assuan_release (kbl->ctx); kbl->ctx = NULL; } @@ -189,73 +151,6 @@ create_new_context (ctrl_t ctrl, assuan_context_t *r_ctx) -/* Setup the pipe used for receiving data from the keyboxd. Store the - * info on KBL. */ -static gpg_error_t -prepare_data_pipe (keyboxd_local_t kbl) -{ - 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 @@ -264,7 +159,6 @@ static gpg_error_t open_context (ctrl_t ctrl, keyboxd_local_t *r_kbl) { gpg_error_t err; - int rc; keyboxd_local_t kbl; *r_kbl = NULL; @@ -277,15 +171,6 @@ open_context (ctrl_t ctrl, keyboxd_local_t *r_kbl) /* Found an inactive keyboxd session - return that. */ log_assert (!kbl->is_active); - /* But first do the per session init if not yet done. */ - if (!kbl->per_session_init_done) - { - err = prepare_data_pipe (kbl); - if (err) - return err; - kbl->per_session_init_done = 1; - } - kbl->is_active = 1; kbl->need_search_reset = 1; @@ -298,29 +183,17 @@ open_context (ctrl_t ctrl, keyboxd_local_t *r_kbl) if (!kbl) return gpg_error_from_syserror (); - 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 = create_new_context (ctrl, &kbl->ctx); + if (err) { - err = gpg_error_from_errno (rc); - log_error ("error initializing condition: %s\n", gpg_strerror (err)); - npth_mutex_destroy (&kbl->datastream.mutex); xfree (kbl); return err; } - err = create_new_context (ctrl, &kbl->ctx); + err = kbx_client_data_new (&kbl->kcd, kbl->ctx); if (err) { - npth_cond_destroy (&kbl->datastream.cond); - npth_mutex_destroy (&kbl->datastream.mutex); + assuan_release (kbl->ctx); xfree (kbl); return err; } @@ -427,224 +300,6 @@ keydb_lock (KEYDB_HANDLE hd) } - -/* FIXME: This helper is duplicates code of partse_keyblock_image. */ -static gpg_error_t -keydb_get_keyblock_do_parse (iobuf_t iobuf, int pk_no, int uid_no, - kbnode_t *r_keyblock) -{ - gpg_error_t err; - struct parse_packet_ctx_s parsectx; - PACKET *pkt; - kbnode_t keyblock = NULL; - kbnode_t node, *tail; - int in_cert, save_mode; - int pk_count, uid_count; - - *r_keyblock = NULL; - - pkt = xtrymalloc (sizeof *pkt); - if (!pkt) - return gpg_error_from_syserror (); - init_packet (pkt); - init_parse_packet (&parsectx, iobuf); - save_mode = set_packet_list_mode (0); - in_cert = 0; - tail = NULL; - pk_count = uid_count = 0; - while ((err = parse_packet (&parsectx, pkt)) != -1) - { - if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET) - { - free_packet (pkt, &parsectx); - init_packet (pkt); - continue; - } - if (err) - { - es_fflush (es_stdout); - log_error ("parse_keyblock_image: read error: %s\n", - gpg_strerror (err)); - if (gpg_err_code (err) == GPG_ERR_INV_PACKET) - { - free_packet (pkt, &parsectx); - init_packet (pkt); - continue; - } - err = gpg_error (GPG_ERR_INV_KEYRING); - break; - } - - /* Filter allowed packets. */ - switch (pkt->pkttype) - { - case PKT_PUBLIC_KEY: - case PKT_PUBLIC_SUBKEY: - case PKT_SECRET_KEY: - case PKT_SECRET_SUBKEY: - case PKT_USER_ID: - case PKT_ATTRIBUTE: - case PKT_SIGNATURE: - case PKT_RING_TRUST: - break; /* Allowed per RFC. */ - - default: - log_info ("skipped packet of type %d in keybox\n", (int)pkt->pkttype); - free_packet(pkt, &parsectx); - init_packet(pkt); - continue; - } - - /* Other sanity checks. */ - if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY) - { - log_error ("parse_keyblock_image: first packet in a keybox blob " - "is not a public key packet\n"); - err = gpg_error (GPG_ERR_INV_KEYRING); - break; - } - if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY - || pkt->pkttype == PKT_SECRET_KEY)) - { - log_error ("parse_keyblock_image: " - "multiple keyblocks in a keybox blob\n"); - err = gpg_error (GPG_ERR_INV_KEYRING); - break; - } - in_cert = 1; - - node = new_kbnode (pkt); - - switch (pkt->pkttype) - { - case PKT_PUBLIC_KEY: - case PKT_PUBLIC_SUBKEY: - case PKT_SECRET_KEY: - case PKT_SECRET_SUBKEY: - if (++pk_count == pk_no) - node->flag |= 1; - break; - - case PKT_USER_ID: - if (++uid_count == uid_no) - node->flag |= 2; - break; - - default: - break; - } - - if (!keyblock) - keyblock = node; - else - *tail = node; - tail = &node->next; - pkt = xtrymalloc (sizeof *pkt); - if (!pkt) - { - err = gpg_error_from_syserror (); - break; - } - init_packet (pkt); - } - set_packet_list_mode (save_mode); - - if (err == -1 && keyblock) - err = 0; /* Got the entire keyblock. */ - - if (err) - release_kbnode (keyblock); - else - { - *r_keyblock = keyblock; - } - free_packet (pkt, &parsectx); - deinit_parse_packet (&parsectx); - xfree (pkt); - return err; -} - - -/* 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. * * On success, the function returns 0 and the caller must free *RET_KB @@ -677,19 +332,13 @@ keydb_get_keyblock (KEYDB_HANDLE hd, kbnode_t *ret_kb) 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); + err = keydb_parse_keyblock (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); @@ -976,7 +625,8 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, gpg_error_t err; int i; char line[ASSUAN_LINELENGTH]; - + char *buffer; + size_t len; if (!hd) return gpg_error (GPG_ERR_INV_ARG); @@ -989,7 +639,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, if (DBG_LOOKUP) { - log_debug ("%s: %zd search descriptions:\n", __func__, ndesc); + log_debug ("%s: %zu search descriptions:\n", __func__, ndesc); for (i = 0; i < ndesc; i ++) { char *t = keydb_search_desc_dump (&desc[i]); @@ -1010,11 +660,6 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, iobuf_close (hd->kbl->search_result); hd->kbl->search_result = NULL; } - if (hd->kbl->datastream.found_keyblock) - { - release_kbnode (hd->kbl->datastream.found_keyblock); - hd->kbl->datastream.found_keyblock = NULL; - } /* Check whether this is a NEXT search. */ if (!hd->kbl->need_search_reset) @@ -1129,72 +774,14 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, do_search: hd->last_ubid_valid = 0; - if (hd->kbl->datastream.fp) - { - /* log_debug ("Sending command '%s'\n", line); */ - err = assuan_transact (hd->kbl->ctx, line, - NULL, NULL, - NULL, NULL, - search_status_cb, hd); - if (err) - { - /* log_debug ("Finished command with error: %s\n", gpg_strerror (err)); */ - /* Fixme: On unexpected errors we need a way to cancel the - * data stream. Probably it will be best to close and - * reopen it. */ - } - else - { - int rc; - - /* log_debug ("Finished command .. telling data stream\n"); */ - lock_datastream (hd->kbl); - if (!hd->kbl->datastream.found_keyblock) - { - /* log_debug ("%s: waiting on datastream_cond ...\n", __func__); */ - rc = npth_cond_wait (&hd->kbl->datastream.cond, - &hd->kbl->datastream.mutex); - /* log_debug ("%s: waiting on datastream.cond done\n", __func__); */ - 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. */ + err = kbx_client_data_cmd (hd->kbl->kcd, line, search_status_cb, hd); + if (!err && !(err = kbx_client_data_wait (hd->kbl->kcd, &buffer, &len))) { - membuf_t data; - void *buffer; - size_t len; - - init_membuf (&data, 8192); - err = assuan_transact (hd->kbl->ctx, line, - put_membuf_cb, &data, - NULL, NULL, - search_status_cb, hd); - if (err) - { - xfree (get_membuf (&data, &len)); - goto leave; - } - - buffer = get_membuf (&data, &len); - if (!buffer) - { - err = gpg_error_from_syserror (); - goto leave; - } - hd->kbl->search_result = iobuf_temp_with_content (buffer, len); xfree (buffer); - } - - /* if (hd->last_ubid_valid) */ - /* log_printhex (hd->last_ubid, 20, "found UBID:"); */ + /* if (hd->last_ubid_valid) */ + /* log_printhex (hd->last_ubid, 20, "found UBID:"); */ + } leave: if (DBG_CLOCK) |