aboutsummaryrefslogtreecommitdiffstats
path: root/dirmngr
diff options
context:
space:
mode:
Diffstat (limited to 'dirmngr')
-rw-r--r--dirmngr/Makefile.am11
-rw-r--r--dirmngr/cdb.h2
-rw-r--r--dirmngr/cdblib.c6
-rw-r--r--dirmngr/crlcache.c8
-rw-r--r--dirmngr/dirmngr.c22
-rw-r--r--dirmngr/dirmngr.h2
-rw-r--r--dirmngr/dirmngr_ldap.c4
-rw-r--r--dirmngr/dns-stuff.c39
-rw-r--r--dirmngr/dns.c175
-rw-r--r--dirmngr/dns.h54
-rw-r--r--dirmngr/domaininfo.c2
-rw-r--r--dirmngr/http-ntbtls.c2
-rw-r--r--dirmngr/http.c230
-rw-r--r--dirmngr/http.h23
-rw-r--r--dirmngr/ks-action.c2
-rw-r--r--dirmngr/ks-engine-hkp.c202
-rw-r--r--dirmngr/ks-engine-http.c68
-rw-r--r--dirmngr/ks-engine-ldap.c35
-rw-r--r--dirmngr/ldap.c2
-rw-r--r--dirmngr/misc.c4
-rw-r--r--dirmngr/ocsp.c33
-rw-r--r--dirmngr/server.c114
-rw-r--r--dirmngr/t-http-basic.c199
-rw-r--r--dirmngr/t-http.c6
-rw-r--r--dirmngr/workqueue.c2
25 files changed, 919 insertions, 328 deletions
diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am
index 22b8c1a3a..098e711e9 100644
--- a/dirmngr/Makefile.am
+++ b/dirmngr/Makefile.am
@@ -120,7 +120,7 @@ t_common_ldadd = $(libcommon) $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) \
$(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \
$(DNSLIBS) $(LIBINTL) $(LIBICONV)
-module_tests =
+module_tests = t-http-basic
if USE_LDAP
module_tests += t-ldap-parse-uri
@@ -151,6 +151,15 @@ t_http_CFLAGS = -DWITHOUT_NPTH=1 $(USE_C99_CFLAGS) \
t_http_LDADD = $(t_common_ldadd) \
$(NTBTLS_LIBS) $(KSBA_LIBS) $(LIBGNUTLS_LIBS) $(DNSLIBS)
+t_http_basic_SOURCES = $(t_common_src) t-http-basic.c http.c \
+ dns-stuff.c http-common.c
+t_http_basic_CFLAGS = -DWITHOUT_NPTH=1 $(USE_C99_CFLAGS) \
+ $(LIBGCRYPT_CFLAGS) $(NTBTLS_CFLAGS) $(LIBGNUTLS_CFLAGS) \
+ $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS) $(KSBA_CFLAGS)
+t_http_basic_LDADD = $(t_common_ldadd) \
+ $(NTBTLS_LIBS) $(KSBA_LIBS) $(LIBGNUTLS_LIBS) $(DNSLIBS)
+
+
t_ldap_parse_uri_SOURCES = \
t-ldap-parse-uri.c ldap-parse-uri.c ldap-parse-uri.h \
http.c http-common.c dns-stuff.c \
diff --git a/dirmngr/cdb.h b/dirmngr/cdb.h
index 0c0d2702a..5d46f6956 100644
--- a/dirmngr/cdb.h
+++ b/dirmngr/cdb.h
@@ -85,7 +85,7 @@ int cdb_make_put(struct cdb_make *cdbmp,
const void *key, cdbi_t klen,
const void *val, cdbi_t vlen,
int flag);
-#define CDB_PUT_ADD 0 /* add unconditionnaly, like cdb_make_add() */
+#define CDB_PUT_ADD 0 /* add unconditionally, like cdb_make_add() */
#define CDB_PUT_REPLACE 1 /* replace: do not place to index OLD record */
#define CDB_PUT_INSERT 2 /* add only if not already exists */
#define CDB_PUT_WARN 3 /* add unconditionally but ret. 1 if exists */
diff --git a/dirmngr/cdblib.c b/dirmngr/cdblib.c
index 827399f7e..c40126396 100644
--- a/dirmngr/cdblib.c
+++ b/dirmngr/cdblib.c
@@ -19,7 +19,7 @@
length, meaning that corresponding hash table is empty.
Right after toc section, data section follows without any
- alingment. It consists of series of records, each is a key length,
+ alignment. It consists of series of records, each is a key length,
value (data) length, key and value. Again, key and value length
are 4-byte unsigned integers. Each next record follows previous
without any special alignment.
@@ -52,7 +52,7 @@
beginning of a table). When hash value in question is found in
hash table, look to key of corresponding record, comparing it with
key in question. If them of the same length and equals to each
- other, then record is found, overwise, repeat with next hash table
+ other, then record is found, otherwise, repeat with next hash table
slot. Note that there may be several records with the same key.
*/
@@ -245,7 +245,7 @@ cdb_find(struct cdb *cdbp, const void *key, cdbi_t klen)
pos = cdb_unpack(htp); /* htab position */
if (n > (cdbp->cdb_fsize >> 3) /* overflow of httodo ? */
|| pos > cdbp->cdb_fsize /* htab start within file ? */
- || httodo > cdbp->cdb_fsize - pos) /* entrie htab within file ? */
+ || httodo > cdbp->cdb_fsize - pos) /* htab entry within file ? */
{
gpg_err_set_errno (EPROTO);
return -1;
diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c
index fbe3beea1..c9e5ca68f 100644
--- a/dirmngr/crlcache.c
+++ b/dirmngr/crlcache.c
@@ -1250,13 +1250,15 @@ crl_cache_deinit (void)
}
-/* Delete the cache from disk. Return 0 on success.*/
+/* Delete the cache from disk and memory. Return 0 on success.*/
int
crl_cache_flush (void)
{
int rc;
+ crl_cache_deinit ();
rc = cleanup_cache_dir (0)? -1 : 0;
+ crl_cache_init ();
return rc;
}
@@ -1782,7 +1784,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
ksba_sexp_t keyid;
/* We need to look for the issuer only after having read
- all items. The issuer itselfs comes before the items
+ all items. The issuer itself comes before the items
but the optional authorityKeyIdentifier comes after the
items. */
err = ksba_crl_get_issuer (crl, &crlissuer);
@@ -1907,7 +1909,7 @@ get_crl_number (ksba_crl_t crl)
/* Return the authorityKeyIdentifier or NULL if it is not available.
- The issuer name may consists of several parts - they are delimted by
+ The issuer name may consists of several parts - they are delimited by
0x01. */
static char *
get_auth_key_id (ksba_crl_t crl, char **serialno)
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index 6fdfe36c2..3a99a2e2e 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -338,7 +338,7 @@ static int active_connections;
* thread to run background network tasks. */
static int network_activity_seen;
-/* A list of filenames registred with --hkp-cacert. */
+/* A list of filenames registered with --hkp-cacert. */
static strlist_t hkp_cacert_filenames;
@@ -411,7 +411,7 @@ my_strusage( int level )
/* Callback from libksba to hash a provided buffer. Our current
implementation does only allow SHA-1 for hashing. This may be
- extended by mapping the name, testing for algorithm availibility
+ extended by mapping the name, testing for algorithm availability
and adjust the length checks accordingly. */
static gpg_error_t
my_ksba_hash_buffer (void *arg, const char *oid,
@@ -520,7 +520,7 @@ set_tor_mode (void)
{
if (dirmngr_use_tor ())
{
- /* Enable Tor mode and when called again force a new curcuit
+ /* Enable Tor mode and when called again force a new circuit
* (e.g. on SIGHUP). */
enable_dns_tormode (1);
if (assuan_sock_set_flag (ASSUAN_INVALID_FD, "tor-mode", 1))
@@ -752,7 +752,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
}
-/* This fucntion is called after option parsing to adjust some values
+/* This function is called after option parsing to adjust some values
* and call option setup functions. */
static void
post_option_parsing (void)
@@ -763,7 +763,6 @@ post_option_parsing (void)
opt.connect_quick_timeout = opt.connect_timeout;
set_debug ();
- set_tor_mode ();
}
@@ -802,6 +801,7 @@ static void
thread_init (void)
{
npth_init ();
+ assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* Now with NPth running we can set the logging callback. Our
@@ -877,7 +877,6 @@ main (int argc, char **argv)
assuan_set_malloc_hooks (&malloc_hooks);
assuan_set_assuan_log_prefix (log_get_prefix (NULL));
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
- assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
assuan_sock_init ();
setup_libassuan_logging (&opt.debug, dirmngr_assuan_log_monitor);
@@ -1090,7 +1089,12 @@ main (int argc, char **argv)
log_printf ("\n");
}
+ /* Note that we do not run set_tor_mode in --gpgconf-list mode
+ * because it will attempt to connect to the tor client and that can
+ * be time consuming. */
post_option_parsing ();
+ if (cmd != aGPGConfTest && cmd != aGPGConfList)
+ set_tor_mode ();
/* Get LDAP server list from file. */
#if USE_LDAP
@@ -1143,6 +1147,7 @@ main (int argc, char **argv)
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
+ ks_hkp_init ();
http_register_netactivity_cb (netactivity_action);
start_command_handler (ASSUAN_INVALID_FD, 0);
shutdown_reaper ();
@@ -1178,6 +1183,7 @@ main (int argc, char **argv)
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
+ ks_hkp_init ();
http_register_netactivity_cb (netactivity_action);
handle_connections (3);
shutdown_reaper ();
@@ -1399,6 +1405,7 @@ main (int argc, char **argv)
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
+ ks_hkp_init ();
http_register_netactivity_cb (netactivity_action);
handle_connections (fd);
shutdown_reaper ();
@@ -1421,6 +1428,7 @@ main (int argc, char **argv)
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
+ ks_hkp_init ();
if (!argc)
rc = crl_cache_load (&ctrlbuf, NULL);
else
@@ -1444,6 +1452,7 @@ main (int argc, char **argv)
thread_init ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
+ ks_hkp_init ();
rc = crl_fetch (&ctrlbuf, argv[0], &reader);
if (rc)
log_error (_("fetching CRL from '%s' failed: %s\n"),
@@ -1859,6 +1868,7 @@ dirmngr_sighup_action (void)
log_info (_("SIGHUP received - "
"re-reading configuration and flushing caches\n"));
reread_configuration ();
+ set_tor_mode ();
cert_cache_deinit (0);
crl_cache_deinit ();
cert_cache_init (hkp_cacert_filenames);
diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h
index edaf46394..9c26c09e6 100644
--- a/dirmngr/dirmngr.h
+++ b/dirmngr/dirmngr.h
@@ -218,7 +218,7 @@ int dirmngr_use_tor (void);
/*-- Various housekeeping functions. --*/
void ks_hkp_housekeeping (time_t curtime);
void ks_hkp_reload (void);
-
+void ks_hkp_init (void);
/*-- server.c --*/
ldap_server_t get_ldapservers_from_ctrl (ctrl_t ctrl);
diff --git a/dirmngr/dirmngr_ldap.c b/dirmngr/dirmngr_ldap.c
index 8452c3ba0..dd7e4bda5 100644
--- a/dirmngr/dirmngr_ldap.c
+++ b/dirmngr/dirmngr_ldap.c
@@ -417,9 +417,9 @@ set_timeout (my_opt_t myopt)
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
- /* Create a manual resetable timer. */
+ /* Create a manual resettable timer. */
timer = CreateWaitableTimer (NULL, TRUE, NULL);
- /* Intially set the timer. */
+ /* Initially set the timer. */
SetWaitableTimer (timer, &due_time, 0, NULL, NULL, 0);
if (CreateThread (&sec_attr, 0, alarm_thread, timer, 0, &tid))
diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
index 09b17c0fb..e48aca730 100644
--- a/dirmngr/dns-stuff.c
+++ b/dirmngr/dns-stuff.c
@@ -151,7 +151,7 @@ static char tor_socks_password[20];
#ifdef USE_LIBDNS
-/* Libdns gobal data. */
+/* Libdns global data. */
struct libdns_s
{
struct dns_resolv_conf *resolv_conf;
@@ -701,6 +701,11 @@ libdns_res_open (ctrl_t ctrl, struct dns_resolver **r_res)
gpg_error_t err;
struct dns_resolver *res;
int derr;
+ struct dns_options opts = { 0 };
+
+ opts.socks_host = &libdns.socks_host;
+ opts.socks_user = tor_socks_user;
+ opts.socks_password = tor_socks_password;
*r_res = NULL;
@@ -726,10 +731,7 @@ libdns_res_open (ctrl_t ctrl, struct dns_resolver **r_res)
set_dns_timeout (0);
res = dns_res_open (libdns.resolv_conf, libdns.hosts, libdns.hints, NULL,
- dns_opts (.socks_host = &libdns.socks_host,
- .socks_user = tor_socks_user,
- .socks_password = tor_socks_password ),
- &derr);
+ &opts, &derr);
if (!res)
return libdns_error_to_gpg_error (derr);
@@ -1056,16 +1058,17 @@ resolve_name_standard (ctrl_t ctrl, const char *name, unsigned short port,
/* This a wrapper around getaddrinfo with slightly different semantics.
- NAME is the name to resolve.
- PORT is the requested port or 0.
- WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
- WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
-
- On success the result is stored in a linked list with the head
- stored at the address R_AI; the caller must call gpg_addrinfo_free
- on this. If R_CANONNAME is not NULL the official name of the host
- is stored there as a malloced string; if that name is not available
- NULL is stored. */
+ * NAME is the name to resolve.
+ * PORT is the requested port or 0.
+ * WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
+ * WANT_SOCKETTYPE is either 0 for any socket type
+ * or SOCK_STREAM or SOCK_DGRAM.
+ *
+ * On success the result is stored in a linked list with the head
+ * stored at the address R_AI; the caller must call free_dns_addrinfo
+ * on this. If R_CANONNAME is not NULL the official name of the host
+ * is stored there as a malloced string; if that name is not available
+ * NULL is stored. */
gpg_error_t
resolve_dns_name (ctrl_t ctrl, const char *name, unsigned short port,
int want_family, int want_socktype,
@@ -1167,7 +1170,7 @@ resolve_addr_libdns (ctrl_t ctrl,
struct dns_rr_i rri;
memset (&rri, 0, sizeof rri);
- dns_rr_i_init (&rri, ans);
+ dns_rr_i_init (&rri);
rri.section = DNS_S_ALL & ~DNS_S_QD;
rri.name = host;
rri.type = DNS_T_PTR;
@@ -1458,7 +1461,7 @@ get_dns_cert_libdns (ctrl_t ctrl, const char *name, int want_certtype,
goto leave;
memset (&rri, 0, sizeof rri);
- dns_rr_i_init (&rri, ans);
+ dns_rr_i_init (&rri);
rri.section = DNS_S_ALL & ~DNS_S_QD;
rri.name = host;
rri.type = qtype;
@@ -1888,7 +1891,7 @@ getsrv_libdns (ctrl_t ctrl,
goto leave;
memset (&rri, 0, sizeof rri);
- dns_rr_i_init (&rri, ans);
+ dns_rr_i_init (&rri);
rri.section = DNS_S_ALL & ~DNS_S_QD;
rri.name = host;
rri.type = DNS_T_SRV;
diff --git a/dirmngr/dns.c b/dirmngr/dns.c
index 77f83f437..fa5e5283d 100644
--- a/dirmngr/dns.c
+++ b/dirmngr/dns.c
@@ -77,6 +77,7 @@ typedef int socket_fd_t;
#include <netdb.h> /* struct addrinfo */
#endif
+#include "gpgrt.h" /* For GGPRT_GCC_VERSION */
#include "dns.h"
@@ -943,10 +944,11 @@ static int dns_sa_cmp(void *a, void *b) {
#if _WIN32
static int dns_inet_pton(int af, const void *src, void *dst) {
union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u;
+ int size_of_u = (int)sizeof u;
u.sin.sin_family = af;
- if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u }))
+ if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &size_of_u))
return -1;
switch (af) {
@@ -1124,6 +1126,7 @@ static inline _Bool dns_isgraph(unsigned char c) {
static int dns_poll(int fd, short events, int timeout) {
fd_set rset, wset;
+ struct timeval tv = { timeout, 0 };
if (!events)
return 0;
@@ -1140,7 +1143,7 @@ static int dns_poll(int fd, short events, int timeout) {
if (events & DNS_POLLOUT)
FD_SET(fd, &wset);
- select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL);
+ select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &tv : NULL);
return 0;
} /* dns_poll() */
@@ -1214,9 +1217,10 @@ static size_t dns_send_nopipe(int fd, const void *src, size_t len, int flags, dn
if (!sigismember(&pending, SIGPIPE)) {
int saved = error;
+ const struct timespec ts = { 0, 0 };
if (!count && error == EPIPE) {
- while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR)
+ while (-1 == sigtimedwait(&piped, NULL, &ts) && errno == EINTR)
;;
}
@@ -1832,7 +1836,7 @@ static void dns_p_free(struct dns_packet *P) {
} /* dns_p_free() */
-/* convience routine to free any existing packet before storing new packet */
+/* convenience routine to free any existing packet before storing new packet */
static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) {
dns_p_free(*dst);
@@ -2213,7 +2217,8 @@ static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
void dns_p_dump(struct dns_packet *P, FILE *fp) {
- dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp);
+ struct dns_rr_i _I = { 0 };
+ dns_p_dump3(P, &_I, fp);
} /* dns_p_dump() */
@@ -2792,8 +2797,7 @@ size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns
{ error = ENAMETOOLONG; goto error; }
for (depth = 0; depth < 7; depth++) {
- dns_rr_i_init(memset(&i, 0, sizeof i), P);
-
+ memset(&i, 0, sizeof i);
i.section = DNS_S_ALL & ~DNS_S_QD;
i.name = host;
i.type = DNS_T_CNAME;
@@ -3218,15 +3222,11 @@ int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, str
} /* dns_rr_i_shuffle() */
-struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) {
+void dns_rr_i_init(struct dns_rr_i *i) {
static const struct dns_rr_i i_initializer;
- (void)P;
-
i->state = i_initializer.state;
i->saved = i->state;
-
- return i;
} /* dns_rr_i_init() */
@@ -3262,7 +3262,8 @@ unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct
return count;
error:
- *error_ = error;
+ if (error_)
+ *error_ = error;
return count;
} /* dns_rr_grep() */
@@ -5274,7 +5275,8 @@ error:
struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
- struct dns_packet *P = dns_p_new(512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
+ struct dns_packet *P = dns_p_init(&_P.p, 512);
struct dns_packet *A = 0;
struct dns_rr rr;
struct dns_hosts_entry *ent;
@@ -6835,6 +6837,7 @@ unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, s
struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
struct dns_packet *A, *P;
struct dns_rr rr;
char zone[DNS_D_MAXNAME + 1];
@@ -6843,8 +6846,11 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q
struct sockaddr *sa;
socklen_t slen;
int error;
+ struct dns_rr_i _I = { 0 };
+
+ _I.section = DNS_S_QUESTION;
- if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error))
+ if (!dns_rr_grep(&rr, 1, &_I, Q, &error))
goto error;
if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
@@ -6852,7 +6858,7 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q
else if (zlen >= sizeof zone)
goto toolong;
- P = dns_p_new(512);
+ P = dns_p_init(&_P.p, 512);
dns_header(P)->qr = 1;
if ((error = dns_rr_copy(P, &rr, Q)))
@@ -7110,7 +7116,8 @@ static int dns_socket(struct sockaddr *local, int type, int *error_) {
#if defined SO_NOSIGPIPE
if (type != SOCK_DGRAM) {
- if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int)))
+ const int v = 1;
+ if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &v, sizeof (int)))
goto soerr;
}
#endif
@@ -7486,11 +7493,12 @@ error:
static _Bool dns_so_tcp_keep(struct dns_socket *so) {
struct sockaddr_storage remote;
+ socklen_t l = sizeof remote;
if (so->tcp == -1)
return 0;
- if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote }))
+ if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &l))
return 0;
return 0 == dns_sa_cmp(&remote, &so->remote);
@@ -7521,9 +7529,13 @@ static unsigned char *dns_so_tcp_recv_buffer(struct dns_socket *so) {
}
-#if defined __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Warray-bounds"
+
+#if GPGRT_GCC_VERSION >= 80000
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Warray-bounds"
+#elif defined __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Warray-bounds"
#endif
static int dns_so_tcp_send(struct dns_socket *so) {
@@ -7589,8 +7601,10 @@ static int dns_so_tcp_recv(struct dns_socket *so) {
return 0;
} /* dns_so_tcp_recv() */
-#if __clang__
-#pragma clang diagnostic pop
+#if GPGRT_GCC_VERSION >= 80000
+# pragma GCC diagnostic pop
+#elif __clang__
+# pragma clang diagnostic pop
#endif
@@ -7634,7 +7648,7 @@ retry:
goto udp_connect_retry;
} else if (error == ECONNREFUSED)
/* Error for previous socket operation may
- be reserverd asynchronously. */
+ be reserverd(?) asynchronously. */
goto udp_connect_retry;
if (error)
@@ -8449,7 +8463,8 @@ error:
static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
- struct dns_packet *P = dns_p_new(512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
+ struct dns_packet *P = dns_p_init(&_P.p, 512);
char qname[DNS_D_MAXNAME + 1];
size_t qlen;
enum dns_type qtype;
@@ -8521,12 +8536,22 @@ static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_r
struct dns_ns ns;
int cmp, error;
- if (!(error = dns_ns_parse(&ns, a, P)))
- glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
+ if (!(error = dns_ns_parse(&ns, a, P))) {
+ struct dns_rr_i _I = { 0 };
- if (!(error = dns_ns_parse(&ns, b, P)))
- glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error);
+ _I.section = (DNS_S_ALL & ~DNS_S_QD);
+ _I.name = ns.host;
+ _I.type = DNS_T_A;
+ glued[0] = !!dns_rr_grep(&x, 1, &_I, P, &error);
+ }
+ if (!(error = dns_ns_parse(&ns, b, P))) {
+ struct dns_rr_i _I = { 0 };
+ _I.section = (DNS_S_ALL & ~DNS_S_QD);
+ _I.name = ns.host;
+ _I.type = DNS_T_A;
+ glued[1] = !!dns_rr_grep(&y, 1, &_I, P, &error);
+ }
if ((cmp = glued[1] - glued[0])) {
return cmp;
} else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) {
@@ -8727,7 +8752,7 @@ exec:
F->state++; /* FALL THROUGH */
case DNS_R_ITERATE:
- dns_rr_i_init(&F->hints_i, F->hints);
+ dns_rr_i_init(&F->hints_i);
F->hints_i.section = DNS_S_AUTHORITY;
F->hints_i.type = DNS_T_NS;
@@ -8746,7 +8771,7 @@ exec:
dgoto(R->sp, DNS_R_SWITCH);
}
- dns_rr_i_init(&F->hints_j, F->hints);
+ dns_rr_i_init(&F->hints_j);
/* Assume there are glue records */
dgoto(R->sp, DNS_R_FOREACH_A);
@@ -8799,14 +8824,14 @@ exec:
if (!dns_rr_i_count(&F->hints_j)) {
/* Check if we have in fact servers
with an IPv6 address. */
- dns_rr_i_init(&F->hints_j, F->hints);
+ dns_rr_i_init(&F->hints_j);
F->hints_j.name = u.ns.host;
F->hints_j.type = DNS_T_AAAA;
F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
if (dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
/* We do. Reinitialize
iterator and handle it. */
- dns_rr_i_init(&F->hints_j, F->hints);
+ dns_rr_i_init(&F->hints_j);
dgoto(R->sp, DNS_R_FOREACH_AAAA);
}
@@ -8935,14 +8960,14 @@ exec:
if (!dns_rr_i_count(&F->hints_j)) {
/* Check if we have in fact servers
with an IPv4 address. */
- dns_rr_i_init(&F->hints_j, F->hints);
+ dns_rr_i_init(&F->hints_j);
F->hints_j.name = u.ns.host;
F->hints_j.type = DNS_T_A;
F->hints_j.section = DNS_S_ALL & ~DNS_S_QD;
if (dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) {
/* We do. Reinitialize
iterator and handle it. */
- dns_rr_i_init(&F->hints_j, F->hints);
+ dns_rr_i_init(&F->hints_j);
dgoto(R->sp, DNS_R_FOREACH_A);
}
@@ -9080,7 +9105,7 @@ exec:
R->smart.section = DNS_S_AN;
R->smart.type = R->qtype;
- dns_rr_i_init(&R->smart, F->answer);
+ dns_rr_i_init(&R->smart);
F->state++; /* FALL THROUGH */
case DNS_R_SMART0_A:
@@ -9824,7 +9849,7 @@ exec:
return error;
dns_strlcpy(ai->i_cname, ai->cname, sizeof ai->i_cname);
- dns_rr_i_init(&ai->i, ai->answer);
+ dns_rr_i_init(&ai->i);
ai->i.section = DNS_S_AN;
ai->i.name = ai->i_cname;
ai->i.type = dns_ai_qtype(ai);
@@ -9871,7 +9896,7 @@ exec:
ai->state++; /* FALL THROUGH */
case DNS_AI_S_ITERATE_G:
dns_strlcpy(ai->g_cname, ai->cname, sizeof ai->g_cname);
- dns_rr_i_init(&ai->g, ai->glue);
+ dns_rr_i_init(&ai->g);
ai->g.section = DNS_S_ALL & ~DNS_S_QD;
ai->g.name = ai->g_cname;
ai->g.type = ai->af.qtype;
@@ -9890,8 +9915,14 @@ exec:
return dns_ai_setent(ent, &any, rr.type, ai);
case DNS_AI_S_SUBMIT_G:
+ {
+ struct dns_rr_i _I = { 0 };
+
+ _I.section = DNS_S_QD;
+ _I.name = ai->g.name;
+ _I.type = ai->g.type;
/* skip if already queried */
- if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error))
+ if (dns_rr_grep(&rr, 1, &_I, ai->glue, &error))
dns_ai_goto(DNS_AI_S_FOREACH_I);
/* skip if we recursed (CNAME chains should have been handled in the resolver) */
if (++ai->g_depth > 1)
@@ -9900,7 +9931,8 @@ exec:
if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN)))
return error;
- ai->state++; /* FALL THROUGH */
+ ai->state++;
+ } /* FALL THROUGH */
case DNS_AI_S_CHECK_G:
if ((error = dns_res_check(ai->res)))
return error;
@@ -10074,8 +10106,9 @@ static const struct {
{ "AR", DNS_S_ADDITIONAL },
};
-const char *(dns_strsection)(enum dns_section section, void *_dst, size_t lim) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
+const char *(dns_strsection)(enum dns_section section) {
+ char _dst[DNS_STRMAXLEN + 1] = { 0 };
+ struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
unsigned i;
for (i = 0; i < lengthof(dns_sections); i++) {
@@ -10123,8 +10156,9 @@ static const struct {
{ "IN", DNS_C_IN },
};
-const char *(dns_strclass)(enum dns_class type, void *_dst, size_t lim) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
+const char *(dns_strclass)(enum dns_class type) {
+ char _dst[DNS_STRMAXLEN + 1] = { 0 };
+ struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
unsigned i;
for (i = 0; i < lengthof(dns_classes); i++) {
@@ -10159,8 +10193,9 @@ enum dns_class dns_iclass(const char *name) {
} /* dns_iclass() */
-const char *(dns_strtype)(enum dns_type type, void *_dst, size_t lim) {
- struct dns_buf dst = DNS_B_INTO(_dst, lim);
+const char *(dns_strtype)(enum dns_type type) {
+ char _dst[DNS_STRMAXLEN + 1] = { 0 };
+ struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst);
unsigned i;
for (i = 0; i < lengthof(dns_rrtypes); i++) {
@@ -10563,7 +10598,9 @@ static struct dns_trace *trace(const char *mode) {
static void print_packet(struct dns_packet *P, FILE *fp) {
- dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp);
+ struct dns_rr_i _I = { 0 };
+ I.sort = MAIN.sort;
+ dns_p_dump3(P, &I, fp);
if (MAIN.verbose > 2)
hexdump(P->data, P->end, fp);
@@ -10571,8 +10608,10 @@ static void print_packet(struct dns_packet *P, FILE *fp) {
static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
- struct dns_packet *P = dns_p_new(512);
- struct dns_packet *Q = dns_p_new(512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
+ struct dns_packet *P = dns_p_init(&_P.p, 512);
+ struct dns_packet *Q = dns_p_init(&_Q.p, 512);
enum dns_section section;
struct dns_rr rr;
int error;
@@ -10612,10 +10651,16 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
#if 0
dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") {
#else
+ char _p[DNS_D_MAXNAME + 1] = { 0 };
+ const char *dn = "ns8.yahoo.com";
+ char *_name = dns_d_init(_p, sizeof _p, dn, strlen (dn), DNS_D_ANCHOR);
struct dns_rr rrset[32];
- struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort);
+ struct dns_rr_i _I = { 0 };
+ struct dns_rr_i *rri = &I;
unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
+ I.name = _name;
+ I.sort = MAIN.sort;
for (unsigned i = 0; i < rrcount; i++) {
rr = rrset[i];
#endif
@@ -10641,13 +10686,14 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
static int parse_domain(int argc, char *argv[]) {
+ char _p[DNS_D_MAXNAME + 1] = { 0 };
char *dn;
dn = (argc > 1)? argv[1] : "f.l.google.com";
printf("[%s]\n", dn);
- dn = dns_d_new(dn);
+ dn = dns_d_init(_p, sizeof _p, dn, strlen (dn), DNS_D_ANCHOR);
do {
puts(dn);
@@ -10772,7 +10818,8 @@ static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
static int query_hosts(int argc, char *argv[]) {
- struct dns_packet *Q = dns_p_new(512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
+ struct dns_packet *Q = dns_p_init(&_Q.p, 512);
struct dns_packet *A;
char qname[DNS_D_MAXNAME + 1];
size_t qlen;
@@ -10890,11 +10937,13 @@ static int dump_random(int argc, char *argv[]) {
static int send_query(int argc, char *argv[]) {
- struct dns_packet *A, *Q = dns_p_new(512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
+ struct dns_packet *A, *Q = dns_p_init(&_Q.p, 512);
char host[INET6_ADDRSTRLEN + 1];
struct sockaddr_storage ss;
struct dns_socket *so;
int error, type;
+ struct dns_options opts = { 0 };
memset(&ss, 0, sizeof ss);
if (argc > 1) {
@@ -10929,7 +10978,7 @@ static int send_query(int argc, char *argv[]) {
fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype));
- if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error)))
+ if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, &opts, &error)))
panic("dns_so_open: %s", dns_strerror(error));
while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) {
@@ -10984,9 +11033,10 @@ static int show_hints(int argc, char *argv[]) {
if (0 == strcmp(how, "plain")) {
dns_hints_dump(hints, stdout);
} else {
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
struct dns_packet *query, *answer;
- query = dns_p_new(512);
+ query = dns_p_init(&_P.p, 512);
if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
panic("%s: %s", who, dns_strerror(error));
@@ -11012,6 +11062,11 @@ static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
struct dns_packet *ans;
const struct dns_stat *st;
int error;
+ struct dns_options opts = { 0 };
+
+ opts.socks_host = &MAIN.socks_host;
+ opts.socks_user = MAIN.socks_user;
+ opts.socks_password = MAIN.socks_password;
if (!MAIN.qname)
MAIN.qname = "www.google.com";
@@ -11021,9 +11076,7 @@ static int resolve_query(int argc DNS_NOTUSED, char *argv[]) {
resconf()->options.recurse = recurse;
if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(),
- dns_opts(.socks_host=&MAIN.socks_host,
- .socks_user=MAIN.socks_user,
- .socks_password=MAIN.socks_password), &error)))
+ &opts, &error)))
panic("%s: %s", MAIN.qname, dns_strerror(error));
dns_res_settrace(R, trace("w+b"));
@@ -11067,6 +11120,7 @@ static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
struct addrinfo *ent;
char pretty[512];
int error;
+ struct dns_options opts = { 0 };
if (!MAIN.qname)
MAIN.qname = "www.google.com";
@@ -11074,7 +11128,7 @@ static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) {
resconf()->options.recurse = recurse;
- if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error)))
+ if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), &opts, &error)))
panic("%s: %s", MAIN.qname, dns_strerror(error));
if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error)))
@@ -11145,7 +11199,8 @@ static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
panic("127.0.0.1:5353: %s", dns_strerror(errno));
for (;;) {
- struct dns_packet *pkt = dns_p_new(512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
+ struct dns_packet *pkt = dns_p_init(&_P.p, 512);
struct sockaddr_storage ss;
socklen_t slen = sizeof ss;
ssize_t count;
diff --git a/dirmngr/dns.h b/dirmngr/dns.h
index 30d0b45af..024d6dcc8 100644
--- a/dirmngr/dns.h
+++ b/dirmngr/dns.h
@@ -132,19 +132,6 @@ DNS_PUBLIC int *dns_debug_p(void);
/*
* C O M P I L E R A N N O T A T I O N S
*
- * GCC with -Wextra, and clang by default, complain about overrides in
- * initializer lists. Overriding previous member initializers is well
- * defined behavior in C. dns.c relies on this behavior to define default,
- * overrideable member values when instantiating configuration objects.
- *
- * dns_quietinit() guards a compound literal expression with pragmas to
- * silence these shrill warnings. This alleviates the burden of requiring
- * third-party projects to adjust their compiler flags.
- *
- * NOTE: If you take the address of the compound literal, take the address
- * of the transformed expression, otherwise the compound literal lifetime is
- * tied to the scope of the GCC statement expression.
- *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#if defined __clang__
@@ -152,21 +139,15 @@ DNS_PUBLIC int *dns_debug_p(void);
#define DNS_PRAGMA_QUIET _Pragma("clang diagnostic ignored \"-Winitializer-overrides\"")
#define DNS_PRAGMA_POP _Pragma("clang diagnostic pop")
-#define dns_quietinit(...) \
- DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__ DNS_PRAGMA_POP
#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
#define DNS_PRAGMA_PUSH _Pragma("GCC diagnostic push")
#define DNS_PRAGMA_QUIET _Pragma("GCC diagnostic ignored \"-Woverride-init\"")
#define DNS_PRAGMA_POP _Pragma("GCC diagnostic pop")
-/* GCC parses the _Pragma operator less elegantly than clang. */
-#define dns_quietinit(...) \
- __extension__ ({ DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__; DNS_PRAGMA_POP })
#else
#define DNS_PRAGMA_PUSH
#define DNS_PRAGMA_QUIET
#define DNS_PRAGMA_POP
-#define dns_quietinit(...) __VA_ARGS__
#endif
#if defined __GNUC__
@@ -291,25 +272,15 @@ enum dns_rcode {
*/
#define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */
-DNS_PUBLIC const char *dns_strsection(enum dns_section, void *, size_t);
-#define dns_strsection3(a, b, c) \
- dns_strsection((a), (b), (c))
-#define dns_strsection1(a) dns_strsection((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
-#define dns_strsection(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strsection, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+DNS_PUBLIC const char *dns_strsection(enum dns_section);
DNS_PUBLIC enum dns_section dns_isection(const char *);
-DNS_PUBLIC const char *dns_strclass(enum dns_class, void *, size_t);
-#define dns_strclass3(a, b, c) dns_strclass((a), (b), (c))
-#define dns_strclass1(a) dns_strclass((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
-#define dns_strclass(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strclass, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+DNS_PUBLIC const char *dns_strclass(enum dns_class);
DNS_PUBLIC enum dns_class dns_iclass(const char *);
-DNS_PUBLIC const char *dns_strtype(enum dns_type, void *, size_t);
-#define dns_strtype3(a, b, c) dns_strtype((a), (b), (c))
-#define dns_strtype1(a) dns_strtype((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
-#define dns_strtype(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strtype, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
+DNS_PUBLIC const char *dns_strtype(enum dns_type);
DNS_PUBLIC enum dns_type dns_itype(const char *);
@@ -422,9 +393,6 @@ struct dns_packet {
#define dns_p_sizeof(P) dns_p_calcsize((P)->end)
-/** takes size of maximum desired payload */
-#define dns_p_new(n) (dns_p_init((struct dns_packet *)&(union { unsigned char b[dns_p_calcsize((n))]; struct dns_packet p; }){ { 0 } }, dns_p_calcsize((n))))
-
/** takes size of entire packet structure as allocated */
DNS_PUBLIC struct dns_packet *dns_p_init(struct dns_packet *, size_t);
@@ -464,11 +432,6 @@ DNS_PUBLIC int dns_p_study(struct dns_packet *);
#define DNS_D_CLEAVE 2 /* cleave sub-domain */
#define DNS_D_TRIM 4 /* remove superfluous dots */
-#define dns_d_new3(a, b, f) dns_d_init(&(char[DNS_D_MAXNAME + 1]){ 0 }, DNS_D_MAXNAME + 1, (a), (b), (f))
-#define dns_d_new2(a, f) dns_d_new3((a), strlen((a)), (f))
-#define dns_d_new1(a) dns_d_new3((a), strlen((a)), DNS_D_ANCHOR)
-#define dns_d_new(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_d_new, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
-
DNS_PUBLIC char *dns_d_init(void *, size_t, const void *, size_t, int);
DNS_PUBLIC size_t dns_d_anchor(void *, size_t, const void *, size_t);
@@ -521,9 +484,6 @@ DNS_PUBLIC int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *,
DNS_PUBLIC size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *);
-#define dns_rr_i_new(P, ...) \
- dns_rr_i_init(&dns_quietinit((struct dns_rr_i){ 0, __VA_ARGS__ }), (P))
-
struct dns_rr_i {
enum dns_section section;
const void *name;
@@ -551,7 +511,7 @@ DNS_PUBLIC int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i
DNS_PUBLIC int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
-DNS_PUBLIC struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *);
+DNS_PUBLIC void dns_rr_i_init(struct dns_rr_i *);
#define dns_rr_i_save(i) ((i)->saved = (i)->state)
#define dns_rr_i_rewind(i) ((i)->state = (i)->saved)
@@ -560,7 +520,7 @@ DNS_PUBLIC struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *
DNS_PUBLIC unsigned dns_rr_grep(struct dns_rr *, unsigned, struct dns_rr_i *, struct dns_packet *, int *);
#define dns_rr_foreach_(rr, P, ...) \
- for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = *dns_rr_i_new((P), __VA_ARGS__); dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), &(int){ 0 }); )
+ for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = { __VA_ARGS__ }; dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), NULL); )
#define dns_rr_foreach(...) dns_rr_foreach_(__VA_ARGS__)
@@ -1001,7 +961,6 @@ struct dns_hints_i {
} state;
}; /* struct dns_hints_i */
-#define dns_hints_i_new(...) (&(struct dns_hints_i){ __VA_ARGS__ })
DNS_PUBLIC unsigned dns_hints_grep(struct sockaddr **, socklen_t *, unsigned, struct dns_hints_i *, struct dns_hints *);
@@ -1053,9 +1012,6 @@ DNS_PUBLIC void dns_cache_close(struct dns_cache *);
#define DNS_OPTS_INITIALIZER_ { 0, 0 }, 0, 0
#define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ }
-#define DNS_OPTS_INIT(...) { DNS_OPTS_INITIALIZER_, __VA_ARGS__ }
-
-#define dns_opts(...) (&dns_quietinit((struct dns_options)DNS_OPTS_INIT(__VA_ARGS__)))
struct dns_options {
/*
diff --git a/dirmngr/domaininfo.c b/dirmngr/domaininfo.c
index a2effffef..f6263b06d 100644
--- a/dirmngr/domaininfo.c
+++ b/dirmngr/domaininfo.c
@@ -119,7 +119,7 @@ domaininfo_print_stats (void)
}
-/* Return true if DOMAIN definitely does not support WKD. Noet that
+/* Return true if DOMAIN definitely does not support WKD. Note that
* DOMAIN is expected to be lowercase. */
int
domaininfo_is_wkd_not_supported (const char *domain)
diff --git a/dirmngr/http-ntbtls.c b/dirmngr/http-ntbtls.c
index ed4cdd496..924b8b25f 100644
--- a/dirmngr/http-ntbtls.c
+++ b/dirmngr/http-ntbtls.c
@@ -55,7 +55,7 @@ gnupg_http_tls_verify_cb (void *opaque,
log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC);
log_assert (!ntbtls_check_context (tls));
- /* Get the peer's certs fron ntbtls. */
+ /* Get the peer's certs from ntbtls. */
for (idx = 0;
(cert = ntbtls_x509_get_peer_cert (tls, idx)); idx++)
{
diff --git a/dirmngr/http.c b/dirmngr/http.c
index 5fb7eed04..d6856fe05 100644
--- a/dirmngr/http.c
+++ b/dirmngr/http.c
@@ -1350,6 +1350,8 @@ do_parse_uri (parsed_uri_t uri, int only_local_part,
uri->v6lit = 0;
uri->onion = 0;
uri->explicit_port = 0;
+ uri->off_host = 0;
+ uri->off_path = 0;
/* A quick validity check. */
if (strspn (p, VALID_URI_CHARS) != n)
@@ -1393,7 +1395,19 @@ do_parse_uri (parsed_uri_t uri, int only_local_part,
{
p += 2;
if ((p2 = strchr (p, '/')))
- *p2++ = 0;
+ {
+ if (p2 - uri->buffer > 10000)
+ return GPG_ERR_BAD_URI;
+ uri->off_path = p2 - uri->buffer;
+ *p2++ = 0;
+ }
+ else
+ {
+ n = (p - uri->buffer) + strlen (p);
+ if (n > 10000)
+ return GPG_ERR_BAD_URI;
+ uri->off_path = n;
+ }
/* Check for username/password encoding */
if ((p3 = strchr (p, '@')))
@@ -1412,11 +1426,19 @@ do_parse_uri (parsed_uri_t uri, int only_local_part,
*p3++ = '\0';
/* worst case, uri->host should have length 0, points to \0 */
uri->host = p + 1;
+ if (p - uri->buffer > 10000)
+ return GPG_ERR_BAD_URI;
+ uri->off_host = (p + 1) - uri->buffer;
uri->v6lit = 1;
p = p3;
}
else
- uri->host = p;
+ {
+ uri->host = p;
+ if (p - uri->buffer > 10000)
+ return GPG_ERR_BAD_URI;
+ uri->off_host = p - uri->buffer;
+ }
if ((p3 = strchr (p, ':')))
{
@@ -3496,3 +3518,207 @@ uri_query_lookup (parsed_uri_t uri, const char *key)
return NULL;
}
+
+
+/* Return true if both URI point to the same host for the purpose of
+ * redirection check. A is the original host and B the host given in
+ * the Location header. As a temporary workaround a fixed list of
+ * exceptions is also consulted. */
+static int
+same_host_p (parsed_uri_t a, parsed_uri_t b)
+{
+ static struct
+ {
+ const char *from; /* NULL uses the last entry from the table. */
+ const char *to;
+ } allow[] =
+ {
+ { "protonmail.com", "api.protonmail.com" },
+ { NULL, "api.protonmail.ch" },
+ { "protonmail.ch", "api.protonmail.com" },
+ { NULL, "api.protonmail.ch" }
+ };
+ int i;
+ const char *from;
+
+ if (!a->host || !b->host)
+ return 0;
+
+ if (!ascii_strcasecmp (a->host, b->host))
+ return 1;
+
+ from = NULL;
+ for (i=0; i < DIM (allow); i++)
+ {
+ if (allow[i].from)
+ from = allow[i].from;
+ if (!from)
+ continue;
+ if (!ascii_strcasecmp (from, a->host)
+ && !ascii_strcasecmp (allow[i].to, b->host))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Prepare a new URL for a HTTP redirect. INFO has flags controlling
+ * the operation, STATUS_CODE is used for diagnostics, LOCATION is the
+ * value of the "Location" header, and R_URL reveives the new URL on
+ * success or NULL or error. Note that INFO->ORIG_URL is
+ * required. */
+gpg_error_t
+http_prepare_redirect (http_redir_info_t *info, unsigned int status_code,
+ const char *location, char **r_url)
+{
+ gpg_error_t err;
+ parsed_uri_t locuri;
+ parsed_uri_t origuri;
+ char *newurl;
+ char *p;
+
+ *r_url = NULL;
+
+ if (!info || !info->orig_url)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if (!info->silent)
+ log_info (_("URL '%s' redirected to '%s' (%u)\n"),
+ info->orig_url, location? location:"[none]", status_code);
+
+ if (!info->redirects_left)
+ {
+ if (!info->silent)
+ log_error (_("too many redirections\n"));
+ return gpg_error (GPG_ERR_NO_DATA);
+ }
+ info->redirects_left--;
+
+ if (!location || !*location)
+ return gpg_error (GPG_ERR_NO_DATA);
+
+ err = http_parse_uri (&locuri, location, 0);
+ if (err)
+ return err;
+
+ /* Make sure that an onion address only redirects to another
+ * onion address, or that a https address only redirects to a
+ * https address. */
+ if (info->orig_onion && !locuri->onion)
+ {
+ http_release_parsed_uri (locuri);
+ return gpg_error (GPG_ERR_FORBIDDEN);
+ }
+ if (!info->allow_downgrade && info->orig_https && !locuri->use_tls)
+ {
+ http_release_parsed_uri (locuri);
+ return gpg_error (GPG_ERR_FORBIDDEN);
+ }
+
+ if (info->trust_location)
+ {
+ /* We trust the Location - return it verbatim. */
+ http_release_parsed_uri (locuri);
+ newurl = xtrystrdup (location);
+ if (!newurl)
+ {
+ err = gpg_error_from_syserror ();
+ http_release_parsed_uri (locuri);
+ return err;
+ }
+ }
+ else if ((err = http_parse_uri (&origuri, info->orig_url, 0)))
+ {
+ http_release_parsed_uri (locuri);
+ return err;
+ }
+ else if (same_host_p (origuri, locuri))
+ {
+ /* The host is the same or on an exception list and thus we can
+ * take the location verbatim. */
+ http_release_parsed_uri (origuri);
+ http_release_parsed_uri (locuri);
+ newurl = xtrystrdup (location);
+ if (!newurl)
+ {
+ err = gpg_error_from_syserror ();
+ http_release_parsed_uri (locuri);
+ return err;
+ }
+ }
+ else
+ {
+ /* We take only the host and port from the URL given in the
+ * Location. This limits the effects of redirection attacks by
+ * rogue hosts returning an URL to servers in the client's own
+ * network. We don't even include the userinfo because they
+ * should be considered similar to the path and query parts.
+ */
+ if (!(locuri->off_path - locuri->off_host))
+ {
+ http_release_parsed_uri (origuri);
+ http_release_parsed_uri (locuri);
+ return gpg_error (GPG_ERR_BAD_URI);
+ }
+ if (!(origuri->off_path - origuri->off_host))
+ {
+ http_release_parsed_uri (origuri);
+ http_release_parsed_uri (locuri);
+ return gpg_error (GPG_ERR_BAD_URI);
+ }
+
+ newurl = xtrymalloc (strlen (origuri->original)
+ + (locuri->off_path - locuri->off_host) + 1);
+ if (!newurl)
+ {
+ err = gpg_error_from_syserror ();
+ http_release_parsed_uri (origuri);
+ http_release_parsed_uri (locuri);
+ return err;
+ }
+ /* Build new URL from
+ * uriguri: scheme userinfo ---- ---- path rest
+ * locuri: ------ -------- host port ---- ----
+ */
+ p = newurl;
+ memcpy (p, origuri->original, origuri->off_host);
+ p += origuri->off_host;
+ memcpy (p, locuri->original + locuri->off_host,
+ (locuri->off_path - locuri->off_host));
+ p += locuri->off_path - locuri->off_host;
+ strcpy (p, origuri->original + origuri->off_path);
+
+ http_release_parsed_uri (origuri);
+ http_release_parsed_uri (locuri);
+ if (!info->silent)
+ log_info (_("redirection changed to '%s'\n"), newurl);
+ }
+
+ *r_url = newurl;
+ return 0;
+}
+
+
+/* Return string describing the http STATUS. Returns an empty string
+ * for an unknown status. */
+const char *
+http_status2string (unsigned int status)
+{
+ switch (status)
+ {
+ case 500: return "Internal Server Error";
+ case 501: return "Not Implemented";
+ case 502: return "Bad Gateway";
+ case 503: return "Service Unavailable";
+ case 504: return "Gateway Timeout";
+ case 505: return "HTTP version Not Supported";
+ case 506: return "Variant Also Negation";
+ case 507: return "Insufficient Storage";
+ case 508: return "Loop Detected";
+ case 510: return "Not Extended";
+ case 511: return "Network Authentication Required";
+ }
+
+ return "";
+}
diff --git a/dirmngr/http.h b/dirmngr/http.h
index a86abbee7..492e86726 100644
--- a/dirmngr/http.h
+++ b/dirmngr/http.h
@@ -58,6 +58,8 @@ struct parsed_uri_s
char *auth; /* username/password for basic auth. */
char *host; /* Host (converted to lowercase). */
unsigned short port; /* Port (always set if the host is set). */
+ unsigned short off_host; /* Offset to the HOST respective PATH parts */
+ unsigned short off_path; /* in the original URI buffer. */
char *path; /* Path. */
uri_tuple_t params; /* ";xxxxx" */
uri_tuple_t query; /* "?xxx=yyy" */
@@ -100,6 +102,21 @@ typedef struct http_session_s *http_session_t;
struct http_context_s;
typedef struct http_context_s *http_t;
+/* An object used to track redirection infos. */
+struct http_redir_info_s
+{
+ unsigned int redirects_left; /* Number of still possible redirects. */
+ const char *orig_url; /* The original requested URL. */
+ unsigned int orig_onion:1; /* Original request was an onion address. */
+ unsigned int orig_https:1; /* Original request was a http address. */
+ unsigned int silent:1; /* No diagnostics. */
+ unsigned int allow_downgrade:1;/* Allow a downgrade from https to http. */
+ unsigned int trust_location:1; /* Trust the received Location header. */
+};
+typedef struct http_redir_info_s http_redir_info_t;
+
+
+
/* A TLS verify callback function. */
typedef gpg_error_t (*http_verify_cb_t) (void *opaque,
http_t http,
@@ -176,5 +193,11 @@ gpg_error_t http_verify_server_credentials (http_session_t sess);
char *http_escape_string (const char *string, const char *specials);
char *http_escape_data (const void *data, size_t datalen, const char *specials);
+gpg_error_t http_prepare_redirect (http_redir_info_t *info,
+ unsigned int status_code,
+ const char *location, char **r_url);
+
+const char *http_status2string (unsigned int status);
+
#endif /*GNUPG_COMMON_HTTP_H*/
diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c
index c1ecafb58..3651ca7db 100644
--- a/dirmngr/ks-action.c
+++ b/dirmngr/ks-action.c
@@ -88,7 +88,7 @@ ks_action_help (ctrl_t ctrl, const char *url)
return err;
}
- /* Call all engines to give them a chance to print a help sting. */
+ /* Call all engines to give them a chance to print a help string. */
err = ks_hkp_help (ctrl, parsed_uri);
if (!err)
err = ks_http_help (ctrl, parsed_uri);
diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c
index 630309991..4d660b87e 100644
--- a/dirmngr/ks-engine-hkp.c
+++ b/dirmngr/ks-engine-hkp.c
@@ -35,6 +35,7 @@
# include <netdb.h>
#endif /*!HAVE_W32_SYSTEM*/
+#include <npth.h>
#include "dirmngr.h"
#include "misc.h"
#include "../common/userids.h"
@@ -108,6 +109,8 @@ struct hostinfo_s
resolved from a pool name and its allocated size.*/
static hostinfo_t *hosttable;
static int hosttable_size;
+/* A mutex used to serialize access to the hosttable. */
+static npth_mutex_t hosttable_lock;
/* The number of host slots we initially allocate for HOSTTABLE. */
#define INITIAL_HOSTTABLE_SIZE 50
@@ -756,9 +759,15 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
if (!name || !*name || !strcmp (name, "localhost"))
return 0;
+ if (npth_mutex_lock (&hosttable_lock))
+ log_fatal ("failed to acquire mutex\n");
+
idx = find_hostinfo (name);
if (idx == -1)
- return gpg_error (GPG_ERR_NOT_FOUND);
+ {
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+ goto leave;
+ }
hi = hosttable[idx];
if (alive && hi->dead)
@@ -817,6 +826,10 @@ ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
}
}
+ leave:
+ if (npth_mutex_unlock (&hosttable_lock))
+ log_fatal ("failed to release mutex\n");
+
return err;
}
@@ -837,7 +850,9 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
if (err)
return err;
- /* FIXME: We need a lock for the hosttable. */
+ if (npth_mutex_lock (&hosttable_lock))
+ log_fatal ("failed to acquire mutex\n");
+
curtime = gnupg_get_time ();
for (idx=0; idx < hosttable_size; idx++)
if ((hi=hosttable[idx]))
@@ -930,12 +945,12 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
diedstr? ")":"" );
xfree (died);
if (err)
- return err;
+ goto leave;
if (hi->cname)
err = ks_printf_help (ctrl, " . %s", hi->cname);
if (err)
- return err;
+ goto leave;
if (hi->pool)
{
@@ -950,14 +965,21 @@ ks_hkp_print_hosttable (ctrl_t ctrl)
put_membuf( &mb, "", 1);
p = get_membuf (&mb, NULL);
if (!p)
- return gpg_error_from_syserror ();
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
err = ks_print_help (ctrl, p);
xfree (p);
if (err)
- return err;
+ goto leave;
}
}
- return 0;
+
+ leave:
+ if (npth_mutex_unlock (&hosttable_lock))
+ log_fatal ("failed to release mutex\n");
+ return err;
}
@@ -1026,9 +1048,16 @@ make_host_part (ctrl_t ctrl,
protocol = KS_PROTOCOL_HKP;
}
+ if (npth_mutex_lock (&hosttable_lock))
+ log_fatal ("failed to acquire mutex\n");
+
portstr[0] = 0;
err = map_host (ctrl, host, srvtag, force_reselect, protocol,
&hostname, portstr, r_httpflags, r_httphost);
+
+ if (npth_mutex_unlock (&hosttable_lock))
+ log_fatal ("failed to release mutex\n");
+
if (err)
return err;
@@ -1102,6 +1131,9 @@ ks_hkp_housekeeping (time_t curtime)
int idx;
hostinfo_t hi;
+ if (npth_mutex_lock (&hosttable_lock))
+ log_fatal ("failed to acquire mutex\n");
+
for (idx=0; idx < hosttable_size; idx++)
{
hi = hosttable[idx];
@@ -1118,6 +1150,9 @@ ks_hkp_housekeeping (time_t curtime)
log_info ("resurrected host '%s'", hi->name);
}
}
+
+ if (npth_mutex_unlock (&hosttable_lock))
+ log_fatal ("failed to release mutex\n");
}
@@ -1129,6 +1164,9 @@ ks_hkp_reload (void)
int idx, count;
hostinfo_t hi;
+ if (npth_mutex_lock (&hosttable_lock))
+ log_fatal ("failed to acquire mutex\n");
+
for (idx=count=0; idx < hosttable_size; idx++)
{
hi = hosttable[idx];
@@ -1142,6 +1180,9 @@ ks_hkp_reload (void)
}
if (count)
log_info ("number of resurrected hosts: %d", count);
+
+ if (npth_mutex_unlock (&hosttable_lock))
+ log_fatal ("failed to release mutex\n");
}
@@ -1160,18 +1201,21 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
gpg_error_t err;
http_session_t session = NULL;
http_t http = NULL;
- int redirects_left = MAX_REDIRECTS;
+ http_redir_info_t redirinfo = { MAX_REDIRECTS };
estream_t fp = NULL;
char *request_buffer = NULL;
parsed_uri_t uri = NULL;
- int is_onion;
*r_fp = NULL;
err = http_parse_uri (&uri, request, 0);
if (err)
goto leave;
- is_onion = uri->onion;
+ redirinfo.orig_url = request;
+ redirinfo.orig_onion = uri->onion;
+ redirinfo.allow_downgrade = 1;
+ /* FIXME: I am not sure whey we allow a downgrade for hkp requests.
+ * Needs at least an explanation here.. */
err = http_session_new (&session, httphost,
((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0)
@@ -1252,45 +1296,18 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
case 302:
case 307:
{
- const char *s = http_get_header (http, "Location");
-
- log_info (_("URL '%s' redirected to '%s' (%u)\n"),
- request, s?s:"[none]", http_get_status_code (http));
- if (s && *s && redirects_left-- )
- {
- if (is_onion)
- {
- /* Make sure that an onion address only redirects to
- * another onion address. */
- http_release_parsed_uri (uri);
- uri = NULL;
- err = http_parse_uri (&uri, s, 0);
- if (err)
- goto leave;
-
- if (! uri->onion)
- {
- err = gpg_error (GPG_ERR_FORBIDDEN);
- goto leave;
- }
- }
+ xfree (request_buffer);
+ err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
+ http_get_header (http, "Location"),
+ &request_buffer);
+ if (err)
+ goto leave;
- xfree (request_buffer);
- request_buffer = xtrystrdup (s);
- if (request_buffer)
- {
- request = request_buffer;
- http_close (http, 0);
- http = NULL;
- goto once_more;
- }
- err = gpg_error_from_syserror ();
- }
- else
- err = gpg_error (GPG_ERR_NO_DATA);
- log_error (_("too many redirections\n"));
+ request = request_buffer;
+ http_close (http, 0);
+ http = NULL;
}
- goto leave;
+ goto once_more;
case 501:
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
@@ -1335,12 +1352,12 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
down to zero. */
static int
handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
- unsigned int *tries_left)
+ unsigned int http_status, unsigned int *tries_left)
{
int retry = 0;
/* Fixme: Should we disable all hosts of a protocol family if a
- * request for an address of that familiy returned ENETDOWN? */
+ * request for an address of that family returned ENETDOWN? */
switch (gpg_err_code (err))
{
@@ -1378,6 +1395,27 @@ handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
}
break;
+ case GPG_ERR_NO_DATA:
+ {
+ switch (http_status)
+ {
+ case 502: /* Bad Gateway */
+ log_info ("marking host dead due to a %u (%s)\n",
+ http_status, http_status2string (http_status));
+ if (mark_host_dead (request) && *tries_left)
+ retry = 1;
+ break;
+
+ case 503: /* Service Unavailable */
+ case 504: /* Gateway Timeout */
+ log_info ("selecting a different host due to a %u (%s)",
+ http_status, http_status2string (http_status));
+ retry = 1;
+ break;
+ }
+ }
+ break;
+
default:
break;
}
@@ -1399,13 +1437,14 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
{
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
- char fprbuf[2+40+1];
+ char fprbuf[2+64+1];
char *hostport = NULL;
char *request = NULL;
estream_t fp = NULL;
int reselect;
unsigned int httpflags;
char *httphost = NULL;
+ unsigned int http_status;
unsigned int tries = SEND_REQUEST_RETRIES;
*r_fp = NULL;
@@ -1417,6 +1456,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
err = classify_user_id (pattern, &desc, 1);
if (err)
return err;
+ log_assert (desc.fprlen <= 64);
switch (desc.mode)
{
case KEYDB_SEARCH_MODE_EXACT:
@@ -1434,17 +1474,10 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
(ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
pattern = fprbuf;
break;
- case KEYDB_SEARCH_MODE_FPR16:
- fprbuf[0] = '0';
- fprbuf[1] = 'x';
- bin2hex (desc.u.fpr, 16, fprbuf+2);
- pattern = fprbuf;
- break;
- case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
fprbuf[0] = '0';
fprbuf[1] = 'x';
- bin2hex (desc.u.fpr, 20, fprbuf+2);
+ bin2hex (desc.u.fpr, desc.fprlen, fprbuf+2);
pattern = fprbuf;
break;
default:
@@ -1487,14 +1520,20 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
/* Send the request. */
err = send_request (ctrl, request, hostport, httphost, httpflags,
- NULL, NULL, &fp, r_http_status);
- if (handle_send_request_error (ctrl, err, request, &tries))
+ NULL, NULL, &fp, &http_status);
+ if (handle_send_request_error (ctrl, err, request, http_status, &tries))
{
reselect = 1;
goto again;
}
+ if (r_http_status)
+ *r_http_status = http_status;
if (err)
- goto leave;
+ {
+ if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+ dirmngr_status (ctrl, "SOURCE", hostport, NULL);
+ goto leave;
+ }
err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
if (err)
@@ -1541,7 +1580,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
{
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
- char kidbuf[2+40+1];
+ char kidbuf[2+64+1];
const char *exactname = NULL;
char *searchkey = NULL;
char *hostport = NULL;
@@ -1550,6 +1589,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
int reselect;
char *httphost = NULL;
unsigned int httpflags;
+ unsigned int http_status;
unsigned int tries = SEND_REQUEST_RETRIES;
*r_fp = NULL;
@@ -1561,6 +1601,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
err = classify_user_id (keyspec, &desc, 1);
if (err)
return err;
+ log_assert (desc.fprlen <= 64);
switch (desc.mode)
{
case KEYDB_SEARCH_MODE_SHORT_KID:
@@ -1570,21 +1611,21 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
(ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
break;
- case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
- /* This is a v4 fingerprint. */
+ if (desc.fprlen < 20)
+ {
+ log_error ("HKP keyservers do not support v3 fingerprints\n");
+ return gpg_error (GPG_ERR_INV_USER_ID);
+ }
kidbuf[0] = '0';
kidbuf[1] = 'x';
- bin2hex (desc.u.fpr, 20, kidbuf+2);
+ bin2hex (desc.u.fpr, desc.fprlen, kidbuf+2);
break;
case KEYDB_SEARCH_MODE_EXACT:
exactname = desc.u.name;
break;
- case KEYDB_SEARCH_MODE_FPR16:
- log_error ("HKP keyservers do not support v3 fingerprints\n");
- /* fall through */
default:
return gpg_error (GPG_ERR_INV_USER_ID);
}
@@ -1622,14 +1663,18 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
/* Send the request. */
err = send_request (ctrl, request, hostport, httphost, httpflags,
- NULL, NULL, &fp, NULL);
- if (handle_send_request_error (ctrl, err, request, &tries))
+ NULL, NULL, &fp, &http_status);
+ if (handle_send_request_error (ctrl, err, request, http_status, &tries))
{
reselect = 1;
goto again;
}
if (err)
- goto leave;
+ {
+ if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+ dirmngr_status (ctrl, "SOURCE", hostport, NULL);
+ goto leave;
+ }
err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
if (err)
@@ -1693,6 +1738,7 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
int reselect;
char *httphost = NULL;
unsigned int httpflags;
+ unsigned int http_status;
unsigned int tries = SEND_REQUEST_RETRIES;
parm.datastring = NULL;
@@ -1731,8 +1777,8 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
/* Send the request. */
err = send_request (ctrl, request, hostport, httphost, 0,
- put_post_cb, &parm, &fp, NULL);
- if (handle_send_request_error (ctrl, err, request, &tries))
+ put_post_cb, &parm, &fp, &http_status);
+ if (handle_send_request_error (ctrl, err, request, http_status, &tries))
{
reselect = 1;
goto again;
@@ -1749,3 +1795,13 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
xfree (httphost);
return err;
}
+
+void
+ks_hkp_init (void)
+{
+ int err;
+
+ err = npth_mutex_init (&hosttable_lock, NULL);
+ if (err)
+ log_fatal ("error initializing mutex: %s\n", strerror (err));
+}
diff --git a/dirmngr/ks-engine-http.c b/dirmngr/ks-engine-http.c
index 9e6b9e1f5..0f3e2db4a 100644
--- a/dirmngr/ks-engine-http.c
+++ b/dirmngr/ks-engine-http.c
@@ -74,17 +74,18 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
http_session_t session = NULL;
unsigned int session_flags;
http_t http = NULL;
- int redirects_left = MAX_REDIRECTS;
+ http_redir_info_t redirinfo = { MAX_REDIRECTS };
estream_t fp = NULL;
char *request_buffer = NULL;
parsed_uri_t uri = NULL;
- int is_onion, is_https;
err = http_parse_uri (&uri, url, 0);
if (err)
goto leave;
- is_onion = uri->onion;
- is_https = uri->use_tls;
+ redirinfo.orig_url = url;
+ redirinfo.orig_onion = uri->onion;
+ redirinfo.orig_https = uri->use_tls;
+ redirinfo.allow_downgrade = !!(flags & KS_HTTP_FETCH_ALLOW_DOWNGRADE);
/* By default we only use the system provided certificates with this
* fetch command. */
@@ -158,53 +159,20 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
case 302:
case 307:
{
- const char *s = http_get_header (http, "Location");
-
- log_info (_("URL '%s' redirected to '%s' (%u)\n"),
- url, s?s:"[none]", http_get_status_code (http));
- if (s && *s && redirects_left-- )
- {
- if (is_onion || is_https)
- {
- /* Make sure that an onion address only redirects to
- * another onion address, or that a https address
- * only redirects to a https address. */
- http_release_parsed_uri (uri);
- uri = NULL;
- err = http_parse_uri (&uri, s, 0);
- if (err)
- goto leave;
-
- if (is_onion && !uri->onion)
- {
- err = gpg_error (GPG_ERR_FORBIDDEN);
- goto leave;
- }
- if (!(flags & KS_HTTP_FETCH_ALLOW_DOWNGRADE)
- && is_https && !uri->use_tls)
- {
- err = gpg_error (GPG_ERR_FORBIDDEN);
- goto leave;
- }
- }
-
- xfree (request_buffer);
- request_buffer = xtrystrdup (s);
- if (request_buffer)
- {
- url = request_buffer;
- http_close (http, 0);
- http = NULL;
- http_session_release (session);
- goto once_more;
- }
- err = gpg_error_from_syserror ();
- }
- else
- err = gpg_error (GPG_ERR_NO_DATA);
- log_error (_("too many redirections\n"));
+ xfree (request_buffer);
+ err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
+ http_get_header (http, "Location"),
+ &request_buffer);
+ if (err)
+ goto leave;
+
+ url = request_buffer;
+ http_close (http, 0);
+ http = NULL;
+ http_session_release (session);
+ session = NULL;
}
- goto leave;
+ goto once_more;
default:
log_error (_("error accessing '%s': http status %u\n"),
diff --git a/dirmngr/ks-engine-ldap.c b/dirmngr/ks-engine-ldap.c
index f50ba50d0..d6af26ec4 100644
--- a/dirmngr/ks-engine-ldap.c
+++ b/dirmngr/ks-engine-ldap.c
@@ -376,8 +376,6 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact)
(ulong) desc.u.kid[0], (ulong) desc.u.kid[1]);
break;
- case KEYDB_SEARCH_MODE_FPR16:
- case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
case KEYDB_SEARCH_MODE_ISSUER:
case KEYDB_SEARCH_MODE_ISSUER_SN:
@@ -1694,26 +1692,16 @@ extract_attributes (LDAPMod ***modlist, char *line)
if (is_pub || is_sub)
{
- char *size = fields[2];
- int val = atoi (size);
- size = NULL;
+ char padded[6];
+ int val;
- if (val > 0)
- {
- /* We zero pad this on the left to make PGP happy. */
- char padded[6];
- if (val < 99999 && val > 0)
- {
- snprintf (padded, sizeof padded, "%05u", val);
- size = padded;
- }
- }
-
- if (size)
- {
- if (is_pub || is_sub)
- modlist_add (modlist, "pgpKeySize", size);
- }
+ val = atoi (fields[2]);
+ if (val < 99999 && val > 0)
+ {
+ /* We zero pad this on the left to make PGP happy. */
+ snprintf (padded, sizeof padded, "%05u", val);
+ modlist_add (modlist, "pgpKeySize", padded);
+ }
}
if (is_pub)
@@ -1736,10 +1724,7 @@ extract_attributes (LDAPMod ***modlist, char *line)
}
if (algo)
- {
- if (is_pub)
- modlist_add (modlist, "pgpKeyType", algo);
- }
+ modlist_add (modlist, "pgpKeyType", algo);
}
if (is_pub || is_sub || is_sig)
diff --git a/dirmngr/ldap.c b/dirmngr/ldap.c
index cb3c0b763..a04bb97a2 100644
--- a/dirmngr/ldap.c
+++ b/dirmngr/ldap.c
@@ -388,7 +388,7 @@ parse_one_pattern (const char *pattern)
}
/* Take the string STRING and escape it according to the URL rules.
- Retun a newly allocated string. */
+ Return a newly allocated string. */
static char *
escape4url (const char *string)
{
diff --git a/dirmngr/misc.c b/dirmngr/misc.c
index 1270b834d..9cedf911c 100644
--- a/dirmngr/misc.c
+++ b/dirmngr/misc.c
@@ -515,7 +515,7 @@ host_and_port_from_url (const char *url, int *port)
if ((p = strchr (buf, '/')))
*p++ = 0;
strlwr (buf);
- if ((p = strchr (p, ':')))
+ if ((p = strchr (buf, ':')))
{
*p++ = 0;
*port = atoi (p);
@@ -637,7 +637,7 @@ armor_data (char **r_string, const void *data, size_t datalen)
}
-/* Copy all data from IN to OUT. OUT may be NULL to use this fucntion
+/* Copy all data from IN to OUT. OUT may be NULL to use this function
* as a dummy reader. */
gpg_error_t
copy_stream (estream_t in, estream_t out)
diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c
index ca28960e4..79c252d87 100644
--- a/dirmngr/ocsp.c
+++ b/dirmngr/ocsp.c
@@ -343,7 +343,7 @@ validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
Note, that in theory we could simply ask the client via an
inquire to validate a certificate but this might involve
- calling DirMngr again recursivly - we can't do that as of now
+ calling DirMngr again recursively - we can't do that as of now
(neither DirMngr nor gpgsm have the ability for concurrent
access to DirMngr. */
@@ -391,7 +391,7 @@ check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
}
-/* Check the signature of an OCSP repsonse. OCSP is the context,
+/* Check the signature of an OCSP response. OCSP is the context,
S_SIG the signature value and MD the handle of the hash we used for
the response. This function automagically finds the correct public
key. If SIGNER_FPR_LIST is not NULL, the default OCSP reponder has been
@@ -653,6 +653,33 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
if (err)
goto leave;
+ /* It is sometimes useful to know the responder ID. */
+ if (opt.verbose)
+ {
+ char *resp_name;
+ ksba_sexp_t resp_keyid;
+
+ err = ksba_ocsp_get_responder_id (ocsp, &resp_name, &resp_keyid);
+ if (err)
+ log_info (_("error getting responder ID: %s\n"), gpg_strerror (err));
+ else
+ {
+ log_info ("responder id: ");
+ if (resp_name)
+ log_printf ("'/%s' ", resp_name);
+ if (resp_keyid)
+ {
+ log_printf ("{");
+ dump_serial (resp_keyid);
+ log_printf ("} ");
+ }
+ log_printf ("\n");
+ }
+ ksba_free (resp_name);
+ ksba_free (resp_keyid);
+ err = 0;
+ }
+
/* We got a useful answer, check that the answer has a valid signature. */
sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
if (!sigval || !*produced_at)
@@ -761,7 +788,7 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
err = gpg_error (GPG_ERR_TIME_CONFLICT);
}
- /* Check that we are not beyound NEXT_UPDATE (plus some extra time). */
+ /* Check that we are not beyond NEXT_UPDATE (plus some extra time). */
if (*next_update)
{
gnupg_copy_time (tmp_time, next_update);
diff --git a/dirmngr/server.c b/dirmngr/server.c
index 2519fd601..4a242539b 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -731,7 +731,7 @@ cmd_dns_cert (assuan_context_t ctx, char *line)
/* We lowercase ascii characters but the DANE I-D does not allow
this. FIXME: Check after the release of the RFC whether to
change this. */
- mbox = mailbox_from_userid (line);
+ mbox = mailbox_from_userid (line, 0);
if (!mbox || !(domain = strchr (mbox, '@')))
{
err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
@@ -837,8 +837,11 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
gpg_error_t err = 0;
char *mbox = NULL;
char *domainbuf = NULL;
- char *domain; /* Points to mbox or domainbuf. */
- char *domain_orig;/* Points to mbox. */
+ char *domain; /* Points to mbox or domainbuf. This is used to
+ * connect to the host. */
+ char *domain_orig;/* Points to mbox. This is the used for the
+ * query; i.e. the domain part of the
+ * addrspec. */
char sha1buf[20];
char *uri = NULL;
char *encodedhash = NULL;
@@ -847,6 +850,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
int is_wkd_query; /* True if this is a real WKD query. */
int no_log = 0;
char portstr[20] = { 0 };
+ int subdomain_mode = 0;
opt_submission_addr = has_option (line, "--submission-address");
opt_policy_flags = has_option (line, "--policy-flags");
@@ -855,7 +859,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
line = skip_options (line);
is_wkd_query = !(opt_policy_flags || opt_submission_addr);
- mbox = mailbox_from_userid (line);
+ mbox = mailbox_from_userid (line, 0);
if (!mbox || !(domain = strchr (mbox, '@')))
{
err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
@@ -864,7 +868,8 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
*domain++ = 0;
domain_orig = domain;
- /* First check whether we already know that the domain does not
+
+ /* Let's check whether we already know that the domain does not
* support WKD. */
if (is_wkd_query)
{
@@ -875,8 +880,41 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
}
}
- /* Check for SRV records. */
- if (1)
+
+ /* First try the new "openpgp" subdomain. We check that the domain
+ * is valid because it is later used as an unescaped filename part
+ * of the URI. */
+ if (is_valid_domain_name (domain_orig))
+ {
+ dns_addrinfo_t aibuf;
+
+ domainbuf = strconcat ( "openpgpkey.", domain_orig, NULL);
+ if (!domainbuf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ /* FIXME: We should put a cache into dns-stuff because the same
+ * query (with a different port and socket type, though) will be
+ * done later by http function. */
+ err = resolve_dns_name (ctrl, domainbuf, 0, 0, 0, &aibuf, NULL);
+ if (err)
+ {
+ err = 0;
+ xfree (domainbuf);
+ domainbuf = NULL;
+ }
+ else /* Got a subdomain. */
+ {
+ free_dns_addrinfo (aibuf);
+ subdomain_mode = 1;
+ domain = domainbuf;
+ }
+ }
+
+ /* Check for SRV records unless we have a subdomain. */
+ if (!subdomain_mode)
{
struct srventry *srvs;
unsigned int srvscount;
@@ -931,6 +969,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
xfree (srvs);
}
+ /* Prepare the hash of the local part. */
gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, mbox, strlen (mbox));
encodedhash = zb32_encode (sha1buf, 8*20);
if (!encodedhash)
@@ -944,7 +983,10 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
uri = strconcat ("https://",
domain,
portstr,
- "/.well-known/openpgpkey/submission-address",
+ "/.well-known/openpgpkey/",
+ subdomain_mode? domain_orig : "",
+ subdomain_mode? "/" : "",
+ "submission-address",
NULL);
}
else if (opt_policy_flags)
@@ -952,24 +994,39 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
uri = strconcat ("https://",
domain,
portstr,
- "/.well-known/openpgpkey/policy",
+ "/.well-known/openpgpkey/",
+ subdomain_mode? domain_orig : "",
+ subdomain_mode? "/" : "",
+ "policy",
NULL);
}
else
{
- uri = strconcat ("https://",
- domain,
- portstr,
- "/.well-known/openpgpkey/hu/",
- encodedhash,
- NULL);
- no_log = 1;
- if (uri)
+ char *escapedmbox;
+
+ escapedmbox = http_escape_string (mbox, "%;?&=");
+ if (escapedmbox)
{
- err = dirmngr_status_printf (ctrl, "SOURCE", "https://%s%s",
- domain, portstr);
- if (err)
- goto leave;
+ uri = strconcat ("https://",
+ domain,
+ portstr,
+ "/.well-known/openpgpkey/",
+ subdomain_mode? domain_orig : "",
+ subdomain_mode? "/" : "",
+ "hu/",
+ encodedhash,
+ "?l=",
+ escapedmbox,
+ NULL);
+ xfree (escapedmbox);
+ no_log = 1;
+ if (uri)
+ {
+ err = dirmngr_status_printf (ctrl, "SOURCE", "https://%s%s",
+ domain, portstr);
+ if (err)
+ goto leave;
+ }
}
}
if (!uri)
@@ -2680,6 +2737,20 @@ cmd_reloaddirmngr (assuan_context_t ctx, char *line)
}
+static const char hlp_flushcrls[] =
+ "FLUSHCRLS\n"
+ "\n"
+ "Remove all cached CRLs from memory and\n"
+ "the file system.";
+static gpg_error_t
+cmd_flushcrls (assuan_context_t ctx, char *line)
+{
+ (void)line;
+
+ return leave_cmd (ctx, crl_cache_flush () ? GPG_ERR_GENERAL : 0);
+}
+
+
/* Tell the assuan library about our commands. */
static int
@@ -2710,6 +2781,7 @@ register_commands (assuan_context_t ctx)
{ "LOADSWDB", cmd_loadswdb, hlp_loadswdb },
{ "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
{ "RELOADDIRMNGR",cmd_reloaddirmngr,hlp_reloaddirmngr },
+ { "FLUSHCRLS", cmd_flushcrls, hlp_flushcrls },
{ NULL, NULL }
};
int i, j, rc;
diff --git a/dirmngr/t-http-basic.c b/dirmngr/t-http-basic.c
new file mode 100644
index 000000000..edf82efb9
--- /dev/null
+++ b/dirmngr/t-http-basic.c
@@ -0,0 +1,199 @@
+/* t-http-basic.c - Basic regression tests for http.c
+ * Copyright (C) 2018 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include "../common/util.h"
+#include "t-support.h"
+#include "http.h"
+
+#define PGM "t-http-basic"
+
+
+static void
+test_http_prepare_redirect (void)
+{
+ static struct {
+ const char *url;
+ const char *location;
+ const char *expect_url;
+ gpg_error_t expect_err;
+ } tests[] = {
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ NULL,
+ "",
+ GPG_ERR_NO_DATA
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "",
+ "",
+ GPG_ERR_NO_DATA
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "foo//bla",
+ "",
+ GPG_ERR_BAD_URI
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ 0
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ 0
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://foo.gnupg.org:8080/.not-so-well-known/openpgpkey/hu/12345678",
+ "http://foo.gnupg.org:8080/.well-known/openpgpkey/hu/12345678",
+ 0
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http:///.no-so-well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ GPG_ERR_BAD_URI
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org:8080/.not-so-well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org:8080/.not-so-well-known/openpgpkey/hu/12345678",
+ 0
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org:8/.not-so-well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org:8/.not-so-well-known/openpgpkey/hu/12345678",
+ 0
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org:/.no-so-well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org:/.no-so-well-known/openpgpkey/hu/12345678",
+ 0
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org/",
+ "http://gnupg.org/",
+ 0
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.net",
+ "http://gnupg.net/.well-known/openpgpkey/hu/12345678",
+ 0
+ },
+ {
+ "http://gnupg.org",
+ "http://gnupg.org",
+ "http://gnupg.org",
+ 0
+ },
+ {
+ "http://gnupg.org",
+ "http://foo.gnupg.org",
+ "http://foo.gnupg.org",
+ 0
+ },
+ {
+ "http://gnupg.org/",
+ "http://foo.gnupg.org",
+ "http://foo.gnupg.org/",
+ 0
+ },
+ {
+ "http://gnupg.org",
+ "http://foo.gnupg.org/",
+ "http://foo.gnupg.org",
+ 0
+ },
+ {
+ "http://gnupg.org/.well-known/openpgpkey/hu/12345678",
+ "http://gnupg.org/something-else",
+ "http://gnupg.org/something-else",
+ 0
+ },
+ };
+ int tidx;
+ http_redir_info_t ri;
+ gpg_error_t err;
+ char *newurl;
+
+ err = http_prepare_redirect (NULL, 301, tests[0].location, &newurl);
+ if (gpg_err_code (err) != GPG_ERR_INV_ARG)
+ fail (0);
+ memset (&ri, 0, sizeof ri);
+ err = http_prepare_redirect (&ri, 301, tests[0].location, &newurl);
+ if (gpg_err_code (err) != GPG_ERR_INV_ARG)
+ fail (0);
+ memset (&ri, 0, sizeof ri);
+ ri.silent = 1;
+ ri.orig_url = "http://example.org";
+ err = http_prepare_redirect (&ri, 301, tests[0].location, &newurl);
+ if (gpg_err_code (err) != GPG_ERR_NO_DATA)
+ fail (0);
+
+ for (tidx = 0; tidx < DIM (tests); tidx++)
+ {
+ memset (&ri, 0, sizeof ri);
+ ri.silent = 1;
+ ri.redirects_left = 1;
+ ri.orig_url = tests[tidx].url;
+
+ err = http_prepare_redirect (&ri, 301, tests[tidx].location, &newurl);
+ if (err && newurl)
+ fail (tidx);
+ if (err && gpg_err_code (err) != tests[tidx].expect_err)
+ fail (tidx);
+ if (err)
+ continue;
+ if (!newurl)
+ fail (tidx);
+ if (strcmp (tests[tidx].expect_url, newurl))
+ {
+ fprintf (stderr, "want: '%s'\n", tests[tidx].expect_url);
+ fprintf (stderr, "got : '%s'\n", newurl);
+ fail (tidx);
+ }
+
+ xfree (newurl);
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_http_prepare_redirect ();
+
+ return 0;
+}
diff --git a/dirmngr/t-http.c b/dirmngr/t-http.c
index 2fc0a465c..70d7f3fac 100644
--- a/dirmngr/t-http.c
+++ b/dirmngr/t-http.c
@@ -137,7 +137,7 @@ my_http_tls_verify_cb (void *opaque,
(void)session;
(void)http_flags;
- /* Get the peer's certs fron ntbtls. */
+ /* Get the peer's certs from ntbtls. */
for (idx = 0;
(cert = ntbtls_x509_get_peer_cert (tls_context, idx)); idx++)
{
@@ -394,9 +394,9 @@ main (int argc, char **argv)
else
{
printf ("Auth : %s\n", uri->auth? uri->auth:"[none]");
- printf ("Host : %s\n", uri->host);
+ printf ("Host : %s (off=%hu)\n", uri->host, uri->off_host);
printf ("Port : %u\n", uri->port);
- printf ("Path : %s\n", uri->path);
+ printf ("Path : %s (off=%hu)\n", uri->path, uri->off_path);
for (r = uri->params; r; r = r->next)
{
printf ("Params: %s", r->name);
diff --git a/dirmngr/workqueue.c b/dirmngr/workqueue.c
index 2cb8573e8..a47cdebc8 100644
--- a/dirmngr/workqueue.c
+++ b/dirmngr/workqueue.c
@@ -116,7 +116,7 @@ workqueue_add_task (wqtask_t func, const char *args, unsigned int session_id,
/* Run the task described by ITEM. ITEM must have been detached from
- * the workqueue; its ownership is transferred to this fucntion. */
+ * the workqueue; its ownership is transferred to this function. */
static void
run_a_task (ctrl_t ctrl, wqitem_t item)
{