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