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