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