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