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