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