Add 'proto' integer value to struct vpn_proto
authorDavid Woodhouse <dwmw2@infradead.org>
Fri, 9 Apr 2021 12:09:11 +0000 (13:09 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Fri, 9 Apr 2021 12:09:11 +0000 (13:09 +0100)
Despite making no mention of this in the commit message, commit
423449253 ("rename (resp_buf, form_buf) → (req_buf, resp_buf) in f5.c
and fortinet.c") added a 'flavor' field to a bunch of functions in
auth-html.c and passed it through from the protocol code to indicate
some protocol-specific quirks for form parsing.

Until then, we had mostly structured the code so that there weren't many
cases where 'core' code needed to behave differently depending on the
protocol. There was only one case, in fact, to handle the stupid Pulse
ESP address family bug. That one *used* to check which protocol was in
use by comparing proto->udp_send_probes with &oncp_esp_send_probes.

So, add an integer 'proto' field to struct vpn_proto so it can be
checked without a strcmp. Remove the now-redundant 'flavor' field from
all those functions in auth-html.c since it's now in the vpninfo, and
make the ESP code check that for NC|PULSE too instead of the trick of
checking the proto->udp_send_probes function. Which was kind of icky.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
auth-html.c
auth-juniper.c
esp.c
f5.c
library.c
openconnect-internal.h

index b5c150e52cddbd3a9c4be313d559b49b37c610da..9bf268e02e92a2a40e2b9e85b0f9608e17360632 100644 (file)
@@ -54,7 +54,7 @@ xmlNodePtr find_form_node(xmlDocPtr doc)
 }
 
 int parse_input_node(struct openconnect_info *vpninfo, struct oc_auth_form *form,
-                    xmlNodePtr node, const char *submit_button, int flavor,
+                    xmlNodePtr node, const char *submit_button,
                     int (*can_gen_tokencode)(struct openconnect_info *vpninfo, struct oc_auth_form *form, struct oc_form_opt *opt))
 {
        char *type = (char *)xmlGetProp(node, (unsigned char *)"type"), *style = (char *)xmlGetProp(node, (unsigned char *)"style");
@@ -93,12 +93,12 @@ int parse_input_node(struct openconnect_info *vpninfo, struct oc_auth_form *form
                        ret = -ENOMEM;
                        goto out;
                }
-               if (flavor == FORM_FLAVOR_JUNIPER &&
+               if (vpninfo->proto->proto == PROTO_NC &&
                    !strcmp(form->auth_id, "loginForm") &&
                    !strcmp(opt->name, "VerificationCode") &&
                    can_gen_tokencode && !can_gen_tokencode(vpninfo, form, opt))
                        opt->type = OC_FORM_OPT_TOKEN;
-       } else if (flavor == FORM_FLAVOR_JUNIPER && !strcasecmp(type, "submit")) {
+       } else if (vpninfo->proto->proto == PROTO_NC && !strcasecmp(type, "submit")) {
 
                xmlnode_get_prop(node, "name", &opt->name);
                if (opt->name && submit_button && (!strcmp(opt->name, submit_button) ||
@@ -149,7 +149,7 @@ int parse_input_node(struct openconnect_info *vpninfo, struct oc_auth_form *form
 }
 
 int parse_select_node(struct openconnect_info *vpninfo, struct oc_auth_form *form,
-                     xmlNodePtr node, int flavor)
+                     xmlNodePtr node)
 {
        xmlNodePtr child;
        struct oc_form_opt_select *opt;
@@ -162,8 +162,8 @@ int parse_select_node(struct openconnect_info *vpninfo, struct oc_auth_form *for
        xmlnode_get_prop(node, "name", &opt->form.name);
        opt->form.label = strdup(opt->form.name);
        opt->form.type = OC_FORM_OPT_SELECT;
-       if ((flavor == FORM_FLAVOR_JUNIPER && !strcmp(opt->form.name, "realm")) ||
-           (flavor == FORM_FLAVOR_F5 && !strcmp(opt->form.name, "domain")))
+       if ((vpninfo->proto->proto == PROTO_NC && !strcmp(opt->form.name, "realm")) ||
+           (vpninfo->proto->proto == PROTO_F5 && !strcmp(opt->form.name, "domain")))
                form->authgroup_opt = opt;
 
        for (child = node->children; child; child = child->next) {
@@ -196,7 +196,7 @@ int parse_select_node(struct openconnect_info *vpninfo, struct oc_auth_form *for
 }
 
 struct oc_auth_form *parse_form_node(struct openconnect_info *vpninfo,
-                                     xmlNodePtr node, const char *submit_button, int flavor,
+                                     xmlNodePtr node, const char *submit_button,
                                      int (*can_gen_tokencode)(struct openconnect_info *vpninfo, struct oc_auth_form *form, struct oc_form_opt *opt))
 {
        struct oc_auth_form *form = calloc(1, sizeof(*form));
@@ -215,12 +215,12 @@ struct oc_auth_form *parse_form_node(struct openconnect_info *vpninfo,
                return NULL;
        }
 
-       if (flavor == FORM_FLAVOR_JUNIPER) {
+       if (vpninfo->proto->proto == PROTO_NC) {
                /* XX: some forms have 'id', but no 'name' */
                if (!xmlnode_get_prop(node, "name", &form->auth_id) ||
                    !xmlnode_get_prop(node, "id", &form->auth_id))
                        form->banner = strdup(form->auth_id);
-       } else if (flavor == FORM_FLAVOR_F5)
+       } else if (vpninfo->proto->proto == PROTO_F5)
                xmlnode_get_prop(node, "id", &form->auth_id);
 
        /* XX: fallback auth_id (since other functions expect it to exist) */
@@ -232,13 +232,13 @@ struct oc_auth_form *parse_form_node(struct openconnect_info *vpninfo,
                        continue;
 
                if (!strcasecmp((char *)child->name, "input"))
-                       parse_input_node(vpninfo, form, child, submit_button, flavor, can_gen_tokencode);
+                       parse_input_node(vpninfo, form, child, submit_button, can_gen_tokencode);
                else if (!strcasecmp((char *)child->name, "select")) {
-                       parse_select_node(vpninfo, form, child, flavor);
+                       parse_select_node(vpninfo, form, child);
                        /* Skip its children */
                        while (child->children)
                                child = child->last;
-               } else if (flavor == FORM_FLAVOR_F5
+               } else if (vpninfo->proto->proto == PROTO_F5
                           && !strcasecmp((char *)child->name, "td")) {
 
                        char *id = (char *)xmlGetProp(child, (unsigned char *)"id");
@@ -257,7 +257,7 @@ struct oc_auth_form *parse_form_node(struct openconnect_info *vpninfo,
                        }
                        free(id);
 
-               } else if (flavor == FORM_FLAVOR_JUNIPER &&
+               } else if (vpninfo->proto->proto == PROTO_NC &&
                           !strcasecmp((char *)child->name, "textarea")) {
 
                        /* display the post sign-in message, if any */
index 1dc6d20580fadfb40a09f3fd4b7e2c1d15803980..8f30a3ba4b65158a305d8cefb247d68763f65c82 100644 (file)
@@ -519,14 +519,14 @@ int oncp_obtain_cookie(struct openconnect_info *vpninfo)
                                     _("Encountered form with no 'name' or 'id'\n"));
                        goto dump_form;
                } else if (form_name && !strcmp(form_name, "frmLogin")) {
-                       form = parse_form_node(vpninfo, node, "btnSubmit", FORM_FLAVOR_JUNIPER, oncp_can_gen_tokencode);
+                       form = parse_form_node(vpninfo, node, "btnSubmit", oncp_can_gen_tokencode);
                } else if (form_id && !strcmp(form_id, "loginForm")) {
-                       form = parse_form_node(vpninfo, node, "submitButton", FORM_FLAVOR_JUNIPER, oncp_can_gen_tokencode);
+                       form = parse_form_node(vpninfo, node, "submitButton", oncp_can_gen_tokencode);
                } else if ((form_name && !strcmp(form_name, "frmDefender")) ||
                           (form_name && !strcmp(form_name, "frmNextToken"))) {
-                       form = parse_form_node(vpninfo, node, "btnAction", FORM_FLAVOR_JUNIPER, oncp_can_gen_tokencode);
+                       form = parse_form_node(vpninfo, node, "btnAction", oncp_can_gen_tokencode);
                } else if (form_name && !strcmp(form_name, "frmConfirmation")) {
-                       form = parse_form_node(vpninfo, node, "btnContinue", FORM_FLAVOR_JUNIPER, oncp_can_gen_tokencode);
+                       form = parse_form_node(vpninfo, node, "btnContinue", oncp_can_gen_tokencode);
                        if (!form) {
                                ret = -EINVAL;
                                break;
@@ -537,10 +537,10 @@ int oncp_obtain_cookie(struct openconnect_info *vpninfo)
                        form = parse_roles_form_node(node);
                        role_select = 1;
                } else if (form_name && !strcmp(form_name, "frmTotpToken")) {
-                       form = parse_form_node(vpninfo, node, "totpactionEnter", FORM_FLAVOR_JUNIPER, oncp_can_gen_tokencode);
+                       form = parse_form_node(vpninfo, node, "totpactionEnter", oncp_can_gen_tokencode);
                } else if ((form_name && !strcmp(form_name, "hiddenform")) ||
                           (form_id && !strcmp(form_id, "formSAMLSSO"))) {
-                       form = parse_form_node(vpninfo, node, "submit", FORM_FLAVOR_JUNIPER, oncp_can_gen_tokencode);
+                       form = parse_form_node(vpninfo, node, "submit", oncp_can_gen_tokencode);
                } else {
                        char *form_action = (char *)xmlGetProp(node, (unsigned char *)"action");
                        if (form_action && strstr(form_action, "remediate.cgi")) {
diff --git a/esp.c b/esp.c
index 03f383431de091b7bc10c355a7c8c81dce6e45ca..385110c101ab5db6c0dfb9d346f35acd779d68af 100644 (file)
--- a/esp.c
+++ b/esp.c
@@ -306,7 +306,8 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
                        if (!this)
                                break;
 
-                       if (vpninfo->proto->udp_send_probes == oncp_esp_send_probes) {
+                       if (vpninfo->proto->proto == PROTO_NC ||
+                           vpninfo->proto->proto == PROTO_PULSE) {
                                uint8_t dontsend;
 
                                /* Pulse/NC can only accept ESP of the same protocol as the one
diff --git a/f5.c b/f5.c
index bbf8e48d143615412cdc70abf12640f69280c02b..7023d99f31c9d4366f990ccd3f069709953a2b0d 100644 (file)
--- a/f5.c
+++ b/f5.c
@@ -148,7 +148,7 @@ int f5_obtain_cookie(struct openconnect_info *vpninfo)
                        if ((form = plain_auth_form()) == NULL)
                                goto nomem;
                } else {
-                       form = parse_form_node(vpninfo, node, NULL, FORM_FLAVOR_F5, NULL);
+                       form = parse_form_node(vpninfo, node, NULL, NULL);
                        if (form_order==1 && (xmlnode_get_prop(node, "id", &form_id) || strcmp(form_id, "auth_form"))) {
                                vpn_progress(vpninfo, PRG_ERR, _("Unknown form ID '%s' (expected 'auth_form')\n"),
                                             form_id);
index cd407d4bcde48f569bdc08cc67d05d9bdab16bfa..4aca1d593a94cd0a7cb98c4a99ecdaff3fd84e9d 100644 (file)
--- a/library.c
+++ b/library.c
@@ -116,6 +116,7 @@ static const struct vpn_proto openconnect_protos[] = {
                .name = "anyconnect",
                .pretty_name = N_("Cisco AnyConnect or openconnect"),
                .description = N_("Compatible with Cisco AnyConnect SSL VPN, as well as ocserv"),
+               .proto = PROTO_ANYCONNECT,
                .flags = OC_PROTO_PROXY | OC_PROTO_CSD | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN,
                .vpn_close_session = cstp_bye,
                .tcp_connect = cstp_connect,
@@ -134,6 +135,7 @@ static const struct vpn_proto openconnect_protos[] = {
                .name = "nc",
                .pretty_name = N_("Juniper Network Connect"),
                .description = N_("Compatible with Juniper Network Connect"),
+               .proto = PROTO_NC,
                .flags = OC_PROTO_PROXY | OC_PROTO_CSD | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_PERIODIC_TROJAN,
                .vpn_close_session = oncp_bye,
                .tcp_connect = oncp_connect,
@@ -154,6 +156,7 @@ static const struct vpn_proto openconnect_protos[] = {
                .name = "gp",
                .pretty_name = N_("Palo Alto Networks GlobalProtect"),
                .description = N_("Compatible with Palo Alto Networks (PAN) GlobalProtect SSL VPN"),
+               .proto = PROTO_GPST,
                .flags = OC_PROTO_PROXY | OC_PROTO_CSD | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN | OC_PROTO_PERIODIC_TROJAN,
                .vpn_close_session = gpst_bye,
                .tcp_connect = gpst_setup,
@@ -173,6 +176,7 @@ static const struct vpn_proto openconnect_protos[] = {
                .name = "pulse",
                .pretty_name = N_("Pulse Connect Secure"),
                .description = N_("Compatible with Pulse Connect Secure SSL VPN"),
+               .proto = PROTO_PULSE,
                .flags = OC_PROTO_PROXY | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN,
                .vpn_close_session = pulse_bye,
                .tcp_connect = pulse_connect,
@@ -192,6 +196,7 @@ static const struct vpn_proto openconnect_protos[] = {
                .name = "f5",
                .pretty_name = N_("F5 BIG-IP SSL VPN"),
                .description = N_("Compatible with F5 BIG-IP SSL VPN"),
+               .proto = PROTO_F5,
                .flags = OC_PROTO_PROXY | OC_PROTO_AUTH_CERT,
                .vpn_close_session = f5_bye,
                .tcp_connect = f5_connect,
@@ -212,6 +217,7 @@ static const struct vpn_proto openconnect_protos[] = {
                .name = "fortinet",
                .pretty_name = N_("Fortinet SSL VPN"),
                .description = N_("Compatible with FortiGate SSL VPN"),
+               .proto = PROTO_FORTINET,
                .flags = OC_PROTO_PROXY | OC_PROTO_AUTH_CERT | OC_PROTO_AUTH_OTP | OC_PROTO_AUTH_STOKEN,
                .vpn_close_session = fortinet_bye,
                .tcp_connect = fortinet_connect,
@@ -232,6 +238,7 @@ static const struct vpn_proto openconnect_protos[] = {
                .name = "nullppp",
                .pretty_name = N_("PPP over TLS"),
                .description = N_("Unauthenticated RFC1661/RFC1662 PPP over TLS, for testing"),
+               .proto = PROTO_NULLPPP,
                .flags = OC_PROTO_PROXY | OC_PROTO_HIDDEN,
                .tcp_connect = nullppp_connect,
                .tcp_mainloop = nullppp_mainloop,
index 93b30c6485dce9908c840900e106af999be2e4c3..ca77770a57f43dc69ee28789631ee9b982749812 100644 (file)
@@ -193,10 +193,14 @@ struct pkt {
 #define DTLS_CONNECTING        4       /* ESP probe received; must tell server */
 #define DTLS_CONNECTED 5       /* Server informed and should be sending ESP */
 
-/* Flavors of HTML forms to screen-scrape */
-#define FORM_FLAVOR_JUNIPER    1
-#define FORM_FLAVOR_F5         2
-#define FORM_FLAVOR_FORTINET   3
+/* Not to be confused with OC_PROTO_xxx flags which are library-visible */
+#define PROTO_ANYCONNECT       0
+#define PROTO_NC               1
+#define PROTO_GPST             2
+#define PROTO_PULSE            3
+#define PROTO_F5               4
+#define PROTO_FORTINET         5
+#define PROTO_NULLPPP          6
 
 /* All supported PPP packet framings/encapsulations */
 #define PPP_ENCAP_RFC1661      1       /* Plain/synchronous/pre-framed PPP (RFC1661) */
@@ -304,6 +308,7 @@ struct vpn_proto {
        const char *description;
        const char *secure_cookie;
        const char *udp_protocol;
+       int proto;
        unsigned int flags;
        int (*vpn_close_session)(struct openconnect_info *vpninfo, const char *reason);
 
@@ -977,17 +982,17 @@ int decompress_and_queue_packet(struct openconnect_info *vpninfo, int compr_type
                                unsigned char *buf, int len);
 int compress_packet(struct openconnect_info *vpninfo, int compr_type, struct pkt *this);
 
-/* html-auth.c */
+/* auth-html.c */
 xmlNodePtr htmlnode_next(xmlNodePtr top, xmlNodePtr node);
 xmlNodePtr htmlnode_dive(xmlNodePtr top, xmlNodePtr node);
 xmlNodePtr find_form_node(xmlDocPtr doc);
 int parse_input_node(struct openconnect_info *vpninfo, struct oc_auth_form *form,
-                    xmlNodePtr node, const char *submit_button, int flavor,
+                    xmlNodePtr node, const char *submit_button,
                     int (*can_gen_tokencode)(struct openconnect_info *vpninfo, struct oc_auth_form *form, struct oc_form_opt *opt));
 int parse_select_node(struct openconnect_info *vpninfo, struct oc_auth_form *form,
-                     xmlNodePtr node, int flavor);
+                     xmlNodePtr node);
 struct oc_auth_form *parse_form_node(struct openconnect_info *vpninfo,
-                                    xmlNodePtr node, const char *submit_button, int flavor,
+                                    xmlNodePtr node, const char *submit_button,
                                     int (*can_gen_tokencode)(struct openconnect_info *vpninfo, struct oc_auth_form *form, struct oc_form_opt *opt));
 
 /* auth-juniper.c */