From 6c1dcd79cf0977844179d9a7b189c10af5e42a7e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 13 Nov 2017 16:09:32 +0100 Subject: [PATCH 01/17] dirmngr: Keep track of domains used for WKD queries * dirmngr/domaininfo.c: New file. * dirmngr/Makefile.am (dirmngr_SOURCES): Add file. * dirmngr/server.c (cmd_wkd_get): Check whether the domain is already known and tell domaininfo about the results. -- This adds a registry for domain information to eventually avoid useless queries for domains which do not support WKD. The missing part is a background task to check whether a queried domain supports WKD at all and to expire old entries. Signed-off-by: Werner Koch (cherry picked from commit 65038e6852185c20413d8f6602218ee636413b77) --- dirmngr/Makefile.am | 3 + dirmngr/dirmngr.c | 3 + dirmngr/dirmngr.h | 12 +++ dirmngr/domaininfo.c | 244 +++++++++++++++++++++++++++++++++++++++++++ dirmngr/server.c | 40 +++++++ 5 files changed, 302 insertions(+) create mode 100644 dirmngr/domaininfo.c diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am index b404165ed..421a32533 100644 --- a/dirmngr/Makefile.am +++ b/dirmngr/Makefile.am @@ -16,6 +16,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, see . +# +# SPDX-License-Identifier: GPL-3.0+ ## Process this file with automake to produce Makefile.in @@ -57,6 +59,7 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \ certcache.c certcache.h \ + domaininfo.c \ loadswdb.c \ cdb.h cdblib.c misc.c dirmngr-err.h \ ocsp.c ocsp.h validate.c validate.h \ diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 5317c214a..2b64655e8 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -17,6 +17,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0+ */ #include @@ -1871,6 +1873,7 @@ handle_signal (int signo) case SIGUSR1: cert_cache_print_stats (); + domaininfo_print_stats (); break; case SIGUSR2: diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index 1f660de10..b08e4fea7 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -17,6 +17,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0+ */ #ifndef DIRMNGR_H @@ -248,4 +250,14 @@ gpg_error_t gnupg_http_tls_verify_cb (void *opaque, gpg_error_t dirmngr_load_swdb (ctrl_t ctrl, int force); +/*-- domaininfo.c --*/ +void domaininfo_print_stats (void); +int domaininfo_is_wkd_not_supported (const char *domain); +void domaininfo_set_no_name (const char *domain); +void domaininfo_set_wkd_supported (const char *domain); +void domaininfo_set_wkd_not_supported (const char *domain); +void domaininfo_set_wkd_not_found (const char *domain); + + + #endif /*DIRMNGR_H*/ diff --git a/dirmngr/domaininfo.c b/dirmngr/domaininfo.c new file mode 100644 index 000000000..393db8c78 --- /dev/null +++ b/dirmngr/domaininfo.c @@ -0,0 +1,244 @@ +/* domaininfo.c - Gather statistics about accessed domains + * Copyright (C) 2017 Werner Koch + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0+ + */ + +#include +#include +#include + +#include "dirmngr.h" + + +#define NO_OF_DOMAINBUCKETS 103 + +/* Object to keep track of a domain name. */ +struct domaininfo_s +{ + struct domaininfo_s *next; + unsigned int no_name:1; /* Domain name not found. */ + unsigned int wkd_not_found:1; /* A WKD query failed. */ + unsigned int wkd_supported:1; /* One WKD entry was found. */ + unsigned int wkd_not_supported:1; /* Definitely does not support WKD. */ + char name[1]; +}; +typedef struct domaininfo_s *domaininfo_t; + +/* And the hashed array. */ +static domaininfo_t domainbuckets[NO_OF_DOMAINBUCKETS]; + + +/* The hash function we use. Must not call a system function. */ +static inline u32 +hash_domain (const char *domain) +{ + const unsigned char *s = (const unsigned char*)domain; + u32 hashval = 0; + u32 carry; + + for (; *s; s++) + { + if (*s == '.') + continue; + hashval = (hashval << 4) + *s; + if ((carry = (hashval & 0xf0000000))) + { + hashval ^= (carry >> 24); + hashval ^= carry; + } + } + + return hashval % NO_OF_DOMAINBUCKETS; +} + + +void +domaininfo_print_stats (void) +{ + int bidx; + domaininfo_t di; + int count, no_name, wkd_not_found, wkd_supported, wkd_not_supported; + + for (bidx = 0; bidx < NO_OF_DOMAINBUCKETS; bidx++) + { + count = no_name = wkd_not_found = wkd_supported = wkd_not_supported = 0; + for (di = domainbuckets[bidx]; di; di = di->next) + { + count++; + if (di->no_name) + no_name++; + if (di->wkd_not_found) + wkd_not_found++; + if (di->wkd_supported) + wkd_supported++; + if (di->wkd_not_supported) + wkd_not_supported++; + } + if (count) + log_info ("domaininfo: chain %3d length=%d nn=%d nf=%d s=%d ns=%d\n", + bidx, count, no_name, + wkd_not_found, wkd_supported, wkd_not_supported); + } +} + + +/* Return true if DOMAIN definitely does not support WKD. Noet that + * DOMAIN is expected to be lowercase. */ +int +domaininfo_is_wkd_not_supported (const char *domain) +{ + domaininfo_t di; + + for (di = domainbuckets[hash_domain (domain)]; di; di = di->next) + if (!strcmp (di->name, domain)) + return !!di->wkd_not_supported; + + return 0; /* We don't know. */ +} + + +/* Core update function. DOMAIN is expected to be lowercase. + * CALLBACK is called to update the existing or the newly inserted + * item. */ +static void +insert_or_update (const char *domain, + void (*callback)(domaininfo_t di, int insert_mode)) +{ + domaininfo_t di; + domaininfo_t di_new; + u32 hash; + + hash = hash_domain (domain); + for (di = domainbuckets[hash]; di; di = di->next) + if (!strcmp (di->name, domain)) + { + callback (di, 0); /* Update */ + return; + } + + di_new = xtrycalloc (1, sizeof *di + strlen (domain)); + if (!di_new) + return; /* Out of core - we ignore this. */ + + /* Need to do another lookup because the malloc is a system call and + * thus the hash array may have been changed by another thread. */ + for (di = domainbuckets[hash]; di; di = di->next) + if (!strcmp (di->name, domain)) + { + callback (di, 0); /* Update */ + xfree (di_new); + return; + } + + callback (di_new, 1); /* Insert */ + di = di_new; + di->next = domainbuckets[hash]; + domainbuckets[hash] = di; +} + + +/* Helper for domaininfo_set_no_name. */ +static void +set_no_name_cb (domaininfo_t di, int insert_mode) +{ + (void)insert_mode; + + di->no_name = 1; + /* Obviously the domain is in this case also not supported. */ + di->wkd_not_supported = 1; + + /* The next should already be 0 but we clear it anyway in the case + * of a temporary DNS failure. */ + di->wkd_supported = 0; +} + + +/* Mark DOMAIN as not existent. */ +void +domaininfo_set_no_name (const char *domain) +{ + insert_or_update (domain, set_no_name_cb); +} + + +/* Helper for domaininfo_set_wkd_supported. */ +static void +set_wkd_supported_cb (domaininfo_t di, int insert_mode) +{ + (void)insert_mode; + + di->wkd_supported = 1; + /* The next will already be set unless the domain enabled WKD in the + * meantime. Thus we need to clear it. */ + di->wkd_not_supported = 0; +} + + +/* Mark DOMAIN as supporting WKD. */ +void +domaininfo_set_wkd_supported (const char *domain) +{ + insert_or_update (domain, set_wkd_supported_cb); +} + + +/* Helper for domaininfo_set_wkd_not_supported. */ +static void +set_wkd_not_supported_cb (domaininfo_t di, int insert_mode) +{ + (void)insert_mode; + + di->wkd_not_supported = 1; + di->wkd_supported = 0; +} + + +/* Mark DOMAIN as not supporting WKD queries (e.g. no policy file). */ +void +domaininfo_set_wkd_not_supported (const char *domain) +{ + insert_or_update (domain, set_wkd_not_supported_cb); +} + + + +/* Helper for domaininfo_set_wkd_not_found. */ +static void +set_wkd_not_found_cb (domaininfo_t di, int insert_mode) +{ + /* Set the not found flag but there is no need to do this if we + * already know that the domain either does not support WKD or we + * know that it supports WKD. */ + if (insert_mode) + di->wkd_not_found = 1; + else if (!di->wkd_not_supported && !di->wkd_supported) + di->wkd_not_found = 1; + + /* Better clear this flag in case we had a DNS failure in the + * past. */ + di->no_name = 0; +} + + +/* Update a counter for DOMAIN to keep track of failed WKD queries. */ +void +domaininfo_set_wkd_not_found (const char *domain) +{ + insert_or_update (domain, set_wkd_not_found_cb); +} diff --git a/dirmngr/server.c b/dirmngr/server.c index 7ed6cde15..18a5f7206 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -18,6 +18,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0+ */ #include @@ -833,11 +835,13 @@ cmd_wkd_get (assuan_context_t ctx, char *line) char *mbox = NULL; char *domainbuf = NULL; char *domain; /* Points to mbox or domainbuf. */ + char *domain_orig;/* Points to mbox. */ char sha1buf[20]; char *uri = NULL; char *encodedhash = NULL; int opt_submission_addr; int opt_policy_flags; + int is_wkd_query; /* True if this is a real WKD query. */ int no_log = 0; char portstr[20] = { 0 }; @@ -846,6 +850,7 @@ cmd_wkd_get (assuan_context_t ctx, char *line) if (has_option (line, "--quick")) ctrl->timeout = opt.connect_quick_timeout; line = skip_options (line); + is_wkd_query = !(opt_policy_flags || opt_submission_addr); mbox = mailbox_from_userid (line); if (!mbox || !(domain = strchr (mbox, '@'))) @@ -854,6 +859,18 @@ cmd_wkd_get (assuan_context_t ctx, char *line) goto leave; } *domain++ = 0; + domain_orig = domain; + + /* First check whether we already know that the domain does not + * support WKD. */ + if (is_wkd_query) + { + if (domaininfo_is_wkd_not_supported (domain_orig)) + { + err = gpg_error (GPG_ERR_NO_DATA); + goto leave; + } + } /* Check for SRV records. */ if (1) @@ -962,6 +979,29 @@ cmd_wkd_get (assuan_context_t ctx, char *line) err = ks_action_fetch (ctrl, uri, outfp); es_fclose (outfp); ctrl->server_local->inhibit_data_logging = 0; + /* Register the result under the domain name of MBOX. */ + switch (gpg_err_code (err)) + { + case 0: + domaininfo_set_wkd_supported (domain_orig); + break; + + case GPG_ERR_NO_NAME: + /* There is no such domain. */ + domaininfo_set_no_name (domain_orig); + break; + + case GPG_ERR_NO_DATA: + if (is_wkd_query) /* Mark that - we will latter do a check. */ + domaininfo_set_wkd_not_found (domain_orig); + else if (opt_policy_flags) /* No policy file - no support. */ + domaininfo_set_wkd_not_supported (domain_orig); + break; + + default: + /* Don't register other errors. */ + break; + } } } From 7a663c296e687f12ccd9a21d414de780feb4dfcf Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 Nov 2017 08:37:27 +0100 Subject: [PATCH 02/17] dirmngr: Limit the number of cached domains for WKD. * dirmngr/domaininfo.c (MAX_DOMAINBUCKET_LEN): New. (insert_or_update): Limit the length of a bucket chain. (domaininfo_print_stats): Print just one summary line. Signed-off-by: Werner Koch (cherry picked from commit 26f08343fbccdbaa177c3507a3c5e24a5cf94a2d) --- dirmngr/domaininfo.c | 62 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/dirmngr/domaininfo.c b/dirmngr/domaininfo.c index 393db8c78..90cdb856c 100644 --- a/dirmngr/domaininfo.c +++ b/dirmngr/domaininfo.c @@ -26,7 +26,18 @@ #include "dirmngr.h" -#define NO_OF_DOMAINBUCKETS 103 +/* Number of bucket for the hash array and limit for the length of a + * bucket chain. For debugging values of 13 and 10 are more suitable + * and a command like + * for j in a b c d e f g h i j k l m n o p q r s t u v w z y z; do \ + * for i in a b c d e f g h i j k l m n o p q r s t u v w z y z; do \ + * gpg-connect-agent --dirmngr "wkd_get foo@$i.$j.gnupg.net" /bye \ + * >/dev/null ; done; done + * will quickly add a couple of domains. + */ +#define NO_OF_DOMAINBUCKETS 103 +#define MAX_DOMAINBUCKET_LEN 20 + /* Object to keep track of a domain name. */ struct domaininfo_s @@ -74,13 +85,18 @@ domaininfo_print_stats (void) int bidx; domaininfo_t di; int count, no_name, wkd_not_found, wkd_supported, wkd_not_supported; + int len, minlen, maxlen; + count = no_name = wkd_not_found = wkd_supported = wkd_not_supported = 0; + maxlen = 0; + minlen = -1; for (bidx = 0; bidx < NO_OF_DOMAINBUCKETS; bidx++) { - count = no_name = wkd_not_found = wkd_supported = wkd_not_supported = 0; + len = 0; for (di = domainbuckets[bidx]; di; di = di->next) { count++; + len++; if (di->no_name) no_name++; if (di->wkd_not_found) @@ -90,11 +106,16 @@ domaininfo_print_stats (void) if (di->wkd_not_supported) wkd_not_supported++; } - if (count) - log_info ("domaininfo: chain %3d length=%d nn=%d nf=%d s=%d ns=%d\n", - bidx, count, no_name, - wkd_not_found, wkd_supported, wkd_not_supported); + if (len > maxlen) + maxlen = len; + if (minlen == -1 || len < minlen) + minlen = len; } + log_info ("domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n", + count, + minlen > 0? minlen : 0, + maxlen, + no_name, wkd_not_found, wkd_not_supported, wkd_supported); } @@ -122,7 +143,9 @@ insert_or_update (const char *domain, { domaininfo_t di; domaininfo_t di_new; + domaininfo_t di_cut; u32 hash; + int count; hash = hash_domain (domain); for (di = domainbuckets[hash]; di; di = di->next) @@ -138,7 +161,8 @@ insert_or_update (const char *domain, /* Need to do another lookup because the malloc is a system call and * thus the hash array may have been changed by another thread. */ - for (di = domainbuckets[hash]; di; di = di->next) + di_cut = NULL; + for (count=0, di = domainbuckets[hash]; di; di = di->next, count++) if (!strcmp (di->name, domain)) { callback (di, 0); /* Update */ @@ -146,10 +170,32 @@ insert_or_update (const char *domain, return; } - callback (di_new, 1); /* Insert */ + /* Before we insert we need to check whether the chain gets too long. */ + di_cut = NULL; + if (count >= MAX_DOMAINBUCKET_LEN) + { + for (count=0, di = domainbuckets[hash]; di; di = di->next, count++) + if (count >= MAX_DOMAINBUCKET_LEN/2) + { + di_cut = di->next; + di->next = NULL; + break; + } + } + + /* Insert */ + callback (di_new, 1); di = di_new; di->next = domainbuckets[hash]; domainbuckets[hash] = di; + + /* Remove the rest of the cutted chain. */ + while (di_cut) + { + di = di_cut->next; + xfree (di_cut); + di_cut = di; + } } From f2997adee0455c8c0fa391a853ec1b0c9fc43342 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 Nov 2017 13:42:18 +0100 Subject: [PATCH 03/17] dirmngr: Add a background task framework. * dirmngr/workqueue.c: New. * dirmngr/Makefile.am (dirmngr_SOURCES): Add new file. * dirmngr/server.c (server_local_s): New field session_id. (cmd_wkd_get): Add a task. (task_check_wkd_support): New stub function. (cmd_getinfo): New sub-commands "session_id" and "workqueue". (start_command_handler): Add arg session_id and store it in SERVER_LOCAL. (dirmngr_status_helpf): New. * dirmngr/dirmngr.h (wqtask_t): New type. * dirmngr/dirmngr.c (main): Pass 0 as session_id to start_command_handler. (start_connection_thread): Introduce a session_id and pass it to start_command_handler. Run post session tasks. (housekeeping_thread): Run global workqueue tasks. -- Signed-off-by: Werner Koch (cherry picked from commit 96a4fbecd1acf946dcde20bef4752c539dae196b) --- dirmngr/Makefile.am | 1 + dirmngr/dirmngr.c | 14 ++- dirmngr/dirmngr.h | 13 ++- dirmngr/server.c | 75 ++++++++++++++-- dirmngr/workqueue.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 305 insertions(+), 12 deletions(-) create mode 100644 dirmngr/workqueue.c diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am index 421a32533..43f59bd45 100644 --- a/dirmngr/Makefile.am +++ b/dirmngr/Makefile.am @@ -60,6 +60,7 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \ certcache.c certcache.h \ domaininfo.c \ + workqueue.c \ loadswdb.c \ cdb.h cdblib.c misc.c dirmngr-err.h \ ocsp.c ocsp.h validate.c validate.h \ diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 2b64655e8..9cb02036e 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -1134,7 +1134,7 @@ main (int argc, char **argv) cert_cache_init (hkp_cacert_filenames); crl_cache_init (); http_register_netactivity_cb (netactivity_action); - start_command_handler (ASSUAN_INVALID_FD); + start_command_handler (ASSUAN_INVALID_FD, 0); shutdown_reaper (); } #ifndef HAVE_W32_SYSTEM @@ -1939,7 +1939,10 @@ housekeeping_thread (void *arg) network_activity_seen = 0; if (opt.allow_version_check) dirmngr_load_swdb (&ctrlbuf, 0); + workqueue_run_global_tasks (&ctrlbuf, 1); } + else + workqueue_run_global_tasks (&ctrlbuf, 0); dirmngr_deinit_default_ctrl (&ctrlbuf); @@ -2034,6 +2037,8 @@ check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) static void * start_connection_thread (void *arg) { + static unsigned int last_session_id; + unsigned int session_id; union int_and_ptr_u argval; gnupg_fd_t fd; @@ -2055,12 +2060,17 @@ start_connection_thread (void *arg) if (opt.verbose) log_info (_("handler for fd %d started\n"), FD2INT (fd)); - start_command_handler (fd); + session_id = ++last_session_id; + if (!session_id) + session_id = ++last_session_id; + start_command_handler (fd, session_id); if (opt.verbose) log_info (_("handler for fd %d terminated\n"), FD2INT (fd)); active_connections--; + workqueue_run_post_session_tasks (session_id); + #ifndef HAVE_W32_SYSTEM argval.afd = ASSUAN_INVALID_FD; npth_setspecific (my_tlskey_current_fd, argval.aptr); diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index b08e4fea7..5189f93b1 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -228,9 +228,11 @@ ksba_cert_t get_cert_local_ski (ctrl_t ctrl, gpg_error_t get_istrusted_from_client (ctrl_t ctrl, const char *hexfpr); int dirmngr_assuan_log_monitor (assuan_context_t ctx, unsigned int cat, const char *msg); -void start_command_handler (gnupg_fd_t fd); +void start_command_handler (gnupg_fd_t fd, unsigned int session_id); gpg_error_t dirmngr_status (ctrl_t ctrl, const char *keyword, ...); gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text); +gpg_error_t dirmngr_status_helpf (ctrl_t ctrl, const char *format, + ...) GPGRT_ATTR_PRINTF(2,3); gpg_error_t dirmngr_status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...) GPGRT_ATTR_PRINTF(3,4); @@ -258,6 +260,15 @@ void domaininfo_set_wkd_supported (const char *domain); void domaininfo_set_wkd_not_supported (const char *domain); void domaininfo_set_wkd_not_found (const char *domain); +/*-- workqueue.c --*/ +typedef const char *(*wqtask_t)(ctrl_t ctrl, const char *args); + +void workqueue_dump_queue (ctrl_t ctrl); +gpg_error_t workqueue_add_task (wqtask_t func, const char *args, + unsigned int session_id, int need_network); +void workqueue_run_global_tasks (ctrl_t ctrl, int with_network); +void workqueue_run_post_session_tasks (unsigned int session_id); + #endif /*DIRMNGR_H*/ diff --git a/dirmngr/server.c b/dirmngr/server.c index 18a5f7206..1fbd007a0 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -90,6 +90,9 @@ struct server_local_s /* Data used to associate an Assuan context with local server data */ assuan_context_t assuan_ctx; + /* The session id (a counter). */ + unsigned int session_id; + /* Per-session LDAP servers. */ ldap_server_t ldapservers; @@ -125,6 +128,9 @@ static es_cookie_io_functions_t data_line_cookie_functions = }; +/* Local prototypes */ +static const char *task_check_wkd_support (ctrl_t ctrl, const char *domain); + @@ -992,8 +998,12 @@ cmd_wkd_get (assuan_context_t ctx, char *line) break; case GPG_ERR_NO_DATA: - if (is_wkd_query) /* Mark that - we will latter do a check. */ - domaininfo_set_wkd_not_found (domain_orig); + if (is_wkd_query) /* Mark that and schedule a check. */ + { + domaininfo_set_wkd_not_found (domain_orig); + workqueue_add_task (task_check_wkd_support, domain_orig, + ctrl->server_local->session_id, 1); + } else if (opt_policy_flags) /* No policy file - no support. */ domaininfo_set_wkd_not_supported (domain_orig); break; @@ -1014,6 +1024,20 @@ cmd_wkd_get (assuan_context_t ctx, char *line) } +/* A task to check whether DOMAIN supports WKD. This is done by + * checking whether the policy flags file can be read. */ +static const char * +task_check_wkd_support (ctrl_t ctrl, const char *domain) +{ + if (!ctrl || !domain) + return "check_wkd_support"; + + log_debug ("FIXME: Implement %s\n", __func__); + + return NULL; +} + + static const char hlp_ldapserver[] = "LDAPSERVER \n" @@ -2428,12 +2452,15 @@ static const char hlp_getinfo[] = "pid - Return the process id of the server.\n" "tor - Return OK if running in Tor mode\n" "dnsinfo - Return info about the DNS resolver\n" - "socket_name - Return the name of the socket.\n"; + "socket_name - Return the name of the socket.\n" + "session_id - Return the current session_id.\n" + "workqueue - Inspect the work queue\n"; static gpg_error_t cmd_getinfo (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err; + char numbuf[50]; if (!strcmp (line, "version")) { @@ -2442,8 +2469,6 @@ cmd_getinfo (assuan_context_t ctx, char *line) } else if (!strcmp (line, "pid")) { - char numbuf[50]; - snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ()); err = assuan_send_data (ctx, numbuf, strlen (numbuf)); } @@ -2452,6 +2477,11 @@ cmd_getinfo (assuan_context_t ctx, char *line) const char *s = dirmngr_get_current_socket_name (); err = assuan_send_data (ctx, s, strlen (s)); } + else if (!strcmp (line, "session_id")) + { + snprintf (numbuf, sizeof numbuf, "%u", ctrl->server_local->session_id); + err = assuan_send_data (ctx, numbuf, strlen (numbuf)); + } else if (!strcmp (line, "tor")) { int use_tor; @@ -2487,6 +2517,11 @@ cmd_getinfo (assuan_context_t ctx, char *line) } err = 0; } + else if (!strcmp (line, "workqueue")) + { + workqueue_dump_queue (ctrl); + err = 0; + } else err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); @@ -2614,9 +2649,10 @@ dirmngr_assuan_log_monitor (assuan_context_t ctx, unsigned int cat, /* Startup the server and run the main command loop. With FD = -1, - use stdin/stdout. */ + * use stdin/stdout. SESSION_ID is either 0 or a unique number + * identifying a session. */ void -start_command_handler (assuan_fd_t fd) +start_command_handler (assuan_fd_t fd, unsigned int session_id) { static const char hello[] = "Dirmngr " VERSION " at your service"; static char *hello_line; @@ -2693,6 +2729,8 @@ start_command_handler (assuan_fd_t fd) assuan_register_option_handler (ctx, option_handler); assuan_register_reset_notify (ctx, reset_notify); + ctrl->server_local->session_id = session_id; + for (;;) { rc = assuan_accept (ctx); @@ -2792,8 +2830,7 @@ dirmngr_status (ctrl_t ctrl, const char *keyword, ...) } -/* Print a help status line. TEXTLEN gives the length of the text - from TEXT to be printed. The function splits text at LFs. */ +/* Print a help status line. The function splits text at LFs. */ gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text) { @@ -2823,6 +2860,26 @@ dirmngr_status_help (ctrl_t ctrl, const char *text) } +/* Print a help status line using a printf like format. The function + * splits text at LFs. */ +gpg_error_t +dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...) +{ + va_list arg_ptr; + gpg_error_t err; + char *buf; + + va_start (arg_ptr, format); + buf = es_vbsprintf (format, arg_ptr); + err = buf? 0 : gpg_error_from_syserror (); + va_end (arg_ptr); + if (!err) + err = dirmngr_status_help (ctrl, buf); + es_free (buf); + return err; +} + + /* This function is similar to print_assuan_status but takes a CTRL * arg instead of an assuan context as first argument. */ gpg_error_t diff --git a/dirmngr/workqueue.c b/dirmngr/workqueue.c new file mode 100644 index 000000000..2cb8573e8 --- /dev/null +++ b/dirmngr/workqueue.c @@ -0,0 +1,214 @@ +/* workqueue.c - Maintain a queue of background tasks + * Copyright (C) 2017 Werner Koch + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0+ + */ + +#include +#include +#include + +#include "dirmngr.h" + + +/* An object for one item in the workqueue. */ +struct wqitem_s +{ + struct wqitem_s *next; + + /* This flag is set if the task requires network access. */ + unsigned int need_network:1; + + /* The id of the session which created this task. If this is 0 the + * task is not associated with a specific session. */ + unsigned int session_id; + + /* The function to perform the backgrount task. */ + wqtask_t func; + + /* A string with the string argument for that task. */ + char args[1]; +}; +typedef struct wqitem_s *wqitem_t; + + +/* The workque is a simple linked list. */ +static wqitem_t workqueue; + + +/* Dump the queue using Assuan status comments. */ +void +workqueue_dump_queue (ctrl_t ctrl) +{ + wqitem_t saved_workqueue; + wqitem_t item; + unsigned int count; + + /* Temporay detach the entiere workqueue so that other threads don't + * get into our way. */ + saved_workqueue = workqueue; + workqueue = NULL; + + for (count=0, item = saved_workqueue; item; item = item->next) + count++; + + dirmngr_status_helpf (ctrl, "wq: number of entries: %u", count); + for (item = saved_workqueue; item; item = item->next) + dirmngr_status_helpf (ctrl, "wq: sess=%u net=%d %s(\"%.100s%s\")", + item->session_id, item->need_network, + item->func? item->func (NULL, NULL): "nop", + item->args, strlen (item->args) > 100? "[...]":""); + + /* Restore then workqueue. Actually we append the saved queue do a + * possibly updated workqueue. */ + if (!(item=workqueue)) + workqueue = saved_workqueue; + else + { + while (item->next) + item = item->next; + item->next = saved_workqueue; + } +} + + +/* Append the task (FUNC,ARGS) to the work queue. FUNC shall return + * its name when called with (NULL, NULL). */ +gpg_error_t +workqueue_add_task (wqtask_t func, const char *args, unsigned int session_id, + int need_network) +{ + wqitem_t item, wi; + + item = xtrycalloc (1, sizeof *item + strlen (args)); + if (!item) + return gpg_error_from_syserror (); + strcpy (item->args, args); + item->func = func; + item->session_id = session_id; + item->need_network = !!need_network; + + if (!(wi=workqueue)) + workqueue = item; + else + { + while (wi->next) + wi = wi->next; + wi->next = item; + } + return 0; +} + + +/* Run the task described by ITEM. ITEM must have been detached from + * the workqueue; its ownership is transferred to this fucntion. */ +static void +run_a_task (ctrl_t ctrl, wqitem_t item) +{ + log_assert (!item->next); + + if (opt.verbose) + log_info ("session %u: running %s(\"%s%s\")\n", + item->session_id, + item->func? item->func (NULL, NULL): "nop", + item->args, strlen (item->args) > 100? "[...]":""); + if (item->func) + item->func (ctrl, item->args); + + xfree (item); +} + + +/* Run tasks not associated with a session. This is called from the + * ticker every few minutes. If WITH_NETWORK is not set tasks which + * require the network are not run. */ +void +workqueue_run_global_tasks (ctrl_t ctrl, int with_network) +{ + wqitem_t item, prev; + + with_network = !!with_network; + + if (opt.verbose) + log_info ("running scheduled tasks%s\n", with_network?" (with network)":""); + + for (;;) + { + prev = NULL; + for (item = workqueue; item; prev = item, item = item->next) + if (!item->session_id + && (!item->need_network || (item->need_network && with_network))) + break; + if (!item) + break; /* No more tasks to run. */ + + /* Detach that item from the workqueue. */ + if (!prev) + workqueue = item->next; + else + prev->next = item->next; + item->next = NULL; + + /* Run the task. */ + run_a_task (ctrl, item); + } +} + + +/* Run tasks scheduled for running after a session. Those tasks are + * identified by the SESSION_ID. */ +void +workqueue_run_post_session_tasks (unsigned int session_id) +{ + struct server_control_s ctrlbuf; + ctrl_t ctrl = NULL; + wqitem_t item, prev; + + if (!session_id) + return; + + for (;;) + { + prev = NULL; + for (item = workqueue; item; prev = item, item = item->next) + if (item->session_id == session_id) + break; + if (!item) + break; /* No more tasks for this session. */ + + /* Detach that item from the workqueue. */ + if (!prev) + workqueue = item->next; + else + prev->next = item->next; + item->next = NULL; + + /* Create a CTRL object the first time we need it. */ + if (!ctrl) + { + memset (&ctrlbuf, 0, sizeof ctrlbuf); + ctrl = &ctrlbuf; + dirmngr_init_default_ctrl (ctrl); + } + + /* Run the task. */ + run_a_task (ctrl, item); + } + + dirmngr_deinit_default_ctrl (ctrl); +} From 20b52be9ca29b0bc843fc68a279cb72728ede72f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 14 Nov 2017 16:24:12 +0100 Subject: [PATCH 04/17] dirmngr: Check for WKD support at session end * dirmngr/domaininfo.c (insert_or_update): Copy the name. * dirmngr/misc.c (copy_stream): Allow arg OUT to be NULL. * dirmngr/server.c (set_error): Protect CTX. (dirmngr_status): Protect against missing ASSUAN_CTX. (dirmngr_status_help): Ditto. (dirmngr_status_printf): Ditto. (cmd_wkd_get): Factor code out to ... (proc_wkd_get): new func. Support silent operation with no CTX. (task_check_wkd_support): New. -- This finalizes the feature to efficiently cache WKD checks. If a standard WKD query returns no data, we queue a test to be run after the end of the session (so that we do not delay the calling client). This check tests whether the server responsible for the queried address has WKD at all enabled. The test is done by checking whether the "policy" file exists. We do not check the "submission-address" file because that is not necessary for the web key operation. The policy file is now required. Signed-off-by: Werner Koch (cherry picked from commit d4e2302d8f4a1ff52d56da4f8e3a5d1c6303822d) --- dirmngr/domaininfo.c | 1 + dirmngr/ks-action.c | 3 +- dirmngr/misc.c | 7 ++-- dirmngr/server.c | 79 +++++++++++++++++++++++++++++++------------- 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/dirmngr/domaininfo.c b/dirmngr/domaininfo.c index 90cdb856c..a2effffef 100644 --- a/dirmngr/domaininfo.c +++ b/dirmngr/domaininfo.c @@ -158,6 +158,7 @@ insert_or_update (const char *domain, di_new = xtrycalloc (1, sizeof *di + strlen (domain)); if (!di_new) return; /* Out of core - we ignore this. */ + strcpy (di_new->name, domain); /* Need to do another lookup because the malloc is a system call and * thus the hash array may have been changed by another thread. */ diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c index 857aab166..38cd02feb 100644 --- a/dirmngr/ks-action.c +++ b/dirmngr/ks-action.c @@ -296,7 +296,8 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers, /* Retrieve keys from URL and write the result to the provided output - stream OUTFP. */ + * stream OUTFP. If OUTFP is NULL the data is written to the bit + * bucket. */ gpg_error_t ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp) { diff --git a/dirmngr/misc.c b/dirmngr/misc.c index 1716141a6..6291a9a35 100644 --- a/dirmngr/misc.c +++ b/dirmngr/misc.c @@ -636,7 +636,9 @@ armor_data (char **r_string, const void *data, size_t datalen) return 0; } -/* Copy all data from IN to OUT. */ + +/* Copy all data from IN to OUT. OUT may be NULL to use this fucntion + * as a dummy reader. */ gpg_error_t copy_stream (estream_t in, estream_t out) { @@ -647,9 +649,8 @@ copy_stream (estream_t in, estream_t out) { if (!nread) return 0; /* EOF */ - if (es_write (out, buffer, nread, NULL)) + if (out && es_write (out, buffer, nread, NULL)) break; - } return gpg_error_from_syserror (); } diff --git a/dirmngr/server.c b/dirmngr/server.c index 1fbd007a0..3d0768b2a 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -80,7 +80,8 @@ #define PARM_ERROR(t) assuan_set_error (ctx, \ gpg_error (GPG_ERR_ASS_PARAMETER), (t)) -#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) +#define set_error(e,t) (ctx ? assuan_set_error (ctx, gpg_error (e), (t)) \ + /**/: gpg_error (e)) @@ -828,15 +829,11 @@ cmd_dns_cert (assuan_context_t ctx, char *line) -static const char hlp_wkd_get[] = - "WKD_GET [--submission-address|--policy-flags] \n" - "\n" - "Return the key or other info for \n" - "from the Web Key Directory."; +/* Core of cmd_wkd_get and task_check_wkd_support. If CTX is NULL + * this function will not write anything to the assuan output. */ static gpg_error_t -cmd_wkd_get (assuan_context_t ctx, char *line) +proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line) { - ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err = 0; char *mbox = NULL; char *domainbuf = NULL; @@ -895,7 +892,8 @@ cmd_wkd_get (assuan_context_t ctx, char *line) domainlen = strlen (domain); for (i = 0; i < srvscount; i++) { - log_debug ("srv: trying '%s:%hu'\n", srvs[i].target, srvs[i].port); + if (DBG_DNS) + log_debug ("srv: trying '%s:%hu'\n", srvs[i].target, srvs[i].port); targetlen = strlen (srvs[i].target); if ((targetlen > domainlen + 1 && srvs[i].target[targetlen - domainlen - 1] == '.' @@ -972,19 +970,24 @@ cmd_wkd_get (assuan_context_t ctx, char *line) { estream_t outfp; - outfp = es_fopencookie (ctx, "w", data_line_cookie_functions); - if (!outfp) + outfp = ctx? es_fopencookie (ctx, "w", data_line_cookie_functions) : NULL; + if (!outfp && ctx) err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream"); else { - if (no_log) - ctrl->server_local->inhibit_data_logging = 1; - ctrl->server_local->inhibit_data_logging_now = 0; - ctrl->server_local->inhibit_data_logging_count = 0; + if (ctrl->server_local) + { + if (no_log) + ctrl->server_local->inhibit_data_logging = 1; + ctrl->server_local->inhibit_data_logging_now = 0; + ctrl->server_local->inhibit_data_logging_count = 0; + } err = ks_action_fetch (ctrl, uri, outfp); es_fclose (outfp); - ctrl->server_local->inhibit_data_logging = 0; + if (ctrl->server_local) + ctrl->server_local->inhibit_data_logging = 0; + /* Register the result under the domain name of MBOX. */ switch (gpg_err_code (err)) { @@ -998,8 +1001,9 @@ cmd_wkd_get (assuan_context_t ctx, char *line) break; case GPG_ERR_NO_DATA: - if (is_wkd_query) /* Mark that and schedule a check. */ + if (is_wkd_query && ctrl->server_local) { + /* Mark that and schedule a check. */ domaininfo_set_wkd_not_found (domain_orig); workqueue_add_task (task_check_wkd_support, domain_orig, ctrl->server_local->session_id, 1); @@ -1020,6 +1024,23 @@ cmd_wkd_get (assuan_context_t ctx, char *line) xfree (encodedhash); xfree (mbox); xfree (domainbuf); + return err; +} + + +static const char hlp_wkd_get[] = + "WKD_GET [--submission-address|--policy-flags] \n" + "\n" + "Return the key or other info for \n" + "from the Web Key Directory."; +static gpg_error_t +cmd_wkd_get (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + + err = proc_wkd_get (ctrl, ctx, line); + return leave_cmd (ctx, err); } @@ -1029,10 +1050,19 @@ cmd_wkd_get (assuan_context_t ctx, char *line) static const char * task_check_wkd_support (ctrl_t ctrl, const char *domain) { + char *string; + if (!ctrl || !domain) return "check_wkd_support"; - log_debug ("FIXME: Implement %s\n", __func__); + string = strconcat ("--policy-flags foo@", domain, NULL); + if (!string) + log_error ("%s: %s\n", __func__, gpg_strerror (gpg_error_from_syserror ())); + else + { + proc_wkd_get (ctrl, NULL, string); + xfree (string); + } return NULL; } @@ -2800,12 +2830,12 @@ dirmngr_status (ctrl_t ctrl, const char *keyword, ...) gpg_error_t err = 0; va_list arg_ptr; const char *text; + assuan_context_t ctx; va_start (arg_ptr, keyword); - if (ctrl->server_local) + if (ctrl->server_local && (ctx = ctrl->server_local->assuan_ctx)) { - assuan_context_t ctx = ctrl->server_local->assuan_ctx; char buf[950], *p; size_t n; @@ -2835,10 +2865,10 @@ gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text) { gpg_error_t err = 0; + assuan_context_t ctx; - if (ctrl->server_local) + if (ctrl->server_local && (ctx = ctrl->server_local->assuan_ctx)) { - assuan_context_t ctx = ctrl->server_local->assuan_ctx; char buf[950], *p; size_t n; @@ -2888,7 +2918,10 @@ dirmngr_status_printf (ctrl_t ctrl, const char *keyword, { gpg_error_t err; va_list arg_ptr; - assuan_context_t ctx = ctrl->server_local->assuan_ctx; + assuan_context_t ctx; + + if (!ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx)) + return 0; va_start (arg_ptr, format); err = vprint_assuan_status (ctx, keyword, format, arg_ptr); From 17efcd2a2acdc3b7f00711272aa51e5be2476921 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Dec 2017 09:42:43 +0100 Subject: [PATCH 05/17] build: New configure option --enable-run-gnupg-user-socket. * configure.ac: (USE_RUN_GNUPG_USER_SOCKET): New ac_define. * common/homedir.c (_gnupg_socketdir_internal): Add extra directories. -- This allows to build GnuPG with an extra socketdir below /run. See https://lists.gnupg.org/pipermail/gnupg-devel/2017-November/033250.html for a longer explanation why this is sometimes useful. Suggested-by: Rainer Perske Signed-off-by: Werner Koch --- common/homedir.c | 14 ++++++++++++-- configure.ac | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/common/homedir.c b/common/homedir.c index 149e1ec62..a598900b9 100644 --- a/common/homedir.c +++ b/common/homedir.c @@ -541,7 +541,17 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info) #else /* Unix and stat(2) available. */ - static const char * const bases[] = { "/run", "/var/run", NULL}; + static const char * const bases[] = { +#ifdef USE_RUN_GNUPG_USER_SOCKET + "/run/gnupg", +#endif + "/run", +#ifdef USE_RUN_GNUPG_USER_SOCKET + "/var/run/gnupg", +#endif + "/var/run", + NULL + }; int i; struct stat sb; char prefix[13 + 1 + 20 + 6 + 1]; @@ -559,7 +569,7 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info) * as a background process with no (desktop) user logged in. Thus * we better don't do that. */ - /* Check whether we have a /run/user dir. */ + /* Check whether we have a /run/[gnupg/]user dir. */ for (i=0; bases[i]; i++) { snprintf (prefix, sizeof prefix, "%s/user/%u", diff --git a/configure.ac b/configure.ac index a9b7a0585..382ef1df5 100644 --- a/configure.ac +++ b/configure.ac @@ -1714,6 +1714,22 @@ if test x"$gnupg_builddir_envvar" = x"yes"; then [This is only used with "make distcheck"]) fi + +# +# To avoid problems with systemd cleaning up the /run/user directory, +# this option will make GnuPG try to use /run/gnupg/user as socket dir +# before /run/user +# +AC_ARG_ENABLE(run-gnupg-user-socket, + AC_HELP_STRING([--enable-run-gnupg-user-socket], + [try /run/gnupg/user for sockets prior to /run/user]), + use_run_gnupg_user_socket=$enableval) +if test x"$use_run_gnupg_user_socket" = x"yes"; then + AC_DEFINE(USE_RUN_GNUPG_USER_SOCKET, 1, + [If defined try /run/gnupg/user before /run/user]) +fi + + # # Decide what to build # From c81a447190d2763ac4c64b2e74e22e824da8aba3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Dec 2017 14:14:40 +0100 Subject: [PATCH 06/17] Change backlog from 5 to 64 and provide option --listen-backlog. * agent/gpg-agent.c (oListenBacklog): New const. (opts): New option --listen-backlog. (listen_backlog): New var. (main): Parse new options. (create_server_socket): Use var instead of 5. * dirmngr/dirmngr.c: Likewise. * scd/scdaemon.c: Likewise. -- GnuPG-bug-id: 3473 Signed-off-by: Werner Koch --- agent/gpg-agent.c | 16 ++++++++++++++-- dirmngr/dirmngr.c | 15 +++++++++++++-- doc/dirmngr.texi | 4 ++++ doc/gpg-agent.texi | 3 +++ doc/scdaemon.texi | 6 ++++++ scd/scdaemon.c | 16 +++++++++++++--- 6 files changed, 53 insertions(+), 7 deletions(-) diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 21beb29c7..a1964ece8 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -136,6 +136,7 @@ enum cmd_and_opt_values oDisableCheckOwnSocket, oS2KCount, oAutoExpandSecmem, + oListenBacklog, oWriteEnvFile }; @@ -255,6 +256,8 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"), + ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"), + /* Dummy options for backward compatibility. */ ARGPARSE_o_s (oWriteEnvFile, "write-env-file", "@"), ARGPARSE_s_n (oUseStandardSocket, "use-standard-socket", "@"), @@ -371,6 +374,10 @@ static assuan_sock_nonce_t socket_nonce_extra; static assuan_sock_nonce_t socket_nonce_browser; static assuan_sock_nonce_t socket_nonce_ssh; +/* Value for the listen() backlog argument. We use the same value for + * all sockets - 64 is on current Linux half of the default maximum. + * Let's try this as default. Change at runtime with --listen-backlog. */ +static int listen_backlog = 64; /* Default values for options passed to the pinentry. */ static char *default_display; @@ -1245,6 +1252,10 @@ main (int argc, char **argv ) (unsigned int)pargs.r.ret_ulong, 0); break; + case oListenBacklog: + listen_backlog = pargs.r.ret_int; + break; + case oDebugQuickRandom: /* Only used by the first stage command line parser. */ break; @@ -2248,9 +2259,10 @@ create_server_socket (char *name, int primary, int cygwin, log_error (_("can't set permissions of '%s': %s\n"), unaddr->sun_path, strerror (errno)); - if (listen (FD2INT(fd), 5 ) == -1) + if (listen (FD2INT(fd), listen_backlog ) == -1) { - log_error (_("listen() failed: %s\n"), strerror (errno)); + log_error ("listen(fd,%d) failed: %s\n", + listen_backlog, strerror (errno)); *name = 0; /* Inhibit removal of the socket by cleanup(). */ assuan_sock_close (fd); xfree (unaddr); diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 9cb02036e..17adae2f4 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -151,6 +151,7 @@ enum cmd_and_opt_values { oResolverTimeout, oConnectTimeout, oConnectQuickTimeout, + oListenBacklog, aTest }; @@ -256,6 +257,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_i (oResolverTimeout, "resolver-timeout", "@"), ARGPARSE_s_i (oConnectTimeout, "connect-timeout", "@"), ARGPARSE_s_i (oConnectQuickTimeout, "connect-quick-timeout", "@"), + ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"), ARGPARSE_group (302,N_("@\n(See the \"info\" manual for a complete listing " "of all commands and options)\n")), @@ -296,6 +298,10 @@ static const char *redir_socket_name; POSIX systems). */ static assuan_sock_nonce_t socket_nonce; +/* Value for the listen() backlog argument. + * Change at runtime with --listen-backlog. */ +static int listen_backlog = 64; + /* Only if this flag has been set will we remove the socket file. */ static int cleanup_socket; @@ -1019,6 +1025,10 @@ main (int argc, char **argv) case oSocketName: socket_name = pargs.r.ret_str; break; + case oListenBacklog: + listen_backlog = pargs.r.ret_int; + break; + default : pargs.err = configfp? 1:2; break; } } @@ -1263,9 +1273,10 @@ main (int argc, char **argv) log_error (_("can't set permissions of '%s': %s\n"), serv_addr.sun_path, strerror (errno)); - if (listen (FD2INT (fd), 5) == -1) + if (listen (FD2INT (fd), listen_backlog) == -1) { - log_error (_("listen() failed: %s\n"), strerror (errno)); + log_error ("listen(fd,%d) failed: %s\n", + listen_backlog, strerror (errno)); assuan_sock_close (fd); dirmngr_exit (1); } diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi index 9654a0e74..800955c52 100644 --- a/doc/dirmngr.texi +++ b/doc/dirmngr.texi @@ -282,6 +282,10 @@ default values are 15 and 2 seconds. Note that the timeout values are for each connection attempt; the connection code will attempt to connect all addresses listed for a server. +@item --listen-backlog @var{n} +@opindex listen-backlog +Set the size of the queue for pending connections. The default is 64. + @item --allow-version-check @opindex allow-version-check Allow Dirmngr to connect to @code{https://versions.gnupg.org} to get diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index 65df9708b..3e8bd894d 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -563,6 +563,9 @@ Ignore requests to change the current @code{tty} or X window system's @code{DISPLAY} variable respectively. This is useful to lock the pinentry to pop up at the @code{tty} or display you started the agent. +@item --listen-backlog @var{n} +@opindex listen-backlog +Set the size of the queue for pending connections. The default is 64. @anchor{option --extra-socket} @item --extra-socket @var{name} diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index 4c6bb93b6..a9e6d1e7a 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -236,6 +236,12 @@ a list of categories see the Libassuan manual. Don't detach the process from the console. This is mainly useful for debugging. +@item --listen-backlog @var{n} +@opindex listen-backlog +Set the size of the queue for pending connections. The default is 64. +This option has an effect only if @option{--multi-server} is also +used. + @item --log-file @var{file} @opindex log-file Append all logging output to @var{file}. This is very helpful in diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 0bedb8de2..3ad265781 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -99,6 +99,7 @@ enum cmd_and_opt_values oDenyAdmin, oDisableApplication, oEnablePinpadVarlen, + oListenBacklog }; @@ -156,6 +157,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen", N_("use variable length input for pinpad")), ARGPARSE_s_s (oHomedir, "homedir", "@"), + ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"), ARGPARSE_end () }; @@ -224,6 +226,10 @@ static char *redir_socket_name; POSIX systems). */ static assuan_sock_nonce_t socket_nonce; +/* Value for the listen() backlog argument. Change at runtime with + * --listen-backlog. */ +static int listen_backlog = 64; + #ifdef HAVE_W32_SYSTEM static HANDLE the_event; #else @@ -594,6 +600,10 @@ main (int argc, char **argv ) case oEnablePinpadVarlen: opt.enable_pinpad_varlen = 1; break; + case oListenBacklog: + listen_backlog = pargs.r.ret_int; + break; + default: pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR; break; @@ -1128,10 +1138,10 @@ create_server_socket (const char *name, char **r_redir_name, log_error (_("can't set permissions of '%s': %s\n"), unaddr->sun_path, strerror (errno)); - if (listen (FD2INT(fd), 5 ) == -1) + if (listen (FD2INT(fd), listen_backlog) == -1) { - log_error (_("listen() failed: %s\n"), - gpg_strerror (gpg_error_from_syserror ())); + log_error ("listen(fd, %d) failed: %s\n", + listen_backlog, gpg_strerror (gpg_error_from_syserror ())); assuan_sock_close (fd); scd_exit (2); } From 8ede3ae29a39641a2f98ad9a4cf61ea99085a892 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Thu, 28 Sep 2017 08:32:26 -0400 Subject: [PATCH 07/17] gpg: default-preference-list: prefer SHA512. * g10/keygen.c (keygen_set_std_prefs): when producing default internal personal-digest-preferences, keep the same order. When publishing external preferences, state preference for SHA512 first. -- SHA-512 has a wider security margin than SHA-256. It is also slightly faster on most of the architectures on which GnuPG runs today. New keys should publish defaults that indicate we prefer the stronger, more performant digest. Specifically, this changes --default-preference-list from: SHA256 SHA384 SHA512 SHA224 to: SHA512 SHA384 SHA256 SHA224 This patch deliberately avoids touching --personal-digest-preferences (which itself would affect the default of --digest-algo and --cert-digest-algo), so that public-facing cleartext signatures and identity certifications will continue to be made with SHA256 by default. Signed-off-by: Daniel Kahn Gillmor --- g10/keygen.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/g10/keygen.c b/g10/keygen.c index 38686b213..7ef3cac1d 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -384,19 +384,36 @@ keygen_set_std_prefs (const char *string,int personal) strcat(dummy_string,"S7 "); strcat(dummy_string,"S2 "); /* 3DES */ - /* The default hash algo order is: - SHA-256, SHA-384, SHA-512, SHA-224, SHA-1. - */ - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) - strcat (dummy_string, "H8 "); + if (personal) + { + /* The default internal hash algo order is: + * SHA-256, SHA-384, SHA-512, SHA-224, SHA-1. + */ + if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) + strcat (dummy_string, "H8 "); - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) - strcat (dummy_string, "H9 "); + if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) + strcat (dummy_string, "H9 "); - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) - strcat (dummy_string, "H10 "); + if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) + strcat (dummy_string, "H10 "); + } + else + { + /* The default advertised hash algo order is: + * SHA-512, SHA-384, SHA-256, SHA-224, SHA-1. + */ + if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) + strcat (dummy_string, "H10 "); - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224)) + if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) + strcat (dummy_string, "H9 "); + + if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) + strcat (dummy_string, "H8 "); + } + + if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224)) strcat (dummy_string, "H11 "); strcat (dummy_string, "H2 "); /* SHA-1 */ From 8602b980dfff9ed1bd5e6c04ca2fd71d12fd8fa2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Dec 2017 09:54:39 +0100 Subject: [PATCH 08/17] indent: Re-indent get_pubkeys. -- --- g10/getkey.c | 107 +++++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 59 deletions(-) diff --git a/g10/getkey.c b/g10/getkey.c index f73e44326..eaf15ade1 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -413,34 +413,35 @@ pubkeys_free (pubkey_t keys) } } + /* Returns all keys that match the search specification SEARCH_TERMS. - - This function also checks for and warns about duplicate entries in - the keydb, which can occur if the user has configured multiple - keyrings or keyboxes or if a keyring or keybox was corrupted. - - Note: SEARCH_TERMS will not be expanded (i.e., it may not be a - group). - - USE is the operation for which the key is required. It must be - either PUBKEY_USAGE_ENC, PUBKEY_USAGE_SIG, PUBKEY_USAGE_CERT or - PUBKEY_USAGE_AUTH. - - XXX: Currently, only PUBKEY_USAGE_ENC and PUBKEY_USAGE_SIG are - implemented. - - INCLUDE_UNUSABLE indicates whether disabled keys are allowed. - (Recipients specified with --encrypt-to and --hidden-encrypt-to may - be disabled. It is possible to edit disabled keys.) - - SOURCE is the context in which SEARCH_TERMS was specified, e.g., - "--encrypt-to", etc. If this function is called interactively, - then this should be NULL. - - If WARN_POSSIBLY_AMBIGUOUS is set, then emits a warning if the user - does not specify a long key id or a fingerprint. - - The results are placed in *KEYS. *KEYS must be NULL! */ + * + * This function also checks for and warns about duplicate entries in + * the keydb, which can occur if the user has configured multiple + * keyrings or keyboxes or if a keyring or keybox was corrupted. + * + * Note: SEARCH_TERMS will not be expanded (i.e., it may not be a + * group). + * + * USE is the operation for which the key is required. It must be + * either PUBKEY_USAGE_ENC, PUBKEY_USAGE_SIG, PUBKEY_USAGE_CERT or + * PUBKEY_USAGE_AUTH. + * + * INCLUDE_UNUSABLE indicates whether disabled keys are allowed. + * (Recipients specified with --encrypt-to and --hidden-encrypt-to may + * be disabled. It is possible to edit disabled keys.) + * + * SOURCE is the context in which SEARCH_TERMS was specified, e.g., + * "--encrypt-to", etc. If this function is called interactively, + * then this should be NULL. + * + * If WARN_POSSIBLY_AMBIGUOUS is set, then emits a warning if the user + * does not specify a long key id or a fingerprint. + * + * The results are placed in *KEYS. *KEYS must be NULL! + * + * Fixme: Currently, only PUBKEY_USAGE_ENC and PUBKEY_USAGE_SIG are + * implemented. */ gpg_error_t get_pubkeys (ctrl_t ctrl, char *search_terms, int use, int include_unusable, char *source, @@ -448,30 +449,23 @@ get_pubkeys (ctrl_t ctrl, pubkey_t *r_keys) { /* We show a warning when a key appears multiple times in the DB. - This can happen for two reasons: - - - The user has configured multiple keyrings or keyboxes. - - - The keyring or keybox has been corrupted in some way, e.g., a - bug or a random process changing them. - - For each duplicate, we only want to show the key once. Hence, - this list. */ + * This can happen for two reasons: + * + * - The user has configured multiple keyrings or keyboxes. + * + * - The keyring or keybox has been corrupted in some way, e.g., a + * bug or a random process changing them. + * + * For each duplicate, we only want to show the key once. Hence, + * this list. */ static strlist_t key_dups; - - /* USE transformed to a string. */ - char *use_str; - gpg_error_t err; - + char *use_str; /* USE transformed to a string. */ KEYDB_SEARCH_DESC desc; - GETKEY_CTX ctx; pubkey_t results = NULL; pubkey_t r; - int count; - char fingerprint[2 * MAX_FINGERPRINT_LEN + 1]; if (DBG_LOOKUP) @@ -533,17 +527,14 @@ get_pubkeys (ctrl_t ctrl, else err = getkey_next (ctrl, ctx, pk, &kb); - if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) - /* No more results. */ + if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) /* No more results. */ { xfree (pk); break; } - else if (err) - /* An error (other than "not found"). */ + else if (err) /* An error (other than "not found"). */ { - log_error (_("error looking up: %s\n"), - gpg_strerror (err)); + log_error (_("error looking up: %s\n"), gpg_strerror (err)); xfree (pk); break; } @@ -570,8 +561,7 @@ get_pubkeys (ctrl_t ctrl, } if (! results && gpg_err_code (err) == GPG_ERR_NOT_FOUND) - /* No match. */ - { + { /* No match. */ if (DBG_LOOKUP) log_debug ("%s: '%s' not found.\n", __func__, search_terms); @@ -582,12 +572,12 @@ get_pubkeys (ctrl_t ctrl, goto out; } else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) - /* No more matches. */ - ; + ; /* No more matches. */ else if (err) - /* Some other error. An error message was already printed - out. Free RESULTS and continue. */ - goto out; + { /* Some other error. An error message was already printed out. + * Free RESULTS and continue. */ + goto out; + } /* Check for duplicates. */ if (DBG_LOOKUP) @@ -607,8 +597,7 @@ get_pubkeys (ctrl_t ctrl, { if (cmp_public_keys (r->keyblock->pkt->pkt.public_key, r2->keyblock->pkt->pkt.public_key) != 0) - /* Not a dup. */ - { + { /* Not a dup. */ prevp = &r2->next; next = r2->next; continue; From 29119a6492eda5dd7920e45e7f2faa043d436591 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Dec 2017 10:06:37 +0100 Subject: [PATCH 09/17] gpg: Remove some xmallocs. * g10/getkey.c (get_pubkeys): Do not use xmalloc. -- We eventually need to get rid of all xmallocs so that gpg won't fail easily when we make more use of the s server mode. Signed-off-by: Werner Koch --- g10/getkey.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/g10/getkey.c b/g10/getkey.c index eaf15ade1..e31e0232e 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -497,7 +497,7 @@ get_pubkeys (ctrl_t ctrl, search_terms, gpg_strerror (err)); if (!opt.quiet && source) log_info (_("(check argument of option '%s')\n"), source); - goto out; + goto leave; } if (warn_possibly_ambiguous @@ -517,8 +517,16 @@ get_pubkeys (ctrl_t ctrl, count = 0; do { - PKT_public_key *pk = xmalloc_clear (sizeof *pk); + PKT_public_key *pk; KBNODE kb; + + pk = xtrycalloc (1, sizeof *pk); + if (!pk) + { + err = gpg_error_from_syserror (); + goto leave; + } + pk->req_usage = use; if (! ctx) @@ -542,7 +550,13 @@ get_pubkeys (ctrl_t ctrl, /* Another result! */ count ++; - r = xmalloc_clear (sizeof (*r)); + r = xtrycalloc (1, sizeof (*r)); + if (!r) + { + err = gpg_error_from_syserror (); + xfree (pk); + goto leave; + } r->pk = pk; r->keyblock = kb; r->next = results; @@ -569,14 +583,14 @@ get_pubkeys (ctrl_t ctrl, if (!opt.quiet && source) log_info (_("(check argument of option '%s')\n"), source); - goto out; + goto leave; } else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) ; /* No more matches. */ else if (err) { /* Some other error. An error message was already printed out. * Free RESULTS and continue. */ - goto out; + goto leave; } /* Check for duplicates. */ @@ -641,7 +655,7 @@ get_pubkeys (ctrl_t ctrl, fingerprint, sizeof fingerprint)); } - out: + leave: if (err) pubkeys_free (results); else @@ -712,8 +726,13 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid) /* More init stuff. */ if (!pk) { - pk = xmalloc_clear (sizeof *pk); internal++; + pk = xtrycalloc (1, sizeof *pk); + if (!pk) + { + rc = gpg_error_from_syserror (); + goto leave; + } } From cd26c5482b10bee7658959ae913f2ddb83190587 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Dec 2017 10:52:34 +0100 Subject: [PATCH 10/17] gpg: Return an error from hexfingerprint on malloc error. * g10/keyid.c (hexfingerprint): Return NULL on malloc failure. Chnage all callers. Signed-off-by: Werner Koch --- g10/export.c | 5 ++++ g10/keygen.c | 5 ++++ g10/keyid.c | 18 +++++++----- g10/revoke.c | 15 +++++++++- g10/tofu.c | 82 ++++++++++++++++++++++++++++++++++++---------------- 5 files changed, 92 insertions(+), 33 deletions(-) diff --git a/g10/export.c b/g10/export.c index 8f6371b30..c538dc1f1 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1430,6 +1430,11 @@ print_pka_or_dane_records (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk, char *hexfpr; hexfpr = hexfingerprint (pk, NULL, 0); + if (!hexfpr) + { + err = gpg_error_from_syserror (); + goto leave; + } hexdata = bin2hex (data, datalen, NULL); if (!hexdata) { diff --git a/g10/keygen.c b/g10/keygen.c index 7ef3cac1d..b42afa858 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -4484,6 +4484,11 @@ card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir) log_info (_("Note: backup of card key saved to '%s'\n"), fname); fprbuf = hexfingerprint (sk, NULL, 0); + if (!fprbuf) + { + err = gpg_error_from_syserror (); + goto leave; + } write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf, fname, strlen (fname), 0); xfree (fprbuf); diff --git a/g10/keyid.c b/g10/keyid.c index d733156f8..ba35ec21f 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -790,12 +790,12 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len) /* Return an allocated buffer with the fingerprint of PK formatted as - a plain hexstring. If BUFFER is NULL the result is a malloc'd - string. If BUFFER is not NULL the result will be copied into this - buffer. In the latter case BUFLEN describes the length of the - buffer; if this is too short the function terminates the process. - Returns a malloc'ed string or BUFFER. A suitable length for BUFFER - is (2*MAX_FINGERPRINT_LEN + 1). */ + * a plain hexstring. If BUFFER is NULL the result is a malloc'd + * string. If BUFFER is not NULL the result will be copied into this + * buffer. In the latter case BUFLEN describes the length of the + * buffer; if this is too short the function terminates the process. + * Returns a malloc'ed string or BUFFER. A suitable length for BUFFER + * is (2*MAX_FINGERPRINT_LEN + 1). */ char * hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen) { @@ -804,7 +804,11 @@ hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen) fingerprint_from_pk (pk, fpr, &len); if (!buffer) - buffer = xmalloc (2 * len + 1); + { + buffer = xtrymalloc (2 * len + 1); + if (!buffer) + return NULL; + } else if (buflen < 2*len+1) log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen); bin2hex (fpr, len, buffer); diff --git a/g10/revoke.c b/g10/revoke.c index 457870082..846523295 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -536,7 +536,20 @@ gen_standard_revoke (ctrl_t ctrl, PKT_public_key *psk, const char *cache_nonce) dir = get_openpgp_revocdir (gnupg_homedir ()); tmpstr = hexfingerprint (psk, NULL, 0); - fname = xstrconcat (dir, DIRSEP_S, tmpstr, NULL); + if (!tmpstr) + { + rc = gpg_error_from_syserror (); + xfree (dir); + return rc; + } + fname = strconcat (dir, DIRSEP_S, tmpstr, NULL); + if (!fname) + { + rc = gpg_error_from_syserror (); + xfree (tmpstr); + xfree (dir); + return rc; + } xfree (tmpstr); xfree (dir); diff --git a/g10/tofu.c b/g10/tofu.c index c183fc665..091d5b0d0 100644 --- a/g10/tofu.c +++ b/g10/tofu.c @@ -3332,8 +3332,8 @@ tofu_register_signature (ctrl_t ctrl, char *fingerprint = NULL; strlist_t user_id; char *email = NULL; - char *err = NULL; - char *sig_digest; + char *sqlerr = NULL; + char *sig_digest = NULL; unsigned long c; dbs = opendbs (ctrl); @@ -3354,11 +3354,20 @@ tofu_register_signature (ctrl_t ctrl, log_assert (pk_is_primary (pk)); sig_digest = make_radix64_string (sig_digest_bin, sig_digest_bin_len); + if (!sig_digest) + { + rc = gpg_error_from_syserror (); + goto leave; + } fingerprint = hexfingerprint (pk, NULL, 0); + if (!fingerprint) + { + rc = gpg_error_from_syserror (); + goto leave; + } if (! origin) - /* The default origin is simply "unknown". */ - origin = "unknown"; + origin = "unknown"; /* The default origin is simply "unknown". */ for (user_id = user_id_list; user_id; user_id = user_id->next) { @@ -3384,7 +3393,7 @@ tofu_register_signature (ctrl_t ctrl, it again. */ rc = gpgsql_stepx (dbs->db, &dbs->s.register_already_seen, - get_single_unsigned_long_cb2, &c, &err, + get_single_unsigned_long_cb2, &c, &sqlerr, "select count (*)\n" " from signatures left join bindings\n" " on signatures.binding = bindings.oid\n" @@ -3396,9 +3405,9 @@ tofu_register_signature (ctrl_t ctrl, GPGSQL_ARG_END); if (rc) { - log_error (_("error reading TOFU database: %s\n"), err); + log_error (_("error reading TOFU database: %s\n"), sqlerr); print_further_info ("checking existence"); - sqlite3_free (err); + sqlite3_free (sqlerr); rc = gpg_error (GPG_ERR_GENERAL); } else if (c > 1) @@ -3436,7 +3445,7 @@ tofu_register_signature (ctrl_t ctrl, log_assert (c == 0); rc = gpgsql_stepx - (dbs->db, &dbs->s.register_signature, NULL, NULL, &err, + (dbs->db, &dbs->s.register_signature, NULL, NULL, &sqlerr, "insert into signatures\n" " (binding, sig_digest, origin, sig_time, time)\n" " values\n" @@ -3450,9 +3459,9 @@ tofu_register_signature (ctrl_t ctrl, GPGSQL_ARG_END); if (rc) { - log_error (_("error updating TOFU database: %s\n"), err); + log_error (_("error updating TOFU database: %s\n"), sqlerr); print_further_info ("insert signatures"); - sqlite3_free (err); + sqlite3_free (sqlerr); rc = gpg_error (GPG_ERR_GENERAL); } } @@ -3463,6 +3472,7 @@ tofu_register_signature (ctrl_t ctrl, break; } + leave: if (rc) rollback_transaction (ctrl); else @@ -3486,7 +3496,8 @@ tofu_register_encryption (ctrl_t ctrl, int free_user_id_list = 0; char *fingerprint = NULL; strlist_t user_id; - char *err = NULL; + char *sqlerr = NULL; + int in_batch = 0; dbs = opendbs (ctrl); if (! dbs) @@ -3531,8 +3542,14 @@ tofu_register_encryption (ctrl_t ctrl, } fingerprint = hexfingerprint (pk, NULL, 0); + if (!fingerprint) + { + rc = gpg_error_from_syserror (); + goto leave; + } tofu_begin_batch_update (ctrl); + in_batch = 1; tofu_resume_batch_transaction (ctrl); for (user_id = user_id_list; user_id; user_id = user_id->next) @@ -3550,7 +3567,7 @@ tofu_register_encryption (ctrl_t ctrl, /* An error. */ rc = gpg_error (GPG_ERR_GENERAL); xfree (email); - goto die; + goto leave; } @@ -3576,7 +3593,7 @@ tofu_register_encryption (ctrl_t ctrl, free_strlist (conflict_set); rc = gpgsql_stepx - (dbs->db, &dbs->s.register_encryption, NULL, NULL, &err, + (dbs->db, &dbs->s.register_encryption, NULL, NULL, &sqlerr, "insert into encryptions\n" " (binding, time)\n" " values\n" @@ -3588,24 +3605,22 @@ tofu_register_encryption (ctrl_t ctrl, GPGSQL_ARG_END); if (rc) { - log_error (_("error updating TOFU database: %s\n"), err); + log_error (_("error updating TOFU database: %s\n"), sqlerr); print_further_info ("insert encryption"); - sqlite3_free (err); + sqlite3_free (sqlerr); rc = gpg_error (GPG_ERR_GENERAL); } xfree (email); } - die: - tofu_end_batch_update (ctrl); - - if (kb) - release_kbnode (kb); + leave: + if (in_batch) + tofu_end_batch_update (ctrl); + release_kbnode (kb); if (free_user_id_list) free_strlist (user_id_list); - xfree (fingerprint); return rc; @@ -3681,10 +3696,10 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, const char *user_id) { time_t now = gnupg_get_time (); - gpg_error_t err; + gpg_error_t err = 0; tofu_dbs_t dbs; char *fingerprint; - char *email; + char *email = NULL; enum tofu_policy policy; if (!*user_id) @@ -3699,14 +3714,20 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp, } fingerprint = hexfingerprint (pk, NULL, 0); + if (!fingerprint) + { + err = gpg_error_from_syserror (); + goto leave; + } email = email_from_user_id (user_id); policy = get_policy (ctrl, dbs, pk, fingerprint, user_id, email, NULL, now); show_statistics (dbs, fingerprint, email, policy, fp, 0, now); + leave: xfree (email); xfree (fingerprint); - return 0; + return err; } @@ -3720,7 +3741,10 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp, will be prompted to choose a policy. If MAY_ASK is 0 and the policy is TOFU_POLICY_ASK, then TRUST_UNKNOWN is returned. - Returns TRUST_UNDEFINED if an error occurs. */ + Returns TRUST_UNDEFINED if an error occurs. + + Fixme: eturn an error code + */ int tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list, int may_ask) @@ -3744,6 +3768,8 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list, } fingerprint = hexfingerprint (pk, NULL, 0); + if (!fingerprint) + log_fatal ("%s: malloc failed\n", __func__); tofu_begin_batch_update (ctrl); /* Start the batch transaction now. */ @@ -3889,6 +3915,8 @@ tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy) log_bug ("%s: Passed a subkey, but expecting a primary key.\n", __func__); fingerprint = hexfingerprint (pk, NULL, 0); + if (!fingerprint) + return gpg_error_from_syserror (); begin_transaction (ctrl, 0); @@ -3958,6 +3986,8 @@ tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id, } fingerprint = hexfingerprint (pk, NULL, 0); + if (!fingerprint) + return gpg_error_from_syserror (); email = email_from_user_id (user_id->name); @@ -3994,6 +4024,8 @@ tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb) } fingerprint = hexfingerprint (pk, NULL, 0); + if (!fingerprint) + return gpg_error_from_syserror (); rc = gpgsql_stepx (dbs->db, NULL, NULL, NULL, &sqlerr, "update bindings set effective_policy = ?" From 9f641430dcdecbd7ee205d407cb19bb4262aa95d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Dec 2017 11:00:24 +0100 Subject: [PATCH 11/17] gpg: Simplify default_recipient(). * g10/pkclist.c (default_recipient): Use hexfingerprint. -- Note that on malloc failure this function now returns NULL instead of terminating the process. However, under memory pressure any function called latter will very likely fail as well. Signed-off-by: Werner Koch --- g10/pkclist.c | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/g10/pkclist.c b/g10/pkclist.c index 220936c56..581cae407 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -730,40 +730,35 @@ key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk) } -/**************** +/* * Return a malloced string with a default recipient if there is any + * Fixme: We don't distinguish between malloc failure and no-default-recipient. */ static char * -default_recipient(ctrl_t ctrl) +default_recipient (ctrl_t ctrl) { - PKT_public_key *pk; - byte fpr[MAX_FINGERPRINT_LEN+1]; - size_t n; - char *p; - int i; + PKT_public_key *pk; + char *result; - if( opt.def_recipient ) - return xstrdup( opt.def_recipient ); - if( !opt.def_recipient_self ) - return NULL; - pk = xmalloc_clear( sizeof *pk ); - i = get_seckey_default (ctrl, pk); - if( i ) { - free_public_key( pk ); - return NULL; + if (opt.def_recipient) + return xtrystrdup (opt.def_recipient); + + if (!opt.def_recipient_self) + return NULL; + pk = xtrycalloc (1, sizeof *pk ); + if (!pk) + return NULL; + if (get_seckey_default (ctrl, pk)) + { + free_public_key (pk); + return NULL; } - n = MAX_FINGERPRINT_LEN; - fingerprint_from_pk( pk, fpr, &n ); - free_public_key( pk ); - p = xmalloc( 2*n+3 ); - *p++ = '0'; - *p++ = 'x'; - for(i=0; i < n; i++ ) - sprintf( p+2*i, "%02X", fpr[i] ); - p -= 2; - return p; + result = hexfingerprint (pk, NULL, 0); + free_public_key (pk); + return result; } + static int expand_id(const char *id,strlist_t *into,unsigned int flags) { From 067e62fe55721cac47c931f01fdb7c1563a64e9c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Dec 2017 11:56:28 +0100 Subject: [PATCH 12/17] indent: Re-indent g10/cipher.c -- --- g10/cipher.c | 210 ++++++++++++++++++++++++++------------------------- 1 file changed, 108 insertions(+), 102 deletions(-) diff --git a/g10/cipher.c b/g10/cipher.c index 655937f07..26779892e 100644 --- a/g10/cipher.c +++ b/g10/cipher.c @@ -1,6 +1,6 @@ /* cipher.c - En-/De-ciphering filter - * Copyright (C) 1998, 1999, 2000, 2001, 2003, - * 2006, 2009 Free Software Foundation, Inc. + * Copyright (C) 1998-2003, 2006, 2009 Free Software Foundation, Inc. + * Copyright (C) 1998-2003, 2006, 2009, 2017 Werner koch * * This file is part of GnuPG. * @@ -16,6 +16,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * SPDX-License-Identifier: GPL-3.0+ */ #include @@ -39,124 +40,129 @@ static void -write_header( cipher_filter_context_t *cfx, IOBUF a ) +write_header (cipher_filter_context_t *cfx, iobuf_t a) { - gcry_error_t err; - PACKET pkt; - PKT_encrypted ed; - byte temp[18]; - unsigned int blocksize; - unsigned int nprefix; + gcry_error_t err; + PACKET pkt; + PKT_encrypted ed; + byte temp[18]; + unsigned int blocksize; + unsigned int nprefix; - blocksize = openpgp_cipher_get_algo_blklen (cfx->dek->algo); - if ( blocksize < 8 || blocksize > 16 ) - log_fatal("unsupported blocksize %u\n", blocksize ); - - memset( &ed, 0, sizeof ed ); - ed.len = cfx->datalen; - ed.extralen = blocksize+2; - ed.new_ctb = !ed.len; - if( cfx->dek->use_mdc ) { - ed.mdc_method = DIGEST_ALGO_SHA1; - gcry_md_open (&cfx->mdc_hash, DIGEST_ALGO_SHA1, 0); - if ( DBG_HASHING ) - gcry_md_debug (cfx->mdc_hash, "creatmdc"); - } + blocksize = openpgp_cipher_get_algo_blklen (cfx->dek->algo); + if ( blocksize < 8 || blocksize > 16 ) + log_fatal ("unsupported blocksize %u\n", blocksize); + memset (&ed, 0, sizeof ed); + ed.len = cfx->datalen; + ed.extralen = blocksize + 2; + ed.new_ctb = !ed.len; + if (cfx->dek->use_mdc) { - char buf[20]; - - sprintf (buf, "%d %d", ed.mdc_method, cfx->dek->algo); - write_status_text (STATUS_BEGIN_ENCRYPTION, buf); + ed.mdc_method = DIGEST_ALGO_SHA1; + gcry_md_open (&cfx->mdc_hash, DIGEST_ALGO_SHA1, 0); + if (DBG_HASHING) + gcry_md_debug (cfx->mdc_hash, "creatmdc"); } - init_packet( &pkt ); - pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED; - pkt.pkt.encrypted = &ed; - if( build_packet( a, &pkt )) - log_bug("build_packet(ENCR_DATA) failed\n"); - nprefix = blocksize; - gcry_randomize (temp, nprefix, GCRY_STRONG_RANDOM ); - temp[nprefix] = temp[nprefix-2]; - temp[nprefix+1] = temp[nprefix-1]; - print_cipher_algo_note( cfx->dek->algo ); - err = openpgp_cipher_open (&cfx->cipher_hd, - cfx->dek->algo, - GCRY_CIPHER_MODE_CFB, - (GCRY_CIPHER_SECURE - | ((cfx->dek->use_mdc || cfx->dek->algo >= 100)? - 0 : GCRY_CIPHER_ENABLE_SYNC))); - if (err) { - /* We should never get an error here cause we already checked, - * that the algorithm is available. */ - BUG(); + { + char buf[20]; + + snprintf (buf, sizeof buf, "%d %d", ed.mdc_method, cfx->dek->algo); + write_status_text (STATUS_BEGIN_ENCRYPTION, buf); + } + + init_packet (&pkt); + pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED; + pkt.pkt.encrypted = &ed; + if (build_packet( a, &pkt)) + log_bug ("build_packet(ENCR_DATA) failed\n"); + nprefix = blocksize; + gcry_randomize (temp, nprefix, GCRY_STRONG_RANDOM ); + temp[nprefix] = temp[nprefix-2]; + temp[nprefix+1] = temp[nprefix-1]; + print_cipher_algo_note (cfx->dek->algo); + err = openpgp_cipher_open (&cfx->cipher_hd, + cfx->dek->algo, + GCRY_CIPHER_MODE_CFB, + (GCRY_CIPHER_SECURE + | ((cfx->dek->use_mdc || cfx->dek->algo >= 100)? + 0 : GCRY_CIPHER_ENABLE_SYNC))); + if (err) + { + /* We should never get an error here cause we already checked, + * that the algorithm is available. */ + BUG(); } -/* log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/ - gcry_cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen ); - gcry_cipher_setiv( cfx->cipher_hd, NULL, 0 ); -/* log_hexdump( "prefix", temp, nprefix+2 ); */ - if (cfx->mdc_hash) /* Hash the "IV". */ - gcry_md_write (cfx->mdc_hash, temp, nprefix+2 ); - gcry_cipher_encrypt (cfx->cipher_hd, temp, nprefix+2, NULL, 0); - gcry_cipher_sync (cfx->cipher_hd); - iobuf_write(a, temp, nprefix+2); - cfx->header=1; + /* log_hexdump ("thekey", cfx->dek->key, cfx->dek->keylen); */ + gcry_cipher_setkey (cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen); + gcry_cipher_setiv (cfx->cipher_hd, NULL, 0); + /* log_hexdump ("prefix", temp, nprefix+2); */ + if (cfx->mdc_hash) /* Hash the "IV". */ + gcry_md_write (cfx->mdc_hash, temp, nprefix+2 ); + gcry_cipher_encrypt (cfx->cipher_hd, temp, nprefix+2, NULL, 0); + gcry_cipher_sync (cfx->cipher_hd); + iobuf_write (a, temp, nprefix+2); + cfx->header = 1; } - -/**************** - * This filter is used to en/de-cipher data with a conventional algorithm +/* + * This filter is used to en/de-cipher data with a symmetric algorithm */ int -cipher_filter( void *opaque, int control, - IOBUF a, byte *buf, size_t *ret_len) +cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len) { - size_t size = *ret_len; - cipher_filter_context_t *cfx = opaque; - int rc=0; + cipher_filter_context_t *cfx = opaque; + size_t size = *ret_len; + int rc = 0; - if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */ - rc = -1; /* not yet used */ + if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */ + { + rc = -1; /* not yet used */ } - else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */ - log_assert(a); - if( !cfx->header ) { - write_header( cfx, a ); + else if (control == IOBUFCTRL_FLUSH) /* encrypt */ + { + log_assert (a); + if (!cfx->header) + write_header (cfx, a); + if (cfx->mdc_hash) + gcry_md_write (cfx->mdc_hash, buf, size); + gcry_cipher_encrypt (cfx->cipher_hd, buf, size, NULL, 0); + rc = iobuf_write (a, buf, size); + } + else if (control == IOBUFCTRL_FREE) + { + if (cfx->mdc_hash) + { + byte *hash; + int hashlen = gcry_md_get_algo_dlen (gcry_md_get_algo(cfx->mdc_hash)); + byte temp[22]; + + log_assert (hashlen == 20); + /* We must hash the prefix of the MDC packet here. */ + temp[0] = 0xd3; + temp[1] = 0x14; + gcry_md_putc (cfx->mdc_hash, temp[0]); + gcry_md_putc (cfx->mdc_hash, temp[1]); + + gcry_md_final (cfx->mdc_hash); + hash = gcry_md_read (cfx->mdc_hash, 0); + memcpy(temp+2, hash, 20); + gcry_cipher_encrypt (cfx->cipher_hd, temp, 22, NULL, 0); + gcry_md_close (cfx->mdc_hash); cfx->mdc_hash = NULL; + if (iobuf_write( a, temp, 22)) + log_error ("writing MDC packet failed\n"); } - if (cfx->mdc_hash) - gcry_md_write (cfx->mdc_hash, buf, size); - gcry_cipher_encrypt (cfx->cipher_hd, buf, size, NULL, 0); - rc = iobuf_write( a, buf, size ); - } - else if( control == IOBUFCTRL_FREE ) { - if( cfx->mdc_hash ) { - byte *hash; - int hashlen = gcry_md_get_algo_dlen (gcry_md_get_algo - (cfx->mdc_hash)); - byte temp[22]; - log_assert( hashlen == 20 ); - /* We must hash the prefix of the MDC packet here. */ - temp[0] = 0xd3; - temp[1] = 0x14; - gcry_md_putc (cfx->mdc_hash, temp[0]); - gcry_md_putc (cfx->mdc_hash, temp[1]); + gcry_cipher_close (cfx->cipher_hd); + } + else if (control == IOBUFCTRL_DESC) + { + mem2str (buf, "cipher_filter", *ret_len); + } - gcry_md_final (cfx->mdc_hash); - hash = gcry_md_read (cfx->mdc_hash, 0); - memcpy(temp+2, hash, 20); - gcry_cipher_encrypt (cfx->cipher_hd, temp, 22, NULL, 0); - gcry_md_close (cfx->mdc_hash); cfx->mdc_hash = NULL; - if( iobuf_write( a, temp, 22 ) ) - log_error("writing MDC packet failed\n" ); - } - gcry_cipher_close (cfx->cipher_hd); - } - else if( control == IOBUFCTRL_DESC ) { - mem2str (buf, "cipher_filter", *ret_len); - } - return rc; + return rc; } From b5333e13cbc9db354ed90762190bf70605a02d1f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Dec 2017 11:58:51 +0100 Subject: [PATCH 13/17] gpg: Simplify cipher:write_header. * g10/cipher.c (write_header): Use write_status_printf. Signed-off-by: Werner Koch --- g10/cipher.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/g10/cipher.c b/g10/cipher.c index 26779892e..409d0adef 100644 --- a/g10/cipher.c +++ b/g10/cipher.c @@ -65,12 +65,8 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a) gcry_md_debug (cfx->mdc_hash, "creatmdc"); } - { - char buf[20]; - - snprintf (buf, sizeof buf, "%d %d", ed.mdc_method, cfx->dek->algo); - write_status_text (STATUS_BEGIN_ENCRYPTION, buf); - } + write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d", + ed.mdc_method, cfx->dek->algo); init_packet (&pkt); pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED; From 416cf9e9be5d2daf0ef629208031989699b3653f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 13 Dec 2017 13:02:34 +0100 Subject: [PATCH 14/17] gpg: Print a warning for too much data encrypted with 3DES et al. * g10/filter.h (cipher_filter_context_t): Remove unused filed 'create_mdc'. Turn field 'header' into a bit field. Add new fields 'short_blklen_warn' and 'short_blklen_count'. * g10/cipher.c (write_header): Print a warning if MDC is not used. (cipher_filter): Print a warning for long messages encrypted with a short block length algorithm. -- Note that to test this warning in a reliable way compression needs to be disabled. Signed-off-by: Werner Koch --- g10/cipher.c | 26 +++++++++++++++++++++++--- g10/filter.h | 5 +++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/g10/cipher.c b/g10/cipher.c index 409d0adef..b950d0c3f 100644 --- a/g10/cipher.c +++ b/g10/cipher.c @@ -64,6 +64,11 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a) if (DBG_HASHING) gcry_md_debug (cfx->mdc_hash, "creatmdc"); } + else if (!opt.no_mdc_warn) + { + log_info ("WARNING: " + "encrypting without integrity protection is dangerous\n"); + } write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d", ed.mdc_method, cfx->dek->algo); @@ -91,7 +96,6 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a) BUG(); } - /* log_hexdump ("thekey", cfx->dek->key, cfx->dek->keylen); */ gcry_cipher_setkey (cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen); gcry_cipher_setiv (cfx->cipher_hd, NULL, 0); @@ -101,7 +105,11 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a) gcry_cipher_encrypt (cfx->cipher_hd, temp, nprefix+2, NULL, 0); gcry_cipher_sync (cfx->cipher_hd); iobuf_write (a, temp, nprefix+2); - cfx->header = 1; + + cfx->short_blklen_warn = (blocksize < 16); + cfx->short_blklen_count = nprefix+2; + + cfx->wrote_header = 1; } @@ -122,11 +130,23 @@ cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len) else if (control == IOBUFCTRL_FLUSH) /* encrypt */ { log_assert (a); - if (!cfx->header) + if (!cfx->wrote_header) write_header (cfx, a); if (cfx->mdc_hash) gcry_md_write (cfx->mdc_hash, buf, size); gcry_cipher_encrypt (cfx->cipher_hd, buf, size, NULL, 0); + if (cfx->short_blklen_warn) + { + cfx->short_blklen_count += size; + if (cfx->short_blklen_count > (150 * 1024 * 1024)) + { + log_info ("WARNING: encrypting more than %d MiB with algorithm " + "%s should be avoided\n", 150, + openpgp_cipher_algo_name (cfx->dek->algo)); + cfx->short_blklen_warn = 0; /* Don't show again. */ + } + } + rc = iobuf_write (a, buf, size); } else if (control == IOBUFCTRL_FREE) diff --git a/g10/filter.h b/g10/filter.h index 275608d4a..9e4b1e538 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -92,10 +92,11 @@ typedef struct { DEK *dek; u32 datalen; gcry_cipher_hd_t cipher_hd; - int header; + unsigned int wrote_header : 1; + unsigned int short_blklen_warn : 1; + unsigned long short_blklen_count; gcry_md_hd_t mdc_hash; byte enchash[20]; - int create_mdc; /* flag will be set by the cipher filter */ } cipher_filter_context_t; From e3ddeff66e8c08a37ddf8b6510d69579c245e192 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 18 Dec 2017 14:09:53 +0900 Subject: [PATCH 15/17] po: Update Japanese translation. * po/ja.po: Fix message with no "%s". -- Backport of master commit from: 77e2fcb4ffbad8577a2cf41f17bf92dec6a93ad8 The wrong message caused segmentation fault for key generation when no expiration is specified. GnuPG-bug-id: 3619 Signed-off-by: NIIBE Yutaka --- po/ja.po | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/po/ja.po b/po/ja.po index 26c032f4a..a3e8ab86b 100644 --- a/po/ja.po +++ b/po/ja.po @@ -8,9 +8,9 @@ # msgid "" msgstr "" -"Project-Id-Version: gnupg 2.2.2\n" +"Project-Id-Version: gnupg 2.2.3\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2017-11-07 11:11+0900\n" +"PO-Revision-Date: 2017-12-18 14:07+0900\n" "Last-Translator: NIIBE Yutaka \n" "Language-Team: none\n" "Language: ja\n" @@ -1340,10 +1340,9 @@ msgstr "暗号化鍵の鍵長は? (%u) " msgid "What keysize do you want for the Authentication key? (%u) " msgstr "認証鍵の鍵長は? (%u) " -#, fuzzy, c-format -#| msgid "The card will now be re-configured to generate a key of %u bits\n" +#, c-format msgid "The card will now be re-configured to generate a key of type: %s\n" -msgstr "今、%uビットの鍵を生成するようにカードは再コンフィグされました\n" +msgstr "カードは、今、こちらのタイプの鍵を生成するように再コンフィグされました: %s\n" #, c-format msgid "rounded up to %u bits\n" @@ -3775,10 +3774,10 @@ msgid "invalid value\n" msgstr "無効な値\n" msgid "Key does not expire at all\n" -msgstr "%sは無期限です\n" +msgstr "鍵は無期限です\n" msgid "Signature does not expire at all\n" -msgstr "%署名は無期限です\n" +msgstr "署名は無期限です\n" #, c-format msgid "Key expires at %s\n" From 8c878ae4c9dfa9fe26aa15f4f9db3e86833575e9 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Dec 2017 12:05:02 +0100 Subject: [PATCH 16/17] sm: Allow explicit setting of the default --compliance=gnupg * sm/gpgsm.c (main): Allow setting of the default compliance. * tools/gpgconf-comp.c (gc_options_gpgsm): Add "compliance". -- This is required so that we can use this option in in gpgconf.conf. Signed-off-by: Werner Koch --- doc/examples/gpgconf.conf | 7 +++---- sm/gpgsm.c | 2 ++ tools/gpgconf-comp.c | 3 +++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/examples/gpgconf.conf b/doc/examples/gpgconf.conf index f40160249..95e463b6e 100644 --- a/doc/examples/gpgconf.conf +++ b/doc/examples/gpgconf.conf @@ -31,8 +31,7 @@ # # Example file: #========== -# :staff gpg-agent allow-mark-trusted [change] -# gpg-agent min-passphrase-len 6 +# :staff gpg-agent min-passphrase-len 6 [change] # # * gpg-agent min-passphrase-len [no-change] 8 # gpg-agent min-passphrase-nonalpha [no-change] 1 @@ -42,9 +41,9 @@ # gpg-agent enforce-passphrase-constraints [no-change] # gpg-agent max-cache-ttl [no-change] 10800 # gpg-agent max-cache-ttl-ssh [no-change] 10800 -# gpg-agent allow-mark-trusted [default] -# gpg-agent allow-mark-trusted [no-change] # gpgsm enable-ocsp +# gpg compliance [no-change] +# gpgsm compliance [no-change] #=========== # All users in the group "staff" are allowed to change the value for # --allow-mark-trusted; gpgconf's default is not to allow a change diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 0feda90b1..b505be154 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1450,6 +1450,7 @@ main ( int argc, char **argv) { struct gnupg_compliance_option compliance_options[] = { + { "gnupg", CO_GNUPG }, { "de-vs", CO_DE_VS } }; int compliance = gnupg_parse_compliance_option (pargs.r.ret_str, @@ -1786,6 +1787,7 @@ main ( int argc, char **argv) proc_parameters actually implements. */ es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "RSA-2048"); + es_printf ("compliance:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "gnupg"); } break; diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 9ce752b18..dd562d256 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -833,6 +833,9 @@ static gc_option_t gc_options_gpgsm[] = (GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_NO_CHANGE), GC_LEVEL_INVISIBLE, NULL, NULL, GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM }, + { "compliance", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, + NULL, NULL, + GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM }, { "Debug", GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED, From d74c40cef0a97cd98aa05f13b1541a94eda502a6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 18 Dec 2017 16:31:54 +0100 Subject: [PATCH 17/17] gpgconf: Show --compliance in expert mode. * tools/gpgconf-comp.c (gc_options_gpg): Set compliance to expert. (gc_options_gpgsm): Ditto. Signed-off-by: Werner Koch --- tools/gpgconf-comp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index dd562d256..b74ee04fd 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -714,7 +714,7 @@ static gc_option_t gc_options_gpg[] = { "options", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, NULL, NULL, GC_ARG_TYPE_FILENAME, GC_BACKEND_GPG }, - { "compliance", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, + { "compliance", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT, NULL, NULL, GC_ARG_TYPE_STRING, GC_BACKEND_GPG }, { "default-new-key-algo", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, @@ -833,7 +833,7 @@ static gc_option_t gc_options_gpgsm[] = (GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_NO_CHANGE), GC_LEVEL_INVISIBLE, NULL, NULL, GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM }, - { "compliance", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, + { "compliance", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT, NULL, NULL, GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },