http: Allow overriding of the Host header.
[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     "  hkps://\n"
632     "Supported methods: search, get, put\n";
633   gpg_error_t err;
634
635   if (!uri)
636     err = ks_print_help (ctrl, "  hkp\n  hkps");
637   else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
638                             || !strcmp (uri->scheme, "hkps")))
639     err = ks_print_help (ctrl, data);
640   else
641     err = 0;
642
643   return err;
644 }
645
646
647 /* Build the remote part or the URL from SCHEME, HOST and an optional
648    PORT.  Returns an allocated string or NULL on failure and sets
649    ERRNO.  */
650 static char *
651 make_host_part (ctrl_t ctrl,
652                 const char *scheme, const char *host, unsigned short port,
653                 int force_reselect, unsigned int *r_httpflags)
654 {
655   char portstr[10];
656   char *hostname;
657   char *hostport;
658
659   /* Map scheme and port.  */
660   if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
661     {
662       scheme = "https";
663       strcpy (portstr, "443");
664     }
665   else /* HKP or HTTP.  */
666     {
667       scheme = "http";
668       strcpy (portstr, "11371");
669     }
670   if (port)
671     snprintf (portstr, sizeof portstr, "%hu", port);
672   else
673     {
674       /*fixme_do_srv_lookup ()*/
675     }
676
677   hostname = map_host (ctrl, host, force_reselect, r_httpflags);
678   if (!hostname)
679     return NULL;
680
681   hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
682   xfree (hostname);
683   return hostport;
684 }
685
686
687 /* Resolve all known keyserver names and update the hosttable.  This
688    is mainly useful for debugging because the resolving is anyway done
689    on demand.  */
690 gpg_error_t
691 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
692 {
693   gpg_error_t err;
694   char *hostport = NULL;
695
696   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1, NULL);
697   if (!hostport)
698     {
699       err = gpg_error_from_syserror ();
700       err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
701                             uri->scheme, uri->host, uri->port,
702                             gpg_strerror (err));
703     }
704   else
705     {
706       err = ks_printf_help (ctrl, "%s", hostport);
707       xfree (hostport);
708     }
709   return err;
710 }
711
712
713 /* Housekeeping function called from the housekeeping thread.  It is
714    used to mark dead hosts alive so that they may be tried again after
715    some time.  */
716 void
717 ks_hkp_housekeeping (time_t curtime)
718 {
719   int idx;
720   hostinfo_t hi;
721
722   for (idx=0; idx < hosttable_size; idx++)
723     {
724       hi = hosttable[idx];
725       if (!hi)
726         continue;
727       if (!hi->dead)
728         continue;
729       if (!hi->died_at)
730         continue; /* Do not resurrect manually shot hosts.  */
731       if (hi->died_at + RESURRECT_INTERVAL <= curtime
732           || hi->died_at > curtime)
733         {
734           hi->dead = 0;
735           log_info ("resurrected host '%s'", hi->name);
736         }
737     }
738 }
739
740
741 /* Send an HTTP request.  On success returns an estream object at
742    R_FP.  HOSTPORTSTR is only used for diagnostics.  If POST_CB is not
743    NULL a post request is used and that callback is called to allow
744    writing the post data.  */
745 static gpg_error_t
746 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
747               unsigned int httpflags,
748               gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
749               estream_t *r_fp)
750 {
751   gpg_error_t err;
752   http_session_t session = NULL;
753   http_t http = NULL;
754   int redirects_left = MAX_REDIRECTS;
755   estream_t fp = NULL;
756   char *request_buffer = NULL;
757
758   *r_fp = NULL;
759
760   err = http_session_new (&session, NULL);
761   if (err)
762     goto leave;
763
764  once_more:
765   err = http_open (&http,
766                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
767                    request,
768                    NULL,
769                    /* fixme: AUTH */ NULL,
770                    httpflags,
771                    /* fixme: proxy*/ NULL,
772                    session,
773                    NULL,
774                    /*FIXME curl->srvtag*/NULL);
775   if (!err)
776     {
777       fp = http_get_write_ptr (http);
778       /* Avoid caches to get the most recent copy of the key.  We set
779          both the Pragma and Cache-Control versions of the header, so
780          we're good with both HTTP 1.0 and 1.1.  */
781       es_fputs ("Pragma: no-cache\r\n"
782                 "Cache-Control: no-cache\r\n", fp);
783       if (post_cb)
784         err = post_cb (post_cb_value, http);
785       if (!err)
786         {
787           http_start_data (http);
788           if (es_ferror (fp))
789             err = gpg_error_from_syserror ();
790         }
791     }
792   if (err)
793     {
794       /* Fixme: After a redirection we show the old host name.  */
795       log_error (_("error connecting to '%s': %s\n"),
796                  hostportstr, gpg_strerror (err));
797       goto leave;
798     }
799
800   /* Wait for the response.  */
801   dirmngr_tick (ctrl);
802   err = http_wait_response (http);
803   if (err)
804     {
805       log_error (_("error reading HTTP response for '%s': %s\n"),
806                  hostportstr, gpg_strerror (err));
807       goto leave;
808     }
809
810   if (http_get_tls_info (http, NULL))
811     {
812       /* Update the httpflags so that a redirect won't fallback to an
813          unencrypted connection.  */
814       httpflags |= HTTP_FLAG_FORCE_TLS;
815     }
816
817   switch (http_get_status_code (http))
818     {
819     case 200:
820       err = 0;
821       break; /* Success.  */
822
823     case 301:
824     case 302:
825     case 307:
826       {
827         const char *s = http_get_header (http, "Location");
828
829         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
830                   request, s?s:"[none]", http_get_status_code (http));
831         if (s && *s && redirects_left-- )
832           {
833             xfree (request_buffer);
834             request_buffer = xtrystrdup (s);
835             if (request_buffer)
836               {
837                 request = request_buffer;
838                 http_close (http, 0);
839                 http = NULL;
840                 goto once_more;
841               }
842             err = gpg_error_from_syserror ();
843           }
844         else
845           err = gpg_error (GPG_ERR_NO_DATA);
846         log_error (_("too many redirections\n"));
847       }
848       goto leave;
849
850     default:
851       log_error (_("error accessing '%s': http status %u\n"),
852                  request, http_get_status_code (http));
853       err = gpg_error (GPG_ERR_NO_DATA);
854       goto leave;
855     }
856
857   /* FIXME: We should register a permanent redirection and whether a
858      host has ever used TLS so that future calls will always use
859      TLS. */
860
861   fp = http_get_read_ptr (http);
862   if (!fp)
863     {
864       err = gpg_error (GPG_ERR_BUG);
865       goto leave;
866     }
867
868   /* Return the read stream and close the HTTP context.  */
869   *r_fp = fp;
870   http_close (http, 1);
871   http = NULL;
872
873  leave:
874   http_close (http, 0);
875   http_session_release (session);
876   xfree (request_buffer);
877   return err;
878 }
879
880
881 /* Helper to evaluate the error code ERR form a send_request() call
882    with REQUEST.  The function returns true if the caller shall try
883    again.  TRIES_LEFT points to a variable to track the number of
884    retries; this function decrements it and won't return true if it is
885    down to zero. */
886 static int
887 handle_send_request_error (gpg_error_t err, const char *request,
888                            unsigned int *tries_left)
889 {
890   int retry = 0;
891
892   switch (gpg_err_code (err))
893     {
894     case GPG_ERR_ECONNREFUSED:
895     case GPG_ERR_ENETUNREACH:
896       if (mark_host_dead (request) && *tries_left)
897         retry = 1;
898       break;
899
900     case GPG_ERR_ETIMEDOUT:
901       if (*tries_left)
902         {
903           log_info ("selecting a different host due to a timeout\n");
904           retry = 1;
905         }
906
907     default:
908       break;
909     }
910
911   if (*tries_left)
912     --*tries_left;
913
914   return retry;
915 }
916
917 static gpg_error_t
918 armor_data (char **r_string, const void *data, size_t datalen)
919 {
920   gpg_error_t err;
921   struct b64state b64state;
922   estream_t fp;
923   long length;
924   char *buffer;
925   size_t nread;
926
927   *r_string = NULL;
928
929   fp = es_fopenmem (0, "rw,samethread");
930   if (!fp)
931     return gpg_error_from_syserror ();
932
933   if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
934       || (err=b64enc_write (&b64state, data, datalen))
935       || (err = b64enc_finish (&b64state)))
936     {
937       es_fclose (fp);
938       return err;
939     }
940
941   /* FIXME: To avoid the extra buffer allocation estream should
942      provide a function to snatch the internal allocated memory from
943      such a memory stream.  */
944   length = es_ftell (fp);
945   if (length < 0)
946     {
947       err = gpg_error_from_syserror ();
948       es_fclose (fp);
949       return err;
950     }
951
952   buffer = xtrymalloc (length+1);
953   if (!buffer)
954     {
955       err = gpg_error_from_syserror ();
956       es_fclose (fp);
957       return err;
958     }
959
960   es_rewind (fp);
961   if (es_read (fp, buffer, length, &nread))
962     {
963       err = gpg_error_from_syserror ();
964       es_fclose (fp);
965       return err;
966     }
967   buffer[nread] = 0;
968   es_fclose (fp);
969
970   *r_string = buffer;
971   return 0;
972 }
973
974
975 \f
976 /* Search the keyserver identified by URI for keys matching PATTERN.
977    On success R_FP has an open stream to read the data.  */
978 gpg_error_t
979 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
980                estream_t *r_fp)
981 {
982   gpg_error_t err;
983   KEYDB_SEARCH_DESC desc;
984   char fprbuf[2+40+1];
985   char *hostport = NULL;
986   char *request = NULL;
987   estream_t fp = NULL;
988   int reselect;
989   unsigned int httpflags;
990   unsigned int tries = SEND_REQUEST_RETRIES;
991
992   *r_fp = NULL;
993
994   /* Remove search type indicator and adjust PATTERN accordingly.
995      Note that HKP keyservers like the 0x to be present when searching
996      by keyid.  We need to re-format the fingerprint and keyids so to
997      remove the gpg specific force-use-of-this-key flag ("!").  */
998   err = classify_user_id (pattern, &desc, 1);
999   if (err)
1000     return err;
1001   switch (desc.mode)
1002     {
1003     case KEYDB_SEARCH_MODE_EXACT:
1004     case KEYDB_SEARCH_MODE_SUBSTR:
1005     case KEYDB_SEARCH_MODE_MAIL:
1006     case KEYDB_SEARCH_MODE_MAILSUB:
1007       pattern = desc.u.name;
1008       break;
1009     case KEYDB_SEARCH_MODE_SHORT_KID:
1010       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1011       pattern = fprbuf;
1012       break;
1013     case KEYDB_SEARCH_MODE_LONG_KID:
1014       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1015                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1016       pattern = fprbuf;
1017       break;
1018     case KEYDB_SEARCH_MODE_FPR16:
1019       bin2hex (desc.u.fpr, 16, fprbuf);
1020       pattern = fprbuf;
1021       break;
1022     case KEYDB_SEARCH_MODE_FPR20:
1023     case KEYDB_SEARCH_MODE_FPR:
1024       bin2hex (desc.u.fpr, 20, fprbuf);
1025       pattern = fprbuf;
1026       break;
1027     default:
1028       return gpg_error (GPG_ERR_INV_USER_ID);
1029     }
1030
1031   /* Build the request string.  */
1032   reselect = 0;
1033  again:
1034   {
1035     char *searchkey;
1036
1037     xfree (hostport);
1038     hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1039                                reselect, &httpflags);
1040     if (!hostport)
1041       {
1042         err = gpg_error_from_syserror ();
1043         goto leave;
1044       }
1045
1046     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1047     if (!searchkey)
1048       {
1049         err = gpg_error_from_syserror ();
1050         goto leave;
1051       }
1052
1053     xfree (request);
1054     request = strconcat (hostport,
1055                          "/pks/lookup?op=index&options=mr&search=",
1056                          searchkey,
1057                          NULL);
1058     xfree (searchkey);
1059     if (!request)
1060       {
1061         err = gpg_error_from_syserror ();
1062         goto leave;
1063       }
1064   }
1065
1066   /* Send the request.  */
1067   err = send_request (ctrl, request, hostport, httpflags, NULL, NULL, &fp);
1068   if (handle_send_request_error (err, request, &tries))
1069     {
1070       reselect = 1;
1071       goto again;
1072     }
1073   if (err)
1074     goto leave;
1075
1076   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1077   if (err)
1078     goto leave;
1079
1080   /* Peek at the response.  */
1081   {
1082     int c = es_getc (fp);
1083     if (c == -1)
1084       {
1085         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1086         log_error ("error reading response: %s\n", gpg_strerror (err));
1087         goto leave;
1088       }
1089     if (c == '<')
1090       {
1091         /* The document begins with a '<': Assume a HTML response,
1092            which we don't support.  */
1093         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1094         goto leave;
1095       }
1096     es_ungetc (c, fp);
1097   }
1098
1099   /* Return the read stream.  */
1100   *r_fp = fp;
1101   fp = NULL;
1102
1103  leave:
1104   es_fclose (fp);
1105   xfree (request);
1106   xfree (hostport);
1107   return err;
1108 }
1109
1110
1111 /* Get the key described key the KEYSPEC string from the keyserver
1112    identified by URI.  On success R_FP has an open stream to read the
1113    data.  */
1114 gpg_error_t
1115 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1116 {
1117   gpg_error_t err;
1118   KEYDB_SEARCH_DESC desc;
1119   char kidbuf[2+40+1];
1120   const char *exactname = NULL;
1121   char *searchkey = NULL;
1122   char *hostport = NULL;
1123   char *request = NULL;
1124   estream_t fp = NULL;
1125   int reselect;
1126   unsigned int httpflags;
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 (keyspec, &desc, 1);
1136   if (err)
1137     return err;
1138   switch (desc.mode)
1139     {
1140     case KEYDB_SEARCH_MODE_SHORT_KID:
1141       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1142       break;
1143     case KEYDB_SEARCH_MODE_LONG_KID:
1144       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1145                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1146       break;
1147     case KEYDB_SEARCH_MODE_FPR20:
1148     case KEYDB_SEARCH_MODE_FPR:
1149       /* This is a v4 fingerprint. */
1150       kidbuf[0] = '0';
1151       kidbuf[1] = 'x';
1152       bin2hex (desc.u.fpr, 20, kidbuf+2);
1153       break;
1154
1155     case KEYDB_SEARCH_MODE_EXACT:
1156       exactname = desc.u.name;
1157       break;
1158
1159     case KEYDB_SEARCH_MODE_FPR16:
1160       log_error ("HKP keyservers do not support v3 fingerprints\n");
1161     default:
1162       return gpg_error (GPG_ERR_INV_USER_ID);
1163     }
1164
1165   searchkey = http_escape_string (exactname? exactname : kidbuf,
1166                                   EXTRA_ESCAPE_CHARS);
1167   if (!searchkey)
1168     {
1169       err = gpg_error_from_syserror ();
1170       goto leave;
1171     }
1172
1173   reselect = 0;
1174  again:
1175   /* Build the request string.  */
1176   xfree (hostport);
1177   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1178                              reselect, &httpflags);
1179   if (!hostport)
1180     {
1181       err = gpg_error_from_syserror ();
1182       goto leave;
1183     }
1184
1185   xfree (request);
1186   request = strconcat (hostport,
1187                        "/pks/lookup?op=get&options=mr&search=",
1188                        searchkey,
1189                        exactname? "&exact=on":"",
1190                        NULL);
1191   if (!request)
1192     {
1193       err = gpg_error_from_syserror ();
1194       goto leave;
1195     }
1196
1197   /* Send the request.  */
1198   err = send_request (ctrl, request, hostport, httpflags, NULL, NULL, &fp);
1199   if (handle_send_request_error (err, request, &tries))
1200     {
1201       reselect = 1;
1202       goto again;
1203     }
1204   if (err)
1205     goto leave;
1206
1207   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1208   if (err)
1209     goto leave;
1210
1211   /* Return the read stream and close the HTTP context.  */
1212   *r_fp = fp;
1213   fp = NULL;
1214
1215  leave:
1216   es_fclose (fp);
1217   xfree (request);
1218   xfree (hostport);
1219   xfree (searchkey);
1220   return err;
1221 }
1222
1223
1224
1225 \f
1226 /* Callback parameters for put_post_cb.  */
1227 struct put_post_parm_s
1228 {
1229   char *datastring;
1230 };
1231
1232
1233 /* Helper for ks_hkp_put.  */
1234 static gpg_error_t
1235 put_post_cb (void *opaque, http_t http)
1236 {
1237   struct put_post_parm_s *parm = opaque;
1238   gpg_error_t err = 0;
1239   estream_t fp;
1240   size_t len;
1241
1242   fp = http_get_write_ptr (http);
1243   len = strlen (parm->datastring);
1244
1245   es_fprintf (fp,
1246               "Content-Type: application/x-www-form-urlencoded\r\n"
1247               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1248   http_start_data (http);
1249   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1250     err = gpg_error_from_syserror ();
1251   return err;
1252 }
1253
1254
1255 /* Send the key in {DATA,DATALEN} to the keyserver identified by  URI.  */
1256 gpg_error_t
1257 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1258 {
1259   gpg_error_t err;
1260   char *hostport = NULL;
1261   char *request = NULL;
1262   estream_t fp = NULL;
1263   struct put_post_parm_s parm;
1264   char *armored = NULL;
1265   int reselect;
1266   unsigned int httpflags;
1267   unsigned int tries = SEND_REQUEST_RETRIES;
1268
1269   parm.datastring = NULL;
1270
1271   err = armor_data (&armored, data, datalen);
1272   if (err)
1273     goto leave;
1274
1275   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1276   if (!parm.datastring)
1277     {
1278       err = gpg_error_from_syserror ();
1279       goto leave;
1280     }
1281   xfree (armored);
1282   armored = NULL;
1283
1284   /* Build the request string.  */
1285   reselect = 0;
1286  again:
1287   xfree (hostport);
1288   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1289                              reselect, &httpflags);
1290   if (!hostport)
1291     {
1292       err = gpg_error_from_syserror ();
1293       goto leave;
1294     }
1295
1296   xfree (request);
1297   request = strconcat (hostport, "/pks/add", NULL);
1298   if (!request)
1299     {
1300       err = gpg_error_from_syserror ();
1301       goto leave;
1302     }
1303
1304   /* Send the request.  */
1305   err = send_request (ctrl, request, hostport, 0, put_post_cb, &parm, &fp);
1306   if (handle_send_request_error (err, request, &tries))
1307     {
1308       reselect = 1;
1309       goto again;
1310     }
1311   if (err)
1312     goto leave;
1313
1314  leave:
1315   es_fclose (fp);
1316   xfree (parm.datastring);
1317   xfree (armored);
1318   xfree (request);
1319   xfree (hostport);
1320   return err;
1321 }