diff --git a/http.c b/http.c index 013f0f99..c5e0045e 100644 --- a/http.c +++ b/http.c @@ -1743,7 +1743,7 @@ static void handle_auth_proto(struct openconnect_info *vpninfo, struct proxy_auth_state *auth = &vpninfo->auth[method->state_index]; int l = strlen(method->name); - if (auth->state == AUTH_FAILED) + if (auth->state <= AUTH_FAILED) return; if (strncmp(method->name, hdr, l)) @@ -1789,7 +1789,7 @@ static void clear_auth_state(struct openconnect_info *vpninfo, free(auth->challenge); auth->challenge = NULL; /* If it *failed* don't try it again even next time */ - if (auth->state == AUTH_FAILED) + if (auth->state <= AUTH_FAILED) return; if (reset || auth->state == AUTH_AVAILABLE) auth->state = AUTH_UNSEEN; @@ -1894,6 +1894,31 @@ int process_proxy(struct openconnect_info *vpninfo, int ssl_sock) return ret; } +int openconnect_set_proxy_auth(struct openconnect_info *vpninfo, char *methods) +{ + int i; + char *p, *start = methods; + + for (i = 0; i < sizeof(auth_methods) / sizeof(auth_methods[0]); i++) + vpninfo->auth[auth_methods[i].state_index].state = AUTH_DISABLED; + + while (methods) { + p = strchr(methods, ','); + if (p) + *(p++) = 0; + + for (i = 0; i < sizeof(auth_methods) / sizeof(auth_methods[0]); i++) { + if (!strcasecmp(methods, auth_methods[i].name)) { + vpninfo->auth[auth_methods[i].state_index].state = AUTH_UNSEEN; + break; + } + } + methods = p; + } + free(start); + return 0; +} + int openconnect_set_http_proxy(struct openconnect_info *vpninfo, char *proxy) { char *url = proxy, *p; diff --git a/java/src/org/infradead/libopenconnect/LibOpenConnect.java b/java/src/org/infradead/libopenconnect/LibOpenConnect.java index 2162aa64..23526756 100644 --- a/java/src/org/infradead/libopenconnect/LibOpenConnect.java +++ b/java/src/org/infradead/libopenconnect/LibOpenConnect.java @@ -112,6 +112,7 @@ public boolean isCanceled() { public synchronized native int passphraseFromFSID(); public synchronized native void setCertExpiryWarning(int seconds); public synchronized native void setDPD(int minSeconds); + public synchronized native int setProxyAuth(String methods); public synchronized native int setHTTPProxy(String proxy); public synchronized native void setXMLSHA1(String hash); public synchronized native void setHostname(String hostname); diff --git a/jni.c b/jni.c index 07cb62d7..43fe5fb9 100644 --- a/jni.c +++ b/jni.c @@ -1034,6 +1034,15 @@ JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_parseURL return ret; } +JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setProxyAuth( + JNIEnv *jenv, jobject jobj, jstring jarg) +{ + int ret; + SET_STRING_START(-ENOMEM) + ret = openconnect_set_proxy_auth(ctx->vpninfo, arg); + return ret; +} + JNIEXPORT jint JNICALL Java_org_infradead_libopenconnect_LibOpenConnect_setHTTPProxy( JNIEnv *jenv, jobject jobj, jstring jarg) { diff --git a/libopenconnect.map.in b/libopenconnect.map.in index 8bd2e369..1a8675af 100644 --- a/libopenconnect.map.in +++ b/libopenconnect.map.in @@ -58,6 +58,7 @@ OPENCONNECT_3.3 { global: openconnect_set_pfs; openconnect_set_dpd; + openconnect_set_proxy_auth; } OPENCONNECT_3.1; OPENCONNECT_PRIVATE { diff --git a/main.c b/main.c index 1aac89cf..6e5ab44b 100644 --- a/main.c +++ b/main.c @@ -157,6 +157,7 @@ enum { OPT_OS, OPT_TIMESTAMP, OPT_PFS, + OPT_PROXY_AUTH, }; #ifdef __sun__ @@ -197,6 +198,7 @@ static struct option long_options[] = { OPTION("timestamp", 0, OPT_TIMESTAMP), OPTION("key-password", 1, 'p'), OPTION("proxy", 1, 'P'), + OPTION("proxy-auth", 1, OPT_PROXY_AUTH), OPTION("user", 1, 'u'), OPTION("verbose", 0, 'v'), OPTION("version", 0, 'V'), @@ -352,6 +354,7 @@ static void usage(void) printf(" -p, --key-password=PASS %s\n", _("Set key passphrase or TPM SRK PIN")); printf(" --key-password-from-fsid %s\n", _("Key passphrase is fsid of file system")); printf(" -P, --proxy=URL %s\n", _("Set proxy server")); + printf(" --proxy-auth=METHODS %s\n", _("Set proxy authentication methods")); printf(" --no-proxy %s\n", _("Disable proxy")); printf(" --libproxy %s\n", _("Use libproxy to automatically configure proxy")); #ifndef LIBPROXY_HDR @@ -784,6 +787,9 @@ int main(int argc, char **argv) proxy = keep_config_arg(); autoproxy = 0; break; + case OPT_PROXY_AUTH: + openconnect_set_proxy_auth(vpninfo, xstrdup(config_arg)); + break; case OPT_NO_PROXY: autoproxy = 0; proxy = NULL; diff --git a/openconnect-internal.h b/openconnect-internal.h index 7c72cff7..4e2da9ec 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -156,6 +156,7 @@ struct oc_text_buf { #define MAX_AUTH_TYPES 4 +#define AUTH_DISABLED -2 #define AUTH_FAILED -1 /* Failed */ #define AUTH_UNSEEN 0 /* Server has not offered it */ #define AUTH_AVAILABLE 1 /* Server has offered it, we have not tried it */ diff --git a/openconnect.8.in b/openconnect.8.in index d2bafa92..d76490b2 100644 --- a/openconnect.8.in +++ b/openconnect.8.in @@ -25,6 +25,7 @@ openconnect \- Connect to Cisco AnyConnect VPN .OP \-\-basemtu mtu .OP \-p,\-\-key\-password pass .OP \-P,\-\-proxy proxyurl +.OP \-\-proxy\-auth methods .OP \-\-no\-proxy .OP \-\-libproxy .OP \-\-key\-password\-from\-fsid @@ -192,6 +193,13 @@ in the given URL, and will be used for authentication. If authentication is required but no credentials are given, GSSAPI and automatic NTLM authentication using Samba's ntlm_auth helper tool may be attempted. .TP +.B \-\-proxy-auth=METHODS +Use only the specified methods for HTTP authentication to a proxy. The argument +is a comma-separated list of methods to be enabled. Note that the order does +not matter: OpenConnect will use Negotiate, NTLM, Digest and Basic authentication +in that order, if each is enabled, regardless of the order specified in the METHODS +string. +.TP .B \-\-no\-proxy Disable use of proxy .TP diff --git a/openconnect.h b/openconnect.h index 6c2ac1be..e714663a 100644 --- a/openconnect.h +++ b/openconnect.h @@ -33,7 +33,8 @@ /* * API version 3.3: - * - Add openconnect_set_pfs(), openconnect_set_dpd() + * - Add openconnect_set_pfs(), openconnect_set_dpd(), + * openconnect_set_proxy_auth() * * API version 3.2: * - Add OC_TOKEN_MODE_HOTP and allow openconnect_has_oath_support() to @@ -271,6 +272,10 @@ char *openconnect_get_cert_details(struct openconnect_info *vpninfo, that will need to be freed by the caller. */ int openconnect_get_cert_DER(struct openconnect_info *vpninfo, OPENCONNECT_X509 *cert, unsigned char **buf); + +/* Contains a comma-separated list of authentication methods to enabled. + Currently supported: Negotiate,NTLM,Digest,Basic */ +int openconnect_set_proxy_auth(struct openconnect_info *vpninfo, char *methods); int openconnect_set_http_proxy(struct openconnect_info *vpninfo, char *proxy); int openconnect_passphrase_from_fsid(struct openconnect_info *vpninfo); int openconnect_obtain_cookie(struct openconnect_info *vpninfo);