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