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;