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