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