dirmngr: Support https for KS_FETCH.
[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     "  hkps://\n"
771     "Supported methods: search, get, put\n";
772   gpg_error_t err;
773
774   if (!uri)
775     err = ks_print_help (ctrl, "  hkp\n  hkps");
776   else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
777                             || !strcmp (uri->scheme, "hkps")))
778     err = ks_print_help (ctrl, data);
779   else
780     err = 0;
781
782   return err;
783 }
784
785
786 /* Build the remote part of the URL from SCHEME, HOST and an optional
787    PORT.  Returns an allocated string or NULL on failure and sets
788    ERRNO.  If R_HTTPHOST is not NULL it receive a mallcoed string with
789    the poolname.  */
790 static char *
791 make_host_part (ctrl_t ctrl,
792                 const char *scheme, const char *host, unsigned short port,
793                 int force_reselect,
794                 unsigned int *r_httpflags, char **r_httphost)
795 {
796   char portstr[10];
797   char *hostname;
798   char *hostport;
799
800   /* Map scheme and port.  */
801   if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
802     {
803       scheme = "https";
804       strcpy (portstr, "443");
805     }
806   else /* HKP or HTTP.  */
807     {
808       scheme = "http";
809       strcpy (portstr, "11371");
810     }
811   if (port)
812     snprintf (portstr, sizeof portstr, "%hu", port);
813   else
814     {
815       /*fixme_do_srv_lookup ()*/
816     }
817
818   hostname = map_host (ctrl, host, force_reselect, r_httpflags, r_httphost);
819   if (!hostname)
820     return NULL;
821
822   hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
823   xfree (hostname);
824   return hostport;
825 }
826
827
828 /* Resolve all known keyserver names and update the hosttable.  This
829    is mainly useful for debugging because the resolving is anyway done
830    on demand.  */
831 gpg_error_t
832 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
833 {
834   gpg_error_t err;
835   char *hostport = NULL;
836
837   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1,
838                              NULL, NULL);
839   if (!hostport)
840     {
841       err = gpg_error_from_syserror ();
842       err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
843                             uri->scheme, uri->host, uri->port,
844                             gpg_strerror (err));
845     }
846   else
847     {
848       err = ks_printf_help (ctrl, "%s", hostport);
849       xfree (hostport);
850     }
851   return err;
852 }
853
854
855 /* Housekeeping function called from the housekeeping thread.  It is
856    used to mark dead hosts alive so that they may be tried again after
857    some time.  */
858 void
859 ks_hkp_housekeeping (time_t curtime)
860 {
861   int idx;
862   hostinfo_t hi;
863
864   for (idx=0; idx < hosttable_size; idx++)
865     {
866       hi = hosttable[idx];
867       if (!hi)
868         continue;
869       if (!hi->dead)
870         continue;
871       if (!hi->died_at)
872         continue; /* Do not resurrect manually shot hosts.  */
873       if (hi->died_at + RESURRECT_INTERVAL <= curtime
874           || hi->died_at > curtime)
875         {
876           hi->dead = 0;
877           log_info ("resurrected host '%s'", hi->name);
878         }
879     }
880 }
881
882
883 /* Send an HTTP request.  On success returns an estream object at
884    R_FP.  HOSTPORTSTR is only used for diagnostics.  If HTTPHOST is
885    not NULL it will be used as HTTP "Host" header.  If POST_CB is not
886    NULL a post request is used and that callback is called to allow
887    writing the post data.  */
888 static gpg_error_t
889 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
890               const char *httphost, unsigned int httpflags,
891               gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
892               estream_t *r_fp)
893 {
894   gpg_error_t err;
895   http_session_t session = NULL;
896   http_t http = NULL;
897   int redirects_left = MAX_REDIRECTS;
898   estream_t fp = NULL;
899   char *request_buffer = NULL;
900
901   *r_fp = NULL;
902
903   err = http_session_new (&session, NULL);
904   if (err)
905     goto leave;
906   http_session_set_log_cb (session, cert_log_cb);
907
908  once_more:
909   err = http_open (&http,
910                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
911                    request,
912                    httphost,
913                    /* fixme: AUTH */ NULL,
914                    httpflags,
915                    /* fixme: proxy*/ NULL,
916                    session,
917                    NULL,
918                    /*FIXME curl->srvtag*/NULL);
919   if (!err)
920     {
921       fp = http_get_write_ptr (http);
922       /* Avoid caches to get the most recent copy of the key.  We set
923          both the Pragma and Cache-Control versions of the header, so
924          we're good with both HTTP 1.0 and 1.1.  */
925       es_fputs ("Pragma: no-cache\r\n"
926                 "Cache-Control: no-cache\r\n", fp);
927       if (post_cb)
928         err = post_cb (post_cb_value, http);
929       if (!err)
930         {
931           http_start_data (http);
932           if (es_ferror (fp))
933             err = gpg_error_from_syserror ();
934         }
935     }
936   if (err)
937     {
938       /* Fixme: After a redirection we show the old host name.  */
939       log_error (_("error connecting to '%s': %s\n"),
940                  hostportstr, gpg_strerror (err));
941       goto leave;
942     }
943
944   /* Wait for the response.  */
945   dirmngr_tick (ctrl);
946   err = http_wait_response (http);
947   if (err)
948     {
949       log_error (_("error reading HTTP response for '%s': %s\n"),
950                  hostportstr, gpg_strerror (err));
951       goto leave;
952     }
953
954   if (http_get_tls_info (http, NULL))
955     {
956       /* Update the httpflags so that a redirect won't fallback to an
957          unencrypted connection.  */
958       httpflags |= HTTP_FLAG_FORCE_TLS;
959     }
960
961   switch (http_get_status_code (http))
962     {
963     case 200:
964       err = 0;
965       break; /* Success.  */
966
967     case 301:
968     case 302:
969     case 307:
970       {
971         const char *s = http_get_header (http, "Location");
972
973         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
974                   request, s?s:"[none]", http_get_status_code (http));
975         if (s && *s && redirects_left-- )
976           {
977             xfree (request_buffer);
978             request_buffer = xtrystrdup (s);
979             if (request_buffer)
980               {
981                 request = request_buffer;
982                 http_close (http, 0);
983                 http = NULL;
984                 goto once_more;
985               }
986             err = gpg_error_from_syserror ();
987           }
988         else
989           err = gpg_error (GPG_ERR_NO_DATA);
990         log_error (_("too many redirections\n"));
991       }
992       goto leave;
993
994     default:
995       log_error (_("error accessing '%s': http status %u\n"),
996                  request, http_get_status_code (http));
997       err = gpg_error (GPG_ERR_NO_DATA);
998       goto leave;
999     }
1000
1001   /* FIXME: We should register a permanent redirection and whether a
1002      host has ever used TLS so that future calls will always use
1003      TLS. */
1004
1005   fp = http_get_read_ptr (http);
1006   if (!fp)
1007     {
1008       err = gpg_error (GPG_ERR_BUG);
1009       goto leave;
1010     }
1011
1012   /* Return the read stream and close the HTTP context.  */
1013   *r_fp = fp;
1014   http_close (http, 1);
1015   http = NULL;
1016
1017  leave:
1018   http_close (http, 0);
1019   http_session_release (session);
1020   xfree (request_buffer);
1021   return err;
1022 }
1023
1024
1025 /* Helper to evaluate the error code ERR form a send_request() call
1026    with REQUEST.  The function returns true if the caller shall try
1027    again.  TRIES_LEFT points to a variable to track the number of
1028    retries; this function decrements it and won't return true if it is
1029    down to zero. */
1030 static int
1031 handle_send_request_error (gpg_error_t err, const char *request,
1032                            unsigned int *tries_left)
1033 {
1034   int retry = 0;
1035
1036   switch (gpg_err_code (err))
1037     {
1038     case GPG_ERR_ECONNREFUSED:
1039     case GPG_ERR_ENETUNREACH:
1040       if (mark_host_dead (request) && *tries_left)
1041         retry = 1;
1042       break;
1043
1044     case GPG_ERR_ETIMEDOUT:
1045       if (*tries_left)
1046         {
1047           log_info ("selecting a different host due to a timeout\n");
1048           retry = 1;
1049         }
1050
1051     default:
1052       break;
1053     }
1054
1055   if (*tries_left)
1056     --*tries_left;
1057
1058   return retry;
1059 }
1060
1061 static gpg_error_t
1062 armor_data (char **r_string, const void *data, size_t datalen)
1063 {
1064   gpg_error_t err;
1065   struct b64state b64state;
1066   estream_t fp;
1067   long length;
1068   char *buffer;
1069   size_t nread;
1070
1071   *r_string = NULL;
1072
1073   fp = es_fopenmem (0, "rw,samethread");
1074   if (!fp)
1075     return gpg_error_from_syserror ();
1076
1077   if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
1078       || (err=b64enc_write (&b64state, data, datalen))
1079       || (err = b64enc_finish (&b64state)))
1080     {
1081       es_fclose (fp);
1082       return err;
1083     }
1084
1085   /* FIXME: To avoid the extra buffer allocation estream should
1086      provide a function to snatch the internal allocated memory from
1087      such a memory stream.  */
1088   length = es_ftell (fp);
1089   if (length < 0)
1090     {
1091       err = gpg_error_from_syserror ();
1092       es_fclose (fp);
1093       return err;
1094     }
1095
1096   buffer = xtrymalloc (length+1);
1097   if (!buffer)
1098     {
1099       err = gpg_error_from_syserror ();
1100       es_fclose (fp);
1101       return err;
1102     }
1103
1104   es_rewind (fp);
1105   if (es_read (fp, buffer, length, &nread))
1106     {
1107       err = gpg_error_from_syserror ();
1108       es_fclose (fp);
1109       return err;
1110     }
1111   buffer[nread] = 0;
1112   es_fclose (fp);
1113
1114   *r_string = buffer;
1115   return 0;
1116 }
1117
1118
1119 \f
1120 /* Search the keyserver identified by URI for keys matching PATTERN.
1121    On success R_FP has an open stream to read the data.  */
1122 gpg_error_t
1123 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1124                estream_t *r_fp)
1125 {
1126   gpg_error_t err;
1127   KEYDB_SEARCH_DESC desc;
1128   char fprbuf[2+40+1];
1129   char *hostport = NULL;
1130   char *request = NULL;
1131   estream_t fp = NULL;
1132   int reselect;
1133   unsigned int httpflags;
1134   char *httphost = NULL;
1135   unsigned int tries = SEND_REQUEST_RETRIES;
1136
1137   *r_fp = NULL;
1138
1139   /* Remove search type indicator and adjust PATTERN accordingly.
1140      Note that HKP keyservers like the 0x to be present when searching
1141      by keyid.  We need to re-format the fingerprint and keyids so to
1142      remove the gpg specific force-use-of-this-key flag ("!").  */
1143   err = classify_user_id (pattern, &desc, 1);
1144   if (err)
1145     return err;
1146   switch (desc.mode)
1147     {
1148     case KEYDB_SEARCH_MODE_EXACT:
1149     case KEYDB_SEARCH_MODE_SUBSTR:
1150     case KEYDB_SEARCH_MODE_MAIL:
1151     case KEYDB_SEARCH_MODE_MAILSUB:
1152       pattern = desc.u.name;
1153       break;
1154     case KEYDB_SEARCH_MODE_SHORT_KID:
1155       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1156       pattern = fprbuf;
1157       break;
1158     case KEYDB_SEARCH_MODE_LONG_KID:
1159       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1160                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1161       pattern = fprbuf;
1162       break;
1163     case KEYDB_SEARCH_MODE_FPR16:
1164       bin2hex (desc.u.fpr, 16, fprbuf);
1165       pattern = fprbuf;
1166       break;
1167     case KEYDB_SEARCH_MODE_FPR20:
1168     case KEYDB_SEARCH_MODE_FPR:
1169       bin2hex (desc.u.fpr, 20, fprbuf);
1170       pattern = fprbuf;
1171       break;
1172     default:
1173       return gpg_error (GPG_ERR_INV_USER_ID);
1174     }
1175
1176   /* Build the request string.  */
1177   reselect = 0;
1178  again:
1179   {
1180     char *searchkey;
1181
1182     xfree (hostport);
1183     xfree (httphost); httphost = NULL;
1184     hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1185                                reselect, &httpflags, &httphost);
1186     if (!hostport)
1187       {
1188         err = gpg_error_from_syserror ();
1189         goto leave;
1190       }
1191
1192     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1193     if (!searchkey)
1194       {
1195         err = gpg_error_from_syserror ();
1196         goto leave;
1197       }
1198
1199     xfree (request);
1200     request = strconcat (hostport,
1201                          "/pks/lookup?op=index&options=mr&search=",
1202                          searchkey,
1203                          NULL);
1204     xfree (searchkey);
1205     if (!request)
1206       {
1207         err = gpg_error_from_syserror ();
1208         goto leave;
1209       }
1210   }
1211
1212   /* Send the request.  */
1213   err = send_request (ctrl, request, hostport, httphost, httpflags,
1214                       NULL, NULL, &fp);
1215   if (handle_send_request_error (err, request, &tries))
1216     {
1217       reselect = 1;
1218       goto again;
1219     }
1220   if (err)
1221     goto leave;
1222
1223   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1224   if (err)
1225     goto leave;
1226
1227   /* Peek at the response.  */
1228   {
1229     int c = es_getc (fp);
1230     if (c == -1)
1231       {
1232         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1233         log_error ("error reading response: %s\n", gpg_strerror (err));
1234         goto leave;
1235       }
1236     if (c == '<')
1237       {
1238         /* The document begins with a '<': Assume a HTML response,
1239            which we don't support.  */
1240         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1241         goto leave;
1242       }
1243     es_ungetc (c, fp);
1244   }
1245
1246   /* Return the read stream.  */
1247   *r_fp = fp;
1248   fp = NULL;
1249
1250  leave:
1251   es_fclose (fp);
1252   xfree (request);
1253   xfree (hostport);
1254   xfree (httphost);
1255   return err;
1256 }
1257
1258
1259 /* Get the key described key the KEYSPEC string from the keyserver
1260    identified by URI.  On success R_FP has an open stream to read the
1261    data.  */
1262 gpg_error_t
1263 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1264 {
1265   gpg_error_t err;
1266   KEYDB_SEARCH_DESC desc;
1267   char kidbuf[2+40+1];
1268   const char *exactname = NULL;
1269   char *searchkey = NULL;
1270   char *hostport = NULL;
1271   char *request = NULL;
1272   estream_t fp = NULL;
1273   int reselect;
1274   char *httphost = NULL;
1275   unsigned int httpflags;
1276   unsigned int tries = SEND_REQUEST_RETRIES;
1277
1278   *r_fp = NULL;
1279
1280   /* Remove search type indicator and adjust PATTERN accordingly.
1281      Note that HKP keyservers like the 0x to be present when searching
1282      by keyid.  We need to re-format the fingerprint and keyids so to
1283      remove the gpg specific force-use-of-this-key flag ("!").  */
1284   err = classify_user_id (keyspec, &desc, 1);
1285   if (err)
1286     return err;
1287   switch (desc.mode)
1288     {
1289     case KEYDB_SEARCH_MODE_SHORT_KID:
1290       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1291       break;
1292     case KEYDB_SEARCH_MODE_LONG_KID:
1293       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1294                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1295       break;
1296     case KEYDB_SEARCH_MODE_FPR20:
1297     case KEYDB_SEARCH_MODE_FPR:
1298       /* This is a v4 fingerprint. */
1299       kidbuf[0] = '0';
1300       kidbuf[1] = 'x';
1301       bin2hex (desc.u.fpr, 20, kidbuf+2);
1302       break;
1303
1304     case KEYDB_SEARCH_MODE_EXACT:
1305       exactname = desc.u.name;
1306       break;
1307
1308     case KEYDB_SEARCH_MODE_FPR16:
1309       log_error ("HKP keyservers do not support v3 fingerprints\n");
1310     default:
1311       return gpg_error (GPG_ERR_INV_USER_ID);
1312     }
1313
1314   searchkey = http_escape_string (exactname? exactname : kidbuf,
1315                                   EXTRA_ESCAPE_CHARS);
1316   if (!searchkey)
1317     {
1318       err = gpg_error_from_syserror ();
1319       goto leave;
1320     }
1321
1322   reselect = 0;
1323  again:
1324   /* Build the request string.  */
1325   xfree (hostport);
1326   xfree (httphost); httphost = NULL;
1327   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1328                              reselect, &httpflags, &httphost);
1329   if (!hostport)
1330     {
1331       err = gpg_error_from_syserror ();
1332       goto leave;
1333     }
1334
1335   xfree (request);
1336   request = strconcat (hostport,
1337                        "/pks/lookup?op=get&options=mr&search=",
1338                        searchkey,
1339                        exactname? "&exact=on":"",
1340                        NULL);
1341   if (!request)
1342     {
1343       err = gpg_error_from_syserror ();
1344       goto leave;
1345     }
1346
1347   /* Send the request.  */
1348   err = send_request (ctrl, request, hostport, httphost, httpflags,
1349                       NULL, NULL, &fp);
1350   if (handle_send_request_error (err, request, &tries))
1351     {
1352       reselect = 1;
1353       goto again;
1354     }
1355   if (err)
1356     goto leave;
1357
1358   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1359   if (err)
1360     goto leave;
1361
1362   /* Return the read stream and close the HTTP context.  */
1363   *r_fp = fp;
1364   fp = NULL;
1365
1366  leave:
1367   es_fclose (fp);
1368   xfree (request);
1369   xfree (hostport);
1370   xfree (httphost);
1371   xfree (searchkey);
1372   return err;
1373 }
1374
1375
1376
1377 \f
1378 /* Callback parameters for put_post_cb.  */
1379 struct put_post_parm_s
1380 {
1381   char *datastring;
1382 };
1383
1384
1385 /* Helper for ks_hkp_put.  */
1386 static gpg_error_t
1387 put_post_cb (void *opaque, http_t http)
1388 {
1389   struct put_post_parm_s *parm = opaque;
1390   gpg_error_t err = 0;
1391   estream_t fp;
1392   size_t len;
1393
1394   fp = http_get_write_ptr (http);
1395   len = strlen (parm->datastring);
1396
1397   es_fprintf (fp,
1398               "Content-Type: application/x-www-form-urlencoded\r\n"
1399               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1400   http_start_data (http);
1401   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1402     err = gpg_error_from_syserror ();
1403   return err;
1404 }
1405
1406
1407 /* Send the key in {DATA,DATALEN} to the keyserver identified by  URI.  */
1408 gpg_error_t
1409 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1410 {
1411   gpg_error_t err;
1412   char *hostport = NULL;
1413   char *request = NULL;
1414   estream_t fp = NULL;
1415   struct put_post_parm_s parm;
1416   char *armored = NULL;
1417   int reselect;
1418   char *httphost = NULL;
1419   unsigned int httpflags;
1420   unsigned int tries = SEND_REQUEST_RETRIES;
1421
1422   parm.datastring = NULL;
1423
1424   err = armor_data (&armored, data, datalen);
1425   if (err)
1426     goto leave;
1427
1428   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1429   if (!parm.datastring)
1430     {
1431       err = gpg_error_from_syserror ();
1432       goto leave;
1433     }
1434   xfree (armored);
1435   armored = NULL;
1436
1437   /* Build the request string.  */
1438   reselect = 0;
1439  again:
1440   xfree (hostport);
1441   xfree (httphost); httphost = NULL;
1442   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1443                              reselect, &httpflags, &httphost);
1444   if (!hostport)
1445     {
1446       err = gpg_error_from_syserror ();
1447       goto leave;
1448     }
1449
1450   xfree (request);
1451   request = strconcat (hostport, "/pks/add", NULL);
1452   if (!request)
1453     {
1454       err = gpg_error_from_syserror ();
1455       goto leave;
1456     }
1457
1458   /* Send the request.  */
1459   err = send_request (ctrl, request, hostport, httphost, 0,
1460                       put_post_cb, &parm, &fp);
1461   if (handle_send_request_error (err, request, &tries))
1462     {
1463       reselect = 1;
1464       goto again;
1465     }
1466   if (err)
1467     goto leave;
1468
1469  leave:
1470   es_fclose (fp);
1471   xfree (parm.datastring);
1472   xfree (armored);
1473   xfree (request);
1474   xfree (hostport);
1475   xfree (httphost);
1476   return err;
1477 }