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