1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
From 0078c320fc2f8342613b5ea849cc697778e1fa6a Mon Sep 17 00:00:00 2001
From: Josephine Pfeiffer <josie@redhat.com>
Date: Thu, 23 Jul 2026 22:27:58 +0200
Subject: [PATCH] service: support private connections
Since NetworkManager 1.58 the daemon refuses to activate a private VPN
connection (one with a user in connection.permissions) unless the plugin
declares supports-safe-private-file-access, so per-user openconnect
connections broke on upgrade with "The 'openconnect' plugin doesn't
support private connections."
The service runs as root and passes the CA certificate (--cafile) to the
openconnect binary. Read it via nm_utils_copy_cert_as_user() (libnm
1.52.2) so a private connection's file is accessed as the owning user, and
declare the capability in the .name file.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1989
---
configure.ac | 2 +-
nm-openconnect-service.name.in | 1 +
src/nm-openconnect-service.c | 54 +++++++++++++++++++++++++++++++++-
3 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index b1cc414..c712ec2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -145,7 +145,7 @@ if test x"$with_gtk4" != xno; then
PKG_CHECK_MODULES(LIBNMA_GTK4, libnma-gtk4 >= 1.8.33)
fi
-PKG_CHECK_MODULES(LIBNM, libnm >= 1.2.0)
+PKG_CHECK_MODULES(LIBNM, libnm >= 1.52.2)
LIBNM_CFLAGS="$LIBNM_CFLAGS -DNM_VERSION_MIN_REQUIRED=NM_VERSION_1_2"
LIBNM_CFLAGS="$LIBNM_CFLAGS -DNM_VERSION_MAX_ALLOWED=NM_VERSION_1_4"
diff --git a/nm-openconnect-service.name.in b/nm-openconnect-service.name.in
index 78d8535..bc2c7e2 100644
--- a/nm-openconnect-service.name.in
+++ b/nm-openconnect-service.name.in
@@ -3,6 +3,7 @@ name=openconnect
service=org.freedesktop.NetworkManager.openconnect
program=@LIBEXECDIR@/nm-openconnect-service
supports-multiple-connections=true
+supports-safe-private-file-access=true
[libnm]
plugin=@PLUGINDIR@/libnm-vpn-plugin-openconnect.so
diff --git a/src/nm-openconnect-service.c b/src/nm-openconnect-service.c
index 0005534..ccf3476 100644
--- a/src/nm-openconnect-service.c
+++ b/src/nm-openconnect-service.c
@@ -122,6 +122,7 @@ static struct {
gboolean debug;
int log_level;
GMainLoop *loop;
+ GPtrArray *tmp_file_paths;
} gl/*obal*/;
/*****************************************************************************/
@@ -424,6 +425,43 @@ openconnect_watch_cb (GPid pid, gint status, gpointer user_data)
}
}
+static const char *
+get_connection_permission_user (NMSettingConnection *s_con)
+{
+ const char *ptype;
+ const char *pitem;
+ const char *pdetail;
+ guint num_perms;
+ guint i;
+
+ num_perms = nm_setting_connection_get_num_permissions (s_con);
+ for (i = 0; i < num_perms; i++) {
+ if (!nm_setting_connection_get_permission (s_con, i, &ptype, &pitem, &pdetail))
+ continue;
+ if (nm_streq0 (ptype, "user"))
+ return pitem;
+ }
+ return NULL;
+}
+
+/* On a private connection the daemon runs us as root, but a file the
+ * connection references must be read with the owning user's privileges. */
+static char *
+access_file (const char *filename, const char *user, GError **error)
+{
+ char *tmp;
+
+ if (!user)
+ return g_strdup (filename);
+
+ tmp = nm_utils_copy_cert_as_user (filename, user, error);
+ if (!tmp)
+ return NULL;
+
+ g_ptr_array_add (gl.tmp_file_paths, g_strdup (tmp));
+ return tmp;
+}
+
static gint
nm_openconnect_start_openconnect_binary (NMOpenconnectPlugin *plugin,
NMSettingConnection *s_con,
@@ -442,6 +480,8 @@ nm_openconnect_start_openconnect_binary (NMOpenconnectPlugin *plugin,
const char *props_disable_udp;
const char *protocol;
const char *props_tun_name;
+ const char *user;
+ gs_free char *cafile = NULL;
/* Find openconnect */
openconnect_binary = openconnect_binary_paths;
@@ -484,6 +524,8 @@ nm_openconnect_start_openconnect_binary (NMOpenconnectPlugin *plugin,
props_gwcert = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GWCERT);
props_resolve = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_RESOLVE);
+ user = get_connection_permission_user (s_con);
+
props_cacert = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_CACERT);
props_mtu = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_MTU);
@@ -507,8 +549,13 @@ nm_openconnect_start_openconnect_binary (NMOpenconnectPlugin *plugin,
g_ptr_array_add (openconnect_argv, (gpointer) "--servercert");
g_ptr_array_add (openconnect_argv, (gpointer) props_gwcert);
} else if (props_cacert && strlen(props_cacert)) {
+ cafile = access_file (props_cacert, user, error);
+ if (!cafile) {
+ g_ptr_array_free (openconnect_argv, TRUE);
+ return -1;
+ }
g_ptr_array_add (openconnect_argv, (gpointer) "--cafile");
- g_ptr_array_add (openconnect_argv, (gpointer) props_cacert);
+ g_ptr_array_add (openconnect_argv, (gpointer) cafile);
}
if (props_mtu && strlen(props_mtu)) {
@@ -839,6 +886,7 @@ int main (int argc, char *argv[])
exit (EXIT_FAILURE);
gl.loop = g_main_loop_new (NULL, FALSE);
+ gl.tmp_file_paths = g_ptr_array_new_with_free_func (g_free);
if (!persist)
g_signal_connect (plugin, "quit", G_CALLBACK (quit_mainloop), gl.loop);
@@ -849,5 +897,9 @@ int main (int argc, char *argv[])
g_clear_pointer (&gl.loop, g_main_loop_unref);
g_object_unref (plugin);
+ for (guint i = 0; i < gl.tmp_file_paths->len; i++)
+ unlink ((const char *) gl.tmp_file_paths->pdata[i]);
+ g_ptr_array_unref (gl.tmp_file_paths);
+
exit (EXIT_SUCCESS);
}
--
GitLab
|