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])
206 /* Select a random host. Consult TABLE which indices into the global
207 hosttable. Returns index into TABLE or -1 if no host could be
210 select_random_host (int *table)
216 /* We create a new table so that we randomly select only from
217 currently alive hosts. */
218 for (idx=0; (pidx = table[idx]) != -1; idx++)
219 if (hosttable[pidx] && !hosttable[pidx]->dead)
222 tbl = xtryrealloc(tbl, tblsize * sizeof *tbl);
224 return -1; /* memory allocation failed! */
225 tbl[tblsize-1] = pidx;
228 return -1; /* No hosts. */
230 if (tblsize == 1) /* Save a get_uint_nonce. */
233 pidx = tbl[get_uint_nonce () % tblsize];
240 /* Figure out if a set of DNS records looks like a pool. */
242 arecords_is_pool (dns_addrinfo_t aibuf)
248 for (ai = aibuf; ai; ai = ai->next)
250 if (ai->family == AF_INET6)
252 else if (ai->family == AF_INET)
256 return n_v6 > 1 || n_v4 > 1;
260 /* Add the host AI under the NAME into the HOSTTABLE. If PORT is not
261 zero, it specifies which port to use to talk to the host. If NAME
262 specifies a pool (as indicated by IS_POOL), update the given
263 reference table accordingly. */
265 add_host (const char *name, int is_pool,
266 const dns_addrinfo_t ai, unsigned short port,
267 int *reftbl, size_t reftblsize, int *refidx)
275 idx = find_hostinfo (name);
277 if (!is_pool && !is_ip_address (name))
279 /* This is a hostname but not a pool. Use the name
280 as given without going through resolve_dns_addr. */
281 tmphost = xtrystrdup (name);
283 tmperr = gpg_error_from_syserror ();
289 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
290 DNS_WITHBRACKET, &tmphost);
291 if (tmphost && is_ip_address (tmphost))
297 log_info ("resolve_dns_addr failed while checking '%s': %s\n",
298 name, gpg_strerror (tmperr));
300 else if ((*refidx) + 1 >= reftblsize)
302 log_error ("resolve_dns_addr for '%s': '%s'"
303 " [index table full - ignored]\n", name, tmphost);
307 if (!is_pool && is_ip_address (name))
308 /* Update the original entry. */
311 tmpidx = find_hostinfo (tmphost);
312 log_info ("resolve_dns_addr for '%s': '%s'%s\n",
314 tmpidx == -1? "" : " [already known]");
316 if (tmpidx == -1) /* Create a new entry. */
317 tmpidx = create_new_hostinfo (tmphost);
321 log_error ("map_host for '%s' problem: %s - '%s'"
323 name, strerror (errno), tmphost);
325 else /* Set or update the entry. */
330 hosttable[tmpidx]->port = port;
335 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
340 log_info ("resolve_dns_addr failed: %s\n",
341 gpg_strerror (tmperr));
349 if (ai->family == AF_INET6)
351 hosttable[tmpidx]->v6 = 1;
352 xfree (hosttable[tmpidx]->v6addr);
353 hosttable[tmpidx]->v6addr = ipaddr;
355 else if (ai->family == AF_INET)
357 hosttable[tmpidx]->v4 = 1;
358 xfree (hosttable[tmpidx]->v4addr);
359 hosttable[tmpidx]->v4addr = ipaddr;
364 for (i=0; i < *refidx; i++)
365 if (reftbl[i] == tmpidx)
367 if (!(i < *refidx) && tmpidx != idx)
368 reftbl[(*refidx)++] = tmpidx;
375 /* Map the host name NAME to the actual to be used host name. This
376 allows us to manage round robin DNS names. We use our own strategy
377 to choose one of the hosts. For example we skip those hosts which
378 failed for some time and we stick to one host for a time
379 independent of DNS retry times. If FORCE_RESELECT is true a new
380 host is always selected. The selected host is stored as a malloced
381 string at R_HOST; on error NULL is stored. If we know the port
382 used by the selected host, a string representation is written to
383 R_PORTSTR, otherwise it is left untouched. If R_HTTPFLAGS is not
384 NULL it will receive flags which are to be passed to http_open. If
385 R_POOLNAME is not NULL a malloced name of the pool is stored or
386 NULL if it is not a pool. */
388 map_host (ctrl_t ctrl, const char *name, int force_reselect,
389 char **r_host, char *r_portstr,
390 unsigned int *r_httpflags, char **r_poolname)
402 /* No hostname means localhost. */
405 *r_host = xtrystrdup ("localhost");
406 return *r_host? 0 : gpg_error_from_syserror ();
409 /* See whether the host is in our table. */
410 idx = find_hostinfo (name);
411 if (idx == -1 && is_onion_address (name))
413 idx = create_new_hostinfo (name);
415 return gpg_error_from_syserror ();
421 /* We never saw this host. Allocate a new entry. */
422 dns_addrinfo_t aibuf, ai;
429 struct srventry *srvs;
430 unsigned int srvscount;
433 reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
435 return gpg_error_from_syserror ();
438 idx = create_new_hostinfo (name);
441 err = gpg_error_from_syserror ();
447 if (!is_ip_address (name))
449 /* Check for SRV records. */
450 srvrecord = xtryasprintf ("_hkp._tcp.%s", name);
451 if (srvrecord == NULL)
453 err = gpg_error_from_syserror ();
458 err = get_dns_srv (srvrecord, &srvs, &srvscount);
469 is_pool = srvscount > 1;
471 for (i = 0; i < srvscount; i++)
473 err = resolve_dns_name (srvs[i].target, 0,
474 AF_UNSPEC, SOCK_STREAM,
479 add_host (name, is_pool, ai, srvs[i].port,
480 reftbl, reftblsize, &refidx);
487 /* Find all A records for this entry and put them into the pool
489 err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
492 log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
497 /* First figure out whether this is a pool. For a pool we
498 use a different strategy than for a plain server: We use
499 the canonical name of the pool as the virtual host along
500 with the IP addresses. If it is not a pool, we use the
503 is_pool = arecords_is_pool (aibuf);
504 if (is_pool && cname)
510 for (ai = aibuf; ai; ai = ai->next)
512 if (ai->family != AF_INET && ai->family != AF_INET6)
516 add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
521 free_dns_addrinfo (aibuf);
523 if (refidx && is_pool)
526 hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
529 err = gpg_error_from_syserror ();
530 log_error ("shrinking index table in map_host failed: %s\n",
535 qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool);
544 /* Deal with the pool name before selecting a host. */
547 *r_poolname = xtrystrdup (hi->cname? hi->cname : hi->name);
549 return gpg_error_from_syserror ();
552 /* If the currently selected host is now marked dead, force a
556 else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
557 && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead)
560 /* Select a host if needed. */
561 if (hi->poolidx == -1)
563 hi->poolidx = select_random_host (hi->pool);
564 if (hi->poolidx == -1)
566 log_error ("no alive host found in pool '%s'\n", name);
572 return gpg_error (GPG_ERR_NO_KEYSERVER);
576 assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
577 hi = hosttable[hi->poolidx];
583 log_error ("host '%s' marked as dead\n", hi->name);
589 return gpg_error (GPG_ERR_NO_KEYSERVER);
594 /* If the hosttable does not indicate that a certain host
595 supports IPv<N>, we explicit set the corresponding http
596 flags. The reason for this is that a host might be listed in
597 a pool as not v6 only but actually support v6 when later
598 the name is resolved by our http layer. */
600 *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
602 *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
604 /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
605 addresses because the http module detects this itself. This
606 also allows us to use an onion address without Tor mode being
610 *r_host = xtrystrdup (hi->name);
613 err = gpg_error_from_syserror ();
622 snprintf (r_portstr, 6 /* five digits and the sentinel */,
628 /* Mark the host NAME as dead. NAME may be given as an URL. Returns
629 true if a host was really marked as dead or was already marked dead
630 (e.g. by a concurrent session). */
632 mark_host_dead (const char *name)
635 char *host_buffer = NULL;
636 parsed_uri_t parsed_uri = NULL;
639 if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
641 if (parsed_uri->v6lit)
643 host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
645 log_error ("out of core in mark_host_dead");
649 host = parsed_uri->host;
654 if (host && *host && strcmp (host, "localhost"))
659 idx = find_hostinfo (host);
663 log_info ("marking host '%s' as dead%s\n",
664 hi->name, hi->dead? " (again)":"");
666 hi->died_at = gnupg_get_time ();
673 http_release_parsed_uri (parsed_uri);
679 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
682 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
686 int idx, idx2, idx3, n;
688 if (!name || !*name || !strcmp (name, "localhost"))
691 idx = find_hostinfo (name);
693 return gpg_error (GPG_ERR_NOT_FOUND);
696 if (alive && hi->dead)
699 err = ks_printf_help (ctrl, "marking '%s' as alive", name);
701 else if (!alive && !hi->dead)
704 hi->died_at = 0; /* Manually set dead. */
705 err = ks_printf_help (ctrl, "marking '%s' as dead", name);
708 /* If the host is a pool mark all member hosts. */
709 if (!err && hi->pool)
711 for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
713 assert (n >= 0 && n < hosttable_size);
717 /* Do not mark a host from a pool dead if it is also a
718 member in another pool. */
719 for (idx3=0; idx3 < hosttable_size; idx3++)
722 && hosttable[idx3]->pool
724 && host_in_pool_p (hosttable[idx3]->pool, n))
727 if (idx3 < hosttable_size)
728 continue; /* Host is also a member of another pool. */
734 else if (alive && hi2->dead)
737 err = ks_printf_help (ctrl, "marking '%s' as alive",
740 else if (!alive && !hi2->dead)
743 hi2->died_at = 0; /* Manually set dead. */
744 err = ks_printf_help (ctrl, "marking '%s' as dead",
754 /* Debug function to print the entire hosttable. */
756 ks_hkp_print_hosttable (ctrl_t ctrl)
766 err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
770 curtime = gnupg_get_time ();
771 for (idx=0; idx < hosttable_size; idx++)
772 if ((hi=hosttable[idx]))
774 if (hi->dead && hi->died_at)
776 died = elapsed_time_string (hi->died_at, curtime);
777 diedstr = died? died : "error";
780 diedstr = died = NULL;
781 err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
783 hi->onion? "O" : hi->v6? "6":" ",
787 hi->v6addr? " v6=":"",
788 hi->v6addr? hi->v6addr:"",
789 hi->v4addr? " v4=":"",
790 hi->v4addr? hi->v4addr:"",
799 err = ks_printf_help (ctrl, " . %s", hi->cname);
805 init_membuf (&mb, 256);
806 put_membuf_printf (&mb, " . -->");
807 for (idx2=0; hi->pool[idx2] != -1; idx2++)
809 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
810 if (hi->poolidx == hi->pool[idx2])
811 put_membuf_printf (&mb, "*");
813 put_membuf( &mb, "", 1);
814 p = get_membuf (&mb, NULL);
816 return gpg_error_from_syserror ();
817 err = ks_print_help (ctrl, p);
828 /* Print a help output for the schemata supported by this module. */
830 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
832 const char const data[] =
833 "Handler for HKP URLs:\n"
835 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
838 "Supported methods: search, get, put\n";
841 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
842 const char data2[] = " hkp\n hkps";
844 const char data2[] = " hkp";
848 err = ks_print_help (ctrl, data2);
849 else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
850 || !strcmp (uri->scheme, "hkps")))
851 err = ks_print_help (ctrl, data);
859 /* Build the remote part of the URL from SCHEME, HOST and an optional
860 PORT. Returns an allocated string at R_HOSTPORT or NULL on failure
861 If R_POOLNAME is not NULL it receives a malloced string with the
864 make_host_part (ctrl_t ctrl,
865 const char *scheme, const char *host, unsigned short port,
867 char **r_hostport, unsigned int *r_httpflags, char **r_poolname)
876 err = map_host (ctrl, host, force_reselect,
877 &hostname, portstr, r_httpflags, r_poolname);
881 /* Map scheme and port. */
882 if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
886 strcpy (portstr, "443");
888 else /* HKP or HTTP. */
892 strcpy (portstr, "11371");
895 snprintf (portstr, sizeof portstr, "%hu", port);
898 /*fixme_do_srv_lookup ()*/
901 *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
910 return gpg_error_from_syserror ();
916 /* Resolve all known keyserver names and update the hosttable. This
917 is mainly useful for debugging because the resolving is anyway done
920 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
923 char *hostport = NULL;
925 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1,
926 &hostport, NULL, NULL);
929 err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
930 uri->scheme, uri->host, uri->port,
935 err = ks_printf_help (ctrl, "%s", hostport);
942 /* Housekeeping function called from the housekeeping thread. It is
943 used to mark dead hosts alive so that they may be tried again after
946 ks_hkp_housekeeping (time_t curtime)
951 for (idx=0; idx < hosttable_size; idx++)
959 continue; /* Do not resurrect manually shot hosts. */
960 if (hi->died_at + RESURRECT_INTERVAL <= curtime
961 || hi->died_at > curtime)
964 log_info ("resurrected host '%s'", hi->name);
970 /* Send an HTTP request. On success returns an estream object at
971 R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is
972 not NULL it will be used as HTTP "Host" header. If POST_CB is not
973 NULL a post request is used and that callback is called to allow
974 writing the post data. If R_HTTP_STATUS is not NULL, the http
975 status code will be stored there. */
977 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
978 const char *httphost, unsigned int httpflags,
979 gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
980 estream_t *r_fp, unsigned int *r_http_status)
983 http_session_t session = NULL;
985 int redirects_left = MAX_REDIRECTS;
987 char *request_buffer = NULL;
991 err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
994 http_session_set_log_cb (session, cert_log_cb);
997 err = http_open (&http,
998 post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1001 /* fixme: AUTH */ NULL,
1003 |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1004 |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
1008 /*FIXME curl->srvtag*/NULL);
1011 fp = http_get_write_ptr (http);
1012 /* Avoid caches to get the most recent copy of the key. We set
1013 both the Pragma and Cache-Control versions of the header, so
1014 we're good with both HTTP 1.0 and 1.1. */
1015 es_fputs ("Pragma: no-cache\r\n"
1016 "Cache-Control: no-cache\r\n", fp);
1018 err = post_cb (post_cb_value, http);
1021 http_start_data (http);
1023 err = gpg_error_from_syserror ();
1028 /* Fixme: After a redirection we show the old host name. */
1029 log_error (_("error connecting to '%s': %s\n"),
1030 hostportstr, gpg_strerror (err));
1034 /* Wait for the response. */
1035 dirmngr_tick (ctrl);
1036 err = http_wait_response (http);
1039 log_error (_("error reading HTTP response for '%s': %s\n"),
1040 hostportstr, gpg_strerror (err));
1044 if (http_get_tls_info (http, NULL))
1046 /* Update the httpflags so that a redirect won't fallback to an
1047 unencrypted connection. */
1048 httpflags |= HTTP_FLAG_FORCE_TLS;
1052 *r_http_status = http_get_status_code (http);
1054 switch (http_get_status_code (http))
1058 break; /* Success. */
1064 const char *s = http_get_header (http, "Location");
1066 log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1067 request, s?s:"[none]", http_get_status_code (http));
1068 if (s && *s && redirects_left-- )
1070 xfree (request_buffer);
1071 request_buffer = xtrystrdup (s);
1074 request = request_buffer;
1075 http_close (http, 0);
1079 err = gpg_error_from_syserror ();
1082 err = gpg_error (GPG_ERR_NO_DATA);
1083 log_error (_("too many redirections\n"));
1088 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1092 log_error (_("error accessing '%s': http status %u\n"),
1093 request, http_get_status_code (http));
1094 err = gpg_error (GPG_ERR_NO_DATA);
1098 /* FIXME: We should register a permanent redirection and whether a
1099 host has ever used TLS so that future calls will always use
1102 fp = http_get_read_ptr (http);
1105 err = gpg_error (GPG_ERR_BUG);
1109 /* Return the read stream and close the HTTP context. */
1111 http_close (http, 1);
1115 http_close (http, 0);
1116 http_session_release (session);
1117 xfree (request_buffer);
1122 /* Helper to evaluate the error code ERR form a send_request() call
1123 with REQUEST. The function returns true if the caller shall try
1124 again. TRIES_LEFT points to a variable to track the number of
1125 retries; this function decrements it and won't return true if it is
1128 handle_send_request_error (gpg_error_t err, const char *request,
1129 unsigned int *tries_left)
1133 switch (gpg_err_code (err))
1135 case GPG_ERR_ECONNREFUSED:
1136 case GPG_ERR_ENETUNREACH:
1137 case GPG_ERR_UNKNOWN_HOST:
1138 case GPG_ERR_NETWORK:
1139 if (mark_host_dead (request) && *tries_left)
1143 case GPG_ERR_ETIMEDOUT:
1146 log_info ("selecting a different host due to a timeout\n");
1161 /* Search the keyserver identified by URI for keys matching PATTERN.
1162 On success R_FP has an open stream to read the data. If
1163 R_HTTP_STATUS is not NULL, the http status code will be stored
1166 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1167 estream_t *r_fp, unsigned int *r_http_status)
1170 KEYDB_SEARCH_DESC desc;
1171 char fprbuf[2+40+1];
1172 char *hostport = NULL;
1173 char *request = NULL;
1174 estream_t fp = NULL;
1176 unsigned int httpflags;
1177 char *httphost = NULL;
1178 unsigned int tries = SEND_REQUEST_RETRIES;
1182 /* Remove search type indicator and adjust PATTERN accordingly.
1183 Note that HKP keyservers like the 0x to be present when searching
1184 by keyid. We need to re-format the fingerprint and keyids so to
1185 remove the gpg specific force-use-of-this-key flag ("!"). */
1186 err = classify_user_id (pattern, &desc, 1);
1191 case KEYDB_SEARCH_MODE_EXACT:
1192 case KEYDB_SEARCH_MODE_SUBSTR:
1193 case KEYDB_SEARCH_MODE_MAIL:
1194 case KEYDB_SEARCH_MODE_MAILSUB:
1195 pattern = desc.u.name;
1197 case KEYDB_SEARCH_MODE_SHORT_KID:
1198 snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1201 case KEYDB_SEARCH_MODE_LONG_KID:
1202 snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1203 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1206 case KEYDB_SEARCH_MODE_FPR16:
1209 bin2hex (desc.u.fpr, 16, fprbuf+2);
1212 case KEYDB_SEARCH_MODE_FPR20:
1213 case KEYDB_SEARCH_MODE_FPR:
1216 bin2hex (desc.u.fpr, 20, fprbuf+2);
1220 return gpg_error (GPG_ERR_INV_USER_ID);
1223 /* Build the request string. */
1229 xfree (hostport); hostport = NULL;
1230 xfree (httphost); httphost = NULL;
1231 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1232 &hostport, &httpflags, &httphost);
1236 searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1239 err = gpg_error_from_syserror ();
1244 request = strconcat (hostport,
1245 "/pks/lookup?op=index&options=mr&search=",
1251 err = gpg_error_from_syserror ();
1256 /* Send the request. */
1257 err = send_request (ctrl, request, hostport, httphost, httpflags,
1258 NULL, NULL, &fp, r_http_status);
1259 if (handle_send_request_error (err, request, &tries))
1267 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1271 /* Peek at the response. */
1273 int c = es_getc (fp);
1276 err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1277 log_error ("error reading response: %s\n", gpg_strerror (err));
1282 /* The document begins with a '<': Assume a HTML response,
1283 which we don't support. */
1284 err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1290 /* Return the read stream. */
1303 /* Get the key described key the KEYSPEC string from the keyserver
1304 identified by URI. On success R_FP has an open stream to read the
1305 data. The data will be provided in a format GnuPG can import
1306 (either a binary OpenPGP message or an armored one). */
1308 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1311 KEYDB_SEARCH_DESC desc;
1312 char kidbuf[2+40+1];
1313 const char *exactname = NULL;
1314 char *searchkey = NULL;
1315 char *hostport = NULL;
1316 char *request = NULL;
1317 estream_t fp = NULL;
1319 char *httphost = NULL;
1320 unsigned int httpflags;
1321 unsigned int tries = SEND_REQUEST_RETRIES;
1325 /* Remove search type indicator and adjust PATTERN accordingly.
1326 Note that HKP keyservers like the 0x to be present when searching
1327 by keyid. We need to re-format the fingerprint and keyids so to
1328 remove the gpg specific force-use-of-this-key flag ("!"). */
1329 err = classify_user_id (keyspec, &desc, 1);
1334 case KEYDB_SEARCH_MODE_SHORT_KID:
1335 snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1337 case KEYDB_SEARCH_MODE_LONG_KID:
1338 snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1339 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1341 case KEYDB_SEARCH_MODE_FPR20:
1342 case KEYDB_SEARCH_MODE_FPR:
1343 /* This is a v4 fingerprint. */
1346 bin2hex (desc.u.fpr, 20, kidbuf+2);
1349 case KEYDB_SEARCH_MODE_EXACT:
1350 exactname = desc.u.name;
1353 case KEYDB_SEARCH_MODE_FPR16:
1354 log_error ("HKP keyservers do not support v3 fingerprints\n");
1356 return gpg_error (GPG_ERR_INV_USER_ID);
1359 searchkey = http_escape_string (exactname? exactname : kidbuf,
1360 EXTRA_ESCAPE_CHARS);
1363 err = gpg_error_from_syserror ();
1369 /* Build the request string. */
1370 xfree (hostport); hostport = NULL;
1371 xfree (httphost); httphost = NULL;
1372 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1373 &hostport, &httpflags, &httphost);
1378 request = strconcat (hostport,
1379 "/pks/lookup?op=get&options=mr&search=",
1381 exactname? "&exact=on":"",
1385 err = gpg_error_from_syserror ();
1389 /* Send the request. */
1390 err = send_request (ctrl, request, hostport, httphost, httpflags,
1391 NULL, NULL, &fp, NULL);
1392 if (handle_send_request_error (err, request, &tries))
1400 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1404 /* Return the read stream and close the HTTP context. */
1420 /* Callback parameters for put_post_cb. */
1421 struct put_post_parm_s
1427 /* Helper for ks_hkp_put. */
1429 put_post_cb (void *opaque, http_t http)
1431 struct put_post_parm_s *parm = opaque;
1432 gpg_error_t err = 0;
1436 fp = http_get_write_ptr (http);
1437 len = strlen (parm->datastring);
1440 "Content-Type: application/x-www-form-urlencoded\r\n"
1441 "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1442 http_start_data (http);
1443 if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1444 err = gpg_error_from_syserror ();
1449 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
1451 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1454 char *hostport = NULL;
1455 char *request = NULL;
1456 estream_t fp = NULL;
1457 struct put_post_parm_s parm;
1458 char *armored = NULL;
1460 char *httphost = NULL;
1461 unsigned int httpflags;
1462 unsigned int tries = SEND_REQUEST_RETRIES;
1464 parm.datastring = NULL;
1466 err = armor_data (&armored, data, datalen);
1470 parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1471 if (!parm.datastring)
1473 err = gpg_error_from_syserror ();
1479 /* Build the request string. */
1482 xfree (hostport); hostport = NULL;
1483 xfree (httphost); httphost = NULL;
1484 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1485 &hostport, &httpflags, &httphost);
1490 request = strconcat (hostport, "/pks/add", NULL);
1493 err = gpg_error_from_syserror ();
1497 /* Send the request. */
1498 err = send_request (ctrl, request, hostport, httphost, 0,
1499 put_post_cb, &parm, &fp, NULL);
1500 if (handle_send_request_error (err, request, &tries))
1510 xfree (parm.datastring);