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