diff options
-rw-r--r-- | dirmngr/dirmngr.c | 7 | ||||
-rw-r--r-- | dirmngr/dirmngr.h | 2 | ||||
-rw-r--r-- | dirmngr/server.c | 144 | ||||
-rw-r--r-- | doc/dirmngr.texi | 5 | ||||
-rw-r--r-- | g10/dirmngr-conf.skel | 5 |
5 files changed, 132 insertions, 31 deletions
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index ccefc3c06..97d2e15e6 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -541,8 +541,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) } FREE_STRLIST (opt.ignored_cert_extensions); http_register_tls_ca (NULL); - xfree (opt.keyserver); - opt.keyserver = NULL; + FREE_STRLIST (opt.keyserver); /* Note: We do not allow resetting of opt.use_tor at runtime. */ return 1; } @@ -622,8 +621,8 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) case oUseTor: opt.use_tor = 1; break; case oKeyServer: - xfree (opt.keyserver); - opt.keyserver = *pargs->r.ret_str? xtrystrdup (pargs->r.ret_str) : NULL; + if (*pargs->r.ret_str) + add_to_strlist (&opt.keyserver, pargs->r.ret_str); break; case oNameServer: diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index b2b14cc4f..60788842b 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -131,7 +131,7 @@ struct unsigned int ocsp_current_period; /* Seconds a response is considered current after nextUpdate. */ - char *keyserver; /* Malloced string with the default keyserver. */ + strlist_t keyserver; /* List of default keyservers. */ } opt; diff --git a/dirmngr/server.c b/dirmngr/server.c index 32c265b18..21cb2dc1e 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -91,6 +91,9 @@ struct server_local_s /* If this flag is set to true this dirmngr process will be terminated after the end of this session. */ int stopme; + + /* State variable private to is_tor_running. */ + int tor_state; }; @@ -120,6 +123,18 @@ get_ldapservers_from_ctrl (ctrl_t ctrl) return NULL; } +/* Release an uri_item_t list. */ +static void +release_uri_item_list (uri_item_t list) +{ + while (list) + { + uri_item_t tmp = list->next; + http_release_parsed_uri (list->parsed_uri); + xfree (list); + list = tmp; + } +} /* Release all configured keyserver info from CTRL. */ void @@ -128,13 +143,8 @@ release_ctrl_keyservers (ctrl_t ctrl) if (! ctrl->server_local) return; - while (ctrl->server_local->keyservers) - { - uri_item_t tmp = ctrl->server_local->keyservers->next; - http_release_parsed_uri (ctrl->server_local->keyservers->parsed_uri); - xfree (ctrl->server_local->keyservers); - ctrl->server_local->keyservers = tmp; - } + release_uri_item_list (ctrl->server_local->keyservers); + ctrl->server_local->keyservers = NULL; } @@ -335,6 +345,38 @@ skip_options (char *line) } +/* This fucntion returns true if a Tor server is running. The sattus + is cached for the current conenction. */ +static int +is_tor_running (ctrl_t ctrl) +{ +#if ASSUAN_VERSION_NUMBER >= 0x020402 + /* Check whether we can connect to the proxy. We use a + special feature introduced with libassuan 2.4.2. */ + + if (!ctrl || !ctrl->server_local) + return 0; /* Ooops. */ + + if (!ctrl->server_local->tor_state) + { + assuan_fd_t sock; + + sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, ASSUAN_SOCK_TOR); + if (sock == ASSUAN_INVALID_FD) + ctrl->server_local->tor_state = -1; /* Not running. */ + else + { + assuan_sock_close (sock); + ctrl->server_local->tor_state = 1; /* Running. */ + } + } + return (ctrl->server_local->tor_state > 0); +#else /* Libassuan < 2.4.2 */ + return 0; /* We don't know. */ +#endif +} + + /* Return an error if the assuan context does not belong to the owner of the process or to root. On error FAILTEXT is set as Assuan error string. */ @@ -1710,15 +1752,74 @@ ensure_keyserver (ctrl_t ctrl) { gpg_error_t err; uri_item_t item; + uri_item_t onion_items = NULL; + uri_item_t plain_items = NULL; + uri_item_t ui; + strlist_t sl; if (ctrl->server_local->keyservers) return 0; /* Already set for this session. */ if (!opt.keyserver) return 0; /* No global option set. */ - err = make_keyserver_item (opt.keyserver, &item); - if (!err) - ctrl->server_local->keyservers = item; + for (sl = opt.keyserver; sl; sl = sl->next) + { + err = make_keyserver_item (sl->d, &item); + if (err) + goto leave; + if (item->parsed_uri->onion) + { + item->next = onion_items; + onion_items = item; + } + else + { + item->next = plain_items; + plain_items = item; + } + } + + /* Decide which to use. Note that the sesssion has no keyservers + yet set. */ + if (onion_items && !onion_items->next && plain_items && !plain_items->next) + { + /* If there is just one onion and one plain keyserver given, we take + only one depending on whether Tor is running or not. */ + if (is_tor_running (ctrl)) + { + ctrl->server_local->keyservers = onion_items; + onion_items = NULL; + } + else + { + ctrl->server_local->keyservers = plain_items; + plain_items = NULL; + } + } + else if (!is_tor_running (ctrl)) + { + /* Tor is not running. It does not make sense to add Onion + addresses. */ + ctrl->server_local->keyservers = plain_items; + plain_items = NULL; + } + else + { + /* In all other cases add all keyservers. */ + ctrl->server_local->keyservers = onion_items; + onion_items = NULL; + for (ui = ctrl->server_local->keyservers; ui && ui->next; ui = ui->next) + ; + if (ui) + ui->next = plain_items; + else + ctrl->server_local->keyservers = plain_items; + plain_items = NULL; + } + + leave: + release_uri_item_list (onion_items); + release_uri_item_list (plain_items); return err; } @@ -2093,6 +2194,7 @@ static const char hlp_getinfo[] = static gpg_error_t cmd_getinfo (assuan_context_t ctx, char *line) { + ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err; if (!strcmp (line, "version")) @@ -2123,24 +2225,11 @@ cmd_getinfo (assuan_context_t ctx, char *line) { if (opt.use_tor) { -#if ASSUAN_VERSION_NUMBER >= 0x020402 - /* Check whether we can connect to the proxy. We use a - special feature introduced with libassuan 2.4.2. */ - assuan_fd_t sock = assuan_sock_connect_byname (NULL, 0, 0, NULL, - ASSUAN_SOCK_TOR); - if (sock == ASSUAN_INVALID_FD) - { - err = assuan_write_status - (ctx, "NO_TOR", - errno == ECONNREFUSED? "Tor not running" : strerror (errno)); - } + if (!is_tor_running (ctrl)) + err = assuan_write_status (ctx, "NO_TOR", "Tor not running"); else - { - assuan_sock_close (sock); - err = 0; - } + err = 0; if (!err) -#endif /* Libassuan >= 2.4.2 */ assuan_set_okay_line (ctx, "- Tor mode is enabled"); } else @@ -2398,6 +2487,7 @@ start_command_handler (assuan_fd_t fd) } } + #if USE_LDAP ldap_wrapper_connection_cleanup (ctrl); @@ -2405,6 +2495,8 @@ start_command_handler (assuan_fd_t fd) #endif /*USE_LDAP*/ ctrl->server_local->ldapservers = NULL; + release_ctrl_keyservers (ctrl); + ctrl->server_local->assuan_ctx = NULL; assuan_release (ctx); diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi index 6a4d6d6c4..5b73d7b4d 100644 --- a/doc/dirmngr.texi +++ b/doc/dirmngr.texi @@ -263,6 +263,11 @@ need to send keys to more than one server. The keyserver @code{hkp://keys.gnupg.net} uses round robin DNS to give a different keyserver each time you use it. +If exactly two keyservers are configured and only one is a Tor hidden +service (.onion), Dirmngr selects the keyserver to use depending on +whether Tor is locally running or not. The check for a running Tor is +done for each new connection. + @item --nameserver @var{ipaddr} @opindex nameserver diff --git a/g10/dirmngr-conf.skel b/g10/dirmngr-conf.skel index 2ba5e4dac..d5a02d949 100644 --- a/g10/dirmngr-conf.skel +++ b/g10/dirmngr-conf.skel @@ -49,7 +49,12 @@ # servers via DNS round-robin. hkp://keys.gnupg.net is an example of # such a "server", which spreads the load over a number of physical # servers. +# +# If exactly two keyservers are configured and only one is a Tor hidden +# service, Dirmngr selects the keyserver to use depending on whether +# Tor is locally running or not (on a per session base). +keyserver hkp://dyh2j3qyrirn43iw.onion keyserver hkp://keys.gnupg.net # --hkp-cacert FILENAME |