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 /* Print a warninng iff Tor is not running but Tor has been requested.
282 * Also return true if it is not running. */
284 tor_not_running_p (ctrl_t ctrl)
288 if (!dirmngr_use_tor ())
291 sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR);
292 if (sock != ASSUAN_INVALID_FD)
294 assuan_sock_close (sock);
298 log_info ("(it seems Tor is not running)\n");
299 dirmngr_status (ctrl, "WARNING", "tor_not_running 0",
300 "Tor is enabled but the local Tor daemon"
301 " seems to be down", NULL);
306 /* Add the host AI under the NAME into the HOSTTABLE. If PORT is not
307 zero, it specifies which port to use to talk to the host. If NAME
308 specifies a pool (as indicated by IS_POOL), update the given
309 reference table accordingly. */
311 add_host (const char *name, int is_pool,
312 const dns_addrinfo_t ai, unsigned short port,
313 int *reftbl, size_t reftblsize, int *refidx)
321 idx = find_hostinfo (name);
325 /* For a pool immediately convert the address to a string. */
326 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
327 (DNS_NUMERICHOST | DNS_WITHBRACKET), &tmphost);
330 else if (!is_ip_address (name))
332 /* This is a hostname. Use the name as given without going
333 * through resolve_dns_addr. */
334 tmphost = xtrystrdup (name);
336 tmperr = gpg_error_from_syserror ();
342 /* Do a PTR lookup on AI. If a name was not found the function
343 * returns the numeric address (with brackets) and we set a flag
344 * so that we know that the conversion to a numerical string has
345 * already be done. */
346 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
347 DNS_WITHBRACKET, &tmphost);
348 if (tmphost && is_ip_address (tmphost))
354 log_info ("resolve_dns_addr failed while checking '%s': %s\n",
355 name, gpg_strerror (tmperr));
357 else if ((*refidx) + 1 >= reftblsize)
359 log_error ("resolve_dns_addr for '%s': '%s'"
360 " [index table full - ignored]\n", name, tmphost);
364 if (!is_pool && is_ip_address (name))
365 /* Update the original entry. */
368 tmpidx = find_hostinfo (tmphost);
369 log_info ("resolve_dns_addr for '%s': '%s'%s\n",
371 tmpidx == -1? "" : " [already known]");
373 if (tmpidx == -1) /* Create a new entry. */
374 tmpidx = create_new_hostinfo (tmphost);
378 log_error ("map_host for '%s' problem: %s - '%s' [ignored]\n",
379 name, strerror (errno), tmphost);
381 else /* Set or update the entry. */
386 hosttable[tmpidx]->port = port;
388 /* If TMPHOST is not yet a numerical value do this now.
389 * Note: This is a simple string operations and not a PTR
390 * lookup (due to DNS_NUMERICHOST). */
394 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
399 log_info ("resolve_dns_addr failed: %s\n",
400 gpg_strerror (tmperr));
408 if (ai->family == AF_INET6)
410 hosttable[tmpidx]->v6 = 1;
411 xfree (hosttable[tmpidx]->v6addr);
412 hosttable[tmpidx]->v6addr = ipaddr;
414 else if (ai->family == AF_INET)
416 hosttable[tmpidx]->v4 = 1;
417 xfree (hosttable[tmpidx]->v4addr);
418 hosttable[tmpidx]->v4addr = ipaddr;
423 for (i=0; i < *refidx; i++)
424 if (reftbl[i] == tmpidx)
426 if (!(i < *refidx) && tmpidx != idx)
427 reftbl[(*refidx)++] = tmpidx;
434 /* Map the host name NAME to the actual to be used host name. This
435 * allows us to manage round robin DNS names. We use our own strategy
436 * to choose one of the hosts. For example we skip those hosts which
437 * failed for some time and we stick to one host for a time
438 * independent of DNS retry times. If FORCE_RESELECT is true a new
439 * host is always selected. If SRVTAG is NULL no service record
440 * lookup will be done, if it is set that service name is used. The
441 * selected host is stored as a malloced string at R_HOST; on error
442 * NULL is stored. If we know the port used by the selected host from
443 * a service record, a string representation is written to R_PORTSTR,
444 * otherwise it is left untouched. If R_HTTPFLAGS is not NULL it will
445 * receive flags which are to be passed to http_open. If R_HTTPHOST
446 * is not NULL a malloced name of the host is stored there; this might
447 * be different from R_HOST in case it has been selected from a
450 map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect,
451 char **r_host, char *r_portstr,
452 unsigned int *r_httpflags, char **r_httphost)
465 /* No hostname means localhost. */
468 *r_host = xtrystrdup ("localhost");
469 return *r_host? 0 : gpg_error_from_syserror ();
472 /* See whether the host is in our table. */
473 idx = find_hostinfo (name);
474 if (idx == -1 && is_onion_address (name))
476 idx = create_new_hostinfo (name);
478 return gpg_error_from_syserror ();
484 /* We never saw this host. Allocate a new entry. */
485 dns_addrinfo_t aibuf, ai;
491 struct srventry *srvs;
492 unsigned int srvscount;
495 reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
497 return gpg_error_from_syserror ();
500 idx = create_new_hostinfo (name);
503 err = gpg_error_from_syserror ();
509 if (srvtag && !is_ip_address (name))
511 /* Check for SRV records. */
512 err = get_dns_srv (name, srvtag, NULL, &srvs, &srvscount);
516 if (gpg_err_code (err) == GPG_ERR_ECONNREFUSED)
517 tor_not_running_p (ctrl);
524 is_pool = srvscount > 1;
526 for (i = 0; i < srvscount; i++)
528 err = resolve_dns_name (srvs[i].target, 0,
529 AF_UNSPEC, SOCK_STREAM,
534 add_host (name, is_pool, ai, srvs[i].port,
535 reftbl, reftblsize, &refidx);
542 /* Find all A records for this entry and put them into the pool
544 err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
547 log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
552 /* First figure out whether this is a pool. For a pool we
553 use a different strategy than for a plain server: We use
554 the canonical name of the pool as the virtual host along
555 with the IP addresses. If it is not a pool, we use the
558 is_pool = arecords_is_pool (aibuf);
559 if (is_pool && cname)
565 for (ai = aibuf; ai; ai = ai->next)
567 if (ai->family != AF_INET && ai->family != AF_INET6)
569 if (opt.disable_ipv4 && ai->family == AF_INET)
573 add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
578 free_dns_addrinfo (aibuf);
580 if (refidx && is_pool)
583 hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
586 err = gpg_error_from_syserror ();
587 log_error ("shrinking index table in map_host failed: %s\n",
592 qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool);
598 curtime = gnupg_get_time ();
602 /* Deal with the pool name before selecting a host. */
605 *r_httphost = xtrystrdup (hi->cname? hi->cname : hi->name);
607 return gpg_error_from_syserror ();
610 /* If the currently selected host is now marked dead, force a
614 else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
615 && hosttable[hi->poolidx] && !host_is_alive (hosttable[hi->poolidx], curtime))
618 /* Select a host if needed. */
619 if (hi->poolidx == -1)
621 hi->poolidx = select_random_host (hi->pool);
622 if (hi->poolidx == -1)
624 log_error ("no alive host found in pool '%s'\n", name);
630 return gpg_error (GPG_ERR_NO_KEYSERVER);
634 assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
635 hi = hosttable[hi->poolidx];
638 else if (r_httphost && is_ip_address (hi->name))
640 /* This is a numerical IP address and not a pool. We want to
641 * find the canonical name so that it can be used in the HTTP
642 * Host header. Fixme: We should store that name in the
644 dns_addrinfo_t aibuf, ai;
647 err = resolve_dns_name (hi->name, 0, 0, SOCK_STREAM, &aibuf, NULL);
650 for (ai = aibuf; ai; ai = ai->next)
652 if (ai->family == AF_INET6
653 || (!opt.disable_ipv4 && ai->family == AF_INET))
655 err = resolve_dns_addr (ai->addr, ai->addrlen, 0, &host);
658 /* Okay, we return the first found name. */
665 free_dns_addrinfo (aibuf);
668 if (!host_is_alive (hi, curtime))
670 log_error ("host '%s' marked as dead\n", hi->name);
676 return gpg_error (GPG_ERR_NO_KEYSERVER);
681 /* If the hosttable does not indicate that a certain host
682 supports IPv<N>, we explicit set the corresponding http
683 flags. The reason for this is that a host might be listed in
684 a pool as not v6 only but actually support v6 when later
685 the name is resolved by our http layer. */
687 *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
689 *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
691 /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
692 addresses because the http module detects this itself. This
693 also allows us to use an onion address without Tor mode being
697 *r_host = xtrystrdup (hi->name);
700 err = gpg_error_from_syserror ();
709 snprintf (r_portstr, 6 /* five digits and the sentinel */,
715 /* Mark the host NAME as dead. NAME may be given as an URL. Returns
716 true if a host was really marked as dead or was already marked dead
717 (e.g. by a concurrent session). */
719 mark_host_dead (const char *name)
722 char *host_buffer = NULL;
723 parsed_uri_t parsed_uri = NULL;
726 if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
728 if (parsed_uri->v6lit)
730 host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
732 log_error ("out of core in mark_host_dead");
736 host = parsed_uri->host;
741 if (host && *host && strcmp (host, "localhost"))
746 idx = find_hostinfo (host);
750 log_info ("marking host '%s' as dead%s\n",
751 hi->name, hi->dead? " (again)":"");
753 hi->died_at = gnupg_get_time ();
760 http_release_parsed_uri (parsed_uri);
766 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
769 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
773 int idx, idx2, idx3, n, is_alive;
776 if (!name || !*name || !strcmp (name, "localhost"))
779 idx = find_hostinfo (name);
781 return gpg_error (GPG_ERR_NOT_FOUND);
783 curtime = gnupg_get_time ();
785 is_alive = host_is_alive (hi, curtime);
786 if (alive && !is_alive)
789 err = ks_printf_help (ctrl, "marking '%s' as alive", name);
791 else if (!alive && is_alive)
794 hi->died_at = 0; /* Manually set dead. */
795 err = ks_printf_help (ctrl, "marking '%s' as dead", name);
798 /* If the host is a pool mark all member hosts. */
799 if (!err && hi->pool)
801 for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
803 assert (n >= 0 && n < hosttable_size);
807 /* Do not mark a host from a pool dead if it is also a
808 member in another pool. */
809 for (idx3=0; idx3 < hosttable_size; idx3++)
812 && hosttable[idx3]->pool
814 && host_in_pool_p (hosttable[idx3]->pool, n))
817 if (idx3 < hosttable_size)
818 continue; /* Host is also a member of another pool. */
824 is_alive = host_is_alive (hi2, curtime);
825 if (alive && !is_alive)
828 err = ks_printf_help (ctrl, "marking '%s' as alive",
831 else if (!alive && is_alive)
834 hi2->died_at = 0; /* Manually set dead. */
835 err = ks_printf_help (ctrl, "marking '%s' as dead",
845 /* Debug function to print the entire hosttable. */
847 ks_hkp_print_hosttable (ctrl_t ctrl)
857 err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
861 curtime = gnupg_get_time ();
862 for (idx=0; idx < hosttable_size; idx++)
863 if ((hi=hosttable[idx]))
865 if (hi->dead && hi->died_at)
867 died = elapsed_time_string (hi->died_at, curtime);
868 diedstr = died? died : "error";
871 diedstr = died = NULL;
872 err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
874 hi->onion? "O" : hi->v6? "6":" ",
878 hi->v6addr? " v6=":"",
879 hi->v6addr? hi->v6addr:"",
880 hi->v4addr? " v4=":"",
881 hi->v4addr? hi->v4addr:"",
890 err = ks_printf_help (ctrl, " . %s", hi->cname);
896 init_membuf (&mb, 256);
897 put_membuf_printf (&mb, " . -->");
898 for (idx2=0; hi->pool[idx2] != -1; idx2++)
900 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
901 if (hi->poolidx == hi->pool[idx2])
902 put_membuf_printf (&mb, "*");
904 put_membuf( &mb, "", 1);
905 p = get_membuf (&mb, NULL);
907 return gpg_error_from_syserror ();
908 err = ks_print_help (ctrl, p);
919 /* Print a help output for the schemata supported by this module. */
921 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
924 "Handler for HKP URLs:\n"
926 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
929 "Supported methods: search, get, put\n";
932 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
933 const char data2[] = " hkp\n hkps";
935 const char data2[] = " hkp";
939 err = ks_print_help (ctrl, data2);
940 else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
941 || !strcmp (uri->scheme, "hkps")))
942 err = ks_print_help (ctrl, data);
950 /* Build the remote part of the URL from SCHEME, HOST and an optional
951 * PORT. If NO_SRV is set no SRV record lookup will be done. Returns
952 * an allocated string at R_HOSTPORT or NULL on failure. If
953 * R_HTTPHOST is not NULL it receives a malloced string with the
954 * hostname; this may be different from HOST if HOST is selected from
957 make_host_part (ctrl_t ctrl,
958 const char *scheme, const char *host, unsigned short port,
959 int force_reselect, int no_srv,
960 char **r_hostport, unsigned int *r_httpflags, char **r_httphost)
969 if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
972 srvtag = no_srv? NULL : "pgpkey-https";
974 else /* HKP or HTTP. */
977 srvtag = no_srv? NULL : "pgpkey-http";
981 err = map_host (ctrl, host, srvtag, force_reselect,
982 &hostname, portstr, r_httpflags, r_httphost);
986 /* If map_host did not return a port (from a SRV record) but a port
987 * has been specified (implicitly or explicitly) then use that port.
988 * In the case that a port was not specified (which is probably a
989 * bug in https.c) we will set up defaults. */
992 else if (!*portstr && port)
993 snprintf (portstr, sizeof portstr, "%hu", port);
994 else if (!strcmp (scheme,"https"))
995 strcpy (portstr, "443");
997 strcpy (portstr, "11371");
999 if (*hostname != '[' && is_ip_address (hostname) == 6)
1000 *r_hostport = strconcat (scheme, "://[", hostname, "]:", portstr, NULL);
1002 *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
1008 xfree (*r_httphost);
1011 return gpg_error_from_syserror ();
1017 /* Resolve all known keyserver names and update the hosttable. This
1018 is mainly useful for debugging because the resolving is anyway done
1021 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
1024 char *hostport = NULL;
1026 /* NB: With an explicitly given port we do not want to consult a
1027 * service record because that might be in conflict with the port
1028 * from such a service record. */
1029 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1030 1, uri->explicit_port,
1031 &hostport, NULL, NULL);
1034 err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
1035 uri->scheme, uri->host, uri->port,
1036 gpg_strerror (err));
1040 err = ks_printf_help (ctrl, "%s", hostport);
1047 /* Reload (SIGHUP) action for this module. We mark all host alive
1048 * even those which have been manually shot. */
1050 ks_hkp_reload (void)
1055 for (idx=count=0; idx < hosttable_size; idx++)
1057 hi = hosttable[idx];
1066 log_info ("number of resurrected hosts: %d", count);
1070 /* Send an HTTP request. On success returns an estream object at
1071 R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is
1072 not NULL it will be used as HTTP "Host" header. If POST_CB is not
1073 NULL a post request is used and that callback is called to allow
1074 writing the post data. If R_HTTP_STATUS is not NULL, the http
1075 status code will be stored there. */
1077 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
1078 const char *httphost, unsigned int httpflags,
1079 gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
1080 estream_t *r_fp, unsigned int *r_http_status)
1083 http_session_t session = NULL;
1085 int redirects_left = MAX_REDIRECTS;
1086 estream_t fp = NULL;
1087 char *request_buffer = NULL;
1091 err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
1094 http_session_set_log_cb (session, cert_log_cb);
1097 err = http_open (&http,
1098 post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1101 /* fixme: AUTH */ NULL,
1103 |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1104 |(dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0)
1105 |(opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)),
1109 /*FIXME curl->srvtag*/NULL);
1112 fp = http_get_write_ptr (http);
1113 /* Avoid caches to get the most recent copy of the key. We set
1114 both the Pragma and Cache-Control versions of the header, so
1115 we're good with both HTTP 1.0 and 1.1. */
1116 es_fputs ("Pragma: no-cache\r\n"
1117 "Cache-Control: no-cache\r\n", fp);
1119 err = post_cb (post_cb_value, http);
1122 http_start_data (http);
1124 err = gpg_error_from_syserror ();
1129 /* Fixme: After a redirection we show the old host name. */
1130 log_error (_("error connecting to '%s': %s\n"),
1131 hostportstr, gpg_strerror (err));
1135 /* Wait for the response. */
1136 dirmngr_tick (ctrl);
1137 err = http_wait_response (http);
1140 log_error (_("error reading HTTP response for '%s': %s\n"),
1141 hostportstr, gpg_strerror (err));
1145 if (http_get_tls_info (http, NULL))
1147 /* Update the httpflags so that a redirect won't fallback to an
1148 unencrypted connection. */
1149 httpflags |= HTTP_FLAG_FORCE_TLS;
1153 *r_http_status = http_get_status_code (http);
1155 switch (http_get_status_code (http))
1159 break; /* Success. */
1165 const char *s = http_get_header (http, "Location");
1167 log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1168 request, s?s:"[none]", http_get_status_code (http));
1169 if (s && *s && redirects_left-- )
1171 xfree (request_buffer);
1172 request_buffer = xtrystrdup (s);
1175 request = request_buffer;
1176 http_close (http, 0);
1180 err = gpg_error_from_syserror ();
1183 err = gpg_error (GPG_ERR_NO_DATA);
1184 log_error (_("too many redirections\n"));
1189 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1193 log_error (_("error accessing '%s': http status %u\n"),
1194 request, http_get_status_code (http));
1195 err = gpg_error (GPG_ERR_NO_DATA);
1199 /* FIXME: We should register a permanent redirection and whether a
1200 host has ever used TLS so that future calls will always use
1203 fp = http_get_read_ptr (http);
1206 err = gpg_error (GPG_ERR_BUG);
1210 /* Return the read stream and close the HTTP context. */
1212 http_close (http, 1);
1216 http_close (http, 0);
1217 http_session_release (session);
1218 xfree (request_buffer);
1223 /* Helper to evaluate the error code ERR from a send_request() call
1224 with REQUEST. The function returns true if the caller shall try
1225 again. TRIES_LEFT points to a variable to track the number of
1226 retries; this function decrements it and won't return true if it is
1229 handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
1230 unsigned int *tries_left)
1234 /* Fixme: Should we disable all hosts of a protocol family if a
1235 * request for an address of that familiy returned ENETDOWN? */
1237 switch (gpg_err_code (err))
1239 case GPG_ERR_ECONNREFUSED:
1240 if (tor_not_running_p (ctrl))
1241 break; /* A retry does not make sense. */
1242 /* Okay: Tor is up or --use-tor is not used. */
1244 case GPG_ERR_ENETUNREACH:
1245 case GPG_ERR_ENETDOWN:
1246 case GPG_ERR_UNKNOWN_HOST:
1247 case GPG_ERR_NETWORK:
1248 if (mark_host_dead (request) && *tries_left)
1252 case GPG_ERR_ETIMEDOUT:
1255 log_info ("selecting a different host due to a timeout\n");
1260 case GPG_ERR_EACCES:
1261 if (dirmngr_use_tor ())
1263 log_info ("(Tor configuration problem)\n");
1264 dirmngr_status (ctrl, "WARNING", "tor_config_problem 0",
1265 "Please check that the \"SocksPort\" flag "
1266 "\"IPv6Traffic\" is set in torrc", NULL);
1281 /* Search the keyserver identified by URI for keys matching PATTERN.
1282 On success R_FP has an open stream to read the data. If
1283 R_HTTP_STATUS is not NULL, the http status code will be stored
1286 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1287 estream_t *r_fp, unsigned int *r_http_status)
1290 KEYDB_SEARCH_DESC desc;
1291 char fprbuf[2+40+1];
1292 char *hostport = NULL;
1293 char *request = NULL;
1294 estream_t fp = NULL;
1296 unsigned int httpflags;
1297 char *httphost = NULL;
1298 unsigned int tries = SEND_REQUEST_RETRIES;
1302 /* Remove search type indicator and adjust PATTERN accordingly.
1303 Note that HKP keyservers like the 0x to be present when searching
1304 by keyid. We need to re-format the fingerprint and keyids so to
1305 remove the gpg specific force-use-of-this-key flag ("!"). */
1306 err = classify_user_id (pattern, &desc, 1);
1311 case KEYDB_SEARCH_MODE_EXACT:
1312 case KEYDB_SEARCH_MODE_SUBSTR:
1313 case KEYDB_SEARCH_MODE_MAIL:
1314 case KEYDB_SEARCH_MODE_MAILSUB:
1315 pattern = desc.u.name;
1317 case KEYDB_SEARCH_MODE_SHORT_KID:
1318 snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1321 case KEYDB_SEARCH_MODE_LONG_KID:
1322 snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1323 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1326 case KEYDB_SEARCH_MODE_FPR16:
1329 bin2hex (desc.u.fpr, 16, fprbuf+2);
1332 case KEYDB_SEARCH_MODE_FPR20:
1333 case KEYDB_SEARCH_MODE_FPR:
1336 bin2hex (desc.u.fpr, 20, fprbuf+2);
1340 return gpg_error (GPG_ERR_INV_USER_ID);
1343 /* Build the request string. */
1349 xfree (hostport); hostport = NULL;
1350 xfree (httphost); httphost = NULL;
1351 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1352 reselect, uri->explicit_port,
1353 &hostport, &httpflags, &httphost);
1357 searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1360 err = gpg_error_from_syserror ();
1365 request = strconcat (hostport,
1366 "/pks/lookup?op=index&options=mr&search=",
1372 err = gpg_error_from_syserror ();
1377 /* Send the request. */
1378 err = send_request (ctrl, request, hostport, httphost, httpflags,
1379 NULL, NULL, &fp, r_http_status);
1380 if (handle_send_request_error (ctrl, err, request, &tries))
1388 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1392 /* Peek at the response. */
1394 int c = es_getc (fp);
1397 err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1398 log_error ("error reading response: %s\n", gpg_strerror (err));
1403 /* The document begins with a '<': Assume a HTML response,
1404 which we don't support. */
1405 err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1411 /* Return the read stream. */
1424 /* Get the key described key the KEYSPEC string from the keyserver
1425 identified by URI. On success R_FP has an open stream to read the
1426 data. The data will be provided in a format GnuPG can import
1427 (either a binary OpenPGP message or an armored one). */
1429 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1432 KEYDB_SEARCH_DESC desc;
1433 char kidbuf[2+40+1];
1434 const char *exactname = NULL;
1435 char *searchkey = NULL;
1436 char *hostport = NULL;
1437 char *request = NULL;
1438 estream_t fp = NULL;
1440 char *httphost = NULL;
1441 unsigned int httpflags;
1442 unsigned int tries = SEND_REQUEST_RETRIES;
1446 /* Remove search type indicator and adjust PATTERN accordingly.
1447 Note that HKP keyservers like the 0x to be present when searching
1448 by keyid. We need to re-format the fingerprint and keyids so to
1449 remove the gpg specific force-use-of-this-key flag ("!"). */
1450 err = classify_user_id (keyspec, &desc, 1);
1455 case KEYDB_SEARCH_MODE_SHORT_KID:
1456 snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1458 case KEYDB_SEARCH_MODE_LONG_KID:
1459 snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1460 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1462 case KEYDB_SEARCH_MODE_FPR20:
1463 case KEYDB_SEARCH_MODE_FPR:
1464 /* This is a v4 fingerprint. */
1467 bin2hex (desc.u.fpr, 20, kidbuf+2);
1470 case KEYDB_SEARCH_MODE_EXACT:
1471 exactname = desc.u.name;
1474 case KEYDB_SEARCH_MODE_FPR16:
1475 log_error ("HKP keyservers do not support v3 fingerprints\n");
1477 return gpg_error (GPG_ERR_INV_USER_ID);
1480 searchkey = http_escape_string (exactname? exactname : kidbuf,
1481 EXTRA_ESCAPE_CHARS);
1484 err = gpg_error_from_syserror ();
1490 /* Build the request string. */
1491 xfree (hostport); hostport = NULL;
1492 xfree (httphost); httphost = NULL;
1493 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1494 reselect, uri->explicit_port,
1495 &hostport, &httpflags, &httphost);
1500 request = strconcat (hostport,
1501 "/pks/lookup?op=get&options=mr&search=",
1503 exactname? "&exact=on":"",
1507 err = gpg_error_from_syserror ();
1511 /* Send the request. */
1512 err = send_request (ctrl, request, hostport, httphost, httpflags,
1513 NULL, NULL, &fp, NULL);
1514 if (handle_send_request_error (ctrl, err, request, &tries))
1522 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1526 /* Return the read stream and close the HTTP context. */
1542 /* Callback parameters for put_post_cb. */
1543 struct put_post_parm_s
1549 /* Helper for ks_hkp_put. */
1551 put_post_cb (void *opaque, http_t http)
1553 struct put_post_parm_s *parm = opaque;
1554 gpg_error_t err = 0;
1558 fp = http_get_write_ptr (http);
1559 len = strlen (parm->datastring);
1562 "Content-Type: application/x-www-form-urlencoded\r\n"
1563 "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1564 http_start_data (http);
1565 if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1566 err = gpg_error_from_syserror ();
1571 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
1573 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1576 char *hostport = NULL;
1577 char *request = NULL;
1578 estream_t fp = NULL;
1579 struct put_post_parm_s parm;
1580 char *armored = NULL;
1582 char *httphost = NULL;
1583 unsigned int httpflags;
1584 unsigned int tries = SEND_REQUEST_RETRIES;
1586 parm.datastring = NULL;
1588 err = armor_data (&armored, data, datalen);
1592 parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1593 if (!parm.datastring)
1595 err = gpg_error_from_syserror ();
1601 /* Build the request string. */
1604 xfree (hostport); hostport = NULL;
1605 xfree (httphost); httphost = NULL;
1606 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
1607 reselect, uri->explicit_port,
1608 &hostport, &httpflags, &httphost);
1613 request = strconcat (hostport, "/pks/add", NULL);
1616 err = gpg_error_from_syserror ();
1620 /* Send the request. */
1621 err = send_request (ctrl, request, hostport, httphost, 0,
1622 put_post_cb, &parm, &fp, NULL);
1623 if (handle_send_request_error (ctrl, err, request, &tries))
1633 xfree (parm.datastring);