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