dirmngr: Handle http status '501 Not Implemented'.
[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     case 501:
1087       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1088       goto leave;
1089
1090     default:
1091       log_error (_("error accessing '%s': http status %u\n"),
1092                  request, http_get_status_code (http));
1093       err = gpg_error (GPG_ERR_NO_DATA);
1094       goto leave;
1095     }
1096
1097   /* FIXME: We should register a permanent redirection and whether a
1098      host has ever used TLS so that future calls will always use
1099      TLS. */
1100
1101   fp = http_get_read_ptr (http);
1102   if (!fp)
1103     {
1104       err = gpg_error (GPG_ERR_BUG);
1105       goto leave;
1106     }
1107
1108   /* Return the read stream and close the HTTP context.  */
1109   *r_fp = fp;
1110   http_close (http, 1);
1111   http = NULL;
1112
1113  leave:
1114   http_close (http, 0);
1115   http_session_release (session);
1116   xfree (request_buffer);
1117   return err;
1118 }
1119
1120
1121 /* Helper to evaluate the error code ERR form a send_request() call
1122    with REQUEST.  The function returns true if the caller shall try
1123    again.  TRIES_LEFT points to a variable to track the number of
1124    retries; this function decrements it and won't return true if it is
1125    down to zero. */
1126 static int
1127 handle_send_request_error (gpg_error_t err, const char *request,
1128                            unsigned int *tries_left)
1129 {
1130   int retry = 0;
1131
1132   switch (gpg_err_code (err))
1133     {
1134     case GPG_ERR_ECONNREFUSED:
1135     case GPG_ERR_ENETUNREACH:
1136     case GPG_ERR_UNKNOWN_HOST:
1137     case GPG_ERR_NETWORK:
1138       if (mark_host_dead (request) && *tries_left)
1139         retry = 1;
1140       break;
1141
1142     case GPG_ERR_ETIMEDOUT:
1143       if (*tries_left)
1144         {
1145           log_info ("selecting a different host due to a timeout\n");
1146           retry = 1;
1147         }
1148
1149     default:
1150       break;
1151     }
1152
1153   if (*tries_left)
1154     --*tries_left;
1155
1156   return retry;
1157 }
1158
1159 \f
1160 /* Search the keyserver identified by URI for keys matching PATTERN.
1161    On success R_FP has an open stream to read the data.  */
1162 gpg_error_t
1163 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1164                estream_t *r_fp)
1165 {
1166   gpg_error_t err;
1167   KEYDB_SEARCH_DESC desc;
1168   char fprbuf[2+40+1];
1169   char *hostport = NULL;
1170   char *request = NULL;
1171   estream_t fp = NULL;
1172   int reselect;
1173   unsigned int httpflags;
1174   char *httphost = NULL;
1175   unsigned int tries = SEND_REQUEST_RETRIES;
1176
1177   *r_fp = NULL;
1178
1179   /* Remove search type indicator and adjust PATTERN accordingly.
1180      Note that HKP keyservers like the 0x to be present when searching
1181      by keyid.  We need to re-format the fingerprint and keyids so to
1182      remove the gpg specific force-use-of-this-key flag ("!").  */
1183   err = classify_user_id (pattern, &desc, 1);
1184   if (err)
1185     return err;
1186   switch (desc.mode)
1187     {
1188     case KEYDB_SEARCH_MODE_EXACT:
1189     case KEYDB_SEARCH_MODE_SUBSTR:
1190     case KEYDB_SEARCH_MODE_MAIL:
1191     case KEYDB_SEARCH_MODE_MAILSUB:
1192       pattern = desc.u.name;
1193       break;
1194     case KEYDB_SEARCH_MODE_SHORT_KID:
1195       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1196       pattern = fprbuf;
1197       break;
1198     case KEYDB_SEARCH_MODE_LONG_KID:
1199       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1200                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1201       pattern = fprbuf;
1202       break;
1203     case KEYDB_SEARCH_MODE_FPR16:
1204       bin2hex (desc.u.fpr, 16, fprbuf);
1205       pattern = fprbuf;
1206       break;
1207     case KEYDB_SEARCH_MODE_FPR20:
1208     case KEYDB_SEARCH_MODE_FPR:
1209       bin2hex (desc.u.fpr, 20, fprbuf);
1210       pattern = fprbuf;
1211       break;
1212     default:
1213       return gpg_error (GPG_ERR_INV_USER_ID);
1214     }
1215
1216   /* Build the request string.  */
1217   reselect = 0;
1218  again:
1219   {
1220     char *searchkey;
1221
1222     xfree (hostport); hostport = NULL;
1223     xfree (httphost); httphost = NULL;
1224     err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1225                           &hostport, &httpflags, &httphost);
1226     if (err)
1227       goto leave;
1228
1229     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1230     if (!searchkey)
1231       {
1232         err = gpg_error_from_syserror ();
1233         goto leave;
1234       }
1235
1236     xfree (request);
1237     request = strconcat (hostport,
1238                          "/pks/lookup?op=index&options=mr&search=",
1239                          searchkey,
1240                          NULL);
1241     xfree (searchkey);
1242     if (!request)
1243       {
1244         err = gpg_error_from_syserror ();
1245         goto leave;
1246       }
1247   }
1248
1249   /* Send the request.  */
1250   err = send_request (ctrl, request, hostport, httphost, httpflags,
1251                       NULL, NULL, &fp);
1252   if (handle_send_request_error (err, request, &tries))
1253     {
1254       reselect = 1;
1255       goto again;
1256     }
1257   if (err)
1258     goto leave;
1259
1260   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1261   if (err)
1262     goto leave;
1263
1264   /* Peek at the response.  */
1265   {
1266     int c = es_getc (fp);
1267     if (c == -1)
1268       {
1269         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1270         log_error ("error reading response: %s\n", gpg_strerror (err));
1271         goto leave;
1272       }
1273     if (c == '<')
1274       {
1275         /* The document begins with a '<': Assume a HTML response,
1276            which we don't support.  */
1277         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1278         goto leave;
1279       }
1280     es_ungetc (c, fp);
1281   }
1282
1283   /* Return the read stream.  */
1284   *r_fp = fp;
1285   fp = NULL;
1286
1287  leave:
1288   es_fclose (fp);
1289   xfree (request);
1290   xfree (hostport);
1291   xfree (httphost);
1292   return err;
1293 }
1294
1295
1296 /* Get the key described key the KEYSPEC string from the keyserver
1297    identified by URI.  On success R_FP has an open stream to read the
1298    data.  The data will be provided in a format GnuPG can import
1299    (either a binary OpenPGP message or an armored one).  */
1300 gpg_error_t
1301 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1302 {
1303   gpg_error_t err;
1304   KEYDB_SEARCH_DESC desc;
1305   char kidbuf[2+40+1];
1306   const char *exactname = NULL;
1307   char *searchkey = NULL;
1308   char *hostport = NULL;
1309   char *request = NULL;
1310   estream_t fp = NULL;
1311   int reselect;
1312   char *httphost = NULL;
1313   unsigned int httpflags;
1314   unsigned int tries = SEND_REQUEST_RETRIES;
1315
1316   *r_fp = NULL;
1317
1318   /* Remove search type indicator and adjust PATTERN accordingly.
1319      Note that HKP keyservers like the 0x to be present when searching
1320      by keyid.  We need to re-format the fingerprint and keyids so to
1321      remove the gpg specific force-use-of-this-key flag ("!").  */
1322   err = classify_user_id (keyspec, &desc, 1);
1323   if (err)
1324     return err;
1325   switch (desc.mode)
1326     {
1327     case KEYDB_SEARCH_MODE_SHORT_KID:
1328       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1329       break;
1330     case KEYDB_SEARCH_MODE_LONG_KID:
1331       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1332                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1333       break;
1334     case KEYDB_SEARCH_MODE_FPR20:
1335     case KEYDB_SEARCH_MODE_FPR:
1336       /* This is a v4 fingerprint. */
1337       kidbuf[0] = '0';
1338       kidbuf[1] = 'x';
1339       bin2hex (desc.u.fpr, 20, kidbuf+2);
1340       break;
1341
1342     case KEYDB_SEARCH_MODE_EXACT:
1343       exactname = desc.u.name;
1344       break;
1345
1346     case KEYDB_SEARCH_MODE_FPR16:
1347       log_error ("HKP keyservers do not support v3 fingerprints\n");
1348     default:
1349       return gpg_error (GPG_ERR_INV_USER_ID);
1350     }
1351
1352   searchkey = http_escape_string (exactname? exactname : kidbuf,
1353                                   EXTRA_ESCAPE_CHARS);
1354   if (!searchkey)
1355     {
1356       err = gpg_error_from_syserror ();
1357       goto leave;
1358     }
1359
1360   reselect = 0;
1361  again:
1362   /* Build the request string.  */
1363   xfree (hostport); hostport = NULL;
1364   xfree (httphost); httphost = NULL;
1365   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1366                         &hostport, &httpflags, &httphost);
1367   if (err)
1368     goto leave;
1369
1370   xfree (request);
1371   request = strconcat (hostport,
1372                        "/pks/lookup?op=get&options=mr&search=",
1373                        searchkey,
1374                        exactname? "&exact=on":"",
1375                        NULL);
1376   if (!request)
1377     {
1378       err = gpg_error_from_syserror ();
1379       goto leave;
1380     }
1381
1382   /* Send the request.  */
1383   err = send_request (ctrl, request, hostport, httphost, httpflags,
1384                       NULL, NULL, &fp);
1385   if (handle_send_request_error (err, request, &tries))
1386     {
1387       reselect = 1;
1388       goto again;
1389     }
1390   if (err)
1391     goto leave;
1392
1393   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1394   if (err)
1395     goto leave;
1396
1397   /* Return the read stream and close the HTTP context.  */
1398   *r_fp = fp;
1399   fp = NULL;
1400
1401  leave:
1402   es_fclose (fp);
1403   xfree (request);
1404   xfree (hostport);
1405   xfree (httphost);
1406   xfree (searchkey);
1407   return err;
1408 }
1409
1410
1411
1412 \f
1413 /* Callback parameters for put_post_cb.  */
1414 struct put_post_parm_s
1415 {
1416   char *datastring;
1417 };
1418
1419
1420 /* Helper for ks_hkp_put.  */
1421 static gpg_error_t
1422 put_post_cb (void *opaque, http_t http)
1423 {
1424   struct put_post_parm_s *parm = opaque;
1425   gpg_error_t err = 0;
1426   estream_t fp;
1427   size_t len;
1428
1429   fp = http_get_write_ptr (http);
1430   len = strlen (parm->datastring);
1431
1432   es_fprintf (fp,
1433               "Content-Type: application/x-www-form-urlencoded\r\n"
1434               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1435   http_start_data (http);
1436   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1437     err = gpg_error_from_syserror ();
1438   return err;
1439 }
1440
1441
1442 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI.  */
1443 gpg_error_t
1444 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1445 {
1446   gpg_error_t err;
1447   char *hostport = NULL;
1448   char *request = NULL;
1449   estream_t fp = NULL;
1450   struct put_post_parm_s parm;
1451   char *armored = NULL;
1452   int reselect;
1453   char *httphost = NULL;
1454   unsigned int httpflags;
1455   unsigned int tries = SEND_REQUEST_RETRIES;
1456
1457   parm.datastring = NULL;
1458
1459   err = armor_data (&armored, data, datalen);
1460   if (err)
1461     goto leave;
1462
1463   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1464   if (!parm.datastring)
1465     {
1466       err = gpg_error_from_syserror ();
1467       goto leave;
1468     }
1469   xfree (armored);
1470   armored = NULL;
1471
1472   /* Build the request string.  */
1473   reselect = 0;
1474  again:
1475   xfree (hostport); hostport = NULL;
1476   xfree (httphost); httphost = NULL;
1477   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1478                         &hostport, &httpflags, &httphost);
1479   if (err)
1480     goto leave;
1481
1482   xfree (request);
1483   request = strconcat (hostport, "/pks/add", NULL);
1484   if (!request)
1485     {
1486       err = gpg_error_from_syserror ();
1487       goto leave;
1488     }
1489
1490   /* Send the request.  */
1491   err = send_request (ctrl, request, hostport, httphost, 0,
1492                       put_post_cb, &parm, &fp);
1493   if (handle_send_request_error (err, request, &tries))
1494     {
1495       reselect = 1;
1496       goto again;
1497     }
1498   if (err)
1499     goto leave;
1500
1501  leave:
1502   es_fclose (fp);
1503   xfree (parm.datastring);
1504   xfree (armored);
1505   xfree (request);
1506   xfree (hostport);
1507   xfree (httphost);
1508   return err;
1509 }