/* Retrieve keys from URL and write the result to the provided output stream OUTFP. */ gpg_error_t ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp) { gpg_error_t err = 0; estream_t infp; parsed_uri_t parsed_uri; /* The broken down URI. */ if (!url) return gpg_error (GPG_ERR_INV_URI); err = http_parse_uri (&parsed_uri, url, 1); if (err) return err; if (parsed_uri->is_http) { err = ks_http_fetch (ctrl, url, &infp); if (!err) { err = copy_stream (infp, outfp); es_fclose (infp); } } else if (!parsed_uri->opaque) { err = gpg_error (GPG_ERR_INV_URI); } else if (!strcmp (parsed_uri->scheme, "finger")) { err = ks_finger_fetch (ctrl, parsed_uri, &infp); if (!err) { err = copy_stream (infp, outfp); es_fclose (infp); } } else if (!strcmp (parsed_uri->scheme, "kdns")) { err = ks_kdns_fetch (ctrl, parsed_uri, &infp); if (!err) { err = copy_stream (infp, outfp); es_fclose (infp); } } else err = gpg_error (GPG_ERR_INV_URI); http_release_parsed_uri (parsed_uri); return err; }
/* Get the requested keys (matching PATTERNS) using all configured keyservers and write the result to the provided output stream. */ gpg_error_t ks_action_get (ctrl_t ctrl, uri_item_t keyservers, strlist_t patterns, estream_t outfp) { gpg_error_t err = 0; gpg_error_t first_err = 0; int any_server = 0; int any_data = 0; strlist_t sl; uri_item_t uri; estream_t infp; if (!patterns) return gpg_error (GPG_ERR_NO_USER_ID); /* FIXME: We only take care of the first keyserver. To fully support multiple keyservers we need to track the result for each pattern and use the next keyserver if one key was not found. The keyservers might not all be fully synced thus it is not clear whether the first keyserver has the freshest copy of the key. Need to think about a better strategy. */ for (uri = keyservers; !err && uri; uri = uri->next) { int is_hkp_s = (strcmp (uri->parsed_uri->scheme, "hkp") == 0 || strcmp (uri->parsed_uri->scheme, "hkps") == 0); int is_http_s = (strcmp (uri->parsed_uri->scheme, "http") == 0 || strcmp (uri->parsed_uri->scheme, "https") == 0); int is_ldap = 0; #if USE_LDAP is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0); #endif if (is_hkp_s || is_http_s || is_ldap) { any_server = 1; for (sl = patterns; !err && sl; sl = sl->next) { #if USE_LDAP if (is_ldap) err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, &infp); else #endif if (is_hkp_s) err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp); else if (is_http_s) err = ks_http_fetch (ctrl, uri->parsed_uri->original, &infp); else BUG (); if (err) { /* It is possible that a server does not carry a key, thus we only save the error and continue with the next pattern. FIXME: It is an open question how to return such an error condition to the caller. */ first_err = err; err = 0; } else { err = copy_stream (infp, outfp); /* Reading from the keyserver should never fail, thus return this error. */ if (!err) any_data = 1; es_fclose (infp); infp = NULL; } } } if (any_data) break; /* Stop loop after a keyserver returned something. */ } if (!any_server) err = gpg_error (GPG_ERR_NO_KEYSERVER); else if (!err && first_err && !any_data) err = first_err; return err; }