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)
531 add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
536 free_dns_addrinfo (aibuf);
538 if (refidx && is_pool)
541 hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
544 err = gpg_error_from_syserror ();
545 log_error ("shrinking index table in map_host failed: %s\n",
550 qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool);
556 curtime = gnupg_get_time ();
560 /* Deal with the pool name before selecting a host. */
563 *r_httphost = xtrystrdup (hi->cname? hi->cname : hi->name);
565 return gpg_error_from_syserror ();
568 /* If the currently selected host is now marked dead, force a
572 else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
573 && hosttable[hi->poolidx] && !host_is_alive (hosttable[hi->poolidx], curtime))
576 /* Select a host if needed. */
577 if (hi->poolidx == -1)
579 hi->poolidx = select_random_host (hi->pool);
580 if (hi->poolidx == -1)
582 log_error ("no alive host found in pool '%s'\n", name);
588 return gpg_error (GPG_ERR_NO_KEYSERVER);
592 assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
593 hi = hosttable[hi->poolidx];
596 else if (r_httphost && is_ip_address (hi->name))
598 /* This is a numerical IP address and not a pool. We want to
599 * find the canonical name so that it can be used in the HTTP
600 * Host header. Fixme: We should store that name in the
602 dns_addrinfo_t aibuf, ai;
605 err = resolve_dns_name (hi->name, 0, 0, SOCK_STREAM, &aibuf, NULL);
608 for (ai = aibuf; ai; ai = ai->next)
610 if (ai->family == AF_INET6 || ai->family == AF_INET)
612 err = resolve_dns_addr (ai->addr, ai->addrlen, 0, &host);
615 /* Okay, we return the first found name. */
622 free_dns_addrinfo (aibuf);
625 if (!host_is_alive (hi, curtime))
627 log_error ("host '%s' marked as dead\n", hi->name);
633 return gpg_error (GPG_ERR_NO_KEYSERVER);
638 /* If the hosttable does not indicate that a certain host
639 supports IPv<N>, we explicit set the corresponding http
640 flags. The reason for this is that a host might be listed in
641 a pool as not v6 only but actually support v6 when later
642 the name is resolved by our http layer. */
644 *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
646 *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
648 /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
649 addresses because the http module detects this itself. This
650 also allows us to use an onion address without Tor mode being
654 *r_host = xtrystrdup (hi->name);
657 err = gpg_error_from_syserror ();
666 snprintf (r_portstr, 6 /* five digits and the sentinel */,
672 /* Mark the host NAME as dead. NAME may be given as an URL. Returns
673 true if a host was really marked as dead or was already marked dead
674 (e.g. by a concurrent session). */
676 mark_host_dead (const char *name)
679 char *host_buffer = NULL;
680 parsed_uri_t parsed_uri = NULL;
683 if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
685 if (parsed_uri->v6lit)
687 host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
689 log_error ("out of core in mark_host_dead");
693 host = parsed_uri->host;
698 if (host && *host && strcmp (host, "localhost"))
703 idx = find_hostinfo (host);
707 log_info ("marking host '%s' as dead%s\n",
708 hi->name, hi->dead? " (again)":"");
710 hi->died_at = gnupg_get_time ();
717 http_release_parsed_uri (parsed_uri);
723 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
726 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
730 int idx, idx2, idx3, n, is_alive;
733 if (!name || !*name || !strcmp (name, "localhost"))
736 idx = find_hostinfo (name);
738 return gpg_error (GPG_ERR_NOT_FOUND);
740 curtime = gnupg_get_time ();
742 is_alive = host_is_alive (hi, curtime);
743 if (alive && !is_alive)
746 err = ks_printf_help (ctrl, "marking '%s' as alive", name);
748 else if (!alive && is_alive)
751 hi->died_at = 0; /* Manually set dead. */
752 err = ks_printf_help (ctrl, "marking '%s' as dead", name);
755 /* If the host is a pool mark all member hosts. */
756 if (!err && hi->pool)
758 for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
760 assert (n >= 0 && n < hosttable_size);
764 /* Do not mark a host from a pool dead if it is also a
765 member in another pool. */
766 for (idx3=0; idx3 < hosttable_size; idx3++)
769 && hosttable[idx3]->pool
771 && host_in_pool_p (hosttable[idx3]->pool, n))
774 if (idx3 < hosttable_size)
775 continue; /* Host is also a member of another pool. */
781 is_alive = host_is_alive (hi2, curtime);
782 if (alive && !is_alive)
785 err = ks_printf_help (ctrl, "marking '%s' as alive",
788 else if (!alive && is_alive)
791 hi2->died_at = 0; /* Manually set dead. */
792 err = ks_printf_help (ctrl, "marking '%s' as dead",
802 /* Debug function to print the entire hosttable. */
804 ks_hkp_print_hosttable (ctrl_t ctrl)
814 err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
818 curtime = gnupg_get_time ();
819 for (idx=0; idx < hosttable_size; idx++)
820 if ((hi=hosttable[idx]))
822 if (hi->dead && hi->died_at)
824 died = elapsed_time_string (hi->died_at, curtime);
825 diedstr = died? died : "error";
828 diedstr = died = NULL;
829 err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
831 hi->onion? "O" : hi->v6? "6":" ",
835 hi->v6addr? " v6=":"",
836 hi->v6addr? hi->v6addr:"",
837 hi->v4addr? " v4=":"",
838 hi->v4addr? hi->v4addr:"",
847 err = ks_printf_help (ctrl, " . %s", hi->cname);
853 init_membuf (&mb, 256);
854 put_membuf_printf (&mb, " . -->");
855 for (idx2=0; hi->pool[idx2] != -1; idx2++)
857 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
858 if (hi->poolidx == hi->pool[idx2])
859 put_membuf_printf (&mb, "*");
861 put_membuf( &mb, "", 1);
862 p = get_membuf (&mb, NULL);
864 return gpg_error_from_syserror ();
865 err = ks_print_help (ctrl, p);
876 /* Print a help output for the schemata supported by this module. */
878 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
881 "Handler for HKP URLs:\n"
883 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
886 "Supported methods: search, get, put\n";
889 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
890 const char data2[] = " hkp\n hkps";
892 const char data2[] = " hkp";
896 err = ks_print_help (ctrl, data2);
897 else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
898 || !strcmp (uri->scheme, "hkps")))
899 err = ks_print_help (ctrl, data);
907 /* Build the remote part of the URL from SCHEME, HOST and an optional
908 * PORT. If NO_SRV is set no SRV record lookup will be done. Returns
909 * an allocated string at R_HOSTPORT or NULL on failure. If
910 * R_HTTPHOST is not NULL it receives a malloced string with the
911 * hostname; this may be different from HOST if HOST is selected from
914 make_host_part (ctrl_t ctrl,
915 const char *scheme, const char *host, unsigned short port,
916 int force_reselect, int no_srv,
917 char **r_hostport, unsigned int *r_httpflags, char **r_httphost)
926 if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
929 srvtag = no_srv? NULL : "pgpkey-https";
931 else /* HKP or HTTP. */
934 srvtag = no_srv? NULL : "pgpkey-http";
938 err = map_host (ctrl, host, srvtag, force_reselect,
939 &hostname, portstr, r_httpflags, r_httphost);
943 /* If map_host did not return a port (from a SRV record) but a port
944 * has been specified (implicitly or explicitly) then use that port.
945 * In the case that a port was not specified (which is probably a
946 * bug in https.c) we will set up defaults. */
949 else if (!*portstr && port)
950 snprintf (portstr, sizeof portstr, "%hu", port);
951 else if (!strcmp (scheme,"https"))
952 strcpy (portstr, "443");
954 strcpy (portstr, "11371");
956 if (*hostname != '[' && is_ip_address (hostname) == 6)
957 *r_hostport = strconcat (scheme, "://[", hostname, "]:", portstr, NULL);
959 *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
968 return gpg_error_from_syserror ();
974 /* Resolve all known keyserver names and update the hosttable. This
975 is mainly useful for debugging because the resolving is anyway done
978 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
981 char *hostport = NULL;
983 /* NB: With an explicitly given port we do not want to consult a
984 * service record because that might be in conflict with the port
985 * from such a service record. */
986 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
987 1, uri->explicit_port,
988 &hostport, NULL, NULL);
991 err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
992 uri->scheme, uri->host, uri->port,
997 err = ks_printf_help (ctrl, "%s", hostport);
1004 /* Reload (SIGHUP) action for this module. We mark all host alive
1005 * even those which have been manually shot. */
1007 ks_hkp_reload (void)
1012 for (idx=count=0; idx < hosttable_size; idx++)
1014 hi = hosttable[idx];
1023 log_info ("number of resurrected hosts: %d", count);
1027 /* Send an HTTP request. On success returns an estream object at
1028 R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is
1029 not NULL it will be used as HTTP "Host" header. If POST_CB is not
1030 NULL a post request is used and that callback is called to allow
1031 writing the post data. If R_HTTP_STATUS is not NULL, the http
1032 status code will be stored there. */
1034 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
1035 const char *httphost, unsigned int httpflags,
1036 gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
1037 estream_t *r_fp, unsigned int *r_http_status)
1040 http_session_t session = NULL;
1042 int redirects_left = MAX_REDIRECTS;
1043 estream_t fp = NULL;
1044 char *request_buffer = NULL;
1048 err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
1051 http_session_set_log_cb (session, cert_log_cb);
1054 err = http_open (&http,
1055 post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1058 /* fixme: AUTH */ NULL,
1060 |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1061 |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
1065 /*FIXME curl->srvtag*/NULL);
1068 fp = http_get_write_ptr (http);
1069 /* Avoid caches to get the most recent copy of the key. We set
1070 both the Pragma and Cache-Control versions of the header, so
1071 we're good with both HTTP 1.0 and 1.1. */
1072 es_fputs ("Pragma: no-cache\r\n"
1073 "Cache-Control: no-cache\r\n", fp);
1075 err = post_cb (post_cb_value, http);
1078 http_start_data (http);
1080 err = gpg_error_from_syserror ();
1085 /* Fixme: After a redirection we show the old host name. */
1086 log_error (_("error connecting to '%s': %s\n"),
1087 hostportstr, gpg_strerror (err));
1091 /* Wait for the response. */
1092 dirmngr_tick (ctrl);
1093 err = http_wait_response (http);
1096 log_error (_("error reading HTTP response for '%s': %s\n"),
1097 hostportstr, gpg_strerror (err));
1101 if (http_get_tls_info (http, NULL))
1103 /* Update the httpflags so that a redirect won't fallback to an
1104 unencrypted connection. */
1105 httpflags |= HTTP_FLAG_FORCE_TLS;
1109 *r_http_status = http_get_status_code (http);
1111 switch (http_get_status_code (http))
1115 break; /* Success. */
1121 const char *s = http_get_header (http, "Location");
1123 log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1124 request, s?s:"[none]", http_get_status_code (http));
1125 if (s && *s && redirects_left-- )
1127 xfree (request_buffer);
1128 request_buffer = xtrystrdup (s);
1131 request = request_buffer;
1132 http_close (http, 0);
1136 err = gpg_error_from_syserror ();
1139 err = gpg_error (GPG_ERR_NO_DATA);
1140 log_error (_("too many redirections\n"));
1145 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1149 log_error (_("error accessing '%s': http status %u\n"),
1150 request, http_get_status_code (http));
1151 err = gpg_error (GPG_ERR_NO_DATA);
1155 /* FIXME: We should register a permanent redirection and whether a
1156 host has ever used TLS so that future calls will always use
1159 fp = http_get_read_ptr (http);
1162 err = gpg_error (GPG_ERR_BUG);
1166 /* Return the read stream and close the HTTP context. */
1168 http_close (http, 1);
1172 http_close (http, 0);
1173 http_session_release (session);
1174 xfree (request_buffer);
1179 /* Helper to evaluate the error code ERR form a send_request() call
1180 with REQUEST. The function returns true if the caller shall try
1181 again. TRIES_LEFT points to a variable to track the number of
1182 retries; this function decrements it and won't return true if it is
1185 handle_send_request_error (gpg_error_t err, const char *request,
1186 unsigned int *tries_left)
1190 /* Fixme: Should we disable all hosts of a protocol family if a
1191 * request for an address of that familiy returned ENETDOWN? */
1193 switch (gpg_err_code (err))
1195 case GPG_ERR_ECONNREFUSED:
1200 sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
1201 if (sock == ASSUAN_INVALID_FD)
1202 log_info ("(it seems Tor is not running)\n");
1204 assuan_sock_close (sock);
1207 case GPG_ERR_ENETUNREACH:
1208 case GPG_ERR_ENETDOWN:
1209 case GPG_ERR_UNKNOWN_HOST:
1210 case GPG_ERR_NETWORK:
1211 if (mark_host_dead (request) && *tries_left)
1215 case GPG_ERR_ETIMEDOUT:
1218 log_info ("selecting a different host due to a timeout\n");
1234 /* Search the keyserver identified by URI for keys matching PATTERN.
1235 On success R_FP has an open stream to read the data. If
1236 R_HTTP_STATUS is not NULL, the http status code will be stored
1239 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1240 estream_t *r_fp, unsigned int *r_http_status)
1243 KEYDB_SEARCH_DESC desc;
1244 char fprbuf[2+40+1];
1245 char *hostport = NULL;
1246 char *request = NULL;
1247 estream_t fp = NULL;
1249 unsigned int httpflags;
1250 char *httphost = NULL;
1251 unsigned int tries = SEND_REQUEST_RETRIES;
1255 /* Remove search type indicator and adjust PATTERN accordingly.
1256 Note that HKP keyservers like the 0x to be present when searching
1257 by keyid. We need to re-format the fingerprint and keyids so to
1258 remove the gpg specific force-use-of-this-key flag ("!"). */
1259 err = classify_user_id (pattern, &desc, 1);
1264 case KEYDB_SEARCH_MODE_EXACT:
1265 case KEYDB_SEARCH_MODE_SUBSTR:
1266 case KEYDB_SEARCH_MODE_MAIL:
1267 case KEYDB_SEARCH_MODE_MAILSUB:
1268 pattern = desc.u.name;
1270 case KEYDB_SEARCH_MODE_SHORT_KID:
1271 snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1274 case KEYDB_SEARCH_MODE_LONG_KID:
1275 snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1276 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1279 case KEYDB_SEARCH_MODE_FPR16:
1282 bin2hex (desc.u.fpr, 16, fprbuf+2);
1285 case KEYDB_SEARCH_MODE_FPR20:
1286 case KEYDB_SEARCH_MODE_FPR:
1289 bin2hex (desc.u.fpr, 20, fprbuf+2);
1293 return gpg_error (GPG_ERR_INV_USER_ID);
1296 /* Build the request string. */
1302 xfree (hostport); hostport = NULL;
1303 xfree (httphost); httphost = NULL;
1304 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1305 reselect, uri->explicit_port,
1306 &hostport, &httpflags, &httphost);
1310 searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1313 err = gpg_error_from_syserror ();
1318 request = strconcat (hostport,
1319 "/pks/lookup?op=index&options=mr&search=",
1325 err = gpg_error_from_syserror ();
1330 /* Send the request. */
1331 err = send_request (ctrl, request, hostport, httphost, httpflags,
1332 NULL, NULL, &fp, r_http_status);
1333 if (handle_send_request_error (err, request, &tries))
1341 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1345 /* Peek at the response. */
1347 int c = es_getc (fp);
1350 err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1351 log_error ("error reading response: %s\n", gpg_strerror (err));
1356 /* The document begins with a '<': Assume a HTML response,
1357 which we don't support. */
1358 err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1364 /* Return the read stream. */
1377 /* Get the key described key the KEYSPEC string from the keyserver
1378 identified by URI. On success R_FP has an open stream to read the
1379 data. The data will be provided in a format GnuPG can import
1380 (either a binary OpenPGP message or an armored one). */
1382 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1385 KEYDB_SEARCH_DESC desc;
1386 char kidbuf[2+40+1];
1387 const char *exactname = NULL;
1388 char *searchkey = NULL;
1389 char *hostport = NULL;
1390 char *request = NULL;
1391 estream_t fp = NULL;
1393 char *httphost = NULL;
1394 unsigned int httpflags;
1395 unsigned int tries = SEND_REQUEST_RETRIES;
1399 /* Remove search type indicator and adjust PATTERN accordingly.
1400 Note that HKP keyservers like the 0x to be present when searching
1401 by keyid. We need to re-format the fingerprint and keyids so to
1402 remove the gpg specific force-use-of-this-key flag ("!"). */
1403 err = classify_user_id (keyspec, &desc, 1);
1408 case KEYDB_SEARCH_MODE_SHORT_KID:
1409 snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1411 case KEYDB_SEARCH_MODE_LONG_KID:
1412 snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1413 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1415 case KEYDB_SEARCH_MODE_FPR20:
1416 case KEYDB_SEARCH_MODE_FPR:
1417 /* This is a v4 fingerprint. */
1420 bin2hex (desc.u.fpr, 20, kidbuf+2);
1423 case KEYDB_SEARCH_MODE_EXACT:
1424 exactname = desc.u.name;
1427 case KEYDB_SEARCH_MODE_FPR16:
1428 log_error ("HKP keyservers do not support v3 fingerprints\n");
1430 return gpg_error (GPG_ERR_INV_USER_ID);
1433 searchkey = http_escape_string (exactname? exactname : kidbuf,
1434 EXTRA_ESCAPE_CHARS);
1437 err = gpg_error_from_syserror ();
1443 /* Build the request string. */
1444 xfree (hostport); hostport = NULL;
1445 xfree (httphost); httphost = NULL;
1446 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1447 reselect, uri->explicit_port,
1448 &hostport, &httpflags, &httphost);
1453 request = strconcat (hostport,
1454 "/pks/lookup?op=get&options=mr&search=",
1456 exactname? "&exact=on":"",
1460 err = gpg_error_from_syserror ();
1464 /* Send the request. */
1465 err = send_request (ctrl, request, hostport, httphost, httpflags,
1466 NULL, NULL, &fp, NULL);
1467 if (handle_send_request_error (err, request, &tries))
1475 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1479 /* Return the read stream and close the HTTP context. */
1495 /* Callback parameters for put_post_cb. */
1496 struct put_post_parm_s
1502 /* Helper for ks_hkp_put. */
1504 put_post_cb (void *opaque, http_t http)
1506 struct put_post_parm_s *parm = opaque;
1507 gpg_error_t err = 0;
1511 fp = http_get_write_ptr (http);
1512 len = strlen (parm->datastring);
1515 "Content-Type: application/x-www-form-urlencoded\r\n"
1516 "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1517 http_start_data (http);
1518 if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1519 err = gpg_error_from_syserror ();
1524 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
1526 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1529 char *hostport = NULL;
1530 char *request = NULL;
1531 estream_t fp = NULL;
1532 struct put_post_parm_s parm;
1533 char *armored = NULL;
1535 char *httphost = NULL;
1536 unsigned int httpflags;
1537 unsigned int tries = SEND_REQUEST_RETRIES;
1539 parm.datastring = NULL;
1541 err = armor_data (&armored, data, datalen);
1545 parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1546 if (!parm.datastring)
1548 err = gpg_error_from_syserror ();
1554 /* Build the request string. */
1557 xfree (hostport); hostport = NULL;
1558 xfree (httphost); httphost = NULL;
1559 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1560 reselect, uri->explicit_port,
1561 &hostport, &httpflags, &httphost);
1566 request = strconcat (hostport, "/pks/add", NULL);
1569 err = gpg_error_from_syserror ();
1573 /* Send the request. */
1574 err = send_request (ctrl, request, hostport, httphost, 0,
1575 put_post_cb, &parm, &fp, NULL);
1576 if (handle_send_request_error (err, request, &tries))
1586 xfree (parm.datastring);