dirmngr: Add support for hkps keyservers.
[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                    /* fixme: AUTH */ NULL,
769                    httpflags,
770                    /* fixme: proxy*/ NULL,
771                    session,
772                    NULL,
773                    /*FIXME curl->srvtag*/NULL);
774   if (!err)
775     {
776       fp = http_get_write_ptr (http);
777       /* Avoid caches to get the most recent copy of the key.  We set
778          both the Pragma and Cache-Control versions of the header, so
779          we're good with both HTTP 1.0 and 1.1.  */
780       es_fputs ("Pragma: no-cache\r\n"
781                 "Cache-Control: no-cache\r\n", fp);
782       if (post_cb)
783         err = post_cb (post_cb_value, http);
784       if (!err)
785         {
786           http_start_data (http);
787           if (es_ferror (fp))
788             err = gpg_error_from_syserror ();
789         }
790     }
791   if (err)
792     {
793       /* Fixme: After a redirection we show the old host name.  */
794       log_error (_("error connecting to '%s': %s\n"),
795                  hostportstr, gpg_strerror (err));
796       goto leave;
797     }
798
799   /* Wait for the response.  */
800   dirmngr_tick (ctrl);
801   err = http_wait_response (http);
802   if (err)
803     {
804       log_error (_("error reading HTTP response for '%s': %s\n"),
805                  hostportstr, gpg_strerror (err));
806       goto leave;
807     }
808
809   if (http_get_tls_info (http, NULL))
810     {
811       /* Update the httpflags so that a redirect won't fallback to an
812          unencrypted connection.  */
813       httpflags |= HTTP_FLAG_FORCE_TLS;
814     }
815
816   switch (http_get_status_code (http))
817     {
818     case 200:
819       err = 0;
820       break; /* Success.  */
821
822     case 301:
823     case 302:
824     case 307:
825       {
826         const char *s = http_get_header (http, "Location");
827
828         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
829                   request, s?s:"[none]", http_get_status_code (http));
830         if (s && *s && redirects_left-- )
831           {
832             xfree (request_buffer);
833             request_buffer = xtrystrdup (s);
834             if (request_buffer)
835               {
836                 request = request_buffer;
837                 http_close (http, 0);
838                 http = NULL;
839                 goto once_more;
840               }
841             err = gpg_error_from_syserror ();
842           }
843         else
844           err = gpg_error (GPG_ERR_NO_DATA);
845         log_error (_("too many redirections\n"));
846       }
847       goto leave;
848
849     default:
850       log_error (_("error accessing '%s': http status %u\n"),
851                  request, http_get_status_code (http));
852       err = gpg_error (GPG_ERR_NO_DATA);
853       goto leave;
854     }
855
856   /* FIXME: We should register a permanent redirection and whether a
857      host has ever used TLS so that future calls will always use
858      TLS. */
859
860   fp = http_get_read_ptr (http);
861   if (!fp)
862     {
863       err = gpg_error (GPG_ERR_BUG);
864       goto leave;
865     }
866
867   /* Return the read stream and close the HTTP context.  */
868   *r_fp = fp;
869   http_close (http, 1);
870   http = NULL;
871
872  leave:
873   http_close (http, 0);
874   http_session_release (session);
875   xfree (request_buffer);
876   return err;
877 }
878
879
880 /* Helper to evaluate the error code ERR form a send_request() call
881    with REQUEST.  The function returns true if the caller shall try
882    again.  TRIES_LEFT points to a variable to track the number of
883    retries; this function decrements it and won't return true if it is
884    down to zero. */
885 static int
886 handle_send_request_error (gpg_error_t err, const char *request,
887                            unsigned int *tries_left)
888 {
889   int retry = 0;
890
891   switch (gpg_err_code (err))
892     {
893     case GPG_ERR_ECONNREFUSED:
894     case GPG_ERR_ENETUNREACH:
895       if (mark_host_dead (request) && *tries_left)
896         retry = 1;
897       break;
898
899     case GPG_ERR_ETIMEDOUT:
900       if (*tries_left)
901         {
902           log_info ("selecting a different host due to a timeout\n");
903           retry = 1;
904         }
905
906     default:
907       break;
908     }
909
910   if (*tries_left)
911     --*tries_left;
912
913   return retry;
914 }
915
916 static gpg_error_t
917 armor_data (char **r_string, const void *data, size_t datalen)
918 {
919   gpg_error_t err;
920   struct b64state b64state;
921   estream_t fp;
922   long length;
923   char *buffer;
924   size_t nread;
925
926   *r_string = NULL;
927
928   fp = es_fopenmem (0, "rw");
929   if (!fp)
930     return gpg_error_from_syserror ();
931
932   if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
933       || (err=b64enc_write (&b64state, data, datalen))
934       || (err = b64enc_finish (&b64state)))
935     {
936       es_fclose (fp);
937       return err;
938     }
939
940   /* FIXME: To avoid the extra buffer allocation estream should
941      provide a function to snatch the internal allocated memory from
942      such a memory stream.  */
943   length = es_ftell (fp);
944   if (length < 0)
945     {
946       err = gpg_error_from_syserror ();
947       es_fclose (fp);
948       return err;
949     }
950
951   buffer = xtrymalloc (length+1);
952   if (!buffer)
953     {
954       err = gpg_error_from_syserror ();
955       es_fclose (fp);
956       return err;
957     }
958
959   es_rewind (fp);
960   if (es_read (fp, buffer, length, &nread))
961     {
962       err = gpg_error_from_syserror ();
963       es_fclose (fp);
964       return err;
965     }
966   buffer[nread] = 0;
967   es_fclose (fp);
968
969   *r_string = buffer;
970   return 0;
971 }
972
973
974 \f
975 /* Search the keyserver identified by URI for keys matching PATTERN.
976    On success R_FP has an open stream to read the data.  */
977 gpg_error_t
978 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
979                estream_t *r_fp)
980 {
981   gpg_error_t err;
982   KEYDB_SEARCH_DESC desc;
983   char fprbuf[2+40+1];
984   char *hostport = NULL;
985   char *request = NULL;
986   estream_t fp = NULL;
987   int reselect;
988   unsigned int httpflags;
989   unsigned int tries = SEND_REQUEST_RETRIES;
990
991   *r_fp = NULL;
992
993   /* Remove search type indicator and adjust PATTERN accordingly.
994      Note that HKP keyservers like the 0x to be present when searching
995      by keyid.  We need to re-format the fingerprint and keyids so to
996      remove the gpg specific force-use-of-this-key flag ("!").  */
997   err = classify_user_id (pattern, &desc, 1);
998   if (err)
999     return err;
1000   switch (desc.mode)
1001     {
1002     case KEYDB_SEARCH_MODE_EXACT:
1003     case KEYDB_SEARCH_MODE_SUBSTR:
1004     case KEYDB_SEARCH_MODE_MAIL:
1005     case KEYDB_SEARCH_MODE_MAILSUB:
1006       pattern = desc.u.name;
1007       break;
1008     case KEYDB_SEARCH_MODE_SHORT_KID:
1009       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1010       pattern = fprbuf;
1011       break;
1012     case KEYDB_SEARCH_MODE_LONG_KID:
1013       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1014                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1015       pattern = fprbuf;
1016       break;
1017     case KEYDB_SEARCH_MODE_FPR16:
1018       bin2hex (desc.u.fpr, 16, fprbuf);
1019       pattern = fprbuf;
1020       break;
1021     case KEYDB_SEARCH_MODE_FPR20:
1022     case KEYDB_SEARCH_MODE_FPR:
1023       bin2hex (desc.u.fpr, 20, fprbuf);
1024       pattern = fprbuf;
1025       break;
1026     default:
1027       return gpg_error (GPG_ERR_INV_USER_ID);
1028     }
1029
1030   /* Build the request string.  */
1031   reselect = 0;
1032  again:
1033   {
1034     char *searchkey;
1035
1036     xfree (hostport);
1037     hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1038                                reselect, &httpflags);
1039     if (!hostport)
1040       {
1041         err = gpg_error_from_syserror ();
1042         goto leave;
1043       }
1044
1045     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1046     if (!searchkey)
1047       {
1048         err = gpg_error_from_syserror ();
1049         goto leave;
1050       }
1051
1052     xfree (request);
1053     request = strconcat (hostport,
1054                          "/pks/lookup?op=index&options=mr&search=",
1055                          searchkey,
1056                          NULL);
1057     xfree (searchkey);
1058     if (!request)
1059       {
1060         err = gpg_error_from_syserror ();
1061         goto leave;
1062       }
1063   }
1064
1065   /* Send the request.  */
1066   err = send_request (ctrl, request, hostport, httpflags, NULL, NULL, &fp);
1067   if (handle_send_request_error (err, request, &tries))
1068     {
1069       reselect = 1;
1070       goto again;
1071     }
1072   if (err)
1073     goto leave;
1074
1075   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1076   if (err)
1077     goto leave;
1078
1079   /* Peek at the response.  */
1080   {
1081     int c = es_getc (fp);
1082     if (c == -1)
1083       {
1084         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1085         log_error ("error reading response: %s\n", gpg_strerror (err));
1086         goto leave;
1087       }
1088     if (c == '<')
1089       {
1090         /* The document begins with a '<': Assume a HTML response,
1091            which we don't support.  */
1092         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1093         goto leave;
1094       }
1095     es_ungetc (c, fp);
1096   }
1097
1098   /* Return the read stream.  */
1099   *r_fp = fp;
1100   fp = NULL;
1101
1102  leave:
1103   es_fclose (fp);
1104   xfree (request);
1105   xfree (hostport);
1106   return err;
1107 }
1108
1109
1110 /* Get the key described key the KEYSPEC string from the keyserver
1111    identified by URI.  On success R_FP has an open stream to read the
1112    data.  */
1113 gpg_error_t
1114 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1115 {
1116   gpg_error_t err;
1117   KEYDB_SEARCH_DESC desc;
1118   char kidbuf[2+40+1];
1119   const char *exactname = NULL;
1120   char *searchkey = NULL;
1121   char *hostport = NULL;
1122   char *request = NULL;
1123   estream_t fp = NULL;
1124   int reselect;
1125   unsigned int httpflags;
1126   unsigned int tries = SEND_REQUEST_RETRIES;
1127
1128   *r_fp = NULL;
1129
1130   /* Remove search type indicator and adjust PATTERN accordingly.
1131      Note that HKP keyservers like the 0x to be present when searching
1132      by keyid.  We need to re-format the fingerprint and keyids so to
1133      remove the gpg specific force-use-of-this-key flag ("!").  */
1134   err = classify_user_id (keyspec, &desc, 1);
1135   if (err)
1136     return err;
1137   switch (desc.mode)
1138     {
1139     case KEYDB_SEARCH_MODE_SHORT_KID:
1140       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1141       break;
1142     case KEYDB_SEARCH_MODE_LONG_KID:
1143       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1144                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1145       break;
1146     case KEYDB_SEARCH_MODE_FPR20:
1147     case KEYDB_SEARCH_MODE_FPR:
1148       /* This is a v4 fingerprint. */
1149       kidbuf[0] = '0';
1150       kidbuf[1] = 'x';
1151       bin2hex (desc.u.fpr, 20, kidbuf+2);
1152       break;
1153
1154     case KEYDB_SEARCH_MODE_EXACT:
1155       exactname = desc.u.name;
1156       break;
1157
1158     case KEYDB_SEARCH_MODE_FPR16:
1159       log_error ("HKP keyservers do not support v3 fingerprints\n");
1160     default:
1161       return gpg_error (GPG_ERR_INV_USER_ID);
1162     }
1163
1164   searchkey = http_escape_string (exactname? exactname : kidbuf,
1165                                   EXTRA_ESCAPE_CHARS);
1166   if (!searchkey)
1167     {
1168       err = gpg_error_from_syserror ();
1169       goto leave;
1170     }
1171
1172   reselect = 0;
1173  again:
1174   /* Build the request string.  */
1175   xfree (hostport);
1176   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1177                              reselect, &httpflags);
1178   if (!hostport)
1179     {
1180       err = gpg_error_from_syserror ();
1181       goto leave;
1182     }
1183
1184   xfree (request);
1185   request = strconcat (hostport,
1186                        "/pks/lookup?op=get&options=mr&search=",
1187                        searchkey,
1188                        exactname? "&exact=on":"",
1189                        NULL);
1190   if (!request)
1191     {
1192       err = gpg_error_from_syserror ();
1193       goto leave;
1194     }
1195
1196   /* Send the request.  */
1197   err = send_request (ctrl, request, hostport, httpflags, NULL, NULL, &fp);
1198   if (handle_send_request_error (err, request, &tries))
1199     {
1200       reselect = 1;
1201       goto again;
1202     }
1203   if (err)
1204     goto leave;
1205
1206   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1207   if (err)
1208     goto leave;
1209
1210   /* Return the read stream and close the HTTP context.  */
1211   *r_fp = fp;
1212   fp = NULL;
1213
1214  leave:
1215   es_fclose (fp);
1216   xfree (request);
1217   xfree (hostport);
1218   xfree (searchkey);
1219   return err;
1220 }
1221
1222
1223
1224 \f
1225 /* Callback parameters for put_post_cb.  */
1226 struct put_post_parm_s
1227 {
1228   char *datastring;
1229 };
1230
1231
1232 /* Helper for ks_hkp_put.  */
1233 static gpg_error_t
1234 put_post_cb (void *opaque, http_t http)
1235 {
1236   struct put_post_parm_s *parm = opaque;
1237   gpg_error_t err = 0;
1238   estream_t fp;
1239   size_t len;
1240
1241   fp = http_get_write_ptr (http);
1242   len = strlen (parm->datastring);
1243
1244   es_fprintf (fp,
1245               "Content-Type: application/x-www-form-urlencoded\r\n"
1246               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1247   http_start_data (http);
1248   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1249     err = gpg_error_from_syserror ();
1250   return err;
1251 }
1252
1253
1254 /* Send the key in {DATA,DATALEN} to the keyserver identified by  URI.  */
1255 gpg_error_t
1256 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1257 {
1258   gpg_error_t err;
1259   char *hostport = NULL;
1260   char *request = NULL;
1261   estream_t fp = NULL;
1262   struct put_post_parm_s parm;
1263   char *armored = NULL;
1264   int reselect;
1265   unsigned int httpflags;
1266   unsigned int tries = SEND_REQUEST_RETRIES;
1267
1268   parm.datastring = NULL;
1269
1270   err = armor_data (&armored, data, datalen);
1271   if (err)
1272     goto leave;
1273
1274   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1275   if (!parm.datastring)
1276     {
1277       err = gpg_error_from_syserror ();
1278       goto leave;
1279     }
1280   xfree (armored);
1281   armored = NULL;
1282
1283   /* Build the request string.  */
1284   reselect = 0;
1285  again:
1286   xfree (hostport);
1287   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1288                              reselect, &httpflags);
1289   if (!hostport)
1290     {
1291       err = gpg_error_from_syserror ();
1292       goto leave;
1293     }
1294
1295   xfree (request);
1296   request = strconcat (hostport, "/pks/add", NULL);
1297   if (!request)
1298     {
1299       err = gpg_error_from_syserror ();
1300       goto leave;
1301     }
1302
1303   /* Send the request.  */
1304   err = send_request (ctrl, request, hostport, 0, put_post_cb, &parm, &fp);
1305   if (handle_send_request_error (err, request, &tries))
1306     {
1307       reselect = 1;
1308       goto again;
1309     }
1310   if (err)
1311     goto leave;
1312
1313  leave:
1314   es_fclose (fp);
1315   xfree (parm.datastring);
1316   xfree (armored);
1317   xfree (request);
1318   xfree (hostport);
1319   return err;
1320 }