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
5 * This file is part of GnuPG.
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.
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.
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/>.
27 #ifdef HAVE_W32_SYSTEM
28 # ifdef HAVE_WINSOCK2_H
29 # include <winsock2.h>
32 #else /*!HAVE_W32_SYSTEM*/
33 # include <sys/types.h>
34 # include <sys/socket.h>
36 #endif /*!HAVE_W32_SYSTEM*/
41 #include "dns-stuff.h"
42 #include "ks-engine.h"
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. */
48 # define EAI_OVERFLOW EAI_FAIL
50 #ifdef HAVE_W32_SYSTEM
52 # define EAI_SYSTEM WSAEINVAL
57 /* Number of seconds after a host is marked as resurrected. */
58 #define RESURRECT_INTERVAL (3600*3) /* 3 hours */
60 /* To match the behaviour of our old gpgkeys helper code we escape
61 more characters than actually needed. */
62 #define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
64 /* How many redirections do we allow. */
65 #define MAX_REDIRECTS 2
67 /* Number of retries done for a dead host etc. */
68 #define SEND_REQUEST_RETRIES 3
70 /* Objects used to maintain information about hosts. */
72 typedef struct hostinfo_s *hostinfo_t;
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
80 int poolidx; /* Index into POOL with the used host. -1 if not set. */
81 unsigned int v4:1; /* Host supports AF_INET. */
82 unsigned int v6:1; /* Host supports AF_INET6. */
83 unsigned int onion:1;/* NAME is an onion (Tor HS) address. */
84 unsigned int dead:1; /* Host is currently unresponsive. */
85 time_t died_at; /* The time the host was marked dead. If this is
86 0 the host has been manually marked dead. */
87 char *cname; /* Canonical name of the host. Only set if this
88 is a pool or NAME has a numerical IP address. */
89 char *v4addr; /* A string with the v4 IP address of the host.
90 NULL if NAME has a numeric IP address or no v4
91 address is available. */
92 char *v6addr; /* A string with the v6 IP address of the host.
93 NULL if NAME has a numeric IP address or no v6
94 address is available. */
95 unsigned short port; /* The port used by the host, 0 if unknown. */
96 char name[1]; /* The hostname. */
100 /* An array of hostinfo_t for all hosts requested by the caller or
101 resolved from a pool name and its allocated size.*/
102 static hostinfo_t *hosttable;
103 static int hosttable_size;
105 /* The number of host slots we initially allocate for HOSTTABLE. */
106 #define INITIAL_HOSTTABLE_SIZE 10
109 /* Create a new hostinfo object, fill in NAME and put it into
110 HOSTTABLE. Return the index into hosttable on success or -1 on
113 create_new_hostinfo (const char *name)
115 hostinfo_t hi, *newtable;
119 hi = xtrymalloc (sizeof *hi + strlen (name));
122 strcpy (hi->name, name);
125 hi->lastused = (time_t)(-1);
126 hi->lastfail = (time_t)(-1);
137 /* Add it to the hosttable. */
138 for (idx=0; idx < hosttable_size; idx++)
144 /* Need to extend the hosttable. */
145 newsize = hosttable_size + INITIAL_HOSTTABLE_SIZE;
146 newtable = xtryrealloc (hosttable, newsize * sizeof *hosttable);
152 hosttable = newtable;
153 idx = hosttable_size;
154 hosttable_size = newsize;
156 hosttable[idx++] = hi;
157 while (idx < hosttable_size)
158 hosttable[idx++] = NULL;
164 /* Find the host NAME in our table. Return the index into the
165 hosttable or -1 if not found. */
167 find_hostinfo (const char *name)
171 for (idx=0; idx < hosttable_size; idx++)
172 if (hosttable[idx] && !ascii_strcasecmp (hosttable[idx]->name, name))
179 sort_hostpool (const void *xa, const void *xb)
184 assert (a >= 0 && a < hosttable_size);
185 assert (b >= 0 && b < hosttable_size);
186 assert (hosttable[a]);
187 assert (hosttable[b]);
189 return ascii_strcasecmp (hosttable[a]->name, hosttable[b]->name);
193 /* Return true if the host with the hosttable index TBLIDX is in POOL. */
195 host_in_pool_p (int *pool, int tblidx)
199 for (i=0; (pidx = pool[i]) != -1; i++)
200 if (pidx == tblidx && hosttable[pidx])
207 host_is_alive (hostinfo_t hi, time_t curtime)
214 return 0; /* manually marked dead */
215 if (hi->died_at + RESURRECT_INTERVAL <= curtime
216 || hi->died_at > curtime)
219 log_info ("resurrected host '%s'", hi->name);
225 /* Select a random host. Consult TABLE which indices into the global
226 hosttable. Returns index into TABLE or -1 if no host could be
229 select_random_host (int *table)
236 curtime = gnupg_get_time ();
237 /* We create a new table so that we randomly select only from
238 currently alive hosts. */
239 for (idx=0; (pidx = table[idx]) != -1; idx++)
240 if (hosttable[pidx] && host_is_alive (hosttable[pidx], curtime))
243 tbl = xtryrealloc(tbl, tblsize * sizeof *tbl);
245 return -1; /* memory allocation failed! */
246 tbl[tblsize-1] = pidx;
249 return -1; /* No hosts. */
251 if (tblsize == 1) /* Save a get_uint_nonce. */
254 pidx = tbl[get_uint_nonce () % tblsize];
261 /* Figure out if a set of DNS records looks like a pool. */
263 arecords_is_pool (dns_addrinfo_t aibuf)
269 for (ai = aibuf; ai; ai = ai->next)
271 if (ai->family == AF_INET6)
273 else if (ai->family == AF_INET)
277 return n_v6 > 1 || n_v4 > 1;
281 /* Add the host AI under the NAME into the HOSTTABLE. If PORT is not
282 zero, it specifies which port to use to talk to the host. If NAME
283 specifies a pool (as indicated by IS_POOL), update the given
284 reference table accordingly. */
286 add_host (const char *name, int is_pool,
287 const dns_addrinfo_t ai, unsigned short port,
288 int *reftbl, size_t reftblsize, int *refidx)
296 idx = find_hostinfo (name);
298 if (!is_pool && !is_ip_address (name))
300 /* This is a hostname but not a pool. Use the name
301 as given without going through resolve_dns_addr. */
302 tmphost = xtrystrdup (name);
304 tmperr = gpg_error_from_syserror ();
310 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
311 DNS_WITHBRACKET, &tmphost);
312 if (tmphost && is_ip_address (tmphost))
318 log_info ("resolve_dns_addr failed while checking '%s': %s\n",
319 name, gpg_strerror (tmperr));
321 else if ((*refidx) + 1 >= reftblsize)
323 log_error ("resolve_dns_addr for '%s': '%s'"
324 " [index table full - ignored]\n", name, tmphost);
328 if (!is_pool && is_ip_address (name))
329 /* Update the original entry. */
332 tmpidx = find_hostinfo (tmphost);
333 log_info ("resolve_dns_addr for '%s': '%s'%s\n",
335 tmpidx == -1? "" : " [already known]");
337 if (tmpidx == -1) /* Create a new entry. */
338 tmpidx = create_new_hostinfo (tmphost);
342 log_error ("map_host for '%s' problem: %s - '%s'"
344 name, strerror (errno), tmphost);
346 else /* Set or update the entry. */
351 hosttable[tmpidx]->port = port;
356 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
361 log_info ("resolve_dns_addr failed: %s\n",
362 gpg_strerror (tmperr));
370 if (ai->family == AF_INET6)
372 hosttable[tmpidx]->v6 = 1;
373 xfree (hosttable[tmpidx]->v6addr);
374 hosttable[tmpidx]->v6addr = ipaddr;
376 else if (ai->family == AF_INET)
378 hosttable[tmpidx]->v4 = 1;
379 xfree (hosttable[tmpidx]->v4addr);
380 hosttable[tmpidx]->v4addr = ipaddr;
385 for (i=0; i < *refidx; i++)
386 if (reftbl[i] == tmpidx)
388 if (!(i < *refidx) && tmpidx != idx)
389 reftbl[(*refidx)++] = tmpidx;
396 /* Map the host name NAME to the actual to be used host name. This
397 * allows us to manage round robin DNS names. We use our own strategy
398 * to choose one of the hosts. For example we skip those hosts which
399 * failed for some time and we stick to one host for a time
400 * independent of DNS retry times. If FORCE_RESELECT is true a new
401 * host is always selected. If SRVTAG is NULL no service record
402 * lookup will be done, if it is set that service name is used. The
403 * selected host is stored as a malloced string at R_HOST; on error
404 * NULL is stored. If we know the port used by the selected host from
405 * a service record, a string representation is written to R_PORTSTR,
406 * otherwise it is left untouched. If R_HTTPFLAGS is not NULL it will
407 * receive flags which are to be passed to http_open. If R_HTTPHOST
408 * is not NULL a malloced name of the host is stored there; this might
409 * be different from R_HOST in case it has been selected from a
412 map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
413 char **r_host, char *r_portstr,
414 unsigned int *r_httpflags, char **r_httphost)
427 /* No hostname means localhost. */
430 *r_host = xtrystrdup ("localhost");
431 return *r_host? 0 : gpg_error_from_syserror ();
434 /* See whether the host is in our table. */
435 idx = find_hostinfo (name);
436 if (idx == -1 && is_onion_address (name))
438 idx = create_new_hostinfo (name);
440 return gpg_error_from_syserror ();
446 /* We never saw this host. Allocate a new entry. */
447 dns_addrinfo_t aibuf, ai;
453 struct srventry *srvs;
454 unsigned int srvscount;
457 reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
459 return gpg_error_from_syserror ();
462 idx = create_new_hostinfo (name);
465 err = gpg_error_from_syserror ();
471 if (srvtag && !is_ip_address (name))
473 /* Check for SRV records. */
474 err = get_dns_srv (name, srvtag, NULL, &srvs, &srvscount);
484 is_pool = srvscount > 1;
486 for (i = 0; i < srvscount; i++)
488 err = resolve_dns_name (srvs[i].target, 0,
489 AF_UNSPEC, SOCK_STREAM,
494 add_host (name, is_pool, ai, srvs[i].port,
495 reftbl, reftblsize, &refidx);
502 /* Find all A records for this entry and put them into the pool
504 err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
507 log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
512 /* First figure out whether this is a pool. For a pool we
513 use a different strategy than for a plain server: We use
514 the canonical name of the pool as the virtual host along
515 with the IP addresses. If it is not a pool, we use the
518 is_pool = arecords_is_pool (aibuf);
519 if (is_pool && cname)
525 for (ai = aibuf; ai; ai = ai->next)
527 if (ai->family != AF_INET && ai->family != AF_INET6)
529 if (opt.disable_ipv4 && ai->family == AF_INET)
533 add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
538 free_dns_addrinfo (aibuf);
540 if (refidx && is_pool)
543 hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
546 err = gpg_error_from_syserror ();
547 log_error ("shrinking index table in map_host failed: %s\n",
552 qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool);
558 curtime = gnupg_get_time ();
562 /* Deal with the pool name before selecting a host. */
565 *r_httphost = xtrystrdup (hi->cname? hi->cname : hi->name);
567 return gpg_error_from_syserror ();
570 /* If the currently selected host is now marked dead, force a
574 else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
575 && hosttable[hi->poolidx] && !host_is_alive (hosttable[hi->poolidx], curtime))
578 /* Select a host if needed. */
579 if (hi->poolidx == -1)
581 hi->poolidx = select_random_host (hi->pool);
582 if (hi->poolidx == -1)
584 log_error ("no alive host found in pool '%s'\n", name);
590 return gpg_error (GPG_ERR_NO_KEYSERVER);
594 assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
595 hi = hosttable[hi->poolidx];
598 else if (r_httphost && is_ip_address (hi->name))
600 /* This is a numerical IP address and not a pool. We want to
601 * find the canonical name so that it can be used in the HTTP
602 * Host header. Fixme: We should store that name in the
604 dns_addrinfo_t aibuf, ai;
607 err = resolve_dns_name (hi->name, 0, 0, SOCK_STREAM, &aibuf, NULL);
610 for (ai = aibuf; ai; ai = ai->next)
612 if (ai->family == AF_INET6
613 || (!opt.disable_ipv4 && ai->family == AF_INET))
615 err = resolve_dns_addr (ai->addr, ai->addrlen, 0, &host);
618 /* Okay, we return the first found name. */
625 free_dns_addrinfo (aibuf);
628 if (!host_is_alive (hi, curtime))
630 log_error ("host '%s' marked as dead\n", hi->name);
636 return gpg_error (GPG_ERR_NO_KEYSERVER);
641 /* If the hosttable does not indicate that a certain host
642 supports IPv<N>, we explicit set the corresponding http
643 flags. The reason for this is that a host might be listed in
644 a pool as not v6 only but actually support v6 when later
645 the name is resolved by our http layer. */
647 *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
649 *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
651 /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
652 addresses because the http module detects this itself. This
653 also allows us to use an onion address without Tor mode being
657 *r_host = xtrystrdup (hi->name);
660 err = gpg_error_from_syserror ();
669 snprintf (r_portstr, 6 /* five digits and the sentinel */,
675 /* Mark the host NAME as dead. NAME may be given as an URL. Returns
676 true if a host was really marked as dead or was already marked dead
677 (e.g. by a concurrent session). */
679 mark_host_dead (const char *name)
682 char *host_buffer = NULL;
683 parsed_uri_t parsed_uri = NULL;
686 if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
688 if (parsed_uri->v6lit)
690 host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
692 log_error ("out of core in mark_host_dead");
696 host = parsed_uri->host;
701 if (host && *host && strcmp (host, "localhost"))
706 idx = find_hostinfo (host);
710 log_info ("marking host '%s' as dead%s\n",
711 hi->name, hi->dead? " (again)":"");
713 hi->died_at = gnupg_get_time ();
720 http_release_parsed_uri (parsed_uri);
726 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
729 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
733 int idx, idx2, idx3, n, is_alive;
736 if (!name || !*name || !strcmp (name, "localhost"))
739 idx = find_hostinfo (name);
741 return gpg_error (GPG_ERR_NOT_FOUND);
743 curtime = gnupg_get_time ();
745 is_alive = host_is_alive (hi, curtime);
746 if (alive && !is_alive)
749 err = ks_printf_help (ctrl, "marking '%s' as alive", name);
751 else if (!alive && is_alive)
754 hi->died_at = 0; /* Manually set dead. */
755 err = ks_printf_help (ctrl, "marking '%s' as dead", name);
758 /* If the host is a pool mark all member hosts. */
759 if (!err && hi->pool)
761 for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
763 assert (n >= 0 && n < hosttable_size);
767 /* Do not mark a host from a pool dead if it is also a
768 member in another pool. */
769 for (idx3=0; idx3 < hosttable_size; idx3++)
772 && hosttable[idx3]->pool
774 && host_in_pool_p (hosttable[idx3]->pool, n))
777 if (idx3 < hosttable_size)
778 continue; /* Host is also a member of another pool. */
784 is_alive = host_is_alive (hi2, curtime);
785 if (alive && !is_alive)
788 err = ks_printf_help (ctrl, "marking '%s' as alive",
791 else if (!alive && is_alive)
794 hi2->died_at = 0; /* Manually set dead. */
795 err = ks_printf_help (ctrl, "marking '%s' as dead",
805 /* Debug function to print the entire hosttable. */
807 ks_hkp_print_hosttable (ctrl_t ctrl)
817 err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
821 curtime = gnupg_get_time ();
822 for (idx=0; idx < hosttable_size; idx++)
823 if ((hi=hosttable[idx]))
825 if (hi->dead && hi->died_at)
827 died = elapsed_time_string (hi->died_at, curtime);
828 diedstr = died? died : "error";
831 diedstr = died = NULL;
832 err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
834 hi->onion? "O" : hi->v6? "6":" ",
838 hi->v6addr? " v6=":"",
839 hi->v6addr? hi->v6addr:"",
840 hi->v4addr? " v4=":"",
841 hi->v4addr? hi->v4addr:"",
850 err = ks_printf_help (ctrl, " . %s", hi->cname);
856 init_membuf (&mb, 256);
857 put_membuf_printf (&mb, " . -->");
858 for (idx2=0; hi->pool[idx2] != -1; idx2++)
860 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
861 if (hi->poolidx == hi->pool[idx2])
862 put_membuf_printf (&mb, "*");
864 put_membuf( &mb, "", 1);
865 p = get_membuf (&mb, NULL);
867 return gpg_error_from_syserror ();
868 err = ks_print_help (ctrl, p);
879 /* Print a help output for the schemata supported by this module. */
881 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
884 "Handler for HKP URLs:\n"
886 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
889 "Supported methods: search, get, put\n";
892 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
893 const char data2[] = " hkp\n hkps";
895 const char data2[] = " hkp";
899 err = ks_print_help (ctrl, data2);
900 else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
901 || !strcmp (uri->scheme, "hkps")))
902 err = ks_print_help (ctrl, data);
910 /* Build the remote part of the URL from SCHEME, HOST and an optional
911 * PORT. If NO_SRV is set no SRV record lookup will be done. Returns
912 * an allocated string at R_HOSTPORT or NULL on failure. If
913 * R_HTTPHOST is not NULL it receives a malloced string with the
914 * hostname; this may be different from HOST if HOST is selected from
917 make_host_part (ctrl_t ctrl,
918 const char *scheme, const char *host, unsigned short port,
919 int force_reselect, int no_srv,
920 char **r_hostport, unsigned int *r_httpflags, char **r_httphost)
929 if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
932 srvtag = no_srv? NULL : "pgpkey-https";
934 else /* HKP or HTTP. */
937 srvtag = no_srv? NULL : "pgpkey-http";
941 err = map_host (ctrl, host, srvtag, force_reselect,
942 &hostname, portstr, r_httpflags, r_httphost);
946 /* If map_host did not return a port (from a SRV record) but a port
947 * has been specified (implicitly or explicitly) then use that port.
948 * In the case that a port was not specified (which is probably a
949 * bug in https.c) we will set up defaults. */
952 else if (!*portstr && port)
953 snprintf (portstr, sizeof portstr, "%hu", port);
954 else if (!strcmp (scheme,"https"))
955 strcpy (portstr, "443");
957 strcpy (portstr, "11371");
959 if (*hostname != '[' && is_ip_address (hostname) == 6)
960 *r_hostport = strconcat (scheme, "://[", hostname, "]:", portstr, NULL);
962 *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
971 return gpg_error_from_syserror ();
977 /* Resolve all known keyserver names and update the hosttable. This
978 is mainly useful for debugging because the resolving is anyway done
981 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
984 char *hostport = NULL;
986 /* NB: With an explicitly given port we do not want to consult a
987 * service record because that might be in conflict with the port
988 * from such a service record. */
989 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
990 1, uri->explicit_port,
991 &hostport, NULL, NULL);
994 err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
995 uri->scheme, uri->host, uri->port,
1000 err = ks_printf_help (ctrl, "%s", hostport);
1007 /* Reload (SIGHUP) action for this module. We mark all host alive
1008 * even those which have been manually shot. */
1010 ks_hkp_reload (void)
1015 for (idx=count=0; idx < hosttable_size; idx++)
1017 hi = hosttable[idx];
1026 log_info ("number of resurrected hosts: %d", count);
1030 /* Send an HTTP request. On success returns an estream object at
1031 R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is
1032 not NULL it will be used as HTTP "Host" header. If POST_CB is not
1033 NULL a post request is used and that callback is called to allow
1034 writing the post data. If R_HTTP_STATUS is not NULL, the http
1035 status code will be stored there. */
1037 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
1038 const char *httphost, unsigned int httpflags,
1039 gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
1040 estream_t *r_fp, unsigned int *r_http_status)
1043 http_session_t session = NULL;
1045 int redirects_left = MAX_REDIRECTS;
1046 estream_t fp = NULL;
1047 char *request_buffer = NULL;
1051 err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
1054 http_session_set_log_cb (session, cert_log_cb);
1057 err = http_open (&http,
1058 post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1061 /* fixme: AUTH */ NULL,
1063 |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1064 |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)
1065 |(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)),
1069 /*FIXME curl->srvtag*/NULL);
1072 fp = http_get_write_ptr (http);
1073 /* Avoid caches to get the most recent copy of the key. We set
1074 both the Pragma and Cache-Control versions of the header, so
1075 we're good with both HTTP 1.0 and 1.1. */
1076 es_fputs ("Pragma: no-cache\r\n"
1077 "Cache-Control: no-cache\r\n", fp);
1079 err = post_cb (post_cb_value, http);
1082 http_start_data (http);
1084 err = gpg_error_from_syserror ();
1089 /* Fixme: After a redirection we show the old host name. */
1090 log_error (_("error connecting to '%s': %s\n"),
1091 hostportstr, gpg_strerror (err));
1095 /* Wait for the response. */
1096 dirmngr_tick (ctrl);
1097 err = http_wait_response (http);
1100 log_error (_("error reading HTTP response for '%s': %s\n"),
1101 hostportstr, gpg_strerror (err));
1105 if (http_get_tls_info (http, NULL))
1107 /* Update the httpflags so that a redirect won't fallback to an
1108 unencrypted connection. */
1109 httpflags |= HTTP_FLAG_FORCE_TLS;
1113 *r_http_status = http_get_status_code (http);
1115 switch (http_get_status_code (http))
1119 break; /* Success. */
1125 const char *s = http_get_header (http, "Location");
1127 log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1128 request, s?s:"[none]", http_get_status_code (http));
1129 if (s && *s && redirects_left-- )
1131 xfree (request_buffer);
1132 request_buffer = xtrystrdup (s);
1135 request = request_buffer;
1136 http_close (http, 0);
1140 err = gpg_error_from_syserror ();
1143 err = gpg_error (GPG_ERR_NO_DATA);
1144 log_error (_("too many redirections\n"));
1149 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1153 log_error (_("error accessing '%s': http status %u\n"),
1154 request, http_get_status_code (http));
1155 err = gpg_error (GPG_ERR_NO_DATA);
1159 /* FIXME: We should register a permanent redirection and whether a
1160 host has ever used TLS so that future calls will always use
1163 fp = http_get_read_ptr (http);
1166 err = gpg_error (GPG_ERR_BUG);
1170 /* Return the read stream and close the HTTP context. */
1172 http_close (http, 1);
1176 http_close (http, 0);
1177 http_session_release (session);
1178 xfree (request_buffer);
1183 /* Helper to evaluate the error code ERR form a send_request() call
1184 with REQUEST. The function returns true if the caller shall try
1185 again. TRIES_LEFT points to a variable to track the number of
1186 retries; this function decrements it and won't return true if it is
1189 handle_send_request_error (gpg_error_t err, const char *request,
1190 unsigned int *tries_left)
1194 /* Fixme: Should we disable all hosts of a protocol family if a
1195 * request for an address of that familiy returned ENETDOWN? */
1197 switch (gpg_err_code (err))
1199 case GPG_ERR_ECONNREFUSED:
1204 sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
1205 if (sock == ASSUAN_INVALID_FD)
1206 log_info ("(it seems Tor is not running)\n");
1208 assuan_sock_close (sock);
1211 case GPG_ERR_ENETUNREACH:
1212 case GPG_ERR_ENETDOWN:
1213 case GPG_ERR_UNKNOWN_HOST:
1214 case GPG_ERR_NETWORK:
1215 if (mark_host_dead (request) && *tries_left)
1219 case GPG_ERR_ETIMEDOUT:
1222 log_info ("selecting a different host due to a timeout\n");
1238 /* Search the keyserver identified by URI for keys matching PATTERN.
1239 On success R_FP has an open stream to read the data. If
1240 R_HTTP_STATUS is not NULL, the http status code will be stored
1243 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1244 estream_t *r_fp, unsigned int *r_http_status)
1247 KEYDB_SEARCH_DESC desc;
1248 char fprbuf[2+40+1];
1249 char *hostport = NULL;
1250 char *request = NULL;
1251 estream_t fp = NULL;
1253 unsigned int httpflags;
1254 char *httphost = NULL;
1255 unsigned int tries = SEND_REQUEST_RETRIES;
1259 /* Remove search type indicator and adjust PATTERN accordingly.
1260 Note that HKP keyservers like the 0x to be present when searching
1261 by keyid. We need to re-format the fingerprint and keyids so to
1262 remove the gpg specific force-use-of-this-key flag ("!"). */
1263 err = classify_user_id (pattern, &desc, 1);
1268 case KEYDB_SEARCH_MODE_EXACT:
1269 case KEYDB_SEARCH_MODE_SUBSTR:
1270 case KEYDB_SEARCH_MODE_MAIL:
1271 case KEYDB_SEARCH_MODE_MAILSUB:
1272 pattern = desc.u.name;
1274 case KEYDB_SEARCH_MODE_SHORT_KID:
1275 snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1278 case KEYDB_SEARCH_MODE_LONG_KID:
1279 snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1280 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1283 case KEYDB_SEARCH_MODE_FPR16:
1286 bin2hex (desc.u.fpr, 16, fprbuf+2);
1289 case KEYDB_SEARCH_MODE_FPR20:
1290 case KEYDB_SEARCH_MODE_FPR:
1293 bin2hex (desc.u.fpr, 20, fprbuf+2);
1297 return gpg_error (GPG_ERR_INV_USER_ID);
1300 /* Build the request string. */
1306 xfree (hostport); hostport = NULL;
1307 xfree (httphost); httphost = NULL;
1308 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1309 reselect, uri->explicit_port,
1310 &hostport, &httpflags, &httphost);
1314 searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1317 err = gpg_error_from_syserror ();
1322 request = strconcat (hostport,
1323 "/pks/lookup?op=index&options=mr&search=",
1329 err = gpg_error_from_syserror ();
1334 /* Send the request. */
1335 err = send_request (ctrl, request, hostport, httphost, httpflags,
1336 NULL, NULL, &fp, r_http_status);
1337 if (handle_send_request_error (err, request, &tries))
1345 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1349 /* Peek at the response. */
1351 int c = es_getc (fp);
1354 err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1355 log_error ("error reading response: %s\n", gpg_strerror (err));
1360 /* The document begins with a '<': Assume a HTML response,
1361 which we don't support. */
1362 err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1368 /* Return the read stream. */
1381 /* Get the key described key the KEYSPEC string from the keyserver
1382 identified by URI. On success R_FP has an open stream to read the
1383 data. The data will be provided in a format GnuPG can import
1384 (either a binary OpenPGP message or an armored one). */
1386 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1389 KEYDB_SEARCH_DESC desc;
1390 char kidbuf[2+40+1];
1391 const char *exactname = NULL;
1392 char *searchkey = NULL;
1393 char *hostport = NULL;
1394 char *request = NULL;
1395 estream_t fp = NULL;
1397 char *httphost = NULL;
1398 unsigned int httpflags;
1399 unsigned int tries = SEND_REQUEST_RETRIES;
1403 /* Remove search type indicator and adjust PATTERN accordingly.
1404 Note that HKP keyservers like the 0x to be present when searching
1405 by keyid. We need to re-format the fingerprint and keyids so to
1406 remove the gpg specific force-use-of-this-key flag ("!"). */
1407 err = classify_user_id (keyspec, &desc, 1);
1412 case KEYDB_SEARCH_MODE_SHORT_KID:
1413 snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1415 case KEYDB_SEARCH_MODE_LONG_KID:
1416 snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1417 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1419 case KEYDB_SEARCH_MODE_FPR20:
1420 case KEYDB_SEARCH_MODE_FPR:
1421 /* This is a v4 fingerprint. */
1424 bin2hex (desc.u.fpr, 20, kidbuf+2);
1427 case KEYDB_SEARCH_MODE_EXACT:
1428 exactname = desc.u.name;
1431 case KEYDB_SEARCH_MODE_FPR16:
1432 log_error ("HKP keyservers do not support v3 fingerprints\n");
1434 return gpg_error (GPG_ERR_INV_USER_ID);
1437 searchkey = http_escape_string (exactname? exactname : kidbuf,
1438 EXTRA_ESCAPE_CHARS);
1441 err = gpg_error_from_syserror ();
1447 /* Build the request string. */
1448 xfree (hostport); hostport = NULL;
1449 xfree (httphost); httphost = NULL;
1450 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1451 reselect, uri->explicit_port,
1452 &hostport, &httpflags, &httphost);
1457 request = strconcat (hostport,
1458 "/pks/lookup?op=get&options=mr&search=",
1460 exactname? "&exact=on":"",
1464 err = gpg_error_from_syserror ();
1468 /* Send the request. */
1469 err = send_request (ctrl, request, hostport, httphost, httpflags,
1470 NULL, NULL, &fp, NULL);
1471 if (handle_send_request_error (err, request, &tries))
1479 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1483 /* Return the read stream and close the HTTP context. */
1499 /* Callback parameters for put_post_cb. */
1500 struct put_post_parm_s
1506 /* Helper for ks_hkp_put. */
1508 put_post_cb (void *opaque, http_t http)
1510 struct put_post_parm_s *parm = opaque;
1511 gpg_error_t err = 0;
1515 fp = http_get_write_ptr (http);
1516 len = strlen (parm->datastring);
1519 "Content-Type: application/x-www-form-urlencoded\r\n"
1520 "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1521 http_start_data (http);
1522 if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1523 err = gpg_error_from_syserror ();
1528 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
1530 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1533 char *hostport = NULL;
1534 char *request = NULL;
1535 estream_t fp = NULL;
1536 struct put_post_parm_s parm;
1537 char *armored = NULL;
1539 char *httphost = NULL;
1540 unsigned int httpflags;
1541 unsigned int tries = SEND_REQUEST_RETRIES;
1543 parm.datastring = NULL;
1545 err = armor_data (&armored, data, datalen);
1549 parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1550 if (!parm.datastring)
1552 err = gpg_error_from_syserror ();
1558 /* Build the request string. */
1561 xfree (hostport); hostport = NULL;
1562 xfree (httphost); httphost = NULL;
1563 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1564 reselect, uri->explicit_port,
1565 &hostport, &httpflags, &httphost);
1570 request = strconcat (hostport, "/pks/add", NULL);
1573 err = gpg_error_from_syserror ();
1577 /* Send the request. */
1578 err = send_request (ctrl, request, hostport, httphost, 0,
1579 put_post_cb, &parm, &fp, NULL);
1580 if (handle_send_request_error (err, request, &tries))
1590 xfree (parm.datastring);