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