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