Provide separate calls for parse_xml_response() and handle_auth_form(), so that the ordering of events in openconnect_obtain_cookie() can be modified. Signed-off-by: Kevin Cernekee <cernekee at gmail.com> --- auth.c | 75 +++++++++++++++++++++++++++++------------------- http.c | 11 +++++-- openconnect-internal.h | 8 ++++-- 3 files changed, 60 insertions(+), 34 deletions(-) diff --git a/auth.c b/auth.c index d51da87..4cfc1e1 100644 --- a/auth.c +++ b/auth.c @@ -396,19 +396,18 @@ out: /* Return value: * < 0, on error - * = 0, when form parsed and POST required - * = 1, when response was cancelled by user - * = 2, when form indicates that login was already successful + * = 0, on success; *form is populated */ -int parse_xml_response(struct openconnect_info *vpninfo, char *response, - char *request_body, int req_len, const char **method, - const char **request_body_type) +int parse_xml_response(struct openconnect_info *vpninfo, char *response, struct oc_auth_form **formp) { struct oc_auth_form *form; xmlDocPtr xml_doc; xmlNode *xml_node; - int ret; - struct vpn_option *opt, *next; + + if (*formp) { + free_auth_form(*formp); + *formp = NULL; + } form = calloc(1, sizeof(*form)); if (!form) @@ -428,27 +427,44 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response, if (xml_node->type != XML_ELEMENT_NODE || strcmp((char *)xml_node->name, "auth")) { vpn_progress(vpninfo, PRG_ERR, _("XML response has no \"auth\" root node\n")); - ret = -EINVAL; goto out; } - form->auth_id = (char *)xmlGetProp(xml_node, (unsigned char *)"id"); - if (!strcmp(form->auth_id, "success")) { - ret = 2; - goto out; + + if (parse_auth_node(vpninfo, xml_node, form) == 0) { + xmlFreeDoc(xml_doc); + *formp = form; + return 0; } + out: + xmlFreeDoc(xml_doc); + free_auth_form(form); + return -EINVAL; +} + +/* Return value: + * < 0, on error + * = 0, when form parsed and POST required + * = 1, when response was cancelled by user + * = 2, when form indicates that login was already successful + */ +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) +{ + int ret; + struct vpn_option *opt, *next; + + if (!strcmp(form->auth_id, "success")) + return 2; + if (vpninfo->nopasswd) { vpn_progress(vpninfo, PRG_ERR, _("Asked for password but '--no-passwd' set\n")); - ret = -EPERM; - goto out; + return -EPERM; } - ret = parse_auth_node(vpninfo, xml_node, form); - if (ret) - goto out; - if (vpninfo->csd_token && vpninfo->csd_ticket && vpninfo->csd_starturl && vpninfo->csd_waiturl) { /* First, redirect to the stuburl -- we'll need to fetch and run that */ vpninfo->redirect_url = strdup(vpninfo->csd_stuburl); @@ -462,17 +478,14 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response, free(opt); } vpninfo->cookies = NULL; - - ret = 0; - goto out; + return 0; } if (!form->opts) { if (form->message) vpn_progress(vpninfo, PRG_INFO, "%s\n", form->message); if (form->error) vpn_progress(vpninfo, PRG_ERR, "%s\n", form->error); - ret = -EPERM; - goto out; + return -EPERM; } if (vpninfo->process_auth_form) @@ -482,20 +495,25 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response, ret = 1; } if (ret) - goto out; + return ret; /* tokencode generation is deferred until after username prompts and CSD */ ret = do_gen_tokencode(vpninfo, form); if (ret) - goto out; + return ret; ret = append_form_opts(vpninfo, form, request_body, req_len); if (!ret) { *method = "POST"; *request_body_type = "application/x-www-form-urlencoded"; } - out: - xmlFreeDoc(xml_doc); + return ret; +} + +void free_auth_form(struct oc_auth_form *form) +{ + if (!form) + return; while (form->opts) { struct oc_form_opt *tmp = form->opts->next; if (form->opts->type == OC_FORM_OPT_TEXT || @@ -527,7 +545,6 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response, free(form->method); free(form->action); free(form); - return ret; } #ifdef LIBSTOKEN_HDR diff --git a/http.c b/http.c index 43d4c61..f0c0a5b 100644 --- a/http.c +++ b/http.c @@ -792,6 +792,7 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo) struct vpn_option *opt; struct oc_text_buf *buf; char *form_buf = NULL; + struct oc_auth_form *form = NULL; int result, buflen; char request_body[2048]; const char *request_body_type = NULL; @@ -900,9 +901,15 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo) free(form_buf); return -EINVAL; } + result = parse_xml_response(vpninfo, form_buf, &form); + if (result) { + free(form_buf); + return -ENOMEM; + } request_body[0] = 0; - result = parse_xml_response(vpninfo, form_buf, request_body, sizeof(request_body), - &method, &request_body_type); + result = handle_auth_form(vpninfo, form, request_body, sizeof(request_body), + &method, &request_body_type); + free_auth_form(form); if (!result) goto redirect; diff --git a/openconnect-internal.h b/openconnect-internal.h index 413bf3a..1349e9e 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -402,9 +402,11 @@ extern int killed; int config_lookup_host(struct openconnect_info *vpninfo, const char *host); /* auth.c */ -int parse_xml_response(struct openconnect_info *vpninfo, char *response, - char *request_body, int req_len, const char **method, - const char **request_body_type); +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); +void free_auth_form(struct oc_auth_form *form); int prepare_stoken(struct openconnect_info *vpninfo); /* http.c */ -- 1.7.10.4