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
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. The selected host is stored as a malloced
402 string at R_HOST; on error NULL is stored. If we know the port
403 used by the selected host, a string representation is written to
404 R_PORTSTR, otherwise it is left untouched. If R_HTTPFLAGS is not
405 NULL it will receive flags which are to be passed to http_open. If
406 R_POOLNAME is not NULL a malloced name of the pool is stored or
407 NULL if it is not a pool. */
409 map_host (ctrl_t ctrl, const char *name, int force_reselect,
410 char **r_host, char *r_portstr,
411 unsigned int *r_httpflags, char **r_poolname)
424 /* No hostname means localhost. */
427 *r_host = xtrystrdup ("localhost");
428 return *r_host? 0 : gpg_error_from_syserror ();
431 /* See whether the host is in our table. */
432 idx = find_hostinfo (name);
433 if (idx == -1 && is_onion_address (name))
435 idx = create_new_hostinfo (name);
437 return gpg_error_from_syserror ();
443 /* We never saw this host. Allocate a new entry. */
444 dns_addrinfo_t aibuf, ai;
451 struct srventry *srvs;
452 unsigned int srvscount;
455 reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
457 return gpg_error_from_syserror ();
460 idx = create_new_hostinfo (name);
463 err = gpg_error_from_syserror ();
469 if (!is_ip_address (name))
471 /* Check for SRV records. */
472 srvrecord = xtryasprintf ("_hkp._tcp.%s", name);
473 if (srvrecord == NULL)
475 err = gpg_error_from_syserror ();
480 err = get_dns_srv (srvrecord, &srvs, &srvscount);
491 is_pool = srvscount > 1;
493 for (i = 0; i < srvscount; i++)
495 err = resolve_dns_name (srvs[i].target, 0,
496 AF_UNSPEC, SOCK_STREAM,
501 add_host (name, is_pool, ai, srvs[i].port,
502 reftbl, reftblsize, &refidx);
509 /* Find all A records for this entry and put them into the pool
511 err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
514 log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
519 /* First figure out whether this is a pool. For a pool we
520 use a different strategy than for a plain server: We use
521 the canonical name of the pool as the virtual host along
522 with the IP addresses. If it is not a pool, we use the
525 is_pool = arecords_is_pool (aibuf);
526 if (is_pool && cname)
532 for (ai = aibuf; ai; ai = ai->next)
534 if (ai->family != AF_INET && ai->family != AF_INET6)
538 add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
543 free_dns_addrinfo (aibuf);
545 if (refidx && is_pool)
548 hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
551 err = gpg_error_from_syserror ();
552 log_error ("shrinking index table in map_host failed: %s\n",
557 qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool);
563 curtime = gnupg_get_time ();
567 /* Deal with the pool name before selecting a host. */
570 *r_poolname = xtrystrdup (hi->cname? hi->cname : hi->name);
572 return gpg_error_from_syserror ();
575 /* If the currently selected host is now marked dead, force a
579 else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
580 && hosttable[hi->poolidx] && !host_is_alive (hosttable[hi->poolidx], curtime))
583 /* Select a host if needed. */
584 if (hi->poolidx == -1)
586 hi->poolidx = select_random_host (hi->pool);
587 if (hi->poolidx == -1)
589 log_error ("no alive host found in pool '%s'\n", name);
595 return gpg_error (GPG_ERR_NO_KEYSERVER);
599 assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
600 hi = hosttable[hi->poolidx];
604 if (!host_is_alive (hi, curtime))
606 log_error ("host '%s' marked as dead\n", hi->name);
612 return gpg_error (GPG_ERR_NO_KEYSERVER);
617 /* If the hosttable does not indicate that a certain host
618 supports IPv<N>, we explicit set the corresponding http
619 flags. The reason for this is that a host might be listed in
620 a pool as not v6 only but actually support v6 when later
621 the name is resolved by our http layer. */
623 *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
625 *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
627 /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
628 addresses because the http module detects this itself. This
629 also allows us to use an onion address without Tor mode being
633 *r_host = xtrystrdup (hi->name);
636 err = gpg_error_from_syserror ();
645 snprintf (r_portstr, 6 /* five digits and the sentinel */,
651 /* Mark the host NAME as dead. NAME may be given as an URL. Returns
652 true if a host was really marked as dead or was already marked dead
653 (e.g. by a concurrent session). */
655 mark_host_dead (const char *name)
658 char *host_buffer = NULL;
659 parsed_uri_t parsed_uri = NULL;
662 if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
664 if (parsed_uri->v6lit)
666 host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
668 log_error ("out of core in mark_host_dead");
672 host = parsed_uri->host;
677 if (host && *host && strcmp (host, "localhost"))
682 idx = find_hostinfo (host);
686 log_info ("marking host '%s' as dead%s\n",
687 hi->name, hi->dead? " (again)":"");
689 hi->died_at = gnupg_get_time ();
696 http_release_parsed_uri (parsed_uri);
702 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
705 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
709 int idx, idx2, idx3, n, is_alive;
712 if (!name || !*name || !strcmp (name, "localhost"))
715 idx = find_hostinfo (name);
717 return gpg_error (GPG_ERR_NOT_FOUND);
719 curtime = gnupg_get_time ();
721 is_alive = host_is_alive (hi, curtime);
722 if (alive && !is_alive)
725 err = ks_printf_help (ctrl, "marking '%s' as alive", name);
727 else if (!alive && is_alive)
730 hi->died_at = 0; /* Manually set dead. */
731 err = ks_printf_help (ctrl, "marking '%s' as dead", name);
734 /* If the host is a pool mark all member hosts. */
735 if (!err && hi->pool)
737 for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
739 assert (n >= 0 && n < hosttable_size);
743 /* Do not mark a host from a pool dead if it is also a
744 member in another pool. */
745 for (idx3=0; idx3 < hosttable_size; idx3++)
748 && hosttable[idx3]->pool
750 && host_in_pool_p (hosttable[idx3]->pool, n))
753 if (idx3 < hosttable_size)
754 continue; /* Host is also a member of another pool. */
760 is_alive = host_is_alive (hi2, curtime);
761 if (alive && !is_alive)
764 err = ks_printf_help (ctrl, "marking '%s' as alive",
767 else if (!alive && is_alive)
770 hi2->died_at = 0; /* Manually set dead. */
771 err = ks_printf_help (ctrl, "marking '%s' as dead",
781 /* Debug function to print the entire hosttable. */
783 ks_hkp_print_hosttable (ctrl_t ctrl)
793 err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
797 curtime = gnupg_get_time ();
798 for (idx=0; idx < hosttable_size; idx++)
799 if ((hi=hosttable[idx]))
801 if (hi->dead && hi->died_at)
803 died = elapsed_time_string (hi->died_at, curtime);
804 diedstr = died? died : "error";
807 diedstr = died = NULL;
808 err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
810 hi->onion? "O" : hi->v6? "6":" ",
814 hi->v6addr? " v6=":"",
815 hi->v6addr? hi->v6addr:"",
816 hi->v4addr? " v4=":"",
817 hi->v4addr? hi->v4addr:"",
826 err = ks_printf_help (ctrl, " . %s", hi->cname);
832 init_membuf (&mb, 256);
833 put_membuf_printf (&mb, " . -->");
834 for (idx2=0; hi->pool[idx2] != -1; idx2++)
836 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
837 if (hi->poolidx == hi->pool[idx2])
838 put_membuf_printf (&mb, "*");
840 put_membuf( &mb, "", 1);
841 p = get_membuf (&mb, NULL);
843 return gpg_error_from_syserror ();
844 err = ks_print_help (ctrl, p);
855 /* Print a help output for the schemata supported by this module. */
857 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
859 const char const data[] =
860 "Handler for HKP URLs:\n"
862 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
865 "Supported methods: search, get, put\n";
868 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
869 const char data2[] = " hkp\n hkps";
871 const char data2[] = " hkp";
875 err = ks_print_help (ctrl, data2);
876 else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
877 || !strcmp (uri->scheme, "hkps")))
878 err = ks_print_help (ctrl, data);
886 /* Build the remote part of the URL from SCHEME, HOST and an optional
887 PORT. Returns an allocated string at R_HOSTPORT or NULL on failure
888 If R_POOLNAME is not NULL it receives a malloced string with the
891 make_host_part (ctrl_t ctrl,
892 const char *scheme, const char *host, unsigned short port,
894 char **r_hostport, unsigned int *r_httpflags, char **r_poolname)
903 err = map_host (ctrl, host, force_reselect,
904 &hostname, portstr, r_httpflags, r_poolname);
908 /* Map scheme and port. */
909 if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
913 strcpy (portstr, "443");
915 else /* HKP or HTTP. */
919 strcpy (portstr, "11371");
922 snprintf (portstr, sizeof portstr, "%hu", port);
925 /*fixme_do_srv_lookup ()*/
928 *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
937 return gpg_error_from_syserror ();
943 /* Resolve all known keyserver names and update the hosttable. This
944 is mainly useful for debugging because the resolving is anyway done
947 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
950 char *hostport = NULL;
952 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1,
953 &hostport, NULL, NULL);
956 err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
957 uri->scheme, uri->host, uri->port,
962 err = ks_printf_help (ctrl, "%s", hostport);
969 /* Send an HTTP request. On success returns an estream object at
970 R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is
971 not NULL it will be used as HTTP "Host" header. If POST_CB is not
972 NULL a post request is used and that callback is called to allow
973 writing the post data. If R_HTTP_STATUS is not NULL, the http
974 status code will be stored there. */
976 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
977 const char *httphost, unsigned int httpflags,
978 gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
979 estream_t *r_fp, unsigned int *r_http_status)
982 http_session_t session = NULL;
984 int redirects_left = MAX_REDIRECTS;
986 char *request_buffer = NULL;
990 err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
993 http_session_set_log_cb (session, cert_log_cb);
996 err = http_open (&http,
997 post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1000 /* fixme: AUTH */ NULL,
1002 |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1003 |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
1007 /*FIXME curl->srvtag*/NULL);
1010 fp = http_get_write_ptr (http);
1011 /* Avoid caches to get the most recent copy of the key. We set
1012 both the Pragma and Cache-Control versions of the header, so
1013 we're good with both HTTP 1.0 and 1.1. */
1014 es_fputs ("Pragma: no-cache\r\n"
1015 "Cache-Control: no-cache\r\n", fp);
1017 err = post_cb (post_cb_value, http);
1020 http_start_data (http);
1022 err = gpg_error_from_syserror ();
1027 /* Fixme: After a redirection we show the old host name. */
1028 log_error (_("error connecting to '%s': %s\n"),
1029 hostportstr, gpg_strerror (err));
1033 /* Wait for the response. */
1034 dirmngr_tick (ctrl);
1035 err = http_wait_response (http);
1038 log_error (_("error reading HTTP response for '%s': %s\n"),
1039 hostportstr, gpg_strerror (err));
1043 if (http_get_tls_info (http, NULL))
1045 /* Update the httpflags so that a redirect won't fallback to an
1046 unencrypted connection. */
1047 httpflags |= HTTP_FLAG_FORCE_TLS;
1051 *r_http_status = http_get_status_code (http);
1053 switch (http_get_status_code (http))
1057 break; /* Success. */
1063 const char *s = http_get_header (http, "Location");
1065 log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1066 request, s?s:"[none]", http_get_status_code (http));
1067 if (s && *s && redirects_left-- )
1069 xfree (request_buffer);
1070 request_buffer = xtrystrdup (s);
1073 request = request_buffer;
1074 http_close (http, 0);
1078 err = gpg_error_from_syserror ();
1081 err = gpg_error (GPG_ERR_NO_DATA);
1082 log_error (_("too many redirections\n"));
1087 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1091 log_error (_("error accessing '%s': http status %u\n"),
1092 request, http_get_status_code (http));
1093 err = gpg_error (GPG_ERR_NO_DATA);
1097 /* FIXME: We should register a permanent redirection and whether a
1098 host has ever used TLS so that future calls will always use
1101 fp = http_get_read_ptr (http);
1104 err = gpg_error (GPG_ERR_BUG);
1108 /* Return the read stream and close the HTTP context. */
1110 http_close (http, 1);
1114 http_close (http, 0);
1115 http_session_release (session);
1116 xfree (request_buffer);
1121 /* Helper to evaluate the error code ERR form a send_request() call
1122 with REQUEST. The function returns true if the caller shall try
1123 again. TRIES_LEFT points to a variable to track the number of
1124 retries; this function decrements it and won't return true if it is
1127 handle_send_request_error (gpg_error_t err, const char *request,
1128 unsigned int *tries_left)
1132 switch (gpg_err_code (err))
1134 case GPG_ERR_ECONNREFUSED:
1135 case GPG_ERR_ENETUNREACH:
1136 case GPG_ERR_UNKNOWN_HOST:
1137 case GPG_ERR_NETWORK:
1138 if (mark_host_dead (request) && *tries_left)
1142 case GPG_ERR_ETIMEDOUT:
1145 log_info ("selecting a different host due to a timeout\n");
1160 /* Search the keyserver identified by URI for keys matching PATTERN.
1161 On success R_FP has an open stream to read the data. If
1162 R_HTTP_STATUS is not NULL, the http status code will be stored
1165 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1166 estream_t *r_fp, unsigned int *r_http_status)
1169 KEYDB_SEARCH_DESC desc;
1170 char fprbuf[2+40+1];
1171 char *hostport = NULL;
1172 char *request = NULL;
1173 estream_t fp = NULL;
1175 unsigned int httpflags;
1176 char *httphost = NULL;
1177 unsigned int tries = SEND_REQUEST_RETRIES;
1181 /* Remove search type indicator and adjust PATTERN accordingly.
1182 Note that HKP keyservers like the 0x to be present when searching
1183 by keyid. We need to re-format the fingerprint and keyids so to
1184 remove the gpg specific force-use-of-this-key flag ("!"). */
1185 err = classify_user_id (pattern, &desc, 1);
1190 case KEYDB_SEARCH_MODE_EXACT:
1191 case KEYDB_SEARCH_MODE_SUBSTR:
1192 case KEYDB_SEARCH_MODE_MAIL:
1193 case KEYDB_SEARCH_MODE_MAILSUB:
1194 pattern = desc.u.name;
1196 case KEYDB_SEARCH_MODE_SHORT_KID:
1197 snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1200 case KEYDB_SEARCH_MODE_LONG_KID:
1201 snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1202 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1205 case KEYDB_SEARCH_MODE_FPR16:
1208 bin2hex (desc.u.fpr, 16, fprbuf+2);
1211 case KEYDB_SEARCH_MODE_FPR20:
1212 case KEYDB_SEARCH_MODE_FPR:
1215 bin2hex (desc.u.fpr, 20, fprbuf+2);
1219 return gpg_error (GPG_ERR_INV_USER_ID);
1222 /* Build the request string. */
1228 xfree (hostport); hostport = NULL;
1229 xfree (httphost); httphost = NULL;
1230 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1231 &hostport, &httpflags, &httphost);
1235 searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1238 err = gpg_error_from_syserror ();
1243 request = strconcat (hostport,
1244 "/pks/lookup?op=index&options=mr&search=",
1250 err = gpg_error_from_syserror ();
1255 /* Send the request. */
1256 err = send_request (ctrl, request, hostport, httphost, httpflags,
1257 NULL, NULL, &fp, r_http_status);
1258 if (handle_send_request_error (err, request, &tries))
1266 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1270 /* Peek at the response. */
1272 int c = es_getc (fp);
1275 err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1276 log_error ("error reading response: %s\n", gpg_strerror (err));
1281 /* The document begins with a '<': Assume a HTML response,
1282 which we don't support. */
1283 err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1289 /* Return the read stream. */
1302 /* Get the key described key the KEYSPEC string from the keyserver
1303 identified by URI. On success R_FP has an open stream to read the
1304 data. The data will be provided in a format GnuPG can import
1305 (either a binary OpenPGP message or an armored one). */
1307 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1310 KEYDB_SEARCH_DESC desc;
1311 char kidbuf[2+40+1];
1312 const char *exactname = NULL;
1313 char *searchkey = NULL;
1314 char *hostport = NULL;
1315 char *request = NULL;
1316 estream_t fp = NULL;
1318 char *httphost = NULL;
1319 unsigned int httpflags;
1320 unsigned int tries = SEND_REQUEST_RETRIES;
1324 /* Remove search type indicator and adjust PATTERN accordingly.
1325 Note that HKP keyservers like the 0x to be present when searching
1326 by keyid. We need to re-format the fingerprint and keyids so to
1327 remove the gpg specific force-use-of-this-key flag ("!"). */
1328 err = classify_user_id (keyspec, &desc, 1);
1333 case KEYDB_SEARCH_MODE_SHORT_KID:
1334 snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1336 case KEYDB_SEARCH_MODE_LONG_KID:
1337 snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1338 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1340 case KEYDB_SEARCH_MODE_FPR20:
1341 case KEYDB_SEARCH_MODE_FPR:
1342 /* This is a v4 fingerprint. */
1345 bin2hex (desc.u.fpr, 20, kidbuf+2);
1348 case KEYDB_SEARCH_MODE_EXACT:
1349 exactname = desc.u.name;
1352 case KEYDB_SEARCH_MODE_FPR16:
1353 log_error ("HKP keyservers do not support v3 fingerprints\n");
1355 return gpg_error (GPG_ERR_INV_USER_ID);
1358 searchkey = http_escape_string (exactname? exactname : kidbuf,
1359 EXTRA_ESCAPE_CHARS);
1362 err = gpg_error_from_syserror ();
1368 /* Build the request string. */
1369 xfree (hostport); hostport = NULL;
1370 xfree (httphost); httphost = NULL;
1371 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1372 &hostport, &httpflags, &httphost);
1377 request = strconcat (hostport,
1378 "/pks/lookup?op=get&options=mr&search=",
1380 exactname? "&exact=on":"",
1384 err = gpg_error_from_syserror ();
1388 /* Send the request. */
1389 err = send_request (ctrl, request, hostport, httphost, httpflags,
1390 NULL, NULL, &fp, NULL);
1391 if (handle_send_request_error (err, request, &tries))
1399 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1403 /* Return the read stream and close the HTTP context. */
1419 /* Callback parameters for put_post_cb. */
1420 struct put_post_parm_s
1426 /* Helper for ks_hkp_put. */
1428 put_post_cb (void *opaque, http_t http)
1430 struct put_post_parm_s *parm = opaque;
1431 gpg_error_t err = 0;
1435 fp = http_get_write_ptr (http);
1436 len = strlen (parm->datastring);
1439 "Content-Type: application/x-www-form-urlencoded\r\n"
1440 "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1441 http_start_data (http);
1442 if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1443 err = gpg_error_from_syserror ();
1448 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
1450 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1453 char *hostport = NULL;
1454 char *request = NULL;
1455 estream_t fp = NULL;
1456 struct put_post_parm_s parm;
1457 char *armored = NULL;
1459 char *httphost = NULL;
1460 unsigned int httpflags;
1461 unsigned int tries = SEND_REQUEST_RETRIES;
1463 parm.datastring = NULL;
1465 err = armor_data (&armored, data, datalen);
1469 parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1470 if (!parm.datastring)
1472 err = gpg_error_from_syserror ();
1478 /* Build the request string. */
1481 xfree (hostport); hostport = NULL;
1482 xfree (httphost); httphost = NULL;
1483 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1484 &hostport, &httpflags, &httphost);
1489 request = strconcat (hostport, "/pks/add", NULL);
1492 err = gpg_error_from_syserror ();
1496 /* Send the request. */
1497 err = send_request (ctrl, request, hostport, httphost, 0,
1498 put_post_cb, &parm, &fp, NULL);
1499 if (handle_send_request_error (err, request, &tries))
1509 xfree (parm.datastring);