summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2023-05-11 12:34:43 +0100
committerDavid Woodhouse <dwmw2@infradead.org>2023-05-11 13:15:53 +0100
commitddce34054e5145c88367da42ce1e0e73fa00a10b (patch)
tree29133ec5738d554ab72e28cdef058514dc21b5ca
parentf791b98284c3b6037e74b7e487aa02e6ad38a1cf (diff)
downloadNetworkManager-ddce34054e5145c88367da42ce1e0e73fa00a10b.tar.gz
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.c47
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,