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