Bump to 2.4.3
[platform/upstream/gpg2.git] / dirmngr / ks-action.c
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
5  *
6  * This file is part of GnuPG.
7  *
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.
12  *
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.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, see <https://www.gnu.org/licenses/>.
20  */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #include "dirmngr.h"
30 #include "misc.h"
31 #include "ks-engine.h"
32 #include "ks-action.h"
33 #if USE_LDAP
34 # include "ldap-parse-uri.h"
35 #endif
36
37
38 /* Parse an URI and store it in a new parsed URI item object which is
39  * returned at R_PARSEDURI (with its next set to NULL).  On error an
40  * error code is returned an NULL stored at R_PARSEDITEM.  */
41 gpg_error_t
42 ks_action_parse_uri (const char *uri, uri_item_t *r_parseduri)
43 {
44   gpg_error_t err;
45   uri_item_t item;
46   char *tmpstr = NULL;
47 #if USE_LDAP
48   const char *s;
49 #endif
50
51   *r_parseduri = NULL;
52
53   if (!uri)
54     return gpg_error (GPG_ERR_INV_URI);
55
56   item = xtrymalloc (sizeof *item + strlen (uri));
57   if (!item)
58     return gpg_error_from_syserror ();
59
60   item->next = NULL;
61   item->parsed_uri = NULL;
62   strcpy (item->uri, uri);
63
64 #if USE_LDAP
65   if (!strncmp (uri, "ldap:", 5) && !(uri[5] == '/' && uri[6] == '/'))
66     {
67       /* Special ldap scheme given.  This differs from a valid ldap
68        * scheme in that no double slash follows.  We use
69        * http_parse_uri to put it as opaque value into parsed_uri.  */
70       tmpstr = strconcat ("opaque:", uri+5, NULL);
71       if (!tmpstr)
72         err = gpg_error_from_syserror ();
73       else
74         err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
75     }
76   else if ((s=strchr (uri, ':')) && !(s[1] == '/' && s[2] == '/'))
77     {
78       /* No valid scheme given.  We use http_parse_uri to put the
79        * string as opaque value into parsed_uri.  */
80       tmpstr = strconcat ("opaque:", uri, NULL);
81       if (!tmpstr)
82         err = gpg_error_from_syserror ();
83       else
84         err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
85     }
86   else if (ldap_uri_p (uri))
87     {
88       int fixup = 0;
89       /* Fixme: We should get rid of that parser and replace it with
90        * our generic (http) URI parser.  */
91
92       /* If no port has been specified and the scheme ist ldaps we use
93        * our idea of the default port because the standard LDAP URL
94        * parser would use 636 here.  This is because we redefined
95        * ldaps to mean starttls.  */
96 #ifdef HAVE_W32_SYSTEM
97       if (!strcmp (uri, "ldap:///"))
98           fixup = 1;
99       else
100 #endif
101         if (!http_parse_uri (&item->parsed_uri,uri,HTTP_PARSE_NO_SCHEME_CHECK))
102         {
103           if (!item->parsed_uri->port
104               && !strcmp (item->parsed_uri->scheme, "ldaps"))
105             fixup = 2;
106           http_release_parsed_uri (item->parsed_uri);
107           item->parsed_uri = NULL;
108         }
109
110       err = ldap_parse_uri (&item->parsed_uri, uri);
111       if (!err && fixup == 1)
112         item->parsed_uri->ad_current = 1;
113       else if (!err && fixup == 2)
114         item->parsed_uri->port = 389;
115     }
116   else
117 #endif /* USE_LDAP */
118     {
119       err = http_parse_uri (&item->parsed_uri, uri, HTTP_PARSE_NO_SCHEME_CHECK);
120     }
121
122   xfree (tmpstr);
123   if (err)
124     xfree (item);
125   else
126     *r_parseduri = item;
127   return err;
128 }
129
130
131 /* Called by the engine's help functions to print the actual help.  */
132 gpg_error_t
133 ks_print_help (ctrl_t ctrl, const char *text)
134 {
135   return dirmngr_status_help (ctrl, text);
136 }
137
138
139 /* Called by the engine's help functions to print the actual help.  */
140 gpg_error_t
141 ks_printf_help (ctrl_t ctrl, const char *format, ...)
142 {
143   va_list arg_ptr;
144   gpg_error_t err;
145   char *buf;
146
147   va_start (arg_ptr, format);
148   buf = es_vbsprintf (format, arg_ptr);
149   err = buf? 0 : gpg_error_from_syserror ();
150   va_end (arg_ptr);
151   if (!err)
152     err = dirmngr_status_help (ctrl, buf);
153   es_free (buf);
154   return err;
155 }
156
157
158 /* Run the help command for the engine responsible for URI.  */
159 gpg_error_t
160 ks_action_help (ctrl_t ctrl, const char *url)
161 {
162   gpg_error_t err;
163   parsed_uri_t parsed_uri;  /* The broken down URI.  */
164 #if USE_LDAP
165   char *tmpstr;
166   const char *s;
167 #endif
168
169   if (!url || !*url)
170     {
171       ks_print_help (ctrl, "Known schemata:\n");
172       parsed_uri = NULL;
173     }
174   else
175     {
176 #if USE_LDAP
177       if (!strncmp (url, "ldap:", 5) && !(url[5] == '/' && url[6] == '/'))
178         {
179           /* Special ldap scheme given.  This differs from a valid
180            * ldap scheme in that no double slash follows.  Use
181            * http_parse_uri to put it as opaque value into parsed_uri.  */
182           tmpstr = strconcat ("opaque:", url+5, NULL);
183           if (!tmpstr)
184             err = gpg_error_from_syserror ();
185           else
186             {
187               err = http_parse_uri (&parsed_uri, tmpstr, 0);
188               xfree (tmpstr);
189             }
190         }
191       else if ((s=strchr (url, ':')) && !(s[1] == '/' && s[2] == '/'))
192         {
193           /* No scheme given.  Use http_parse_uri to put the string as
194            * opaque value into parsed_uri.  */
195           tmpstr = strconcat ("opaque:", url, NULL);
196           if (!tmpstr)
197             err = gpg_error_from_syserror ();
198           else
199             {
200               err = http_parse_uri (&parsed_uri, tmpstr, 0);
201               xfree (tmpstr);
202             }
203         }
204       else if (ldap_uri_p (url))
205         err = ldap_parse_uri (&parsed_uri, url);
206       else
207 #endif
208         {
209           err = http_parse_uri (&parsed_uri, url, HTTP_PARSE_NO_SCHEME_CHECK);
210         }
211
212       if (err)
213         return err;
214     }
215
216   /* Call all engines to give them a chance to print a help string.  */
217   err = ks_hkp_help (ctrl, parsed_uri);
218   if (!err)
219     err = ks_http_help (ctrl, parsed_uri);
220   if (!err)
221     err = ks_finger_help (ctrl, parsed_uri);
222   if (!err)
223     err = ks_kdns_help (ctrl, parsed_uri);
224 #if USE_LDAP
225   if (!err)
226     err = ks_ldap_help (ctrl, parsed_uri);
227 #endif
228
229   if (!parsed_uri)
230     ks_print_help (ctrl,
231                    "(Use an URL for engine specific help.)");
232   else
233     http_release_parsed_uri (parsed_uri);
234   return err;
235 }
236
237
238 /* Resolve all host names.  This is useful for looking at the status
239    of configured keyservers.  */
240 gpg_error_t
241 ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers)
242 {
243   gpg_error_t err = 0;
244   int any_server = 0;
245   uri_item_t uri;
246
247   for (uri = keyservers; !err && uri; uri = uri->next)
248     {
249       if (uri->parsed_uri->is_http)
250         {
251           any_server = 1;
252           err = ks_hkp_resolve (ctrl, uri->parsed_uri);
253           if (err)
254             break;
255         }
256     }
257
258   if (!any_server)
259     err = gpg_error (GPG_ERR_NO_KEYSERVER);
260   return err;
261 }
262
263
264 /* Search all configured keyservers for keys matching PATTERNS and
265    write the result to the provided output stream.  */
266 gpg_error_t
267 ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
268                   strlist_t patterns, estream_t outfp)
269 {
270   gpg_error_t err = 0;
271   int any_server = 0;
272   int any_results = 0;
273   uri_item_t uri;
274   estream_t infp;
275
276   if (!patterns)
277     return gpg_error (GPG_ERR_NO_USER_ID);
278
279   /* FIXME: We only take care of the first pattern.  To fully support
280      multiple patterns we might either want to run several queries in
281      parallel and merge them.  We also need to decide what to do with
282      errors - it might not be the best idea to ignore an error from
283      one server and silently continue with another server.  For now we
284      stop at the first error, unless the server responds with '404 Not
285      Found', in which case we try the next server.  */
286   for (uri = keyservers; !err && uri; uri = uri->next)
287     {
288       int is_http = uri->parsed_uri->is_http;
289       int is_ldap = 0;
290       unsigned int http_status = 0;
291 #if USE_LDAP
292       is_ldap = (!strcmp (uri->parsed_uri->scheme, "ldap")
293                  || !strcmp (uri->parsed_uri->scheme, "ldaps")
294                  || !strcmp (uri->parsed_uri->scheme, "ldapi")
295                  || uri->parsed_uri->opaque);
296 #endif
297       if (is_http || is_ldap)
298         {
299           any_server = 1;
300 #if USE_LDAP
301           if (is_ldap)
302             err = ks_ldap_search (ctrl, uri->parsed_uri, patterns->d, &infp);
303           else
304 #endif
305             {
306               err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d,
307                                    &infp, &http_status);
308             }
309
310           if (err == gpg_error (GPG_ERR_NO_DATA)
311               && http_status == 404 /* not found */)
312             {
313               /* No record found.  Clear error and try next server.  */
314               err = 0;
315               continue;
316             }
317
318           if (!err)
319             {
320               err = copy_stream (infp, outfp);
321               es_fclose (infp);
322               any_results = 1;
323               break;
324             }
325         }
326     }
327
328   if (!any_server)
329     err = gpg_error (GPG_ERR_NO_KEYSERVER);
330   else if (err == 0 && !any_results)
331     err = gpg_error (GPG_ERR_NO_DATA);
332   return err;
333 }
334
335
336 /* Get the requested keys (matching PATTERNS) using all configured
337    keyservers and write the result to the provided output stream.  */
338 gpg_error_t
339 ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
340                strlist_t patterns, unsigned int ks_get_flags,
341                gnupg_isotime_t newer, estream_t outfp)
342 {
343   gpg_error_t err = 0;
344   gpg_error_t first_err = 0;
345   int any_server = 0;
346   int any_data = 0;
347   strlist_t sl;
348   uri_item_t uri;
349   estream_t infp;
350
351   if (!patterns)
352     return gpg_error (GPG_ERR_NO_USER_ID);
353
354   /* FIXME: We only take care of the first keyserver.  To fully
355      support multiple keyservers we need to track the result for each
356      pattern and use the next keyserver if one key was not found.  The
357      keyservers might not all be fully synced thus it is not clear
358      whether the first keyserver has the freshest copy of the key.
359      Need to think about a better strategy.  */
360   for (uri = keyservers; !err && uri; uri = uri->next)
361     {
362       int is_hkp_s = (strcmp (uri->parsed_uri->scheme, "hkp") == 0
363                       || strcmp (uri->parsed_uri->scheme, "hkps") == 0);
364       int is_http_s = (strcmp (uri->parsed_uri->scheme, "http") == 0
365                        || strcmp (uri->parsed_uri->scheme, "https") == 0);
366       int is_ldap = 0;
367
368       if ((ks_get_flags & (KS_GET_FLAG_ONLY_LDAP|KS_GET_FLAG_ONLY_AD)))
369         is_hkp_s = is_http_s = 0;
370
371 #if USE_LDAP
372       is_ldap = (!strcmp (uri->parsed_uri->scheme, "ldap")
373                  || !strcmp (uri->parsed_uri->scheme, "ldaps")
374                  || !strcmp (uri->parsed_uri->scheme, "ldapi")
375                  || uri->parsed_uri->opaque);
376 #endif
377
378       if (is_hkp_s || is_http_s || is_ldap)
379         {
380           any_server = 1;
381           for (sl = patterns; !err && sl; sl = sl->next)
382             {
383 #if USE_LDAP
384               if (is_ldap)
385                 err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, ks_get_flags,
386                                    newer, &infp);
387               else
388 #endif
389               if (is_hkp_s)
390                 err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
391               else if (is_http_s)
392                 err = ks_http_fetch (ctrl, uri->parsed_uri->original,
393                                      KS_HTTP_FETCH_NOCACHE,
394                                      &infp);
395               else
396                 BUG ();
397
398               if (err)
399                 {
400                   /* It is possible that a server does not carry a
401                      key, thus we only save the error and continue
402                      with the next pattern.  FIXME: It is an open
403                      question how to return such an error condition to
404                      the caller.  */
405                   first_err = err;
406                   err = 0;
407                 }
408               else
409                 {
410                   err = copy_stream (infp, outfp);
411                   /* Reading from the keyserver should never fail, thus
412                      return this error.  */
413                   if (!err)
414                     any_data = 1;
415                   es_fclose (infp);
416                   infp = NULL;
417                 }
418             }
419         }
420       if (any_data)
421         break; /* Stop loop after a keyserver returned something.  */
422     }
423
424   if (!any_server)
425     err = gpg_error (GPG_ERR_NO_KEYSERVER);
426   else if (!err && first_err && !any_data)
427     err = first_err;
428   return err;
429 }
430
431
432 /* Retrieve keys from URL and write the result to the provided output
433  * stream OUTFP.  If OUTFP is NULL the data is written to the bit
434  * bucket. */
435 gpg_error_t
436 ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
437 {
438   gpg_error_t err = 0;
439   estream_t infp;
440   parsed_uri_t parsed_uri;  /* The broken down URI.  */
441
442   if (!url)
443     return gpg_error (GPG_ERR_INV_URI);
444
445   err = http_parse_uri (&parsed_uri, url, HTTP_PARSE_NO_SCHEME_CHECK);
446   if (err)
447     return err;
448
449   if (parsed_uri->is_http)
450     {
451       err = ks_http_fetch (ctrl, url, KS_HTTP_FETCH_NOCACHE, &infp);
452       if (!err)
453         {
454           err = copy_stream (infp, outfp);
455           es_fclose (infp);
456         }
457     }
458   else if (!parsed_uri->opaque)
459     {
460       err = gpg_error (GPG_ERR_INV_URI);
461     }
462   else if (!strcmp (parsed_uri->scheme, "finger"))
463     {
464       err = ks_finger_fetch (ctrl, parsed_uri, &infp);
465       if (!err)
466         {
467           err = copy_stream (infp, outfp);
468           es_fclose (infp);
469         }
470     }
471   else if (!strcmp (parsed_uri->scheme, "kdns"))
472     {
473       err = ks_kdns_fetch (ctrl, parsed_uri, &infp);
474       if (!err)
475         {
476           err = copy_stream (infp, outfp);
477           es_fclose (infp);
478         }
479     }
480   else
481     err = gpg_error (GPG_ERR_INV_URI);
482
483   http_release_parsed_uri (parsed_uri);
484   return err;
485 }
486
487
488
489 /* Send an OpenPGP key to all keyservers.  The key in {DATA,DATALEN}
490    is expected to be in OpenPGP binary transport format.  The metadata
491    in {INFO,INFOLEN} is in colon-separated format (concretely, it is
492    the output of 'gpg --list-keys --with-colons KEYID').  This function
493    may modify DATA and INFO.  If this is a problem, then the caller
494    should create a copy.  */
495 gpg_error_t
496 ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
497                void *data, size_t datalen,
498                void *info, size_t infolen)
499 {
500   gpg_error_t err = 0;
501   gpg_error_t first_err = 0;
502   int any_server = 0;
503   uri_item_t uri;
504
505   (void) info;
506   (void) infolen;
507
508   for (uri = keyservers; !err && uri; uri = uri->next)
509     {
510       int is_http = uri->parsed_uri->is_http;
511       int is_ldap = 0;
512
513 #if USE_LDAP
514       is_ldap = (!strcmp (uri->parsed_uri->scheme, "ldap")
515                  || !strcmp (uri->parsed_uri->scheme, "ldaps")
516                  || !strcmp (uri->parsed_uri->scheme, "ldapi")
517                  || uri->parsed_uri->opaque);
518 #endif
519
520       if (is_http || is_ldap)
521         {
522           any_server = 1;
523 #if USE_LDAP
524           if (is_ldap)
525             err = ks_ldap_put (ctrl, uri->parsed_uri, data, datalen,
526                                info, infolen);
527           else
528 #endif
529             {
530               err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
531             }
532           if (err)
533             {
534               first_err = err;
535               err = 0;
536             }
537         }
538     }
539
540   if (!any_server)
541     err = gpg_error (GPG_ERR_NO_KEYSERVER);
542   else if (!err && first_err)
543     err = first_err;
544   return err;
545 }
546
547
548
549 /* Query the default LDAP server or the one given by URL using
550  * the filter expression FILTER.  Write the result to OUTFP.  */
551 gpg_error_t
552 ks_action_query (ctrl_t ctrl, const char *url, unsigned int ks_get_flags,
553                  const char *filter, char **attrs,
554                  gnupg_isotime_t newer, estream_t outfp)
555 {
556 #if USE_LDAP
557   gpg_error_t err;
558   estream_t infp = NULL;
559   uri_item_t puri;  /* The broken down URI (only one item used).  */
560
561   if (!url && (ks_get_flags & KS_GET_FLAG_ROOTDSE))
562     url = "ldap://";
563
564   err = ks_action_parse_uri (url, &puri);
565   if (err)
566     return err;
567
568   if ((ks_get_flags & KS_GET_FLAG_ROOTDSE))
569     {
570       /* Reset authentication for a serverless connection.  */
571       puri->parsed_uri->ad_current = 0;
572       puri->parsed_uri->auth = NULL;
573     }
574
575   if (!strcmp (puri->parsed_uri->scheme, "ldap")
576       || !strcmp (puri->parsed_uri->scheme, "ldaps")
577       || !strcmp (puri->parsed_uri->scheme, "ldapi")
578       || puri->parsed_uri->opaque)
579     {
580       err = ks_ldap_query (ctrl, puri->parsed_uri, ks_get_flags, filter,
581                            attrs, newer, &infp);
582       if (!err)
583         err = copy_stream (infp, outfp);
584     }
585   else
586     err = gpg_error (GPG_ERR_CONFIGURATION); /* No LDAP server known.  */
587
588   es_fclose (infp);
589   release_uri_item_list (puri);
590   return err;
591
592 #else /* !USE_LDAP */
593   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
594 #endif
595 }