dirmngr: Add option --keyserver.
[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 plain server: We use
387              the canonical name of the pool as the virtual host along
388              with the IP addresses.  If it is not a pool, we use the
389              specified name. */
390           n_v6 = n_v4 = 0;
391           for (ai = aibuf; ai; ai = ai->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 (hi->pool, 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
969                     |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
970                     |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
971                    ctrl->http_proxy,
972                    session,
973                    NULL,
974                    /*FIXME curl->srvtag*/NULL);
975   if (!err)
976     {
977       fp = http_get_write_ptr (http);
978       /* Avoid caches to get the most recent copy of the key.  We set
979          both the Pragma and Cache-Control versions of the header, so
980          we're good with both HTTP 1.0 and 1.1.  */
981       es_fputs ("Pragma: no-cache\r\n"
982                 "Cache-Control: no-cache\r\n", fp);
983       if (post_cb)
984         err = post_cb (post_cb_value, http);
985       if (!err)
986         {
987           http_start_data (http);
988           if (es_ferror (fp))
989             err = gpg_error_from_syserror ();
990         }
991     }
992   if (err)
993     {
994       /* Fixme: After a redirection we show the old host name.  */
995       log_error (_("error connecting to '%s': %s\n"),
996                  hostportstr, gpg_strerror (err));
997       goto leave;
998     }
999
1000   /* Wait for the response.  */
1001   dirmngr_tick (ctrl);
1002   err = http_wait_response (http);
1003   if (err)
1004     {
1005       log_error (_("error reading HTTP response for '%s': %s\n"),
1006                  hostportstr, gpg_strerror (err));
1007       goto leave;
1008     }
1009
1010   if (http_get_tls_info (http, NULL))
1011     {
1012       /* Update the httpflags so that a redirect won't fallback to an
1013          unencrypted connection.  */
1014       httpflags |= HTTP_FLAG_FORCE_TLS;
1015     }
1016
1017   switch (http_get_status_code (http))
1018     {
1019     case 200:
1020       err = 0;
1021       break; /* Success.  */
1022
1023     case 301:
1024     case 302:
1025     case 307:
1026       {
1027         const char *s = http_get_header (http, "Location");
1028
1029         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1030                   request, s?s:"[none]", http_get_status_code (http));
1031         if (s && *s && redirects_left-- )
1032           {
1033             xfree (request_buffer);
1034             request_buffer = xtrystrdup (s);
1035             if (request_buffer)
1036               {
1037                 request = request_buffer;
1038                 http_close (http, 0);
1039                 http = NULL;
1040                 goto once_more;
1041               }
1042             err = gpg_error_from_syserror ();
1043           }
1044         else
1045           err = gpg_error (GPG_ERR_NO_DATA);
1046         log_error (_("too many redirections\n"));
1047       }
1048       goto leave;
1049
1050     default:
1051       log_error (_("error accessing '%s': http status %u\n"),
1052                  request, http_get_status_code (http));
1053       err = gpg_error (GPG_ERR_NO_DATA);
1054       goto leave;
1055     }
1056
1057   /* FIXME: We should register a permanent redirection and whether a
1058      host has ever used TLS so that future calls will always use
1059      TLS. */
1060
1061   fp = http_get_read_ptr (http);
1062   if (!fp)
1063     {
1064       err = gpg_error (GPG_ERR_BUG);
1065       goto leave;
1066     }
1067
1068   /* Return the read stream and close the HTTP context.  */
1069   *r_fp = fp;
1070   http_close (http, 1);
1071   http = NULL;
1072
1073  leave:
1074   http_close (http, 0);
1075   http_session_release (session);
1076   xfree (request_buffer);
1077   return err;
1078 }
1079
1080
1081 /* Helper to evaluate the error code ERR form a send_request() call
1082    with REQUEST.  The function returns true if the caller shall try
1083    again.  TRIES_LEFT points to a variable to track the number of
1084    retries; this function decrements it and won't return true if it is
1085    down to zero. */
1086 static int
1087 handle_send_request_error (gpg_error_t err, const char *request,
1088                            unsigned int *tries_left)
1089 {
1090   int retry = 0;
1091
1092   switch (gpg_err_code (err))
1093     {
1094     case GPG_ERR_ECONNREFUSED:
1095     case GPG_ERR_ENETUNREACH:
1096     case GPG_ERR_UNKNOWN_HOST:
1097     case GPG_ERR_NETWORK:
1098       if (mark_host_dead (request) && *tries_left)
1099         retry = 1;
1100       break;
1101
1102     case GPG_ERR_ETIMEDOUT:
1103       if (*tries_left)
1104         {
1105           log_info ("selecting a different host due to a timeout\n");
1106           retry = 1;
1107         }
1108
1109     default:
1110       break;
1111     }
1112
1113   if (*tries_left)
1114     --*tries_left;
1115
1116   return retry;
1117 }
1118
1119 \f
1120 /* Search the keyserver identified by URI for keys matching PATTERN.
1121    On success R_FP has an open stream to read the data.  */
1122 gpg_error_t
1123 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1124                estream_t *r_fp)
1125 {
1126   gpg_error_t err;
1127   KEYDB_SEARCH_DESC desc;
1128   char fprbuf[2+40+1];
1129   char *hostport = NULL;
1130   char *request = NULL;
1131   estream_t fp = NULL;
1132   int reselect;
1133   unsigned int httpflags;
1134   char *httphost = NULL;
1135   unsigned int tries = SEND_REQUEST_RETRIES;
1136
1137   *r_fp = NULL;
1138
1139   /* Remove search type indicator and adjust PATTERN accordingly.
1140      Note that HKP keyservers like the 0x to be present when searching
1141      by keyid.  We need to re-format the fingerprint and keyids so to
1142      remove the gpg specific force-use-of-this-key flag ("!").  */
1143   err = classify_user_id (pattern, &desc, 1);
1144   if (err)
1145     return err;
1146   switch (desc.mode)
1147     {
1148     case KEYDB_SEARCH_MODE_EXACT:
1149     case KEYDB_SEARCH_MODE_SUBSTR:
1150     case KEYDB_SEARCH_MODE_MAIL:
1151     case KEYDB_SEARCH_MODE_MAILSUB:
1152       pattern = desc.u.name;
1153       break;
1154     case KEYDB_SEARCH_MODE_SHORT_KID:
1155       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1156       pattern = fprbuf;
1157       break;
1158     case KEYDB_SEARCH_MODE_LONG_KID:
1159       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1160                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1161       pattern = fprbuf;
1162       break;
1163     case KEYDB_SEARCH_MODE_FPR16:
1164       bin2hex (desc.u.fpr, 16, fprbuf);
1165       pattern = fprbuf;
1166       break;
1167     case KEYDB_SEARCH_MODE_FPR20:
1168     case KEYDB_SEARCH_MODE_FPR:
1169       bin2hex (desc.u.fpr, 20, fprbuf);
1170       pattern = fprbuf;
1171       break;
1172     default:
1173       return gpg_error (GPG_ERR_INV_USER_ID);
1174     }
1175
1176   /* Build the request string.  */
1177   reselect = 0;
1178  again:
1179   {
1180     char *searchkey;
1181
1182     xfree (hostport); hostport = NULL;
1183     xfree (httphost); httphost = NULL;
1184     err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1185                           &hostport, &httpflags, &httphost);
1186     if (err)
1187       goto leave;
1188
1189     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1190     if (!searchkey)
1191       {
1192         err = gpg_error_from_syserror ();
1193         goto leave;
1194       }
1195
1196     xfree (request);
1197     request = strconcat (hostport,
1198                          "/pks/lookup?op=index&options=mr&search=",
1199                          searchkey,
1200                          NULL);
1201     xfree (searchkey);
1202     if (!request)
1203       {
1204         err = gpg_error_from_syserror ();
1205         goto leave;
1206       }
1207   }
1208
1209   /* Send the request.  */
1210   err = send_request (ctrl, request, hostport, httphost, httpflags,
1211                       NULL, NULL, &fp);
1212   if (handle_send_request_error (err, request, &tries))
1213     {
1214       reselect = 1;
1215       goto again;
1216     }
1217   if (err)
1218     goto leave;
1219
1220   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1221   if (err)
1222     goto leave;
1223
1224   /* Peek at the response.  */
1225   {
1226     int c = es_getc (fp);
1227     if (c == -1)
1228       {
1229         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1230         log_error ("error reading response: %s\n", gpg_strerror (err));
1231         goto leave;
1232       }
1233     if (c == '<')
1234       {
1235         /* The document begins with a '<': Assume a HTML response,
1236            which we don't support.  */
1237         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1238         goto leave;
1239       }
1240     es_ungetc (c, fp);
1241   }
1242
1243   /* Return the read stream.  */
1244   *r_fp = fp;
1245   fp = NULL;
1246
1247  leave:
1248   es_fclose (fp);
1249   xfree (request);
1250   xfree (hostport);
1251   xfree (httphost);
1252   return err;
1253 }
1254
1255
1256 /* Get the key described key the KEYSPEC string from the keyserver
1257    identified by URI.  On success R_FP has an open stream to read the
1258    data.  The data will be provided in a format GnuPG can import
1259    (either a binary OpenPGP message or an armored one).  */
1260 gpg_error_t
1261 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1262 {
1263   gpg_error_t err;
1264   KEYDB_SEARCH_DESC desc;
1265   char kidbuf[2+40+1];
1266   const char *exactname = NULL;
1267   char *searchkey = NULL;
1268   char *hostport = NULL;
1269   char *request = NULL;
1270   estream_t fp = NULL;
1271   int reselect;
1272   char *httphost = NULL;
1273   unsigned int httpflags;
1274   unsigned int tries = SEND_REQUEST_RETRIES;
1275
1276   *r_fp = NULL;
1277
1278   /* Remove search type indicator and adjust PATTERN accordingly.
1279      Note that HKP keyservers like the 0x to be present when searching
1280      by keyid.  We need to re-format the fingerprint and keyids so to
1281      remove the gpg specific force-use-of-this-key flag ("!").  */
1282   err = classify_user_id (keyspec, &desc, 1);
1283   if (err)
1284     return err;
1285   switch (desc.mode)
1286     {
1287     case KEYDB_SEARCH_MODE_SHORT_KID:
1288       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1289       break;
1290     case KEYDB_SEARCH_MODE_LONG_KID:
1291       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1292                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1293       break;
1294     case KEYDB_SEARCH_MODE_FPR20:
1295     case KEYDB_SEARCH_MODE_FPR:
1296       /* This is a v4 fingerprint. */
1297       kidbuf[0] = '0';
1298       kidbuf[1] = 'x';
1299       bin2hex (desc.u.fpr, 20, kidbuf+2);
1300       break;
1301
1302     case KEYDB_SEARCH_MODE_EXACT:
1303       exactname = desc.u.name;
1304       break;
1305
1306     case KEYDB_SEARCH_MODE_FPR16:
1307       log_error ("HKP keyservers do not support v3 fingerprints\n");
1308     default:
1309       return gpg_error (GPG_ERR_INV_USER_ID);
1310     }
1311
1312   searchkey = http_escape_string (exactname? exactname : kidbuf,
1313                                   EXTRA_ESCAPE_CHARS);
1314   if (!searchkey)
1315     {
1316       err = gpg_error_from_syserror ();
1317       goto leave;
1318     }
1319
1320   reselect = 0;
1321  again:
1322   /* Build the request string.  */
1323   xfree (hostport); hostport = NULL;
1324   xfree (httphost); httphost = NULL;
1325   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1326                         &hostport, &httpflags, &httphost);
1327   if (err)
1328     goto leave;
1329
1330   xfree (request);
1331   request = strconcat (hostport,
1332                        "/pks/lookup?op=get&options=mr&search=",
1333                        searchkey,
1334                        exactname? "&exact=on":"",
1335                        NULL);
1336   if (!request)
1337     {
1338       err = gpg_error_from_syserror ();
1339       goto leave;
1340     }
1341
1342   /* Send the request.  */
1343   err = send_request (ctrl, request, hostport, httphost, httpflags,
1344                       NULL, NULL, &fp);
1345   if (handle_send_request_error (err, request, &tries))
1346     {
1347       reselect = 1;
1348       goto again;
1349     }
1350   if (err)
1351     goto leave;
1352
1353   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1354   if (err)
1355     goto leave;
1356
1357   /* Return the read stream and close the HTTP context.  */
1358   *r_fp = fp;
1359   fp = NULL;
1360
1361  leave:
1362   es_fclose (fp);
1363   xfree (request);
1364   xfree (hostport);
1365   xfree (httphost);
1366   xfree (searchkey);
1367   return err;
1368 }
1369
1370
1371
1372 \f
1373 /* Callback parameters for put_post_cb.  */
1374 struct put_post_parm_s
1375 {
1376   char *datastring;
1377 };
1378
1379
1380 /* Helper for ks_hkp_put.  */
1381 static gpg_error_t
1382 put_post_cb (void *opaque, http_t http)
1383 {
1384   struct put_post_parm_s *parm = opaque;
1385   gpg_error_t err = 0;
1386   estream_t fp;
1387   size_t len;
1388
1389   fp = http_get_write_ptr (http);
1390   len = strlen (parm->datastring);
1391
1392   es_fprintf (fp,
1393               "Content-Type: application/x-www-form-urlencoded\r\n"
1394               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1395   http_start_data (http);
1396   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1397     err = gpg_error_from_syserror ();
1398   return err;
1399 }
1400
1401
1402 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI.  */
1403 gpg_error_t
1404 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1405 {
1406   gpg_error_t err;
1407   char *hostport = NULL;
1408   char *request = NULL;
1409   estream_t fp = NULL;
1410   struct put_post_parm_s parm;
1411   char *armored = NULL;
1412   int reselect;
1413   char *httphost = NULL;
1414   unsigned int httpflags;
1415   unsigned int tries = SEND_REQUEST_RETRIES;
1416
1417   parm.datastring = NULL;
1418
1419   err = armor_data (&armored, data, datalen);
1420   if (err)
1421     goto leave;
1422
1423   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1424   if (!parm.datastring)
1425     {
1426       err = gpg_error_from_syserror ();
1427       goto leave;
1428     }
1429   xfree (armored);
1430   armored = NULL;
1431
1432   /* Build the request string.  */
1433   reselect = 0;
1434  again:
1435   xfree (hostport); hostport = NULL;
1436   xfree (httphost); httphost = NULL;
1437   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1438                         &hostport, &httpflags, &httphost);
1439   if (err)
1440     goto leave;
1441
1442   xfree (request);
1443   request = strconcat (hostport, "/pks/add", NULL);
1444   if (!request)
1445     {
1446       err = gpg_error_from_syserror ();
1447       goto leave;
1448     }
1449
1450   /* Send the request.  */
1451   err = send_request (ctrl, request, hostport, httphost, 0,
1452                       put_post_cb, &parm, &fp);
1453   if (handle_send_request_error (err, request, &tries))
1454     {
1455       reselect = 1;
1456       goto again;
1457     }
1458   if (err)
1459     goto leave;
1460
1461  leave:
1462   es_fclose (fp);
1463   xfree (parm.datastring);
1464   xfree (armored);
1465   xfree (request);
1466   xfree (hostport);
1467   xfree (httphost);
1468   return err;
1469 }