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