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