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