From 929b7da88002579bf8028cd36201bf4d175e68df Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 11 Jun 2012 00:52:08 +0100 Subject: [PATCH] GnuTLS: Cache token PIN Otherwise we get prompted for it about four times in the course of a single connection, which is going to make users unhappy. GnuTLS has been fixed not to do it on decent tokens that can have more than one active session, but on the crap tokens it's still needed. Signed-off-by: David Woodhouse --- gnutls.c | 45 +++++++++++++++++++++++++++++++++++++++--- openconnect-internal.h | 7 +++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/gnutls.c b/gnutls.c index c1225969..06a274d9 100644 --- a/gnutls.c +++ b/gnutls.c @@ -1261,6 +1261,16 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final) sprintf(pin_source, "openconnect:%p", vpninfo); p11_kit_pin_unregister_callback(pin_source, pin_callback, vpninfo); + + while (vpninfo->pin_cache) { + struct pin_cache *cache = vpninfo->pin_cache; + + free(cache->token); + memset(cache->pin, 0x5a, strlen(cache->pin)); + free(cache->pin); + vpninfo->pin_cache = cache->next; + free(cache); + } } #endif } @@ -1316,15 +1326,43 @@ static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri, void *_vpninfo) { struct openconnect_info *vpninfo = _vpninfo; + struct pin_cache **cache = &vpninfo->pin_cache; struct oc_auth_form f; struct oc_form_opt o; char message[1024]; + char *uri; P11KitPin *pin; int ret; if (!vpninfo || !vpninfo->process_auth_form) return NULL; + if (p11_kit_uri_format(pin_uri, P11_KIT_URI_FOR_TOKEN, &uri)) + return NULL; + + while (*cache) { + if (!strcmp(uri, (*cache)->token)) { + free(uri); + uri = NULL; + if ((*cache)->pin) { + if ((flags & P11_KIT_PIN_FLAGS_RETRY) != P11_KIT_PIN_FLAGS_RETRY) + return p11_kit_pin_new_for_string((*cache)->pin); + memset((*cache)->pin, 0x5a, strlen((*cache)->pin)); + free((*cache)->pin); + (*cache)->pin = NULL; + } + break; + } + } + if (!*cache) { + *cache = calloc(1, sizeof(struct pin_cache)); + if (!*cache) { + free(uri); + return NULL; + } + (*cache)->token = uri; + } + memset(&f, 0, sizeof(f)); f.auth_id = (char *)"pkcs11_pin"; f.opts = &o; @@ -1334,9 +1372,10 @@ static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri, f.message = message; /* - * p11-kit flags are *odd*. + * In p11-kit <= 0.12, these flags are *odd*. * RETRY is 0xa, FINAL_TRY is 0x14 and MANY_TRIES is 0x28. - * So don't treat it like a sane bitmask. + * So don't treat it like a sane bitmask. Fixed in + * http://cgit.freedesktop.org/p11-glue/p11-kit/commit/?id=59774b11 */ if ((flags & P11_KIT_PIN_FLAGS_RETRY) == P11_KIT_PIN_FLAGS_RETRY) f.error = _("Wrong PIN"); @@ -1357,7 +1396,7 @@ static P11KitPin *pin_callback(const char *pin_source, P11KitUri *pin_uri, return NULL; pin = p11_kit_pin_new_for_string(o.value); - free(o.value); + (*cache)->pin = o.value; return pin; } diff --git a/openconnect-internal.h b/openconnect-internal.h index ac6ffe44..8282fdd4 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -95,6 +95,12 @@ struct split_include { struct split_include *next; }; +struct pin_cache { + struct pin_cache *next; + char *token; + char *pin; +}; + #define RECONNECT_INTERVAL_MIN 10 #define RECONNECT_INTERVAL_MAX 100 @@ -159,6 +165,7 @@ struct openconnect_info { #elif defined(OPENCONNECT_GNUTLS) gnutls_session_t https_sess; gnutls_certificate_credentials_t https_cred; + struct pin_cache *pin_cache; #endif struct keepalive_info ssl_times; int owe_ssl_dpd_response;