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