Imported Upstream version 2.2.1
[platform/upstream/gpg2.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*3)  /* 3 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 10
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 (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 (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 (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 (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 (srvs[i].target, 0,
518                                       AF_UNSPEC, SOCK_STREAM,
519                                       &ai, &cname);
520               if (err)
521                 continue;
522               dirmngr_tick (ctrl);
523               add_host (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 (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 (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->cname? hi->cname : 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 (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 (ai->addr, ai->addrlen, 0, &host);
636                   if (!err)
637                     {
638                       /* Okay, we return the first found name.  */
639                       *r_httphost = host;
640                       break;
641                     }
642                 }
643             }
644         }
645       free_dns_addrinfo (aibuf);
646     }
647
648   if (hi->dead)
649     {
650       log_error ("host '%s' marked as dead\n", hi->name);
651       if (r_httphost)
652         {
653           xfree (*r_httphost);
654           *r_httphost = NULL;
655         }
656       return gpg_error (GPG_ERR_NO_KEYSERVER);
657     }
658
659   if (r_httpflags)
660     {
661       /* If the hosttable does not indicate that a certain host
662          supports IPv<N>, we explicit set the corresponding http
663          flags.  The reason for this is that a host might be listed in
664          a pool as not v6 only but actually support v6 when later
665          the name is resolved by our http layer.  */
666       if (!hi->v4)
667         *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
668       if (!hi->v6)
669         *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
670
671       /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
672          addresses because the http module detects this itself.  This
673          also allows us to use an onion address without Tor mode being
674          enabled.  */
675     }
676
677   *r_host = xtrystrdup (hi->name);
678   if (!*r_host)
679     {
680       err = gpg_error_from_syserror ();
681       if (r_httphost)
682         {
683           xfree (*r_httphost);
684           *r_httphost = NULL;
685         }
686       return err;
687     }
688   if (hi->port[protocol])
689     snprintf (r_portstr, 6 /* five digits and the sentinel */,
690               "%hu", hi->port[protocol]);
691   return 0;
692 }
693
694
695 /* Mark the host NAME as dead.  NAME may be given as an URL.  Returns
696    true if a host was really marked as dead or was already marked dead
697    (e.g. by a concurrent session).  */
698 static int
699 mark_host_dead (const char *name)
700 {
701   const char *host;
702   char *host_buffer = NULL;
703   parsed_uri_t parsed_uri = NULL;
704   int done = 0;
705
706   if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
707     {
708       if (parsed_uri->v6lit)
709         {
710           host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
711           if (!host_buffer)
712             log_error ("out of core in mark_host_dead");
713           host = host_buffer;
714         }
715       else
716         host = parsed_uri->host;
717     }
718   else
719     host = name;
720
721   if (host && *host && strcmp (host, "localhost"))
722     {
723       hostinfo_t hi;
724       int idx;
725
726       idx = find_hostinfo (host);
727       if (idx != -1)
728         {
729           hi = hosttable[idx];
730           log_info ("marking host '%s' as dead%s\n",
731                     hi->name, hi->dead? " (again)":"");
732           hi->dead = 1;
733           hi->died_at = gnupg_get_time ();
734           if (!hi->died_at)
735             hi->died_at = 1;
736           done = 1;
737         }
738     }
739
740   http_release_parsed_uri (parsed_uri);
741   xfree (host_buffer);
742   return done;
743 }
744
745
746 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
747    alive.  */
748 gpg_error_t
749 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
750 {
751   gpg_error_t err = 0;
752   hostinfo_t hi, hi2;
753   int idx, idx2, idx3, n;
754
755   if (!name || !*name || !strcmp (name, "localhost"))
756     return 0;
757
758   idx = find_hostinfo (name);
759   if (idx == -1)
760     return gpg_error (GPG_ERR_NOT_FOUND);
761
762   hi = hosttable[idx];
763   if (alive && hi->dead)
764     {
765       hi->dead = 0;
766       err = ks_printf_help (ctrl, "marking '%s' as alive", name);
767     }
768   else if (!alive && !hi->dead)
769     {
770       hi->dead = 1;
771       hi->died_at = 0; /* Manually set dead.  */
772       err = ks_printf_help (ctrl, "marking '%s' as dead", name);
773     }
774
775   /* If the host is a pool mark all member hosts. */
776   if (!err && hi->pool)
777     {
778       for (idx2 = 0;
779            !err && idx2 < hi->pool_len && (n = hi->pool[idx2]) != -1;
780            idx2++)
781         {
782           assert (n >= 0 && n < hosttable_size);
783
784           if (!alive)
785             {
786               /* Do not mark a host from a pool dead if it is also a
787                  member in another pool.  */
788               for (idx3=0; idx3 < hosttable_size; idx3++)
789                 {
790                   if (hosttable[idx3]
791                       && hosttable[idx3]->pool
792                       && idx3 != idx
793                       && host_in_pool_p (hosttable[idx3], n))
794                     break;
795                 }
796               if (idx3 < hosttable_size)
797                 continue;  /* Host is also a member of another pool.  */
798             }
799
800           hi2 = hosttable[n];
801           if (!hi2)
802             ;
803           else if (alive && hi2->dead)
804             {
805               hi2->dead = 0;
806               err = ks_printf_help (ctrl, "marking '%s' as alive",
807                                     hi2->name);
808             }
809           else if (!alive && !hi2->dead)
810             {
811               hi2->dead = 1;
812               hi2->died_at = 0; /* Manually set dead. */
813               err = ks_printf_help (ctrl, "marking '%s' as dead",
814                                     hi2->name);
815             }
816         }
817     }
818
819   return err;
820 }
821
822
823 /* Debug function to print the entire hosttable.  */
824 gpg_error_t
825 ks_hkp_print_hosttable (ctrl_t ctrl)
826 {
827   gpg_error_t err;
828   int idx, idx2;
829   hostinfo_t hi;
830   membuf_t mb;
831   time_t curtime;
832   char *p, *died;
833   const char *diedstr;
834
835   err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
836   if (err)
837     return err;
838
839   /* FIXME: We need a lock for the hosttable.  */
840   curtime = gnupg_get_time ();
841   for (idx=0; idx < hosttable_size; idx++)
842     if ((hi=hosttable[idx]))
843       {
844         if (hi->dead && hi->died_at)
845           {
846             died = elapsed_time_string (hi->died_at, curtime);
847             diedstr = died? died : "error";
848           }
849         else
850           diedstr = died = NULL;
851
852         if (!hi->iporname_valid)
853           {
854             char *canon = NULL;
855
856             xfree (hi->iporname);
857             hi->iporname = NULL;
858
859             /* Do a lookup just for the display purpose.  */
860             if (hi->onion || hi->pool)
861               ;
862             else if (is_ip_address (hi->name))
863               {
864                 dns_addrinfo_t aibuf, ai;
865
866                 /* Turn the numerical IP address string into an AI and
867                  * then do a DNS PTR lookup.  */
868                 if (!resolve_dns_name (hi->name, 0, 0,
869                                        SOCK_STREAM,
870                                        &aibuf, &canon))
871                   {
872                     if (canon && is_ip_address (canon))
873                       {
874                         xfree (canon);
875                         canon = NULL;
876                       }
877                     for (ai = aibuf; !canon && ai; ai = ai->next)
878                       {
879                         resolve_dns_addr (ai->addr, ai->addrlen,
880                                           DNS_WITHBRACKET, &canon);
881                         if (canon && is_ip_address (canon))
882                           {
883                             /* We already have the numeric IP - no need to
884                              * display it a second time.  */
885                             xfree (canon);
886                             canon = NULL;
887                           }
888                       }
889                   }
890                 free_dns_addrinfo (aibuf);
891               }
892             else
893               {
894                 dns_addrinfo_t aibuf, ai;
895
896                 /* Get the IP address as a string from a name.  Note
897                  * that resolve_dns_addr allocates CANON on success
898                  * and thus terminates the loop. */
899                 if (!resolve_dns_name (hi->name, 0,
900                                        hi->v6? AF_INET6 : AF_INET,
901                                        SOCK_STREAM,
902                                        &aibuf, NULL))
903                   {
904                     for (ai = aibuf; !canon && ai; ai = ai->next)
905                       {
906                         resolve_dns_addr (ai->addr, ai->addrlen,
907                                           DNS_NUMERICHOST|DNS_WITHBRACKET,
908                                           &canon);
909                       }
910                   }
911                 free_dns_addrinfo (aibuf);
912               }
913
914             hi->iporname = canon;
915             hi->iporname_valid = 1;
916           }
917
918         err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s\n",
919                               idx,
920                               hi->onion? "O" : hi->v6? "6":" ",
921                               hi->v4? "4":" ",
922                               hi->dead? "d":" ",
923                               hi->name,
924                               hi->iporname? " (":"",
925                               hi->iporname? hi->iporname : "",
926                               hi->iporname? ")":"",
927                               diedstr? "  (":"",
928                               diedstr? diedstr:"",
929                               diedstr? ")":""   );
930         xfree (died);
931         if (err)
932           return err;
933
934         if (hi->cname)
935           err = ks_printf_help (ctrl, "  .       %s", hi->cname);
936         if (err)
937           return err;
938
939         if (hi->pool)
940           {
941             init_membuf (&mb, 256);
942             put_membuf_printf (&mb, "  .   -->");
943             for (idx2 = 0; idx2 < hi->pool_len && hi->pool[idx2] != -1; idx2++)
944               {
945                 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
946                 if (hi->poolidx == hi->pool[idx2])
947                   put_membuf_printf (&mb, "*");
948               }
949             put_membuf( &mb, "", 1);
950             p = get_membuf (&mb, NULL);
951             if (!p)
952               return gpg_error_from_syserror ();
953             err = ks_print_help (ctrl, p);
954             xfree (p);
955             if (err)
956               return err;
957           }
958       }
959   return 0;
960 }
961
962
963
964 /* Print a help output for the schemata supported by this module. */
965 gpg_error_t
966 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
967 {
968   const char data[] =
969     "Handler for HKP URLs:\n"
970     "  hkp://\n"
971 #if  HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
972     "  hkps://\n"
973 #endif
974     "Supported methods: search, get, put\n";
975   gpg_error_t err;
976
977 #if  HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
978   const char data2[] = "  hkp\n  hkps";
979 #else
980   const char data2[] = "  hkp";
981 #endif
982
983   if (!uri)
984     err = ks_print_help (ctrl, data2);
985   else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
986                             || !strcmp (uri->scheme, "hkps")))
987     err = ks_print_help (ctrl, data);
988   else
989     err = 0;
990
991   return err;
992 }
993
994
995 /* Build the remote part of the URL from SCHEME, HOST and an optional
996  * PORT.  If NO_SRV is set no SRV record lookup will be done.  Returns
997  * an allocated string at R_HOSTPORT or NULL on failure.  If
998  * R_HTTPHOST is not NULL it receives a malloced string with the
999  * hostname; this may be different from HOST if HOST is selected from
1000  * a pool.  */
1001 static gpg_error_t
1002 make_host_part (ctrl_t ctrl,
1003                 const char *scheme, const char *host, unsigned short port,
1004                 int force_reselect, int no_srv,
1005                 char **r_hostport, unsigned int *r_httpflags, char **r_httphost)
1006 {
1007   gpg_error_t err;
1008   const char *srvtag;
1009   char portstr[10];
1010   char *hostname;
1011   enum ks_protocol protocol;
1012
1013   *r_hostport = NULL;
1014
1015   if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
1016     {
1017       scheme = "https";
1018       srvtag = no_srv? NULL : "pgpkey-https";
1019       protocol = KS_PROTOCOL_HKPS;
1020     }
1021   else /* HKP or HTTP.  */
1022     {
1023       scheme = "http";
1024       srvtag = no_srv? NULL : "pgpkey-http";
1025       protocol = KS_PROTOCOL_HKP;
1026     }
1027
1028   portstr[0] = 0;
1029   err = map_host (ctrl, host, srvtag, force_reselect, protocol,
1030                   &hostname, portstr, r_httpflags, r_httphost);
1031   if (err)
1032     return err;
1033
1034   /* If map_host did not return a port (from a SRV record) but a port
1035    * has been specified (implicitly or explicitly) then use that port.
1036    * In the case that a port was not specified (which is probably a
1037    * bug in https.c) we will set up defaults.  */
1038   if (*portstr)
1039     ;
1040   else if (!*portstr && port)
1041     snprintf (portstr, sizeof portstr, "%hu", port);
1042   else if (!strcmp (scheme,"https"))
1043     strcpy (portstr, "443");
1044   else
1045     strcpy (portstr, "11371");
1046
1047   if (*hostname != '[' && is_ip_address (hostname) == 6)
1048     *r_hostport = strconcat (scheme, "://[", hostname, "]:", portstr, NULL);
1049   else
1050     *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
1051   xfree (hostname);
1052   if (!*r_hostport)
1053     {
1054       if (r_httphost)
1055         {
1056           xfree (*r_httphost);
1057           *r_httphost = NULL;
1058         }
1059       return gpg_error_from_syserror ();
1060     }
1061   return 0;
1062 }
1063
1064
1065 /* Resolve all known keyserver names and update the hosttable.  This
1066    is mainly useful for debugging because the resolving is anyway done
1067    on demand.  */
1068 gpg_error_t
1069 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
1070 {
1071   gpg_error_t err;
1072   char *hostport = NULL;
1073
1074   /* NB: With an explicitly given port we do not want to consult a
1075    * service record because that might be in conflict with the port
1076    * from such a service record.  */
1077   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1078                         1, uri->explicit_port,
1079                         &hostport, NULL, NULL);
1080   if (err)
1081     {
1082       err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
1083                             uri->scheme, uri->host, uri->port,
1084                             gpg_strerror (err));
1085     }
1086   else
1087     {
1088       err = ks_printf_help (ctrl, "%s", hostport);
1089       xfree (hostport);
1090     }
1091   return err;
1092 }
1093
1094
1095 /* Housekeeping function called from the housekeeping thread.  It is
1096    used to mark dead hosts alive so that they may be tried again after
1097    some time.  */
1098 void
1099 ks_hkp_housekeeping (time_t curtime)
1100 {
1101   int idx;
1102   hostinfo_t hi;
1103
1104   for (idx=0; idx < hosttable_size; idx++)
1105     {
1106       hi = hosttable[idx];
1107       if (!hi)
1108         continue;
1109       if (!hi->dead)
1110         continue;
1111       if (!hi->died_at)
1112         continue; /* Do not resurrect manually shot hosts.  */
1113       if (hi->died_at + RESURRECT_INTERVAL <= curtime
1114           || hi->died_at > curtime)
1115         {
1116           hi->dead = 0;
1117           log_info ("resurrected host '%s'", hi->name);
1118         }
1119     }
1120 }
1121
1122
1123 /* Reload (SIGHUP) action for this module.  We mark all host alive
1124  * even those which have been manually shot.  */
1125 void
1126 ks_hkp_reload (void)
1127 {
1128   int idx, count;
1129   hostinfo_t hi;
1130
1131   for (idx=count=0; idx < hosttable_size; idx++)
1132     {
1133       hi = hosttable[idx];
1134       if (!hi)
1135         continue;
1136       hi->iporname_valid = 0;
1137       if (!hi->dead)
1138         continue;
1139       hi->dead = 0;
1140       count++;
1141     }
1142   if (count)
1143     log_info ("number of resurrected hosts: %d", count);
1144 }
1145
1146
1147 /* Send an HTTP request.  On success returns an estream object at
1148    R_FP.  HOSTPORTSTR is only used for diagnostics.  If HTTPHOST is
1149    not NULL it will be used as HTTP "Host" header.  If POST_CB is not
1150    NULL a post request is used and that callback is called to allow
1151    writing the post data.  If R_HTTP_STATUS is not NULL, the http
1152    status code will be stored there.  */
1153 static gpg_error_t
1154 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
1155               const char *httphost, unsigned int httpflags,
1156               gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
1157               estream_t *r_fp, unsigned int *r_http_status)
1158 {
1159   gpg_error_t err;
1160   http_session_t session = NULL;
1161   http_t http = NULL;
1162   int redirects_left = MAX_REDIRECTS;
1163   estream_t fp = NULL;
1164   char *request_buffer = NULL;
1165   parsed_uri_t uri = NULL;
1166   int is_onion;
1167
1168   *r_fp = NULL;
1169
1170   err = http_parse_uri (&uri, request, 0);
1171   if (err)
1172     goto leave;
1173   is_onion = uri->onion;
1174
1175   err = http_session_new (&session, httphost,
1176                           ((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0)
1177                            | HTTP_FLAG_TRUST_DEF),
1178                           gnupg_http_tls_verify_cb, ctrl);
1179   if (err)
1180     goto leave;
1181   http_session_set_log_cb (session, cert_log_cb);
1182   http_session_set_timeout (session, ctrl->timeout);
1183
1184  once_more:
1185   err = http_open (&http,
1186                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1187                    request,
1188                    httphost,
1189                    /* fixme: AUTH */ NULL,
1190                    (httpflags
1191                     |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1192                     |(dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0)
1193                     |(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)
1194                     |(opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6 : 0)),
1195                    ctrl->http_proxy,
1196                    session,
1197                    NULL,
1198                    /*FIXME curl->srvtag*/NULL);
1199   if (!err)
1200     {
1201       fp = http_get_write_ptr (http);
1202       /* Avoid caches to get the most recent copy of the key.  We set
1203          both the Pragma and Cache-Control versions of the header, so
1204          we're good with both HTTP 1.0 and 1.1.  */
1205       es_fputs ("Pragma: no-cache\r\n"
1206                 "Cache-Control: no-cache\r\n", fp);
1207       if (post_cb)
1208         err = post_cb (post_cb_value, http);
1209       if (!err)
1210         {
1211           http_start_data (http);
1212           if (es_ferror (fp))
1213             err = gpg_error_from_syserror ();
1214         }
1215     }
1216   if (err)
1217     {
1218       /* Fixme: After a redirection we show the old host name.  */
1219       log_error (_("error connecting to '%s': %s\n"),
1220                  hostportstr, gpg_strerror (err));
1221       goto leave;
1222     }
1223
1224   /* Wait for the response.  */
1225   dirmngr_tick (ctrl);
1226   err = http_wait_response (http);
1227   if (err)
1228     {
1229       log_error (_("error reading HTTP response for '%s': %s\n"),
1230                  hostportstr, gpg_strerror (err));
1231       goto leave;
1232     }
1233
1234   if (http_get_tls_info (http, NULL))
1235     {
1236       /* Update the httpflags so that a redirect won't fallback to an
1237          unencrypted connection.  */
1238       httpflags |= HTTP_FLAG_FORCE_TLS;
1239     }
1240
1241   if (r_http_status)
1242     *r_http_status = http_get_status_code (http);
1243
1244   switch (http_get_status_code (http))
1245     {
1246     case 200:
1247       err = 0;
1248       break; /* Success.  */
1249
1250     case 301:
1251     case 302:
1252     case 307:
1253       {
1254         const char *s = http_get_header (http, "Location");
1255
1256         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1257                   request, s?s:"[none]", http_get_status_code (http));
1258         if (s && *s && redirects_left-- )
1259           {
1260             if (is_onion)
1261               {
1262                 /* Make sure that an onion address only redirects to
1263                  * another onion address.  */
1264                 http_release_parsed_uri (uri);
1265                 uri = NULL;
1266                 err = http_parse_uri (&uri, s, 0);
1267                 if (err)
1268                   goto leave;
1269
1270                 if (! uri->onion)
1271                   {
1272                     err = gpg_error (GPG_ERR_FORBIDDEN);
1273                     goto leave;
1274                   }
1275               }
1276
1277             xfree (request_buffer);
1278             request_buffer = xtrystrdup (s);
1279             if (request_buffer)
1280               {
1281                 request = request_buffer;
1282                 http_close (http, 0);
1283                 http = NULL;
1284                 goto once_more;
1285               }
1286             err = gpg_error_from_syserror ();
1287           }
1288         else
1289           err = gpg_error (GPG_ERR_NO_DATA);
1290         log_error (_("too many redirections\n"));
1291       }
1292       goto leave;
1293
1294     case 501:
1295       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1296       goto leave;
1297
1298     default:
1299       log_error (_("error accessing '%s': http status %u\n"),
1300                  request, http_get_status_code (http));
1301       err = gpg_error (GPG_ERR_NO_DATA);
1302       goto leave;
1303     }
1304
1305   /* FIXME: We should register a permanent redirection and whether a
1306      host has ever used TLS so that future calls will always use
1307      TLS. */
1308
1309   fp = http_get_read_ptr (http);
1310   if (!fp)
1311     {
1312       err = gpg_error (GPG_ERR_BUG);
1313       goto leave;
1314     }
1315
1316   /* Return the read stream and close the HTTP context.  */
1317   *r_fp = fp;
1318   http_close (http, 1);
1319   http = NULL;
1320
1321  leave:
1322   http_close (http, 0);
1323   http_session_release (session);
1324   xfree (request_buffer);
1325   http_release_parsed_uri (uri);
1326   return err;
1327 }
1328
1329
1330 /* Helper to evaluate the error code ERR from a send_request() call
1331    with REQUEST.  The function returns true if the caller shall try
1332    again.  TRIES_LEFT points to a variable to track the number of
1333    retries; this function decrements it and won't return true if it is
1334    down to zero. */
1335 static int
1336 handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
1337                            unsigned int *tries_left)
1338 {
1339   int retry = 0;
1340
1341   /* Fixme: Should we disable all hosts of a protocol family if a
1342    * request for an address of that familiy returned ENETDOWN?  */
1343
1344   switch (gpg_err_code (err))
1345     {
1346     case GPG_ERR_ECONNREFUSED:
1347       if (tor_not_running_p (ctrl))
1348         break; /* A retry does not make sense.  */
1349       /* Okay: Tor is up or --use-tor is not used.  */
1350       /*FALLTHRU*/
1351     case GPG_ERR_ENETUNREACH:
1352     case GPG_ERR_ENETDOWN:
1353     case GPG_ERR_UNKNOWN_HOST:
1354     case GPG_ERR_NETWORK:
1355     case GPG_ERR_EIO:  /* Sometimes used by estream cookie functions.  */
1356       if (mark_host_dead (request) && *tries_left)
1357         retry = 1;
1358       break;
1359
1360     case GPG_ERR_ETIMEDOUT:
1361       if (*tries_left)
1362         {
1363           log_info ("selecting a different host due to a timeout\n");
1364           retry = 1;
1365         }
1366       break;
1367
1368     case GPG_ERR_EACCES:
1369       if (dirmngr_use_tor ())
1370         {
1371           log_info ("(Tor configuration problem)\n");
1372           dirmngr_status (ctrl, "WARNING", "tor_config_problem 0",
1373                           "Please check that the \"SocksPort\" flag "
1374                           "\"IPv6Traffic\" is set in torrc", NULL);
1375         }
1376       break;
1377
1378     default:
1379       break;
1380     }
1381
1382   if (*tries_left)
1383     --*tries_left;
1384
1385   return retry;
1386 }
1387
1388 \f
1389 /* Search the keyserver identified by URI for keys matching PATTERN.
1390    On success R_FP has an open stream to read the data.  If
1391    R_HTTP_STATUS is not NULL, the http status code will be stored
1392    there.  */
1393 gpg_error_t
1394 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1395                estream_t *r_fp, unsigned int *r_http_status)
1396 {
1397   gpg_error_t err;
1398   KEYDB_SEARCH_DESC desc;
1399   char fprbuf[2+40+1];
1400   char *hostport = NULL;
1401   char *request = NULL;
1402   estream_t fp = NULL;
1403   int reselect;
1404   unsigned int httpflags;
1405   char *httphost = NULL;
1406   unsigned int tries = SEND_REQUEST_RETRIES;
1407
1408   *r_fp = NULL;
1409
1410   /* Remove search type indicator and adjust PATTERN accordingly.
1411      Note that HKP keyservers like the 0x to be present when searching
1412      by keyid.  We need to re-format the fingerprint and keyids so to
1413      remove the gpg specific force-use-of-this-key flag ("!").  */
1414   err = classify_user_id (pattern, &desc, 1);
1415   if (err)
1416     return err;
1417   switch (desc.mode)
1418     {
1419     case KEYDB_SEARCH_MODE_EXACT:
1420     case KEYDB_SEARCH_MODE_SUBSTR:
1421     case KEYDB_SEARCH_MODE_MAIL:
1422     case KEYDB_SEARCH_MODE_MAILSUB:
1423       pattern = desc.u.name;
1424       break;
1425     case KEYDB_SEARCH_MODE_SHORT_KID:
1426       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1427       pattern = fprbuf;
1428       break;
1429     case KEYDB_SEARCH_MODE_LONG_KID:
1430       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1431                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1432       pattern = fprbuf;
1433       break;
1434     case KEYDB_SEARCH_MODE_FPR16:
1435       fprbuf[0] = '0';
1436       fprbuf[1] = 'x';
1437       bin2hex (desc.u.fpr, 16, fprbuf+2);
1438       pattern = fprbuf;
1439       break;
1440     case KEYDB_SEARCH_MODE_FPR20:
1441     case KEYDB_SEARCH_MODE_FPR:
1442       fprbuf[0] = '0';
1443       fprbuf[1] = 'x';
1444       bin2hex (desc.u.fpr, 20, fprbuf+2);
1445       pattern = fprbuf;
1446       break;
1447     default:
1448       return gpg_error (GPG_ERR_INV_USER_ID);
1449     }
1450
1451   /* Build the request string.  */
1452   reselect = 0;
1453  again:
1454   {
1455     char *searchkey;
1456
1457     xfree (hostport); hostport = NULL;
1458     xfree (httphost); httphost = NULL;
1459     err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1460                           reselect, uri->explicit_port,
1461                           &hostport, &httpflags, &httphost);
1462     if (err)
1463       goto leave;
1464
1465     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1466     if (!searchkey)
1467       {
1468         err = gpg_error_from_syserror ();
1469         goto leave;
1470       }
1471
1472     xfree (request);
1473     request = strconcat (hostport,
1474                          "/pks/lookup?op=index&options=mr&search=",
1475                          searchkey,
1476                          NULL);
1477     xfree (searchkey);
1478     if (!request)
1479       {
1480         err = gpg_error_from_syserror ();
1481         goto leave;
1482       }
1483   }
1484
1485   /* Send the request.  */
1486   err = send_request (ctrl, request, hostport, httphost, httpflags,
1487                       NULL, NULL, &fp, r_http_status);
1488   if (handle_send_request_error (ctrl, err, request, &tries))
1489     {
1490       reselect = 1;
1491       goto again;
1492     }
1493   if (err)
1494     goto leave;
1495
1496   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1497   if (err)
1498     goto leave;
1499
1500   /* Peek at the response.  */
1501   {
1502     int c = es_getc (fp);
1503     if (c == -1)
1504       {
1505         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1506         log_error ("error reading response: %s\n", gpg_strerror (err));
1507         goto leave;
1508       }
1509     if (c == '<')
1510       {
1511         /* The document begins with a '<': Assume a HTML response,
1512            which we don't support.  */
1513         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1514         goto leave;
1515       }
1516     es_ungetc (c, fp);
1517   }
1518
1519   /* Return the read stream.  */
1520   *r_fp = fp;
1521   fp = NULL;
1522
1523  leave:
1524   es_fclose (fp);
1525   xfree (request);
1526   xfree (hostport);
1527   xfree (httphost);
1528   return err;
1529 }
1530
1531
1532 /* Get the key described key the KEYSPEC string from the keyserver
1533    identified by URI.  On success R_FP has an open stream to read the
1534    data.  The data will be provided in a format GnuPG can import
1535    (either a binary OpenPGP message or an armored one).  */
1536 gpg_error_t
1537 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1538 {
1539   gpg_error_t err;
1540   KEYDB_SEARCH_DESC desc;
1541   char kidbuf[2+40+1];
1542   const char *exactname = NULL;
1543   char *searchkey = NULL;
1544   char *hostport = NULL;
1545   char *request = NULL;
1546   estream_t fp = NULL;
1547   int reselect;
1548   char *httphost = NULL;
1549   unsigned int httpflags;
1550   unsigned int tries = SEND_REQUEST_RETRIES;
1551
1552   *r_fp = NULL;
1553
1554   /* Remove search type indicator and adjust PATTERN accordingly.
1555      Note that HKP keyservers like the 0x to be present when searching
1556      by keyid.  We need to re-format the fingerprint and keyids so to
1557      remove the gpg specific force-use-of-this-key flag ("!").  */
1558   err = classify_user_id (keyspec, &desc, 1);
1559   if (err)
1560     return err;
1561   switch (desc.mode)
1562     {
1563     case KEYDB_SEARCH_MODE_SHORT_KID:
1564       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1565       break;
1566     case KEYDB_SEARCH_MODE_LONG_KID:
1567       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1568                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1569       break;
1570     case KEYDB_SEARCH_MODE_FPR20:
1571     case KEYDB_SEARCH_MODE_FPR:
1572       /* This is a v4 fingerprint. */
1573       kidbuf[0] = '0';
1574       kidbuf[1] = 'x';
1575       bin2hex (desc.u.fpr, 20, kidbuf+2);
1576       break;
1577
1578     case KEYDB_SEARCH_MODE_EXACT:
1579       exactname = desc.u.name;
1580       break;
1581
1582     case KEYDB_SEARCH_MODE_FPR16:
1583       log_error ("HKP keyservers do not support v3 fingerprints\n");
1584       /* fall through */
1585     default:
1586       return gpg_error (GPG_ERR_INV_USER_ID);
1587     }
1588
1589   searchkey = http_escape_string (exactname? exactname : kidbuf,
1590                                   EXTRA_ESCAPE_CHARS);
1591   if (!searchkey)
1592     {
1593       err = gpg_error_from_syserror ();
1594       goto leave;
1595     }
1596
1597   reselect = 0;
1598  again:
1599   /* Build the request string.  */
1600   xfree (hostport); hostport = NULL;
1601   xfree (httphost); httphost = NULL;
1602   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1603                         reselect, uri->explicit_port,
1604                         &hostport, &httpflags, &httphost);
1605   if (err)
1606     goto leave;
1607
1608   xfree (request);
1609   request = strconcat (hostport,
1610                        "/pks/lookup?op=get&options=mr&search=",
1611                        searchkey,
1612                        exactname? "&exact=on":"",
1613                        NULL);
1614   if (!request)
1615     {
1616       err = gpg_error_from_syserror ();
1617       goto leave;
1618     }
1619
1620   /* Send the request.  */
1621   err = send_request (ctrl, request, hostport, httphost, httpflags,
1622                       NULL, NULL, &fp, NULL);
1623   if (handle_send_request_error (ctrl, err, request, &tries))
1624     {
1625       reselect = 1;
1626       goto again;
1627     }
1628   if (err)
1629     goto leave;
1630
1631   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1632   if (err)
1633     goto leave;
1634
1635   /* Return the read stream and close the HTTP context.  */
1636   *r_fp = fp;
1637   fp = NULL;
1638
1639  leave:
1640   es_fclose (fp);
1641   xfree (request);
1642   xfree (hostport);
1643   xfree (httphost);
1644   xfree (searchkey);
1645   return err;
1646 }
1647
1648
1649
1650 \f
1651 /* Callback parameters for put_post_cb.  */
1652 struct put_post_parm_s
1653 {
1654   char *datastring;
1655 };
1656
1657
1658 /* Helper for ks_hkp_put.  */
1659 static gpg_error_t
1660 put_post_cb (void *opaque, http_t http)
1661 {
1662   struct put_post_parm_s *parm = opaque;
1663   gpg_error_t err = 0;
1664   estream_t fp;
1665   size_t len;
1666
1667   fp = http_get_write_ptr (http);
1668   len = strlen (parm->datastring);
1669
1670   es_fprintf (fp,
1671               "Content-Type: application/x-www-form-urlencoded\r\n"
1672               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1673   http_start_data (http);
1674   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1675     err = gpg_error_from_syserror ();
1676   return err;
1677 }
1678
1679
1680 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI.  */
1681 gpg_error_t
1682 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1683 {
1684   gpg_error_t err;
1685   char *hostport = NULL;
1686   char *request = NULL;
1687   estream_t fp = NULL;
1688   struct put_post_parm_s parm;
1689   char *armored = NULL;
1690   int reselect;
1691   char *httphost = NULL;
1692   unsigned int httpflags;
1693   unsigned int tries = SEND_REQUEST_RETRIES;
1694
1695   parm.datastring = NULL;
1696
1697   err = armor_data (&armored, data, datalen);
1698   if (err)
1699     goto leave;
1700
1701   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1702   if (!parm.datastring)
1703     {
1704       err = gpg_error_from_syserror ();
1705       goto leave;
1706     }
1707   xfree (armored);
1708   armored = NULL;
1709
1710   /* Build the request string.  */
1711   reselect = 0;
1712  again:
1713   xfree (hostport); hostport = NULL;
1714   xfree (httphost); httphost = NULL;
1715   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1716                         reselect, uri->explicit_port,
1717                         &hostport, &httpflags, &httphost);
1718   if (err)
1719     goto leave;
1720
1721   xfree (request);
1722   request = strconcat (hostport, "/pks/add", NULL);
1723   if (!request)
1724     {
1725       err = gpg_error_from_syserror ();
1726       goto leave;
1727     }
1728
1729   /* Send the request.  */
1730   err = send_request (ctrl, request, hostport, httphost, 0,
1731                       put_post_cb, &parm, &fp, NULL);
1732   if (handle_send_request_error (ctrl, err, request, &tries))
1733     {
1734       reselect = 1;
1735       goto again;
1736     }
1737   if (err)
1738     goto leave;
1739
1740  leave:
1741   es_fclose (fp);
1742   xfree (parm.datastring);
1743   xfree (armored);
1744   xfree (request);
1745   xfree (hostport);
1746   xfree (httphost);
1747   return err;
1748 }