[PATCH 13/24] auth: Add new XML POST capability
Kevin Cernekee
cernekee at gmail.com
Sat Nov 3 13:22:55 EDT 2012
Signed-off-by: Kevin Cernekee <cernekee at gmail.com>
---
auth.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++-
http.c | 2 +-
library.c | 4 ++
openconnect-internal.h | 3 +-
4 files changed, 166 insertions(+), 4 deletions(-)
diff --git a/auth.c b/auth.c
index 79c9bc1..de02e77 100644
--- a/auth.c
+++ b/auth.c
@@ -41,6 +41,8 @@
#include "openconnect-internal.h"
+static int xmlpost_append_form_opts(struct openconnect_info *vpninfo,
+ struct oc_auth_form *form, char *body, int bodylen);
static int can_gen_tokencode(struct openconnect_info *vpninfo, struct oc_form_opt *opt);
static int do_gen_tokencode(struct openconnect_info *vpninfo, struct oc_auth_form *form);
@@ -560,7 +562,7 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response, struct
*/
int handle_auth_form(struct openconnect_info *vpninfo, struct oc_auth_form *form,
char *request_body, int req_len, const char **method,
- const char **request_body_type)
+ const char **request_body_type, int xmlpost)
{
int ret;
struct vpn_option *opt, *next;
@@ -611,7 +613,9 @@ int handle_auth_form(struct openconnect_info *vpninfo, struct oc_auth_form *form
if (ret)
return ret;
- ret = append_form_opts(vpninfo, form, request_body, req_len);
+ ret = xmlpost ?
+ xmlpost_append_form_opts(vpninfo, form, request_body, req_len) :
+ append_form_opts(vpninfo, form, request_body, req_len);
if (!ret) {
*method = "POST";
*request_body_type = "application/x-www-form-urlencoded";
@@ -656,6 +660,159 @@ void free_auth_form(struct oc_auth_form *form)
free(form);
}
+/*
+ * Old submission format is just an HTTP query string:
+ *
+ * password=12345678&username=joe
+ *
+ * New XML format is more complicated:
+ *
+ * <config-auth client="vpn" type="<!-- init or auth-reply -->">
+ * <version who="vpn"><!-- currently just the OpenConnect version --></version>
+ * <device-id><!-- linux, linux-64, mac, win --></device-id>
+ * <opaque is-for="<!-- some name -->">
+ * <!-- just copy this verbatim from whatever the gateway sent us -->
+ * </opaque>
+ *
+ * For init only, add:
+ * <group-access>https://<!-- insert hostname here --></group-access>
+ *
+ * For auth-reply only, add:
+ * <auth>
+ * <username><!-- same treatment as the old form options --></username>
+ * <password><!-- ditto -->
+ * </auth>
+ * <host-scan-token><!-- vpninfo->csd_ticket --></host-scan-token>
+ */
+
+#define XCAST(x) ((const xmlChar *)(x))
+
+static xmlDocPtr xmlpost_new_query(struct openconnect_info *vpninfo, const char *type,
+ xmlNodePtr *rootp)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root, node;
+
+ doc = xmlNewDoc(XCAST("1.0"));
+ if (!doc)
+ return NULL;
+
+ *rootp = root = xmlNewNode(NULL, XCAST("config-auth"));
+ if (!root)
+ goto bad;
+ if (!xmlNewProp(root, XCAST("client"), XCAST("vpn")))
+ goto bad;
+ if (!xmlNewProp(root, XCAST("type"), XCAST(type)))
+ goto bad;
+ xmlDocSetRootElement(doc, root);
+
+ node = xmlNewTextChild(root, NULL, XCAST("version"), XCAST(openconnect_version_str));
+ if (!node)
+ goto bad;
+ if (!xmlNewProp(node, XCAST("who"), XCAST("vpn")))
+ goto bad;
+
+ if (!xmlNewTextChild(root, NULL, XCAST("device-id"), XCAST(vpninfo->platname)))
+ goto bad;
+
+ return doc;
+
+bad:
+ xmlFreeDoc(doc);
+ return NULL;
+}
+
+static int xmlpost_complete(xmlDocPtr doc, char *body, int bodylen)
+{
+ xmlChar *mem = NULL;
+ int len, ret = 0;
+
+ if (!body) {
+ xmlFree(doc);
+ return 0;
+ }
+
+ xmlDocDumpMemoryEnc(doc, &mem, &len, "UTF-8");
+ if (!mem) {
+ xmlFreeDoc(doc);
+ return -ENOMEM;
+ }
+
+ if (len > bodylen)
+ ret = -E2BIG;
+ else {
+ memcpy(body, mem, len);
+ body[len] = 0;
+ }
+
+ xmlFreeDoc(doc);
+ xmlFree(mem);
+
+ return ret;
+}
+
+int xmlpost_initial_req(struct openconnect_info *vpninfo, char *request_body, int req_len)
+{
+ xmlNodePtr root, node;
+ xmlDocPtr doc = xmlpost_new_query(vpninfo, "init", &root);
+ char *url;
+
+ if (!doc)
+ return -ENOMEM;
+
+ if (asprintf(&url, "https://%s", vpninfo->hostname) == -1)
+ goto bad;
+ node = xmlNewTextChild(root, NULL, XCAST("group-access"), XCAST(url));
+ free(url);
+ if (!node)
+ goto bad;
+
+ return xmlpost_complete(doc, request_body, req_len);
+
+bad:
+ xmlpost_complete(doc, NULL, 0);
+ return -ENOMEM;
+}
+
+static int xmlpost_append_form_opts(struct openconnect_info *vpninfo,
+ struct oc_auth_form *form, char *body, int bodylen)
+{
+ xmlNodePtr root, node;
+ xmlDocPtr doc = xmlpost_new_query(vpninfo, "auth-reply", &root);
+ struct oc_form_opt *opt;
+
+ if (!doc)
+ return -ENOMEM;
+
+ if (vpninfo->opaque_srvdata) {
+ node = xmlCopyNode(vpninfo->opaque_srvdata, 1);
+ if (!node)
+ goto bad;
+ if (!xmlAddChild(root, node))
+ goto bad;
+ }
+
+ node = xmlNewChild(root, NULL, XCAST("auth"), NULL);
+ if (!node)
+ goto bad;
+
+ for (opt = form->opts; opt; opt = opt->next) {
+ if (!xmlNewTextChild(node, NULL, XCAST(opt->name), XCAST(opt->value)))
+ goto bad;
+ }
+
+ if (vpninfo->csd_token &&
+ !xmlNewTextChild(root, NULL, XCAST("host-scan-token"), XCAST(vpninfo->csd_token)))
+ goto bad;
+
+ return xmlpost_complete(doc, body, bodylen);
+
+bad:
+ xmlpost_complete(doc, NULL, 0);
+ return -ENOMEM;
+}
+
+
#ifdef LIBSTOKEN_HDR
static void nuke_opt_values(struct oc_form_opt *opt)
{
diff --git a/http.c b/http.c
index f0c0a5b..7b2c0fe 100644
--- a/http.c
+++ b/http.c
@@ -908,7 +908,7 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo)
}
request_body[0] = 0;
result = handle_auth_form(vpninfo, form, request_body, sizeof(request_body),
- &method, &request_body_type);
+ &method, &request_body_type, 0);
free_auth_form(form);
if (!result)
diff --git a/library.c b/library.c
index c1cf95f..16b7bab 100644
--- a/library.c
+++ b/library.c
@@ -30,6 +30,8 @@
#include LIBSTOKEN_HDR
#endif
+#include <libxml/tree.h>
+
#include "openconnect-internal.h"
struct openconnect_info *openconnect_vpninfo_new (char *useragent,
@@ -112,6 +114,8 @@ void openconnect_vpninfo_free (struct openconnect_info *vpninfo)
free(vpninfo->csd_scriptname);
}
free(vpninfo->csd_stuburl);
+ if (vpninfo->opaque_srvdata)
+ xmlFreeNode(vpninfo->opaque_srvdata);
/* These are const in openconnect itself, but for consistency of
the library API we do take ownership of the strings we're given,
and thus we have to free them too. */
diff --git a/openconnect-internal.h b/openconnect-internal.h
index fd0060d..f1a3fb6 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -409,8 +409,9 @@ int config_lookup_host(struct openconnect_info *vpninfo, const char *host);
int parse_xml_response(struct openconnect_info *vpninfo, char *response, struct oc_auth_form **form);
int handle_auth_form(struct openconnect_info *vpninfo, struct oc_auth_form *form,
char *request_body, int req_len, const char **method,
- const char **request_body_type);
+ const char **request_body_type, int xmlpost);
void free_auth_form(struct oc_auth_form *form);
+int xmlpost_initial_req(struct openconnect_info *vpninfo, char *request_body, int req_len);
int prepare_stoken(struct openconnect_info *vpninfo);
/* http.c */
--
1.7.10.4
More information about the openconnect-devel
mailing list