1b14a2e6aeb3eab5df7605c7599e791e9d04aa79
[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 *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     default:
1399       break;
1400     }
1401
1402   if (*tries_left)
1403     --*tries_left;
1404
1405   return retry;
1406 }
1407
1408 \f
1409 /* Search the keyserver identified by URI for keys matching PATTERN.
1410    On success R_FP has an open stream to read the data.  If
1411    R_HTTP_STATUS is not NULL, the http status code will be stored
1412    there.  */
1413 gpg_error_t
1414 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1415                estream_t *r_fp, unsigned int *r_http_status)
1416 {
1417   gpg_error_t err;
1418   KEYDB_SEARCH_DESC desc;
1419   char fprbuf[2+40+1];
1420   char *hostport = NULL;
1421   char *request = NULL;
1422   estream_t fp = NULL;
1423   int reselect;
1424   unsigned int httpflags;
1425   char *httphost = NULL;
1426   unsigned int tries = SEND_REQUEST_RETRIES;
1427
1428   *r_fp = NULL;
1429
1430   /* Remove search type indicator and adjust PATTERN accordingly.
1431      Note that HKP keyservers like the 0x to be present when searching
1432      by keyid.  We need to re-format the fingerprint and keyids so to
1433      remove the gpg specific force-use-of-this-key flag ("!").  */
1434   err = classify_user_id (pattern, &desc, 1);
1435   if (err)
1436     return err;
1437   switch (desc.mode)
1438     {
1439     case KEYDB_SEARCH_MODE_EXACT:
1440     case KEYDB_SEARCH_MODE_SUBSTR:
1441     case KEYDB_SEARCH_MODE_MAIL:
1442     case KEYDB_SEARCH_MODE_MAILSUB:
1443       pattern = desc.u.name;
1444       break;
1445     case KEYDB_SEARCH_MODE_SHORT_KID:
1446       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1447       pattern = fprbuf;
1448       break;
1449     case KEYDB_SEARCH_MODE_LONG_KID:
1450       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1451                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1452       pattern = fprbuf;
1453       break;
1454     case KEYDB_SEARCH_MODE_FPR16:
1455       fprbuf[0] = '0';
1456       fprbuf[1] = 'x';
1457       bin2hex (desc.u.fpr, 16, fprbuf+2);
1458       pattern = fprbuf;
1459       break;
1460     case KEYDB_SEARCH_MODE_FPR20:
1461     case KEYDB_SEARCH_MODE_FPR:
1462       fprbuf[0] = '0';
1463       fprbuf[1] = 'x';
1464       bin2hex (desc.u.fpr, 20, fprbuf+2);
1465       pattern = fprbuf;
1466       break;
1467     default:
1468       return gpg_error (GPG_ERR_INV_USER_ID);
1469     }
1470
1471   /* Build the request string.  */
1472   reselect = 0;
1473  again:
1474   {
1475     char *searchkey;
1476
1477     xfree (hostport); hostport = NULL;
1478     xfree (httphost); httphost = NULL;
1479     err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1480                           reselect, uri->explicit_port,
1481                           &hostport, &httpflags, &httphost);
1482     if (err)
1483       goto leave;
1484
1485     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1486     if (!searchkey)
1487       {
1488         err = gpg_error_from_syserror ();
1489         goto leave;
1490       }
1491
1492     xfree (request);
1493     request = strconcat (hostport,
1494                          "/pks/lookup?op=index&options=mr&search=",
1495                          searchkey,
1496                          NULL);
1497     xfree (searchkey);
1498     if (!request)
1499       {
1500         err = gpg_error_from_syserror ();
1501         goto leave;
1502       }
1503   }
1504
1505   /* Send the request.  */
1506   err = send_request (ctrl, request, hostport, httphost, httpflags,
1507                       NULL, NULL, &fp, r_http_status);
1508   if (handle_send_request_error (ctrl, err, request, &tries))
1509     {
1510       reselect = 1;
1511       goto again;
1512     }
1513   if (err)
1514     {
1515       if (gpg_err_code (err) == GPG_ERR_NO_DATA)
1516         dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1517       goto leave;
1518     }
1519
1520   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1521   if (err)
1522     goto leave;
1523
1524   /* Peek at the response.  */
1525   {
1526     int c = es_getc (fp);
1527     if (c == -1)
1528       {
1529         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1530         log_error ("error reading response: %s\n", gpg_strerror (err));
1531         goto leave;
1532       }
1533     if (c == '<')
1534       {
1535         /* The document begins with a '<': Assume a HTML response,
1536            which we don't support.  */
1537         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1538         goto leave;
1539       }
1540     es_ungetc (c, fp);
1541   }
1542
1543   /* Return the read stream.  */
1544   *r_fp = fp;
1545   fp = NULL;
1546
1547  leave:
1548   es_fclose (fp);
1549   xfree (request);
1550   xfree (hostport);
1551   xfree (httphost);
1552   return err;
1553 }
1554
1555
1556 /* Get the key described key the KEYSPEC string from the keyserver
1557    identified by URI.  On success R_FP has an open stream to read the
1558    data.  The data will be provided in a format GnuPG can import
1559    (either a binary OpenPGP message or an armored one).  */
1560 gpg_error_t
1561 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1562 {
1563   gpg_error_t err;
1564   KEYDB_SEARCH_DESC desc;
1565   char kidbuf[2+40+1];
1566   const char *exactname = NULL;
1567   char *searchkey = NULL;
1568   char *hostport = NULL;
1569   char *request = NULL;
1570   estream_t fp = NULL;
1571   int reselect;
1572   char *httphost = NULL;
1573   unsigned int httpflags;
1574   unsigned int tries = SEND_REQUEST_RETRIES;
1575
1576   *r_fp = NULL;
1577
1578   /* Remove search type indicator and adjust PATTERN accordingly.
1579      Note that HKP keyservers like the 0x to be present when searching
1580      by keyid.  We need to re-format the fingerprint and keyids so to
1581      remove the gpg specific force-use-of-this-key flag ("!").  */
1582   err = classify_user_id (keyspec, &desc, 1);
1583   if (err)
1584     return err;
1585   switch (desc.mode)
1586     {
1587     case KEYDB_SEARCH_MODE_SHORT_KID:
1588       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1589       break;
1590     case KEYDB_SEARCH_MODE_LONG_KID:
1591       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1592                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1593       break;
1594     case KEYDB_SEARCH_MODE_FPR20:
1595     case KEYDB_SEARCH_MODE_FPR:
1596       /* This is a v4 fingerprint. */
1597       kidbuf[0] = '0';
1598       kidbuf[1] = 'x';
1599       bin2hex (desc.u.fpr, 20, kidbuf+2);
1600       break;
1601
1602     case KEYDB_SEARCH_MODE_EXACT:
1603       exactname = desc.u.name;
1604       break;
1605
1606     case KEYDB_SEARCH_MODE_FPR16:
1607       log_error ("HKP keyservers do not support v3 fingerprints\n");
1608       /* fall through */
1609     default:
1610       return gpg_error (GPG_ERR_INV_USER_ID);
1611     }
1612
1613   searchkey = http_escape_string (exactname? exactname : kidbuf,
1614                                   EXTRA_ESCAPE_CHARS);
1615   if (!searchkey)
1616     {
1617       err = gpg_error_from_syserror ();
1618       goto leave;
1619     }
1620
1621   reselect = 0;
1622  again:
1623   /* Build the request string.  */
1624   xfree (hostport); hostport = NULL;
1625   xfree (httphost); httphost = NULL;
1626   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1627                         reselect, uri->explicit_port,
1628                         &hostport, &httpflags, &httphost);
1629   if (err)
1630     goto leave;
1631
1632   xfree (request);
1633   request = strconcat (hostport,
1634                        "/pks/lookup?op=get&options=mr&search=",
1635                        searchkey,
1636                        exactname? "&exact=on":"",
1637                        NULL);
1638   if (!request)
1639     {
1640       err = gpg_error_from_syserror ();
1641       goto leave;
1642     }
1643
1644   /* Send the request.  */
1645   err = send_request (ctrl, request, hostport, httphost, httpflags,
1646                       NULL, NULL, &fp, NULL);
1647   if (handle_send_request_error (ctrl, err, request, &tries))
1648     {
1649       reselect = 1;
1650       goto again;
1651     }
1652   if (err)
1653     {
1654       if (gpg_err_code (err) == GPG_ERR_NO_DATA)
1655         dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1656       goto leave;
1657     }
1658
1659   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1660   if (err)
1661     goto leave;
1662
1663   /* Return the read stream and close the HTTP context.  */
1664   *r_fp = fp;
1665   fp = NULL;
1666
1667  leave:
1668   es_fclose (fp);
1669   xfree (request);
1670   xfree (hostport);
1671   xfree (httphost);
1672   xfree (searchkey);
1673   return err;
1674 }
1675
1676
1677
1678 \f
1679 /* Callback parameters for put_post_cb.  */
1680 struct put_post_parm_s
1681 {
1682   char *datastring;
1683 };
1684
1685
1686 /* Helper for ks_hkp_put.  */
1687 static gpg_error_t
1688 put_post_cb (void *opaque, http_t http)
1689 {
1690   struct put_post_parm_s *parm = opaque;
1691   gpg_error_t err = 0;
1692   estream_t fp;
1693   size_t len;
1694
1695   fp = http_get_write_ptr (http);
1696   len = strlen (parm->datastring);
1697
1698   es_fprintf (fp,
1699               "Content-Type: application/x-www-form-urlencoded\r\n"
1700               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1701   http_start_data (http);
1702   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1703     err = gpg_error_from_syserror ();
1704   return err;
1705 }
1706
1707
1708 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI.  */
1709 gpg_error_t
1710 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1711 {
1712   gpg_error_t err;
1713   char *hostport = NULL;
1714   char *request = NULL;
1715   estream_t fp = NULL;
1716   struct put_post_parm_s parm;
1717   char *armored = NULL;
1718   int reselect;
1719   char *httphost = NULL;
1720   unsigned int httpflags;
1721   unsigned int tries = SEND_REQUEST_RETRIES;
1722
1723   parm.datastring = NULL;
1724
1725   err = armor_data (&armored, data, datalen);
1726   if (err)
1727     goto leave;
1728
1729   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1730   if (!parm.datastring)
1731     {
1732       err = gpg_error_from_syserror ();
1733       goto leave;
1734     }
1735   xfree (armored);
1736   armored = NULL;
1737
1738   /* Build the request string.  */
1739   reselect = 0;
1740  again:
1741   xfree (hostport); hostport = NULL;
1742   xfree (httphost); httphost = NULL;
1743   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1744                         reselect, uri->explicit_port,
1745                         &hostport, &httpflags, &httphost);
1746   if (err)
1747     goto leave;
1748
1749   xfree (request);
1750   request = strconcat (hostport, "/pks/add", NULL);
1751   if (!request)
1752     {
1753       err = gpg_error_from_syserror ();
1754       goto leave;
1755     }
1756
1757   /* Send the request.  */
1758   err = send_request (ctrl, request, hostport, httphost, 0,
1759                       put_post_cb, &parm, &fp, NULL);
1760   if (handle_send_request_error (ctrl, err, request, &tries))
1761     {
1762       reselect = 1;
1763       goto again;
1764     }
1765   if (err)
1766     goto leave;
1767
1768  leave:
1769   es_fclose (fp);
1770   xfree (parm.datastring);
1771   xfree (armored);
1772   xfree (request);
1773   xfree (hostport);
1774   xfree (httphost);
1775   return err;
1776 }
1777
1778 void
1779 ks_hkp_init (void)
1780 {
1781   int err;
1782
1783   err = npth_mutex_init (&hosttable_lock, NULL);
1784   if (err)
1785     log_fatal ("error initializing mutex: %s\n", strerror (err));
1786 }