diff --git a/.NetworkManager-libreswan.metadata b/.NetworkManager-libreswan.metadata index 2188a15..1ffe5e5 100644 --- a/.NetworkManager-libreswan.metadata +++ b/.NetworkManager-libreswan.metadata @@ -1 +1 @@ -7f62450f66f2a21789fd6cfebbf3355ae99553ea SOURCES/NetworkManager-libreswan-1.2.22.tar.xz +14cb2d2927fea678b7421da5e28874d78ad8fdc8 SOURCES/NetworkManager-libreswan-1.2.27.tar.xz diff --git a/.gitignore b/.gitignore index 6fe0fdb..f49011e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/NetworkManager-libreswan-1.2.22.tar.xz +SOURCES/NetworkManager-libreswan-1.2.27.tar.xz diff --git a/SOURCES/0001-Export-esp-option.patch b/SOURCES/0001-Export-esp-option.patch new file mode 100644 index 0000000..52f4822 --- /dev/null +++ b/SOURCES/0001-Export-esp-option.patch @@ -0,0 +1,43 @@ +From ce3b4049ce916d23b7c8e57d43765e7eb044779b Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Mon, 13 Oct 2025 17:48:07 +0800 +Subject: [PATCH] Export `esp` option + +Unit test case updated. + +Resolves: https://issues.redhat.com/browse/RHEL-119653 + +Signed-off-by: Gris Ge +--- + shared/test-utils.c | 1 + + shared/utils.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/shared/test-utils.c b/shared/test-utils.c +index 76c903e..16a96d1 100644 +--- a/shared/test-utils.c ++++ b/shared/test-utils.c +@@ -199,6 +199,7 @@ test_config_write (void) + " salifetime=24h\n" + " rightsubnet=0.0.0.0/0\n" + " rekey=yes\n" ++ " esp=aes_gcm256\n" + " phase2alg=aes_gcm256\n" + " keyingtries=1\n" + " leftxauthclient=yes\n" +diff --git a/shared/utils.c b/shared/utils.c +index cdaaaf0..ac735a5 100644 +--- a/shared/utils.c ++++ b/shared/utils.c +@@ -338,7 +338,7 @@ static const struct LibreswanParam params[] = { + + /* Special. */ + { NM_LIBRESWAN_KEY_REKEY, add_rekey, PARAM_PRINTABLE }, +- { NM_LIBRESWAN_KEY_ESP, add }, ++ { NM_LIBRESWAN_KEY_ESP, add, PARAM_PRINTABLE }, + + /* Used internally or just ignored altogether. */ + { NM_LIBRESWAN_KEY_VENDOR, add, PARAM_IGNORE }, +-- +2.51.0 + diff --git a/SOURCES/0001-ipsec-conf-escaping-cve-2024-9050.patch b/SOURCES/0001-ipsec-conf-escaping-cve-2024-9050.patch deleted file mode 100644 index e7f78e4..0000000 --- a/SOURCES/0001-ipsec-conf-escaping-cve-2024-9050.patch +++ /dev/null @@ -1,1691 +0,0 @@ -From f9f321fc00f9016569a592140d9e5a24f9c4db01 Mon Sep 17 00:00:00 2001 -From: Lubomir Rintel -Date: Fri, 13 Sep 2024 14:49:12 +0200 -Subject: [PATCH 1/6] shared/nm-glib: import newer g_steal_pointer() - -The version that's there doesn't work with current glib, still -considering g_steal_pointer() deprecated. - -We should probably do a full import, but it's became such a mess -in NetworkManager.git that it's not feasible at this point. - -[lkundrak@v3.sk: Backported from 1.24.0] ---- - shared/nm-utils/nm-glib.h | 32 +++++++++++++++++--------------- - 1 file changed, 17 insertions(+), 15 deletions(-) - -diff --git a/shared/nm-utils/nm-glib.h b/shared/nm-utils/nm-glib.h -index 770cf0f..1b6487c 100644 ---- a/shared/nm-utils/nm-glib.h -+++ b/shared/nm-utils/nm-glib.h -@@ -412,24 +412,26 @@ _nm_g_hash_table_get_keys_as_array (GHashTable *hash_table, - - /*****************************************************************************/ - --#if !GLIB_CHECK_VERSION(2, 44, 0) --static inline gpointer --g_steal_pointer (gpointer pp) --{ -- gpointer *ptr = (gpointer *) pp; -- gpointer ref; -+#define _NM_ENSURE_POINTER(value) \ -+ do { \ -+ _nm_unused const void *const _unused_for_type_check = 0 ? (value) : NULL; \ -+ } while (0) - -- ref = *ptr; -- *ptr = NULL; -- -- return ref; --} -- --/* type safety */ --#define g_steal_pointer(pp) \ -- (0 ? (*(pp)) : (g_steal_pointer) (pp)) -+#ifdef g_steal_pointer -+#undef g_steal_pointer - #endif - -+#define g_steal_pointer(pp) \ -+ ({ \ -+ typeof(*(pp)) *const _pp = (pp); \ -+ typeof(*_pp) _p = *_pp; \ -+ \ -+ _NM_ENSURE_POINTER(_p); \ -+ \ -+ *_pp = NULL; \ -+ _p; \ -+ }) -+ - /*****************************************************************************/ - - static inline gboolean --- -2.46.0 - -From 72816f82b029063e4d8aaff6703f175da5232293 Mon Sep 17 00:00:00 2001 -From: Lubomir Rintel -Date: Tue, 17 Sep 2024 13:28:58 +0200 -Subject: [PATCH 2/6] build: get rid of {properties,src}/libutils.la - -Useless build of an extra libraries, just making the build slower and -more complicated. Get rid of then, and just roll src/libutils.la. - -[lkundrak@v3.sk: Backported from 1.24.0] ---- - Makefile.am | 69 +++++++++++++++++++++-------------------------------- - 1 file changed, 27 insertions(+), 42 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 29084a9..d46cfcd 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -33,6 +33,26 @@ nmvpnservice_DATA = nm-libreswan-service.name - - ############################################################################### - -+noinst_LTLIBRARIES += shared/libutils.la -+ -+shared_libutils_la_SOURCES = \ -+ shared/nm-utils/nm-shared-utils.c \ -+ shared/nm-utils/nm-shared-utils.h \ -+ shared/utils.c \ -+ shared/utils.h \ -+ shared/nm-service-defines.h -+ -+shared_libutils_la_CFLAGS = \ -+ -DPREFIX=\""$(prefix)"\" \ -+ $(common_CFLAGS) \ -+ $(LIBNM_CFLAGS) -+ -+shared_libutils_la_LIBADD = \ -+ $(GLIB_LIBS) \ -+ $(LIBNM_LIBS) -+ -+############################################################################### -+ - properties/resources.h: properties/gresource.xml - $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< --target=$@ --sourcedir=$(srcdir)/properties --generate-header --internal - -@@ -53,10 +73,6 @@ gtk4/%.ui: properties/%.ui - EXTRA_DIST += \ - gtk4/nm-libreswan-dialog.ui - --plugin_sources = \ -- properties/nm-libreswan-editor-plugin.c \ -- properties/nm-libreswan-editor-plugin.h -- - editor_sources = \ - properties/nm-libreswan-editor.c \ - properties/nm-libreswan-editor.h -@@ -68,23 +84,6 @@ common_CFLAGS = \ - - ############################################################################### - --noinst_LTLIBRARIES += properties/libutils.la -- --properties_libutils_la_SOURCES = \ -- shared/utils.c \ -- shared/utils.h \ -- shared/nm-utils/nm-vpn-plugin-utils.c \ -- shared/nm-utils/nm-vpn-plugin-utils.h \ -- shared/nm-utils/nm-shared-utils.c \ -- shared/nm-utils/nm-shared-utils.h \ -- shared/nm-service-defines.h -- --properties_libutils_la_CPPFLAGS = \ -- -DPREFIX=\""$(prefix)"\" \ -- -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIB_BASE \ -- $(common_CFLAGS) \ -- $(LIBNM_CFLAGS) -- - plugin_LTLIBRARIES += properties/libnm-vpn-plugin-libreswan.la - - properties_libnm_vpn_plugin_libreswan_la_CFLAGS = \ -@@ -93,10 +92,13 @@ properties_libnm_vpn_plugin_libreswan_la_CFLAGS = \ - $(LIBNM_CFLAGS) - - properties_libnm_vpn_plugin_libreswan_la_SOURCES = \ -- $(plugin_sources) -+ shared/nm-utils/nm-vpn-plugin-utils.c \ -+ shared/nm-utils/nm-vpn-plugin-utils.h \ -+ properties/nm-libreswan-editor-plugin.c \ -+ properties/nm-libreswan-editor-plugin.h - - properties_libnm_vpn_plugin_libreswan_la_LIBADD = \ -- properties/libutils.la \ -+ shared/libutils.la \ - $(LIBNM_LIBS) \ - $(DL_LIBS) - -@@ -198,7 +200,6 @@ auth_dialog_nm_libreswan_auth_dialog_LDADD = \ - - src_cppflags = \ - -DBINDIR=\"$(bindir)\" \ -- -DPREFIX=\""$(prefix)"\" \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DLOCALSTATEDIR=\""$(localstatedir)"\" \ -@@ -230,22 +231,6 @@ src/nm-libreswan-helper-service-dbus.h: src/nm-libreswan-helper-service.xml - src/nm-libreswan-helper-service-dbus.c: src/nm-libreswan-helper-service-dbus.h - @true - --noinst_LTLIBRARIES += src/libutils.la -- --src_libutils_la_SOURCES = \ -- shared/nm-utils/nm-shared-utils.c \ -- shared/nm-utils/nm-shared-utils.h \ -- shared/utils.c \ -- shared/utils.h \ -- shared/nm-service-defines.h -- --src_libutils_la_CPPFLAGS = \ -- $(src_cppflags) -- --src_libutils_la_LIBADD = \ -- $(GLIB_LIBS) \ -- $(LIBNM_LIBS) -- - ############################################################################### - - libexec_PROGRAMS += src/nm-libreswan-service -@@ -255,7 +240,7 @@ src_nm_libreswan_service_CPPFLAGS = \ - - src_nm_libreswan_service_LDADD = \ - src/libnm-libreswan-helper-service-dbus.la \ -- src/libutils.la \ -+ shared/libutils.la \ - $(GLIB_LIBS) \ - $(LIBNM_LIBS) \ - $(LIBNL_LIBS) \ -@@ -272,7 +257,7 @@ src_nm_libreswan_service_helper_CPPFLAGS = \ - - src_nm_libreswan_service_helper_LDADD = \ - src/libnm-libreswan-helper-service-dbus.la \ -- src/libutils.la \ -+ shared/libutils.la \ - $(GLIB_LIBS) \ - $(LIBNM_LIBS) - --- -2.46.0 - -From cf9777bd065ddc40c627e1d994432e95b1e70a82 Mon Sep 17 00:00:00 2001 -From: Lubomir Rintel -Date: Mon, 23 Sep 2024 11:39:22 +0200 -Subject: [PATCH 3/6] shared/test-utils: cover config write with unit tests - -Test that we generate good configuration for typical IKEv1 and IKEv2 -cases. - -[lkundrak@v3.sk: Backported from 1.24.0] ---- - Makefile.am | 16 ++++++ - shared/test-utils.c | 127 ++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 143 insertions(+) - create mode 100644 shared/test-utils.c - -diff --git a/Makefile.am b/Makefile.am -index d46cfcd..3f4e85c 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -21,6 +21,8 @@ libexec_PROGRAMS = - - noinst_PROGRAMS = - -+TESTS = -+ - SUBDIRS = po man - - ############################################################################### -@@ -51,6 +53,20 @@ shared_libutils_la_LIBADD = \ - $(GLIB_LIBS) \ - $(LIBNM_LIBS) - -+noinst_PROGRAMS += shared/test-utils -+ -+TESTS += shared/test-utils -+ -+shared_test_utils_SOURCES = shared/test-utils.c -+ -+shared_test_utils_CFLAGS = \ -+ $(common_CFLAGS) \ -+ $(LIBNM_CFLAGS) -+ -+shared_test_utils_LDADD = \ -+ shared/libutils.la \ -+ $(LIBNM_LIBS) -+ - ############################################################################### - - properties/resources.h: properties/gresource.xml -diff --git a/shared/test-utils.c b/shared/test-utils.c -new file mode 100644 -index 0000000..82ee933 ---- /dev/null -+++ b/shared/test-utils.c -@@ -0,0 +1,127 @@ -+#include "nm-default.h" -+ -+#include "utils.h" -+ -+#include -+ -+static char * -+_setting_into_ipsec_conf (NMSetting *s_vpn, const char *name, GError **error) -+{ -+ gs_unref_object NMConnection *connection = NULL; -+ gs_unref_object GFile *tmp = NULL; -+ GFileIOStream *tmpstream; -+ char buf[4096]; -+ gboolean res; -+ gsize count; -+ gint fd; -+ -+ connection = nm_simple_connection_new (); -+ nm_connection_add_setting (connection, s_vpn); -+ -+ tmp = g_file_new_tmp (NULL, &tmpstream, error); -+ if (tmp == NULL) -+ return NULL; -+ -+ res = g_file_delete (tmp, NULL, error); -+ if (res == FALSE) -+ return NULL; -+ -+ fd = g_file_descriptor_based_get_fd(G_FILE_DESCRIPTOR_BASED( -+ g_io_stream_get_output_stream(G_IO_STREAM (tmpstream)))); -+ -+ res = nm_libreswan_config_write (fd, 4, connection, -+ name, NULL, -+ FALSE, TRUE, NULL, -+ error); -+ if (res == FALSE) -+ return NULL; -+ -+ res = g_seekable_seek (G_SEEKABLE(tmpstream), -+ 0, G_SEEK_SET, NULL, error); -+ if (res == FALSE) -+ return NULL; -+ -+ res = g_input_stream_read_all ( -+ g_io_stream_get_input_stream(G_IO_STREAM (tmpstream)), -+ buf, -+ sizeof(buf)-1, -+ &count, -+ NULL, -+ error); -+ if (res == FALSE) -+ return NULL; -+ -+ buf[count] = '\0'; -+ return g_strdup(buf); -+} -+ -+static void -+test_config_write (void) -+{ -+ GError *error = NULL; -+ NMSetting *s_vpn; -+ char *str; -+ -+ s_vpn = nm_setting_vpn_new (); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "right", "11.12.13.14"); -+ str = _setting_into_ipsec_conf (s_vpn, "con_name", &error); -+ g_assert_no_error (error); -+ g_assert_cmpstr (str, ==, -+ "conn con_name\n" -+ " authby=secret\n" -+ " left=%defaultroute\n" -+ " leftmodecfgclient=yes\n" -+ " right=11.12.13.14\n" -+ " rightmodecfgserver=yes\n" -+ " modecfgpull=yes\n" -+ " rightsubnet=0.0.0.0/0\n" -+ " leftxauthclient=yes\n" -+ " remote-peer-type=cisco\n" -+ " rightxauthserver=yes\n" -+ " ikelifetime=24h\n" -+ " salifetime=24h\n" -+ " rekey=yes\n" -+ " keyingtries=1\n" -+ " ikev2=never\n" -+ " nm-configured=yes\n" -+ " auto=add\n"); -+ g_free (str); -+ -+ s_vpn = nm_setting_vpn_new (); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "ikev2", "insist"); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "leftcert", "LibreswanClient"); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "leftid", "%fromcert"); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "right", "11.12.13.14"); -+ str = _setting_into_ipsec_conf (s_vpn, -+ "f0008435-07af-4836-a53d-b43e8730e68f", -+ &error); -+ g_assert_no_error (error); -+ g_assert_cmpstr (str, ==, -+ "conn f0008435-07af-4836-a53d-b43e8730e68f\n" -+ " leftid=%fromcert\n" -+ " leftcert=LibreswanClient\n" -+ " leftrsasigkey=%cert\n" -+ " rightrsasigkey=%cert\n" -+ " left=%defaultroute\n" -+ " leftmodecfgclient=yes\n" -+ " right=11.12.13.14\n" -+ " rightmodecfgserver=yes\n" -+ " modecfgpull=yes\n" -+ " rightsubnet=0.0.0.0/0\n" -+ " rekey=yes\n" -+ " keyingtries=1\n" -+ " ikev2=insist\n" -+ " nm-configured=yes\n" -+ " auto=add\n"); -+ g_free (str); -+} -+ -+int -+main (int argc, char **argv) -+{ -+ g_test_init (&argc, &argv, NULL); -+ -+ g_test_add_func ("/utils/config/write", test_config_write); -+ -+ return g_test_run (); -+} --- -2.46.0 - -From 2b07bfeec5e67cbdce9b23b7c0648cb0ee55416d Mon Sep 17 00:00:00 2001 -From: Lubomir Rintel -Date: Sun, 22 Sep 2024 14:20:22 +0200 -Subject: [PATCH 4/6] all: rework formatting of ipsec.conf - -Simplify the interface and validate each item carefully. - -Note this fixes a security issue (CVE-2024-9050), with an "Important" -impact severity, where insufficient validation could lead to injection -of potentialy malicious values into the ipsec.conf snippet we send over -to pluto. - -https://issues.redhat.com/browse/RHEL-59565 - -[lkundrak@v3.sk: Backported from 1.24.0] ---- - properties/nm-libreswan-editor-plugin.c | 30 +- - shared/test-utils.c | 97 +---- - shared/utils.c | 491 ++++++++++++++---------- - shared/utils.h | 28 +- - src/nm-libreswan-service.c | 183 +++++---- - 5 files changed, 423 insertions(+), 406 deletions(-) - -diff --git a/properties/nm-libreswan-editor-plugin.c b/properties/nm-libreswan-editor-plugin.c -index fe473d1..9393212 100644 ---- a/properties/nm-libreswan-editor-plugin.c -+++ b/properties/nm-libreswan-editor-plugin.c -@@ -286,19 +286,11 @@ export_to_file (NMVpnEditorPlugin *self, - { - NMSettingVpn *s_vpn; - gboolean openswan = FALSE; -- int fd, errsv; - gs_free_error GError *local = NULL; -+ gs_free char *ipsec_conf = NULL; - gboolean is_openswan; - int version; - -- fd = g_open (path, O_WRONLY | O_CREAT, 0666); -- if (fd == -1) { -- errsv = errno; -- g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED, -- _("Can’t open file “%s”: %s"), path, g_strerror (errsv)); -- return FALSE; -- } -- - s_vpn = nm_connection_get_setting_vpn (connection); - if (s_vpn) - openswan = nm_streq (nm_setting_vpn_get_service_type (s_vpn), NM_VPN_SERVICE_TYPE_OPENSWAN); -@@ -306,24 +298,18 @@ export_to_file (NMVpnEditorPlugin *self, - nm_libreswan_detect_version (nm_libreswan_find_helper_bin ("ipsec", NULL), - &is_openswan, &version, NULL); - -- if (!nm_libreswan_config_write (fd, -- version, -- connection, -- nm_connection_get_id (connection), -- NULL, -- openswan, -- TRUE, -- NULL, -- &local)) { -- g_close (fd, NULL); -+ ipsec_conf = nm_libreswan_get_ipsec_conf (version, s_vpn, -+ nm_connection_get_id (connection), -+ NULL, openswan, TRUE, error); -+ if (ipsec_conf == NULL) -+ return FALSE; -+ -+ if (!g_file_set_contents (path, ipsec_conf, -1, &local)) { - g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED, - _("Error writing to file “%s”: %s"), path, local->message); - return FALSE; - } - -- if (!g_close (fd, error)) -- return FALSE; -- - return TRUE; - } - -diff --git a/shared/test-utils.c b/shared/test-utils.c -index 82ee933..49aa32a 100644 ---- a/shared/test-utils.c -+++ b/shared/test-utils.c -@@ -2,117 +2,60 @@ - - #include "utils.h" - --#include -- --static char * --_setting_into_ipsec_conf (NMSetting *s_vpn, const char *name, GError **error) --{ -- gs_unref_object NMConnection *connection = NULL; -- gs_unref_object GFile *tmp = NULL; -- GFileIOStream *tmpstream; -- char buf[4096]; -- gboolean res; -- gsize count; -- gint fd; -- -- connection = nm_simple_connection_new (); -- nm_connection_add_setting (connection, s_vpn); -- -- tmp = g_file_new_tmp (NULL, &tmpstream, error); -- if (tmp == NULL) -- return NULL; -- -- res = g_file_delete (tmp, NULL, error); -- if (res == FALSE) -- return NULL; -- -- fd = g_file_descriptor_based_get_fd(G_FILE_DESCRIPTOR_BASED( -- g_io_stream_get_output_stream(G_IO_STREAM (tmpstream)))); -- -- res = nm_libreswan_config_write (fd, 4, connection, -- name, NULL, -- FALSE, TRUE, NULL, -- error); -- if (res == FALSE) -- return NULL; -- -- res = g_seekable_seek (G_SEEKABLE(tmpstream), -- 0, G_SEEK_SET, NULL, error); -- if (res == FALSE) -- return NULL; -- -- res = g_input_stream_read_all ( -- g_io_stream_get_input_stream(G_IO_STREAM (tmpstream)), -- buf, -- sizeof(buf)-1, -- &count, -- NULL, -- error); -- if (res == FALSE) -- return NULL; -- -- buf[count] = '\0'; -- return g_strdup(buf); --} -- - static void - test_config_write (void) - { - GError *error = NULL; -- NMSetting *s_vpn; -+ NMSettingVpn *s_vpn; - char *str; - -- s_vpn = nm_setting_vpn_new (); -+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); - nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "right", "11.12.13.14"); -- str = _setting_into_ipsec_conf (s_vpn, "con_name", &error); -+ str = nm_libreswan_get_ipsec_conf (4, s_vpn, "con_name", NULL, FALSE, TRUE, &error); - g_assert_no_error (error); - g_assert_cmpstr (str, ==, - "conn con_name\n" -+ " ikev2=never\n" -+ " right=11.12.13.14\n" - " authby=secret\n" - " left=%defaultroute\n" - " leftmodecfgclient=yes\n" -- " right=11.12.13.14\n" -- " rightmodecfgserver=yes\n" -- " modecfgpull=yes\n" - " rightsubnet=0.0.0.0/0\n" - " leftxauthclient=yes\n" - " remote-peer-type=cisco\n" - " rightxauthserver=yes\n" - " ikelifetime=24h\n" - " salifetime=24h\n" -- " rekey=yes\n" - " keyingtries=1\n" -- " ikev2=never\n" -- " nm-configured=yes\n" -- " auto=add\n"); -+ " rekey=yes\n" -+ " rightmodecfgserver=yes\n" -+ " modecfgpull=yes\n"); - g_free (str); - -- s_vpn = nm_setting_vpn_new (); -+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); - nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "ikev2", "insist"); - nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "leftcert", "LibreswanClient"); - nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "leftid", "%fromcert"); - nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "right", "11.12.13.14"); -- str = _setting_into_ipsec_conf (s_vpn, -- "f0008435-07af-4836-a53d-b43e8730e68f", -- &error); -+ str = nm_libreswan_get_ipsec_conf (4, s_vpn, -+ "f0008435-07af-4836-a53d-b43e8730e68f", -+ NULL, FALSE, TRUE, &error); - g_assert_no_error (error); - g_assert_cmpstr (str, ==, - "conn f0008435-07af-4836-a53d-b43e8730e68f\n" -+ " ikev2=insist\n" -+ " right=11.12.13.14\n" - " leftid=%fromcert\n" -- " leftcert=LibreswanClient\n" -- " leftrsasigkey=%cert\n" -- " rightrsasigkey=%cert\n" -+ " leftcert=\"LibreswanClient\"\n" -+ " leftrsasigkey=\"%cert\"\n" -+ " rightrsasigkey=\"%cert\"\n" - " left=%defaultroute\n" - " leftmodecfgclient=yes\n" -- " right=11.12.13.14\n" -- " rightmodecfgserver=yes\n" -- " modecfgpull=yes\n" - " rightsubnet=0.0.0.0/0\n" -- " rekey=yes\n" - " keyingtries=1\n" -- " ikev2=insist\n" -- " nm-configured=yes\n" -- " auto=add\n"); -+ " rekey=yes\n" -+ " rightmodecfgserver=yes\n" -+ " modecfgpull=yes\n"); - g_free (str); - } - -diff --git a/shared/utils.c b/shared/utils.c -index 65bc603..2482311 100644 ---- a/shared/utils.c -+++ b/shared/utils.c -@@ -30,82 +30,109 @@ - #include - #include - --gboolean --write_config_option_newline (int fd, -- gboolean new_line, -- NMDebugWriteFcn debug_write_fcn, -- GError **error, -- const char *format, ...) -+static gboolean -+printable_val (GString *str, const char *val, GError **error) - { -- gs_free char *string = NULL; - const char *p; -- va_list args; -- gsize l; -- int errsv; -- gssize w; - -- va_start (args, format); -- string = g_strdup_vprintf (format, args); -- va_end (args); -+ g_return_val_if_fail (val, FALSE); - -- if (debug_write_fcn) -- debug_write_fcn (string); -- -- l = strlen (string); -- if (new_line) { -- gs_free char *s = string; -- -- string = g_new (char, l + 1 + 1); -- memcpy (string, s, l); -- string[l] = '\n'; -- string[l + 1] = '\0'; -- l++; -+ for (p = val; *p != '\0'; p++) { -+ /* Printable characters except " and space allowed. */ -+ if (*p != '"' && !g_ascii_isspace (*p) && g_ascii_isprint (*p)) -+ continue; -+ g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, -+ _("Invalid character in '%s'"), val); -+ return FALSE; - } - -- p = string; -- while (true) { -- w = write (fd, p, l); -- if (w == l) -- return TRUE; -- if (w > 0) { -- g_assert (w < l); -- p += w; -- l -= w; -- continue; -- } -- if (w == 0) { -- errsv = EIO; -- break; -- } -- errsv = errno; -- if (errsv == EINTR) -- continue; -- break; -- } -- g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR, -- _("Error writing config: %s"), g_strerror (errsv)); -- return FALSE; -+ g_string_append (str, val); -+ g_string_append_c (str, '\n'); -+ return TRUE; - } - --gboolean --nm_libreswan_config_write (gint fd, -- int ipsec_version, -- NMConnection *connection, -- const char *con_name, -- const char *leftupdown_script, -- gboolean openswan, -- gboolean trailing_newline, -- NMDebugWriteFcn debug_write_fcn, -- GError **error) -+static gboolean -+string_val (GString *str, const char *val, GError **error) - { -- NMSettingVpn *s_vpn; -- const char *props_username; -- const char *default_username; -+ const char *p; -+ -+ g_return_val_if_fail (val, FALSE); -+ -+ for (p = val; *p != '\0'; p++) { -+ /* Printable characters except " allowed. */ -+ if (*p != '"' && g_ascii_isprint (*p)) -+ continue; -+ g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, -+ _("Invalid character in '%s'"), val); -+ return FALSE; -+ } -+ -+ g_string_append_printf (str, "\"%s\"\n", val); -+ return TRUE; -+} -+ -+static inline gboolean -+optional_string_val (GString *str, const char *key, const char *val, GError **error) -+{ -+ if (val == NULL || val[0] == '\0') -+ return TRUE; -+ g_string_append_c (str, ' '); -+ g_string_append (str, key); -+ g_string_append_c (str, '='); -+ -+ if (!string_val (str, val, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), key); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static inline gboolean -+optional_printable_val (GString *str, const char *key, const char *val, GError **error) -+{ -+ if (val == NULL || val[0] == '\0') -+ return TRUE; -+ -+ g_string_append_c (str, ' '); -+ g_string_append (str, key); -+ g_string_append_c (str, '='); -+ -+ if (!printable_val (str, val, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), key); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+ -+static inline gboolean -+optional_printable (GString *str, NMSettingVpn *s_vpn, const char *key, GError **error) -+{ -+ return optional_printable_val (str, -+ key, -+ nm_setting_vpn_get_data_item (s_vpn, key), -+ error); -+} -+ -+char * -+nm_libreswan_get_ipsec_conf (int ipsec_version, -+ NMSettingVpn *s_vpn, -+ const char *con_name, -+ const char *leftupdown_script, -+ gboolean openswan, -+ gboolean trailing_newline, -+ GError **error) -+{ -+ nm_auto_free_gstring GString *ipsec_conf = NULL; -+ const char *username; - const char *phase1_alg_str; - const char *phase2_alg_str; - const char *phase1_lifetime_str; - const char *phase2_lifetime_str; - const char *left; -+ const char *right; - const char *leftid; - const char *leftcert; - const char *rightcert; -@@ -116,129 +143,176 @@ nm_libreswan_config_write (gint fd, - const char *remote_network; - const char *ikev2 = NULL; - const char *rightid; -- const char *narrowing; - const char *rekey; -- const char *fragmentation; -- const char *mobike; - const char *pfs; - const char *client_family; - const char *item; - gboolean is_ikev2 = FALSE; - -- g_return_val_if_fail (fd > 0, FALSE); -- g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); -+ g_return_val_if_fail (NM_IS_SETTING_VPN (s_vpn), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - g_return_val_if_fail (con_name && *con_name, FALSE); - -- s_vpn = nm_connection_get_setting_vpn (connection); -- g_return_val_if_fail (NM_IS_SETTING_VPN (s_vpn), FALSE); -+ ipsec_conf = g_string_sized_new (1024); -+ g_string_append (ipsec_conf, "conn "); -+ if (!printable_val (ipsec_conf, con_name, error)) { -+ g_prefix_error (error, _("Bad connection name: ")); -+ return FALSE; -+ } - -- is_ikev2 = nm_libreswan_utils_setting_is_ikev2 (s_vpn, &ikev2); -+ if (leftupdown_script) { -+ g_string_append (ipsec_conf, " auto=add\n"); -+ g_string_append (ipsec_conf, " nm-configured=yes\n"); -+ g_string_append (ipsec_conf, " leftupdown="); -+ if (!string_val (ipsec_conf, leftupdown_script, error)) -+ g_return_val_if_reached (FALSE); -+ } - - /* When using IKEv1 (default in our plugin), we should ensure that we make - * it explicit to Libreswan (which now defaults to IKEv2): when crypto algorithms - * are not specified ("esp" & "ike") Libreswan will use system-wide crypto - * policies based on the IKE version in place. - */ -+ is_ikev2 = nm_libreswan_utils_setting_is_ikev2 (s_vpn, &ikev2); - if (!ikev2) - ikev2 = NM_LIBRESWAN_IKEV2_NEVER; -+ g_string_append (ipsec_conf, " ikev2="); -+ if (!printable_val (ipsec_conf, ikev2, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), "ikev2"); -+ return FALSE; -+ } -+ -+ right = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_RIGHT); -+ if (right && right[0] != '\0') { -+ g_string_append (ipsec_conf, " right="); -+ if (!printable_val (ipsec_conf, right, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_RIGHT); -+ return FALSE; -+ } -+ } else { -+ g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, -+ _("'%s' key needs to be present."), NM_LIBRESWAN_KEY_RIGHT); -+ return FALSE; -+ } - - leftid = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTID); -- --#define WRITE_CHECK_NEWLINE(fd, new_line, debug_write_fcn, error, ...) \ -- G_STMT_START { \ -- if (!write_config_option_newline ((fd), (new_line), debug_write_fcn, (error), __VA_ARGS__)) \ -- return FALSE; \ -- } G_STMT_END --#define WRITE_CHECK(fd, debug_write_fcn, error, ...) WRITE_CHECK_NEWLINE (fd, TRUE, debug_write_fcn, error, __VA_ARGS__) -- -- WRITE_CHECK (fd, debug_write_fcn, error, "conn %s", con_name); -- if (leftid && strlen (leftid)) { -+ if (leftid && leftid[0] != '\0') { - if (!is_ikev2) -- WRITE_CHECK (fd, debug_write_fcn, error, " aggrmode=yes"); -+ g_string_append (ipsec_conf, " aggrmode=yes\n"); - - if ( leftid[0] == '%' - || leftid[0] == '@' - || nm_utils_parse_inaddr_bin (AF_UNSPEC, leftid, NULL)) { -- WRITE_CHECK (fd, debug_write_fcn, error, " leftid=%s", leftid); -+ g_string_append (ipsec_conf, " leftid="); - } else -- WRITE_CHECK (fd, debug_write_fcn, error, " leftid=@%s", leftid); -+ g_string_append (ipsec_conf, " leftid=@"); -+ if (!printable_val (ipsec_conf, leftid, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_LEFTID); -+ return FALSE; -+ } - } - -- item = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_HOSTADDRFAMILY); -- if (item && strlen (item)) -- WRITE_CHECK (fd, debug_write_fcn, error, " hostaddrfamily=%s", item); -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_HOSTADDRFAMILY, error)) -+ return FALSE; - - client_family = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_CLIENTADDRFAMILY); -- if (client_family && strlen (client_family)) -- WRITE_CHECK (fd, debug_write_fcn, error, " clientaddrfamily=%s", client_family); -+ if (client_family && client_family[0] != '\0') { -+ g_string_append (ipsec_conf, " clientaddrfamily="); -+ if (!printable_val (ipsec_conf, client_family, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_CLIENTADDRFAMILY); -+ return FALSE; -+ } -+ } - - leftrsasigkey = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTRSASIGKEY); - rightrsasigkey = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_RIGHTRSASIGKEY); - leftcert = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTCERT); - rightcert = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_RIGHTCERT); - authby = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_AUTHBY); -- if (rightcert && strlen (rightcert)) { -- WRITE_CHECK (fd, debug_write_fcn, error, " rightcert=%s", rightcert); -+ if (rightcert && rightcert[0] != '\0') { -+ g_string_append (ipsec_conf, " rightcert="); -+ if (!string_val (ipsec_conf, rightcert, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_RIGHTCERT); -+ return FALSE; -+ } - if (!rightrsasigkey) - rightrsasigkey = "%cert"; - } -- if (leftcert && strlen (leftcert)) { -- WRITE_CHECK (fd, debug_write_fcn, error, " leftcert=%s", leftcert); -+ if (leftcert && leftcert[0] != '\0') { -+ g_string_append (ipsec_conf, " leftcert="); -+ if (!string_val (ipsec_conf, leftcert, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_LEFTCERT); -+ return FALSE; -+ } - if (!leftrsasigkey) - leftrsasigkey = "%cert"; - if (!rightrsasigkey) - rightrsasigkey = "%cert"; - } -- if (leftrsasigkey && strlen (leftrsasigkey)) -- WRITE_CHECK (fd, debug_write_fcn, error, " leftrsasigkey=%s", leftrsasigkey); -- if (rightrsasigkey && strlen (rightrsasigkey)) -- WRITE_CHECK (fd, debug_write_fcn, error, " rightrsasigkey=%s", rightrsasigkey); -+ if (!optional_string_val (ipsec_conf, NM_LIBRESWAN_KEY_LEFTRSASIGKEY, leftrsasigkey, error)) -+ return FALSE; -+ if (!optional_string_val (ipsec_conf, NM_LIBRESWAN_KEY_RIGHTRSASIGKEY, rightrsasigkey, error)) -+ return FALSE; - -- if (authby && strlen (authby)) { -- WRITE_CHECK (fd, debug_write_fcn, error, " authby=%s", authby); -- } else if ( !(leftrsasigkey && strlen (leftrsasigkey)) -- && !(rightrsasigkey && strlen (rightrsasigkey))) { -- WRITE_CHECK (fd, debug_write_fcn, error, " authby=secret"); -+ if (authby == NULL || authby[0] == '\0') { -+ if ( !(leftrsasigkey && leftrsasigkey[0] != '\0') -+ && !(rightrsasigkey && rightrsasigkey[0] != '\0')) { -+ authby = "secret"; -+ } - } -+ if (!optional_printable_val (ipsec_conf, NM_LIBRESWAN_KEY_AUTHBY, authby, error)) -+ return FALSE; - - left = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFT); -- if (left && strlen (left)) -- WRITE_CHECK (fd, debug_write_fcn, error, " left=%s", left); -- else -- WRITE_CHECK (fd, debug_write_fcn, error, " left=%%defaultroute"); -+ if (left == NULL || left[0] == '\0') -+ left = "%defaultroute"; -+ g_string_append (ipsec_conf, " left="); -+ if (!printable_val (ipsec_conf, left, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_LEFT); -+ return FALSE; -+ } - - item = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTMODECFGCLIENT); - if (nm_streq0 (item, "no")) { -- WRITE_CHECK (fd, debug_write_fcn, error, " leftmodecfgclient=no"); -+ g_string_append (ipsec_conf, " leftmodecfgclient=no\n"); - } else { -- WRITE_CHECK (fd, debug_write_fcn, error, " leftmodecfgclient=yes"); -+ g_string_append (ipsec_conf, " leftmodecfgclient=yes\n"); - } - -- if (leftupdown_script) -- WRITE_CHECK (fd, debug_write_fcn, error, " leftupdown=%s", leftupdown_script); -- -- WRITE_CHECK (fd, debug_write_fcn, error, " right=%s", nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_RIGHT)); - rightid = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_RIGHTID); -- if (rightid && strlen (rightid)) { -+ if (rightid && rightid[0] != '\0') { - if ( rightid[0] == '@' - || rightid[0] == '%' -- || nm_utils_parse_inaddr_bin (AF_UNSPEC, rightid, NULL)) { -- WRITE_CHECK (fd, debug_write_fcn, error, " rightid=%s", rightid); -- } else -- WRITE_CHECK (fd, debug_write_fcn, error, " rightid=@%s", rightid); -+ || nm_utils_parse_inaddr_bin (AF_UNSPEC, rightid, NULL)) { -+ g_string_append (ipsec_conf, " rightid="); -+ } else { -+ g_string_append (ipsec_conf, " rightid=@"); -+ } -+ if (!printable_val (ipsec_conf, rightid, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_RIGHTID); -+ return FALSE; -+ } - } -- WRITE_CHECK (fd, debug_write_fcn, error, " rightmodecfgserver=yes"); -- WRITE_CHECK (fd, debug_write_fcn, error, " modecfgpull=yes"); -- - - local_network = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LOCALNETWORK); - if (local_network) { -- WRITE_CHECK (fd, debug_write_fcn, error, " leftsubnet=%s", local_network); -+ g_string_append (ipsec_conf, " leftsubnet="); -+ if (!printable_val (ipsec_conf, local_network, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_LOCALNETWORK); -+ return FALSE; -+ } - } - - remote_network = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_REMOTENETWORK); -- if (!remote_network || !strlen (remote_network)) { -+ if (!remote_network || remote_network[0] == '\0') { - int addr_family = AF_UNSPEC; - - /* Detect the address family of the remote subnet. We use in order: -@@ -259,43 +333,50 @@ nm_libreswan_config_write (gint fd, - } - - if (addr_family == AF_INET6) { -- WRITE_CHECK (fd, debug_write_fcn, error, " rightsubnet=::/0"); -+ remote_network = "::/0"; - } else { - /* For backwards compatibility, if we can't determine the family - * assume it's IPv4. Anyway, in the future we need to stop adding - * the option automatically. */ -- WRITE_CHECK (fd, debug_write_fcn, error, " rightsubnet=0.0.0.0/0"); -+ remote_network = "0.0.0.0/0"; - } -- } else { -- WRITE_CHECK (fd, debug_write_fcn, error, " rightsubnet=%s", remote_network); -+ } -+ g_string_append (ipsec_conf, " rightsubnet="); -+ if (!printable_val (ipsec_conf, remote_network, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_REMOTENETWORK); -+ return FALSE; - } - - if (!is_ikev2) { - /* When IKEv1 is in place, we enforce XAUTH: so, use IKE version - * also to check if XAUTH conf options should be passed to Libreswan. - */ -- WRITE_CHECK (fd, debug_write_fcn, error, " leftxauthclient=yes"); -+ g_string_append (ipsec_conf, " leftxauthclient=yes\n"); - -- default_username = nm_setting_vpn_get_user_name (s_vpn); -- props_username = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTXAUTHUSER); -- if (!props_username) -- props_username = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTUSERNAME); -- if (props_username && strlen (props_username)) -- WRITE_CHECK (fd, debug_write_fcn, error, -- ipsec_version >= 4 ? " leftusername=%s" : " leftxauthusername=%s", -- props_username); -- else if (default_username && strlen (default_username)) -- WRITE_CHECK (fd, debug_write_fcn, error, -- ipsec_version >= 4 ? " leftusername=%s" : " leftxauthusername=%s", -- default_username); -+ username = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTXAUTHUSER); -+ if (username == NULL || username[0] == '\0') -+ username = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTUSERNAME); -+ if (username == NULL || username[0] == '\0') -+ username = nm_setting_vpn_get_user_name (s_vpn); -+ if (username != NULL && username[0] != '\0') { -+ g_string_append (ipsec_conf, -+ ipsec_version >= 4 ? -+ " leftusername=" : -+ " leftxauthusername="); -+ if (!string_val (ipsec_conf, username, error)) { -+ g_prefix_error (error, _("Invalid username: ")); -+ return FALSE; -+ } -+ } - -- WRITE_CHECK (fd, debug_write_fcn, error, -- ipsec_version >= 4 ? " remote-peer-type=cisco" : " remote_peer_type=cisco"); -- WRITE_CHECK (fd, debug_write_fcn, error, " rightxauthserver=yes"); -+ g_string_append (ipsec_conf, -+ ipsec_version >= 4 ? -+ " remote-peer-type=cisco\n" : -+ " remote_peer_type=cisco\n"); -+ g_string_append (ipsec_conf, " rightxauthserver=yes\n"); - } - -- -- phase1_alg_str = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_IKE); - /* When the crypto is unspecified, let Libreswan use many sets of crypto - * proposals (just leave the property unset). An exception should be made - * for IKEv1 connections in aggressive mode: there the DH group in the crypto -@@ -304,84 +385,80 @@ nm_libreswan_config_write (gint fd, - * force the best proposal that should be accepted by all obsolete VPN SW/HW - * acting as a remote access VPN server. - */ -- if (phase1_alg_str && strlen (phase1_alg_str)) -- WRITE_CHECK (fd, debug_write_fcn, error, " ike=%s", phase1_alg_str); -- else if (!is_ikev2 && leftid) -- WRITE_CHECK (fd, debug_write_fcn, error, " ike=%s", NM_LIBRESWAN_AGGRMODE_DEFAULT_IKE); -+ phase1_alg_str = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_IKE); -+ if (phase1_alg_str == NULL || phase1_alg_str[0] == '\0') { -+ if (!is_ikev2 && leftid) -+ phase1_alg_str = NM_LIBRESWAN_AGGRMODE_DEFAULT_IKE; -+ } -+ if (!optional_string_val (ipsec_conf, NM_LIBRESWAN_KEY_IKE, phase1_alg_str, error)) -+ return FALSE; - - phase2_alg_str = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_ESP); -- if (phase2_alg_str && strlen (phase2_alg_str)) -- WRITE_CHECK (fd, debug_write_fcn, error, " phase2alg=%s", phase2_alg_str); -- else if (!is_ikev2 && leftid) -- WRITE_CHECK (fd, debug_write_fcn, error, " phase2alg=%s", NM_LIBRESWAN_AGGRMODE_DEFAULT_ESP); -+ if (phase2_alg_str == NULL || phase2_alg_str[0] == '\0') { -+ if (!is_ikev2 && leftid) -+ phase2_alg_str = NM_LIBRESWAN_AGGRMODE_DEFAULT_ESP; -+ } -+ if (!optional_string_val (ipsec_conf, "phase2alg", phase2_alg_str, error)) -+ return FALSE; - - pfs = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_PFS); - if (pfs && !strcmp (pfs, "no")) -- WRITE_CHECK (fd, debug_write_fcn, error, " pfs=no"); -+ g_string_append (ipsec_conf, " pfs=no\n"); - -- phase1_lifetime_str = nm_setting_vpn_get_data_item (s_vpn, -- NM_LIBRESWAN_KEY_IKELIFETIME); -- if (phase1_lifetime_str && strlen (phase1_lifetime_str)) -- WRITE_CHECK (fd, debug_write_fcn, error, " ikelifetime=%s", phase1_lifetime_str); -- else if (!is_ikev2) -- WRITE_CHECK (fd, debug_write_fcn, error, " ikelifetime=%s", NM_LIBRESWAN_IKEV1_DEFAULT_LIFETIME); -+ phase1_lifetime_str = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_IKELIFETIME); -+ if (phase1_lifetime_str == NULL || phase1_lifetime_str[0] == '\0') { -+ if (!is_ikev2) -+ phase1_lifetime_str = NM_LIBRESWAN_IKEV1_DEFAULT_LIFETIME; -+ } -+ if (!optional_printable_val (ipsec_conf, NM_LIBRESWAN_KEY_IKELIFETIME, phase1_lifetime_str, error)) -+ return FALSE; - -- phase2_lifetime_str = nm_setting_vpn_get_data_item (s_vpn, -- NM_LIBRESWAN_KEY_SALIFETIME); -- if (phase2_lifetime_str && strlen (phase2_lifetime_str)) -- WRITE_CHECK (fd, debug_write_fcn, error, " salifetime=%s", phase2_lifetime_str); -- else if (!is_ikev2) -- WRITE_CHECK (fd, debug_write_fcn, error, " salifetime=%s", NM_LIBRESWAN_IKEV1_DEFAULT_LIFETIME); -+ phase2_lifetime_str = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_SALIFETIME); -+ if (phase2_lifetime_str == NULL || phase2_lifetime_str[0] == '\0') { -+ if (!is_ikev2) -+ phase2_lifetime_str = NM_LIBRESWAN_IKEV1_DEFAULT_LIFETIME; -+ } -+ if (!optional_printable_val (ipsec_conf, NM_LIBRESWAN_KEY_SALIFETIME, phase2_lifetime_str, error)) -+ return FALSE; - - rekey = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_REKEY); -- if (!rekey || !strlen (rekey)) { -- WRITE_CHECK (fd, debug_write_fcn, error, " rekey=yes"); -- WRITE_CHECK (fd, debug_write_fcn, error, " keyingtries=1"); -- } else -- WRITE_CHECK (fd, debug_write_fcn, error, " rekey=%s", rekey); -+ if (!rekey || rekey[0] == '\0') { -+ g_string_append (ipsec_conf, " keyingtries=1\n"); -+ rekey = "yes"; -+ } -+ g_string_append (ipsec_conf, " rekey="); -+ if (!printable_val (ipsec_conf, rekey, error)) { -+ g_prefix_error (error, _("Invalid value for '%s': "), -+ NM_LIBRESWAN_KEY_REKEY); -+ return FALSE; -+ } - - if (!openswan && g_strcmp0 (nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_VENDOR), "Cisco") == 0) -- WRITE_CHECK (fd, debug_write_fcn, error, " cisco-unity=yes"); -+ g_string_append (ipsec_conf, " cisco-unity=yes\n"); - -- WRITE_CHECK (fd, debug_write_fcn, error, " ikev2=%s", ikev2); -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_NARROWING, error)) -+ return FALSE; -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_FRAGMENTATION, error)) -+ return FALSE; -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_MOBIKE, error)) -+ return FALSE; -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_DPDDELAY, error)) -+ return FALSE; -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_DPDTIMEOUT, error)) -+ return FALSE; -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_DPDACTION, error)) -+ return FALSE; -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_IPSEC_INTERFACE, error)) -+ return FALSE; -+ if (!optional_printable (ipsec_conf, s_vpn, NM_LIBRESWAN_KEY_TYPE, error)) -+ return FALSE; - -- narrowing = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_NARROWING); -- if (narrowing && strlen (narrowing)) -- WRITE_CHECK (fd, debug_write_fcn, error, " narrowing=%s", narrowing); -+ g_string_append (ipsec_conf, " rightmodecfgserver=yes\n"); -+ g_string_append (ipsec_conf, " modecfgpull=yes"); -+ if (trailing_newline) -+ g_string_append_c (ipsec_conf, '\n'); - -- fragmentation = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_FRAGMENTATION); -- if (fragmentation && strlen (fragmentation)) -- WRITE_CHECK (fd, debug_write_fcn, error, " fragmentation=%s", fragmentation); -- -- mobike = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_MOBIKE); -- if (mobike && strlen (mobike)) -- WRITE_CHECK (fd, debug_write_fcn, error, " mobike=%s", mobike); -- -- item = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_DPDDELAY); -- if (item && strlen (item)) -- WRITE_CHECK (fd, debug_write_fcn, error, " dpddelay=%s", item); -- -- item = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_DPDTIMEOUT); -- if (item && strlen (item)) -- WRITE_CHECK (fd, debug_write_fcn, error, " dpdtimeout=%s", item); -- -- item = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_DPDACTION); -- if (item && strlen (item)) -- WRITE_CHECK (fd, debug_write_fcn, error, " dpdaction=%s", item); -- -- item = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_IPSEC_INTERFACE); -- if (item && strlen (item)) -- WRITE_CHECK (fd, debug_write_fcn, error, " ipsec-interface=%s", item); -- -- item = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_TYPE); -- if (item && strlen (item)) -- WRITE_CHECK (fd, debug_write_fcn, error, " type=%s", item); -- -- WRITE_CHECK (fd, debug_write_fcn, error, " nm-configured=yes"); -- -- WRITE_CHECK_NEWLINE (fd, trailing_newline, debug_write_fcn, error, " auto=add"); -- -- return TRUE; -+ return g_string_free (g_steal_pointer (&ipsec_conf), FALSE); - } - - static const char * -diff --git a/shared/utils.h b/shared/utils.h -index 7e89841..2e2450c 100644 ---- a/shared/utils.h -+++ b/shared/utils.h -@@ -24,27 +24,13 @@ - #ifndef __UTILS_H__ - #define __UTILS_H__ - --typedef void (*NMDebugWriteFcn) (const char *setting); -- --__attribute__((__format__ (__printf__, 5, 6))) --gboolean write_config_option_newline (int fd, -- gboolean new_line, -- NMDebugWriteFcn debug_write_fcn, -- GError **error, -- const char *format, ...); -- --#define write_config_option(fd, debug_write_fcn, error, ...) write_config_option_newline((fd), TRUE, debug_write_fcn, error, __VA_ARGS__) -- --gboolean --nm_libreswan_config_write (gint fd, -- int ipsec_version, -- NMConnection *connection, -- const char *con_name, -- const char *leftupdown_script, -- gboolean openswan, -- gboolean trailing_newline, -- NMDebugWriteFcn debug_write_fcn, -- GError **error); -+char *nm_libreswan_get_ipsec_conf (int ipsec_version, -+ NMSettingVpn *s_vpn, -+ const char *con_name, -+ const char *leftupdown_script, -+ gboolean openswan, -+ gboolean trailing_newline, -+ GError **error); - - static inline gboolean - nm_libreswan_utils_setting_is_ikev2 (NMSettingVpn *s_vpn, const char **out_ikev2) -diff --git a/src/nm-libreswan-service.c b/src/nm-libreswan-service.c -index e5956af..35f602c 100644 ---- a/src/nm-libreswan-service.c -+++ b/src/nm-libreswan-service.c -@@ -101,12 +101,13 @@ typedef struct { - const char *whack_path; - char *secrets_path; - -+ char *ipsec_conf; -+ - gboolean openswan; - gboolean interactive; - gboolean pending_auth; - gboolean managed; - gboolean xauth_enabled; -- int version; - - GPid pid; - guint watch_id; -@@ -152,12 +153,6 @@ _LOGD_enabled (void) - #define _LOGW(...) _NMLOG(LOG_WARNING, __VA_ARGS__) - #define _LOGE(...) _NMLOG(LOG_EMERG, __VA_ARGS__) - --static void --_debug_write_option (const char *setting) --{ -- _LOGD ("Config %s", setting); --} -- - /****************************************************************/ - - static gboolean pr_cb (GIOChannel *source, GIOCondition condition, gpointer user_data); -@@ -666,9 +661,9 @@ nm_libreswan_config_psk_write (NMSettingVpn *s_vpn, - GError **error) - { - const char *pw_type, *psk, *leftid, *right; -- int fd; -- int errsv; -- gboolean success; -+ gs_free const char *secrets = NULL; -+ mode_t old_mask; -+ gboolean res; - - /* Check for ignored group password */ - pw_type = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_PSK_INPUT_MODES); -@@ -679,47 +674,32 @@ nm_libreswan_config_psk_write (NMSettingVpn *s_vpn, - if (!psk) - return TRUE; - -- /* Write the PSK */ -- errno = 0; -- fd = open (secrets_path, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); -- if (fd < 0) { -- errsv = errno; -- -- if (errsv == ENOENT) { -- gs_free char *dirname = g_path_get_dirname (secrets_path); -- -- if (!g_file_test (dirname, G_FILE_TEST_IS_DIR)) { -- g_set_error (error, -- NM_VPN_PLUGIN_ERROR, -- NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, -- "Failed to open secrets file: no directory %s", -- dirname); -- return FALSE; -- } -- } -- -- g_set_error (error, -- NM_VPN_PLUGIN_ERROR, -- NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, -- "Failed to open secrets file: (%d) %s.", -- errsv, g_strerror (errsv)); -- return FALSE; -- } -- - leftid = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_LEFTID); - if (leftid) { -- success = write_config_option (fd, NULL, error, "@%s: PSK \"%s\"", leftid, psk); -+ if (strchr (leftid, '"') || strchr (leftid, '\n')) { -+ g_set_error_literal (error, -+ NM_VPN_PLUGIN_ERROR, -+ NM_VPN_PLUGIN_ERROR_INVALID_CONNECTION, -+ _("Invalid character in password.")); -+ return FALSE; -+ } -+ secrets = g_strdup_printf ("@%s: PSK \"%s\"", leftid, psk); - } else { - right = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_RIGHT); -- g_assert (right); -- success = write_config_option (fd, NULL, error, "%s %%any: PSK \"%s\"", right, psk); -+ -+ /* nm_libreswan_get_ipsec_conf() in _connect_common should've check these. */ -+ g_return_val_if_fail (right != NULL, FALSE); -+ g_return_val_if_fail (strchr (right, '"') == NULL, FALSE); -+ g_return_val_if_fail (strchr (right, '\n') == NULL, FALSE); -+ -+ secrets = g_strdup_printf ("%s %%any: PSK \"%s\"", right, psk); - } - -- if (!success) { -- g_close (fd, NULL); -- return FALSE; -- } -- return g_close (fd, error); -+ -+ old_mask = umask (S_IRWXG | S_IRWXO); -+ res = g_file_set_contents (secrets_path, secrets, -1, error); -+ umask (old_mask); -+ return res; - } - - /****************************************************************/ -@@ -1766,6 +1746,44 @@ done: - return success ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE; - } - -+static gboolean -+write_config (int fd, -+ const char *string, -+ GError **error) -+{ -+ const char *p; -+ gsize l; -+ int errsv; -+ gssize w; -+ -+ _LOGD ("Config %s", string); -+ -+ l = strlen (string); -+ p = string; -+ while (true) { -+ w = write (fd, p, l); -+ if (w == l) -+ return TRUE; -+ if (w > 0) { -+ g_assert (w < l); -+ p += w; -+ l -= w; -+ continue; -+ } -+ if (w == 0) { -+ errsv = EIO; -+ break; -+ } -+ errsv = errno; -+ if (errsv == EINTR) -+ continue; -+ break; -+ } -+ g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR, -+ _("Error writing config: %s"), g_strerror (errsv)); -+ return FALSE; -+} -+ - static gboolean - connect_step (NMLibreswanPlugin *self, GError **error) - { -@@ -1848,37 +1866,12 @@ connect_step (NMLibreswanPlugin *self, GError **error) - return TRUE; - - case CONNECT_STEP_CONFIG_ADD: { -- gboolean trailing_newline; -- gs_free char *bus_name = NULL; -- gs_free char *ifupdown_script = NULL; - - if (!do_spawn (self, &priv->pid, &fd, NULL, error, priv->ipsec_path, - "auto", "--replace", "--config", "-", uuid, NULL)) - return FALSE; - priv->watch_id = g_child_watch_add (priv->pid, child_watch_cb, self); -- g_object_get (self, NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, &bus_name, NULL); -- -- /* openswan requires a terminating \n (otherwise it segfaults) while -- * libreswan fails parsing the configuration if you include the \n. -- * WTF? -- */ -- trailing_newline = priv->openswan; -- -- ifupdown_script = g_strdup_printf ("\"%s %d %ld %s\"", -- NM_LIBRESWAN_HELPER_PATH, -- LOG_DEBUG, -- (long) getpid (), -- bus_name); -- -- if (!nm_libreswan_config_write (fd, -- priv->version, -- priv->connection, -- uuid, -- ifupdown_script, -- priv->openswan, -- trailing_newline, -- _debug_write_option, -- error)) { -+ if (!write_config (fd, priv->ipsec_conf, error)) { - g_close (fd, NULL); - return FALSE; - } -@@ -1928,19 +1921,31 @@ _connect_common (NMVpnServicePlugin *plugin, - NMSettingVpn *s_vpn; - const char *con_name = nm_connection_get_uuid (connection); - gs_free char *ipsec_banner = NULL; -+ gs_free char *ifupdown_script = NULL; -+ gs_free char *bus_name = NULL; -+ gboolean trailing_newline; -+ int version; - - if (_LOGD_enabled ()) { - _LOGD ("connection:"); - nm_connection_dump (connection); - } - -+ if (priv->connect_step != CONNECT_STEP_FIRST) { -+ g_set_error_literal (error, -+ NM_VPN_PLUGIN_ERROR, -+ NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, -+ "Already connecting!"); -+ return FALSE; -+ } -+ - priv->ipsec_path = nm_libreswan_find_helper_bin ("ipsec", error); - if (!priv->ipsec_path) - return FALSE; - -- nm_libreswan_detect_version (priv->ipsec_path, &priv->openswan, &priv->version, &ipsec_banner); -+ nm_libreswan_detect_version (priv->ipsec_path, &priv->openswan, &version, &ipsec_banner); - _LOGD ("ipsec: version banner: %s", ipsec_banner); -- _LOGD ("ipsec: detected version %d (%s)", priv->version, priv->openswan ? "Openswan" : "Libreswan"); -+ _LOGD ("ipsec: detected version %d (%s)", version, priv->openswan ? "Openswan" : "Libreswan"); - - if (!priv->openswan) { - priv->pluto_path = nm_libreswan_find_helper_libexec ("pluto", error); -@@ -1960,13 +1965,31 @@ _connect_common (NMVpnServicePlugin *plugin, - if (!nm_libreswan_secrets_validate (s_vpn, error)) - return FALSE; - -- if (priv->connect_step != CONNECT_STEP_FIRST) { -- g_set_error_literal (error, -- NM_VPN_PLUGIN_ERROR, -- NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, -- "Already connecting!"); -+ g_object_get (self, NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, &bus_name, NULL); -+ -+ ifupdown_script = g_strdup_printf ("%s %d %ld %s", -+ NM_LIBRESWAN_HELPER_PATH, -+ LOG_DEBUG, -+ (long) getpid (), -+ bus_name); -+ -+ /* openswan requires a terminating \n (otherwise it segfaults) while -+ * libreswan fails parsing the configuration if you include the \n. -+ * WTF? -+ */ -+ trailing_newline = priv->openswan; -+ -+ /* Compose the ipsec.conf early, to catch configuration errors before -+ * we initiate the conneciton. */ -+ priv->ipsec_conf = nm_libreswan_get_ipsec_conf (version, -+ s_vpn, -+ con_name, -+ ifupdown_script, -+ priv->openswan, -+ trailing_newline, -+ error); -+ if (priv->ipsec_conf == NULL) - return FALSE; -- } - - /* XAUTH is not part of the IKEv2 standard and we always enforce it in IKEv1 */ - priv->xauth_enabled = !nm_libreswan_utils_setting_is_ikev2 (s_vpn, NULL); -@@ -2141,6 +2164,7 @@ real_disconnect (NMVpnServicePlugin *plugin, GError **error) - priv->watch_id = g_child_watch_add (priv->pid, child_watch_cb, plugin); - - g_clear_object (&priv->connection); -+ g_clear_pointer (&priv->ipsec_conf, g_free); - - return ret; - } -@@ -2173,6 +2197,7 @@ finalize (GObject *object) - { - NMLibreswanPluginPrivate *priv = NM_LIBRESWAN_PLUGIN_GET_PRIVATE (object); - -+ g_clear_pointer (&priv->ipsec_conf, g_free); - delete_secrets_file (NM_LIBRESWAN_PLUGIN (object)); - connect_cleanup (NM_LIBRESWAN_PLUGIN (object)); - g_clear_object (&priv->connection); --- -2.46.0 - -From 8cbc188222d6a3dcff7ed937d44415f75e34b503 Mon Sep 17 00:00:00 2001 -From: Lubomir Rintel -Date: Tue, 24 Sep 2024 10:55:02 +0200 -Subject: [PATCH 6/6] shared/test-utils: add more test cases - -Test ipsec.conf formatting more thoroughly, include negative cases. - -[lkundrak@v3.sk: Backported from 1.24.0] ---- - shared/test-utils.c | 82 +++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 82 insertions(+) - -diff --git a/shared/test-utils.c b/shared/test-utils.c -index 49aa32a..0a92d2b 100644 ---- a/shared/test-utils.c -+++ b/shared/test-utils.c -@@ -2,6 +2,8 @@ - - #include "utils.h" - -+#include "nm-utils/nm-shared-utils.h" -+ - static void - test_config_write (void) - { -@@ -57,6 +59,86 @@ test_config_write (void) - " rightmodecfgserver=yes\n" - " modecfgpull=yes\n"); - g_free (str); -+ -+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "ikev2", "insist"); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "leftrsasigkey", "hello"); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "rightrsasigkey", "world"); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "right", "11.12.13.14"); -+ str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); -+ g_assert_no_error (error); -+ g_assert_cmpstr (str, ==, -+ "conn conn\n" -+ " ikev2=insist\n" -+ " right=11.12.13.14\n" -+ " leftrsasigkey=\"hello\"\n" -+ " rightrsasigkey=\"world\"\n" -+ " left=%defaultroute\n" -+ " leftmodecfgclient=yes\n" -+ " rightsubnet=0.0.0.0/0\n" -+ " keyingtries=1\n" -+ " rekey=yes\n" -+ " rightmodecfgserver=yes\n" -+ " modecfgpull=yes\n"); -+ g_free (str); -+ -+ -+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "right", "11.12.13.14"); -+ str = nm_libreswan_get_ipsec_conf (3, s_vpn, -+ "my_con", -+ "/foo/bar/ifupdown hello 123 456", -+ TRUE, FALSE, &error); -+ g_assert_no_error (error); -+ g_assert_cmpstr (str, ==, -+ "conn my_con\n" -+ " auto=add\n" -+ " nm-configured=yes\n" -+ " leftupdown=\"/foo/bar/ifupdown hello 123 456\"\n" -+ " ikev2=never\n" -+ " right=11.12.13.14\n" -+ " authby=secret\n" -+ " left=%defaultroute\n" -+ " leftmodecfgclient=yes\n" -+ " rightsubnet=0.0.0.0/0\n" -+ " leftxauthclient=yes\n" -+ " remote_peer_type=cisco\n" -+ " rightxauthserver=yes\n" -+ " ikelifetime=24h\n" -+ " salifetime=24h\n" -+ " keyingtries=1\n" -+ " rekey=yes\n" -+ " rightmodecfgserver=yes\n" -+ " modecfgpull=yes"); -+ g_free (str); -+ -+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); -+ str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); -+ g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); -+ g_assert_null (str); -+ g_clear_error (&error); -+ -+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "right", "11.12.13.14"); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "ikev2", "hello world"); -+ str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); -+ g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); -+ g_assert_null (str); -+ g_clear_error (&error); -+ -+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "right", "11.12\n13.14"); -+ str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); -+ g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); -+ g_assert_null (str); -+ g_clear_error (&error); -+ -+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); -+ nm_setting_vpn_add_data_item (NM_SETTING_VPN(s_vpn), "rightcert", "\"cert\""); -+ str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); -+ g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); -+ g_assert_null (str); -+ g_clear_error (&error); - } - - int --- -2.46.0 - diff --git a/SOURCES/0002-fix-psk-auth-when-leftid-starts-with-at.patch b/SOURCES/0002-fix-psk-auth-when-leftid-starts-with-at.patch new file mode 100644 index 0000000..5aab561 --- /dev/null +++ b/SOURCES/0002-fix-psk-auth-when-leftid-starts-with-at.patch @@ -0,0 +1,425 @@ +From 50d0fc5a265b63fe14eac8e82560012ad112e4b7 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Wed, 15 Oct 2025 16:06:19 +0800 +Subject: [PATCH 1/2] Fix PSK authentication when leftid starts with `@` + +When `leftid` starts with `@`, the +`/etc/ipsec.d/ipsec-<$connection_uuid>.secrets` file created will +contains content like: + +``` +@@cli-a.example.org: PSK "LONG_PSK_STRING" +``` + +To fix that issue, change both `nm_libreswan_get_ipsec_conf()` and +`nm_libreswan_config_psk_write()` to accept sanitized NmSettingVPN only. + +The `nm_libreswan_config_psk_write()` will not adding any leading `@` +anymore since the leftid is already sanitized. + +Signed-off-by: Gris Ge +--- + shared/test-utils.c | 65 ++++++++++++++++++++++++++------------ + shared/utils.c | 14 +++----- + shared/utils.h | 3 ++ + src/nm-libreswan-service.c | 8 ++--- + 4 files changed, 57 insertions(+), 33 deletions(-) + +diff --git a/shared/test-utils.c b/shared/test-utils.c +index 16a96d1..8bf5888 100644 +--- a/shared/test-utils.c ++++ b/shared/test-utils.c +@@ -30,11 +30,14 @@ test_config_write (void) + { + GError *error = NULL; + NMSettingVpn *s_vpn; ++ NMSettingVpn *s_vpn_sanitized; + char *str; + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "con_name", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); ++ g_assert_no_error (error); ++ str = nm_libreswan_get_ipsec_conf (4, s_vpn_sanitized, "con_name", NULL, FALSE, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, + "conn con_name\n" +@@ -55,11 +58,14 @@ test_config_write (void) + " modecfgpull=yes\n"); + g_free (str); + g_object_unref (s_vpn); ++ g_object_unref (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); + nm_setting_vpn_add_data_item (s_vpn, "dhgroup", "ignored"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "con_name", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); ++ g_assert_no_error (error); ++ str = nm_libreswan_get_ipsec_conf (4, s_vpn_sanitized, "con_name", NULL, FALSE, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, + "conn con_name\n" +@@ -81,13 +87,16 @@ test_config_write (void) + + g_free (str); + g_object_unref (s_vpn); ++ g_object_unref (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "ikev2", "insist"); + nm_setting_vpn_add_data_item (s_vpn, "leftcert", "LibreswanClient"); + nm_setting_vpn_add_data_item (s_vpn, "leftid", "%fromcert"); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); ++ g_assert_no_error (error); ++ str = nm_libreswan_get_ipsec_conf (4, s_vpn_sanitized, + "f0008435-07af-4836-a53d-b43e8730e68f", + NULL, FALSE, TRUE, &error); + g_assert_no_error (error); +@@ -108,13 +117,16 @@ test_config_write (void) + " modecfgpull=yes\n"); + g_free (str); + g_object_unref (s_vpn); ++ g_object_unref (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "ikev2", "insist"); + nm_setting_vpn_add_data_item (s_vpn, "leftrsasigkey", "hello"); + nm_setting_vpn_add_data_item (s_vpn, "rightrsasigkey", "world"); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); ++ g_assert_no_error (error); ++ str = nm_libreswan_get_ipsec_conf (4, s_vpn_sanitized, "conn", NULL, FALSE, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, + "conn conn\n" +@@ -131,10 +143,13 @@ test_config_write (void) + " modecfgpull=yes\n"); + g_free (str); + g_object_unref (s_vpn); ++ g_object_unref (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); +- str = nm_libreswan_get_ipsec_conf (3, s_vpn, ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); ++ g_assert_no_error (error); ++ str = nm_libreswan_get_ipsec_conf (3, s_vpn_sanitized, + "my_con", + "/foo/bar/ifupdown hello 123 456", + TRUE, FALSE, &error); +@@ -161,6 +176,7 @@ test_config_write (void) + " nm-configured=yes"); + g_free (str); + g_object_unref (s_vpn); ++ g_object_unref (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "ikev2", "insist"); +@@ -170,7 +186,9 @@ test_config_write (void) + nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "false"); + nm_setting_vpn_add_data_item (s_vpn, "leftsendcert", "always"); + nm_setting_vpn_add_data_item (s_vpn, "rightca", "%same"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); ++ g_assert_no_error (error); ++ str = nm_libreswan_get_ipsec_conf (4, s_vpn_sanitized, "conn", NULL, FALSE, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, + "conn conn\n" +@@ -182,11 +200,14 @@ test_config_write (void) + " rightca=\"%same\"\n"); + g_free (str); + g_object_unref (s_vpn); ++ g_object_unref (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); + nm_setting_vpn_add_data_item (s_vpn, "esp", "aes_gcm256"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "con_name", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); ++ g_assert_no_error (error); ++ str = nm_libreswan_get_ipsec_conf (4, s_vpn_sanitized, "con_name", NULL, FALSE, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, + "conn con_name\n" +@@ -209,11 +230,14 @@ test_config_write (void) + " modecfgpull=yes\n"); + g_free (str); + g_object_unref (s_vpn); ++ g_object_unref (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); + nm_setting_vpn_add_data_item (s_vpn, "vendor", "Cisco"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "con_name", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); ++ g_assert_no_error (error); ++ str = nm_libreswan_get_ipsec_conf (4, s_vpn_sanitized, "con_name", NULL, FALSE, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, + "conn con_name\n" +@@ -235,53 +259,54 @@ test_config_write (void) + " modecfgpull=yes\n"); + g_free (str); + g_object_unref (s_vpn); ++ g_object_unref (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); +- g_assert_null (str); + g_clear_error (&error); + g_object_unref (s_vpn); ++ g_assert_null (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); + nm_setting_vpn_add_data_item (s_vpn, "ikev2", "hello world"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); +- g_assert_null (str); + g_clear_error (&error); + g_object_unref (s_vpn); ++ g_assert_null (s_vpn_sanitized); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12\n13.14"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); +- g_assert_null (str); ++ g_assert_null (s_vpn_sanitized); + g_clear_error (&error); + g_object_unref (s_vpn); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "rightcert", "\"cert\""); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); +- g_assert_null (str); ++ g_assert_null (s_vpn_sanitized); + g_clear_error (&error); + g_object_unref (s_vpn); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "false"); + nm_setting_vpn_add_data_item (s_vpn, "rightcert", "\"cert\""); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); +- g_assert_null (str); ++ g_assert_null (s_vpn_sanitized); + g_clear_error (&error); + g_object_unref (s_vpn); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "false"); +- str = nm_libreswan_get_ipsec_conf (4, s_vpn, "conn", NULL, FALSE, TRUE, &error); ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); +- g_assert_null (str); ++ g_assert_null (s_vpn_sanitized); + g_clear_error (&error); + g_object_unref (s_vpn); + } +diff --git a/shared/utils.c b/shared/utils.c +index ac735a5..8dab313 100644 +--- a/shared/utils.c ++++ b/shared/utils.c +@@ -384,7 +384,7 @@ check_val (const char *val, gboolean allow_spaces, GError **error) + return TRUE; + } + +-static NMSettingVpn * ++NMSettingVpn * + sanitize_setting_vpn (NMSettingVpn *s_vpn, + GError **error) + { +@@ -458,34 +458,30 @@ sanitize_setting_vpn (NMSettingVpn *s_vpn, + + char * + nm_libreswan_get_ipsec_conf (int ipsec_version, +- NMSettingVpn *s_vpn, ++ NMSettingVpn *s_vpn_sanitized, + const char *con_name, + const char *leftupdown_script, + gboolean openswan, + gboolean trailing_newline, + GError **error) + { +- gs_unref_object NMSettingVpn *sanitized = NULL; + nm_auto_free_gstring GString *ipsec_conf = NULL; + const char *val; + int i; + +- g_return_val_if_fail (NM_IS_SETTING_VPN (s_vpn), NULL); ++ g_return_val_if_fail (NM_IS_SETTING_VPN (s_vpn_sanitized), NULL); + g_return_val_if_fail (!error || !*error, NULL); + g_return_val_if_fail (con_name && *con_name, NULL); + + if (!check_val (con_name, FALSE, error)) + return NULL; + +- sanitized = sanitize_setting_vpn (s_vpn, error); +- if (!sanitized) +- return NULL; +- + ipsec_conf = g_string_sized_new (1024); + g_string_append_printf (ipsec_conf, "conn %s\n", con_name); + + for (i = 0; params[i].name != NULL; i++) { +- val = nm_setting_vpn_get_data_item (sanitized, params[i].name); ++ val = nm_setting_vpn_get_data_item (s_vpn_sanitized, ++ params[i].name); + if (val == NULL) + continue; + +diff --git a/shared/utils.h b/shared/utils.h +index 67718e9..7832966 100644 +--- a/shared/utils.h ++++ b/shared/utils.h +@@ -64,4 +64,7 @@ const char *nm_libreswan_find_helper_libexec (const char *progname, GError **err + gboolean nm_libreswan_parse_subnets (const char *str, GPtrArray *arr, GError **error); + char *nm_libreswan_normalize_subnets (const char *str, GError **error); + ++NMSettingVpn *sanitize_setting_vpn (NMSettingVpn *s_vpn, GError **error); ++ ++ + #endif /* __UTILS_H__ */ +diff --git a/src/nm-libreswan-service.c b/src/nm-libreswan-service.c +index 7987ada..58ada03 100644 +--- a/src/nm-libreswan-service.c ++++ b/src/nm-libreswan-service.c +@@ -522,8 +522,7 @@ nm_libreswan_config_psk_write (NMSettingVpn *s_vpn, + /* nm_libreswan_get_ipsec_conf() in _connect_common should've checked these. */ + g_return_val_if_fail (strchr (leftid, '"') == NULL, FALSE); + g_return_val_if_fail (strchr (leftid, '\n') == NULL, FALSE); +- +- secrets = g_strdup_printf ("@%s: PSK \"%s\"", leftid, psk); ++ secrets = g_strdup_printf ("%s: PSK \"%s\"", leftid, psk); + } else { + right = nm_setting_vpn_get_data_item (s_vpn, NM_LIBRESWAN_KEY_RIGHT); + +@@ -1757,7 +1756,7 @@ _connect_common (NMVpnServicePlugin *plugin, + { + NMLibreswanPlugin *self = NM_LIBRESWAN_PLUGIN (plugin); + NMLibreswanPluginPrivate *priv = NM_LIBRESWAN_PLUGIN_GET_PRIVATE (self); +- NMSettingVpn *s_vpn; ++ gs_unref_object NMSettingVpn *s_vpn = NULL; + const char *con_name = nm_connection_get_uuid (connection); + gs_free char *ipsec_banner = NULL; + gs_free char *ifupdown_script = NULL; +@@ -1795,7 +1794,8 @@ _connect_common (NMVpnServicePlugin *plugin, + return FALSE; + } + +- s_vpn = nm_connection_get_setting_vpn (connection); ++ s_vpn = sanitize_setting_vpn(nm_connection_get_setting_vpn (connection), ++ error); + g_assert (s_vpn); + + g_object_get (self, NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, &bus_name, NULL); +-- +2.51.0 + + +From 55aa9f0e48acfe1ff5ee06825139bc6bdd59b4cc Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Fri, 17 Oct 2025 16:58:30 +0800 +Subject: [PATCH 2/2] Copy secrets when sanitizing + +The PSK authentication is not wkring because the +`sanitize_setting_vpn()` never copy secrets. + +Fixed by introduce `PARAM_SECRET` and change `sanitize_setting_vpn()` to +copy secrets. + +Signed-off-by: Gris Ge +--- + shared/utils.c | 46 +++++++++++++++++++++++++++++++--------------- + 1 file changed, 31 insertions(+), 15 deletions(-) + +diff --git a/shared/utils.c b/shared/utils.c +index 8dab313..9cb36be 100644 +--- a/shared/utils.c ++++ b/shared/utils.c +@@ -38,6 +38,7 @@ enum LibreswanParamFlags { + PARAM_OLD = 0x0010, /* Only include for libreswan < 4. */ + PARAM_NEW = 0x0020, /* Only include for libreswan >= 4. */ + PARAM_IGNORE = 0x0040, /* Not passed to or from Libreswan. */ ++ PARAM_SECRET = 0x0080, /* For secrets */ + }; + + struct LibreswanParam { +@@ -347,7 +348,9 @@ static const struct LibreswanParam params[] = { + { NM_LIBRESWAN_KEY_PFSGROUP, add, PARAM_IGNORE }, + { NM_LIBRESWAN_KEY_PSK_INPUT_MODES, add, PARAM_IGNORE }, + { NM_LIBRESWAN_KEY_XAUTH_PASSWORD_INPUT_MODES, add, PARAM_IGNORE }, ++ { NM_LIBRESWAN_KEY_PSK_VALUE, add, PARAM_IGNORE | PARAM_SECRET}, + { NM_LIBRESWAN_KEY_PSK_VALUE "-flags", add, PARAM_IGNORE }, ++ { NM_LIBRESWAN_KEY_XAUTH_PASSWORD, add, PARAM_IGNORE | PARAM_SECRET}, + { NM_LIBRESWAN_KEY_XAUTH_PASSWORD "-flags", add, PARAM_IGNORE }, + { NM_LIBRESWAN_KEY_NM_AUTO_DEFAULTS, add, PARAM_IGNORE }, + +@@ -407,22 +410,35 @@ sanitize_setting_vpn (NMSettingVpn *s_vpn, + TRUE); + + for (i = 0; params[i].name != NULL; i++) { +- val = nm_setting_vpn_get_data_item (s_vpn, params[i].name); +- if (val != NULL) { +- handled_items++; +- } else if (params[i].flags & PARAM_REQUIRED) { +- g_set_error (error, +- NM_UTILS_ERROR, +- NM_UTILS_ERROR_INVALID_ARGUMENT, +- _("'%s' key needs to be present"), +- params[i].name); +- return NULL; +- } +- +- if (auto_defaults) { +- params[i].add_sanitized (sanitized, params[i].name, val); ++ if (params[i].flags & PARAM_SECRET) { ++ val = nm_setting_vpn_get_secret(s_vpn, params[i].name); ++ if (val != NULL) { ++ nm_setting_vpn_add_secret(sanitized, ++ params[i].name, ++ val); ++ } + } else { +- nm_setting_vpn_add_data_item (sanitized, params[i].name, val); ++ val = nm_setting_vpn_get_data_item (s_vpn, ++ params[i].name); ++ if (val != NULL) { ++ handled_items++; ++ } else if (params[i].flags & PARAM_REQUIRED) { ++ g_set_error (error, ++ NM_UTILS_ERROR, ++ NM_UTILS_ERROR_INVALID_ARGUMENT, ++ _("'%s' key needs to be present"), ++ params[i].name); ++ return NULL; ++ } ++ ++ if (auto_defaults) { ++ params[i].add_sanitized (sanitized, ++ params[i].name, val); ++ } else { ++ nm_setting_vpn_add_data_item (sanitized, ++ params[i].name, ++ val); ++ } + } + + val = nm_setting_vpn_get_data_item (sanitized, params[i].name); +-- +2.51.0 + diff --git a/SOURCES/0003-import-export-nm-auto-defaults-no.patch b/SOURCES/0003-import-export-nm-auto-defaults-no.patch new file mode 100644 index 0000000..4d075c2 --- /dev/null +++ b/SOURCES/0003-import-export-nm-auto-defaults-no.patch @@ -0,0 +1,228 @@ +From a304902564b3f27080da30c0e5c9adfe6f1071c0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= +Date: Thu, 16 Oct 2025 12:45:41 +0200 +Subject: [PATCH] import/export: add special comment for nm-auto-defaults + detection + +In commit 3ea80883fef we added the nm-auto-defaults property to allow +interpreting configurations just like Libreswan, without assumptions +like setting leftmodecfgclient=yes by default, which is different to +what Libreswan would do. + +This means that with nm-auto-defaults=no the behaviour is slightly +different. When we export a connection with nm-auto-defaults=no, we +cannot reflect it in the exported file, as it is not a valid option in +Libreswan. If we import back the same file, it will be imported as +nm-auto-defaults=yes (by default), thus it will have different +behaviour. This is wrong, export & import should be symetric. + +Make the "write" function to emit a `# nm-auto-defaults=no` comment in +the exported file. When importing, make the "parse" function to +interpret this special comment as `nm-auto-defaults=no`. This will +ensure that we can export & import symetrically. + +The comment can also be added manually to any file that users want to +import. + +Note: increase the minimum GLib version to 2.44 to use g_autoptr. It was +released more than 10 years ago, so we're quite safe. +--- + configure.ac | 6 ++--- + shared/test-utils.c | 57 ++++++++++++++++++++++++++++++++++++++++++--- + shared/utils.c | 25 ++++++++++++++++++-- + 3 files changed, 80 insertions(+), 8 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 9b9677a..f87ffdf 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -116,9 +116,9 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package]) + IT_PROG_INTLTOOL([0.35]) + AM_GLIB_GNU_GETTEXT + +-PKG_CHECK_MODULES(GLIB, gio-unix-2.0 >= 2.36) +-GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_36" +-GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_36" ++PKG_CHECK_MODULES(GLIB, gio-unix-2.0 >= 2.44) ++GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_44" ++GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_44" + + PKG_CHECK_MODULES(LIBNL, libnl-3.0 >= 3.2.8) + +diff --git a/shared/test-utils.c b/shared/test-utils.c +index 8bf5888..c523c9c 100644 +--- a/shared/test-utils.c ++++ b/shared/test-utils.c +@@ -183,7 +183,7 @@ test_config_write (void) + nm_setting_vpn_add_data_item (s_vpn, "leftrsasigkey", "hello"); + nm_setting_vpn_add_data_item (s_vpn, "rightrsasigkey", "world"); + nm_setting_vpn_add_data_item (s_vpn, "right", "11.12.13.14"); +- nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "false"); ++ nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "no"); + nm_setting_vpn_add_data_item (s_vpn, "leftsendcert", "always"); + nm_setting_vpn_add_data_item (s_vpn, "rightca", "%same"); + s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); +@@ -191,6 +191,9 @@ test_config_write (void) + str = nm_libreswan_get_ipsec_conf (4, s_vpn_sanitized, "conn", NULL, FALSE, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, ++ "# NetworkManager specific configs, don't remove:\n" ++ "# nm-auto-defaults=no\n" ++ "\n" + "conn conn\n" + " ikev2=insist\n" + " right=11.12.13.14\n" +@@ -294,7 +297,7 @@ test_config_write (void) + g_object_unref (s_vpn); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); +- nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "false"); ++ nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "no"); + nm_setting_vpn_add_data_item (s_vpn, "rightcert", "\"cert\""); + s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); +@@ -303,7 +306,7 @@ test_config_write (void) + g_object_unref (s_vpn); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); +- nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "false"); ++ nm_setting_vpn_add_data_item (s_vpn, "nm-auto-defaults", "no"); + s_vpn_sanitized = sanitize_setting_vpn (s_vpn, &error); + g_assert_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); + g_assert_null (s_vpn_sanitized); +@@ -612,6 +615,54 @@ test_config_read (void) + g_object_unref (s_vpn); + g_clear_pointer (&con_name, g_free); + ++ /* With the '# nm-auto-defaults=no' special comment */ ++ s_vpn = nm_libreswan_parse_ipsec_conf ( ++ "# nm-auto-defaults=no\n" ++ "conn conn\n" ++ " ikev2=insist\n" ++ " right=11.12.13.14\n" ++ " rightrsasigkey=\"world\"\n" ++ " leftrsasigkey=\"hello\"\n" ++ " leftsendcert=always\n" ++ " rightca=\"%same\"\n", ++ &con_name, ++ &error); ++ g_assert_no_error (error); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "ikev2"), ==, "insist"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "leftrsasigkey"), == , "hello"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "rightrsasigkey"), == , "world"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "right"), == , "11.12.13.14"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "nm-auto-defaults"), == , "no"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "leftsendcert"), == , "always"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "rightca"), == , "%same"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "rightca"), == , "%same"); ++ g_object_unref (s_vpn); ++ g_clear_pointer (&con_name, g_free); ++ ++ /* With the '# nm-auto-defaults=no' special comment, different spacing */ ++ s_vpn = nm_libreswan_parse_ipsec_conf ( ++ "#nm-auto-defaults = no \n" ++ "conn conn\n" ++ " ikev2=insist\n" ++ " right=11.12.13.14\n" ++ " rightrsasigkey=\"world\"\n" ++ " leftrsasigkey=\"hello\"\n" ++ " leftsendcert=always\n" ++ " rightca=\"%same\"\n", ++ &con_name, ++ &error); ++ g_assert_no_error (error); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "ikev2"), ==, "insist"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "leftrsasigkey"), == , "hello"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "rightrsasigkey"), == , "world"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "right"), == , "11.12.13.14"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "nm-auto-defaults"), == , "no"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "leftsendcert"), == , "always"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "rightca"), == , "%same"); ++ g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, "rightca"), == , "%same"); ++ g_object_unref (s_vpn); ++ g_clear_pointer (&con_name, g_free); ++ + s_vpn = nm_libreswan_parse_ipsec_conf ( + "conn my_con\n", + &con_name, +diff --git a/shared/utils.c b/shared/utils.c +index 9cb36be..c188e5b 100644 +--- a/shared/utils.c ++++ b/shared/utils.c +@@ -482,6 +482,7 @@ nm_libreswan_get_ipsec_conf (int ipsec_version, + GError **error) + { + nm_auto_free_gstring GString *ipsec_conf = NULL; ++ gboolean auto_defaults; + const char *val; + int i; + +@@ -493,6 +494,16 @@ nm_libreswan_get_ipsec_conf (int ipsec_version, + return NULL; + + ipsec_conf = g_string_sized_new (1024); ++ ++ auto_defaults = _nm_utils_ascii_str_to_bool ( ++ nm_setting_vpn_get_data_item (s_vpn_sanitized, NM_LIBRESWAN_KEY_NM_AUTO_DEFAULTS), ++ TRUE); ++ if (!auto_defaults) { ++ g_string_append(ipsec_conf, "# NetworkManager specific configs, don't remove:\n"); ++ g_string_append(ipsec_conf, "# nm-auto-defaults=no\n"); ++ g_string_append(ipsec_conf, "\n"); ++ } ++ + g_string_append_printf (ipsec_conf, "conn %s\n", con_name); + + for (i = 0; params[i].name != NULL; i++) { +@@ -573,6 +584,8 @@ static const char line_match[] = + ")?" /* (or just blank line) */ + "\\s*(?:#.*)?$"; /* optional comment */ + ++static const char no_auto_match[] = "#\\s*nm-auto-defaults\\s*=\\s*no"; ++ + NMSettingVpn * + nm_libreswan_parse_ipsec_conf (const char *ipsec_conf, + char **out_con_name, +@@ -584,7 +597,8 @@ nm_libreswan_parse_ipsec_conf (const char *ipsec_conf, + gs_free char *con_name = NULL; + GMatchInfo *match_info = NULL; + GError *parse_error = NULL; +- GRegex *line_regex; ++ g_autoptr(GRegex) line_regex = NULL; ++ g_autoptr(GRegex) no_auto_regex = NULL; + const char *old, *new; + const char *rekey; + char *key, *val; +@@ -596,6 +610,8 @@ nm_libreswan_parse_ipsec_conf (const char *ipsec_conf, + + line_regex = g_regex_new (line_match, G_REGEX_RAW, 0, NULL); + g_return_val_if_fail (line_regex, NULL); ++ no_auto_regex = g_regex_new (no_auto_match, G_REGEX_RAW, 0, NULL); ++ g_return_val_if_fail (no_auto_regex, NULL); + + s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ()); + +@@ -611,6 +627,11 @@ nm_libreswan_parse_ipsec_conf (const char *ipsec_conf, + break; + } + ++ if (g_regex_match(no_auto_regex, lines[i], 0, NULL)) { ++ nm_setting_vpn_add_data_item(s_vpn, NM_LIBRESWAN_KEY_NM_AUTO_DEFAULTS, "no"); ++ continue; ++ } ++ + key = g_match_info_fetch (match_info, 1); /* Key */ + val = g_match_info_fetch (match_info, 2); /* Unquoted value */ + /* Without fix from +@@ -666,7 +687,7 @@ nm_libreswan_parse_ipsec_conf (const char *ipsec_conf, + if (parse_error) + break; + } +- g_regex_unref (line_regex); ++ + if (parse_error) { + g_propagate_error (error, parse_error); + return NULL; +-- +2.51.0 + diff --git a/SOURCES/0004-sanitize-before-exporting-RHEL-only.patch b/SOURCES/0004-sanitize-before-exporting-RHEL-only.patch new file mode 100644 index 0000000..f396d31 --- /dev/null +++ b/SOURCES/0004-sanitize-before-exporting-RHEL-only.patch @@ -0,0 +1,54 @@ +From 15946667c771ba88d38f82cc467fd52d268e44bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= +Date: Tue, 21 Oct 2025 08:37:35 +0200 +Subject: [PATCH] export: sanitize before exporting (RHEL only) + +The commit referenced below moved the responsibility of sanitizing the +connection from nm_libreswan_get_ipsec_conf to its caller, but it forgot +to sanitize in export_to_file(). Fix it. + +This is a RHEL-only patch, as this is fixed by a later commit that we +didn't want to backport yet. When we rebase, this patch can be dropped. + +Fixes: 50d0fc5a265b ('Fix PSK authentication when leftid starts with `@`') +--- + properties/nm-libreswan-editor-plugin.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/properties/nm-libreswan-editor-plugin.c b/properties/nm-libreswan-editor-plugin.c +index 2b455ba..7a75e09 100644 +--- a/properties/nm-libreswan-editor-plugin.c ++++ b/properties/nm-libreswan-editor-plugin.c +@@ -91,6 +91,7 @@ export_to_file (NMVpnEditorPlugin *self, + GError **error) + { + NMSettingVpn *s_vpn; ++ gs_unref_object NMSettingVpn *s_vpn_sanitized = NULL; + gboolean openswan = FALSE; + gs_free_error GError *local = NULL; + gs_free char *ipsec_conf = NULL; +@@ -98,8 +99,19 @@ export_to_file (NMVpnEditorPlugin *self, + int version; + + s_vpn = nm_connection_get_setting_vpn (connection); +- if (s_vpn) +- openswan = nm_streq (nm_setting_vpn_get_service_type (s_vpn), NM_VPN_SERVICE_TYPE_OPENSWAN); ++ if (!s_vpn) { ++ g_set_error_literal (error, ++ NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INVALID_CONNECTION, ++ _("Empty VPN setting.")); ++ return FALSE; ++ } ++ ++ s_vpn_sanitized = sanitize_setting_vpn (s_vpn, error); ++ if (!s_vpn_sanitized) ++ return FALSE; ++ ++ s_vpn = s_vpn_sanitized; ++ openswan = nm_streq (nm_setting_vpn_get_service_type (s_vpn), NM_VPN_SERVICE_TYPE_OPENSWAN); + + nm_libreswan_detect_version (nm_libreswan_find_helper_bin ("ipsec", NULL), + &is_openswan, &version, NULL); +-- +2.51.0 + diff --git a/SOURCES/0005-service-don-t-crash-with-malformed-connections.patch b/SOURCES/0005-service-don-t-crash-with-malformed-connections.patch new file mode 100644 index 0000000..e5f1a54 --- /dev/null +++ b/SOURCES/0005-service-don-t-crash-with-malformed-connections.patch @@ -0,0 +1,61 @@ +From 397096f85c155d18834e8f7b90b1ea439344cd32 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= +Date: Thu, 23 Oct 2025 11:54:46 +0200 +Subject: [PATCH] service: don't crash with malformed connections + +If a connection is malformed, i.e. by having incorrect values, a crash +(or something worse) could happen in _connect_common because we were +assuming that the value returned from sanitize_setting_vpn() must be +non-NULL. If the connection is malformed, it will be NULL. + +Fix it by gracefully handling this scenario. + +This is a RHEL-only patch, as this is fixed by a later commit that we +didn't want to backport yet. When we rebase, this patch can be dropped. + +Fixes: 50d0fc5a265b ('Fix PSK authentication when leftid starts with `@`') +--- + src/nm-libreswan-service.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/src/nm-libreswan-service.c b/src/nm-libreswan-service.c +index 58ada03..a093547 100644 +--- a/src/nm-libreswan-service.c ++++ b/src/nm-libreswan-service.c +@@ -1756,7 +1756,8 @@ _connect_common (NMVpnServicePlugin *plugin, + { + NMLibreswanPlugin *self = NM_LIBRESWAN_PLUGIN (plugin); + NMLibreswanPluginPrivate *priv = NM_LIBRESWAN_PLUGIN_GET_PRIVATE (self); +- gs_unref_object NMSettingVpn *s_vpn = NULL; ++ NMSettingVpn *s_vpn; ++ gs_unref_object NMSettingVpn *s_vpn_sanitized = NULL; + const char *con_name = nm_connection_get_uuid (connection); + gs_free char *ipsec_banner = NULL; + gs_free char *ifupdown_script = NULL; +@@ -1794,9 +1795,20 @@ _connect_common (NMVpnServicePlugin *plugin, + return FALSE; + } + +- s_vpn = sanitize_setting_vpn(nm_connection_get_setting_vpn (connection), +- error); +- g_assert (s_vpn); ++ s_vpn = nm_connection_get_setting_vpn(connection); ++ if (!s_vpn) { ++ g_set_error_literal(error, ++ NM_VPN_PLUGIN_ERROR, ++ NM_VPN_PLUGIN_ERROR_INVALID_CONNECTION, ++ _("Empty VPN setting.")); ++ return FALSE; ++ } ++ ++ s_vpn_sanitized = sanitize_setting_vpn(s_vpn, error); ++ if (!s_vpn_sanitized) ++ return FALSE; ++ ++ s_vpn = s_vpn_sanitized; + + g_object_get (self, NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, &bus_name, NULL); + +-- +2.51.0 + diff --git a/SPECS/NetworkManager-libreswan.spec b/SPECS/NetworkManager-libreswan.spec index f35f8b1..fbab3c0 100644 --- a/SPECS/NetworkManager-libreswan.spec +++ b/SPECS/NetworkManager-libreswan.spec @@ -9,9 +9,9 @@ %bcond_without gtk4 %endif -%global real_version 1.2.22 -%global rpm_version 1.2.22 -%global release_version 4 +%global real_version 1.2.27 +%global rpm_version 1.2.27 +%global release_version 2 %global real_version_major %(printf '%s' '%{real_version}' | sed -n 's/^\\([1-9][0-9]*\\.[1-9][0-9]*\\)\\.[1-9][0-9]*$/\\1/p') @@ -24,14 +24,17 @@ Name: NetworkManager-libreswan Version: %{rpm_version} Release: %{release_version}%{?dist} License: GPLv2+ -URL: http://www.gnome.org/projects/NetworkManager/ +URL: https://gitlab.gnome.org/GNOME/NetworkManager-libreswan/ Source0: https://download.gnome.org/sources/NetworkManager-libreswan/%{real_version_major}/%{name}-%{real_version}.tar.xz -# Patch1: 0001-some.patch -Patch1: 0001-ipsec-conf-escaping-cve-2024-9050.patch +Patch0: 0001-Export-esp-option.patch +Patch1: 0002-fix-psk-auth-when-leftid-starts-with-at.patch +Patch2: 0003-import-export-nm-auto-defaults-no.patch +Patch3: 0004-sanitize-before-exporting-RHEL-only.patch +Patch4: 0005-service-don-t-crash-with-malformed-connections.patch BuildRequires: make -BuildRequires: gcc +BuildRequires: gcc BuildRequires: gtk3-devel BuildRequires: libnl3-devel BuildRequires: NetworkManager-libnm-devel >= %{nm_version} @@ -130,12 +133,27 @@ rm -f %{buildroot}%{_libdir}/NetworkManager/lib*.la %endif %changelog -* Thu Oct 03 2024 Lubomir Rintel - 1.2.22-4 -- Unbreak validation of unknown keys +* Thu Oct 23 2025 Vladimír Beneš - 1.2.22-2 +* Tue Oct 21 2025 Vladimír Beneš - 1.2.26-1 +- Update to 1.2.26 release +- Add support for leftsubnets/rightsubnets (RHEL-56553) + +* Tue Oct 22 2024 Lubomir Rintel - 1.2.24-1 +- Update to 1.2.24 release - Fix improper escaping of Libreswan configuration (CVE-2024-9050) +* Thu Sep 12 2024 Íñigo Huguet - 1.2.22-2 +- Support require-id-on-certificate (RHEL-58040) + * Wed May 22 2024 Beniamino Galvani - 1.2.22-1 - Add IPv6 support (RHEL-21875)