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