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