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