diff options
author | David Woodhouse <dwmw2@infradead.org> | 2023-05-11 12:34:43 +0100 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2023-05-11 13:15:53 +0100 |
commit | ddce34054e5145c88367da42ce1e0e73fa00a10b (patch) | |
tree | 29133ec5738d554ab72e28cdef058514dc21b5ca | |
parent | f791b98284c3b6037e74b7e487aa02e6ad38a1cf (diff) |
libnmc-base: fix port extraction for openconnect auth
With old versions of openconnect we need to extract the port# from the
initial URL and then append it to the hostname we eventually get back.
Using strrchr(gw, ':') isn't going to work right with IPv6 literals,
ad we should also be dropping any path element.
So switch to using an int for the port instead of a string, and import a
cut-down variant of openconnect's internal_parse_url() which does
*largely* the same thing with strrchr() but is saved by using the 'end'
value returned from strtol() and insisting that the port is the very
end of the host part of the URL.
-rw-r--r-- | src/libnmc-base/nm-vpn-helpers.c | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/src/libnmc-base/nm-vpn-helpers.c b/src/libnmc-base/nm-vpn-helpers.c index 1a43fbc1a0..10e2e0e696 100644 --- a/src/libnmc-base/nm-vpn-helpers.c +++ b/src/libnmc-base/nm-vpn-helpers.c @@ -233,6 +233,46 @@ struct { #define NR_OC_STRING_PROPS (sizeof(oc_property_args) / sizeof(oc_property_args[0])) #define OC_ARGS_MAX (12 + 2 * NR_OC_STRING_PROPS) +/* + * For old versions of openconnect we need to extract the port# and + * append it to the hostname that is returned to us. Use a cut-down + * version of openconnect's own internal_parse_url() function. + */ +static int +extract_url_port(const char *url) +{ + const char *host, *port_str, *path; + char *end; + int port_nr; + + /* Skip the scheme, if present */ + host = strstr(url, "://"); + if (host) + host += 3; + else + host = url; + + port_str = strrchr(host, ':'); + if (!port_str) + return 0; + + /* + * If the host is an IPv6 literal, port_str may point somewhere + * inside it rather than to an actual port#. But IPv6 literals + * are always enclosed in [], e.g. '[fec0::1]:443'. So we check + * that the end pointer returned by strtol points exactly to the + * end of the hostname (either the end of the string, or to the + * first '/' of the path element if there is one). + */ + path = strchr(host, '/'); + port_nr = strtol(port_str + 1, &end, 10); + + if (end == path || (!path && !*end)) + return port_nr; + + return 0; +} + gboolean nm_vpn_openconnect_authenticate_helper(NMSettingVpn *s_vpn, GPtrArray *secrets, GError **error) { @@ -256,7 +296,8 @@ nm_vpn_openconnect_authenticate_helper(NMSettingVpn *s_vpn, GPtrArray *secrets, "/usr/local/bin/", NULL, }; - const char *gw, *port; + int port = 0; + const char *gw; const char *oc_argv[OC_ARGS_MAX]; int i, oc_argc = 0; @@ -270,7 +311,7 @@ nm_vpn_openconnect_authenticate_helper(NMSettingVpn *s_vpn, GPtrArray *secrets, return FALSE; } - port = strrchr(gw, ':'); + port = extract_url_port(gw); path = nm_utils_file_search_in_paths("openconnect", "/usr/sbin/openconnect", @@ -407,7 +448,7 @@ nm_vpn_openconnect_authenticate_helper(NMSettingVpn *s_vpn, GPtrArray *secrets, if (connect_url) secret->value = g_steal_pointer(&connect_url); else if (port) - secret->value = g_strdup_printf("%s%s", legacy_host, port); + secret->value = g_strdup_printf("%s:%d", legacy_host, port); else secret->value = g_steal_pointer(&legacy_host); } else if (nm_streq0(secret->entry_id, |