dirmngr: Implement hkps lookups using literal addresses.
[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 const 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 /* Send an HTTP request.  On success returns an estream object at
1007    R_FP.  HOSTPORTSTR is only used for diagnostics.  If HTTPHOST is
1008    not NULL it will be used as HTTP "Host" header.  If POST_CB is not
1009    NULL a post request is used and that callback is called to allow
1010    writing the post data.  If R_HTTP_STATUS is not NULL, the http
1011    status code will be stored there.  */
1012 static gpg_error_t
1013 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
1014               const char *httphost, unsigned int httpflags,
1015               gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
1016               estream_t *r_fp, unsigned int *r_http_status)
1017 {
1018   gpg_error_t err;
1019   http_session_t session = NULL;
1020   http_t http = NULL;
1021   int redirects_left = MAX_REDIRECTS;
1022   estream_t fp = NULL;
1023   char *request_buffer = NULL;
1024
1025   *r_fp = NULL;
1026
1027   err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
1028   if (err)
1029     goto leave;
1030   http_session_set_log_cb (session, cert_log_cb);
1031
1032  once_more:
1033   err = http_open (&http,
1034                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1035                    request,
1036                    httphost,
1037                    /* fixme: AUTH */ NULL,
1038                    (httpflags
1039                     |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1040                     |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
1041                    ctrl->http_proxy,
1042                    session,
1043                    NULL,
1044                    /*FIXME curl->srvtag*/NULL);
1045   if (!err)
1046     {
1047       fp = http_get_write_ptr (http);
1048       /* Avoid caches to get the most recent copy of the key.  We set
1049          both the Pragma and Cache-Control versions of the header, so
1050          we're good with both HTTP 1.0 and 1.1.  */
1051       es_fputs ("Pragma: no-cache\r\n"
1052                 "Cache-Control: no-cache\r\n", fp);
1053       if (post_cb)
1054         err = post_cb (post_cb_value, http);
1055       if (!err)
1056         {
1057           http_start_data (http);
1058           if (es_ferror (fp))
1059             err = gpg_error_from_syserror ();
1060         }
1061     }
1062   if (err)
1063     {
1064       /* Fixme: After a redirection we show the old host name.  */
1065       log_error (_("error connecting to '%s': %s\n"),
1066                  hostportstr, gpg_strerror (err));
1067       goto leave;
1068     }
1069
1070   /* Wait for the response.  */
1071   dirmngr_tick (ctrl);
1072   err = http_wait_response (http);
1073   if (err)
1074     {
1075       log_error (_("error reading HTTP response for '%s': %s\n"),
1076                  hostportstr, gpg_strerror (err));
1077       goto leave;
1078     }
1079
1080   if (http_get_tls_info (http, NULL))
1081     {
1082       /* Update the httpflags so that a redirect won't fallback to an
1083          unencrypted connection.  */
1084       httpflags |= HTTP_FLAG_FORCE_TLS;
1085     }
1086
1087   if (r_http_status)
1088     *r_http_status = http_get_status_code (http);
1089
1090   switch (http_get_status_code (http))
1091     {
1092     case 200:
1093       err = 0;
1094       break; /* Success.  */
1095
1096     case 301:
1097     case 302:
1098     case 307:
1099       {
1100         const char *s = http_get_header (http, "Location");
1101
1102         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1103                   request, s?s:"[none]", http_get_status_code (http));
1104         if (s && *s && redirects_left-- )
1105           {
1106             xfree (request_buffer);
1107             request_buffer = xtrystrdup (s);
1108             if (request_buffer)
1109               {
1110                 request = request_buffer;
1111                 http_close (http, 0);
1112                 http = NULL;
1113                 goto once_more;
1114               }
1115             err = gpg_error_from_syserror ();
1116           }
1117         else
1118           err = gpg_error (GPG_ERR_NO_DATA);
1119         log_error (_("too many redirections\n"));
1120       }
1121       goto leave;
1122
1123     case 501:
1124       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1125       goto leave;
1126
1127     default:
1128       log_error (_("error accessing '%s': http status %u\n"),
1129                  request, http_get_status_code (http));
1130       err = gpg_error (GPG_ERR_NO_DATA);
1131       goto leave;
1132     }
1133
1134   /* FIXME: We should register a permanent redirection and whether a
1135      host has ever used TLS so that future calls will always use
1136      TLS. */
1137
1138   fp = http_get_read_ptr (http);
1139   if (!fp)
1140     {
1141       err = gpg_error (GPG_ERR_BUG);
1142       goto leave;
1143     }
1144
1145   /* Return the read stream and close the HTTP context.  */
1146   *r_fp = fp;
1147   http_close (http, 1);
1148   http = NULL;
1149
1150  leave:
1151   http_close (http, 0);
1152   http_session_release (session);
1153   xfree (request_buffer);
1154   return err;
1155 }
1156
1157
1158 /* Helper to evaluate the error code ERR form a send_request() call
1159    with REQUEST.  The function returns true if the caller shall try
1160    again.  TRIES_LEFT points to a variable to track the number of
1161    retries; this function decrements it and won't return true if it is
1162    down to zero. */
1163 static int
1164 handle_send_request_error (gpg_error_t err, const char *request,
1165                            unsigned int *tries_left)
1166 {
1167   int retry = 0;
1168
1169   /* Fixme: Should we disable all hosts of a protocol family if a
1170    * request for an address of that familiy returned ENETDOWN?  */
1171
1172   switch (gpg_err_code (err))
1173     {
1174     case GPG_ERR_ECONNREFUSED:
1175       if (opt.use_tor)
1176         {
1177           assuan_fd_t sock;
1178
1179           sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
1180           if (sock == ASSUAN_INVALID_FD)
1181             log_info ("(it seems Tor is not running)\n");
1182           else
1183             assuan_sock_close (sock);
1184         }
1185       /*FALLTHRU*/
1186     case GPG_ERR_ENETUNREACH:
1187     case GPG_ERR_ENETDOWN:
1188     case GPG_ERR_UNKNOWN_HOST:
1189     case GPG_ERR_NETWORK:
1190       if (mark_host_dead (request) && *tries_left)
1191         retry = 1;
1192       break;
1193
1194     case GPG_ERR_ETIMEDOUT:
1195       if (*tries_left)
1196         {
1197           log_info ("selecting a different host due to a timeout\n");
1198           retry = 1;
1199         }
1200       break;
1201
1202     default:
1203       break;
1204     }
1205
1206   if (*tries_left)
1207     --*tries_left;
1208
1209   return retry;
1210 }
1211
1212 \f
1213 /* Search the keyserver identified by URI for keys matching PATTERN.
1214    On success R_FP has an open stream to read the data.  If
1215    R_HTTP_STATUS is not NULL, the http status code will be stored
1216    there.  */
1217 gpg_error_t
1218 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1219                estream_t *r_fp, unsigned int *r_http_status)
1220 {
1221   gpg_error_t err;
1222   KEYDB_SEARCH_DESC desc;
1223   char fprbuf[2+40+1];
1224   char *hostport = NULL;
1225   char *request = NULL;
1226   estream_t fp = NULL;
1227   int reselect;
1228   unsigned int httpflags;
1229   char *httphost = NULL;
1230   unsigned int tries = SEND_REQUEST_RETRIES;
1231
1232   *r_fp = NULL;
1233
1234   /* Remove search type indicator and adjust PATTERN accordingly.
1235      Note that HKP keyservers like the 0x to be present when searching
1236      by keyid.  We need to re-format the fingerprint and keyids so to
1237      remove the gpg specific force-use-of-this-key flag ("!").  */
1238   err = classify_user_id (pattern, &desc, 1);
1239   if (err)
1240     return err;
1241   switch (desc.mode)
1242     {
1243     case KEYDB_SEARCH_MODE_EXACT:
1244     case KEYDB_SEARCH_MODE_SUBSTR:
1245     case KEYDB_SEARCH_MODE_MAIL:
1246     case KEYDB_SEARCH_MODE_MAILSUB:
1247       pattern = desc.u.name;
1248       break;
1249     case KEYDB_SEARCH_MODE_SHORT_KID:
1250       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1251       pattern = fprbuf;
1252       break;
1253     case KEYDB_SEARCH_MODE_LONG_KID:
1254       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1255                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1256       pattern = fprbuf;
1257       break;
1258     case KEYDB_SEARCH_MODE_FPR16:
1259       fprbuf[0] = '0';
1260       fprbuf[1] = 'x';
1261       bin2hex (desc.u.fpr, 16, fprbuf+2);
1262       pattern = fprbuf;
1263       break;
1264     case KEYDB_SEARCH_MODE_FPR20:
1265     case KEYDB_SEARCH_MODE_FPR:
1266       fprbuf[0] = '0';
1267       fprbuf[1] = 'x';
1268       bin2hex (desc.u.fpr, 20, fprbuf+2);
1269       pattern = fprbuf;
1270       break;
1271     default:
1272       return gpg_error (GPG_ERR_INV_USER_ID);
1273     }
1274
1275   /* Build the request string.  */
1276   reselect = 0;
1277  again:
1278   {
1279     char *searchkey;
1280
1281     xfree (hostport); hostport = NULL;
1282     xfree (httphost); httphost = NULL;
1283     err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1284                           reselect, uri->explicit_port,
1285                           &hostport, &httpflags, &httphost);
1286     if (err)
1287       goto leave;
1288
1289     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1290     if (!searchkey)
1291       {
1292         err = gpg_error_from_syserror ();
1293         goto leave;
1294       }
1295
1296     xfree (request);
1297     request = strconcat (hostport,
1298                          "/pks/lookup?op=index&options=mr&search=",
1299                          searchkey,
1300                          NULL);
1301     xfree (searchkey);
1302     if (!request)
1303       {
1304         err = gpg_error_from_syserror ();
1305         goto leave;
1306       }
1307   }
1308
1309   /* Send the request.  */
1310   err = send_request (ctrl, request, hostport, httphost, httpflags,
1311                       NULL, NULL, &fp, r_http_status);
1312   if (handle_send_request_error (err, request, &tries))
1313     {
1314       reselect = 1;
1315       goto again;
1316     }
1317   if (err)
1318     goto leave;
1319
1320   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1321   if (err)
1322     goto leave;
1323
1324   /* Peek at the response.  */
1325   {
1326     int c = es_getc (fp);
1327     if (c == -1)
1328       {
1329         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1330         log_error ("error reading response: %s\n", gpg_strerror (err));
1331         goto leave;
1332       }
1333     if (c == '<')
1334       {
1335         /* The document begins with a '<': Assume a HTML response,
1336            which we don't support.  */
1337         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1338         goto leave;
1339       }
1340     es_ungetc (c, fp);
1341   }
1342
1343   /* Return the read stream.  */
1344   *r_fp = fp;
1345   fp = NULL;
1346
1347  leave:
1348   es_fclose (fp);
1349   xfree (request);
1350   xfree (hostport);
1351   xfree (httphost);
1352   return err;
1353 }
1354
1355
1356 /* Get the key described key the KEYSPEC string from the keyserver
1357    identified by URI.  On success R_FP has an open stream to read the
1358    data.  The data will be provided in a format GnuPG can import
1359    (either a binary OpenPGP message or an armored one).  */
1360 gpg_error_t
1361 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1362 {
1363   gpg_error_t err;
1364   KEYDB_SEARCH_DESC desc;
1365   char kidbuf[2+40+1];
1366   const char *exactname = NULL;
1367   char *searchkey = NULL;
1368   char *hostport = NULL;
1369   char *request = NULL;
1370   estream_t fp = NULL;
1371   int reselect;
1372   char *httphost = NULL;
1373   unsigned int httpflags;
1374   unsigned int tries = SEND_REQUEST_RETRIES;
1375
1376   *r_fp = NULL;
1377
1378   /* Remove search type indicator and adjust PATTERN accordingly.
1379      Note that HKP keyservers like the 0x to be present when searching
1380      by keyid.  We need to re-format the fingerprint and keyids so to
1381      remove the gpg specific force-use-of-this-key flag ("!").  */
1382   err = classify_user_id (keyspec, &desc, 1);
1383   if (err)
1384     return err;
1385   switch (desc.mode)
1386     {
1387     case KEYDB_SEARCH_MODE_SHORT_KID:
1388       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1389       break;
1390     case KEYDB_SEARCH_MODE_LONG_KID:
1391       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1392                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1393       break;
1394     case KEYDB_SEARCH_MODE_FPR20:
1395     case KEYDB_SEARCH_MODE_FPR:
1396       /* This is a v4 fingerprint. */
1397       kidbuf[0] = '0';
1398       kidbuf[1] = 'x';
1399       bin2hex (desc.u.fpr, 20, kidbuf+2);
1400       break;
1401
1402     case KEYDB_SEARCH_MODE_EXACT:
1403       exactname = desc.u.name;
1404       break;
1405
1406     case KEYDB_SEARCH_MODE_FPR16:
1407       log_error ("HKP keyservers do not support v3 fingerprints\n");
1408     default:
1409       return gpg_error (GPG_ERR_INV_USER_ID);
1410     }
1411
1412   searchkey = http_escape_string (exactname? exactname : kidbuf,
1413                                   EXTRA_ESCAPE_CHARS);
1414   if (!searchkey)
1415     {
1416       err = gpg_error_from_syserror ();
1417       goto leave;
1418     }
1419
1420   reselect = 0;
1421  again:
1422   /* Build the request string.  */
1423   xfree (hostport); hostport = NULL;
1424   xfree (httphost); httphost = NULL;
1425   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1426                         reselect, uri->explicit_port,
1427                         &hostport, &httpflags, &httphost);
1428   if (err)
1429     goto leave;
1430
1431   xfree (request);
1432   request = strconcat (hostport,
1433                        "/pks/lookup?op=get&options=mr&search=",
1434                        searchkey,
1435                        exactname? "&exact=on":"",
1436                        NULL);
1437   if (!request)
1438     {
1439       err = gpg_error_from_syserror ();
1440       goto leave;
1441     }
1442
1443   /* Send the request.  */
1444   err = send_request (ctrl, request, hostport, httphost, httpflags,
1445                       NULL, NULL, &fp, NULL);
1446   if (handle_send_request_error (err, request, &tries))
1447     {
1448       reselect = 1;
1449       goto again;
1450     }
1451   if (err)
1452     goto leave;
1453
1454   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1455   if (err)
1456     goto leave;
1457
1458   /* Return the read stream and close the HTTP context.  */
1459   *r_fp = fp;
1460   fp = NULL;
1461
1462  leave:
1463   es_fclose (fp);
1464   xfree (request);
1465   xfree (hostport);
1466   xfree (httphost);
1467   xfree (searchkey);
1468   return err;
1469 }
1470
1471
1472
1473 \f
1474 /* Callback parameters for put_post_cb.  */
1475 struct put_post_parm_s
1476 {
1477   char *datastring;
1478 };
1479
1480
1481 /* Helper for ks_hkp_put.  */
1482 static gpg_error_t
1483 put_post_cb (void *opaque, http_t http)
1484 {
1485   struct put_post_parm_s *parm = opaque;
1486   gpg_error_t err = 0;
1487   estream_t fp;
1488   size_t len;
1489
1490   fp = http_get_write_ptr (http);
1491   len = strlen (parm->datastring);
1492
1493   es_fprintf (fp,
1494               "Content-Type: application/x-www-form-urlencoded\r\n"
1495               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1496   http_start_data (http);
1497   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1498     err = gpg_error_from_syserror ();
1499   return err;
1500 }
1501
1502
1503 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI.  */
1504 gpg_error_t
1505 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1506 {
1507   gpg_error_t err;
1508   char *hostport = NULL;
1509   char *request = NULL;
1510   estream_t fp = NULL;
1511   struct put_post_parm_s parm;
1512   char *armored = NULL;
1513   int reselect;
1514   char *httphost = NULL;
1515   unsigned int httpflags;
1516   unsigned int tries = SEND_REQUEST_RETRIES;
1517
1518   parm.datastring = NULL;
1519
1520   err = armor_data (&armored, data, datalen);
1521   if (err)
1522     goto leave;
1523
1524   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1525   if (!parm.datastring)
1526     {
1527       err = gpg_error_from_syserror ();
1528       goto leave;
1529     }
1530   xfree (armored);
1531   armored = NULL;
1532
1533   /* Build the request string.  */
1534   reselect = 0;
1535  again:
1536   xfree (hostport); hostport = NULL;
1537   xfree (httphost); httphost = NULL;
1538   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1539                         reselect, uri->explicit_port,
1540                         &hostport, &httpflags, &httphost);
1541   if (err)
1542     goto leave;
1543
1544   xfree (request);
1545   request = strconcat (hostport, "/pks/add", NULL);
1546   if (!request)
1547     {
1548       err = gpg_error_from_syserror ();
1549       goto leave;
1550     }
1551
1552   /* Send the request.  */
1553   err = send_request (ctrl, request, hostport, httphost, 0,
1554                       put_post_cb, &parm, &fp, NULL);
1555   if (handle_send_request_error (err, request, &tries))
1556     {
1557       reselect = 1;
1558       goto again;
1559     }
1560   if (err)
1561     goto leave;
1562
1563  leave:
1564   es_fclose (fp);
1565   xfree (parm.datastring);
1566   xfree (armored);
1567   xfree (request);
1568   xfree (hostport);
1569   xfree (httphost);
1570   return err;
1571 }