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 <http://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, tblsize=0; (pidx = table[idx]) != -1; idx++)
219 if (hosttable[pidx] && !hosttable[pidx]->dead)
222 return -1; /* No hosts. */
224 tbl = xtrymalloc (tblsize * sizeof *tbl);
227 for (idx=0, tblsize=0; (pidx = table[idx]) != -1; idx++)
228 if (hosttable[pidx] && !hosttable[pidx]->dead)
229 tbl[tblsize++] = pidx;
231 if (tblsize == 1) /* Save a get_uint_nonce. */
234 pidx = tbl[get_uint_nonce () % tblsize];
241 /* Figure out if a set of DNS records looks like a pool. */
243 arecords_is_pool (dns_addrinfo_t aibuf)
249 for (ai = aibuf; ai; ai = ai->next)
251 if (ai->family == AF_INET6)
253 else if (ai->family == AF_INET)
257 return n_v6 > 1 || n_v4 > 1;
261 /* Add the host AI under the NAME into the HOSTTABLE. If PORT is not
262 zero, it specifies which port to use to talk to the host. If NAME
263 specifies a pool (as indicated by IS_POOL), update the given
264 reference table accordingly. */
266 add_host (const char *name, int is_pool,
267 const dns_addrinfo_t ai, unsigned short port,
268 int *reftbl, size_t reftblsize, int *refidx)
276 idx = find_hostinfo (name);
278 if (!is_pool && !is_ip_address (name))
280 /* This is a hostname but not a pool. Use the name
281 as given without going through resolve_dns_addr. */
282 tmphost = xtrystrdup (name);
284 tmperr = gpg_error_from_syserror ();
290 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
291 DNS_WITHBRACKET, &tmphost);
292 if (tmphost && is_ip_address (tmphost))
298 log_info ("resolve_dns_addr failed while checking '%s': %s\n",
299 name, gpg_strerror (tmperr));
301 else if ((*refidx) + 1 >= reftblsize)
303 log_error ("resolve_dns_addr for '%s': '%s'"
304 " [index table full - ignored]\n", name, tmphost);
308 if (!is_pool && is_ip_address (name))
309 /* Update the original entry. */
312 tmpidx = find_hostinfo (tmphost);
313 log_info ("resolve_dns_addr for '%s': '%s'%s\n",
315 tmpidx == -1? "" : " [already known]");
317 if (tmpidx == -1) /* Create a new entry. */
318 tmpidx = create_new_hostinfo (tmphost);
322 log_error ("map_host for '%s' problem: %s - '%s'"
324 name, strerror (errno), tmphost);
326 else /* Set or update the entry. */
331 hosttable[tmpidx]->port = port;
336 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
341 log_info ("resolve_dns_addr failed: %s\n",
342 gpg_strerror (tmperr));
350 if (ai->family == AF_INET6)
352 hosttable[tmpidx]->v6 = 1;
353 xfree (hosttable[tmpidx]->v6addr);
354 hosttable[tmpidx]->v6addr = ipaddr;
356 else if (ai->family == AF_INET)
358 hosttable[tmpidx]->v4 = 1;
359 xfree (hosttable[tmpidx]->v4addr);
360 hosttable[tmpidx]->v4addr = ipaddr;
365 for (i=0; i < *refidx; i++)
366 if (reftbl[i] == tmpidx)
368 if (!(i < *refidx) && tmpidx != idx)
369 reftbl[(*refidx)++] = tmpidx;
376 /* Map the host name NAME to the actual to be used host name. This
377 allows us to manage round robin DNS names. We use our own strategy
378 to choose one of the hosts. For example we skip those hosts which
379 failed for some time and we stick to one host for a time
380 independent of DNS retry times. If FORCE_RESELECT is true a new
381 host is always selected. The selected host is stored as a malloced
382 string at R_HOST; on error NULL is stored. If we know the port
383 used by the selected host, a string representation is written to
384 R_PORTSTR, otherwise it is left untouched. If R_HTTPFLAGS is not
385 NULL it will receive flags which are to be passed to http_open. If
386 R_POOLNAME is not NULL a malloced name of the pool is stored or
387 NULL if it is not a pool. */
389 map_host (ctrl_t ctrl, const char *name, int force_reselect,
390 char **r_host, char *r_portstr,
391 unsigned int *r_httpflags, char **r_poolname)
403 /* No hostname means localhost. */
406 *r_host = xtrystrdup ("localhost");
407 return *r_host? 0 : gpg_error_from_syserror ();
410 /* See whether the host is in our table. */
411 idx = find_hostinfo (name);
412 if (idx == -1 && is_onion_address (name))
414 idx = create_new_hostinfo (name);
416 return gpg_error_from_syserror ();
422 /* We never saw this host. Allocate a new entry. */
423 dns_addrinfo_t aibuf, ai;
431 struct srventry *srvs;
433 #endif /* USE_DNS_SRV */
436 reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
438 return gpg_error_from_syserror ();
441 idx = create_new_hostinfo (name);
444 err = gpg_error_from_syserror ();
451 /* Check for SRV records. */
452 srvrecord = xtryasprintf ("_hkp._tcp.%s", name);
453 if (srvrecord == NULL)
455 err = gpg_error_from_syserror ();
460 srvscount = getsrv (srvrecord, &srvs);
464 err = gpg_error_from_syserror ();
472 is_pool = srvscount > 1;
474 for (i = 0; i < srvscount; i++)
476 err = resolve_dns_name (srvs[i].target, 0,
477 AF_UNSPEC, SOCK_STREAM,
482 add_host (name, is_pool, ai, srvs[i].port,
483 reftbl, reftblsize, &refidx);
488 #endif /* USE_DNS_SRV */
490 /* Find all A records for this entry and put them into the pool
492 err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
495 log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
500 /* First figure out whether this is a pool. For a pool we
501 use a different strategy than for a plain server: We use
502 the canonical name of the pool as the virtual host along
503 with the IP addresses. If it is not a pool, we use the
506 is_pool = arecords_is_pool (aibuf);
507 if (is_pool && cname)
513 for (ai = aibuf; ai; ai = ai->next)
515 if (ai->family != AF_INET && ai->family != AF_INET6)
519 add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
524 free_dns_addrinfo (aibuf);
526 if (refidx && is_pool)
529 hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
532 err = gpg_error_from_syserror ();
533 log_error ("shrinking index table in map_host failed: %s\n",
538 qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool);
547 /* Deal with the pool name before selecting a host. */
550 *r_poolname = xtrystrdup (hi->cname? hi->cname : hi->name);
552 return gpg_error_from_syserror ();
555 /* If the currently selected host is now marked dead, force a
559 else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
560 && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead)
563 /* Select a host if needed. */
564 if (hi->poolidx == -1)
566 hi->poolidx = select_random_host (hi->pool);
567 if (hi->poolidx == -1)
569 log_error ("no alive host found in pool '%s'\n", name);
575 return gpg_error (GPG_ERR_NO_KEYSERVER);
579 assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
580 hi = hosttable[hi->poolidx];
586 log_error ("host '%s' marked as dead\n", hi->name);
592 return gpg_error (GPG_ERR_NO_KEYSERVER);
597 /* If the hosttable does not indicate that a certain host
598 supports IPv<N>, we explicit set the corresponding http
599 flags. The reason for this is that a host might be listed in
600 a pool as not v6 only but actually support v6 when later
601 the name is resolved by our http layer. */
603 *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
605 *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
607 /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
608 addresses because the http module detects this itself. This
609 also allows us to use an onion address without Tor mode being
613 *r_host = xtrystrdup (hi->name);
616 err = gpg_error_from_syserror ();
625 snprintf (r_portstr, 6 /* five digits and the sentinel */,
631 /* Mark the host NAME as dead. NAME may be given as an URL. Returns
632 true if a host was really marked as dead or was already marked dead
633 (e.g. by a concurrent session). */
635 mark_host_dead (const char *name)
638 char *host_buffer = NULL;
639 parsed_uri_t parsed_uri = NULL;
642 if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
644 if (parsed_uri->v6lit)
646 host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
648 log_error ("out of core in mark_host_dead");
652 host = parsed_uri->host;
657 if (host && *host && strcmp (host, "localhost"))
662 idx = find_hostinfo (host);
666 log_info ("marking host '%s' as dead%s\n",
667 hi->name, hi->dead? " (again)":"");
669 hi->died_at = gnupg_get_time ();
676 http_release_parsed_uri (parsed_uri);
682 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
685 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
689 int idx, idx2, idx3, n;
691 if (!name || !*name || !strcmp (name, "localhost"))
694 idx = find_hostinfo (name);
696 return gpg_error (GPG_ERR_NOT_FOUND);
699 if (alive && hi->dead)
702 err = ks_printf_help (ctrl, "marking '%s' as alive", name);
704 else if (!alive && !hi->dead)
707 hi->died_at = 0; /* Manually set dead. */
708 err = ks_printf_help (ctrl, "marking '%s' as dead", name);
711 /* If the host is a pool mark all member hosts. */
712 if (!err && hi->pool)
714 for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
716 assert (n >= 0 && n < hosttable_size);
720 /* Do not mark a host from a pool dead if it is also a
721 member in another pool. */
722 for (idx3=0; idx3 < hosttable_size; idx3++)
725 && hosttable[idx3]->pool
727 && host_in_pool_p (hosttable[idx3]->pool, n))
730 if (idx3 < hosttable_size)
731 continue; /* Host is also a member of another pool. */
737 else if (alive && hi2->dead)
740 err = ks_printf_help (ctrl, "marking '%s' as alive",
743 else if (!alive && !hi2->dead)
746 hi2->died_at = 0; /* Manually set dead. */
747 err = ks_printf_help (ctrl, "marking '%s' as dead",
757 /* Debug function to print the entire hosttable. */
759 ks_hkp_print_hosttable (ctrl_t ctrl)
769 err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
773 curtime = gnupg_get_time ();
774 for (idx=0; idx < hosttable_size; idx++)
775 if ((hi=hosttable[idx]))
777 if (hi->dead && hi->died_at)
779 died = elapsed_time_string (hi->died_at, curtime);
780 diedstr = died? died : "error";
783 diedstr = died = NULL;
784 err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
786 hi->onion? "O" : hi->v6? "6":" ",
790 hi->v6addr? " v6=":"",
791 hi->v6addr? hi->v6addr:"",
792 hi->v4addr? " v4=":"",
793 hi->v4addr? hi->v4addr:"",
802 err = ks_printf_help (ctrl, " . %s", hi->cname);
808 init_membuf (&mb, 256);
809 put_membuf_printf (&mb, " . -->");
810 for (idx2=0; hi->pool[idx2] != -1; idx2++)
812 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
813 if (hi->poolidx == hi->pool[idx2])
814 put_membuf_printf (&mb, "*");
816 put_membuf( &mb, "", 1);
817 p = get_membuf (&mb, NULL);
819 return gpg_error_from_syserror ();
820 err = ks_print_help (ctrl, p);
831 /* Print a help output for the schemata supported by this module. */
833 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
835 const char const data[] =
836 "Handler for HKP URLs:\n"
838 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
841 "Supported methods: search, get, put\n";
844 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
845 const char data2[] = " hkp\n hkps";
847 const char data2[] = " hkp";
851 err = ks_print_help (ctrl, data2);
852 else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
853 || !strcmp (uri->scheme, "hkps")))
854 err = ks_print_help (ctrl, data);
862 /* Build the remote part of the URL from SCHEME, HOST and an optional
863 PORT. Returns an allocated string at R_HOSTPORT or NULL on failure
864 If R_POOLNAME is not NULL it receives a malloced string with the
867 make_host_part (ctrl_t ctrl,
868 const char *scheme, const char *host, unsigned short port,
870 char **r_hostport, unsigned int *r_httpflags, char **r_poolname)
879 err = map_host (ctrl, host, force_reselect,
880 &hostname, portstr, r_httpflags, r_poolname);
884 /* Map scheme and port. */
885 if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
889 strcpy (portstr, "443");
891 else /* HKP or HTTP. */
895 strcpy (portstr, "11371");
898 snprintf (portstr, sizeof portstr, "%hu", port);
901 /*fixme_do_srv_lookup ()*/
904 *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
913 return gpg_error_from_syserror ();
919 /* Resolve all known keyserver names and update the hosttable. This
920 is mainly useful for debugging because the resolving is anyway done
923 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
926 char *hostport = NULL;
928 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1,
929 &hostport, NULL, NULL);
932 err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
933 uri->scheme, uri->host, uri->port,
938 err = ks_printf_help (ctrl, "%s", hostport);
945 /* Housekeeping function called from the housekeeping thread. It is
946 used to mark dead hosts alive so that they may be tried again after
949 ks_hkp_housekeeping (time_t curtime)
954 for (idx=0; idx < hosttable_size; idx++)
962 continue; /* Do not resurrect manually shot hosts. */
963 if (hi->died_at + RESURRECT_INTERVAL <= curtime
964 || hi->died_at > curtime)
967 log_info ("resurrected host '%s'", hi->name);
973 /* Send an HTTP request. On success returns an estream object at
974 R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is
975 not NULL it will be used as HTTP "Host" header. If POST_CB is not
976 NULL a post request is used and that callback is called to allow
977 writing the post data. If R_HTTP_STATUS is not NULL, the http
978 status code will be stored there. */
980 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
981 const char *httphost, unsigned int httpflags,
982 gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
983 estream_t *r_fp, unsigned int *r_http_status)
986 http_session_t session = NULL;
988 int redirects_left = MAX_REDIRECTS;
990 char *request_buffer = NULL;
994 err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
997 http_session_set_log_cb (session, cert_log_cb);
1000 err = http_open (&http,
1001 post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1004 /* fixme: AUTH */ NULL,
1006 |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1007 |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
1011 /*FIXME curl->srvtag*/NULL);
1014 fp = http_get_write_ptr (http);
1015 /* Avoid caches to get the most recent copy of the key. We set
1016 both the Pragma and Cache-Control versions of the header, so
1017 we're good with both HTTP 1.0 and 1.1. */
1018 es_fputs ("Pragma: no-cache\r\n"
1019 "Cache-Control: no-cache\r\n", fp);
1021 err = post_cb (post_cb_value, http);
1024 http_start_data (http);
1026 err = gpg_error_from_syserror ();
1031 /* Fixme: After a redirection we show the old host name. */
1032 log_error (_("error connecting to '%s': %s\n"),
1033 hostportstr, gpg_strerror (err));
1037 /* Wait for the response. */
1038 dirmngr_tick (ctrl);
1039 err = http_wait_response (http);
1042 log_error (_("error reading HTTP response for '%s': %s\n"),
1043 hostportstr, gpg_strerror (err));
1047 if (http_get_tls_info (http, NULL))
1049 /* Update the httpflags so that a redirect won't fallback to an
1050 unencrypted connection. */
1051 httpflags |= HTTP_FLAG_FORCE_TLS;
1055 *r_http_status = http_get_status_code (http);
1057 switch (http_get_status_code (http))
1061 break; /* Success. */
1067 const char *s = http_get_header (http, "Location");
1069 log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1070 request, s?s:"[none]", http_get_status_code (http));
1071 if (s && *s && redirects_left-- )
1073 xfree (request_buffer);
1074 request_buffer = xtrystrdup (s);
1077 request = request_buffer;
1078 http_close (http, 0);
1082 err = gpg_error_from_syserror ();
1085 err = gpg_error (GPG_ERR_NO_DATA);
1086 log_error (_("too many redirections\n"));
1091 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1095 log_error (_("error accessing '%s': http status %u\n"),
1096 request, http_get_status_code (http));
1097 err = gpg_error (GPG_ERR_NO_DATA);
1101 /* FIXME: We should register a permanent redirection and whether a
1102 host has ever used TLS so that future calls will always use
1105 fp = http_get_read_ptr (http);
1108 err = gpg_error (GPG_ERR_BUG);
1112 /* Return the read stream and close the HTTP context. */
1114 http_close (http, 1);
1118 http_close (http, 0);
1119 http_session_release (session);
1120 xfree (request_buffer);
1125 /* Helper to evaluate the error code ERR form a send_request() call
1126 with REQUEST. The function returns true if the caller shall try
1127 again. TRIES_LEFT points to a variable to track the number of
1128 retries; this function decrements it and won't return true if it is
1131 handle_send_request_error (gpg_error_t err, const char *request,
1132 unsigned int *tries_left)
1136 switch (gpg_err_code (err))
1138 case GPG_ERR_ECONNREFUSED:
1139 case GPG_ERR_ENETUNREACH:
1140 case GPG_ERR_UNKNOWN_HOST:
1141 case GPG_ERR_NETWORK:
1142 if (mark_host_dead (request) && *tries_left)
1146 case GPG_ERR_ETIMEDOUT:
1149 log_info ("selecting a different host due to a timeout\n");
1164 /* Search the keyserver identified by URI for keys matching PATTERN.
1165 On success R_FP has an open stream to read the data. If
1166 R_HTTP_STATUS is not NULL, the http status code will be stored
1169 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1170 estream_t *r_fp, unsigned int *r_http_status)
1173 KEYDB_SEARCH_DESC desc;
1174 char fprbuf[2+40+1];
1175 char *hostport = NULL;
1176 char *request = NULL;
1177 estream_t fp = NULL;
1179 unsigned int httpflags;
1180 char *httphost = NULL;
1181 unsigned int tries = SEND_REQUEST_RETRIES;
1185 /* Remove search type indicator and adjust PATTERN accordingly.
1186 Note that HKP keyservers like the 0x to be present when searching
1187 by keyid. We need to re-format the fingerprint and keyids so to
1188 remove the gpg specific force-use-of-this-key flag ("!"). */
1189 err = classify_user_id (pattern, &desc, 1);
1194 case KEYDB_SEARCH_MODE_EXACT:
1195 case KEYDB_SEARCH_MODE_SUBSTR:
1196 case KEYDB_SEARCH_MODE_MAIL:
1197 case KEYDB_SEARCH_MODE_MAILSUB:
1198 pattern = desc.u.name;
1200 case KEYDB_SEARCH_MODE_SHORT_KID:
1201 snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1204 case KEYDB_SEARCH_MODE_LONG_KID:
1205 snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1206 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1209 case KEYDB_SEARCH_MODE_FPR16:
1212 bin2hex (desc.u.fpr, 16, fprbuf+2);
1215 case KEYDB_SEARCH_MODE_FPR20:
1216 case KEYDB_SEARCH_MODE_FPR:
1219 bin2hex (desc.u.fpr, 20, fprbuf+2);
1223 return gpg_error (GPG_ERR_INV_USER_ID);
1226 /* Build the request string. */
1232 xfree (hostport); hostport = NULL;
1233 xfree (httphost); httphost = NULL;
1234 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1235 &hostport, &httpflags, &httphost);
1239 searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1242 err = gpg_error_from_syserror ();
1247 request = strconcat (hostport,
1248 "/pks/lookup?op=index&options=mr&search=",
1254 err = gpg_error_from_syserror ();
1259 /* Send the request. */
1260 err = send_request (ctrl, request, hostport, httphost, httpflags,
1261 NULL, NULL, &fp, r_http_status);
1262 if (handle_send_request_error (err, request, &tries))
1270 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1274 /* Peek at the response. */
1276 int c = es_getc (fp);
1279 err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1280 log_error ("error reading response: %s\n", gpg_strerror (err));
1285 /* The document begins with a '<': Assume a HTML response,
1286 which we don't support. */
1287 err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1293 /* Return the read stream. */
1306 /* Get the key described key the KEYSPEC string from the keyserver
1307 identified by URI. On success R_FP has an open stream to read the
1308 data. The data will be provided in a format GnuPG can import
1309 (either a binary OpenPGP message or an armored one). */
1311 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1314 KEYDB_SEARCH_DESC desc;
1315 char kidbuf[2+40+1];
1316 const char *exactname = NULL;
1317 char *searchkey = NULL;
1318 char *hostport = NULL;
1319 char *request = NULL;
1320 estream_t fp = NULL;
1322 char *httphost = NULL;
1323 unsigned int httpflags;
1324 unsigned int tries = SEND_REQUEST_RETRIES;
1328 /* Remove search type indicator and adjust PATTERN accordingly.
1329 Note that HKP keyservers like the 0x to be present when searching
1330 by keyid. We need to re-format the fingerprint and keyids so to
1331 remove the gpg specific force-use-of-this-key flag ("!"). */
1332 err = classify_user_id (keyspec, &desc, 1);
1337 case KEYDB_SEARCH_MODE_SHORT_KID:
1338 snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1340 case KEYDB_SEARCH_MODE_LONG_KID:
1341 snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1342 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1344 case KEYDB_SEARCH_MODE_FPR20:
1345 case KEYDB_SEARCH_MODE_FPR:
1346 /* This is a v4 fingerprint. */
1349 bin2hex (desc.u.fpr, 20, kidbuf+2);
1352 case KEYDB_SEARCH_MODE_EXACT:
1353 exactname = desc.u.name;
1356 case KEYDB_SEARCH_MODE_FPR16:
1357 log_error ("HKP keyservers do not support v3 fingerprints\n");
1359 return gpg_error (GPG_ERR_INV_USER_ID);
1362 searchkey = http_escape_string (exactname? exactname : kidbuf,
1363 EXTRA_ESCAPE_CHARS);
1366 err = gpg_error_from_syserror ();
1372 /* Build the request string. */
1373 xfree (hostport); hostport = NULL;
1374 xfree (httphost); httphost = NULL;
1375 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1376 &hostport, &httpflags, &httphost);
1381 request = strconcat (hostport,
1382 "/pks/lookup?op=get&options=mr&search=",
1384 exactname? "&exact=on":"",
1388 err = gpg_error_from_syserror ();
1392 /* Send the request. */
1393 err = send_request (ctrl, request, hostport, httphost, httpflags,
1394 NULL, NULL, &fp, NULL);
1395 if (handle_send_request_error (err, request, &tries))
1403 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1407 /* Return the read stream and close the HTTP context. */
1423 /* Callback parameters for put_post_cb. */
1424 struct put_post_parm_s
1430 /* Helper for ks_hkp_put. */
1432 put_post_cb (void *opaque, http_t http)
1434 struct put_post_parm_s *parm = opaque;
1435 gpg_error_t err = 0;
1439 fp = http_get_write_ptr (http);
1440 len = strlen (parm->datastring);
1443 "Content-Type: application/x-www-form-urlencoded\r\n"
1444 "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1445 http_start_data (http);
1446 if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1447 err = gpg_error_from_syserror ();
1452 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
1454 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1457 char *hostport = NULL;
1458 char *request = NULL;
1459 estream_t fp = NULL;
1460 struct put_post_parm_s parm;
1461 char *armored = NULL;
1463 char *httphost = NULL;
1464 unsigned int httpflags;
1465 unsigned int tries = SEND_REQUEST_RETRIES;
1467 parm.datastring = NULL;
1469 err = armor_data (&armored, data, datalen);
1473 parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1474 if (!parm.datastring)
1476 err = gpg_error_from_syserror ();
1482 /* Build the request string. */
1485 xfree (hostport); hostport = NULL;
1486 xfree (httphost); httphost = NULL;
1487 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1488 &hostport, &httpflags, &httphost);
1493 request = strconcat (hostport, "/pks/add", NULL);
1496 err = gpg_error_from_syserror ();
1500 /* Send the request. */
1501 err = send_request (ctrl, request, hostport, httphost, 0,
1502 put_post_cb, &parm, &fp, NULL);
1503 if (handle_send_request_error (err, request, &tries))
1513 xfree (parm.datastring);