From c407e79e9825503cd8ea73cd6cc5193785598b1e Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Thu, 25 Oct 2012 21:53:10 -0700 Subject: [PATCH] auth: Parse the new server response format Newer AnyConnect installations use a different XML document tree to pass information to the client. This patch allows OpenConnect to parse the new format, and attempts to document both the old format and the new format in the comments. Signed-off-by: Kevin Cernekee --- auth.c | 127 ++++++++++++++++++++++++++++++++++++++--- openconnect-internal.h | 3 + 2 files changed, 121 insertions(+), 9 deletions(-) diff --git a/auth.c b/auth.c index 4cfc1e1d..79c9bc1b 100644 --- a/auth.c +++ b/auth.c @@ -348,6 +348,63 @@ static int xmlnode_get_text(xmlNode *xml_node, const char *name, char **var) return 0; } +/* + * Legacy server response looks like: + * + * "> + * <!-- title to display to user --> + * + * + * + * + * Please enter your username and password. + *
+ * + * + * + * + * + *
+ *
+ * + * New server response looks like: + * + * + * + * + * + * + * foobar + * 1234567 + * + * method = strdup("POST"); + form->action = strdup("/"); + xmlnode_get_prop(xml_node, "method", &form->method); xmlnode_get_prop(xml_node, "action", &form->action); @@ -394,6 +455,24 @@ static int parse_auth_node(struct openconnect_info *vpninfo, xmlNode *xml_node, return ret; } +static int parse_host_scan_node(struct openconnect_info *vpninfo, xmlNode *xml_node) +{ + /* ignore this whole section if the CSD trojan has already run */ + if (vpninfo->csd_scriptname) + return 0; + + for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) { + if (xml_node->type != XML_ELEMENT_NODE) + continue; + + xmlnode_get_text(xml_node, "host-scan-ticket", &vpninfo->csd_ticket); + xmlnode_get_text(xml_node, "host-scan-token", &vpninfo->csd_token); + xmlnode_get_text(xml_node, "host-scan-base-uri", &vpninfo->csd_starturl); + xmlnode_get_text(xml_node, "host-scan-wait-uri", &vpninfo->csd_waiturl); + } + return 0; +} + /* Return value: * < 0, on error * = 0, on success; *form is populated @@ -403,6 +482,7 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response, struct struct oc_auth_form *form; xmlDocPtr xml_doc; xmlNode *xml_node; + int ret = -EINVAL; if (*formp) { free_auth_form(*formp); @@ -424,23 +504,52 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response, struct } xml_node = xmlDocGetRootElement(xml_doc); - if (xml_node->type != XML_ELEMENT_NODE || strcmp((char *)xml_node->name, "auth")) { + while (xml_node) { + int ret = 0; + + if (xml_node->type != XML_ELEMENT_NODE) { + xml_node = xml_node->next; + continue; + } + if (xmlnode_is_named(xml_node, "config-auth")) { + /* if we do have a config-auth node, it is the root element */ + xml_node = xml_node->children; + continue; + } else if (xmlnode_is_named(xml_node, "auth")) { + xmlnode_get_prop(xml_node, "id", &form->auth_id); + ret = parse_auth_node(vpninfo, xml_node, form); + } else if (xmlnode_is_named(xml_node, "opaque")) { + if (vpninfo->opaque_srvdata) + xmlFreeNode(vpninfo->opaque_srvdata); + vpninfo->opaque_srvdata = xmlCopyNode(xml_node, 1); + if (!vpninfo->opaque_srvdata) + ret = -ENOMEM; + } else if (xmlnode_is_named(xml_node, "host-scan")) { + ret = parse_host_scan_node(vpninfo, xml_node); + } else { + xmlnode_get_text(xml_node, "session-token", &vpninfo->cookie); + xmlnode_get_text(xml_node, "error", &form->error); + } + + if (ret) + goto out; + xml_node = xml_node->next; + } + + if (!form->auth_id) { vpn_progress(vpninfo, PRG_ERR, - _("XML response has no \"auth\" root node\n")); + _("XML response has no \"auth\" node\n")); goto out; } - form->auth_id = (char *)xmlGetProp(xml_node, (unsigned char *)"id"); - if (parse_auth_node(vpninfo, xml_node, form) == 0) { - xmlFreeDoc(xml_doc); - *formp = form; - return 0; - } + *formp = form; + xmlFreeDoc(xml_doc); + return 0; out: xmlFreeDoc(xml_doc); free_auth_form(form); - return -EINVAL; + return ret; } /* Return value: diff --git a/openconnect-internal.h b/openconnect-internal.h index 1349e9e9..cd0e7e74 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -74,6 +74,8 @@ #endif #define N_(s) s +#include + #define SHA1_SIZE 20 #define MD5_SIZE 16 @@ -139,6 +141,7 @@ struct openconnect_info { char *csd_preurl; char *csd_scriptname; + xmlNode *opaque_srvdata; #ifdef LIBPROXY_HDR pxProxyFactory *proxy_factory;