1 /* ks-action.c - OpenPGP keyserver actions
2 * Copyright (C) 2011 Free Software Foundation, Inc.
3 * Copyright (C) 2011, 2014 Werner Koch
4 * Copyright (C) 2015 g10 Code GmbH
6 * This file is part of GnuPG.
8 * GnuPG is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * GnuPG is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
31 #include "ks-engine.h"
32 #include "ks-action.h"
34 # include "ldap-parse-uri.h"
37 /* Called by the engine's help functions to print the actual help. */
39 ks_print_help (ctrl_t ctrl, const char *text)
41 return dirmngr_status_help (ctrl, text);
45 /* Called by the engine's help functions to print the actual help. */
47 ks_printf_help (ctrl_t ctrl, const char *format, ...)
53 va_start (arg_ptr, format);
54 buf = es_vbsprintf (format, arg_ptr);
55 err = buf? 0 : gpg_error_from_syserror ();
58 err = dirmngr_status_help (ctrl, buf);
64 /* Run the help command for the engine responsible for URI. */
66 ks_action_help (ctrl_t ctrl, const char *url)
69 parsed_uri_t parsed_uri; /* The broken down URI. */
73 ks_print_help (ctrl, "Known schemata:\n");
80 err = ldap_parse_uri (&parsed_uri, url);
84 err = http_parse_uri (&parsed_uri, url, 1);
91 /* Call all engines to give them a chance to print a help sting. */
92 err = ks_hkp_help (ctrl, parsed_uri);
94 err = ks_http_help (ctrl, parsed_uri);
96 err = ks_finger_help (ctrl, parsed_uri);
98 err = ks_kdns_help (ctrl, parsed_uri);
101 err = ks_ldap_help (ctrl, parsed_uri);
106 "(Use an URL for engine specific help.)");
108 http_release_parsed_uri (parsed_uri);
113 /* Resolve all host names. This is useful for looking at the status
114 of configured keyservers. */
116 ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers)
122 for (uri = keyservers; !err && uri; uri = uri->next)
124 if (uri->parsed_uri->is_http)
127 err = ks_hkp_resolve (ctrl, uri->parsed_uri);
134 err = gpg_error (GPG_ERR_NO_KEYSERVER);
139 /* Search all configured keyservers for keys matching PATTERNS and
140 write the result to the provided output stream. */
142 ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
143 strlist_t patterns, estream_t outfp)
151 return gpg_error (GPG_ERR_NO_USER_ID);
153 /* FIXME: We only take care of the first pattern. To fully support
154 multiple patterns we might either want to run several queries in
155 parallel and merge them. We also need to decide what to do with
156 errors - it might not be the best idea to ignore an error from
157 one server and silently continue with another server. For now we
158 stop at the first error. */
159 for (uri = keyservers; !err && uri; uri = uri->next)
161 int is_http = uri->parsed_uri->is_http;
164 is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
165 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
166 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
168 if (is_http || is_ldap)
173 err = ks_ldap_search (ctrl, uri->parsed_uri, patterns->d, &infp);
177 err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp);
182 err = copy_stream (infp, outfp);
190 err = gpg_error (GPG_ERR_NO_KEYSERVER);
195 /* Get the requested keys (matching PATTERNS) using all configured
196 keyservers and write the result to the provided output stream. */
198 ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
199 strlist_t patterns, estream_t outfp)
202 gpg_error_t first_err = 0;
210 return gpg_error (GPG_ERR_NO_USER_ID);
212 /* FIXME: We only take care of the first keyserver. To fully
213 support multiple keyservers we need to track the result for each
214 pattern and use the next keyserver if one key was not found. The
215 keyservers might not all be fully synced thus it is not clear
216 whether the first keyserver has the freshest copy of the key.
217 Need to think about a better strategy. */
218 for (uri = keyservers; !err && uri; uri = uri->next)
220 int is_http = uri->parsed_uri->is_http;
224 is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
225 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
226 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
229 if (is_http || is_ldap)
232 for (sl = patterns; !err && sl; sl = sl->next)
236 err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, &infp);
240 err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
245 /* It is possible that a server does not carry a
246 key, thus we only save the error and continue
247 with the next pattern. FIXME: It is an open
248 question how to return such an error condition to
255 err = copy_stream (infp, outfp);
256 /* Reading from the keyserver should never fail, thus
257 return this error. */
266 break; /* Stop loop after a keyserver returned something. */
270 err = gpg_error (GPG_ERR_NO_KEYSERVER);
271 else if (!err && first_err && !any_data)
277 /* Retrieve keys from URL and write the result to the provided output
280 ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
284 parsed_uri_t parsed_uri; /* The broken down URI. */
287 return gpg_error (GPG_ERR_INV_URI);
289 err = http_parse_uri (&parsed_uri, url, 1);
293 if (parsed_uri->is_http)
295 err = ks_http_fetch (ctrl, url, &infp);
298 err = copy_stream (infp, outfp);
302 else if (!parsed_uri->opaque)
304 err = gpg_error (GPG_ERR_INV_URI);
306 else if (!strcmp (parsed_uri->scheme, "finger"))
308 err = ks_finger_fetch (ctrl, parsed_uri, &infp);
311 err = copy_stream (infp, outfp);
315 else if (!strcmp (parsed_uri->scheme, "kdns"))
317 err = ks_kdns_fetch (ctrl, parsed_uri, &infp);
320 err = copy_stream (infp, outfp);
325 err = gpg_error (GPG_ERR_INV_URI);
327 http_release_parsed_uri (parsed_uri);
333 /* Send an OpenPGP key to all keyservers. The key in {DATA,DATALEN}
334 is expected to be in OpenPGP binary transport format. The metadata
335 in {INFO,INFOLEN} is in colon-separated format (concretely, it is
336 the output of 'for x in keys sigs; do gpg --list-$x --with-colons
337 KEYID; done'. This function may modify DATA and INFO. If this is
338 a problem, then the caller should create a copy. */
340 ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
341 void *data, size_t datalen,
342 void *info, size_t infolen)
345 gpg_error_t first_err = 0;
352 for (uri = keyservers; !err && uri; uri = uri->next)
354 int is_http = uri->parsed_uri->is_http;
358 is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
359 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
360 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
363 if (is_http || is_ldap)
368 err = ks_ldap_put (ctrl, uri->parsed_uri, data, datalen,
373 err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
384 err = gpg_error (GPG_ERR_NO_KEYSERVER);
385 else if (!err && first_err)