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