1 /* ks-action.c - OpenPGP keyserver actions
2 * Copyright (C) 2011 Free Software Foundation, Inc.
3 * Copyright (C) 2011, 2014 Werner Koch
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
30 #include "ks-engine.h"
31 #include "ks-action.h"
34 /* Copy all data from IN to OUT. */
36 copy_stream (estream_t in, estream_t out)
41 while (!es_read (in, buffer, sizeof buffer, &nread))
45 if (es_write (out, buffer, nread, NULL))
49 return gpg_error_from_syserror ();
53 /* Called by the engine's help functions to print the actual help. */
55 ks_print_help (ctrl_t ctrl, const char *text)
57 return dirmngr_status_help (ctrl, text);
61 /* Called by the engine's help functions to print the actual help. */
63 ks_printf_help (ctrl_t ctrl, const char *format, ...)
69 va_start (arg_ptr, format);
70 buf = es_vbsprintf (format, arg_ptr);
71 err = buf? 0 : gpg_error_from_syserror ();
74 err = dirmngr_status_help (ctrl, buf);
80 /* Run the help command for the engine responsible for URI. */
82 ks_action_help (ctrl_t ctrl, const char *url)
85 parsed_uri_t parsed_uri; /* The broken down URI. */
89 ks_print_help (ctrl, "Known schemata:\n");
94 err = http_parse_uri (&parsed_uri, url, 1);
99 /* Call all engines to give them a chance to print a help sting. */
100 err = ks_hkp_help (ctrl, parsed_uri);
102 err = ks_http_help (ctrl, parsed_uri);
104 err = ks_finger_help (ctrl, parsed_uri);
106 err = ks_kdns_help (ctrl, parsed_uri);
110 "(Use an URL for engine specific help.)");
112 http_release_parsed_uri (parsed_uri);
117 /* Resolve all host names. This is useful for looking at the status
118 of configured keyservers. */
120 ks_action_resolve (ctrl_t ctrl)
126 for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
128 if (uri->parsed_uri->is_http)
131 err = ks_hkp_resolve (ctrl, uri->parsed_uri);
138 err = gpg_error (GPG_ERR_NO_KEYSERVER);
143 /* Search all configured keyservers for keys matching PATTERNS and
144 write the result to the provided output stream. */
146 ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
154 return gpg_error (GPG_ERR_NO_USER_ID);
156 /* FIXME: We only take care of the first pattern. To fully support
157 multiple patterns we might either want to run several queries in
158 parallel and merge them. We also need to decide what to do with
159 errors - it might not be the best idea to ignore an error from
160 one server and silently continue with another server. For now we
161 stop at the first error. */
162 for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
164 if (uri->parsed_uri->is_http)
167 err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp);
170 err = copy_stream (infp, outfp);
178 err = gpg_error (GPG_ERR_NO_KEYSERVER);
183 /* Get the requested keys (matching PATTERNS) using all configured
184 keyservers and write the result to the provided output stream. */
186 ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
189 gpg_error_t first_err = 0;
197 return gpg_error (GPG_ERR_NO_USER_ID);
199 /* FIXME: We only take care of the first keyserver. To fully
200 support multiple keyservers we need to track the result for each
201 pattern and use the next keyserver if one key was not found. The
202 keyservers might not all be fully synced thus it is not clear
203 whether the first keyserver has the freshest copy of the key.
204 Need to think about a better strategy. */
205 for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
207 if (uri->parsed_uri->is_http)
210 for (sl = patterns; !err && sl; sl = sl->next)
212 err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
215 /* It is possible that a server does not carry a
216 key, thus we only save the error and continue
217 with the next pattern. FIXME: It is an open
218 question how to return such an error condition to
225 err = copy_stream (infp, outfp);
226 /* Reading from the keyserver should never fail, thus
227 return this error. */
236 break; /* Stop loop after a keyserver returned something. */
240 err = gpg_error (GPG_ERR_NO_KEYSERVER);
241 else if (!err && first_err && !any_data)
247 /* Retrieve keys from URL and write the result to the provided output
250 ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
254 parsed_uri_t parsed_uri; /* The broken down URI. */
257 return gpg_error (GPG_ERR_INV_URI);
259 err = http_parse_uri (&parsed_uri, url, 1);
263 if (parsed_uri->is_http)
265 err = ks_http_fetch (ctrl, url, &infp);
268 err = copy_stream (infp, outfp);
272 else if (!parsed_uri->opaque)
274 err = gpg_error (GPG_ERR_INV_URI);
276 else if (!strcmp (parsed_uri->scheme, "finger"))
278 err = ks_finger_fetch (ctrl, parsed_uri, &infp);
281 err = copy_stream (infp, outfp);
285 else if (!strcmp (parsed_uri->scheme, "kdns"))
287 err = ks_kdns_fetch (ctrl, parsed_uri, &infp);
290 err = copy_stream (infp, outfp);
295 err = gpg_error (GPG_ERR_INV_URI);
297 http_release_parsed_uri (parsed_uri);
303 /* Send an OpenPGP key to all keyservers. The key in {DATA,DATALEN}
304 is expected in OpenPGP binary transport format. */
306 ks_action_put (ctrl_t ctrl, const void *data, size_t datalen)
309 gpg_error_t first_err = 0;
313 for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
315 if (uri->parsed_uri->is_http)
318 err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
328 err = gpg_error (GPG_ERR_NO_KEYSERVER);
329 else if (!err && first_err)