g10: Fix memory leak.
[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 <https://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 "../common/userids.h"
41 #include "dns-stuff.h"
42 #include "ks-engine.h"
43
44 /* Substitutes for missing Mingw macro.  The EAI_SYSTEM mechanism
45    seems not to be available (probably because there is only one set
46    of error codes anyway).  For now we use WSAEINVAL. */
47 #ifndef EAI_OVERFLOW
48 # define EAI_OVERFLOW EAI_FAIL
49 #endif
50 #ifdef HAVE_W32_SYSTEM
51 # ifndef EAI_SYSTEM
52 #  define EAI_SYSTEM WSAEINVAL
53 # endif
54 #endif
55
56
57 /* Number of seconds after a host is marked as resurrected.  */
58 #define RESURRECT_INTERVAL  (3600+1800)  /* 1.5 hours */
59
60 /* To match the behaviour of our old gpgkeys helper code we escape
61    more characters than actually needed. */
62 #define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
63
64 /* How many redirections do we allow.  */
65 #define MAX_REDIRECTS 2
66
67 /* Number of retries done for a dead host etc.  */
68 #define SEND_REQUEST_RETRIES 3
69
70 enum ks_protocol { KS_PROTOCOL_HKP, KS_PROTOCOL_HKPS, KS_PROTOCOL_MAX };
71
72 /* Objects used to maintain information about hosts.  */
73 struct hostinfo_s;
74 typedef struct hostinfo_s *hostinfo_t;
75 struct hostinfo_s
76 {
77   time_t lastfail;   /* Time we tried to connect and failed.  */
78   time_t lastused;   /* Time of last use.  */
79   int *pool;         /* An array with indices into HOSTTABLE or NULL
80                         if NAME is not a pool name.  */
81   size_t pool_len;   /* Length of POOL.  */
82   size_t pool_size;  /* Allocated size of POOL.  */
83 #define MAX_POOL_SIZE   128
84   int poolidx;       /* Index into POOL with the used host.  -1 if not set.  */
85   unsigned int v4:1; /* Host supports AF_INET.  */
86   unsigned int v6:1; /* Host supports AF_INET6.  */
87   unsigned int onion:1;/* NAME is an onion (Tor HS) address.  */
88   unsigned int dead:1; /* Host is currently unresponsive.  */
89   unsigned int iporname_valid:1;  /* The field IPORNAME below is valid */
90                                   /* (but may be NULL) */
91   unsigned int did_a_lookup:1;    /* Have we done an A lookup yet?  */
92   unsigned int did_srv_lookup:2;  /* One bit per protocol indicating
93                                      whether we already did a SRV
94                                      lookup.  */
95   time_t died_at;    /* The time the host was marked dead.  If this is
96                         0 the host has been manually marked dead.  */
97   char *cname;       /* Canonical name of the host.  Only set if this
98                         is a pool or NAME has a numerical IP address.  */
99   char *iporname;    /* Numeric IP address or name for printing.  */
100   unsigned short port[KS_PROTOCOL_MAX];
101                      /* The port used by the host for all protocols, 0
102                         if unknown.  */
103   char name[1];      /* The hostname.  */
104 };
105
106
107 /* An array of hostinfo_t for all hosts requested by the caller or
108    resolved from a pool name and its allocated size.*/
109 static hostinfo_t *hosttable;
110 static int hosttable_size;
111
112 /* The number of host slots we initially allocate for HOSTTABLE.  */
113 #define INITIAL_HOSTTABLE_SIZE 50
114
115
116 /* Create a new hostinfo object, fill in NAME and put it into
117    HOSTTABLE.  Return the index into hosttable on success or -1 on
118    error. */
119 static int
120 create_new_hostinfo (const char *name)
121 {
122   hostinfo_t hi, *newtable;
123   int newsize;
124   int idx, rc;
125
126   hi = xtrymalloc (sizeof *hi + strlen (name));
127   if (!hi)
128     return -1;
129   strcpy (hi->name, name);
130   hi->pool = NULL;
131   hi->pool_len = 0;
132   hi->pool_size = 0;
133   hi->poolidx = -1;
134   hi->lastused = (time_t)(-1);
135   hi->lastfail = (time_t)(-1);
136   hi->v4 = 0;
137   hi->v6 = 0;
138   hi->onion = 0;
139   hi->dead = 0;
140   hi->did_a_lookup = 0;
141   hi->did_srv_lookup = 0;
142   hi->iporname_valid = 0;
143   hi->died_at = 0;
144   hi->cname = NULL;
145   hi->iporname = NULL;
146   hi->port[KS_PROTOCOL_HKP] = 0;
147   hi->port[KS_PROTOCOL_HKPS] = 0;
148
149   /* Add it to the hosttable. */
150   for (idx=0; idx < hosttable_size; idx++)
151     if (!hosttable[idx])
152       {
153         hosttable[idx] = hi;
154         return idx;
155       }
156   /* Need to extend the hosttable.  */
157   newsize = hosttable_size + INITIAL_HOSTTABLE_SIZE;
158   newtable = xtryrealloc (hosttable, newsize * sizeof *hosttable);
159   if (!newtable)
160     {
161       xfree (hi);
162       return -1;
163     }
164   hosttable = newtable;
165   idx = hosttable_size;
166   hosttable_size = newsize;
167   rc = idx;
168   hosttable[idx++] = hi;
169   while (idx < hosttable_size)
170     hosttable[idx++] = NULL;
171
172   return rc;
173 }
174
175
176 /* Find the host NAME in our table.  Return the index into the
177    hosttable or -1 if not found.  */
178 static int
179 find_hostinfo (const char *name)
180 {
181   int idx;
182
183   for (idx=0; idx < hosttable_size; idx++)
184     if (hosttable[idx] && !ascii_strcasecmp (hosttable[idx]->name, name))
185       return idx;
186   return -1;
187 }
188
189
190 static int
191 sort_hostpool (const void *xa, const void *xb)
192 {
193   int a = *(int *)xa;
194   int b = *(int *)xb;
195
196   assert (a >= 0 && a < hosttable_size);
197   assert (b >= 0 && b < hosttable_size);
198   assert (hosttable[a]);
199   assert (hosttable[b]);
200
201   return ascii_strcasecmp (hosttable[a]->name, hosttable[b]->name);
202 }
203
204
205 /* Return true if the host with the hosttable index TBLIDX is in HI->pool.  */
206 static int
207 host_in_pool_p (hostinfo_t hi, int tblidx)
208 {
209   int i, pidx;
210
211   for (i = 0; i < hi->pool_len && (pidx = hi->pool[i]) != -1; i++)
212     if (pidx == tblidx && hosttable[pidx])
213       return 1;
214   return 0;
215 }
216
217
218 /* Select a random host.  Consult HI->pool which indices into the global
219    hosttable.  Returns index into HI->pool or -1 if no host could be
220    selected.  */
221 static int
222 select_random_host (hostinfo_t hi)
223 {
224   int *tbl;
225   size_t tblsize;
226   int pidx, idx;
227
228   /* We create a new table so that we randomly select only from
229      currently alive hosts.  */
230   for (idx = 0, tblsize = 0;
231        idx < hi->pool_len && (pidx = hi->pool[idx]) != -1;
232        idx++)
233     if (hosttable[pidx] && !hosttable[pidx]->dead)
234       tblsize++;
235   if (!tblsize)
236     return -1; /* No hosts.  */
237
238   tbl = xtrymalloc (tblsize * sizeof *tbl);
239   if (!tbl)
240     return -1;
241   for (idx = 0, tblsize = 0;
242        idx < hi->pool_len && (pidx = hi->pool[idx]) != -1;
243        idx++)
244     if (hosttable[pidx] && !hosttable[pidx]->dead)
245       tbl[tblsize++] = pidx;
246
247   if (tblsize == 1)  /* Save a get_uint_nonce.  */
248     pidx = tbl[0];
249   else
250     pidx = tbl[get_uint_nonce () % tblsize];
251
252   xfree (tbl);
253   return pidx;
254 }
255
256
257 /* Figure out if a set of DNS records looks like a pool.  */
258 static int
259 arecords_is_pool (dns_addrinfo_t aibuf)
260 {
261   dns_addrinfo_t ai;
262   int n_v6, n_v4;
263
264   n_v6 = n_v4 = 0;
265   for (ai = aibuf; ai; ai = ai->next)
266     {
267       if (ai->family == AF_INET6)
268         n_v6++;
269       else if (ai->family == AF_INET)
270         n_v4++;
271     }
272
273   return n_v6 > 1 || n_v4 > 1;
274 }
275
276
277 /* Print a warning iff Tor is not running but Tor has been requested.
278  * Also return true if it is not running.  */
279 static int
280 tor_not_running_p (ctrl_t ctrl)
281 {
282   assuan_fd_t sock;
283
284   if (!dirmngr_use_tor ())
285     return 0;
286
287   sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
288   if (sock != ASSUAN_INVALID_FD)
289     {
290       assuan_sock_close (sock);
291       return 0;
292     }
293
294   log_info ("(it seems Tor is not running)\n");
295   dirmngr_status (ctrl, "WARNING", "tor_not_running 0",
296                   "Tor is enabled but the local Tor daemon"
297                   " seems to be down", NULL);
298   return 1;
299 }
300
301
302 /* Add the host AI under the NAME into the HOSTTABLE.  If PORT is not
303    zero, it specifies which port to use to talk to the host for
304    PROTOCOL.  If NAME specifies a pool (as indicated by IS_POOL),
305    update the given reference table accordingly.  */
306 static void
307 add_host (ctrl_t ctrl, const char *name, int is_pool,
308           const dns_addrinfo_t ai,
309           enum ks_protocol protocol, unsigned short port)
310 {
311   gpg_error_t tmperr;
312   char *tmphost;
313   int idx, tmpidx;
314   hostinfo_t host;
315   int i;
316
317   idx = find_hostinfo (name);
318   host = hosttable[idx];
319
320   if (is_pool)
321     {
322       /* For a pool immediately convert the address to a string.  */
323       tmperr = resolve_dns_addr (ctrl, ai->addr, ai->addrlen,
324                                  (DNS_NUMERICHOST | DNS_WITHBRACKET), &tmphost);
325     }
326   else if (!is_ip_address (name))
327     {
328       /* This is a hostname.  Use the name as given without going
329        * through resolve_dns_addr.  */
330       tmphost = xtrystrdup (name);
331       if (!tmphost)
332         tmperr = gpg_error_from_syserror ();
333       else
334         tmperr = 0;
335     }
336   else
337     {
338       /* Do a PTR lookup on AI.  If a name was not found the function
339        * returns the numeric address (with brackets).  */
340       tmperr = resolve_dns_addr (ctrl, ai->addr, ai->addrlen,
341                                  DNS_WITHBRACKET, &tmphost);
342     }
343
344   if (tmperr)
345     {
346       log_info ("resolve_dns_addr failed while checking '%s': %s\n",
347                 name, gpg_strerror (tmperr));
348     }
349   else if (host->pool_len + 1 >= MAX_POOL_SIZE)
350     {
351       log_error ("resolve_dns_addr for '%s': '%s'"
352                  " [index table full - ignored]\n", name, tmphost);
353     }
354   else
355     {
356       if (!is_pool && is_ip_address (name))
357         /* Update the original entry.  */
358         tmpidx = idx;
359       else
360         tmpidx = find_hostinfo (tmphost);
361       log_info ("resolve_dns_addr for '%s': '%s'%s\n",
362                 name, tmphost,
363                 tmpidx == -1? "" : " [already known]");
364
365       if (tmpidx == -1) /* Create a new entry.  */
366         tmpidx = create_new_hostinfo (tmphost);
367
368       if (tmpidx == -1)
369         {
370           log_error ("map_host for '%s' problem: %s - '%s' [ignored]\n",
371                      name, strerror (errno), tmphost);
372         }
373       else  /* Set or update the entry. */
374         {
375           if (port)
376             hosttable[tmpidx]->port[protocol] = port;
377
378           if (ai->family == AF_INET6)
379             {
380               hosttable[tmpidx]->v6 = 1;
381             }
382           else if (ai->family == AF_INET)
383             {
384               hosttable[tmpidx]->v4 = 1;
385             }
386           else
387             BUG ();
388
389           /* If we updated the main entry, we're done.  */
390           if (idx == tmpidx)
391             goto leave;
392
393           /* If we updated an existing entry, we're done.  */
394           for (i = 0; i < host->pool_len; i++)
395             if (host->pool[i] == tmpidx)
396               goto leave;
397
398           /* Otherwise, we need to add it to the pool.  Check if there
399              is space.  */
400           if (host->pool_len + 1 > host->pool_size)
401             {
402               int *new_pool;
403               size_t new_size;
404
405               if (host->pool_size == 0)
406                 new_size = 4;
407               else
408                 new_size = host->pool_size * 2;
409
410               new_pool = xtryrealloc (host->pool,
411                                       new_size * sizeof *new_pool);
412
413               if (new_pool == NULL)
414                 goto leave;
415
416               host->pool = new_pool;
417               host->pool_size = new_size;
418             }
419
420           /* Finally, add it.  */
421           log_assert (host->pool_len < host->pool_size);
422           host->pool[host->pool_len++] = tmpidx;
423         }
424     }
425  leave:
426   xfree (tmphost);
427 }
428
429
430 /* Sort the pool of the given hostinfo HI.  */
431 static void
432 hostinfo_sort_pool (hostinfo_t hi)
433 {
434   qsort (hi->pool, hi->pool_len, sizeof *hi->pool, sort_hostpool);
435 }
436
437 /* Map the host name NAME to the actual to be used host name.  This
438  * allows us to manage round robin DNS names.  We use our own strategy
439  * to choose one of the hosts.  For example we skip those hosts which
440  * failed for some time and we stick to one host for a time
441  * independent of DNS retry times.  If FORCE_RESELECT is true a new
442  * host is always selected.  If SRVTAG is NULL no service record
443  * lookup will be done, if it is set that service name is used.  The
444  * selected host is stored as a malloced string at R_HOST; on error
445  * NULL is stored.  If we know the port used by the selected host from
446  * a service record, a string representation is written to R_PORTSTR,
447  * otherwise it is left untouched.  If R_HTTPFLAGS is not NULL it will
448  * receive flags which are to be passed to http_open.  If R_HTTPHOST
449  * is not NULL a malloced name of the host is stored there; this might
450  * be different from R_HOST in case it has been selected from a
451  * pool.  */
452 static gpg_error_t
453 map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
454           enum ks_protocol protocol, char **r_host, char *r_portstr,
455           unsigned int *r_httpflags, char **r_httphost)
456 {
457   gpg_error_t err = 0;
458   hostinfo_t hi;
459   int idx;
460   dns_addrinfo_t aibuf, ai;
461   int is_pool;
462   int new_hosts = 0;
463   char *cname;
464
465   *r_host = NULL;
466   if (r_httpflags)
467     *r_httpflags = 0;
468   if (r_httphost)
469     *r_httphost = NULL;
470
471   /* No hostname means localhost.  */
472   if (!name || !*name)
473     {
474       *r_host = xtrystrdup ("localhost");
475       return *r_host? 0 : gpg_error_from_syserror ();
476     }
477
478   /* See whether the host is in our table.  */
479   idx = find_hostinfo (name);
480   if (idx == -1)
481     {
482       idx = create_new_hostinfo (name);
483       if (idx == -1)
484         return gpg_error_from_syserror ();
485       hi = hosttable[idx];
486       hi->onion = is_onion_address (name);
487     }
488   else
489     hi = hosttable[idx];
490
491   is_pool = hi->pool != NULL;
492
493   if (srvtag && !is_ip_address (name)
494       && ! hi->onion
495       && ! (hi->did_srv_lookup & 1 << protocol))
496     {
497       struct srventry *srvs;
498       unsigned int srvscount;
499
500       /* Check for SRV records.  */
501       err = get_dns_srv (ctrl, name, srvtag, NULL, &srvs, &srvscount);
502       if (err)
503         {
504           if (gpg_err_code (err) == GPG_ERR_ECONNREFUSED)
505             tor_not_running_p (ctrl);
506           return err;
507         }
508
509       if (srvscount > 0)
510         {
511           int i;
512           if (! is_pool)
513             is_pool = srvscount > 1;
514
515           for (i = 0; i < srvscount; i++)
516             {
517               err = resolve_dns_name (ctrl, srvs[i].target, 0,
518                                       AF_UNSPEC, SOCK_STREAM,
519                                       &ai, &cname);
520               if (err)
521                 continue;
522               dirmngr_tick (ctrl);
523               add_host (ctrl, name, is_pool, ai, protocol, srvs[i].port);
524               new_hosts = 1;
525             }
526
527           xfree (srvs);
528         }
529
530       hi->did_srv_lookup |= 1 << protocol;
531     }
532
533   if (! hi->did_a_lookup
534       && ! hi->onion)
535     {
536       /* Find all A records for this entry and put them into the pool
537          list - if any.  */
538       err = resolve_dns_name (ctrl, name, 0, 0, SOCK_STREAM, &aibuf, &cname);
539       if (err)
540         {
541           log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
542           err = 0;
543         }
544       else
545         {
546           /* First figure out whether this is a pool.  For a pool we
547              use a different strategy than for a plain server: We use
548              the canonical name of the pool as the virtual host along
549              with the IP addresses.  If it is not a pool, we use the
550              specified name. */
551           if (! is_pool)
552             is_pool = arecords_is_pool (aibuf);
553           if (is_pool && cname)
554             {
555               hi->cname = cname;
556               cname = NULL;
557             }
558
559           for (ai = aibuf; ai; ai = ai->next)
560             {
561               if (ai->family != AF_INET && ai->family != AF_INET6)
562                 continue;
563               if (opt.disable_ipv4 && ai->family == AF_INET)
564                 continue;
565               if (opt.disable_ipv6 && ai->family == AF_INET6)
566                 continue;
567               dirmngr_tick (ctrl);
568
569               add_host (ctrl, name, is_pool, ai, 0, 0);
570               new_hosts = 1;
571             }
572
573           hi->did_a_lookup = 1;
574         }
575       xfree (cname);
576       free_dns_addrinfo (aibuf);
577     }
578   if (new_hosts)
579     hostinfo_sort_pool (hi);
580
581   if (hi->pool)
582     {
583       /* Deal with the pool name before selecting a host. */
584       if (r_httphost)
585         {
586           *r_httphost = xtrystrdup (hi->name);
587           if (!*r_httphost)
588             return gpg_error_from_syserror ();
589         }
590
591       /* If the currently selected host is now marked dead, force a
592          re-selection .  */
593       if (force_reselect)
594         hi->poolidx = -1;
595       else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
596                && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead)
597         hi->poolidx = -1;
598
599       /* Select a host if needed.  */
600       if (hi->poolidx == -1)
601         {
602           hi->poolidx = select_random_host (hi);
603           if (hi->poolidx == -1)
604             {
605               log_error ("no alive host found in pool '%s'\n", name);
606               if (r_httphost)
607                 {
608                   xfree (*r_httphost);
609                   *r_httphost = NULL;
610                 }
611               return gpg_error (GPG_ERR_NO_KEYSERVER);
612             }
613         }
614
615       assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
616       hi = hosttable[hi->poolidx];
617       assert (hi);
618     }
619   else if (r_httphost && is_ip_address (hi->name))
620     {
621       /* This is a numerical IP address and not a pool.  We want to
622        * find the canonical name so that it can be used in the HTTP
623        * Host header.  Fixme: We should store that name in the
624        * hosttable. */
625       char *host;
626
627       err = resolve_dns_name (ctrl, hi->name, 0, 0, SOCK_STREAM, &aibuf, NULL);
628       if (!err)
629         {
630           for (ai = aibuf; ai; ai = ai->next)
631             {
632               if ((!opt.disable_ipv6 && ai->family == AF_INET6)
633                   || (!opt.disable_ipv4 && ai->family == AF_INET))
634                 {
635                   err = resolve_dns_addr (ctrl,
636                                           ai->addr, ai->addrlen, 0, &host);
637                   if (!err)
638                     {
639                       /* Okay, we return the first found name.  */
640                       *r_httphost = host;
641                       break;
642                     }
643                 }
644             }
645         }
646       free_dns_addrinfo (aibuf);
647     }
648
649   if (hi->dead)
650     {
651       log_error ("host '%s' marked as dead\n", hi->name);
652       if (r_httphost)
653         {
654           xfree (*r_httphost);
655           *r_httphost = NULL;
656         }
657       return gpg_error (GPG_ERR_NO_KEYSERVER);
658     }
659
660   if (r_httpflags)
661     {
662       /* If the hosttable does not indicate that a certain host
663          supports IPv<N>, we explicit set the corresponding http
664          flags.  The reason for this is that a host might be listed in
665          a pool as not v6 only but actually support v6 when later
666          the name is resolved by our http layer.  */
667       if (!hi->v4)
668         *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
669       if (!hi->v6)
670         *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
671
672       /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
673          addresses because the http module detects this itself.  This
674          also allows us to use an onion address without Tor mode being
675          enabled.  */
676     }
677
678   *r_host = xtrystrdup (hi->name);
679   if (!*r_host)
680     {
681       err = gpg_error_from_syserror ();
682       if (r_httphost)
683         {
684           xfree (*r_httphost);
685           *r_httphost = NULL;
686         }
687       return err;
688     }
689   if (hi->port[protocol])
690     snprintf (r_portstr, 6 /* five digits and the sentinel */,
691               "%hu", hi->port[protocol]);
692   return 0;
693 }
694
695
696 /* Mark the host NAME as dead.  NAME may be given as an URL.  Returns
697    true if a host was really marked as dead or was already marked dead
698    (e.g. by a concurrent session).  */
699 static int
700 mark_host_dead (const char *name)
701 {
702   const char *host;
703   char *host_buffer = NULL;
704   parsed_uri_t parsed_uri = NULL;
705   int done = 0;
706
707   if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
708     {
709       if (parsed_uri->v6lit)
710         {
711           host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
712           if (!host_buffer)
713             log_error ("out of core in mark_host_dead");
714           host = host_buffer;
715         }
716       else
717         host = parsed_uri->host;
718     }
719   else
720     host = name;
721
722   if (host && *host && strcmp (host, "localhost"))
723     {
724       hostinfo_t hi;
725       int idx;
726
727       idx = find_hostinfo (host);
728       if (idx != -1)
729         {
730           hi = hosttable[idx];
731           log_info ("marking host '%s' as dead%s\n",
732                     hi->name, hi->dead? " (again)":"");
733           hi->dead = 1;
734           hi->died_at = gnupg_get_time ();
735           if (!hi->died_at)
736             hi->died_at = 1;
737           done = 1;
738         }
739     }
740
741   http_release_parsed_uri (parsed_uri);
742   xfree (host_buffer);
743   return done;
744 }
745
746
747 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
748    alive.  */
749 gpg_error_t
750 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
751 {
752   gpg_error_t err = 0;
753   hostinfo_t hi, hi2;
754   int idx, idx2, idx3, n;
755
756   if (!name || !*name || !strcmp (name, "localhost"))
757     return 0;
758
759   idx = find_hostinfo (name);
760   if (idx == -1)
761     return gpg_error (GPG_ERR_NOT_FOUND);
762
763   hi = hosttable[idx];
764   if (alive && hi->dead)
765     {
766       hi->dead = 0;
767       err = ks_printf_help (ctrl, "marking '%s' as alive", name);
768     }
769   else if (!alive && !hi->dead)
770     {
771       hi->dead = 1;
772       hi->died_at = 0; /* Manually set dead.  */
773       err = ks_printf_help (ctrl, "marking '%s' as dead", name);
774     }
775
776   /* If the host is a pool mark all member hosts. */
777   if (!err && hi->pool)
778     {
779       for (idx2 = 0;
780            !err && idx2 < hi->pool_len && (n = hi->pool[idx2]) != -1;
781            idx2++)
782         {
783           assert (n >= 0 && n < hosttable_size);
784
785           if (!alive)
786             {
787               /* Do not mark a host from a pool dead if it is also a
788                  member in another pool.  */
789               for (idx3=0; idx3 < hosttable_size; idx3++)
790                 {
791                   if (hosttable[idx3]
792                       && hosttable[idx3]->pool
793                       && idx3 != idx
794                       && host_in_pool_p (hosttable[idx3], n))
795                     break;
796                 }
797               if (idx3 < hosttable_size)
798                 continue;  /* Host is also a member of another pool.  */
799             }
800
801           hi2 = hosttable[n];
802           if (!hi2)
803             ;
804           else if (alive && hi2->dead)
805             {
806               hi2->dead = 0;
807               err = ks_printf_help (ctrl, "marking '%s' as alive",
808                                     hi2->name);
809             }
810           else if (!alive && !hi2->dead)
811             {
812               hi2->dead = 1;
813               hi2->died_at = 0; /* Manually set dead. */
814               err = ks_printf_help (ctrl, "marking '%s' as dead",
815                                     hi2->name);
816             }
817         }
818     }
819
820   return err;
821 }
822
823
824 /* Debug function to print the entire hosttable.  */
825 gpg_error_t
826 ks_hkp_print_hosttable (ctrl_t ctrl)
827 {
828   gpg_error_t err;
829   int idx, idx2;
830   hostinfo_t hi;
831   membuf_t mb;
832   time_t curtime;
833   char *p, *died;
834   const char *diedstr;
835
836   err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
837   if (err)
838     return err;
839
840   /* FIXME: We need a lock for the hosttable.  */
841   curtime = gnupg_get_time ();
842   for (idx=0; idx < hosttable_size; idx++)
843     if ((hi=hosttable[idx]))
844       {
845         if (hi->dead && hi->died_at)
846           {
847             died = elapsed_time_string (hi->died_at, curtime);
848             diedstr = died? died : "error";
849           }
850         else
851           diedstr = died = NULL;
852
853         if (!hi->iporname_valid)
854           {
855             char *canon = NULL;
856
857             xfree (hi->iporname);
858             hi->iporname = NULL;
859
860             /* Do a lookup just for the display purpose.  */
861             if (hi->onion || hi->pool)
862               ;
863             else if (is_ip_address (hi->name))
864               {
865                 dns_addrinfo_t aibuf, ai;
866
867                 /* Turn the numerical IP address string into an AI and
868                  * then do a DNS PTR lookup.  */
869                 if (!resolve_dns_name (ctrl, hi->name, 0, 0,
870                                        SOCK_STREAM,
871                                        &aibuf, &canon))
872                   {
873                     if (canon && is_ip_address (canon))
874                       {
875                         xfree (canon);
876                         canon = NULL;
877                       }
878                     for (ai = aibuf; !canon && ai; ai = ai->next)
879                       {
880                         resolve_dns_addr (ctrl, ai->addr, ai->addrlen,
881                                           DNS_WITHBRACKET, &canon);
882                         if (canon && is_ip_address (canon))
883                           {
884                             /* We already have the numeric IP - no need to
885                              * display it a second time.  */
886                             xfree (canon);
887                             canon = NULL;
888                           }
889                       }
890                   }
891                 free_dns_addrinfo (aibuf);
892               }
893             else
894               {
895                 dns_addrinfo_t aibuf, ai;
896
897                 /* Get the IP address as a string from a name.  Note
898                  * that resolve_dns_addr allocates CANON on success
899                  * and thus terminates the loop. */
900                 if (!resolve_dns_name (ctrl, hi->name, 0,
901                                        hi->v6? AF_INET6 : AF_INET,
902                                        SOCK_STREAM,
903                                        &aibuf, NULL))
904                   {
905                     for (ai = aibuf; !canon && ai; ai = ai->next)
906                       {
907                         resolve_dns_addr (ctrl, ai->addr, ai->addrlen,
908                                           DNS_NUMERICHOST|DNS_WITHBRACKET,
909                                           &canon);
910                       }
911                   }
912                 free_dns_addrinfo (aibuf);
913               }
914
915             hi->iporname = canon;
916             hi->iporname_valid = 1;
917           }
918
919         err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s\n",
920                               idx,
921                               hi->onion? "O" : hi->v6? "6":" ",
922                               hi->v4? "4":" ",
923                               hi->dead? "d":" ",
924                               hi->name,
925                               hi->iporname? " (":"",
926                               hi->iporname? hi->iporname : "",
927                               hi->iporname? ")":"",
928                               diedstr? "  (":"",
929                               diedstr? diedstr:"",
930                               diedstr? ")":""   );
931         xfree (died);
932         if (err)
933           return err;
934
935         if (hi->cname)
936           err = ks_printf_help (ctrl, "  .       %s", hi->cname);
937         if (err)
938           return err;
939
940         if (hi->pool)
941           {
942             init_membuf (&mb, 256);
943             put_membuf_printf (&mb, "  .   -->");
944             for (idx2 = 0; idx2 < hi->pool_len && hi->pool[idx2] != -1; idx2++)
945               {
946                 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
947                 if (hi->poolidx == hi->pool[idx2])
948                   put_membuf_printf (&mb, "*");
949               }
950             put_membuf( &mb, "", 1);
951             p = get_membuf (&mb, NULL);
952             if (!p)
953               return gpg_error_from_syserror ();
954             err = ks_print_help (ctrl, p);
955             xfree (p);
956             if (err)
957               return err;
958           }
959       }
960   return 0;
961 }
962
963
964
965 /* Print a help output for the schemata supported by this module. */
966 gpg_error_t
967 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
968 {
969   const char data[] =
970     "Handler for HKP URLs:\n"
971     "  hkp://\n"
972 #if  HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
973     "  hkps://\n"
974 #endif
975     "Supported methods: search, get, put\n";
976   gpg_error_t err;
977
978 #if  HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
979   const char data2[] = "  hkp\n  hkps";
980 #else
981   const char data2[] = "  hkp";
982 #endif
983
984   if (!uri)
985     err = ks_print_help (ctrl, data2);
986   else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
987                             || !strcmp (uri->scheme, "hkps")))
988     err = ks_print_help (ctrl, data);
989   else
990     err = 0;
991
992   return err;
993 }
994
995
996 /* Build the remote part of the URL from SCHEME, HOST and an optional
997  * PORT.  If NO_SRV is set no SRV record lookup will be done.  Returns
998  * an allocated string at R_HOSTPORT or NULL on failure.  If
999  * R_HTTPHOST is not NULL it receives a malloced string with the
1000  * hostname; this may be different from HOST if HOST is selected from
1001  * a pool.  */
1002 static gpg_error_t
1003 make_host_part (ctrl_t ctrl,
1004                 const char *scheme, const char *host, unsigned short port,
1005                 int force_reselect, int no_srv,
1006                 char **r_hostport, unsigned int *r_httpflags, char **r_httphost)
1007 {
1008   gpg_error_t err;
1009   const char *srvtag;
1010   char portstr[10];
1011   char *hostname;
1012   enum ks_protocol protocol;
1013
1014   *r_hostport = NULL;
1015
1016   if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
1017     {
1018       scheme = "https";
1019       srvtag = no_srv? NULL : "pgpkey-https";
1020       protocol = KS_PROTOCOL_HKPS;
1021     }
1022   else /* HKP or HTTP.  */
1023     {
1024       scheme = "http";
1025       srvtag = no_srv? NULL : "pgpkey-http";
1026       protocol = KS_PROTOCOL_HKP;
1027     }
1028
1029   portstr[0] = 0;
1030   err = map_host (ctrl, host, srvtag, force_reselect, protocol,
1031                   &hostname, portstr, r_httpflags, r_httphost);
1032   if (err)
1033     return err;
1034
1035   /* If map_host did not return a port (from a SRV record) but a port
1036    * has been specified (implicitly or explicitly) then use that port.
1037    * In the case that a port was not specified (which is probably a
1038    * bug in https.c) we will set up defaults.  */
1039   if (*portstr)
1040     ;
1041   else if (!*portstr && port)
1042     snprintf (portstr, sizeof portstr, "%hu", port);
1043   else if (!strcmp (scheme,"https"))
1044     strcpy (portstr, "443");
1045   else
1046     strcpy (portstr, "11371");
1047
1048   if (*hostname != '[' && is_ip_address (hostname) == 6)
1049     *r_hostport = strconcat (scheme, "://[", hostname, "]:", portstr, NULL);
1050   else
1051     *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
1052   xfree (hostname);
1053   if (!*r_hostport)
1054     {
1055       if (r_httphost)
1056         {
1057           xfree (*r_httphost);
1058           *r_httphost = NULL;
1059         }
1060       return gpg_error_from_syserror ();
1061     }
1062   return 0;
1063 }
1064
1065
1066 /* Resolve all known keyserver names and update the hosttable.  This
1067    is mainly useful for debugging because the resolving is anyway done
1068    on demand.  */
1069 gpg_error_t
1070 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
1071 {
1072   gpg_error_t err;
1073   char *hostport = NULL;
1074
1075   /* NB: With an explicitly given port we do not want to consult a
1076    * service record because that might be in conflict with the port
1077    * from such a service record.  */
1078   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1079                         1, uri->explicit_port,
1080                         &hostport, NULL, NULL);
1081   if (err)
1082     {
1083       err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
1084                             uri->scheme, uri->host, uri->port,
1085                             gpg_strerror (err));
1086     }
1087   else
1088     {
1089       err = ks_printf_help (ctrl, "%s", hostport);
1090       xfree (hostport);
1091     }
1092   return err;
1093 }
1094
1095
1096 /* Housekeeping function called from the housekeeping thread.  It is
1097    used to mark dead hosts alive so that they may be tried again after
1098    some time.  */
1099 void
1100 ks_hkp_housekeeping (time_t curtime)
1101 {
1102   int idx;
1103   hostinfo_t hi;
1104
1105   for (idx=0; idx < hosttable_size; idx++)
1106     {
1107       hi = hosttable[idx];
1108       if (!hi)
1109         continue;
1110       if (!hi->dead)
1111         continue;
1112       if (!hi->died_at)
1113         continue; /* Do not resurrect manually shot hosts.  */
1114       if (hi->died_at + RESURRECT_INTERVAL <= curtime
1115           || hi->died_at > curtime)
1116         {
1117           hi->dead = 0;
1118           log_info ("resurrected host '%s'", hi->name);
1119         }
1120     }
1121 }
1122
1123
1124 /* Reload (SIGHUP) action for this module.  We mark all host alive
1125  * even those which have been manually shot.  */
1126 void
1127 ks_hkp_reload (void)
1128 {
1129   int idx, count;
1130   hostinfo_t hi;
1131
1132   for (idx=count=0; idx < hosttable_size; idx++)
1133     {
1134       hi = hosttable[idx];
1135       if (!hi)
1136         continue;
1137       hi->iporname_valid = 0;
1138       if (!hi->dead)
1139         continue;
1140       hi->dead = 0;
1141       count++;
1142     }
1143   if (count)
1144     log_info ("number of resurrected hosts: %d", count);
1145 }
1146
1147
1148 /* Send an HTTP request.  On success returns an estream object at
1149    R_FP.  HOSTPORTSTR is only used for diagnostics.  If HTTPHOST is
1150    not NULL it will be used as HTTP "Host" header.  If POST_CB is not
1151    NULL a post request is used and that callback is called to allow
1152    writing the post data.  If R_HTTP_STATUS is not NULL, the http
1153    status code will be stored there.  */
1154 static gpg_error_t
1155 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
1156               const char *httphost, unsigned int httpflags,
1157               gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
1158               estream_t *r_fp, unsigned int *r_http_status)
1159 {
1160   gpg_error_t err;
1161   http_session_t session = NULL;
1162   http_t http = NULL;
1163   int redirects_left = MAX_REDIRECTS;
1164   estream_t fp = NULL;
1165   char *request_buffer = NULL;
1166   parsed_uri_t uri = NULL;
1167   int is_onion;
1168
1169   *r_fp = NULL;
1170
1171   err = http_parse_uri (&uri, request, 0);
1172   if (err)
1173     goto leave;
1174   is_onion = uri->onion;
1175
1176   err = http_session_new (&session, httphost,
1177                           ((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0)
1178                            | HTTP_FLAG_TRUST_DEF),
1179                           gnupg_http_tls_verify_cb, ctrl);
1180   if (err)
1181     goto leave;
1182   http_session_set_log_cb (session, cert_log_cb);
1183   http_session_set_timeout (session, ctrl->timeout);
1184
1185  once_more:
1186   err = http_open (ctrl, &http,
1187                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1188                    request,
1189                    httphost,
1190                    /* fixme: AUTH */ NULL,
1191                    (httpflags
1192                     |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1193                     |(dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0)
1194                     |(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)
1195                     |(opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6 : 0)),
1196                    ctrl->http_proxy,
1197                    session,
1198                    NULL,
1199                    /*FIXME curl->srvtag*/NULL);
1200   if (!err)
1201     {
1202       fp = http_get_write_ptr (http);
1203       /* Avoid caches to get the most recent copy of the key.  We set
1204          both the Pragma and Cache-Control versions of the header, so
1205          we're good with both HTTP 1.0 and 1.1.  */
1206       es_fputs ("Pragma: no-cache\r\n"
1207                 "Cache-Control: no-cache\r\n", fp);
1208       if (post_cb)
1209         err = post_cb (post_cb_value, http);
1210       if (!err)
1211         {
1212           http_start_data (http);
1213           if (es_ferror (fp))
1214             err = gpg_error_from_syserror ();
1215         }
1216     }
1217   if (err)
1218     {
1219       /* Fixme: After a redirection we show the old host name.  */
1220       log_error (_("error connecting to '%s': %s\n"),
1221                  hostportstr, gpg_strerror (err));
1222       goto leave;
1223     }
1224
1225   /* Wait for the response.  */
1226   dirmngr_tick (ctrl);
1227   err = http_wait_response (http);
1228   if (err)
1229     {
1230       log_error (_("error reading HTTP response for '%s': %s\n"),
1231                  hostportstr, gpg_strerror (err));
1232       goto leave;
1233     }
1234
1235   if (http_get_tls_info (http, NULL))
1236     {
1237       /* Update the httpflags so that a redirect won't fallback to an
1238          unencrypted connection.  */
1239       httpflags |= HTTP_FLAG_FORCE_TLS;
1240     }
1241
1242   if (r_http_status)
1243     *r_http_status = http_get_status_code (http);
1244
1245   switch (http_get_status_code (http))
1246     {
1247     case 200:
1248       err = 0;
1249       break; /* Success.  */
1250
1251     case 301:
1252     case 302:
1253     case 307:
1254       {
1255         const char *s = http_get_header (http, "Location");
1256
1257         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1258                   request, s?s:"[none]", http_get_status_code (http));
1259         if (s && *s && redirects_left-- )
1260           {
1261             if (is_onion)
1262               {
1263                 /* Make sure that an onion address only redirects to
1264                  * another onion address.  */
1265                 http_release_parsed_uri (uri);
1266                 uri = NULL;
1267                 err = http_parse_uri (&uri, s, 0);
1268                 if (err)
1269                   goto leave;
1270
1271                 if (! uri->onion)
1272                   {
1273                     err = gpg_error (GPG_ERR_FORBIDDEN);
1274                     goto leave;
1275                   }
1276               }
1277
1278             xfree (request_buffer);
1279             request_buffer = xtrystrdup (s);
1280             if (request_buffer)
1281               {
1282                 request = request_buffer;
1283                 http_close (http, 0);
1284                 http = NULL;
1285                 goto once_more;
1286               }
1287             err = gpg_error_from_syserror ();
1288           }
1289         else
1290           err = gpg_error (GPG_ERR_NO_DATA);
1291         log_error (_("too many redirections\n"));
1292       }
1293       goto leave;
1294
1295     case 501:
1296       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1297       goto leave;
1298
1299     default:
1300       log_error (_("error accessing '%s': http status %u\n"),
1301                  request, http_get_status_code (http));
1302       err = gpg_error (GPG_ERR_NO_DATA);
1303       goto leave;
1304     }
1305
1306   /* FIXME: We should register a permanent redirection and whether a
1307      host has ever used TLS so that future calls will always use
1308      TLS. */
1309
1310   fp = http_get_read_ptr (http);
1311   if (!fp)
1312     {
1313       err = gpg_error (GPG_ERR_BUG);
1314       goto leave;
1315     }
1316
1317   /* Return the read stream and close the HTTP context.  */
1318   *r_fp = fp;
1319   http_close (http, 1);
1320   http = NULL;
1321
1322  leave:
1323   http_close (http, 0);
1324   http_session_release (session);
1325   xfree (request_buffer);
1326   http_release_parsed_uri (uri);
1327   return err;
1328 }
1329
1330
1331 /* Helper to evaluate the error code ERR from a send_request() call
1332    with REQUEST.  The function returns true if the caller shall try
1333    again.  TRIES_LEFT points to a variable to track the number of
1334    retries; this function decrements it and won't return true if it is
1335    down to zero. */
1336 static int
1337 handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
1338                            unsigned int *tries_left)
1339 {
1340   int retry = 0;
1341
1342   /* Fixme: Should we disable all hosts of a protocol family if a
1343    * request for an address of that familiy returned ENETDOWN?  */
1344
1345   switch (gpg_err_code (err))
1346     {
1347     case GPG_ERR_ECONNREFUSED:
1348       if (tor_not_running_p (ctrl))
1349         break; /* A retry does not make sense.  */
1350       /* Okay: Tor is up or --use-tor is not used.  */
1351       /*FALLTHRU*/
1352     case GPG_ERR_ENETUNREACH:
1353     case GPG_ERR_ENETDOWN:
1354     case GPG_ERR_UNKNOWN_HOST:
1355     case GPG_ERR_NETWORK:
1356     case GPG_ERR_EIO:  /* Sometimes used by estream cookie functions.  */
1357     case GPG_ERR_EADDRNOTAVAIL:  /* e.g. when IPv6 is disabled */
1358     case GPG_ERR_EAFNOSUPPORT:  /* e.g. when IPv6 is not compiled in */
1359       if (mark_host_dead (request) && *tries_left)
1360         retry = 1;
1361       break;
1362
1363     case GPG_ERR_ETIMEDOUT:
1364       if (*tries_left)
1365         {
1366           log_info ("selecting a different host due to a timeout\n");
1367           retry = 1;
1368         }
1369       break;
1370
1371     case GPG_ERR_EACCES:
1372       if (dirmngr_use_tor ())
1373         {
1374           log_info ("(Tor configuration problem)\n");
1375           dirmngr_status (ctrl, "WARNING", "tor_config_problem 0",
1376                           "Please check that the \"SocksPort\" flag "
1377                           "\"IPv6Traffic\" is set in torrc", NULL);
1378         }
1379       break;
1380
1381     default:
1382       break;
1383     }
1384
1385   if (*tries_left)
1386     --*tries_left;
1387
1388   return retry;
1389 }
1390
1391 \f
1392 /* Search the keyserver identified by URI for keys matching PATTERN.
1393    On success R_FP has an open stream to read the data.  If
1394    R_HTTP_STATUS is not NULL, the http status code will be stored
1395    there.  */
1396 gpg_error_t
1397 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1398                estream_t *r_fp, unsigned int *r_http_status)
1399 {
1400   gpg_error_t err;
1401   KEYDB_SEARCH_DESC desc;
1402   char fprbuf[2+40+1];
1403   char *hostport = NULL;
1404   char *request = NULL;
1405   estream_t fp = NULL;
1406   int reselect;
1407   unsigned int httpflags;
1408   char *httphost = NULL;
1409   unsigned int tries = SEND_REQUEST_RETRIES;
1410
1411   *r_fp = NULL;
1412
1413   /* Remove search type indicator and adjust PATTERN accordingly.
1414      Note that HKP keyservers like the 0x to be present when searching
1415      by keyid.  We need to re-format the fingerprint and keyids so to
1416      remove the gpg specific force-use-of-this-key flag ("!").  */
1417   err = classify_user_id (pattern, &desc, 1);
1418   if (err)
1419     return err;
1420   switch (desc.mode)
1421     {
1422     case KEYDB_SEARCH_MODE_EXACT:
1423     case KEYDB_SEARCH_MODE_SUBSTR:
1424     case KEYDB_SEARCH_MODE_MAIL:
1425     case KEYDB_SEARCH_MODE_MAILSUB:
1426       pattern = desc.u.name;
1427       break;
1428     case KEYDB_SEARCH_MODE_SHORT_KID:
1429       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1430       pattern = fprbuf;
1431       break;
1432     case KEYDB_SEARCH_MODE_LONG_KID:
1433       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1434                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1435       pattern = fprbuf;
1436       break;
1437     case KEYDB_SEARCH_MODE_FPR16:
1438       fprbuf[0] = '0';
1439       fprbuf[1] = 'x';
1440       bin2hex (desc.u.fpr, 16, fprbuf+2);
1441       pattern = fprbuf;
1442       break;
1443     case KEYDB_SEARCH_MODE_FPR20:
1444     case KEYDB_SEARCH_MODE_FPR:
1445       fprbuf[0] = '0';
1446       fprbuf[1] = 'x';
1447       bin2hex (desc.u.fpr, 20, fprbuf+2);
1448       pattern = fprbuf;
1449       break;
1450     default:
1451       return gpg_error (GPG_ERR_INV_USER_ID);
1452     }
1453
1454   /* Build the request string.  */
1455   reselect = 0;
1456  again:
1457   {
1458     char *searchkey;
1459
1460     xfree (hostport); hostport = NULL;
1461     xfree (httphost); httphost = NULL;
1462     err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1463                           reselect, uri->explicit_port,
1464                           &hostport, &httpflags, &httphost);
1465     if (err)
1466       goto leave;
1467
1468     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1469     if (!searchkey)
1470       {
1471         err = gpg_error_from_syserror ();
1472         goto leave;
1473       }
1474
1475     xfree (request);
1476     request = strconcat (hostport,
1477                          "/pks/lookup?op=index&options=mr&search=",
1478                          searchkey,
1479                          NULL);
1480     xfree (searchkey);
1481     if (!request)
1482       {
1483         err = gpg_error_from_syserror ();
1484         goto leave;
1485       }
1486   }
1487
1488   /* Send the request.  */
1489   err = send_request (ctrl, request, hostport, httphost, httpflags,
1490                       NULL, NULL, &fp, r_http_status);
1491   if (handle_send_request_error (ctrl, err, request, &tries))
1492     {
1493       reselect = 1;
1494       goto again;
1495     }
1496   if (err)
1497     goto leave;
1498
1499   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1500   if (err)
1501     goto leave;
1502
1503   /* Peek at the response.  */
1504   {
1505     int c = es_getc (fp);
1506     if (c == -1)
1507       {
1508         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1509         log_error ("error reading response: %s\n", gpg_strerror (err));
1510         goto leave;
1511       }
1512     if (c == '<')
1513       {
1514         /* The document begins with a '<': Assume a HTML response,
1515            which we don't support.  */
1516         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1517         goto leave;
1518       }
1519     es_ungetc (c, fp);
1520   }
1521
1522   /* Return the read stream.  */
1523   *r_fp = fp;
1524   fp = NULL;
1525
1526  leave:
1527   es_fclose (fp);
1528   xfree (request);
1529   xfree (hostport);
1530   xfree (httphost);
1531   return err;
1532 }
1533
1534
1535 /* Get the key described key the KEYSPEC string from the keyserver
1536    identified by URI.  On success R_FP has an open stream to read the
1537    data.  The data will be provided in a format GnuPG can import
1538    (either a binary OpenPGP message or an armored one).  */
1539 gpg_error_t
1540 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1541 {
1542   gpg_error_t err;
1543   KEYDB_SEARCH_DESC desc;
1544   char kidbuf[2+40+1];
1545   const char *exactname = NULL;
1546   char *searchkey = NULL;
1547   char *hostport = NULL;
1548   char *request = NULL;
1549   estream_t fp = NULL;
1550   int reselect;
1551   char *httphost = NULL;
1552   unsigned int httpflags;
1553   unsigned int tries = SEND_REQUEST_RETRIES;
1554
1555   *r_fp = NULL;
1556
1557   /* Remove search type indicator and adjust PATTERN accordingly.
1558      Note that HKP keyservers like the 0x to be present when searching
1559      by keyid.  We need to re-format the fingerprint and keyids so to
1560      remove the gpg specific force-use-of-this-key flag ("!").  */
1561   err = classify_user_id (keyspec, &desc, 1);
1562   if (err)
1563     return err;
1564   switch (desc.mode)
1565     {
1566     case KEYDB_SEARCH_MODE_SHORT_KID:
1567       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1568       break;
1569     case KEYDB_SEARCH_MODE_LONG_KID:
1570       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1571                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1572       break;
1573     case KEYDB_SEARCH_MODE_FPR20:
1574     case KEYDB_SEARCH_MODE_FPR:
1575       /* This is a v4 fingerprint. */
1576       kidbuf[0] = '0';
1577       kidbuf[1] = 'x';
1578       bin2hex (desc.u.fpr, 20, kidbuf+2);
1579       break;
1580
1581     case KEYDB_SEARCH_MODE_EXACT:
1582       exactname = desc.u.name;
1583       break;
1584
1585     case KEYDB_SEARCH_MODE_FPR16:
1586       log_error ("HKP keyservers do not support v3 fingerprints\n");
1587       /* fall through */
1588     default:
1589       return gpg_error (GPG_ERR_INV_USER_ID);
1590     }
1591
1592   searchkey = http_escape_string (exactname? exactname : kidbuf,
1593                                   EXTRA_ESCAPE_CHARS);
1594   if (!searchkey)
1595     {
1596       err = gpg_error_from_syserror ();
1597       goto leave;
1598     }
1599
1600   reselect = 0;
1601  again:
1602   /* Build the request string.  */
1603   xfree (hostport); hostport = NULL;
1604   xfree (httphost); httphost = NULL;
1605   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1606                         reselect, uri->explicit_port,
1607                         &hostport, &httpflags, &httphost);
1608   if (err)
1609     goto leave;
1610
1611   xfree (request);
1612   request = strconcat (hostport,
1613                        "/pks/lookup?op=get&options=mr&search=",
1614                        searchkey,
1615                        exactname? "&exact=on":"",
1616                        NULL);
1617   if (!request)
1618     {
1619       err = gpg_error_from_syserror ();
1620       goto leave;
1621     }
1622
1623   /* Send the request.  */
1624   err = send_request (ctrl, request, hostport, httphost, httpflags,
1625                       NULL, NULL, &fp, NULL);
1626   if (handle_send_request_error (ctrl, err, request, &tries))
1627     {
1628       reselect = 1;
1629       goto again;
1630     }
1631   if (err)
1632     goto leave;
1633
1634   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1635   if (err)
1636     goto leave;
1637
1638   /* Return the read stream and close the HTTP context.  */
1639   *r_fp = fp;
1640   fp = NULL;
1641
1642  leave:
1643   es_fclose (fp);
1644   xfree (request);
1645   xfree (hostport);
1646   xfree (httphost);
1647   xfree (searchkey);
1648   return err;
1649 }
1650
1651
1652
1653 \f
1654 /* Callback parameters for put_post_cb.  */
1655 struct put_post_parm_s
1656 {
1657   char *datastring;
1658 };
1659
1660
1661 /* Helper for ks_hkp_put.  */
1662 static gpg_error_t
1663 put_post_cb (void *opaque, http_t http)
1664 {
1665   struct put_post_parm_s *parm = opaque;
1666   gpg_error_t err = 0;
1667   estream_t fp;
1668   size_t len;
1669
1670   fp = http_get_write_ptr (http);
1671   len = strlen (parm->datastring);
1672
1673   es_fprintf (fp,
1674               "Content-Type: application/x-www-form-urlencoded\r\n"
1675               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1676   http_start_data (http);
1677   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1678     err = gpg_error_from_syserror ();
1679   return err;
1680 }
1681
1682
1683 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI.  */
1684 gpg_error_t
1685 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1686 {
1687   gpg_error_t err;
1688   char *hostport = NULL;
1689   char *request = NULL;
1690   estream_t fp = NULL;
1691   struct put_post_parm_s parm;
1692   char *armored = NULL;
1693   int reselect;
1694   char *httphost = NULL;
1695   unsigned int httpflags;
1696   unsigned int tries = SEND_REQUEST_RETRIES;
1697
1698   parm.datastring = NULL;
1699
1700   err = armor_data (&armored, data, datalen);
1701   if (err)
1702     goto leave;
1703
1704   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1705   if (!parm.datastring)
1706     {
1707       err = gpg_error_from_syserror ();
1708       goto leave;
1709     }
1710   xfree (armored);
1711   armored = NULL;
1712
1713   /* Build the request string.  */
1714   reselect = 0;
1715  again:
1716   xfree (hostport); hostport = NULL;
1717   xfree (httphost); httphost = NULL;
1718   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1719                         reselect, uri->explicit_port,
1720                         &hostport, &httpflags, &httphost);
1721   if (err)
1722     goto leave;
1723
1724   xfree (request);
1725   request = strconcat (hostport, "/pks/add", NULL);
1726   if (!request)
1727     {
1728       err = gpg_error_from_syserror ();
1729       goto leave;
1730     }
1731
1732   /* Send the request.  */
1733   err = send_request (ctrl, request, hostport, httphost, 0,
1734                       put_post_cb, &parm, &fp, NULL);
1735   if (handle_send_request_error (ctrl, err, request, &tries))
1736     {
1737       reselect = 1;
1738       goto again;
1739     }
1740   if (err)
1741     goto leave;
1742
1743  leave:
1744   es_fclose (fp);
1745   xfree (parm.datastring);
1746   xfree (armored);
1747   xfree (request);
1748   xfree (hostport);
1749   xfree (httphost);
1750   return err;
1751 }