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"
33 #include "ldap-parse-uri.h"
35 /* Called by the engine's help functions to print the actual help. */
37 ks_print_help (ctrl_t ctrl, const char *text)
39 return dirmngr_status_help (ctrl, text);
43 /* Called by the engine's help functions to print the actual help. */
45 ks_printf_help (ctrl_t ctrl, const char *format, ...)
51 va_start (arg_ptr, format);
52 buf = es_vbsprintf (format, arg_ptr);
53 err = buf? 0 : gpg_error_from_syserror ();
56 err = dirmngr_status_help (ctrl, buf);
62 /* Run the help command for the engine responsible for URI. */
64 ks_action_help (ctrl_t ctrl, const char *url)
67 parsed_uri_t parsed_uri; /* The broken down URI. */
71 ks_print_help (ctrl, "Known schemata:\n");
77 err = ldap_parse_uri (&parsed_uri, url);
79 err = http_parse_uri (&parsed_uri, url, 1);
85 /* Call all engines to give them a chance to print a help sting. */
86 err = ks_hkp_help (ctrl, parsed_uri);
88 err = ks_http_help (ctrl, parsed_uri);
90 err = ks_finger_help (ctrl, parsed_uri);
92 err = ks_kdns_help (ctrl, parsed_uri);
94 err = ks_ldap_help (ctrl, parsed_uri);
98 "(Use an URL for engine specific help.)");
100 http_release_parsed_uri (parsed_uri);
105 /* Resolve all host names. This is useful for looking at the status
106 of configured keyservers. */
108 ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers)
114 for (uri = keyservers; !err && uri; uri = uri->next)
116 if (uri->parsed_uri->is_http)
119 err = ks_hkp_resolve (ctrl, uri->parsed_uri);
126 err = gpg_error (GPG_ERR_NO_KEYSERVER);
131 /* Search all configured keyservers for keys matching PATTERNS and
132 write the result to the provided output stream. */
134 ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
135 strlist_t patterns, estream_t outfp)
143 return gpg_error (GPG_ERR_NO_USER_ID);
145 /* FIXME: We only take care of the first pattern. To fully support
146 multiple patterns we might either want to run several queries in
147 parallel and merge them. We also need to decide what to do with
148 errors - it might not be the best idea to ignore an error from
149 one server and silently continue with another server. For now we
150 stop at the first error. */
151 for (uri = keyservers; !err && uri; uri = uri->next)
153 int is_http = uri->parsed_uri->is_http;
154 int is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
155 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
156 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
157 if (is_http || is_ldap)
161 err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp);
163 err = ks_ldap_search (ctrl, uri->parsed_uri, patterns->d, &infp);
167 err = copy_stream (infp, outfp);
175 err = gpg_error (GPG_ERR_NO_KEYSERVER);
180 /* Get the requested keys (matching PATTERNS) using all configured
181 keyservers and write the result to the provided output stream. */
183 ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
184 strlist_t patterns, estream_t outfp)
187 gpg_error_t first_err = 0;
195 return gpg_error (GPG_ERR_NO_USER_ID);
197 /* FIXME: We only take care of the first keyserver. To fully
198 support multiple keyservers we need to track the result for each
199 pattern and use the next keyserver if one key was not found. The
200 keyservers might not all be fully synced thus it is not clear
201 whether the first keyserver has the freshest copy of the key.
202 Need to think about a better strategy. */
203 for (uri = keyservers; !err && uri; uri = uri->next)
205 int is_http = uri->parsed_uri->is_http;
206 int is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
207 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
208 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
209 if (is_http || is_ldap)
212 for (sl = patterns; !err && sl; sl = sl->next)
215 err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
217 err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, &infp);
221 /* It is possible that a server does not carry a
222 key, thus we only save the error and continue
223 with the next pattern. FIXME: It is an open
224 question how to return such an error condition to
231 err = copy_stream (infp, outfp);
232 /* Reading from the keyserver should never fail, thus
233 return this error. */
242 break; /* Stop loop after a keyserver returned something. */
246 err = gpg_error (GPG_ERR_NO_KEYSERVER);
247 else if (!err && first_err && !any_data)
253 /* Retrieve keys from URL and write the result to the provided output
256 ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
260 parsed_uri_t parsed_uri; /* The broken down URI. */
263 return gpg_error (GPG_ERR_INV_URI);
265 err = http_parse_uri (&parsed_uri, url, 1);
269 if (parsed_uri->is_http)
271 err = ks_http_fetch (ctrl, url, &infp);
274 err = copy_stream (infp, outfp);
278 else if (!parsed_uri->opaque)
280 err = gpg_error (GPG_ERR_INV_URI);
282 else if (!strcmp (parsed_uri->scheme, "finger"))
284 err = ks_finger_fetch (ctrl, parsed_uri, &infp);
287 err = copy_stream (infp, outfp);
291 else if (!strcmp (parsed_uri->scheme, "kdns"))
293 err = ks_kdns_fetch (ctrl, parsed_uri, &infp);
296 err = copy_stream (infp, outfp);
301 err = gpg_error (GPG_ERR_INV_URI);
303 http_release_parsed_uri (parsed_uri);
309 /* Send an OpenPGP key to all keyservers. The key in {DATA,DATALEN}
310 is expected to be in OpenPGP binary transport format. The metadata
311 in {INFO,INFOLEN} is in colon-separated format (concretely, it is
312 the output of 'for x in keys sigs; do gpg --list-$x --with-colons
313 KEYID; done'. This function may modify DATA and INFO. If this is
314 a problem, then the caller should create a copy. */
316 ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
317 void *data, size_t datalen,
318 void *info, size_t infolen)
321 gpg_error_t first_err = 0;
325 for (uri = keyservers; !err && uri; uri = uri->next)
327 int is_http = uri->parsed_uri->is_http;
328 int is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
329 || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
330 || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
332 if (is_http || is_ldap)
336 err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
338 err = ks_ldap_put (ctrl, uri->parsed_uri, data, datalen,
350 err = gpg_error (GPG_ERR_NO_KEYSERVER);
351 else if (!err && first_err)