diff --git a/http.c b/http.c index 0d9a2b08..98da98e9 100644 --- a/http.c +++ b/http.c @@ -1879,6 +1879,12 @@ static int proxy_hdrs(struct openconnect_info *vpninfo, char *hdr, char *val) { int i; + if (!strcasecmp(hdr, "Proxy-Connection")) { + if (!strcasecmp(val, "close")) + vpninfo->proxy_close_during_auth = 1; + return 0; + } + if (strcasecmp(hdr, "Proxy-Authenticate")) return 0; @@ -1919,7 +1925,9 @@ static int process_http_proxy(struct openconnect_info *vpninfo) int resplen; struct oc_text_buf *reqbuf; int result; - int auth = 0; + int auth = vpninfo->proxy_close_during_auth; + + vpninfo->proxy_close_during_auth = 0; vpn_progress(vpninfo, PRG_INFO, _("Requesting HTTP proxy connection to %s:%d\n"), @@ -1973,6 +1981,10 @@ static int process_http_proxy(struct openconnect_info *vpninfo) } if (result == 407) { + /* If the proxy asked us to close the connection, do so */ + if (vpninfo->proxy_close_during_auth) + return -EAGAIN; + auth = 1; goto retry; } @@ -1985,9 +1997,17 @@ static int process_http_proxy(struct openconnect_info *vpninfo) return -EIO; } +void cleanup_proxy_auth(struct openconnect_info *vpninfo) +{ + int i; + + for (i = 0; i < sizeof(auth_methods) / sizeof(auth_methods[0]); i++) + clear_auth_state(vpninfo, &auth_methods[i], 1); +} + int process_proxy(struct openconnect_info *vpninfo, int ssl_sock) { - int ret, i; + int ret; vpninfo->proxy_fd = ssl_sock; vpninfo->ssl_read = proxy_read; @@ -2006,8 +2026,9 @@ int process_proxy(struct openconnect_info *vpninfo, int ssl_sock) } vpninfo->proxy_fd = -1; - for (i = 0; i < sizeof(auth_methods) / sizeof(auth_methods[0]); i++) - clear_auth_state(vpninfo, &auth_methods[i], 1); + if (!vpninfo->proxy_close_during_auth) + cleanup_proxy_auth(vpninfo); + return ret; } diff --git a/openconnect-internal.h b/openconnect-internal.h index 0c888eac..1738da29 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -206,6 +206,7 @@ struct openconnect_info { int proxy_fd; char *proxy_user; char *proxy_pass; + int proxy_close_during_auth; struct proxy_auth_state auth[MAX_AUTH_TYPES]; #ifdef HAVE_GSSAPI gss_name_t gss_target_name; @@ -610,6 +611,7 @@ void *openconnect_base64_decode(int *len, const char *in); int buf_error(struct oc_text_buf *buf); int buf_free(struct oc_text_buf *buf); char *openconnect_create_useragent(const char *base); +void cleanup_proxy_auth(struct openconnect_info *vpninfo); int process_proxy(struct openconnect_info *vpninfo, int ssl_sock); int internal_parse_url(char *url, char **res_proto, char **res_host, int *res_port, char **res_path, int default_port); diff --git a/ssl.c b/ssl.c index fd171d97..e5d3ace1 100644 --- a/ssl.c +++ b/ssl.c @@ -139,7 +139,8 @@ int connect_https_socket(struct openconnect_info *vpninfo) } if (ssl_sock >= 0) closesocket(ssl_sock); - return -EINVAL; + ssl_sock = -EINVAL; + goto out; } } else { struct addrinfo hints, *result, *rp; @@ -176,8 +177,10 @@ int connect_https_socket(struct openconnect_info *vpninfo) else i = asprintf(&url, "https://%s:%d/%s", vpninfo->hostname, vpninfo->port, vpninfo->urlpath?:""); - if (i == -1) - return -ENOMEM; + if (i == -1) { + ssl_sock = -ENOMEM; + goto out; + } proxies = px_proxy_factory_get_proxies(vpninfo->proxy_factory, url); @@ -211,8 +214,10 @@ int connect_https_socket(struct openconnect_info *vpninfo) if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') { hostname = strndup(hostname + 1, strlen(hostname) - 2); - if (!hostname) - return -ENOMEM; + if (!hostname) { + ssl_sock = -ENOMEM; + goto out; + } hints.ai_flags |= AI_NUMERICHOST; } @@ -224,7 +229,8 @@ int connect_https_socket(struct openconnect_info *vpninfo) hostname, gai_strerror(err)); if (hints.ai_flags & AI_NUMERICHOST) free(hostname); - return -EINVAL; + ssl_sock = -EINVAL; + goto out; } if (hints.ai_flags & AI_NUMERICHOST) free(hostname); @@ -256,7 +262,8 @@ int connect_https_socket(struct openconnect_info *vpninfo) vpn_progress(vpninfo, PRG_ERR, _("Failed to allocate sockaddr storage\n")); closesocket(ssl_sock); - return -ENOMEM; + ssl_sock = -ENOMEM; + goto out; } vpninfo->peer_addrlen = rp->ai_addrlen; memcpy(vpninfo->peer_addr, rp->ai_addr, rp->ai_addrlen); @@ -288,7 +295,8 @@ int connect_https_socket(struct openconnect_info *vpninfo) vpn_progress(vpninfo, PRG_ERR, _("Failed to connect to host %s\n"), vpninfo->proxy?:vpninfo->hostname); - return -EINVAL; + ssl_sock = -EINVAL; + goto out; } } @@ -302,10 +310,13 @@ int connect_https_socket(struct openconnect_info *vpninfo) _("Reconnecting to proxy %s\n"), vpninfo->proxy); goto reconnect; } - return err; + ssl_sock = err; } } - + out: + /* If proxy processing returned -EAGAIN to reconnect before attempting + further auth, and we failed to reconnect, we have to clean up here. */ + cleanup_proxy_auth(vpninfo); return ssl_sock; }