dirmngr: Do PTR lookups only for 'keyserver --hosttable'.
[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   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, NULL, httphost, HTTP_FLAG_TRUST_DEF);
1127   if (err)
1128     goto leave;
1129   http_session_set_log_cb (session, cert_log_cb);
1130
1131  once_more:
1132   err = http_open (&http,
1133                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1134                    request,
1135                    httphost,
1136                    /* fixme: AUTH */ NULL,
1137                    (httpflags
1138                     |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1139                     |(dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0)
1140                     |(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)),
1141                    ctrl->http_proxy,
1142                    session,
1143                    NULL,
1144                    /*FIXME curl->srvtag*/NULL);
1145   if (!err)
1146     {
1147       fp = http_get_write_ptr (http);
1148       /* Avoid caches to get the most recent copy of the key.  We set
1149          both the Pragma and Cache-Control versions of the header, so
1150          we're good with both HTTP 1.0 and 1.1.  */
1151       es_fputs ("Pragma: no-cache\r\n"
1152                 "Cache-Control: no-cache\r\n", fp);
1153       if (post_cb)
1154         err = post_cb (post_cb_value, http);
1155       if (!err)
1156         {
1157           http_start_data (http);
1158           if (es_ferror (fp))
1159             err = gpg_error_from_syserror ();
1160         }
1161     }
1162   if (err)
1163     {
1164       /* Fixme: After a redirection we show the old host name.  */
1165       log_error (_("error connecting to '%s': %s\n"),
1166                  hostportstr, gpg_strerror (err));
1167       goto leave;
1168     }
1169
1170   /* Wait for the response.  */
1171   dirmngr_tick (ctrl);
1172   err = http_wait_response (http);
1173   if (err)
1174     {
1175       log_error (_("error reading HTTP response for '%s': %s\n"),
1176                  hostportstr, gpg_strerror (err));
1177       goto leave;
1178     }
1179
1180   if (http_get_tls_info (http, NULL))
1181     {
1182       /* Update the httpflags so that a redirect won't fallback to an
1183          unencrypted connection.  */
1184       httpflags |= HTTP_FLAG_FORCE_TLS;
1185     }
1186
1187   if (r_http_status)
1188     *r_http_status = http_get_status_code (http);
1189
1190   switch (http_get_status_code (http))
1191     {
1192     case 200:
1193       err = 0;
1194       break; /* Success.  */
1195
1196     case 301:
1197     case 302:
1198     case 307:
1199       {
1200         const char *s = http_get_header (http, "Location");
1201
1202         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1203                   request, s?s:"[none]", http_get_status_code (http));
1204         if (s && *s && redirects_left-- )
1205           {
1206             xfree (request_buffer);
1207             request_buffer = xtrystrdup (s);
1208             if (request_buffer)
1209               {
1210                 request = request_buffer;
1211                 http_close (http, 0);
1212                 http = NULL;
1213                 goto once_more;
1214               }
1215             err = gpg_error_from_syserror ();
1216           }
1217         else
1218           err = gpg_error (GPG_ERR_NO_DATA);
1219         log_error (_("too many redirections\n"));
1220       }
1221       goto leave;
1222
1223     case 501:
1224       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1225       goto leave;
1226
1227     default:
1228       log_error (_("error accessing '%s': http status %u\n"),
1229                  request, http_get_status_code (http));
1230       err = gpg_error (GPG_ERR_NO_DATA);
1231       goto leave;
1232     }
1233
1234   /* FIXME: We should register a permanent redirection and whether a
1235      host has ever used TLS so that future calls will always use
1236      TLS. */
1237
1238   fp = http_get_read_ptr (http);
1239   if (!fp)
1240     {
1241       err = gpg_error (GPG_ERR_BUG);
1242       goto leave;
1243     }
1244
1245   /* Return the read stream and close the HTTP context.  */
1246   *r_fp = fp;
1247   http_close (http, 1);
1248   http = NULL;
1249
1250  leave:
1251   http_close (http, 0);
1252   http_session_release (session);
1253   xfree (request_buffer);
1254   return err;
1255 }
1256
1257
1258 /* Helper to evaluate the error code ERR from a send_request() call
1259    with REQUEST.  The function returns true if the caller shall try
1260    again.  TRIES_LEFT points to a variable to track the number of
1261    retries; this function decrements it and won't return true if it is
1262    down to zero. */
1263 static int
1264 handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
1265                            unsigned int *tries_left)
1266 {
1267   int retry = 0;
1268
1269   /* Fixme: Should we disable all hosts of a protocol family if a
1270    * request for an address of that familiy returned ENETDOWN?  */
1271
1272   switch (gpg_err_code (err))
1273     {
1274     case GPG_ERR_ECONNREFUSED:
1275       if (tor_not_running_p (ctrl))
1276         break; /* A retry does not make sense.  */
1277       /* Okay: Tor is up or --use-tor is not used.  */
1278       /*FALLTHRU*/
1279     case GPG_ERR_ENETUNREACH:
1280     case GPG_ERR_ENETDOWN:
1281     case GPG_ERR_UNKNOWN_HOST:
1282     case GPG_ERR_NETWORK:
1283       if (mark_host_dead (request) && *tries_left)
1284         retry = 1;
1285       break;
1286
1287     case GPG_ERR_ETIMEDOUT:
1288       if (*tries_left)
1289         {
1290           log_info ("selecting a different host due to a timeout\n");
1291           retry = 1;
1292         }
1293       break;
1294
1295     case GPG_ERR_EACCES:
1296       if (dirmngr_use_tor ())
1297         {
1298           log_info ("(Tor configuration problem)\n");
1299           dirmngr_status (ctrl, "WARNING", "tor_config_problem 0",
1300                           "Please check that the \"SocksPort\" flag "
1301                           "\"IPv6Traffic\" is set in torrc", NULL);
1302         }
1303       break;
1304
1305     default:
1306       break;
1307     }
1308
1309   if (*tries_left)
1310     --*tries_left;
1311
1312   return retry;
1313 }
1314
1315 \f
1316 /* Search the keyserver identified by URI for keys matching PATTERN.
1317    On success R_FP has an open stream to read the data.  If
1318    R_HTTP_STATUS is not NULL, the http status code will be stored
1319    there.  */
1320 gpg_error_t
1321 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1322                estream_t *r_fp, unsigned int *r_http_status)
1323 {
1324   gpg_error_t err;
1325   KEYDB_SEARCH_DESC desc;
1326   char fprbuf[2+40+1];
1327   char *hostport = NULL;
1328   char *request = NULL;
1329   estream_t fp = NULL;
1330   int reselect;
1331   unsigned int httpflags;
1332   char *httphost = NULL;
1333   unsigned int tries = SEND_REQUEST_RETRIES;
1334
1335   *r_fp = NULL;
1336
1337   /* Remove search type indicator and adjust PATTERN accordingly.
1338      Note that HKP keyservers like the 0x to be present when searching
1339      by keyid.  We need to re-format the fingerprint and keyids so to
1340      remove the gpg specific force-use-of-this-key flag ("!").  */
1341   err = classify_user_id (pattern, &desc, 1);
1342   if (err)
1343     return err;
1344   switch (desc.mode)
1345     {
1346     case KEYDB_SEARCH_MODE_EXACT:
1347     case KEYDB_SEARCH_MODE_SUBSTR:
1348     case KEYDB_SEARCH_MODE_MAIL:
1349     case KEYDB_SEARCH_MODE_MAILSUB:
1350       pattern = desc.u.name;
1351       break;
1352     case KEYDB_SEARCH_MODE_SHORT_KID:
1353       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1354       pattern = fprbuf;
1355       break;
1356     case KEYDB_SEARCH_MODE_LONG_KID:
1357       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1358                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1359       pattern = fprbuf;
1360       break;
1361     case KEYDB_SEARCH_MODE_FPR16:
1362       fprbuf[0] = '0';
1363       fprbuf[1] = 'x';
1364       bin2hex (desc.u.fpr, 16, fprbuf+2);
1365       pattern = fprbuf;
1366       break;
1367     case KEYDB_SEARCH_MODE_FPR20:
1368     case KEYDB_SEARCH_MODE_FPR:
1369       fprbuf[0] = '0';
1370       fprbuf[1] = 'x';
1371       bin2hex (desc.u.fpr, 20, fprbuf+2);
1372       pattern = fprbuf;
1373       break;
1374     default:
1375       return gpg_error (GPG_ERR_INV_USER_ID);
1376     }
1377
1378   /* Build the request string.  */
1379   reselect = 0;
1380  again:
1381   {
1382     char *searchkey;
1383
1384     xfree (hostport); hostport = NULL;
1385     xfree (httphost); httphost = NULL;
1386     err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1387                           reselect, uri->explicit_port,
1388                           &hostport, &httpflags, &httphost);
1389     if (err)
1390       goto leave;
1391
1392     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1393     if (!searchkey)
1394       {
1395         err = gpg_error_from_syserror ();
1396         goto leave;
1397       }
1398
1399     xfree (request);
1400     request = strconcat (hostport,
1401                          "/pks/lookup?op=index&options=mr&search=",
1402                          searchkey,
1403                          NULL);
1404     xfree (searchkey);
1405     if (!request)
1406       {
1407         err = gpg_error_from_syserror ();
1408         goto leave;
1409       }
1410   }
1411
1412   /* Send the request.  */
1413   err = send_request (ctrl, request, hostport, httphost, httpflags,
1414                       NULL, NULL, &fp, r_http_status);
1415   if (handle_send_request_error (ctrl, err, request, &tries))
1416     {
1417       reselect = 1;
1418       goto again;
1419     }
1420   if (err)
1421     goto leave;
1422
1423   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1424   if (err)
1425     goto leave;
1426
1427   /* Peek at the response.  */
1428   {
1429     int c = es_getc (fp);
1430     if (c == -1)
1431       {
1432         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1433         log_error ("error reading response: %s\n", gpg_strerror (err));
1434         goto leave;
1435       }
1436     if (c == '<')
1437       {
1438         /* The document begins with a '<': Assume a HTML response,
1439            which we don't support.  */
1440         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1441         goto leave;
1442       }
1443     es_ungetc (c, fp);
1444   }
1445
1446   /* Return the read stream.  */
1447   *r_fp = fp;
1448   fp = NULL;
1449
1450  leave:
1451   es_fclose (fp);
1452   xfree (request);
1453   xfree (hostport);
1454   xfree (httphost);
1455   return err;
1456 }
1457
1458
1459 /* Get the key described key the KEYSPEC string from the keyserver
1460    identified by URI.  On success R_FP has an open stream to read the
1461    data.  The data will be provided in a format GnuPG can import
1462    (either a binary OpenPGP message or an armored one).  */
1463 gpg_error_t
1464 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1465 {
1466   gpg_error_t err;
1467   KEYDB_SEARCH_DESC desc;
1468   char kidbuf[2+40+1];
1469   const char *exactname = NULL;
1470   char *searchkey = NULL;
1471   char *hostport = NULL;
1472   char *request = NULL;
1473   estream_t fp = NULL;
1474   int reselect;
1475   char *httphost = NULL;
1476   unsigned int httpflags;
1477   unsigned int tries = SEND_REQUEST_RETRIES;
1478
1479   *r_fp = NULL;
1480
1481   /* Remove search type indicator and adjust PATTERN accordingly.
1482      Note that HKP keyservers like the 0x to be present when searching
1483      by keyid.  We need to re-format the fingerprint and keyids so to
1484      remove the gpg specific force-use-of-this-key flag ("!").  */
1485   err = classify_user_id (keyspec, &desc, 1);
1486   if (err)
1487     return err;
1488   switch (desc.mode)
1489     {
1490     case KEYDB_SEARCH_MODE_SHORT_KID:
1491       snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1492       break;
1493     case KEYDB_SEARCH_MODE_LONG_KID:
1494       snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1495                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1496       break;
1497     case KEYDB_SEARCH_MODE_FPR20:
1498     case KEYDB_SEARCH_MODE_FPR:
1499       /* This is a v4 fingerprint. */
1500       kidbuf[0] = '0';
1501       kidbuf[1] = 'x';
1502       bin2hex (desc.u.fpr, 20, kidbuf+2);
1503       break;
1504
1505     case KEYDB_SEARCH_MODE_EXACT:
1506       exactname = desc.u.name;
1507       break;
1508
1509     case KEYDB_SEARCH_MODE_FPR16:
1510       log_error ("HKP keyservers do not support v3 fingerprints\n");
1511     default:
1512       return gpg_error (GPG_ERR_INV_USER_ID);
1513     }
1514
1515   searchkey = http_escape_string (exactname? exactname : kidbuf,
1516                                   EXTRA_ESCAPE_CHARS);
1517   if (!searchkey)
1518     {
1519       err = gpg_error_from_syserror ();
1520       goto leave;
1521     }
1522
1523   reselect = 0;
1524  again:
1525   /* Build the request string.  */
1526   xfree (hostport); hostport = NULL;
1527   xfree (httphost); httphost = NULL;
1528   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1529                         reselect, uri->explicit_port,
1530                         &hostport, &httpflags, &httphost);
1531   if (err)
1532     goto leave;
1533
1534   xfree (request);
1535   request = strconcat (hostport,
1536                        "/pks/lookup?op=get&options=mr&search=",
1537                        searchkey,
1538                        exactname? "&exact=on":"",
1539                        NULL);
1540   if (!request)
1541     {
1542       err = gpg_error_from_syserror ();
1543       goto leave;
1544     }
1545
1546   /* Send the request.  */
1547   err = send_request (ctrl, request, hostport, httphost, httpflags,
1548                       NULL, NULL, &fp, NULL);
1549   if (handle_send_request_error (ctrl, err, request, &tries))
1550     {
1551       reselect = 1;
1552       goto again;
1553     }
1554   if (err)
1555     goto leave;
1556
1557   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1558   if (err)
1559     goto leave;
1560
1561   /* Return the read stream and close the HTTP context.  */
1562   *r_fp = fp;
1563   fp = NULL;
1564
1565  leave:
1566   es_fclose (fp);
1567   xfree (request);
1568   xfree (hostport);
1569   xfree (httphost);
1570   xfree (searchkey);
1571   return err;
1572 }
1573
1574
1575
1576 \f
1577 /* Callback parameters for put_post_cb.  */
1578 struct put_post_parm_s
1579 {
1580   char *datastring;
1581 };
1582
1583
1584 /* Helper for ks_hkp_put.  */
1585 static gpg_error_t
1586 put_post_cb (void *opaque, http_t http)
1587 {
1588   struct put_post_parm_s *parm = opaque;
1589   gpg_error_t err = 0;
1590   estream_t fp;
1591   size_t len;
1592
1593   fp = http_get_write_ptr (http);
1594   len = strlen (parm->datastring);
1595
1596   es_fprintf (fp,
1597               "Content-Type: application/x-www-form-urlencoded\r\n"
1598               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1599   http_start_data (http);
1600   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1601     err = gpg_error_from_syserror ();
1602   return err;
1603 }
1604
1605
1606 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI.  */
1607 gpg_error_t
1608 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1609 {
1610   gpg_error_t err;
1611   char *hostport = NULL;
1612   char *request = NULL;
1613   estream_t fp = NULL;
1614   struct put_post_parm_s parm;
1615   char *armored = NULL;
1616   int reselect;
1617   char *httphost = NULL;
1618   unsigned int httpflags;
1619   unsigned int tries = SEND_REQUEST_RETRIES;
1620
1621   parm.datastring = NULL;
1622
1623   err = armor_data (&armored, data, datalen);
1624   if (err)
1625     goto leave;
1626
1627   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1628   if (!parm.datastring)
1629     {
1630       err = gpg_error_from_syserror ();
1631       goto leave;
1632     }
1633   xfree (armored);
1634   armored = NULL;
1635
1636   /* Build the request string.  */
1637   reselect = 0;
1638  again:
1639   xfree (hostport); hostport = NULL;
1640   xfree (httphost); httphost = NULL;
1641   err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1642                         reselect, uri->explicit_port,
1643                         &hostport, &httpflags, &httphost);
1644   if (err)
1645     goto leave;
1646
1647   xfree (request);
1648   request = strconcat (hostport, "/pks/add", NULL);
1649   if (!request)
1650     {
1651       err = gpg_error_from_syserror ();
1652       goto leave;
1653     }
1654
1655   /* Send the request.  */
1656   err = send_request (ctrl, request, hostport, httphost, 0,
1657                       put_post_cb, &parm, &fp, NULL);
1658   if (handle_send_request_error (ctrl, err, request, &tries))
1659     {
1660       reselect = 1;
1661       goto again;
1662     }
1663   if (err)
1664     goto leave;
1665
1666  leave:
1667   es_fclose (fp);
1668   xfree (parm.datastring);
1669   xfree (armored);
1670   xfree (request);
1671   xfree (hostport);
1672   xfree (httphost);
1673   return err;
1674 }