In order to support refreshing the <opaque> data (XML POST) or the secondary_* fields (non XML POST) on the auth form, it is necessary for the process_auth_form() callback to return to libopenconnect to refresh the form fields whenever the user changes the value of a <select> dropdown. This change should not break existing implementations. Signed-off-by: Kevin Cernekee <cernekee at gmail.com> --- auth.c | 12 ++++++++++++ http.c | 8 ++++++++ library.c | 1 + main.c | 9 ++++++--- openconnect.h | 1 + 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/auth.c b/auth.c index 2b08403..7c95037 100644 --- a/auth.c +++ b/auth.c @@ -631,6 +631,7 @@ int process_auth_form(struct openconnect_info *vpninfo, struct __oc_auth_form *f return OC_FORM_RESULT_ERR; } +retry: /* We have two parallel linked lists of form fields here: form->u.opts is a linked list of user-visible oc_form_opt's form->opts is a linked list of internally-visible __oc_form_opt's @@ -661,6 +662,17 @@ int process_auth_form(struct openconnect_info *vpninfo, struct __oc_auth_form *f sopt->u = NULL; } } + + if (ret == OC_FORM_RESULT_NEWGROUP && + form->authgroup_opt && + form->authgroup_opt->form.u.value) { + free(vpninfo->authgroup); + vpninfo->authgroup = strdup(form->authgroup_opt->form.u.value); + + if (!vpninfo->xmlpost) + goto retry; + } + return ret; } diff --git a/http.c b/http.c index 4f85f8a..f66acf5 100644 --- a/http.c +++ b/http.c @@ -1025,6 +1025,7 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo) * b) Same-host redirect (e.g. Location: /foo/bar) * c) Three redirects without seeing a plausible login form */ +newgroup: result = xmlpost_initial_req(vpninfo, request_body, sizeof(request_body), 0); if (result < 0) return result; @@ -1185,6 +1186,13 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo) goto out; if (result == __OC_FORM_RESULT_LOGGEDIN) break; + if (result == OC_FORM_RESULT_NEWGROUP) { + free(form_buf); + form_buf = NULL; + free_auth_form(form); + form = NULL; + goto newgroup; + } result = do_https_request(vpninfo, method, request_body_type, request_body, &form_buf, 1); diff --git a/library.c b/library.c index 66bf89b..e1bd0f2 100644 --- a/library.c +++ b/library.c @@ -145,6 +145,7 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo) vpninfo->peer_cert = NULL; } free(vpninfo->useragent); + free(vpninfo->authgroup); #ifdef HAVE_LIBSTOKEN if (vpninfo->stoken_pin) free(vpninfo->stoken_pin); diff --git a/main.c b/main.c index b7ccb1f..c9a3fa4 100644 --- a/main.c +++ b/main.c @@ -1105,13 +1105,12 @@ static int process_auth_form_cb(void *_vpninfo, if (opt->type == OC_FORM_OPT_SELECT) { struct oc_form_opt_select *select_opt = (void *)opt; struct oc_choice *choice = NULL; - int i; + int i, is_group_list = form->authgroup_field && !strcmp(opt->name, form->authgroup_field); if (!select_opt->nr_choices) continue; - if (authgroup && - !strcmp(opt->name, "group_list")) { + if (authgroup && is_group_list) { for (i = 0; i < select_opt->nr_choices; i++) { choice = &select_opt->choices[i]; @@ -1158,9 +1157,13 @@ static int process_auth_form_cb(void *_vpninfo, for (i = 0; i < select_opt->nr_choices; i++) { choice = &select_opt->choices[i]; + select_opt->form.value = choice->name; if (!strcmp(response, choice->label)) { select_opt->form.value = choice->name; + authgroup = strdup(choice->label); + if (is_group_list) + return OC_FORM_RESULT_NEWGROUP; break; } } diff --git a/openconnect.h b/openconnect.h index 18d31ae..97747ff 100644 --- a/openconnect.h +++ b/openconnect.h @@ -96,6 +96,7 @@ #define OC_FORM_RESULT_ERR -1 #define OC_FORM_RESULT_OK 0 #define OC_FORM_RESULT_CANCELLED 1 +#define OC_FORM_RESULT_NEWGROUP 2 #define __OC_FORM_RESULT_LOGGEDIN 255 /* internal library use only */ /* char * fields are static (owned by XML parser) and don't need to be -- 1.7.9.5