dirmngr: Retry another server from the pool on 502, 503, 504.
[gnupg.git] / dirmngr / ks-engine-hkp.c
1 /* ks-engine-hkp.c - HKP keyserver engine
2  * Copyright (C) 2011, 2012 Free Software Foundation, Inc.
3  * Copyright (C) 2011, 2012, 2014 Werner Koch
4  *
5  * This file is part of GnuPG.
6  *
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.
11  *
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.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #ifdef HAVE_W32_SYSTEM
28 # ifdef HAVE_WINSOCK2_H
29 #  include <winsock2.h>
30 # endif
31 # include <windows.h>
32 #else /*!HAVE_W32_SYSTEM*/
33 # include <sys/types.h>
34 # include <sys/socket.h>
35 # include <netdb.h>
36 #endif /*!HAVE_W32_SYSTEM*/
37
38 #include <npth.h>
39 #include "dirmngr.h"
40 #include "misc.h"
41 #include "../common/userids.h"
42 #include "dns-stuff.h"
43 #include "ks-engine.h"
44
45 /* Substitutes for missing Mingw macro.  The EAI_SYSTEM mechanism
46    seems not to be available (probably because there is only one set
47    of error codes anyway).  For now we use WSAEINVAL. */
48 #ifndef EAI_OVERFLOW
49 # define EAI_OVERFLOW EAI_FAIL
50 #endif
51 #ifdef HAVE_W32_SYSTEM
52 # ifndef EAI_SYSTEM
53 #  define EAI_SYSTEM WSAEINVAL
54 # endif
55 #endif
56
57
58 /* Number of seconds after a host is marked as resurrected.  */
59 #define RESURRECT_INTERVAL  (3600+1800)  /* 1.5 hours */
60
61 /* To match the behaviour of our old gpgkeys helper code we escape
62    more characters than actually needed. */
63 #define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
64
65 /* How many redirections do we allow.  */
66 #define MAX_REDIRECTS 2
67
68 /* Number of retries done for a dead host etc.  */
69 #define SEND_REQUEST_RETRIES 3
70
71 enum ks_protocol { KS_PROTOCOL_HKP, KS_PROTOCOL_HKPS, KS_PROTOCOL_MAX };
72
73 /* Objects used to maintain information about hosts.  */
74 struct hostinfo_s;
75 typedef struct hostinfo_s *hostinfo_t;
76 struct hostinfo_s
77 {
78   time_t lastfail;   /* Time we tried to connect and failed.  */
79   time_t lastused;   /* Time of last use.  */
80   int *pool;         /* An array with indices into HOSTTABLE or NULL
81                         if NAME is not a pool name.  */
82   size_t pool_len;   /* Length of POOL.  */
83   size_t pool_size;  /* Allocated size of POOL.  */
84 #define MAX_POOL_SIZE   128
85   int poolidx;       /* Index into POOL with the used host.  -1 if not set.  */
86   unsigned int v4:1; /* Host supports AF_INET.  */
87   unsigned int v6:1; /* Host supports AF_INET6.  */
88   unsigned int onion:1;/* NAME is an onion (Tor HS) address.  */
89   unsigned int dead:1; /* Host is currently unresponsive.  */
90   unsigned int iporname_valid:1;  /* The field IPORNAME below is valid */
91                                   /* (but may be NULL) */
92   unsigned int did_a_lookup:1;    /* Have we done an A lookup yet?  */
93   unsigned int did_srv_lookup:2;  /* One bit per protocol indicating
94                                      whether we already did a SRV
95                                      lookup.  */
96   time_t died_at;    /* The time the host was marked dead.  If this is
97                         0 the host has been manually marked dead.  */
98   char *cname;       /* Canonical name of the host.  Only set if this
99                         is a pool or NAME has a numerical IP address.  */
100   char *iporname;    /* Numeric IP address or name for printing.  */
101   unsigned short port[KS_PROTOCOL_MAX];
102                      /* The port used by the host for all protocols, 0
103                         if unknown.  */
104   char name[1];      /* The hostname.  */
105 };
106
107
108 /* An array of hostinfo_t for all hosts requested by the caller or
109    resolved from a pool name and its allocated size.*/
110 static hostinfo_t *hosttable;
111 static int hosttable_size;
112 /* A mutex used to serialize access to the hosttable. */
113 static npth_mutex_t hosttable_lock;
114
115 /* The number of host slots we initially allocate for HOSTTABLE.  */
116 #define INITIAL_HOSTTABLE_SIZE 50
117
118
119 /* Create a new hostinfo object, fill in NAME and put it into
120    HOSTTABLE.  Return the index into hosttable on success or -1 on
121    error. */
122 static int
123 create_new_hostinfo (const char *name)
124 {
125   hostinfo_t hi, *newtable;
126   int newsize;
127   int idx, rc;
128
129   hi = xtrymalloc (sizeof *hi + strlen (name));
130   if (!hi)
131     return -1;
132   strcpy (hi->name, name);
133   hi->pool = NULL;
134   hi->pool_len = 0;
135   hi->pool_size = 0;
136   hi->poolidx = -1;
137   hi->lastused = (time_t)(-1);
138   hi->lastfail = (time_t)(-1);
139   hi->v4 = 0;
140   hi->v6 = 0;
141   hi->onion = 0;
142   hi->dead = 0;
143   hi->did_a_lookup = 0;
144   hi->did_srv_lookup = 0;
145   hi->iporname_valid = 0;
146   hi->died_at = 0;
147   hi->cname = NULL;
148   hi->iporname = NULL;
149   hi->port[KS_PROTOCOL_HKP] = 0;
150   hi->port[KS_PROTOCOL_HKPS] = 0;
151
152   /* Add it to the hosttable. */
153   for (idx=0; idx < hosttable_size; idx++)
154     if (!hosttable[idx])
155       {
156         hosttable[idx] = hi;
157         return idx;
158       }
159   /* Need to extend the hosttable.  */
160   newsize = hosttable_size + INITIAL_HOSTTABLE_SIZE;
161   newtable = xtryrealloc (hosttable, newsize * sizeof *hosttable);
162   if (!newtable)
163     {
164       xfree (hi);
165       return -1;
166     }
167   hosttable = newtable;
168   idx = hosttable_size;
169   hosttable_size = newsize;
170   rc = idx;
171   hosttable[idx++] = hi;
172   while (idx < hosttable_size)
173     hosttable[idx++] = NULL;
174
175   return rc;
176 }
177
178
179 /* Find the host NAME in our table.  Return the index into the
180    hosttable or -1 if not found.  */
181 static int
182 find_hostinfo (const char *name)
183 {
184   int idx;
185
186   for (idx=0; idx < hosttable_size; idx++)
187     if (hosttable[idx] && !ascii_strcasecmp (hosttable[idx]->name, name))
188       return idx;
189   return -1;
190 }
191
192
193 static int
194 sort_hostpool (const void *xa, const void *xb)
195 {
196   int a = *(int *)xa;
197   int b = *(int *)xb;
198
199   assert (a >= 0 && a < hosttable_size);
200   assert (b >= 0 && b < hosttable_size);
201   assert (hosttable[a]);
202   assert (hosttable[b]);
203
204   return ascii_strcasecmp (hosttable[a]->name, hosttable[b]->name);
205 }
206
207
208 /* Return true if the host with the hosttable index TBLIDX is in HI->pool.  */
209 static int
210 host_in_pool_p (hostinfo_t hi, int tblidx)
211 {
212   int i, pidx;
213
214   for (i = 0; i < hi->pool_len && (pidx = hi->pool[i]) != -1; i++)
215     if (pidx == tblidx && hosttable[pidx])
216       return 1;
217   return 0;
218 }
219
220
221 /* Select a random host.  Consult HI->pool which indices into the global
222    hosttable.  Returns index into HI->pool or -1 if no host could be
223    selected.  */
224 static int
225 select_random_host (hostinfo_t hi)
226 {
227   int *tbl;
228   size_t tblsize;
229   int pidx, idx;
230
231   /* We create a new table so that we randomly select only from
232      currently alive hosts.  */
233   for (idx = 0, tblsize = 0;
234        idx < hi->pool_len && (pidx = hi->pool[idx]) != -1;
235        idx++)
236     if (hosttable[pidx] && !hosttable[pidx]->dead)
237       tblsize++;
238   if (!tblsize)
239     return -1; /* No hosts.  */
240
241   tbl = xtrymalloc (tblsize * sizeof *tbl);
242   if (!tbl)
243     return -1;
244   for (idx = 0, tblsize = 0;
245        idx < hi->pool_len && (pidx = hi->pool[idx]) != -1;
246        idx++)
247     if (hosttable[pidx] && !hosttable[pidx]->dead)
248       tbl[tblsize++] = pidx;
249
250   if (tblsize == 1)  /* Save a get_uint_nonce.  */
251     pidx = tbl[0];
252   else
253     pidx = tbl[get_uint_nonce () % tblsize];
254
255   xfree (tbl);
256   return pidx;
257 }
258
259
260 /* Figure out if a set of DNS records looks like a pool.  */
261 static int
262 arecords_is_pool (dns_addrinfo_t aibuf)
263 {
264   dns_addrinfo_t ai;
265   int n_v6, n_v4;
266
267   n_v6 = n_v4 = 0;
268   for (ai = aibuf; ai; ai = ai->next)
269     {
270       if (ai->family == AF_INET6)
271         n_v6++;
272       else if (ai->family == AF_INET)
273         n_v4++;
274     }
275
276   return n_v6 > 1 || n_v4 > 1;
277 }
278
279
280 /* Print a warning iff Tor is not running but Tor has been requested.
281  * Also return true if it is not running.  */
282 static int
283 tor_not_running_p (ctrl_t ctrl)
284 {
285   assuan_fd_t sock;
286
287   if (!dirmngr_use_tor ())
288     return 0;
289
290   sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
291   if (sock != ASSUAN_INVALID_FD)
292     {
293       assuan_sock_close (sock);
294       return 0;
295     }
296
297   log_info ("(it seems Tor is not running)\n");
298   dirmngr_status (ctrl, "WARNING", "tor_not_running 0",
299                   "Tor is enabled but the local Tor daemon"
300                   " seems to be down", NULL);
301   return 1;
302 }
303
304
305 /* Add the host AI under the NAME into the HOSTTABLE.  If PORT is not
306    zero, it specifies which port to use to talk to the host for
307    PROTOCOL.  If NAME specifies a pool (as indicated by IS_POOL),
308    update the given reference table accordingly.  */
309 static void
310 add_host (ctrl_t ctrl, const char *name, int is_pool,
311           const dns_addrinfo_t ai,
312           enum ks_protocol protocol, unsigned short port)
313 {
314   gpg_error_t tmperr;
315   char *tmphost;
316   int idx, tmpidx;
317   hostinfo_t host;
318   int i;
319
320   idx = find_hostinfo (name);
321   host = hosttable[idx];
322
323   if (is_pool)
324     {
325       /* For a pool immediately convert the address to a string.  */
326       tmperr = resolve_dns_addr (ctrl, ai->addr, ai->addrlen,
327                                  (DNS_NUMERICHOST | DNS_WITHBRACKET), &tmphost);
328     }
329   else if (!is_ip_address (name))
330     {
331       /* This is a hostname.  Use the name as given without going
332        * through resolve_dns_addr.  */
333       tmphost = xtrystrdup (name);
334       if (!tmphost)
335         tmperr = gpg_error_from_syserror ();
336       else
337         tmperr = 0;
338     }
339   else
340     {
341       /* Do a PTR lookup on AI.  If a name was not found the function
342        * returns the numeric address (with brackets).  */
343       tmperr = resolve_dns_addr (ctrl, ai->addr, ai->addrlen,
344                                  DNS_WITHBRACKET, &tmphost);
345     }
346
347   if (tmperr)
348     {
349       log_info ("resolve_dns_addr failed while checking '%s': %s\n",
350                 name, gpg_strerror (tmperr));
351     }
352   else if (host->pool_len + 1 >= MAX_POOL_SIZE)
353     {
354       log_error ("resolve_dns_addr for '%s': '%s'"
355                  " [index table full - ignored]\n", name, tmphost);
356     }
357   else
358     {
359       if (!is_pool && is_ip_address (name))
360         /* Update the original entry.  */
361         tmpidx = idx;
362       else
363         tmpidx = find_hostinfo (tmphost);
364       log_info ("resolve_dns_addr for '%s': '%s'%s\n",
365                 name, tmphost,
366                 tmpidx == -1? "" : " [already known]");
367
368       if (tmpidx == -1) /* Create a new entry.  */
369         tmpidx = create_new_hostinfo (tmphost);
370
371       if (tmpidx == -1)
372         {
373           log_error ("map_host for '%s' problem: %s - '%s' [ignored]\n",
374                      name, strerror (errno), tmphost);
375         }
376       else  /* Set or update the entry. */
377         {
378           if (port)
379             hosttable[tmpidx]->port[protocol] = port;
380
381           if (ai->family == AF_INET6)
382             {
383               hosttable[tmpidx]->v6 = 1;
384             }
385           else if (ai->family == AF_INET)
386             {
387               hosttable[tmpidx]->v4 = 1;
388             }
389           else
390             BUG ();
391
392           /* If we updated the main entry, we're done.  */
393           if (idx == tmpidx)
394             goto leave;
395
396           /* If we updated an existing entry, we're done.  */
397           for (i = 0; i < host->pool_len; i++)
398             if (host->pool[i] == tmpidx)
399               goto leave;
400
401           /* Otherwise, we need to add it to the pool.  Check if there
402              is space.  */
403           if (host->pool_len + 1 > host->pool_size)
404             {
405               int *new_pool;
406               size_t new_size;
407
408               if (host->pool_size == 0)
409                 new_size = 4;
410               else
411                 new_size = host->pool_size * 2;
412
413               new_pool = xtryrealloc (host->pool,
414                                       new_size * sizeof *new_pool);
415
416               if (new_pool == NULL)
417                 goto leave;
418
419               host->pool = new_pool;
420               host->pool_size = new_size;
421             }
422
423           /* Finally, add it.  */
424           log_assert (host->pool_len < host->pool_size);
425           host->pool[host->pool_len++] = tmpidx;
426         }
427     }
428  leave:
429   xfree (tmphost);
430 }
431
432
433 /* Sort the pool of the given hostinfo HI.  */
434 static void
435 hostinfo_sort_pool (hostinfo_t hi)
436 {
437   qsort (hi->pool, hi->pool_len, sizeof *hi->pool, sort_hostpool);
438 }
439
440 /* Map the host name NAME to the actual to be used host name.  This
441  * allows us to manage round robin DNS names.  We use our own strategy
442  * to choose one of the hosts.  For example we skip those hosts which
443  * failed for some time and we stick to one host for a time
444  * independent of DNS retry times.  If FORCE_RESELECT is true a new
445  * host is always selected.  If SRVTAG is NULL no service record
446  * lookup will be done, if it is set that service name is used.  The
447  * selected host is stored as a malloced string at R_HOST; on error
448  * NULL is stored.  If we know the port used by the selected host from
449  * a service record, a string representation is written to R_PORTSTR,
450  * otherwise it is left untouched.  If R_HTTPFLAGS is not NULL it will
451  * receive flags which are to be passed to http_open.  If R_HTTPHOST
452  * is not NULL a malloced name of the host is stored there; this might
453  * be different from R_HOST in case it has been selected from a
454  * pool.  */
455 static gpg_error_t
456 map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
457           enum ks_protocol protocol, char **r_host, char *r_portstr,
458           unsigned int *r_httpflags, char **r_httphost)
459 {
460   gpg_error_t err = 0;
461   hostinfo_t hi;
462   int idx;
463   dns_addrinfo_t aibuf, ai;
464   int is_pool;
465   int new_hosts = 0;
466   char *cname;
467
468   *r_host = NULL;
469   if (r_httpflags)
470     *r_httpflags = 0;
471   if (r_httphost)
472     *r_httphost = NULL;
473
474   /* No hostname means localhost.  */
475   if (!name || !*name)
476     {
477       *r_host = xtrystrdup ("localhost");
478       return *r_host? 0 : gpg_error_from_syserror ();
479     }
480
481   /* See whether the host is in our table.  */
482   idx = find_hostinfo (name);
483   if (idx == -1)
484     {
485       idx = create_new_hostinfo (name);
486       if (idx == -1)
487         return gpg_error_from_syserror ();
488       hi = hosttable[idx];
489       hi->onion = is_onion_address (name);
490     }
491   else
492     hi = hosttable[idx];
493
494   is_pool = hi->pool != NULL;
495
496   if (srvtag && !is_ip_address (name)
497       && ! hi->onion
498       && ! (hi->did_srv_lookup & 1 << protocol))
499     {
500       struct srventry *srvs;
501       unsigned int srvscount;
502
503       /* Check for SRV records.  */
504       err = get_dns_srv (ctrl, name, srvtag, NULL, &srvs, &srvscount);
505       if (err)
506         {
507           if (gpg_err_code (err) == GPG_ERR_ECONNREFUSED)
508             tor_not_running_p (ctrl);
509           return err;
510         }
511
512       if (srvscount > 0)
513         {
514           int i;
515           if (! is_pool)
516             is_pool = srvscount > 1;
517
518           for (i = 0; i < srvscount; i++)
519             {
520               err = resolve_dns_name (ctrl, srvs[i].target, 0,
521                                       AF_UNSPEC, SOCK_STREAM,
522                                       &ai, &cname);
523               if (err)
524                 continue;
525               dirmngr_tick (ctrl);
526               add_host (ctrl, name, is_pool, ai, protocol, srvs[i].port);
527               new_hosts = 1;
528             }
529
530           xfree (srvs);
531         }
532
533       hi->did_srv_lookup |= 1 << protocol;
534     }
535
536   if (! hi->did_a_lookup
537       && ! hi->onion)
538     {
539       /* Find all A records for this entry and put them into the pool
540          list - if any.  */
541       err = resolve_dns_name (ctrl, name, 0, 0, SOCK_STREAM, &aibuf, &cname);
542       if (err)
543         {
544           log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
545           err = 0;
546         }
547       else
548         {
549           /* First figure out whether this is a pool.  For a pool we
550              use a different strategy than for a plain server: We use
551              the canonical name of the pool as the virtual host along
552              with the IP addresses.  If it is not a pool, we use the
553              specified name. */
554           if (! is_pool)
555             is_pool = arecords_is_pool (aibuf);
556           if (is_pool && cname)
557             {
558               hi->cname = cname;
559               cname = NULL;
560             }
561
562           for (ai = aibuf; ai; ai = ai->next)
563             {
564               if (ai->family != AF_INET && ai->family != AF_INET6)
565                 continue;
566               if (opt.disable_ipv4 && ai->family == AF_INET)
567                 continue;
568               if (opt.disable_ipv6 && ai->family == AF_INET6)
569                 continue;
570               dirmngr_tick (ctrl);
571
572               add_host (ctrl, name, is_pool, ai, 0, 0);
573               new_hosts = 1;
574             }
575
576           hi->did_a_lookup = 1;
577         }
578       xfree (cname);
579       free_dns_addrinfo (aibuf);
580     }
581   if (new_hosts)
582     hostinfo_sort_pool (hi);
583
584   if (hi->pool)
585     {
586       /* Deal with the pool name before selecting a host. */
587       if (r_httphost)
588         {
589           *r_httphost = xtrystrdup (hi->name);
590           if (!*r_httphost)
591             return gpg_error_from_syserror ();
592         }
593
594       /* If the currently selected host is now marked dead, force a
595          re-selection .  */
596       if (force_reselect)
597         hi->poolidx = -1;
598       else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
599                && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead)
600         hi->poolidx = -1;
601
602       /* Select a host if needed.  */
603       if (hi->poolidx == -1)
604         {
605           hi->poolidx = select_random_host (hi);
606           if (hi->poolidx == -1)
607             {
608               log_error ("no alive host found in pool '%s'\n", name);
609               if (r_httphost)
610                 {
611                   xfree (*r_httphost);
612                   *r_httphost = NULL;
613                 }
614               return gpg_error (GPG_ERR_NO_KEYSERVER);
615             }
616         }
617
618       assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
619       hi = hosttable[hi->poolidx];
620       assert (hi);
621     }
622   else if (r_httphost && is_ip_address (hi->name))
623     {
624       /* This is a numerical IP address and not a pool.  We want to
625        * find the canonical name so that it can be used in the HTTP
626        * Host header.  Fixme: We should store that name in the
627        * hosttable. */
628       char *host;
629
630       err = resolve_dns_name (ctrl, hi->name, 0, 0, SOCK_STREAM, &aibuf, NULL);
631       if (!err)
632         {
633           for (ai = aibuf; ai; ai = ai->next)
634             {
635               if ((!opt.disable_ipv6 && ai->family == AF_INET6)
636                   || (!opt.disable_ipv4 && ai->family == AF_INET))
637                 {
638                   err = resolve_dns_addr (ctrl,
639                                           ai->addr, ai->addrlen, 0, &host);
640                   if (!err)
641                     {
642                       /* Okay, we return the first found name.  */
643                       *r_httphost = host;
644                       break;
645                     }
646                 }
647             }
648         }
649       free_dns_addrinfo (aibuf);
650     }
651
652   if (hi->dead)
653     {
654       log_error ("host '%s' marked as dead\n", hi->name);
655       if (r_httphost)
656         {
657           xfree (*r_httphost);
658           *r_httphost = NULL;
659         }
660       return gpg_error (GPG_ERR_NO_KEYSERVER);
661     }
662
663   if (r_httpflags)
664     {
665       /* If the hosttable does not indicate that a certain host
666          supports IPv<N>, we explicit set the corresponding http
667          flags.  The reason for this is that a host might be listed in
668          a pool as not v6 only but actually support v6 when later
669          the name is resolved by our http layer.  */
670       if (!hi->v4)
671         *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
672       if (!hi->v6)
673         *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
674
675       /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
676          addresses because the http module detects this itself.  This
677          also allows us to use an onion address without Tor mode being
678          enabled.  */
679     }
680
681   *r_host = xtrystrdup (hi->name);
682   if (!*r_host)
683     {
684       err = gpg_error_from_syserror ();
685       if (r_httphost)
686         {
687           xfree (*r_httphost);
688           *r_httphost = NULL;
689         }
690       return err;
691     }
692   if (hi->port[protocol])
693     snprintf (r_portstr, 6 /* five digits and the sentinel */,
694               "%hu", hi->port[protocol]);
695   return 0;
696 }
697
698
699 /* Mark the host NAME as dead.  NAME may be given as an URL.  Returns
700    true if a host was really marked as dead or was already marked dead
701    (e.g. by a concurrent session).  */
702 static int
703 mark_host_dead (const char *name)
704 {
705   const char *host;
706   char *host_buffer = NULL;
707   parsed_uri_t parsed_uri = NULL;
708   int done = 0;
709
710   if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
711     {
712       if (parsed_uri->v6lit)
713         {
714           host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
715           if (!host_buffer)
716             log_error ("out of core in mark_host_dead");
717           host = host_buffer;
718         }
719       else
720         host = parsed_uri->host;
721     }
722   else
723     host = name;
724
725   if (host && *host && strcmp (host, "localhost"))
726     {
727       hostinfo_t hi;
728       int idx;
729
730       idx = find_hostinfo (host);
731       if (idx != -1)
732         {
733           hi = hosttable[idx];
734           log_info ("marking host '%s' as dead%s\n",
735                     hi->name, hi->dead? " (again)":"");
736           hi->dead = 1;
737           hi->died_at = gnupg_get_time ();
738           if (!hi->died_at)
739             hi->died_at = 1;
740           done = 1;
741         }
742     }
743
744   http_release_parsed_uri (parsed_uri);
745   xfree (host_buffer);
746   return done;
747 }
748
749
750 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
751    alive.  */
752 gpg_error_t
753 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
754 {
755   gpg_error_t err = 0;
756   hostinfo_t hi, hi2;
757   int idx, idx2, idx3, n;
758
759   if (!name || !*name || !strcmp (name, "localhost"))
760     return 0;
761
762   if (npth_mutex_lock (&hosttable_lock))
763     log_fatal ("failed to acquire mutex\n");
764
765   idx = find_hostinfo (name);
766   if (idx == -1)
767     {
768       err = gpg_error (GPG_ERR_NOT_FOUND);
769       goto leave;
770     }
771
772   hi = hosttable[idx];
773   if (alive && hi->dead)
774     {
775       hi->dead = 0;
776       err = ks_printf_help (ctrl, "marking '%s' as alive", name);
777     }
778   else if (!alive && !hi->dead)
779     {
780       hi->dead = 1;
781       hi->died_at = 0; /* Manually set dead.  */
782       err = ks_printf_help (ctrl, "marking '%s' as dead", name);
783     }
784
785   /* If the host is a pool mark all member hosts. */
786   if (!err && hi->pool)
787     {
788       for (idx2 = 0;
789            !err && idx2 < hi->pool_len && (n = hi->pool[idx2]) != -1;
790            idx2++)
791         {
792           assert (n >= 0 && n < hosttable_size);
793
794           if (!alive)
795             {
796               /* Do not mark a host from a pool dead if it is also a
797                  member in another pool.  */
798               for (idx3=0; idx3 < hosttable_size; idx3++)
799                 {
800                   if (hosttable[idx3]
801                       && hosttable[idx3]->pool
802                       && idx3 != idx
803                       && host_in_pool_p (hosttable[idx3], n))
804                     break;
805                 }
806               if (idx3 < hosttable_size)
807                 continue;  /* Host is also a member of another pool.  */
808             }
809
810           hi2 = hosttable[n];
811           if (!hi2)
812             ;
813           else if (alive && hi2->dead)
814             {
815               hi2->dead = 0;
816               err = ks_printf_help (ctrl, "marking '%s' as alive",
817                                     hi2->name);
818             }
819           else if (!alive && !hi2->dead)
820             {
821               hi2->dead = 1;
822               hi2->died_at = 0; /* Manually set dead. */
823               err = ks_printf_help (ctrl, "marking '%s' as dead",
824                                     hi2->name);
825             }
826         }
827     }
828
829  leave:
830   if (npth_mutex_unlock (&hosttable_lock))
831     log_fatal ("failed to release mutex\n");
832
833   return err;
834 }
835
836
837 /* Debug function to print the entire hosttable.  */
838 gpg_error_t
839 ks_hkp_print_hosttable (ctrl_t ctrl)
840 {
841   gpg_error_t err;
842   int idx, idx2;
843   hostinfo_t hi;
844   membuf_t mb;
845   time_t curtime;
846   char *p, *died;
847   const char *diedstr;
848
849   err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
850   if (err)
851     return err;
852
853   if (npth_mutex_lock (&hosttable_lock))
854     log_fatal ("failed to acquire mutex\n");
855
856   curtime = gnupg_get_time ();
857   for (idx=0; idx < hosttable_size; idx++)
858     if ((hi=hosttable[idx]))
859       {
860         if (hi->dead && hi->died_at)
861           {
862             died = elapsed_time_string (hi->died_at, curtime);
863             diedstr = died? died : "error";
864           }
865         else
866           diedstr = died = NULL;
867
868         if (!hi->iporname_valid)
869           {
870             char *canon = NULL;
871
872             xfree (hi->iporname);
873             hi->iporname = NULL;
874
875             /* Do a lookup just for the display purpose.  */
876             if (hi->onion || hi->pool)
877               ;
878             else if (is_ip_address (hi->name))
879               {
880                 dns_addrinfo_t aibuf, ai;
881
882                 /* Turn the numerical IP address string into an AI and
883                  * then do a DNS PTR lookup.  */
884                 if (!resolve_dns_name (ctrl, hi->name, 0, 0,
885                                        SOCK_STREAM,
886                                        &aibuf, &canon))
887                   {
888                     if (canon && is_ip_address (canon))
889                       {
890                         xfree (canon);
891                         canon = NULL;
892                       }
893                     for (ai = aibuf; !canon && ai; ai = ai->next)
894                       {
895                         resolve_dns_addr (ctrl, ai->addr, ai->addrlen,
896                                           DNS_WITHBRACKET, &canon);
897                         if (canon && is_ip_address (canon))
898                           {
899                             /* We already have the numeric IP - no need to
900                              * display it a second time.  */
901                             xfree (canon);
902                             canon = NULL;
903                           }
904                       }
905                   }
906                 free_dns_addrinfo (aibuf);
907               }
908             else
909               {
910                 dns_addrinfo_t aibuf, ai;
911
912                 /* Get the IP address as a string from a name.  Note
913                  * that resolve_dns_addr allocates CANON on success
914                  * and thus terminates the loop. */
915                 if (!resolve_dns_name (ctrl, hi->name, 0,
916                                        hi->v6? AF_INET6 : AF_INET,
917                                        SOCK_STREAM,
918                                        &aibuf, NULL))
919                   {
920                     for (ai = aibuf; !canon && ai; ai = ai->next)
921                       {
922                         resolve_dns_addr (ctrl, ai->addr, ai->addrlen,
923                                           DNS_NUMERICHOST|DNS_WITHBRACKET,
924                                           &canon);
925                       }
926                   }
927                 free_dns_addrinfo (aibuf);
928               }
929
930             hi->iporname = canon;
931             hi->iporname_valid = 1;
932           }
933
934         err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s\n",
935                               idx,
936                               hi->onion? "O" : hi->v6? "6":" ",
937                               hi->v4? "4":" ",
938                               hi->dead? "d":" ",
939                               hi->name,
940                               hi->iporname? " (":"",
941                               hi->iporname? hi->iporname : "",
942                               hi->iporname? ")":"",
943                               diedstr? "  (":"",
944                               diedstr? diedstr:"",
945                               diedstr? ")":""   );
946         xfree (died);
947         if (err)
948           goto leave;
949
950         if (hi->cname)
951           err = ks_printf_help (ctrl, "  .       %s", hi->cname);
952         if (err)
953           goto leave;
954
955         if (hi->pool)
956           {
957             init_membuf (&mb, 256);
958             put_membuf_printf (&mb, "  .   -->");
959             for (idx2 = 0; idx2 < hi->pool_len && hi->pool[idx2] != -1; idx2++)
960               {
961                 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
962                 if (hi->poolidx == hi->pool[idx2])
963                   put_membuf_printf (&mb, "*");
964               }
965             put_membuf( &mb, "", 1);
966             p = get_membuf (&mb, NULL);
967             if (!p)
968               {
969                 err = gpg_error_from_syserror ();
970                 goto leave;
971               }
972             err = ks_print_help (ctrl, p);
973             xfree (p);
974             if (err)
975               goto leave;
976           }
977       }
978
979  leave:
980   if (npth_mutex_unlock (&hosttable_lock))
981     log_fatal ("failed to release mutex\n");
982   return err;
983 }
984
985
986
987 /* Print a help output for the schemata supported by this module. */
988 gpg_error_t
989 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
990 {
991   const char data[] =
992     "Handler for HKP URLs:\n"
993     "  hkp://\n"
994 #if  HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
995     "  hkps://\n"
996 #endif
997     "Supported methods: search, get, put\n";
998   gpg_error_t err;
999
1000 #if  HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
1001   const char data2[] = "  hkp\n  hkps";
1002 #else
1003   const char data2[] = "  hkp";
1004 #endif
1005
1006   if (!uri)
1007     err = ks_print_help (ctrl, data2);
1008   else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
1009                             || !strcmp (uri->scheme, "hkps")))
1010     err = ks_print_help (ctrl, data);
1011   else
1012     err = 0;
1013
1014   return err;
1015 }
1016
1017
1018 /* Build the remote part of the URL from SCHEME, HOST and an optional
1019  * PORT.  If NO_SRV is set no SRV record lookup will be done.  Returns
1020  * an allocated string at R_HOSTPORT or NULL on failure.  If
1021  * R_HTTPHOST is not NULL it receives a malloced string with the
1022  * hostname; this may be different from HOST if HOST is selected from
1023  * a pool.  */
1024 static gpg_error_t
1025 make_host_part (ctrl_t ctrl,
1026                 const char *scheme, const char *host, unsigned short port,
1027                 int force_reselect, int no_srv,
1028                 char **r_hostport, unsigned int *r_httpflags, char **r_httphost)
1029 {
1030   gpg_error_t err;
1031   const char *srvtag;
1032   char portstr[10];
1033   char *hostname;
1034   enum ks_protocol protocol;
1035
1036   *r_hostport = NULL;
1037
1038   if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
1039     {
1040       scheme = "https";
1041       srvtag = no_srv? NULL : "pgpkey-https";
1042       protocol = KS_PROTOCOL_HKPS;
1043     }
1044   else /* HKP or HTTP.  */
1045     {
1046       scheme = "http";
1047       srvtag = no_srv? NULL : "pgpkey-http";
1048       protocol = KS_PROTOCOL_HKP;
1049     }
1050
1051   if (npth_mutex_lock (&hosttable_lock))
1052     log_fatal ("failed to acquire mutex\n");
1053
1054   portstr[0] = 0;
1055   err = map_host (ctrl, host, srvtag, force_reselect, protocol,
1056                   &hostname, portstr, r_httpflags, r_httphost);
1057
1058   if (npth_mutex_unlock (&hosttable_lock))
1059     log_fatal ("failed to release mutex\n");
1060
1061   if (err)
1062     return err;
1063
1064   /* If map_host did not return a port (from a SRV record) but a port
1065    * has been specified (implicitly or explicitly) then use that port.
1066    * In the case that a port was not specified (which is probably a
1067    * bug in https.c) we will set up defaults.  */
1068   if (*portstr)
1069     ;
1070   else if (!*portstr && port)
1071     snprintf (portstr, sizeof portstr, "%hu", port);
1072   else if (!strcmp (scheme,"https"))
1073     strcpy (portstr, "443");
1074   else
1075     strcpy (portstr, "11371");
1076
1077   if (*hostname != '[' && is_ip_address (hostname) == 6)
1078     *r_hostport = strconcat (scheme, "://[", hostname, "]:", portstr, NULL);
1079   else
1080     *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
1081   xfree (hostname);
1082   if (!*r_hostport)
1083     {
1084       if (r_httphost)
1085         {
1086           xfree (*r_httphost);
1087           *r_httphost = NULL;
1088         }
1089       return gpg_error_from_syserror ();
1090     }
1091   return 0;
1092 }
1093
1094
1095 /* Resolve all known keyserver names and update the hosttable.  This
1096    is mainly useful for debugging because the resolving is anyway done
1097    on demand.  */
1098 gpg_error_t
1099 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
1100 {
1101   gpg_error_t err;
1102   char *hostport = NULL;
1103
1104   /* NB: With an explicitly given port we do not want to consult a
1105    * service record because that might be in conflict with the port
1106    * from such a service record.  */
1107   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1108                         1, uri->explicit_port,
1109                         &hostport, NULL, NULL);
1110   if (err)
1111     {
1112       err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
1113                             uri->scheme, uri->host, uri->port,
1114                             gpg_strerror (err));
1115     }
1116   else
1117     {
1118       err = ks_printf_help (ctrl, "%s", hostport);
1119       xfree (hostport);
1120     }
1121   return err;
1122 }
1123
1124
1125 /* Housekeeping function called from the housekeeping thread.  It is
1126    used to mark dead hosts alive so that they may be tried again after
1127    some time.  */
1128 void
1129 ks_hkp_housekeeping (time_t curtime)
1130 {
1131   int idx;
1132   hostinfo_t hi;
1133
1134   if (npth_mutex_lock (&hosttable_lock))
1135     log_fatal ("failed to acquire mutex\n");
1136
1137   for (idx=0; idx < hosttable_size; idx++)
1138     {
1139       hi = hosttable[idx];
1140       if (!hi)
1141         continue;
1142       if (!hi->dead)
1143         continue;
1144       if (!hi->died_at)
1145         continue; /* Do not resurrect manually shot hosts.  */
1146       if (hi->died_at + RESURRECT_INTERVAL <= curtime
1147           || hi->died_at > curtime)
1148         {
1149           hi->dead = 0;
1150           log_info ("resurrected host '%s'", hi->name);
1151         }
1152     }
1153
1154   if (npth_mutex_unlock (&hosttable_lock))
1155     log_fatal ("failed to release mutex\n");
1156 }
1157
1158
1159 /* Reload (SIGHUP) action for this module.  We mark all host alive
1160  * even those which have been manually shot.  */
1161 void
1162 ks_hkp_reload (void)
1163 {
1164   int idx, count;
1165   hostinfo_t hi;
1166
1167   if (npth_mutex_lock (&hosttable_lock))
1168     log_fatal ("failed to acquire mutex\n");
1169
1170   for (idx=count=0; idx < hosttable_size; idx++)
1171     {
1172       hi = hosttable[idx];
1173       if (!hi)
1174         continue;
1175       hi->iporname_valid = 0;
1176       if (!hi->dead)
1177         continue;
1178       hi->dead = 0;
1179       count++;
1180     }
1181   if (count)
1182     log_info ("number of resurrected hosts: %d", count);
1183
1184   if (npth_mutex_unlock (&hosttable_lock))
1185     log_fatal ("failed to release mutex\n");
1186 }
1187
1188
1189 /* Send an HTTP request.  On success returns an estream object at
1190    R_FP.  HOSTPORTSTR is only used for diagnostics.  If HTTPHOST is
1191    not NULL it will be used as HTTP "Host" header.  If POST_CB is not
1192    NULL a post request is used and that callback is called to allow
1193    writing the post data.  If R_HTTP_STATUS is not NULL, the http
1194    status code will be stored there.  */
1195 static gpg_error_t
1196 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
1197               const char *httphost, unsigned int httpflags,
1198               gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
1199               estream_t *r_fp, unsigned int *r_http_status)
1200 {
1201   gpg_error_t err;
1202   http_session_t session = NULL;
1203   http_t http = NULL;
1204   http_redir_info_t redirinfo = { MAX_REDIRECTS };
1205   estream_t fp = NULL;
1206   char *request_buffer = NULL;
1207   parsed_uri_t uri = NULL;
1208
1209   *r_fp = NULL;
1210
1211   err = http_parse_uri (&uri, request, 0);
1212   if (err)
1213     goto leave;
1214   redirinfo.orig_url   = request;
1215   redirinfo.orig_onion = uri->onion;
1216   redirinfo.allow_downgrade = 1;
1217   /* FIXME: I am not sure whey we allow a downgrade for hkp requests.
1218    * Needs at least an explanation here..  */
1219
1220   err = http_session_new (&session, httphost,
1221                           ((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0)
1222                            | HTTP_FLAG_TRUST_DEF),
1223                           gnupg_http_tls_verify_cb, ctrl);
1224   if (err)
1225     goto leave;
1226   http_session_set_log_cb (session, cert_log_cb);
1227   http_session_set_timeout (session, ctrl->timeout);
1228
1229  once_more:
1230   err = http_open (ctrl, &http,
1231                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1232                    request,
1233                    httphost,
1234                    /* fixme: AUTH */ NULL,
1235                    (httpflags
1236                     |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1237                     |(dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0)
1238                     |(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)
1239                     |(opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6 : 0)),
1240                    ctrl->http_proxy,
1241                    session,
1242                    NULL,
1243                    /*FIXME curl->srvtag*/NULL);
1244   if (!err)
1245     {
1246       fp = http_get_write_ptr (http);
1247       /* Avoid caches to get the most recent copy of the key.  We set
1248          both the Pragma and Cache-Control versions of the header, so
1249          we're good with both HTTP 1.0 and 1.1.  */
1250       es_fputs ("Pragma: no-cache\r\n"
1251                 "Cache-Control: no-cache\r\n", fp);
1252       if (post_cb)
1253         err = post_cb (post_cb_value, http);
1254       if (!err)
1255         {
1256           http_start_data (http);
1257           if (es_ferror (fp))
1258             err = gpg_error_from_syserror ();
1259         }
1260     }
1261   if (err)
1262     {
1263       /* Fixme: After a redirection we show the old host name.  */
1264       log_error (_("error connecting to '%s': %s\n"),
1265                  hostportstr, gpg_strerror (err));
1266       goto leave;
1267     }
1268
1269   /* Wait for the response.  */
1270   dirmngr_tick (ctrl);
1271   err = http_wait_response (http);
1272   if (err)
1273     {
1274       log_error (_("error reading HTTP response for '%s': %s\n"),
1275                  hostportstr, gpg_strerror (err));
1276       goto leave;
1277     }
1278
1279   if (http_get_tls_info (http, NULL))
1280     {
1281       /* Update the httpflags so that a redirect won't fallback to an
1282          unencrypted connection.  */
1283       httpflags |= HTTP_FLAG_FORCE_TLS;
1284     }
1285
1286   if (r_http_status)
1287     *r_http_status = http_get_status_code (http);
1288
1289   switch (http_get_status_code (http))
1290     {
1291     case 200:
1292       err = 0;
1293       break; /* Success.  */
1294
1295     case 301:
1296     case 302:
1297     case 307:
1298       {
1299         xfree (request_buffer);
1300         err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
1301                                      http_get_header (http, "Location"),
1302                                      &request_buffer);
1303         if (err)
1304           goto leave;
1305
1306         request = request_buffer;
1307         http_close (http, 0);
1308         http = NULL;
1309       }
1310       goto once_more;
1311
1312     case 501:
1313       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1314       goto leave;
1315
1316     default:
1317       log_error (_("error accessing '%s': http status %u\n"),
1318                  request, http_get_status_code (http));
1319       err = gpg_error (GPG_ERR_NO_DATA);
1320       goto leave;
1321     }
1322
1323   /* FIXME: We should register a permanent redirection and whether a
1324      host has ever used TLS so that future calls will always use
1325      TLS. */
1326
1327   fp = http_get_read_ptr (http);
1328   if (!fp)
1329     {
1330       err = gpg_error (GPG_ERR_BUG);
1331       goto leave;
1332     }
1333
1334   /* Return the read stream and close the HTTP context.  */
1335   *r_fp = fp;
1336   http_close (http, 1);
1337   http = NULL;
1338
1339  leave:
1340   http_close (http, 0);
1341   http_session_release (session);
1342   xfree (request_buffer);
1343   http_release_parsed_uri (uri);
1344   return err;
1345 }
1346
1347
1348 /* Helper to evaluate the error code ERR from a send_request() call
1349    with REQUEST.  The function returns true if the caller shall try
1350    again.  TRIES_LEFT points to a variable to track the number of
1351    retries; this function decrements it and won't return true if it is
1352    down to zero. */
1353 static int
1354 handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
1355                            unsigned int http_status, unsigned int *tries_left)
1356 {
1357   int retry = 0;
1358
1359   /* Fixme: Should we disable all hosts of a protocol family if a
1360    * request for an address of that family returned ENETDOWN?  */
1361
1362   switch (gpg_err_code (err))
1363     {
1364     case GPG_ERR_ECONNREFUSED:
1365       if (tor_not_running_p (ctrl))
1366         break; /* A retry does not make sense.  */
1367       /* Okay: Tor is up or --use-tor is not used.  */
1368       /*FALLTHRU*/
1369     case GPG_ERR_ENETUNREACH:
1370     case GPG_ERR_ENETDOWN:
1371     case GPG_ERR_UNKNOWN_HOST:
1372     case GPG_ERR_NETWORK:
1373     case GPG_ERR_EIO:  /* Sometimes used by estream cookie functions.  */
1374     case GPG_ERR_EADDRNOTAVAIL:  /* e.g. when IPv6 is disabled */
1375     case GPG_ERR_EAFNOSUPPORT:  /* e.g. when IPv6 is not compiled in */
1376       if (mark_host_dead (request) && *tries_left)
1377         retry = 1;
1378       break;
1379
1380     case GPG_ERR_ETIMEDOUT:
1381       if (*tries_left)
1382         {
1383           log_info ("selecting a different host due to a timeout\n");
1384           retry = 1;
1385         }
1386       break;
1387
1388     case GPG_ERR_EACCES:
1389       if (dirmngr_use_tor ())
1390         {
1391           log_info ("(Tor configuration problem)\n");
1392           dirmngr_status (ctrl, "WARNING", "tor_config_problem 0",
1393                           "Please check that the \"SocksPort\" flag "
1394                           "\"IPv6Traffic\" is set in torrc", NULL);
1395         }
1396       break;
1397
1398     case GPG_ERR_NO_DATA:
1399       {
1400         switch (http_status)
1401           {
1402           case 502: /* Bad Gateway  */
1403             log_info ("marking host dead due to a %u (%s)\n",
1404                       http_status, http_status2string (http_status));
1405             if (mark_host_dead (request) && *tries_left)
1406               retry = 1;
1407             break;
1408
1409           case 503: /* Service Unavailable */
1410           case 504: /* Gateway Timeout    */
1411             log_info ("selecting a different host due to a %u (%s)",
1412                       http_status, http_status2string (http_status));
1413             retry = 1;
1414             break;
1415           }
1416       }
1417       break;
1418
1419     default:
1420       break;
1421     }
1422
1423   if (*tries_left)
1424     --*tries_left;
1425
1426   return retry;
1427 }
1428
1429 \f
1430 /* Search the keyserver identified by URI for keys matching PATTERN.
1431    On success R_FP has an open stream to read the data.  If
1432    R_HTTP_STATUS is not NULL, the http status code will be stored
1433    there.  */
1434 gpg_error_t
1435 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1436                estream_t *r_fp, unsigned int *r_http_status)
1437 {
1438   gpg_error_t err;
1439   KEYDB_SEARCH_DESC desc;
1440   char fprbuf[2+40+1];
1441   char *hostport = NULL;
1442   char *request = NULL;
1443   estream_t fp = NULL;
1444   int reselect;
1445   unsigned int httpflags;
1446   char *httphost = NULL;
1447   unsigned int http_status;
1448   unsigned int tries = SEND_REQUEST_RETRIES;
1449
1450   *r_fp = NULL;
1451
1452   /* Remove search type indicator and adjust PATTERN accordingly.
1453      Note that HKP keyservers like the 0x to be present when searching
1454      by keyid.  We need to re-format the fingerprint and keyids so to
1455      remove the gpg specific force-use-of-this-key flag ("!").  */
1456   err = classify_user_id (pattern, &desc, 1);
1457   if (err)
1458     return err;
1459   switch (desc.mode)
1460     {
1461     case KEYDB_SEARCH_MODE_EXACT:
1462     case KEYDB_SEARCH_MODE_SUBSTR:
1463     case KEYDB_SEARCH_MODE_MAIL:
1464     case KEYDB_SEARCH_MODE_MAILSUB:
1465       pattern = desc.u.name;
1466       break;
1467     case KEYDB_SEARCH_MODE_SHORT_KID:
1468       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1469       pattern = fprbuf;
1470       break;
1471     case KEYDB_SEARCH_MODE_LONG_KID:
1472       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1473                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1474       pattern = fprbuf;
1475       break;
1476     case KEYDB_SEARCH_MODE_FPR16:
1477       fprbuf[0] = '0';
1478       fprbuf[1] = 'x';
1479       bin2hex (desc.u.fpr, 16, fprbuf+2);
1480       pattern = fprbuf;
1481       break;
1482     case KEYDB_SEARCH_MODE_FPR20:
1483     case KEYDB_SEARCH_MODE_FPR:
1484       fprbuf[0] = '0';
1485       fprbuf[1] = 'x';
1486       bin2hex (desc.u.fpr, 20, fprbuf+2);
1487       pattern = fprbuf;
1488       break;
1489     default:
1490       return gpg_error (GPG_ERR_INV_USER_ID);
1491     }
1492
1493   /* Build the request string.  */
1494   reselect = 0;
1495  again:
1496   {
1497     char *searchkey;
1498
1499     xfree (hostport); hostport = NULL;
1500     xfree (httphost); httphost = NULL;
1501     err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1502                           reselect, uri->explicit_port,
1503                           &hostport, &httpflags, &httphost);
1504     if (err)
1505       goto leave;
1506
1507     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1508     if (!searchkey)
1509       {
1510         err = gpg_error_from_syserror ();
1511         goto leave;
1512       }
1513
1514     xfree (request);
1515     request = strconcat (hostport,
1516                          "/pks/lookup?op=index&options=mr&search=",
1517                          searchkey,
1518                          NULL);
1519     xfree (searchkey);
1520     if (!request)
1521       {
1522         err = gpg_error_from_syserror ();
1523         goto leave;
1524       }
1525   }
1526
1527   /* Send the request.  */
1528   err = send_request (ctrl, request, hostport, httphost, httpflags,
1529                       NULL, NULL, &fp, &http_status);
1530   if (handle_send_request_error (ctrl, err, request, http_status, &tries))
1531     {
1532       reselect = 1;
1533       goto again;
1534     }
1535   if (r_http_status)
1536     *r_http_status = http_status;
1537   if (err)
1538     {
1539       if (gpg_err_code (err) == GPG_ERR_NO_DATA)
1540         dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1541       goto leave;
1542     }
1543
1544   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1545   if (err)
1546     goto leave;
1547
1548   /* Peek at the response.  */
1549   {
1550     int c = es_getc (fp);
1551     if (c == -1)
1552       {
1553         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1554         log_error ("error reading response: %s\n", gpg_strerror (err));
1555         goto leave;
1556       }
1557     if (c == '<')
1558       {
1559         /* The document begins with a '<': Assume a HTML response,
1560            which we don't support.  */
1561         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1562         goto leave;
1563       }
1564     es_ungetc (c, fp);
1565   }
1566
1567   /* Return the read stream.  */
1568   *r_fp = fp;
1569   fp = NULL;
1570
1571  leave:
1572   es_fclose (fp);
1573   xfree (request);
1574   xfree (hostport);
1575   xfree (httphost);
1576   return err;
1577 }
1578
1579
1580 /* Get the key described key the KEYSPEC string from the keyserver
1581    identified by URI.  On success R_FP has an open stream to read the
1582    data.  The data will be provided in a format GnuPG can import
1583    (either a binary OpenPGP message or an armored one).  */
1584 gpg_error_t
1585 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1586 {
1587   gpg_error_t err;
1588   KEYDB_SEARCH_DESC desc;
1589   char kidbuf[2+40+1];
1590   const char *exactname = NULL;
1591   char *searchkey = NULL;
1592   char *hostport = NULL;
1593   char *request = NULL;
1594   estream_t fp = NULL;
1595   int reselect;
1596   char *httphost = NULL;
1597   unsigned int httpflags;
1598   unsigned int http_status;
1599   unsigned int tries = SEND_REQUEST_RETRIES;
1600
1601   *r_fp = NULL;
1602
1603   /* Remove search type indicator and adjust PATTERN accordingly.
1604      Note that HKP keyservers like the 0x to be present when searching
1605      by keyid.  We need to re-format the fingerprint and keyids so to
1606      remove the gpg specific force-use-of-this-key flag ("!").  */
1607   err = classify_user_id (keyspec, &desc, 1);
1608   if (err)
1609     return err;
1610   switch (desc.mode)
1611     {
1612     case KEYDB_SEARCH_MODE_SHORT_KID:
1613       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1614       break;
1615     case KEYDB_SEARCH_MODE_LONG_KID:
1616       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1617                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1618       break;
1619     case KEYDB_SEARCH_MODE_FPR20:
1620     case KEYDB_SEARCH_MODE_FPR:
1621       /* This is a v4 fingerprint. */
1622       kidbuf[0] = '0';
1623       kidbuf[1] = 'x';
1624       bin2hex (desc.u.fpr, 20, kidbuf+2);
1625       break;
1626
1627     case KEYDB_SEARCH_MODE_EXACT:
1628       exactname = desc.u.name;
1629       break;
1630
1631     case KEYDB_SEARCH_MODE_FPR16:
1632       log_error ("HKP keyservers do not support v3 fingerprints\n");
1633       /* fall through */
1634     default:
1635       return gpg_error (GPG_ERR_INV_USER_ID);
1636     }
1637
1638   searchkey = http_escape_string (exactname? exactname : kidbuf,
1639                                   EXTRA_ESCAPE_CHARS);
1640   if (!searchkey)
1641     {
1642       err = gpg_error_from_syserror ();
1643       goto leave;
1644     }
1645
1646   reselect = 0;
1647  again:
1648   /* Build the request string.  */
1649   xfree (hostport); hostport = NULL;
1650   xfree (httphost); httphost = NULL;
1651   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1652                         reselect, uri->explicit_port,
1653                         &hostport, &httpflags, &httphost);
1654   if (err)
1655     goto leave;
1656
1657   xfree (request);
1658   request = strconcat (hostport,
1659                        "/pks/lookup?op=get&options=mr&search=",
1660                        searchkey,
1661                        exactname? "&exact=on":"",
1662                        NULL);
1663   if (!request)
1664     {
1665       err = gpg_error_from_syserror ();
1666       goto leave;
1667     }
1668
1669   /* Send the request.  */
1670   err = send_request (ctrl, request, hostport, httphost, httpflags,
1671                       NULL, NULL, &fp, &http_status);
1672   if (handle_send_request_error (ctrl, err, request, http_status, &tries))
1673     {
1674       reselect = 1;
1675       goto again;
1676     }
1677   if (err)
1678     {
1679       if (gpg_err_code (err) == GPG_ERR_NO_DATA)
1680         dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1681       goto leave;
1682     }
1683
1684   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1685   if (err)
1686     goto leave;
1687
1688   /* Return the read stream and close the HTTP context.  */
1689   *r_fp = fp;
1690   fp = NULL;
1691
1692  leave:
1693   es_fclose (fp);
1694   xfree (request);
1695   xfree (hostport);
1696   xfree (httphost);
1697   xfree (searchkey);
1698   return err;
1699 }
1700
1701
1702
1703 \f
1704 /* Callback parameters for put_post_cb.  */
1705 struct put_post_parm_s
1706 {
1707   char *datastring;
1708 };
1709
1710
1711 /* Helper for ks_hkp_put.  */
1712 static gpg_error_t
1713 put_post_cb (void *opaque, http_t http)
1714 {
1715   struct put_post_parm_s *parm = opaque;
1716   gpg_error_t err = 0;
1717   estream_t fp;
1718   size_t len;
1719
1720   fp = http_get_write_ptr (http);
1721   len = strlen (parm->datastring);
1722
1723   es_fprintf (fp,
1724               "Content-Type: application/x-www-form-urlencoded\r\n"
1725               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1726   http_start_data (http);
1727   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1728     err = gpg_error_from_syserror ();
1729   return err;
1730 }
1731
1732
1733 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI.  */
1734 gpg_error_t
1735 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1736 {
1737   gpg_error_t err;
1738   char *hostport = NULL;
1739   char *request = NULL;
1740   estream_t fp = NULL;
1741   struct put_post_parm_s parm;
1742   char *armored = NULL;
1743   int reselect;
1744   char *httphost = NULL;
1745   unsigned int httpflags;
1746   unsigned int http_status;
1747   unsigned int tries = SEND_REQUEST_RETRIES;
1748
1749   parm.datastring = NULL;
1750
1751   err = armor_data (&armored, data, datalen);
1752   if (err)
1753     goto leave;
1754
1755   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1756   if (!parm.datastring)
1757     {
1758       err = gpg_error_from_syserror ();
1759       goto leave;
1760     }
1761   xfree (armored);
1762   armored = NULL;
1763
1764   /* Build the request string.  */
1765   reselect = 0;
1766  again:
1767   xfree (hostport); hostport = NULL;
1768   xfree (httphost); httphost = NULL;
1769   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1770                         reselect, uri->explicit_port,
1771                         &hostport, &httpflags, &httphost);
1772   if (err)
1773     goto leave;
1774
1775   xfree (request);
1776   request = strconcat (hostport, "/pks/add", NULL);
1777   if (!request)
1778     {
1779       err = gpg_error_from_syserror ();
1780       goto leave;
1781     }
1782
1783   /* Send the request.  */
1784   err = send_request (ctrl, request, hostport, httphost, 0,
1785                       put_post_cb, &parm, &fp, &http_status);
1786   if (handle_send_request_error (ctrl, err, request, http_status, &tries))
1787     {
1788       reselect = 1;
1789       goto again;
1790     }
1791   if (err)
1792     goto leave;
1793
1794  leave:
1795   es_fclose (fp);
1796   xfree (parm.datastring);
1797   xfree (armored);
1798   xfree (request);
1799   xfree (hostport);
1800   xfree (httphost);
1801   return err;
1802 }
1803
1804 void
1805 ks_hkp_init (void)
1806 {
1807   int err;
1808
1809   err = npth_mutex_init (&hosttable_lock, NULL);
1810   if (err)
1811     log_fatal ("error initializing mutex: %s\n", strerror (err));
1812 }