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