From ba51b0c4b6a10085c6772af37f15b31e3090f4db Mon Sep 17 00:00:00 2001 From: Daniel Lenski Date: Fri, 23 Apr 2021 16:39:04 -0700 Subject: [PATCH] F5, Fortinet: ignore errors in landing page once we've got a cookie MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Like Juniper, F5 and Fortinet redirect the user to a landing page (“webtop”) after a successful authentication. We should ignore HTTP errors in fetching the landing page if/when we've received a valid cookie, as done for Juniper in 3e77943692b511719d9217d2ecc43588b7c6c08b. Tests for {f5,fortinet}-auth-and-config are still passing with these changes. Signed-off-by: Daniel Lenski --- f5.c | 15 ++++++--- fortinet.c | 92 ++++++++++++++++++++++++++---------------------------- 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/f5.c b/f5.c index 4035f4ba..e1c69ecf 100644 --- a/f5.c +++ b/f5.c @@ -68,8 +68,13 @@ static int check_cookie_success(struct openconnect_info *vpninfo) struct oc_vpn_option *cookie; const char *session = NULL, *f5_st = NULL; - /* XX: if login succeeded worked, we should have a response size of zero, and F5_ST - * and MRHSession cookies in the response. + /* XX: The MRHSession cookie is often set repeatedly to new values prior + * to the completion of authentication, so it is not a sufficient + * indicator of successfully completed authentication by itself. + * + * The combination of the MRHSession and F5_ST cookies appears to be + * reliable indicator. F5_ST is a "session timeout" cookie (see + * https://support.f5.com/csp/article/K15387). */ for (cookie = vpninfo->cookies; cookie; cookie = cookie->next) { if (!strcmp(cookie->option, "MRHSession")) @@ -111,15 +116,15 @@ int f5_obtain_cookie(struct openconnect_info *vpninfo) ret = do_https_request(vpninfo, "GET", NULL, NULL, &resp_buf, 2); - if (ret < 0) - break; - if (!check_cookie_success(vpninfo)) { free(resp_buf); ret = 0; break; } + if (ret < 0) + break; + url = internal_get_url(vpninfo); if (!url) { free(resp_buf); diff --git a/fortinet.c b/fortinet.c index e51994de..0373e2d1 100644 --- a/fortinet.c +++ b/fortinet.c @@ -194,55 +194,53 @@ int fortinet_obtain_cookie(struct openconnect_info *vpninfo) ret = do_https_request(vpninfo, "POST", "application/x-www-form-urlencoded", req_buf, &resp_buf, 0); - /* XX: if this worked, we should have 200 status */ - if (ret >= 0) { - /* If we got SVPNCOOKIE, then we're done. */ - struct oc_vpn_option *cookie; - for (cookie = vpninfo->cookies; cookie; cookie = cookie->next) { - if (!strcmp(cookie->option, "SVPNCOOKIE")) { - free(vpninfo->cookie); - vpninfo->cookie = strdup(cookie->value); - if (!vpninfo->cookie) - goto nomem; - ret = 0; - goto out; - } + /* If we got SVPNCOOKIE, then we're done. */ + struct oc_vpn_option *cookie; + for (cookie = vpninfo->cookies; cookie; cookie = cookie->next) { + if (!strcmp(cookie->option, "SVPNCOOKIE")) { + free(vpninfo->cookie); + vpninfo->cookie = strdup(cookie->value); + if (!vpninfo->cookie) + goto nomem; + ret = 0; + goto out; } + } - /* XX: We didn't get SVPNCOOKIE. 2FA? */ - if (!strncmp(resp_buf, "ret=", 4) && strstr(resp_buf, ",tokeninfo=")) { - const char *prompt; - struct oc_text_buf *action_buf = buf_alloc(); - - /* Hide 'username' field */ - opt->type = OC_FORM_OPT_HIDDEN; - free(opt2->label); - free(opt2->_value); - - /* Change 'credential' field to 'code'. */ - opt2->_value = NULL; - opt2->name = strdup("code"); - opt2->label = strdup("Code: "); - if (!can_gen_tokencode(vpninfo, form, opt2)) - opt2->type = OC_FORM_OPT_TOKEN; - else - opt2->type = OC_FORM_OPT_PASSWORD; - - /* Save a bunch of values to parrot back */ - filter_opts(action_buf, resp_buf, "reqid,polid,grp,portal,peer,magic", 1); - if ((ret = buf_error(action_buf))) - goto out; - free(form->action); - form->action = action_buf->data; - action_buf->data = NULL; - buf_free(action_buf); - - if ((prompt = strstr(resp_buf, ",chal_msg="))) { - const char *end = strchrnul(prompt, ','); - prompt += 10; - free(form->message); - form->message = strndup(prompt, end-prompt); - } + /* XX: We got 200 status, but no SVPNCOOKIE. 2FA? */ + if (ret >= 0 && + !strncmp(resp_buf, "ret=", 4) && strstr(resp_buf, ",tokeninfo=")) { + const char *prompt; + struct oc_text_buf *action_buf = buf_alloc(); + + /* Hide 'username' field */ + opt->type = OC_FORM_OPT_HIDDEN; + free(opt2->label); + free(opt2->_value); + + /* Change 'credential' field to 'code'. */ + opt2->_value = NULL; + opt2->name = strdup("code"); + opt2->label = strdup("Code: "); + if (!can_gen_tokencode(vpninfo, form, opt2)) + opt2->type = OC_FORM_OPT_TOKEN; + else + opt2->type = OC_FORM_OPT_PASSWORD; + + /* Save a bunch of values to parrot back */ + filter_opts(action_buf, resp_buf, "reqid,polid,grp,portal,peer,magic", 1); + if ((ret = buf_error(action_buf))) + goto out; + free(form->action); + form->action = action_buf->data; + action_buf->data = NULL; + buf_free(action_buf); + + if ((prompt = strstr(resp_buf, ",chal_msg="))) { + const char *end = strchrnul(prompt, ','); + prompt += 10; + free(form->message); + form->message = strndup(prompt, end-prompt); } } } -- 2.50.1