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*/
40 #include "../common/userids.h"
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 enum ks_protocol { KS_PROTOCOL_HKP, KS_PROTOCOL_HKPS, KS_PROTOCOL_MAX };
72 /* Objects used to maintain information about hosts. */
74 typedef struct hostinfo_s *hostinfo_t;
77 time_t lastfail; /* Time we tried to connect and failed. */
78 time_t lastused; /* Time of last use. */
79 int *pool; /* An array with indices into HOSTTABLE or NULL
80 if NAME is not a pool name. */
81 size_t pool_len; /* Length of POOL. */
82 size_t pool_size; /* Allocated size of POOL. */
83 #define MAX_POOL_SIZE 128
84 int poolidx; /* Index into POOL with the used host. -1 if not set. */
85 unsigned int v4:1; /* Host supports AF_INET. */
86 unsigned int v6:1; /* Host supports AF_INET6. */
87 unsigned int onion:1;/* NAME is an onion (Tor HS) address. */
88 unsigned int dead:1; /* Host is currently unresponsive. */
89 unsigned int iporname_valid:1; /* The field IPORNAME below is valid */
90 /* (but may be NULL) */
91 unsigned int did_a_lookup:1; /* Have we done an A lookup yet? */
92 unsigned int did_srv_lookup:2; /* One bit per protocol indicating
93 whether we already did a SRV
95 time_t died_at; /* The time the host was marked dead. If this is
96 0 the host has been manually marked dead. */
97 char *cname; /* Canonical name of the host. Only set if this
98 is a pool or NAME has a numerical IP address. */
99 char *iporname; /* Numeric IP address or name for printing. */
100 unsigned short port[KS_PROTOCOL_MAX];
101 /* The port used by the host for all protocols, 0
103 char name[1]; /* The hostname. */
107 /* An array of hostinfo_t for all hosts requested by the caller or
108 resolved from a pool name and its allocated size.*/
109 static hostinfo_t *hosttable;
110 static int hosttable_size;
112 /* The number of host slots we initially allocate for HOSTTABLE. */
113 #define INITIAL_HOSTTABLE_SIZE 10
116 /* Create a new hostinfo object, fill in NAME and put it into
117 HOSTTABLE. Return the index into hosttable on success or -1 on
120 create_new_hostinfo (const char *name)
122 hostinfo_t hi, *newtable;
126 hi = xtrymalloc (sizeof *hi + strlen (name));
129 strcpy (hi->name, name);
134 hi->lastused = (time_t)(-1);
135 hi->lastfail = (time_t)(-1);
140 hi->did_a_lookup = 0;
141 hi->did_srv_lookup = 0;
142 hi->iporname_valid = 0;
146 hi->port[KS_PROTOCOL_HKP] = 0;
147 hi->port[KS_PROTOCOL_HKPS] = 0;
149 /* Add it to the hosttable. */
150 for (idx=0; idx < hosttable_size; idx++)
156 /* Need to extend the hosttable. */
157 newsize = hosttable_size + INITIAL_HOSTTABLE_SIZE;
158 newtable = xtryrealloc (hosttable, newsize * sizeof *hosttable);
164 hosttable = newtable;
165 idx = hosttable_size;
166 hosttable_size = newsize;
168 hosttable[idx++] = hi;
169 while (idx < hosttable_size)
170 hosttable[idx++] = NULL;
176 /* Find the host NAME in our table. Return the index into the
177 hosttable or -1 if not found. */
179 find_hostinfo (const char *name)
183 for (idx=0; idx < hosttable_size; idx++)
184 if (hosttable[idx] && !ascii_strcasecmp (hosttable[idx]->name, name))
191 sort_hostpool (const void *xa, const void *xb)
196 assert (a >= 0 && a < hosttable_size);
197 assert (b >= 0 && b < hosttable_size);
198 assert (hosttable[a]);
199 assert (hosttable[b]);
201 return ascii_strcasecmp (hosttable[a]->name, hosttable[b]->name);
205 /* Return true if the host with the hosttable index TBLIDX is in HI->pool. */
207 host_in_pool_p (hostinfo_t hi, int tblidx)
211 for (i = 0; i < hi->pool_len && (pidx = hi->pool[i]) != -1; i++)
212 if (pidx == tblidx && hosttable[pidx])
218 /* Select a random host. Consult HI->pool which indices into the global
219 hosttable. Returns index into HI->pool or -1 if no host could be
222 select_random_host (hostinfo_t hi)
228 /* We create a new table so that we randomly select only from
229 currently alive hosts. */
230 for (idx = 0, tblsize = 0;
231 idx < hi->pool_len && (pidx = hi->pool[idx]) != -1;
233 if (hosttable[pidx] && !hosttable[pidx]->dead)
236 return -1; /* No hosts. */
238 tbl = xtrymalloc (tblsize * sizeof *tbl);
241 for (idx = 0, tblsize = 0;
242 idx < hi->pool_len && (pidx = hi->pool[idx]) != -1;
244 if (hosttable[pidx] && !hosttable[pidx]->dead)
245 tbl[tblsize++] = pidx;
247 if (tblsize == 1) /* Save a get_uint_nonce. */
250 pidx = tbl[get_uint_nonce () % tblsize];
257 /* Figure out if a set of DNS records looks like a pool. */
259 arecords_is_pool (dns_addrinfo_t aibuf)
265 for (ai = aibuf; ai; ai = ai->next)
267 if (ai->family == AF_INET6)
269 else if (ai->family == AF_INET)
273 return n_v6 > 1 || n_v4 > 1;
277 /* Print a warning iff Tor is not running but Tor has been requested.
278 * Also return true if it is not running. */
280 tor_not_running_p (ctrl_t ctrl)
284 if (!dirmngr_use_tor ())
287 sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
288 if (sock != ASSUAN_INVALID_FD)
290 assuan_sock_close (sock);
294 log_info ("(it seems Tor is not running)\n");
295 dirmngr_status (ctrl, "WARNING", "tor_not_running 0",
296 "Tor is enabled but the local Tor daemon"
297 " seems to be down", NULL);
302 /* Add the host AI under the NAME into the HOSTTABLE. If PORT is not
303 zero, it specifies which port to use to talk to the host for
304 PROTOCOL. If NAME specifies a pool (as indicated by IS_POOL),
305 update the given reference table accordingly. */
307 add_host (const char *name, int is_pool,
308 const dns_addrinfo_t ai,
309 enum ks_protocol protocol, unsigned short port)
317 idx = find_hostinfo (name);
318 host = hosttable[idx];
322 /* For a pool immediately convert the address to a string. */
323 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
324 (DNS_NUMERICHOST | DNS_WITHBRACKET), &tmphost);
326 else if (!is_ip_address (name))
328 /* This is a hostname. Use the name as given without going
329 * through resolve_dns_addr. */
330 tmphost = xtrystrdup (name);
332 tmperr = gpg_error_from_syserror ();
338 /* Do a PTR lookup on AI. If a name was not found the function
339 * returns the numeric address (with brackets). */
340 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
341 DNS_WITHBRACKET, &tmphost);
346 log_info ("resolve_dns_addr failed while checking '%s': %s\n",
347 name, gpg_strerror (tmperr));
349 else if (host->pool_len + 1 >= MAX_POOL_SIZE)
351 log_error ("resolve_dns_addr for '%s': '%s'"
352 " [index table full - ignored]\n", name, tmphost);
356 if (!is_pool && is_ip_address (name))
357 /* Update the original entry. */
360 tmpidx = find_hostinfo (tmphost);
361 log_info ("resolve_dns_addr for '%s': '%s'%s\n",
363 tmpidx == -1? "" : " [already known]");
365 if (tmpidx == -1) /* Create a new entry. */
366 tmpidx = create_new_hostinfo (tmphost);
370 log_error ("map_host for '%s' problem: %s - '%s' [ignored]\n",
371 name, strerror (errno), tmphost);
373 else /* Set or update the entry. */
376 hosttable[tmpidx]->port[protocol] = port;
378 if (ai->family == AF_INET6)
380 hosttable[tmpidx]->v6 = 1;
382 else if (ai->family == AF_INET)
384 hosttable[tmpidx]->v4 = 1;
389 /* If we updated the main entry, we're done. */
393 /* If we updated an existing entry, we're done. */
394 for (i = 0; i < host->pool_len; i++)
395 if (host->pool[i] == tmpidx)
398 /* Otherwise, we need to add it to the pool. Check if there
400 if (host->pool_len + 1 > host->pool_size)
405 if (host->pool_size == 0)
408 new_size = host->pool_size * 2;
410 new_pool = xtryrealloc (host->pool,
411 new_size * sizeof *new_pool);
413 if (new_pool == NULL)
416 host->pool = new_pool;
417 host->pool_size = new_size;
420 /* Finally, add it. */
421 log_assert (host->pool_len < host->pool_size);
422 host->pool[host->pool_len++] = tmpidx;
430 /* Sort the pool of the given hostinfo HI. */
432 hostinfo_sort_pool (hostinfo_t hi)
434 qsort (hi->pool, hi->pool_len, sizeof *hi->pool, sort_hostpool);
437 /* Map the host name NAME to the actual to be used host name. This
438 * allows us to manage round robin DNS names. We use our own strategy
439 * to choose one of the hosts. For example we skip those hosts which
440 * failed for some time and we stick to one host for a time
441 * independent of DNS retry times. If FORCE_RESELECT is true a new
442 * host is always selected. If SRVTAG is NULL no service record
443 * lookup will be done, if it is set that service name is used. The
444 * selected host is stored as a malloced string at R_HOST; on error
445 * NULL is stored. If we know the port used by the selected host from
446 * a service record, a string representation is written to R_PORTSTR,
447 * otherwise it is left untouched. If R_HTTPFLAGS is not NULL it will
448 * receive flags which are to be passed to http_open. If R_HTTPHOST
449 * is not NULL a malloced name of the host is stored there; this might
450 * be different from R_HOST in case it has been selected from a
453 map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
454 enum ks_protocol protocol, char **r_host, char *r_portstr,
455 unsigned int *r_httpflags, char **r_httphost)
460 dns_addrinfo_t aibuf, ai;
471 /* No hostname means localhost. */
474 *r_host = xtrystrdup ("localhost");
475 return *r_host? 0 : gpg_error_from_syserror ();
478 /* See whether the host is in our table. */
479 idx = find_hostinfo (name);
482 idx = create_new_hostinfo (name);
484 return gpg_error_from_syserror ();
486 hi->onion = is_onion_address (name);
491 is_pool = hi->pool != NULL;
493 if (srvtag && !is_ip_address (name)
495 && ! (hi->did_srv_lookup & 1 << protocol))
497 struct srventry *srvs;
498 unsigned int srvscount;
500 /* Check for SRV records. */
501 err = get_dns_srv (name, srvtag, NULL, &srvs, &srvscount);
504 if (gpg_err_code (err) == GPG_ERR_ECONNREFUSED)
505 tor_not_running_p (ctrl);
513 is_pool = srvscount > 1;
515 for (i = 0; i < srvscount; i++)
517 err = resolve_dns_name (srvs[i].target, 0,
518 AF_UNSPEC, SOCK_STREAM,
523 add_host (name, is_pool, ai, protocol, srvs[i].port);
530 hi->did_srv_lookup |= 1 << protocol;
533 if (! hi->did_a_lookup
536 /* Find all A records for this entry and put them into the pool
538 err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
541 log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
546 /* First figure out whether this is a pool. For a pool we
547 use a different strategy than for a plain server: We use
548 the canonical name of the pool as the virtual host along
549 with the IP addresses. If it is not a pool, we use the
552 is_pool = arecords_is_pool (aibuf);
553 if (is_pool && cname)
559 for (ai = aibuf; ai; ai = ai->next)
561 if (ai->family != AF_INET && ai->family != AF_INET6)
563 if (opt.disable_ipv4 && ai->family == AF_INET)
565 if (opt.disable_ipv6 && ai->family == AF_INET6)
569 add_host (name, is_pool, ai, 0, 0);
573 hi->did_a_lookup = 1;
576 free_dns_addrinfo (aibuf);
579 hostinfo_sort_pool (hi);
583 /* Deal with the pool name before selecting a host. */
586 *r_httphost = xtrystrdup (hi->cname? hi->cname : hi->name);
588 return gpg_error_from_syserror ();
591 /* If the currently selected host is now marked dead, force a
595 else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
596 && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead)
599 /* Select a host if needed. */
600 if (hi->poolidx == -1)
602 hi->poolidx = select_random_host (hi);
603 if (hi->poolidx == -1)
605 log_error ("no alive host found in pool '%s'\n", name);
611 return gpg_error (GPG_ERR_NO_KEYSERVER);
615 assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
616 hi = hosttable[hi->poolidx];
619 else if (r_httphost && is_ip_address (hi->name))
621 /* This is a numerical IP address and not a pool. We want to
622 * find the canonical name so that it can be used in the HTTP
623 * Host header. Fixme: We should store that name in the
627 err = resolve_dns_name (hi->name, 0, 0, SOCK_STREAM, &aibuf, NULL);
630 for (ai = aibuf; ai; ai = ai->next)
632 if ((!opt.disable_ipv6 && ai->family == AF_INET6)
633 || (!opt.disable_ipv4 && ai->family == AF_INET))
635 err = resolve_dns_addr (ai->addr, ai->addrlen, 0, &host);
638 /* Okay, we return the first found name. */
645 free_dns_addrinfo (aibuf);
650 log_error ("host '%s' marked as dead\n", hi->name);
656 return gpg_error (GPG_ERR_NO_KEYSERVER);
661 /* If the hosttable does not indicate that a certain host
662 supports IPv<N>, we explicit set the corresponding http
663 flags. The reason for this is that a host might be listed in
664 a pool as not v6 only but actually support v6 when later
665 the name is resolved by our http layer. */
667 *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
669 *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
671 /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
672 addresses because the http module detects this itself. This
673 also allows us to use an onion address without Tor mode being
677 *r_host = xtrystrdup (hi->name);
680 err = gpg_error_from_syserror ();
688 if (hi->port[protocol])
689 snprintf (r_portstr, 6 /* five digits and the sentinel */,
690 "%hu", hi->port[protocol]);
695 /* Mark the host NAME as dead. NAME may be given as an URL. Returns
696 true if a host was really marked as dead or was already marked dead
697 (e.g. by a concurrent session). */
699 mark_host_dead (const char *name)
702 char *host_buffer = NULL;
703 parsed_uri_t parsed_uri = NULL;
706 if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
708 if (parsed_uri->v6lit)
710 host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
712 log_error ("out of core in mark_host_dead");
716 host = parsed_uri->host;
721 if (host && *host && strcmp (host, "localhost"))
726 idx = find_hostinfo (host);
730 log_info ("marking host '%s' as dead%s\n",
731 hi->name, hi->dead? " (again)":"");
733 hi->died_at = gnupg_get_time ();
740 http_release_parsed_uri (parsed_uri);
746 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
749 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
753 int idx, idx2, idx3, n;
755 if (!name || !*name || !strcmp (name, "localhost"))
758 idx = find_hostinfo (name);
760 return gpg_error (GPG_ERR_NOT_FOUND);
763 if (alive && hi->dead)
766 err = ks_printf_help (ctrl, "marking '%s' as alive", name);
768 else if (!alive && !hi->dead)
771 hi->died_at = 0; /* Manually set dead. */
772 err = ks_printf_help (ctrl, "marking '%s' as dead", name);
775 /* If the host is a pool mark all member hosts. */
776 if (!err && hi->pool)
779 !err && idx2 < hi->pool_len && (n = hi->pool[idx2]) != -1;
782 assert (n >= 0 && n < hosttable_size);
786 /* Do not mark a host from a pool dead if it is also a
787 member in another pool. */
788 for (idx3=0; idx3 < hosttable_size; idx3++)
791 && hosttable[idx3]->pool
793 && host_in_pool_p (hosttable[idx3], n))
796 if (idx3 < hosttable_size)
797 continue; /* Host is also a member of another pool. */
803 else if (alive && hi2->dead)
806 err = ks_printf_help (ctrl, "marking '%s' as alive",
809 else if (!alive && !hi2->dead)
812 hi2->died_at = 0; /* Manually set dead. */
813 err = ks_printf_help (ctrl, "marking '%s' as dead",
823 /* Debug function to print the entire hosttable. */
825 ks_hkp_print_hosttable (ctrl_t ctrl)
835 err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
839 /* FIXME: We need a lock for the hosttable. */
840 curtime = gnupg_get_time ();
841 for (idx=0; idx < hosttable_size; idx++)
842 if ((hi=hosttable[idx]))
844 if (hi->dead && hi->died_at)
846 died = elapsed_time_string (hi->died_at, curtime);
847 diedstr = died? died : "error";
850 diedstr = died = NULL;
852 if (!hi->iporname_valid)
856 xfree (hi->iporname);
859 /* Do a lookup just for the display purpose. */
860 if (hi->onion || hi->pool)
862 else if (is_ip_address (hi->name))
864 dns_addrinfo_t aibuf, ai;
866 /* Turn the numerical IP address string into an AI and
867 * then do a DNS PTR lookup. */
868 if (!resolve_dns_name (hi->name, 0, 0,
872 if (canon && is_ip_address (canon))
877 for (ai = aibuf; !canon && ai; ai = ai->next)
879 resolve_dns_addr (ai->addr, ai->addrlen,
880 DNS_WITHBRACKET, &canon);
881 if (canon && is_ip_address (canon))
883 /* We already have the numeric IP - no need to
884 * display it a second time. */
890 free_dns_addrinfo (aibuf);
894 dns_addrinfo_t aibuf, ai;
896 /* Get the IP address as a string from a name. Note
897 * that resolve_dns_addr allocates CANON on success
898 * and thus terminates the loop. */
899 if (!resolve_dns_name (hi->name, 0,
900 hi->v6? AF_INET6 : AF_INET,
904 for (ai = aibuf; !canon && ai; ai = ai->next)
906 resolve_dns_addr (ai->addr, ai->addrlen,
907 DNS_NUMERICHOST|DNS_WITHBRACKET,
911 free_dns_addrinfo (aibuf);
914 hi->iporname = canon;
915 hi->iporname_valid = 1;
918 err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s\n",
920 hi->onion? "O" : hi->v6? "6":" ",
924 hi->iporname? " (":"",
925 hi->iporname? hi->iporname : "",
926 hi->iporname? ")":"",
935 err = ks_printf_help (ctrl, " . %s", hi->cname);
941 init_membuf (&mb, 256);
942 put_membuf_printf (&mb, " . -->");
943 for (idx2 = 0; idx2 < hi->pool_len && hi->pool[idx2] != -1; idx2++)
945 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
946 if (hi->poolidx == hi->pool[idx2])
947 put_membuf_printf (&mb, "*");
949 put_membuf( &mb, "", 1);
950 p = get_membuf (&mb, NULL);
952 return gpg_error_from_syserror ();
953 err = ks_print_help (ctrl, p);
964 /* Print a help output for the schemata supported by this module. */
966 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
969 "Handler for HKP URLs:\n"
971 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
974 "Supported methods: search, get, put\n";
977 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
978 const char data2[] = " hkp\n hkps";
980 const char data2[] = " hkp";
984 err = ks_print_help (ctrl, data2);
985 else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
986 || !strcmp (uri->scheme, "hkps")))
987 err = ks_print_help (ctrl, data);
995 /* Build the remote part of the URL from SCHEME, HOST and an optional
996 * PORT. If NO_SRV is set no SRV record lookup will be done. Returns
997 * an allocated string at R_HOSTPORT or NULL on failure. If
998 * R_HTTPHOST is not NULL it receives a malloced string with the
999 * hostname; this may be different from HOST if HOST is selected from
1002 make_host_part (ctrl_t ctrl,
1003 const char *scheme, const char *host, unsigned short port,
1004 int force_reselect, int no_srv,
1005 char **r_hostport, unsigned int *r_httpflags, char **r_httphost)
1011 enum ks_protocol protocol;
1015 if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
1018 srvtag = no_srv? NULL : "pgpkey-https";
1019 protocol = KS_PROTOCOL_HKPS;
1021 else /* HKP or HTTP. */
1024 srvtag = no_srv? NULL : "pgpkey-http";
1025 protocol = KS_PROTOCOL_HKP;
1029 err = map_host (ctrl, host, srvtag, force_reselect, protocol,
1030 &hostname, portstr, r_httpflags, r_httphost);
1034 /* If map_host did not return a port (from a SRV record) but a port
1035 * has been specified (implicitly or explicitly) then use that port.
1036 * In the case that a port was not specified (which is probably a
1037 * bug in https.c) we will set up defaults. */
1040 else if (!*portstr && port)
1041 snprintf (portstr, sizeof portstr, "%hu", port);
1042 else if (!strcmp (scheme,"https"))
1043 strcpy (portstr, "443");
1045 strcpy (portstr, "11371");
1047 if (*hostname != '[' && is_ip_address (hostname) == 6)
1048 *r_hostport = strconcat (scheme, "://[", hostname, "]:", portstr, NULL);
1050 *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
1056 xfree (*r_httphost);
1059 return gpg_error_from_syserror ();
1065 /* Resolve all known keyserver names and update the hosttable. This
1066 is mainly useful for debugging because the resolving is anyway done
1069 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
1072 char *hostport = NULL;
1074 /* NB: With an explicitly given port we do not want to consult a
1075 * service record because that might be in conflict with the port
1076 * from such a service record. */
1077 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1078 1, uri->explicit_port,
1079 &hostport, NULL, NULL);
1082 err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
1083 uri->scheme, uri->host, uri->port,
1084 gpg_strerror (err));
1088 err = ks_printf_help (ctrl, "%s", hostport);
1095 /* Housekeeping function called from the housekeeping thread. It is
1096 used to mark dead hosts alive so that they may be tried again after
1099 ks_hkp_housekeeping (time_t curtime)
1104 for (idx=0; idx < hosttable_size; idx++)
1106 hi = hosttable[idx];
1112 continue; /* Do not resurrect manually shot hosts. */
1113 if (hi->died_at + RESURRECT_INTERVAL <= curtime
1114 || hi->died_at > curtime)
1117 log_info ("resurrected host '%s'", hi->name);
1123 /* Reload (SIGHUP) action for this module. We mark all host alive
1124 * even those which have been manually shot. */
1126 ks_hkp_reload (void)
1131 for (idx=count=0; idx < hosttable_size; idx++)
1133 hi = hosttable[idx];
1136 hi->iporname_valid = 0;
1143 log_info ("number of resurrected hosts: %d", count);
1147 /* Send an HTTP request. On success returns an estream object at
1148 R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is
1149 not NULL it will be used as HTTP "Host" header. If POST_CB is not
1150 NULL a post request is used and that callback is called to allow
1151 writing the post data. If R_HTTP_STATUS is not NULL, the http
1152 status code will be stored there. */
1154 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
1155 const char *httphost, unsigned int httpflags,
1156 gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
1157 estream_t *r_fp, unsigned int *r_http_status)
1160 http_session_t session = NULL;
1162 int redirects_left = MAX_REDIRECTS;
1163 estream_t fp = NULL;
1164 char *request_buffer = NULL;
1165 parsed_uri_t uri = NULL;
1170 err = http_parse_uri (&uri, request, 0);
1173 is_onion = uri->onion;
1175 err = http_session_new (&session, httphost,
1176 ((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0)
1177 | HTTP_FLAG_TRUST_DEF),
1178 gnupg_http_tls_verify_cb, ctrl);
1181 http_session_set_log_cb (session, cert_log_cb);
1182 http_session_set_timeout (session, ctrl->timeout);
1185 err = http_open (&http,
1186 post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1189 /* fixme: AUTH */ NULL,
1191 |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1192 |(dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0)
1193 |(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)
1194 |(opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6 : 0)),
1198 /*FIXME curl->srvtag*/NULL);
1201 fp = http_get_write_ptr (http);
1202 /* Avoid caches to get the most recent copy of the key. We set
1203 both the Pragma and Cache-Control versions of the header, so
1204 we're good with both HTTP 1.0 and 1.1. */
1205 es_fputs ("Pragma: no-cache\r\n"
1206 "Cache-Control: no-cache\r\n", fp);
1208 err = post_cb (post_cb_value, http);
1211 http_start_data (http);
1213 err = gpg_error_from_syserror ();
1218 /* Fixme: After a redirection we show the old host name. */
1219 log_error (_("error connecting to '%s': %s\n"),
1220 hostportstr, gpg_strerror (err));
1224 /* Wait for the response. */
1225 dirmngr_tick (ctrl);
1226 err = http_wait_response (http);
1229 log_error (_("error reading HTTP response for '%s': %s\n"),
1230 hostportstr, gpg_strerror (err));
1234 if (http_get_tls_info (http, NULL))
1236 /* Update the httpflags so that a redirect won't fallback to an
1237 unencrypted connection. */
1238 httpflags |= HTTP_FLAG_FORCE_TLS;
1242 *r_http_status = http_get_status_code (http);
1244 switch (http_get_status_code (http))
1248 break; /* Success. */
1254 const char *s = http_get_header (http, "Location");
1256 log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1257 request, s?s:"[none]", http_get_status_code (http));
1258 if (s && *s && redirects_left-- )
1262 /* Make sure that an onion address only redirects to
1263 * another onion address. */
1264 http_release_parsed_uri (uri);
1266 err = http_parse_uri (&uri, s, 0);
1272 err = gpg_error (GPG_ERR_FORBIDDEN);
1277 xfree (request_buffer);
1278 request_buffer = xtrystrdup (s);
1281 request = request_buffer;
1282 http_close (http, 0);
1286 err = gpg_error_from_syserror ();
1289 err = gpg_error (GPG_ERR_NO_DATA);
1290 log_error (_("too many redirections\n"));
1295 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1299 log_error (_("error accessing '%s': http status %u\n"),
1300 request, http_get_status_code (http));
1301 err = gpg_error (GPG_ERR_NO_DATA);
1305 /* FIXME: We should register a permanent redirection and whether a
1306 host has ever used TLS so that future calls will always use
1309 fp = http_get_read_ptr (http);
1312 err = gpg_error (GPG_ERR_BUG);
1316 /* Return the read stream and close the HTTP context. */
1318 http_close (http, 1);
1322 http_close (http, 0);
1323 http_session_release (session);
1324 xfree (request_buffer);
1325 http_release_parsed_uri (uri);
1330 /* Helper to evaluate the error code ERR from a send_request() call
1331 with REQUEST. The function returns true if the caller shall try
1332 again. TRIES_LEFT points to a variable to track the number of
1333 retries; this function decrements it and won't return true if it is
1336 handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
1337 unsigned int *tries_left)
1341 /* Fixme: Should we disable all hosts of a protocol family if a
1342 * request for an address of that familiy returned ENETDOWN? */
1344 switch (gpg_err_code (err))
1346 case GPG_ERR_ECONNREFUSED:
1347 if (tor_not_running_p (ctrl))
1348 break; /* A retry does not make sense. */
1349 /* Okay: Tor is up or --use-tor is not used. */
1351 case GPG_ERR_ENETUNREACH:
1352 case GPG_ERR_ENETDOWN:
1353 case GPG_ERR_UNKNOWN_HOST:
1354 case GPG_ERR_NETWORK:
1355 case GPG_ERR_EIO: /* Sometimes used by estream cookie functions. */
1356 if (mark_host_dead (request) && *tries_left)
1360 case GPG_ERR_ETIMEDOUT:
1363 log_info ("selecting a different host due to a timeout\n");
1368 case GPG_ERR_EACCES:
1369 if (dirmngr_use_tor ())
1371 log_info ("(Tor configuration problem)\n");
1372 dirmngr_status (ctrl, "WARNING", "tor_config_problem 0",
1373 "Please check that the \"SocksPort\" flag "
1374 "\"IPv6Traffic\" is set in torrc", NULL);
1389 /* Search the keyserver identified by URI for keys matching PATTERN.
1390 On success R_FP has an open stream to read the data. If
1391 R_HTTP_STATUS is not NULL, the http status code will be stored
1394 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1395 estream_t *r_fp, unsigned int *r_http_status)
1398 KEYDB_SEARCH_DESC desc;
1399 char fprbuf[2+40+1];
1400 char *hostport = NULL;
1401 char *request = NULL;
1402 estream_t fp = NULL;
1404 unsigned int httpflags;
1405 char *httphost = NULL;
1406 unsigned int tries = SEND_REQUEST_RETRIES;
1410 /* Remove search type indicator and adjust PATTERN accordingly.
1411 Note that HKP keyservers like the 0x to be present when searching
1412 by keyid. We need to re-format the fingerprint and keyids so to
1413 remove the gpg specific force-use-of-this-key flag ("!"). */
1414 err = classify_user_id (pattern, &desc, 1);
1419 case KEYDB_SEARCH_MODE_EXACT:
1420 case KEYDB_SEARCH_MODE_SUBSTR:
1421 case KEYDB_SEARCH_MODE_MAIL:
1422 case KEYDB_SEARCH_MODE_MAILSUB:
1423 pattern = desc.u.name;
1425 case KEYDB_SEARCH_MODE_SHORT_KID:
1426 snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1429 case KEYDB_SEARCH_MODE_LONG_KID:
1430 snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1431 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1434 case KEYDB_SEARCH_MODE_FPR16:
1437 bin2hex (desc.u.fpr, 16, fprbuf+2);
1440 case KEYDB_SEARCH_MODE_FPR20:
1441 case KEYDB_SEARCH_MODE_FPR:
1444 bin2hex (desc.u.fpr, 20, fprbuf+2);
1448 return gpg_error (GPG_ERR_INV_USER_ID);
1451 /* Build the request string. */
1457 xfree (hostport); hostport = NULL;
1458 xfree (httphost); httphost = NULL;
1459 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1460 reselect, uri->explicit_port,
1461 &hostport, &httpflags, &httphost);
1465 searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1468 err = gpg_error_from_syserror ();
1473 request = strconcat (hostport,
1474 "/pks/lookup?op=index&options=mr&search=",
1480 err = gpg_error_from_syserror ();
1485 /* Send the request. */
1486 err = send_request (ctrl, request, hostport, httphost, httpflags,
1487 NULL, NULL, &fp, r_http_status);
1488 if (handle_send_request_error (ctrl, err, request, &tries))
1496 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1500 /* Peek at the response. */
1502 int c = es_getc (fp);
1505 err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1506 log_error ("error reading response: %s\n", gpg_strerror (err));
1511 /* The document begins with a '<': Assume a HTML response,
1512 which we don't support. */
1513 err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1519 /* Return the read stream. */
1532 /* Get the key described key the KEYSPEC string from the keyserver
1533 identified by URI. On success R_FP has an open stream to read the
1534 data. The data will be provided in a format GnuPG can import
1535 (either a binary OpenPGP message or an armored one). */
1537 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1540 KEYDB_SEARCH_DESC desc;
1541 char kidbuf[2+40+1];
1542 const char *exactname = NULL;
1543 char *searchkey = NULL;
1544 char *hostport = NULL;
1545 char *request = NULL;
1546 estream_t fp = NULL;
1548 char *httphost = NULL;
1549 unsigned int httpflags;
1550 unsigned int tries = SEND_REQUEST_RETRIES;
1554 /* Remove search type indicator and adjust PATTERN accordingly.
1555 Note that HKP keyservers like the 0x to be present when searching
1556 by keyid. We need to re-format the fingerprint and keyids so to
1557 remove the gpg specific force-use-of-this-key flag ("!"). */
1558 err = classify_user_id (keyspec, &desc, 1);
1563 case KEYDB_SEARCH_MODE_SHORT_KID:
1564 snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1566 case KEYDB_SEARCH_MODE_LONG_KID:
1567 snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1568 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1570 case KEYDB_SEARCH_MODE_FPR20:
1571 case KEYDB_SEARCH_MODE_FPR:
1572 /* This is a v4 fingerprint. */
1575 bin2hex (desc.u.fpr, 20, kidbuf+2);
1578 case KEYDB_SEARCH_MODE_EXACT:
1579 exactname = desc.u.name;
1582 case KEYDB_SEARCH_MODE_FPR16:
1583 log_error ("HKP keyservers do not support v3 fingerprints\n");
1586 return gpg_error (GPG_ERR_INV_USER_ID);
1589 searchkey = http_escape_string (exactname? exactname : kidbuf,
1590 EXTRA_ESCAPE_CHARS);
1593 err = gpg_error_from_syserror ();
1599 /* Build the request string. */
1600 xfree (hostport); hostport = NULL;
1601 xfree (httphost); httphost = NULL;
1602 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1603 reselect, uri->explicit_port,
1604 &hostport, &httpflags, &httphost);
1609 request = strconcat (hostport,
1610 "/pks/lookup?op=get&options=mr&search=",
1612 exactname? "&exact=on":"",
1616 err = gpg_error_from_syserror ();
1620 /* Send the request. */
1621 err = send_request (ctrl, request, hostport, httphost, httpflags,
1622 NULL, NULL, &fp, NULL);
1623 if (handle_send_request_error (ctrl, err, request, &tries))
1631 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1635 /* Return the read stream and close the HTTP context. */
1651 /* Callback parameters for put_post_cb. */
1652 struct put_post_parm_s
1658 /* Helper for ks_hkp_put. */
1660 put_post_cb (void *opaque, http_t http)
1662 struct put_post_parm_s *parm = opaque;
1663 gpg_error_t err = 0;
1667 fp = http_get_write_ptr (http);
1668 len = strlen (parm->datastring);
1671 "Content-Type: application/x-www-form-urlencoded\r\n"
1672 "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1673 http_start_data (http);
1674 if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1675 err = gpg_error_from_syserror ();
1680 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
1682 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1685 char *hostport = NULL;
1686 char *request = NULL;
1687 estream_t fp = NULL;
1688 struct put_post_parm_s parm;
1689 char *armored = NULL;
1691 char *httphost = NULL;
1692 unsigned int httpflags;
1693 unsigned int tries = SEND_REQUEST_RETRIES;
1695 parm.datastring = NULL;
1697 err = armor_data (&armored, data, datalen);
1701 parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1702 if (!parm.datastring)
1704 err = gpg_error_from_syserror ();
1710 /* Build the request string. */
1713 xfree (hostport); hostport = NULL;
1714 xfree (httphost); httphost = NULL;
1715 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1716 reselect, uri->explicit_port,
1717 &hostport, &httpflags, &httphost);
1722 request = strconcat (hostport, "/pks/add", NULL);
1725 err = gpg_error_from_syserror ();
1729 /* Send the request. */
1730 err = send_request (ctrl, request, hostport, httphost, 0,
1731 put_post_cb, &parm, &fp, NULL);
1732 if (handle_send_request_error (ctrl, err, request, &tries))
1742 xfree (parm.datastring);