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