Feature Request: HTTP proxy authentication

David Woodhouse dwmw2 at infradead.org
Thu Jun 19 02:04:39 PDT 2014


On Thu, 2014-06-19 at 09:12 +0530, Marc-André Laverdière wrote:
> 
> I discovered yesterday how rusty I got at C... oh well.
> Here are some of the changes I did, straight from the "I don't know
> what I'm doing dept."

Looks good; thanks. I'd actually already implemented the
username/password parsing for openconnect_set_http_proxy() but it was a
bit of a hack, just post-processing the "hostname" returned by the
standard URL parsing function and looking for the @ sign.

You've done a much better job, making internal_parse_url() do it sanely
and propagating that API change — and as an added bonus you've also made
it use the xmlParseUri() function instead of its own implementation. I
hadn't realised that was available.

There are *lots* of wheels reinvented in the OpenConnect code, which
always makes me sad, but often it's not avoidable. This one *was*
avoidable, and well done for spotting that.

(If you can find a suitable base64 encode/decode function that I can use
too, that'd make me even happier. OpenSSL gives me one, but not GnuTLS
or libxml2 AFAICT.)

It took me a while to work out what you'd changed, though. Instead of
complete files (which were so large that the mailing list didn't even
let them through), it's best to send a patch. That way, I don't have to
spend time trying to work out which historical version of the code you
*started* with, to tell your changes from all the other changes which
have been made since then.

Here's your work as a patch, which makes it easy to read and review
right here in the mail. When submitting a patch please also include a
Signed-Off-By: tag as described at
http://www.infradead.org/openconnect/contribute.html

Thanks again.

diff --git a/http.c b/http.c
index 323ff43..8b9d87f 100644
--- a/http.c
+++ b/http.c
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <libxml/uri.h>
 #ifndef _WIN32
 #include <pwd.h>
 #endif
@@ -662,69 +663,65 @@ out:
 #endif /* !_WIN32 */
 }
 
-int internal_parse_url(char *url, char **res_proto, char **res_host,
-		       int *res_port, char **res_path, int default_port)
+int internal_parse_url(char *url, char **res_proto, char **res_host, int *res_port,
+                       char **res_auth_uname, char **res_auth_pwd, char **res_path, int default_port)
 {
-	char *proto = url;
-	char *host, *path, *port_str;
-	int port;
-
-	host = strstr(url, "://");
-	if (host) {
-		*host = 0;
-		host += 3;
-
-		if (!strcasecmp(proto, "https"))
-			port = 443;
-		else if (!strcasecmp(proto, "http"))
-			port = 80;
-		else if (!strcasecmp(proto, "socks") ||
-			 !strcasecmp(proto, "socks4") ||
-			 !strcasecmp(proto, "socks5"))
-			port = 1080;
-		else
-			return -EPROTONOSUPPORT;
-	} else {
-		if (default_port) {
-			proto = NULL;
-			port = default_port;
-			host = url;
-		} else
-			return -EINVAL;
-	}
-
-	path = strchr(host, '/');
-	if (path)
-		*(path++) = 0;
 
-	port_str = strrchr(host, ':');
-	if (port_str) {
-		char *end;
-		int new_port = strtol(port_str + 1, &end, 10);
-
-		if (!*end) {
-			*port_str = 0;
-			port = new_port;
-		}
-	}
-
-	if (res_proto)
-		*res_proto = proto ? strdup(proto) : NULL;
-	if (res_host)
-		*res_host = strdup(host);
-	if (res_port)
-		*res_port = port;
-	if (res_path)
-		*res_path = (path && *path) ? strdup(path) : NULL;
-
-	/* Undo the damage we did to the original string */
-	if (port_str)
-		*(port_str) = ':';
-	if (path)
-		*(path - 1) = '/';
-	if (proto)
-		*(host - 3) = ':';
-	return 0;
+    int port = default_port;
+
+    xmlURIPtr uriInfo = xmlParseURI(url);
+    if (uriInfo == NULL || uriInfo->scheme == NULL || uriInfo->server == NULL)
+        return -EPROTONOSUPPORT;
+
+    *res_proto = strdup(uriInfo->scheme);
+
+    if (res_proto != NULL)
+    {
+        if (!strcasecmp(*res_proto, "https"))
+            port = 443;
+        else if (!strcasecmp(*res_proto, "http"))
+            port = 80;
+        else if (!strcasecmp(*res_proto, "socks") ||
+                 !strcasecmp(*res_proto, "socks4") ||
+                 !strcasecmp(*res_proto, "socks5"))
+            port = 1080;
+        else
+            return -EPROTONOSUPPORT;
+    }
+
+    if (res_port != NULL)
+    {
+        if (uriInfo->port >= 0)
+            port = uriInfo->port;
+        *res_port = port;
+    }
+
+    if (res_host != NULL)
+        *res_host = strdup(uriInfo->server);
+
+    //user information may contain the password too
+    if (res_auth_uname != NULL && res_auth_pwd != NULL && uriInfo->user != NULL)
+    {
+        char * copy = strdup(uriInfo->user);
+        char * separator = strchr(copy, ':');
+        if (separator == NULL)
+            *res_auth_uname = copy;
+        else
+        {
+            *res_auth_uname = copy;
+            *res_auth_pwd = separator ++;
+            *separator = '\0';
+        }
+    }
+
+    if (res_path != NULL && uriInfo->path != NULL)
+    {
+        *res_path = strdup(uriInfo->path);
+    }
+
+    xmlFreeURI(uriInfo);
+
+	return 0; //Success
 }
 
 static void clear_cookies(struct openconnect_info *vpninfo)
@@ -758,7 +755,7 @@ static int handle_redirect(struct openconnect_info *vpninfo)
 		free(vpninfo->urlpath);
 		vpninfo->urlpath = NULL;
 
-		ret = internal_parse_url(vpninfo->redirect_url, NULL, &host, &port, &vpninfo->urlpath, 0);
+		ret = internal_parse_url(vpninfo->redirect_url, NULL, &host, &port, NULL, NULL, &vpninfo->urlpath, 0);
 		if (ret) {
 			vpn_progress(vpninfo, PRG_ERR,
 				     _("Failed to parse redirected URL '%s': %s\n"),
@@ -1533,6 +1530,19 @@ static int process_http_proxy(struct openconnect_info *vpninfo, int ssl_sock)
 		return -EINVAL;
 	}
 
+    //Check for authentication demand from the proxy
+    //TODO her, here here!
+    if (result == 407)
+    {
+        //Step 1: extract the token(s) provided and the method(s) supported
+        //
+        //Step 2: encode the usernmae+password combination in base64
+        //
+        //Step 3: Add the tokens and auth info
+        //
+        //Step 4: Send to proxy and get response
+    }
+
 	if (result != 200) {
 		vpn_progress(vpninfo, PRG_ERR,
 			     _("Proxy CONNECT request failed: %s\n"), buf);
@@ -1581,7 +1591,7 @@ int openconnect_set_http_proxy(struct openconnect_info *vpninfo, char *proxy)
 	vpninfo->proxy = NULL;
 
 	ret = internal_parse_url(url, &vpninfo->proxy_type, &vpninfo->proxy,
-				 &vpninfo->proxy_port, NULL, 80);
+				 &vpninfo->proxy_port, &vpninfo->proxy_auth_uname, &vpninfo->proxy_auth_pwd, NULL, 80);
 	if (ret)
 		goto out;
 
diff --git a/library.c b/library.c
index ae91e8d..0a8ee3c 100644
--- a/library.c
+++ b/library.c
@@ -343,7 +343,7 @@ int openconnect_parse_url(struct openconnect_info *vpninfo, char *url)
 	vpninfo->urlpath = NULL;
 
 	ret = internal_parse_url(url, &scheme, &vpninfo->hostname,
-				 &vpninfo->port, &vpninfo->urlpath, 443);
+				 &vpninfo->port, NULL, NULL, &vpninfo->urlpath, 443);
 
 	if (ret) {
 		vpn_progress(vpninfo, PRG_ERR,


-- 
dwmw2
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5745 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/openconnect-devel/attachments/20140619/a8283de0/attachment-0001.bin>


More information about the openconnect-devel mailing list