Merge ~hellsworth/snappy-hwe-snaps/+git/network-manager:add-netplan into ~snappy-hwe-team/snappy-hwe-snaps/+git/network-manager:snap-20
- Git
- lp:~hellsworth/snappy-hwe-snaps/+git/network-manager
- add-netplan
- Merge into snap-20
Status: | Merged |
---|---|
Approved by: | Alfonso Sanchez-Beato |
Approved revision: | 9f4ffcffb20516c4648cfcb5b47ba4edecd0ef7e |
Merged at revision: | 54fd7daf463370dcc7a3529e1eacae16420c90b2 |
Proposed branch: | ~hellsworth/snappy-hwe-snaps/+git/network-manager:add-netplan |
Merge into: | ~snappy-hwe-team/snappy-hwe-snaps/+git/network-manager:snap-20 |
Diff against target: |
66425 lines (+66390/-0) 2 files modified
snap-patch/networkmanager/0002-nm-netplan.patch (+66384/-0) snap/snapcraft.yaml (+6/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Lukas Märdian | Approve | ||
Alfonso Sanchez-Beato | Approve | ||
System Enablement Bot | continuous-integration | Approve | |
Review via email: mp+391222@code.launchpad.net |
Commit message
Add netplan patch
Description of the change
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:9f4ffcffb20
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:9f4ffcffb20
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:9f4ffcffb20
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
snapcraft.yaml changes LGTM
Lukas Märdian (slyon) wrote : | # |
+1.
The netplan patch itself has been checked by Lukasz and myself. Also, it contains an automatic test-suite in src/settings/
Preview Diff
1 | diff --git a/snap-patch/networkmanager/0002-nm-netplan.patch b/snap-patch/networkmanager/0002-nm-netplan.patch |
2 | new file mode 100644 |
3 | index 0000000..8ffcb4f |
4 | --- /dev/null |
5 | +++ b/snap-patch/networkmanager/0002-nm-netplan.patch |
6 | @@ -0,0 +1,66384 @@ |
7 | +From 2c8ce0635167a447df9c1cee1c3fbd8bc40b3e48 Mon Sep 17 00:00:00 2001 |
8 | +From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> |
9 | +Date: Mon, 16 Sep 2019 11:12:57 +0100 |
10 | +Subject: [PATCH 01/80] Import structure based on ifcfg-rh |
11 | + |
12 | +--- |
13 | + configure.ac | 7 + |
14 | + meson.build | 8 + |
15 | + src/settings/plugins/meson.build | 4 + |
16 | + src/settings/plugins/netplan/meson.build | 48 + |
17 | + .../plugins/netplan/nms-netplan-plugin.c | 1259 ++ |
18 | + .../plugins/netplan/nms-netplan-plugin.h | 25 + |
19 | + .../plugins/netplan/nms-netplan-reader.c | 5991 +++++++++ |
20 | + .../plugins/netplan/nms-netplan-reader.h | 23 + |
21 | + .../plugins/netplan/nms-netplan-utils.c | 589 + |
22 | + .../plugins/netplan/nms-netplan-utils.h | 90 + |
23 | + .../plugins/netplan/nms-netplan-writer.c | 3464 +++++ |
24 | + .../plugins/netplan/nms-netplan-writer.h | 29 + |
25 | + .../plugins/netplan/tests/meson.build | 17 + |
26 | + .../plugins/netplan/tests/test-netplan.c | 10485 ++++++++++++++++ |
27 | + 14 files changed, 22039 insertions(+) |
28 | + create mode 100644 src/settings/plugins/netplan/meson.build |
29 | + create mode 100644 src/settings/plugins/netplan/nms-netplan-plugin.c |
30 | + create mode 100644 src/settings/plugins/netplan/nms-netplan-plugin.h |
31 | + create mode 100644 src/settings/plugins/netplan/nms-netplan-reader.c |
32 | + create mode 100644 src/settings/plugins/netplan/nms-netplan-reader.h |
33 | + create mode 100644 src/settings/plugins/netplan/nms-netplan-utils.c |
34 | + create mode 100644 src/settings/plugins/netplan/nms-netplan-utils.h |
35 | + create mode 100644 src/settings/plugins/netplan/nms-netplan-writer.c |
36 | + create mode 100644 src/settings/plugins/netplan/nms-netplan-writer.h |
37 | + create mode 100644 src/settings/plugins/netplan/tests/meson.build |
38 | + create mode 100644 src/settings/plugins/netplan/tests/test-netplan.c |
39 | + |
40 | +diff --git a/configure.ac b/configure.ac |
41 | +index 4f36e8825fa2f0a08b5bcabe26b11ad8564af27c..66986e52a64a308c41ead80678c80e688ca7fa5b 100644 |
42 | +--- a/configure.ac |
43 | ++++ b/configure.ac |
44 | +@@ -143,15 +143,19 @@ AC_CHECK_FUNCS([__secure_getenv secure_getenv]) |
45 | + |
46 | + # Alternative configuration plugins |
47 | + AC_ARG_ENABLE(ifcfg-rh, AS_HELP_STRING([--enable-ifcfg-rh], [enable ifcfg-rh configuration plugin (Fedora/RHEL)])) |
48 | ++AC_ARG_ENABLE(netplan, AS_HELP_STRING([--enable-netplan], [enable netplan configuration plugin (Ubuntu)])) |
49 | + AC_ARG_ENABLE(ifupdown, AS_HELP_STRING([--enable-ifupdown], [enable ifupdown configuration plugin (Debian/Ubuntu)])) |
50 | + # Default alternative plugins by distribution |
51 | + AS_IF([test -z "$enable_ifcfg_rh" -a -d /etc/sysconfig/network-scripts], enable_ifcfg_rh=yes) |
52 | ++AS_IF([test -z "$enable_netplan" -a -d /etc/netplan], enable_netplan=yes) |
53 | + AS_IF([test -z "$enable_ifupdown" -a -f /etc/debian_version], enable_ifupdown=yes) |
54 | + # Otherwise plugins default to "no" |
55 | + AS_IF([test -z "$enable_ifcfg_rh"], enable_ifcfg_rh=no) |
56 | ++AS_IF([test -z "$enable_netplan"], enable_netplan=no) |
57 | + AS_IF([test -z "$enable_ifupdown"], enable_ifupdown=no) |
58 | + # Create automake conditionals |
59 | + AM_CONDITIONAL(CONFIG_PLUGIN_IFCFG_RH, test "$enable_ifcfg_rh" = "yes") |
60 | ++AM_CONDITIONAL(CONFIG_PLUGIN_NETPLAN, test "$enable_netplan" = "yes") |
61 | + AM_CONDITIONAL(CONFIG_PLUGIN_IFUPDOWN, test "$enable_ifupdown" = "yes") |
62 | + |
63 | + AC_ARG_WITH(config-plugins-default, |
64 | +@@ -161,11 +165,13 @@ AC_ARG_WITH(config-plugins-default, |
65 | + if test -z "$config_plugins_default" -o "$config_plugins_default" = no; then |
66 | + config_plugins_default='' |
67 | + test "$enable_ifcfg_rh" = "yes" && config_plugins_default="$config_plugins_default,ifcfg-rh" |
68 | ++ test "$enable_netplan" = "yes" && config_plugins_default="$config_plugins_default,netplan" |
69 | + test "$enable_ifupdown" = "yes" && config_plugins_default="$config_plugins_default,ifupdown" |
70 | + config_plugins_default="${config_plugins_default#,}" |
71 | + fi |
72 | + |
73 | + test "$enable_ifcfg_rh" = "yes" && distro_plugins="$distro_plugins,ifcfg-rh" |
74 | ++test "$enable_netplan" = "yes" && distro_plugins="$distro_plugins,netplan" |
75 | + test "$enable_ifupdown" = "yes" && distro_plugins="$distro_plugins,ifupdown" |
76 | + distro_plugins="${distro_plugins#,}" |
77 | + |
78 | +@@ -1320,6 +1326,7 @@ echo |
79 | + |
80 | + echo "Configuration plugins (main.plugins=${config_plugins_default})" |
81 | + echo " ifcfg-rh: ${enable_ifcfg_rh}" |
82 | ++echo " netplan: ${enable_netplan}" |
83 | + echo " ifupdown: ${enable_ifupdown}" |
84 | + echo |
85 | + |
86 | +diff --git a/meson.build b/meson.build |
87 | +index 5bd55e6a0884b52a69d7295b3e0d2bbf5f8ae1fe..1d59d95104ac03d33b7c90f384260f394f0225d1 100644 |
88 | +--- a/meson.build |
89 | ++++ b/meson.build |
90 | +@@ -279,6 +279,8 @@ glib_dep = declare_dependency( |
91 | + |
92 | + if run_command('test', '-e', '/etc/sysconfig/network-scripts').returncode() == 0 |
93 | + distro = 'redhat' |
94 | ++elif run_command('test', '-e', '/etc/netplan').returncode() == 0 |
95 | ++ distro = 'ubuntu' |
96 | + elif run_command('test', '-e', '/etc/SuSE-release').returncode() == 0 |
97 | + distro = 'suse' |
98 | + elif run_command('test', '-e', '/etc/debian_version').returncode() == 0 |
99 | +@@ -290,6 +292,7 @@ else |
100 | + endif |
101 | + |
102 | + enable_ifcfg_rh = get_option('ifcfg_rh') or (distro == 'redhat') |
103 | ++enable_netplan = get_option('netplan') or (distro == 'ubuntu') |
104 | + enable_ifupdown = get_option('ifupdown') or (distro == 'debian') |
105 | + |
106 | + config_plugins_default = get_option('config_plugins_default') |
107 | +@@ -300,6 +303,10 @@ if config_plugins_default == '' |
108 | + config_plugins += ['ifcfg-rh'] |
109 | + endif |
110 | + |
111 | ++ if enable_netplan |
112 | ++ config_plugins += ['netplan'] |
113 | ++ endif |
114 | ++ |
115 | + if enable_ifupdown |
116 | + config_plugins += ['ifupdown'] |
117 | + endif |
118 | +@@ -1006,6 +1013,7 @@ output += ' nmtui: ' + enable_nmtui.to_string() + '\n' |
119 | + output += ' nm-cloud-setup: ' + enable_nm_cloud_setup.to_string() + '\n' |
120 | + output += '\nConfiguration_plugins (main.plugins=' + config_plugins_default + ')\n' |
121 | + output += ' ifcfg-rh: ' + enable_ifcfg_rh.to_string() + '\n' |
122 | ++output += ' netplan: ' + enable_netplan.to_string() + '\n' |
123 | + output += ' ifupdown: ' + enable_ifupdown.to_string() + '\n' |
124 | + output += '\nHandlers for /etc/resolv.conf:\n' + resolv_conf_summary |
125 | + output += '\n' |
126 | +diff --git a/src/settings/plugins/meson.build b/src/settings/plugins/meson.build |
127 | +index 83981aaba77a2fb869191fcc58235664bd729120..c36a69cd35ba342554d4b4924ce9bd4fd8835d55 100644 |
128 | +--- a/src/settings/plugins/meson.build |
129 | ++++ b/src/settings/plugins/meson.build |
130 | +@@ -6,6 +6,10 @@ if enable_ifupdown |
131 | + subdir('ifupdown') |
132 | + endif |
133 | + |
134 | ++if enable_netplan |
135 | ++ subdir('netplan') |
136 | ++endif |
137 | ++ |
138 | + if enable_tests |
139 | + subdir('keyfile/tests') |
140 | + endif |
141 | +diff --git a/src/settings/plugins/netplan/meson.build b/src/settings/plugins/netplan/meson.build |
142 | +new file mode 100644 |
143 | +index 0000000000000000000000000000000000000000..365ae1a9c50980c1d14d56db9d76dedfb8e9aec7 |
144 | +--- /dev/null |
145 | ++++ b/src/settings/plugins/netplan/meson.build |
146 | +@@ -0,0 +1,48 @@ |
147 | ++sources = files( |
148 | ++ 'nms-ifupdown-interface-parser.c', |
149 | ++ 'nms-ifupdown-parser.c', |
150 | ++) |
151 | ++ |
152 | ++deps = [ |
153 | ++ libudev_dep, |
154 | ++ nm_dep, |
155 | ++] |
156 | ++ |
157 | ++libnms_ifupdown_core = static_library( |
158 | ++ 'nms-ifupdown-core', |
159 | ++ sources: sources, |
160 | ++ dependencies: deps, |
161 | ++) |
162 | ++ |
163 | ++sources = files( |
164 | ++ 'nms-ifupdown-plugin.c', |
165 | ++) |
166 | ++ |
167 | ++libnm_settings_plugin_ifupdown = shared_module( |
168 | ++ 'nm-settings-plugin-ifupdown', |
169 | ++ sources: sources, |
170 | ++ dependencies: deps, |
171 | ++ link_with: libnms_ifupdown_core, |
172 | ++ link_args: ldflags_linker_script_settings, |
173 | ++ link_depends: linker_script_settings, |
174 | ++ install: true, |
175 | ++ install_dir: nm_plugindir, |
176 | ++) |
177 | ++ |
178 | ++core_plugins += libnm_settings_plugin_ifupdown |
179 | ++ |
180 | ++# FIXME: check_so_symbols replacement |
181 | ++''' |
182 | ++run_target( |
183 | ++ 'check-local-symbols-settings-ifupdown', |
184 | ++ command: [check_so_symbols, libnm_settings_plugin_ifupdown.full_path()], |
185 | ++ depends: libnm_settings_plugin_ifupdown, |
186 | ++) |
187 | ++ |
188 | ++check-local-symbols-settings-ifupdown: src/settings/plugins/ifupdown/libnm-settings-plugin-ifupdown.la |
189 | ++ $(call check_so_symbols,$(builddir)/src/settings/plugins/ifupdown/.libs/libnm-settings-plugin-ifupdown.so) |
190 | ++''' |
191 | ++ |
192 | ++if enable_tests |
193 | ++ subdir('tests') |
194 | ++endif |
195 | +diff --git a/src/settings/plugins/netplan/nms-netplan-plugin.c b/src/settings/plugins/netplan/nms-netplan-plugin.c |
196 | +new file mode 100644 |
197 | +index 0000000000000000000000000000000000000000..f438755d98958623d6d0dc06086a83610c0f3072 |
198 | +--- /dev/null |
199 | ++++ b/src/settings/plugins/netplan/nms-netplan-plugin.c |
200 | +@@ -0,0 +1,1259 @@ |
201 | ++// SPDX-License-Identifier: GPL-2.0+ |
202 | ++/* NetworkManager system settings service |
203 | ++ * |
204 | ++ * Dan Williams <dcbw@redhat.com> |
205 | ++ * Søren Sandmann <sandmann@daimi.au.dk> |
206 | ++ * |
207 | ++ * Copyright (C) 2007 - 2011 Red Hat, Inc. |
208 | ++ */ |
209 | ++ |
210 | ++#include "nm-default.h" |
211 | ++ |
212 | ++#include "nms-ifcfg-rh-plugin.h" |
213 | ++ |
214 | ++#include <sys/types.h> |
215 | ++#include <sys/stat.h> |
216 | ++#include <unistd.h> |
217 | ++ |
218 | ++#include "nm-std-aux/c-list-util.h" |
219 | ++#include "nm-glib-aux/nm-c-list.h" |
220 | ++#include "nm-glib-aux/nm-io-utils.h" |
221 | ++#include "nm-std-aux/nm-dbus-compat.h" |
222 | ++#include "nm-utils.h" |
223 | ++#include "nm-core-internal.h" |
224 | ++#include "nm-config.h" |
225 | ++#include "settings/nm-settings-plugin.h" |
226 | ++#include "settings/nm-settings-utils.h" |
227 | ++#include "NetworkManagerUtils.h" |
228 | ++ |
229 | ++#include "nms-ifcfg-rh-storage.h" |
230 | ++#include "nms-ifcfg-rh-common.h" |
231 | ++#include "nms-ifcfg-rh-utils.h" |
232 | ++#include "nms-ifcfg-rh-reader.h" |
233 | ++#include "nms-ifcfg-rh-writer.h" |
234 | ++ |
235 | ++#define IFCFGRH1_BUS_NAME "com.redhat.ifcfgrh1" |
236 | ++#define IFCFGRH1_OBJECT_PATH "/com/redhat/ifcfgrh1" |
237 | ++#define IFCFGRH1_IFACE1_NAME "com.redhat.ifcfgrh1" |
238 | ++#define IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS "GetIfcfgDetails" |
239 | ++ |
240 | ++/*****************************************************************************/ |
241 | ++ |
242 | ++typedef struct { |
243 | ++ NMConfig *config; |
244 | ++ |
245 | ++ struct { |
246 | ++ GDBusConnection *connection; |
247 | ++ GCancellable *cancellable; |
248 | ++ gulong signal_id; |
249 | ++ guint regist_id; |
250 | ++ } dbus; |
251 | ++ |
252 | ++ NMSettUtilStorages storages; |
253 | ++ |
254 | ++ GHashTable *unmanaged_specs; |
255 | ++ GHashTable *unrecognized_specs; |
256 | ++ |
257 | ++} NMSIfcfgRHPluginPrivate; |
258 | ++ |
259 | ++struct _NMSIfcfgRHPlugin { |
260 | ++ NMSettingsPlugin parent; |
261 | ++ NMSIfcfgRHPluginPrivate _priv; |
262 | ++}; |
263 | ++ |
264 | ++struct _NMSIfcfgRHPluginClass { |
265 | ++ NMSettingsPluginClass parent; |
266 | ++}; |
267 | ++ |
268 | ++G_DEFINE_TYPE (NMSIfcfgRHPlugin, nms_ifcfg_rh_plugin, NM_TYPE_SETTINGS_PLUGIN) |
269 | ++ |
270 | ++#define NMS_IFCFG_RH_PLUGIN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSIfcfgRHPlugin, NMS_IS_IFCFG_RH_PLUGIN, NMSettingsPlugin) |
271 | ++ |
272 | ++/*****************************************************************************/ |
273 | ++ |
274 | ++#define _NMLOG_DOMAIN LOGD_SETTINGS |
275 | ++#define _NMLOG(level, ...) \ |
276 | ++ G_STMT_START { \ |
277 | ++ nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \ |
278 | ++ "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ |
279 | ++ "ifcfg-rh: " \ |
280 | ++ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ |
281 | ++ } G_STMT_END |
282 | ++ |
283 | ++/*****************************************************************************/ |
284 | ++ |
285 | ++static void _unhandled_specs_reset (NMSIfcfgRHPlugin *self); |
286 | ++ |
287 | ++static void _unhandled_specs_merge_storages (NMSIfcfgRHPlugin *self, |
288 | ++ NMSettUtilStorages *storages); |
289 | ++ |
290 | ++/*****************************************************************************/ |
291 | ++ |
292 | ++static void |
293 | ++nm_assert_self (NMSIfcfgRHPlugin *self, gboolean unhandled_specs_consistent) |
294 | ++{ |
295 | ++ nm_assert (NMS_IS_IFCFG_RH_PLUGIN (self)); |
296 | ++ |
297 | ++#if NM_MORE_ASSERTS > 5 |
298 | ++ { |
299 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
300 | ++ NMSIfcfgRHStorage *storage; |
301 | ++ gsize n_uuid; |
302 | ++ gs_unref_hashtable GHashTable *h_unmanaged = NULL; |
303 | ++ gs_unref_hashtable GHashTable *h_unrecognized = NULL; |
304 | ++ |
305 | ++ nm_assert (g_hash_table_size (priv->storages.idx_by_filename) == c_list_length (&priv->storages._storage_lst_head)); |
306 | ++ |
307 | ++ h_unmanaged = g_hash_table_new (nm_str_hash, g_str_equal); |
308 | ++ h_unrecognized = g_hash_table_new (nm_str_hash, g_str_equal); |
309 | ++ |
310 | ++ n_uuid = 0; |
311 | ++ |
312 | ++ c_list_for_each_entry (storage, &priv->storages._storage_lst_head, parent._storage_lst) { |
313 | ++ const char *uuid; |
314 | ++ const char *filename; |
315 | ++ |
316 | ++ filename = nms_ifcfg_rh_storage_get_filename (storage); |
317 | ++ |
318 | ++ nm_assert (filename && NM_STR_HAS_PREFIX (filename, IFCFG_DIR"/")); |
319 | ++ |
320 | ++ uuid = nms_ifcfg_rh_storage_get_uuid_opt (storage); |
321 | ++ |
322 | ++ nm_assert ((!!uuid) + (!!storage->unmanaged_spec) + (!!storage->unrecognized_spec) == 1); |
323 | ++ |
324 | ++ nm_assert (storage == nm_sett_util_storages_lookup_by_filename (&priv->storages, filename)); |
325 | ++ |
326 | ++ if (uuid) { |
327 | ++ NMSettUtilStorageByUuidHead *sbuh; |
328 | ++ NMSettUtilStorageByUuidHead *sbuh2; |
329 | ++ |
330 | ++ if (storage->connection) |
331 | ++ nm_assert (nm_streq0 (nm_connection_get_uuid (storage->connection), uuid)); |
332 | ++ |
333 | ++ if (!g_hash_table_lookup_extended (priv->storages.idx_by_uuid, &uuid, (gpointer *) &sbuh, (gpointer *) &sbuh2)) |
334 | ++ nm_assert_not_reached (); |
335 | ++ |
336 | ++ nm_assert (sbuh); |
337 | ++ nm_assert (nm_streq (uuid, sbuh->uuid)); |
338 | ++ nm_assert (sbuh == sbuh2); |
339 | ++ nm_assert (c_list_contains (&sbuh->_storage_by_uuid_lst_head, &storage->parent._storage_by_uuid_lst)); |
340 | ++ |
341 | ++ if (c_list_first (&sbuh->_storage_by_uuid_lst_head) == &storage->parent._storage_by_uuid_lst) |
342 | ++ n_uuid++; |
343 | ++ } else if (storage->unmanaged_spec) { |
344 | ++ nm_assert (strlen (storage->unmanaged_spec) > 0); |
345 | ++ g_hash_table_add (h_unmanaged, storage->unmanaged_spec); |
346 | ++ } else if (storage->unrecognized_spec) { |
347 | ++ nm_assert (strlen (storage->unrecognized_spec) > 0); |
348 | ++ g_hash_table_add (h_unrecognized, storage->unrecognized_spec); |
349 | ++ } else |
350 | ++ nm_assert_not_reached (); |
351 | ++ |
352 | ++ nm_assert (!storage->connection); |
353 | ++ } |
354 | ++ |
355 | ++ nm_assert (g_hash_table_size (priv->storages.idx_by_uuid) == n_uuid); |
356 | ++ |
357 | ++ if (unhandled_specs_consistent) { |
358 | ++ nm_assert (nm_utils_hashtable_same_keys (h_unmanaged, priv->unmanaged_specs)); |
359 | ++ nm_assert (nm_utils_hashtable_same_keys (h_unrecognized, priv->unrecognized_specs)); |
360 | ++ } |
361 | ++ } |
362 | ++#endif |
363 | ++} |
364 | ++ |
365 | ++/*****************************************************************************/ |
366 | ++ |
367 | ++static NMSIfcfgRHStorage * |
368 | ++_load_file (NMSIfcfgRHPlugin *self, |
369 | ++ const char *filename, |
370 | ++ GError **error) |
371 | ++{ |
372 | ++ gs_unref_object NMConnection *connection = NULL; |
373 | ++ gs_free_error GError *load_error = NULL; |
374 | ++ gs_free char *unhandled_spec = NULL; |
375 | ++ gboolean load_error_ignore; |
376 | ++ struct stat st; |
377 | ++ |
378 | ++ if (stat (filename, &st) != 0) { |
379 | ++ int errsv = errno; |
380 | ++ |
381 | ++ if (error) { |
382 | ++ nm_utils_error_set_errno (error, errsv, |
383 | ++ "failure to stat file \%s\": %s", |
384 | ++ filename); |
385 | ++ } else |
386 | ++ _LOGT ("load[%s]: failure to stat file: %s", filename, nm_strerror_native (errsv)); |
387 | ++ return NULL; |
388 | ++ } |
389 | ++ |
390 | ++ connection = connection_from_file (filename, |
391 | ++ &unhandled_spec, |
392 | ++ &load_error, |
393 | ++ &load_error_ignore); |
394 | ++ if (load_error) { |
395 | ++ if (error) { |
396 | ++ nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, |
397 | ++ "failure to read file \"%s\": %s", |
398 | ++ filename, load_error->message); |
399 | ++ } else { |
400 | ++ _NMLOG (load_error_ignore ? LOGL_TRACE : LOGL_WARN, |
401 | ++ "load[%s]: failure to read file: %s", filename, load_error->message); |
402 | ++ } |
403 | ++ return NULL; |
404 | ++ } |
405 | ++ |
406 | ++ if (unhandled_spec) { |
407 | ++ const char *unmanaged_spec; |
408 | ++ const char *unrecognized_spec; |
409 | ++ |
410 | ++ if (!nms_ifcfg_rh_util_parse_unhandled_spec (unhandled_spec, |
411 | ++ &unmanaged_spec, |
412 | ++ &unrecognized_spec)) { |
413 | ++ nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, |
414 | ++ "invalid unhandled spec \"%s\"", |
415 | ++ unhandled_spec); |
416 | ++ nm_assert_not_reached (); |
417 | ++ return NULL; |
418 | ++ } |
419 | ++ return nms_ifcfg_rh_storage_new_unhandled (self, |
420 | ++ filename, |
421 | ++ unmanaged_spec, |
422 | ++ unrecognized_spec); |
423 | ++ } |
424 | ++ |
425 | ++ return nms_ifcfg_rh_storage_new_connection (self, |
426 | ++ filename, |
427 | ++ g_steal_pointer (&connection), |
428 | ++ &st.st_mtim); |
429 | ++} |
430 | ++ |
431 | ++static void |
432 | ++_load_dir (NMSIfcfgRHPlugin *self, |
433 | ++ NMSettUtilStorages *storages) |
434 | ++{ |
435 | ++ gs_unref_hashtable GHashTable *dupl_filenames = NULL; |
436 | ++ gs_free_error GError *local = NULL; |
437 | ++ const char *f_filename; |
438 | ++ GDir *dir; |
439 | ++ |
440 | ++ dir = g_dir_open (IFCFG_DIR, 0, &local); |
441 | ++ if (!dir) { |
442 | ++ _LOGT ("Could not read directory '%s': %s", IFCFG_DIR, local->message); |
443 | ++ return; |
444 | ++ } |
445 | ++ |
446 | ++ dupl_filenames = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_free); |
447 | ++ |
448 | ++ while ((f_filename = g_dir_read_name (dir))) { |
449 | ++ gs_free char *full_path = NULL; |
450 | ++ NMSIfcfgRHStorage *storage; |
451 | ++ char *full_filename; |
452 | ++ |
453 | ++ full_path = g_build_filename (IFCFG_DIR, f_filename, NULL); |
454 | ++ full_filename = utils_detect_ifcfg_path (full_path, TRUE); |
455 | ++ if (!full_filename) |
456 | ++ continue; |
457 | ++ |
458 | ++ if (!g_hash_table_add (dupl_filenames, full_filename)) |
459 | ++ continue; |
460 | ++ |
461 | ++ nm_assert (!nm_sett_util_storages_lookup_by_filename (storages, full_filename)); |
462 | ++ |
463 | ++ storage = _load_file (self, |
464 | ++ full_filename, |
465 | ++ NULL); |
466 | ++ if (storage) |
467 | ++ nm_sett_util_storages_add_take (storages, storage); |
468 | ++ } |
469 | ++ g_dir_close (dir); |
470 | ++} |
471 | ++ |
472 | ++static void |
473 | ++_storages_consolidate (NMSIfcfgRHPlugin *self, |
474 | ++ NMSettUtilStorages *storages_new, |
475 | ++ gboolean replace_all, |
476 | ++ GHashTable *storages_replaced, |
477 | ++ NMSettingsPluginConnectionLoadCallback callback, |
478 | ++ gpointer user_data) |
479 | ++{ |
480 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
481 | ++ CList lst_conn_info_deleted = C_LIST_INIT (lst_conn_info_deleted); |
482 | ++ gs_unref_ptrarray GPtrArray *storages_modified = NULL; |
483 | ++ CList storages_deleted; |
484 | ++ NMSIfcfgRHStorage *storage_safe; |
485 | ++ NMSIfcfgRHStorage *storage_new; |
486 | ++ NMSIfcfgRHStorage *storage_old; |
487 | ++ NMSIfcfgRHStorage *storage; |
488 | ++ guint i; |
489 | ++ |
490 | ++ /* when we reload all files, we must signal add/update/modify of profiles one-by-one. |
491 | ++ * NMSettings then goes ahead and emits further signals and a lot of things happen. |
492 | ++ * |
493 | ++ * So, first, emit an update of the unmanaged/unrecognized specs that contains *all* |
494 | ++ * the unmanaged/unrecognized devices from before and after. Since both unmanaged/unrecognized |
495 | ++ * specs have the meaning of "not doing something", it makes sense that we temporarily |
496 | ++ * disable that action for the sum of before and after. */ |
497 | ++ _unhandled_specs_merge_storages (self, storages_new); |
498 | ++ |
499 | ++ storages_modified = g_ptr_array_new_with_free_func (g_object_unref); |
500 | ++ c_list_init (&storages_deleted); |
501 | ++ |
502 | ++ c_list_for_each_entry (storage_old, &priv->storages._storage_lst_head, parent._storage_lst) |
503 | ++ storage_old->dirty = TRUE; |
504 | ++ |
505 | ++ c_list_for_each_entry_safe (storage_new, storage_safe, &storages_new->_storage_lst_head, parent._storage_lst) { |
506 | ++ storage_old = nm_sett_util_storages_lookup_by_filename (&priv->storages, nms_ifcfg_rh_storage_get_filename (storage_new)); |
507 | ++ |
508 | ++ nm_sett_util_storages_steal (storages_new, storage_new); |
509 | ++ |
510 | ++ if ( !storage_old |
511 | ++ || !nms_ifcfg_rh_storage_equal_type (storage_new, storage_old)) { |
512 | ++ if (storage_old) { |
513 | ++ nm_sett_util_storages_steal (&priv->storages, storage_old); |
514 | ++ if (nms_ifcfg_rh_storage_get_uuid_opt (storage_old)) |
515 | ++ c_list_link_tail (&storages_deleted, &storage_old->parent._storage_lst); |
516 | ++ else |
517 | ++ nms_ifcfg_rh_storage_destroy (storage_old); |
518 | ++ } |
519 | ++ storage_new->dirty = FALSE; |
520 | ++ nm_sett_util_storages_add_take (&priv->storages, storage_new); |
521 | ++ g_ptr_array_add (storages_modified, g_object_ref (storage_new)); |
522 | ++ continue; |
523 | ++ } |
524 | ++ |
525 | ++ storage_old->dirty = FALSE; |
526 | ++ nms_ifcfg_rh_storage_copy_content (storage_old, storage_new); |
527 | ++ nms_ifcfg_rh_storage_destroy (storage_new); |
528 | ++ g_ptr_array_add (storages_modified, g_object_ref (storage_old)); |
529 | ++ } |
530 | ++ |
531 | ++ c_list_for_each_entry_safe (storage_old, storage_safe, &priv->storages._storage_lst_head, parent._storage_lst) { |
532 | ++ if (!storage_old->dirty) |
533 | ++ continue; |
534 | ++ if ( replace_all |
535 | ++ || ( storages_replaced |
536 | ++ && g_hash_table_contains (storages_replaced, storage_old))) { |
537 | ++ nm_sett_util_storages_steal (&priv->storages, storage_old); |
538 | ++ if (nms_ifcfg_rh_storage_get_uuid_opt (storage_old)) |
539 | ++ c_list_link_tail (&storages_deleted, &storage_old->parent._storage_lst); |
540 | ++ else |
541 | ++ nms_ifcfg_rh_storage_destroy (storage_old); |
542 | ++ } |
543 | ++ } |
544 | ++ |
545 | ++ /* raise events. */ |
546 | ++ |
547 | ++ for (i = 0; i < storages_modified->len; i++) { |
548 | ++ storage = storages_modified->pdata[i]; |
549 | ++ storage->dirty = TRUE; |
550 | ++ } |
551 | ++ |
552 | ++ for (i = 0; i < storages_modified->len; i++) { |
553 | ++ gs_unref_object NMConnection *connection = NULL; |
554 | ++ storage = storages_modified->pdata[i]; |
555 | ++ |
556 | ++ if (!storage->dirty) { |
557 | ++ /* the entry is no longer dirty. In the meantime we already emited |
558 | ++ * another signal for it. */ |
559 | ++ continue; |
560 | ++ } |
561 | ++ storage->dirty = FALSE; |
562 | ++ if (storage != nm_sett_util_storages_lookup_by_filename (&priv->storages, nms_ifcfg_rh_storage_get_filename (storage))) { |
563 | ++ /* hm? The profile was deleted in the meantime? That is only possible |
564 | ++ * if the signal handler called again into the plugin. In any case, the event |
565 | ++ * was already emitted. Skip. */ |
566 | ++ continue; |
567 | ++ } |
568 | ++ |
569 | ++ connection = nms_ifcfg_rh_storage_steal_connection (storage); |
570 | ++ if (!connection) { |
571 | ++ nm_assert (!nms_ifcfg_rh_storage_get_uuid_opt (storage)); |
572 | ++ continue; |
573 | ++ } |
574 | ++ |
575 | ++ nm_assert (NM_IS_CONNECTION (connection)); |
576 | ++ nm_assert (nms_ifcfg_rh_storage_get_uuid_opt (storage)); |
577 | ++ callback (NM_SETTINGS_PLUGIN (self), |
578 | ++ NM_SETTINGS_STORAGE (storage), |
579 | ++ connection, |
580 | ++ user_data); |
581 | ++ } |
582 | ++ |
583 | ++ while ((storage = c_list_first_entry (&storages_deleted, NMSIfcfgRHStorage, parent._storage_lst))) { |
584 | ++ c_list_unlink (&storage->parent._storage_lst); |
585 | ++ callback (NM_SETTINGS_PLUGIN (self), |
586 | ++ NM_SETTINGS_STORAGE (storage), |
587 | ++ NULL, |
588 | ++ user_data); |
589 | ++ nms_ifcfg_rh_storage_destroy (storage); |
590 | ++ } |
591 | ++} |
592 | ++ |
593 | ++/*****************************************************************************/ |
594 | ++ |
595 | ++static void |
596 | ++load_connections (NMSettingsPlugin *plugin, |
597 | ++ NMSettingsPluginConnectionLoadEntry *entries, |
598 | ++ gsize n_entries, |
599 | ++ NMSettingsPluginConnectionLoadCallback callback, |
600 | ++ gpointer user_data) |
601 | ++{ |
602 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (plugin); |
603 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
604 | ++ nm_auto_clear_sett_util_storages NMSettUtilStorages storages_new = NM_SETT_UTIL_STORAGES_INIT (storages_new, nms_ifcfg_rh_storage_destroy); |
605 | ++ gs_unref_hashtable GHashTable *dupl_filenames = NULL; |
606 | ++ gs_unref_hashtable GHashTable *storages_replaced = NULL; |
607 | ++ gs_unref_hashtable GHashTable *loaded_uuids = NULL; |
608 | ++ const char *loaded_uuid; |
609 | ++ GHashTableIter h_iter; |
610 | ++ gsize i; |
611 | ++ |
612 | ++ if (n_entries == 0) |
613 | ++ return; |
614 | ++ |
615 | ++ dupl_filenames = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); |
616 | ++ |
617 | ++ loaded_uuids = g_hash_table_new (nm_str_hash, g_str_equal); |
618 | ++ |
619 | ++ storages_replaced = g_hash_table_new_full (nm_direct_hash, NULL, g_object_unref, NULL); |
620 | ++ |
621 | ++ for (i = 0; i < n_entries; i++) { |
622 | ++ NMSettingsPluginConnectionLoadEntry *const entry = &entries[i]; |
623 | ++ gs_free_error GError *local = NULL; |
624 | ++ const char *full_filename; |
625 | ++ const char *uuid; |
626 | ++ gs_free char *full_filename_keep = NULL; |
627 | ++ NMSettingsPluginConnectionLoadEntry *dupl_content_entry; |
628 | ++ gs_unref_object NMSIfcfgRHStorage *storage = NULL; |
629 | ++ |
630 | ++ if (entry->handled) |
631 | ++ continue; |
632 | ++ |
633 | ++ if (entry->filename[0] != '/') |
634 | ++ continue; |
635 | ++ |
636 | ++ full_filename_keep = utils_detect_ifcfg_path (entry->filename, FALSE); |
637 | ++ |
638 | ++ if (!full_filename_keep) { |
639 | ++ if (nm_utils_file_is_in_path (entry->filename, IFCFG_DIR)) { |
640 | ++ nm_utils_error_set (&entry->error, |
641 | ++ NM_UTILS_ERROR_UNKNOWN, |
642 | ++ ("path is not a valid name for an ifcfg-rh file")); |
643 | ++ entry->handled = TRUE; |
644 | ++ } |
645 | ++ continue; |
646 | ++ } |
647 | ++ |
648 | ++ if ((dupl_content_entry = g_hash_table_lookup (dupl_filenames, full_filename_keep))) { |
649 | ++ /* we already visited this file. */ |
650 | ++ entry->handled = dupl_content_entry->handled; |
651 | ++ if (dupl_content_entry->error) { |
652 | ++ g_set_error_literal (&entry->error, |
653 | ++ dupl_content_entry->error->domain, |
654 | ++ dupl_content_entry->error->code, |
655 | ++ dupl_content_entry->error->message); |
656 | ++ } |
657 | ++ continue; |
658 | ++ } |
659 | ++ |
660 | ++ entry->handled = TRUE; |
661 | ++ |
662 | ++ full_filename = full_filename_keep; |
663 | ++ if (!g_hash_table_insert (dupl_filenames, g_steal_pointer (&full_filename_keep), entry)) |
664 | ++ nm_assert_not_reached (); |
665 | ++ |
666 | ++ storage = _load_file (self, |
667 | ++ full_filename, |
668 | ++ &local); |
669 | ++ if (!storage) { |
670 | ++ if (nm_utils_file_stat (full_filename, NULL) == -ENOENT) { |
671 | ++ NMSIfcfgRHStorage *storage2; |
672 | ++ |
673 | ++ /* the file does not exist. We take that as indication to unload the file |
674 | ++ * that was previously loaded... */ |
675 | ++ storage2 = nm_sett_util_storages_lookup_by_filename (&priv->storages, full_filename); |
676 | ++ if (storage2) |
677 | ++ g_hash_table_add (storages_replaced, g_object_ref (storage2)); |
678 | ++ continue; |
679 | ++ } |
680 | ++ g_propagate_error (&entry->error, g_steal_pointer (&local)); |
681 | ++ continue; |
682 | ++ } |
683 | ++ |
684 | ++ uuid = nms_ifcfg_rh_storage_get_uuid_opt (storage); |
685 | ++ if (uuid) |
686 | ++ g_hash_table_add (loaded_uuids, (char *) uuid); |
687 | ++ |
688 | ++ nm_sett_util_storages_add_take (&storages_new, g_steal_pointer (&storage)); |
689 | ++ } |
690 | ++ |
691 | ++ /* now we visit all UUIDs that are about to change... */ |
692 | ++ g_hash_table_iter_init (&h_iter, loaded_uuids); |
693 | ++ while (g_hash_table_iter_next (&h_iter, (gpointer *) &loaded_uuid, NULL)) { |
694 | ++ NMSIfcfgRHStorage *storage; |
695 | ++ NMSettUtilStorageByUuidHead *sbuh; |
696 | ++ |
697 | ++ sbuh = nm_sett_util_storages_lookup_by_uuid (&priv->storages, loaded_uuid); |
698 | ++ if (!sbuh) |
699 | ++ continue; |
700 | ++ |
701 | ++ c_list_for_each_entry (storage, &sbuh->_storage_by_uuid_lst_head, parent._storage_by_uuid_lst) { |
702 | ++ const char *full_filename = nms_ifcfg_rh_storage_get_filename (storage); |
703 | ++ gs_unref_object NMSIfcfgRHStorage *storage_new = NULL; |
704 | ++ gs_free_error GError *local = NULL; |
705 | ++ |
706 | ++ if (g_hash_table_contains (dupl_filenames, full_filename)) { |
707 | ++ /* already re-loaded. */ |
708 | ++ continue; |
709 | ++ } |
710 | ++ |
711 | ++ /* @storage has a UUID that was just loaded from disk, but we have an entry in cache. |
712 | ++ * Reload that file too despite not being told to do so. The reason is to get |
713 | ++ * the latest file timestamp so that we get the priorities right. */ |
714 | ++ |
715 | ++ storage_new = _load_file (self, |
716 | ++ full_filename, |
717 | ++ &local); |
718 | ++ if ( storage_new |
719 | ++ && !nm_streq0 (loaded_uuid, nms_ifcfg_rh_storage_get_uuid_opt (storage_new))) { |
720 | ++ /* the file now references a different UUID. We are not told to reload |
721 | ++ * that file, so this means the existing storage (with the previous |
722 | ++ * filename and UUID tuple) is no longer valid. */ |
723 | ++ g_clear_object (&storage_new); |
724 | ++ } |
725 | ++ |
726 | ++ g_hash_table_add (storages_replaced, g_object_ref (storage)); |
727 | ++ if (storage_new) |
728 | ++ nm_sett_util_storages_add_take (&storages_new, g_steal_pointer (&storage_new)); |
729 | ++ } |
730 | ++ } |
731 | ++ |
732 | ++ nm_clear_pointer (&loaded_uuids, g_hash_table_destroy); |
733 | ++ nm_clear_pointer (&dupl_filenames, g_hash_table_destroy); |
734 | ++ |
735 | ++ _storages_consolidate (self, |
736 | ++ &storages_new, |
737 | ++ FALSE, |
738 | ++ storages_replaced, |
739 | ++ callback, |
740 | ++ user_data); |
741 | ++} |
742 | ++ |
743 | ++static void |
744 | ++reload_connections (NMSettingsPlugin *plugin, |
745 | ++ NMSettingsPluginConnectionLoadCallback callback, |
746 | ++ gpointer user_data) |
747 | ++{ |
748 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (plugin); |
749 | ++ nm_auto_clear_sett_util_storages NMSettUtilStorages storages_new = NM_SETT_UTIL_STORAGES_INIT (storages_new, nms_ifcfg_rh_storage_destroy); |
750 | ++ |
751 | ++ nm_assert_self (self, TRUE); |
752 | ++ |
753 | ++ _load_dir (self, &storages_new); |
754 | ++ |
755 | ++ _storages_consolidate (self, |
756 | ++ &storages_new, |
757 | ++ TRUE, |
758 | ++ NULL, |
759 | ++ callback, |
760 | ++ user_data); |
761 | ++ |
762 | ++ nm_assert_self (self, FALSE); |
763 | ++} |
764 | ++ |
765 | ++static void |
766 | ++load_connections_done (NMSettingsPlugin *plugin) |
767 | ++{ |
768 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (plugin); |
769 | ++ |
770 | ++ /* at the beginning of a load, we emit a change signal for unmanaged/unrecognized |
771 | ++ * specs that contain the sum of before and after (_unhandled_specs_merge_storages()). |
772 | ++ * |
773 | ++ * The idea is that while we emit signals about changes to connection, we have |
774 | ++ * the sum of all unmanaged/unrecognized devices from before and after. |
775 | ++ * |
776 | ++ * This if triggered at the end, to reset the specs. */ |
777 | ++ _unhandled_specs_reset (self); |
778 | ++ |
779 | ++ nm_assert_self (self, TRUE); |
780 | ++} |
781 | ++ |
782 | ++/*****************************************************************************/ |
783 | ++ |
784 | ++static gboolean |
785 | ++add_connection (NMSettingsPlugin *plugin, |
786 | ++ NMConnection *connection, |
787 | ++ NMSettingsStorage **out_storage, |
788 | ++ NMConnection **out_connection, |
789 | ++ GError **error) |
790 | ++{ |
791 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (plugin); |
792 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
793 | ++ gs_unref_object NMSIfcfgRHStorage *storage = NULL; |
794 | ++ gs_unref_object NMConnection *reread = NULL; |
795 | ++ gs_free char *full_filename = NULL; |
796 | ++ GError *local = NULL; |
797 | ++ gboolean reread_same; |
798 | ++ struct timespec mtime; |
799 | ++ |
800 | ++ nm_assert_self (self, TRUE); |
801 | ++ nm_assert (NM_IS_CONNECTION (connection)); |
802 | ++ nm_assert (out_storage && !*out_storage); |
803 | ++ nm_assert (out_connection && !*out_connection); |
804 | ++ |
805 | ++ if (!nms_ifcfg_rh_writer_write_connection (connection, |
806 | ++ IFCFG_DIR, |
807 | ++ NULL, |
808 | ++ nm_sett_util_allow_filename_cb, |
809 | ++ NM_SETT_UTIL_ALLOW_FILENAME_DATA (&priv->storages, NULL), |
810 | ++ &full_filename, |
811 | ++ &reread, |
812 | ++ &reread_same, |
813 | ++ &local)) { |
814 | ++ _LOGT ("commit: %s (%s): failed to add: %s", |
815 | ++ nm_connection_get_uuid (connection), |
816 | ++ nm_connection_get_id (connection), |
817 | ++ local->message); |
818 | ++ g_propagate_error (error, local); |
819 | ++ return FALSE; |
820 | ++ } |
821 | ++ |
822 | ++ if ( !reread |
823 | ++ || reread_same) |
824 | ++ nm_g_object_ref_set (&reread, connection); |
825 | ++ |
826 | ++ nm_assert (full_filename && full_filename[0] == '/'); |
827 | ++ |
828 | ++ _LOGT ("commit: %s (%s) added as \"%s\"", |
829 | ++ nm_connection_get_uuid (reread), |
830 | ++ nm_connection_get_id (reread), |
831 | ++ full_filename); |
832 | ++ |
833 | ++ storage = nms_ifcfg_rh_storage_new_connection (self, |
834 | ++ full_filename, |
835 | ++ g_steal_pointer (&reread), |
836 | ++ nm_sett_util_stat_mtime (full_filename, FALSE, &mtime)); |
837 | ++ |
838 | ++ nm_sett_util_storages_add_take (&priv->storages, g_object_ref (storage)); |
839 | ++ |
840 | ++ *out_connection = nms_ifcfg_rh_storage_steal_connection (storage); |
841 | ++ *out_storage = NM_SETTINGS_STORAGE (g_steal_pointer (&storage)); |
842 | ++ |
843 | ++ nm_assert_self (self, TRUE); |
844 | ++ |
845 | ++ return TRUE; |
846 | ++} |
847 | ++ |
848 | ++static gboolean |
849 | ++update_connection (NMSettingsPlugin *plugin, |
850 | ++ NMSettingsStorage *storage_x, |
851 | ++ NMConnection *connection, |
852 | ++ NMSettingsStorage **out_storage, |
853 | ++ NMConnection **out_connection, |
854 | ++ GError **error) |
855 | ++{ |
856 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (plugin); |
857 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
858 | ++ NMSIfcfgRHStorage *storage = NMS_IFCFG_RH_STORAGE (storage_x); |
859 | ++ const char *full_filename; |
860 | ++ const char *uuid; |
861 | ++ GError *local = NULL; |
862 | ++ gs_unref_object NMConnection *reread = NULL; |
863 | ++ gboolean reread_same; |
864 | ++ struct timespec mtime; |
865 | ++ |
866 | ++ nm_assert_self (self, TRUE); |
867 | ++ nm_assert (NM_IS_CONNECTION (connection)); |
868 | ++ nm_assert (NMS_IS_IFCFG_RH_STORAGE (storage)); |
869 | ++ nm_assert (_nm_connection_verify (connection, NULL) == NM_SETTING_VERIFY_SUCCESS); |
870 | ++ nm_assert (!error || !*error); |
871 | ++ |
872 | ++ uuid = nms_ifcfg_rh_storage_get_uuid_opt (storage); |
873 | ++ |
874 | ++ nm_assert (uuid && nm_streq0 (uuid, nm_connection_get_uuid (connection))); |
875 | ++ |
876 | ++ full_filename = nms_ifcfg_rh_storage_get_filename (storage); |
877 | ++ |
878 | ++ nm_assert (full_filename); |
879 | ++ nm_assert (storage == nm_sett_util_storages_lookup_by_filename (&priv->storages, full_filename)); |
880 | ++ |
881 | ++ if (!nms_ifcfg_rh_writer_write_connection (connection, |
882 | ++ IFCFG_DIR, |
883 | ++ full_filename, |
884 | ++ nm_sett_util_allow_filename_cb, |
885 | ++ NM_SETT_UTIL_ALLOW_FILENAME_DATA (&priv->storages, full_filename), |
886 | ++ NULL, |
887 | ++ &reread, |
888 | ++ &reread_same, |
889 | ++ &local)) { |
890 | ++ _LOGT ("commit: failure to write %s (%s) to \"%s\": %s", |
891 | ++ nm_connection_get_uuid (connection), |
892 | ++ nm_connection_get_id (connection), |
893 | ++ full_filename, |
894 | ++ local->message); |
895 | ++ g_propagate_error (error, local); |
896 | ++ return FALSE; |
897 | ++ } |
898 | ++ |
899 | ++ if ( !reread |
900 | ++ || reread_same) |
901 | ++ nm_g_object_ref_set (&reread, connection); |
902 | ++ |
903 | ++ _LOGT ("commit: \"%s\": profile %s (%s) written", |
904 | ++ full_filename, |
905 | ++ uuid, |
906 | ++ nm_connection_get_id (connection)); |
907 | ++ |
908 | ++ storage->stat_mtime = *nm_sett_util_stat_mtime (full_filename, FALSE, &mtime); |
909 | ++ |
910 | ++ *out_storage = NM_SETTINGS_STORAGE (g_object_ref (storage)); |
911 | ++ *out_connection = g_steal_pointer (&reread); |
912 | ++ |
913 | ++ nm_assert_self (self, TRUE); |
914 | ++ |
915 | ++ return TRUE; |
916 | ++} |
917 | ++ |
918 | ++static gboolean |
919 | ++delete_connection (NMSettingsPlugin *plugin, |
920 | ++ NMSettingsStorage *storage_x, |
921 | ++ GError **error) |
922 | ++{ |
923 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (plugin); |
924 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
925 | ++ NMSIfcfgRHStorage *storage = NMS_IFCFG_RH_STORAGE (storage_x); |
926 | ++ const char *operation_message; |
927 | ++ const char *full_filename; |
928 | ++ |
929 | ++ nm_assert_self (self, TRUE); |
930 | ++ nm_assert (!error || !*error); |
931 | ++ nm_assert (NMS_IS_IFCFG_RH_STORAGE (storage)); |
932 | ++ |
933 | ++ full_filename = nms_ifcfg_rh_storage_get_filename (storage); |
934 | ++ nm_assert (full_filename); |
935 | ++ |
936 | ++ nm_assert (nms_ifcfg_rh_storage_get_uuid_opt (storage)); |
937 | ++ |
938 | ++ nm_assert (storage == nm_sett_util_storages_lookup_by_filename (&priv->storages, full_filename)); |
939 | ++ |
940 | ++ { |
941 | ++ gs_free char *keyfile = utils_get_keys_path (full_filename); |
942 | ++ gs_free char *routefile = utils_get_route_path (full_filename); |
943 | ++ gs_free char *route6file = utils_get_route6_path (full_filename); |
944 | ++ const char *const files[] = { full_filename, keyfile, routefile, route6file }; |
945 | ++ gboolean any_deleted = FALSE; |
946 | ++ gboolean any_failure = FALSE; |
947 | ++ int i; |
948 | ++ |
949 | ++ for (i = 0; i < G_N_ELEMENTS (files); i++) { |
950 | ++ int errsv; |
951 | ++ |
952 | ++ if (unlink (files[i]) == 0) { |
953 | ++ any_deleted = TRUE; |
954 | ++ continue; |
955 | ++ } |
956 | ++ errsv = errno; |
957 | ++ if (errsv == ENOENT) |
958 | ++ continue; |
959 | ++ |
960 | ++ _LOGW ("commit: failure to delete file \"%s\": %s", |
961 | ++ files[i], |
962 | ++ nm_strerror_native (errsv)); |
963 | ++ any_failure = TRUE; |
964 | ++ } |
965 | ++ if (any_failure) |
966 | ++ operation_message = "failed to delete files from disk"; |
967 | ++ else if (any_deleted) |
968 | ++ operation_message = "deleted from disk"; |
969 | ++ else |
970 | ++ operation_message = "does not exist on disk"; |
971 | ++ } |
972 | ++ |
973 | ++ _LOGT ("commit: deleted \"%s\", profile %s (%s)", |
974 | ++ full_filename, |
975 | ++ nms_ifcfg_rh_storage_get_uuid_opt (storage), |
976 | ++ operation_message); |
977 | ++ |
978 | ++ nm_sett_util_storages_steal (&priv->storages, storage); |
979 | ++ nms_ifcfg_rh_storage_destroy (storage); |
980 | ++ |
981 | ++ nm_assert_self (self, TRUE); |
982 | ++ |
983 | ++ return TRUE; |
984 | ++} |
985 | ++ |
986 | ++/*****************************************************************************/ |
987 | ++ |
988 | ++static void |
989 | ++_unhandled_specs_reset (NMSIfcfgRHPlugin *self) |
990 | ++{ |
991 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
992 | ++ gs_unref_hashtable GHashTable *unmanaged_specs = NULL; |
993 | ++ gs_unref_hashtable GHashTable *unrecognized_specs = NULL; |
994 | ++ NMSIfcfgRHStorage *storage; |
995 | ++ |
996 | ++ unmanaged_specs = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); |
997 | ++ unrecognized_specs = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); |
998 | ++ |
999 | ++ c_list_for_each_entry (storage, &priv->storages._storage_lst_head, parent._storage_lst) { |
1000 | ++ if (storage->unmanaged_spec) |
1001 | ++ g_hash_table_add (unmanaged_specs, g_strdup (storage->unmanaged_spec)); |
1002 | ++ if (storage->unrecognized_spec) |
1003 | ++ g_hash_table_add (unrecognized_specs, g_strdup (storage->unrecognized_spec)); |
1004 | ++ } |
1005 | ++ |
1006 | ++ if (!nm_utils_hashtable_same_keys (unmanaged_specs, priv->unmanaged_specs)) { |
1007 | ++ g_hash_table_unref (priv->unmanaged_specs); |
1008 | ++ priv->unmanaged_specs = g_steal_pointer (&unmanaged_specs); |
1009 | ++ } |
1010 | ++ if (!nm_utils_hashtable_same_keys (unrecognized_specs, priv->unrecognized_specs)) { |
1011 | ++ g_hash_table_unref (priv->unrecognized_specs); |
1012 | ++ priv->unrecognized_specs = g_steal_pointer (&unrecognized_specs); |
1013 | ++ } |
1014 | ++ |
1015 | ++ if (!unmanaged_specs) |
1016 | ++ _nm_settings_plugin_emit_signal_unmanaged_specs_changed (NM_SETTINGS_PLUGIN (self)); |
1017 | ++ if (!unrecognized_specs) |
1018 | ++ _nm_settings_plugin_emit_signal_unrecognized_specs_changed (NM_SETTINGS_PLUGIN (self)); |
1019 | ++} |
1020 | ++ |
1021 | ++static void |
1022 | ++_unhandled_specs_merge_storages (NMSIfcfgRHPlugin *self, |
1023 | ++ NMSettUtilStorages *storages) |
1024 | ++{ |
1025 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1026 | ++ gboolean unmanaged_changed = FALSE; |
1027 | ++ gboolean unrecognized_changed = FALSE; |
1028 | ++ NMSIfcfgRHStorage *storage; |
1029 | ++ |
1030 | ++ c_list_for_each_entry (storage, &storages->_storage_lst_head, parent._storage_lst) { |
1031 | ++ if ( storage->unmanaged_spec |
1032 | ++ && !g_hash_table_contains (priv->unmanaged_specs, storage->unmanaged_spec)) { |
1033 | ++ unmanaged_changed = TRUE; |
1034 | ++ g_hash_table_add (priv->unmanaged_specs, g_strdup (storage->unmanaged_spec)); |
1035 | ++ } |
1036 | ++ if ( storage->unrecognized_spec |
1037 | ++ && !g_hash_table_contains (priv->unrecognized_specs, storage->unrecognized_spec)) { |
1038 | ++ unrecognized_changed = TRUE; |
1039 | ++ g_hash_table_add (priv->unrecognized_specs, g_strdup (storage->unrecognized_spec)); |
1040 | ++ } |
1041 | ++ } |
1042 | ++ |
1043 | ++ if (unmanaged_changed) |
1044 | ++ _nm_settings_plugin_emit_signal_unmanaged_specs_changed (NM_SETTINGS_PLUGIN (self)); |
1045 | ++ if (unrecognized_changed) |
1046 | ++ _nm_settings_plugin_emit_signal_unrecognized_specs_changed (NM_SETTINGS_PLUGIN (self)); |
1047 | ++} |
1048 | ++ |
1049 | ++static GSList * |
1050 | ++_unhandled_specs_from_hashtable (GHashTable *hash) |
1051 | ++{ |
1052 | ++ gs_free const char **keys = NULL; |
1053 | ++ GSList *list = NULL; |
1054 | ++ guint i, l; |
1055 | ++ |
1056 | ++ keys = nm_utils_strdict_get_keys (hash, TRUE, &l); |
1057 | ++ for (i = l; i > 0; ) { |
1058 | ++ i--; |
1059 | ++ list = g_slist_prepend (list, g_strdup (keys[i])); |
1060 | ++ } |
1061 | ++ return list; |
1062 | ++} |
1063 | ++ |
1064 | ++static GSList * |
1065 | ++get_unmanaged_specs (NMSettingsPlugin *plugin) |
1066 | ++{ |
1067 | ++ return _unhandled_specs_from_hashtable (NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (plugin)->unmanaged_specs); |
1068 | ++} |
1069 | ++ |
1070 | ++static GSList * |
1071 | ++get_unrecognized_specs (NMSettingsPlugin *plugin) |
1072 | ++{ |
1073 | ++ return _unhandled_specs_from_hashtable (NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (plugin)->unrecognized_specs); |
1074 | ++} |
1075 | ++ |
1076 | ++/*****************************************************************************/ |
1077 | ++ |
1078 | ++static void |
1079 | ++impl_ifcfgrh_get_ifcfg_details (NMSIfcfgRHPlugin *self, |
1080 | ++ GDBusMethodInvocation *context, |
1081 | ++ const char *in_ifcfg) |
1082 | ++{ |
1083 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1084 | ++ gs_free char *ifcfg_path = NULL; |
1085 | ++ NMSIfcfgRHStorage *storage; |
1086 | ++ const char *uuid; |
1087 | ++ const char *path; |
1088 | ++ |
1089 | ++ if (in_ifcfg[0] != '/') { |
1090 | ++ g_dbus_method_invocation_return_error (context, |
1091 | ++ NM_SETTINGS_ERROR, |
1092 | ++ NM_SETTINGS_ERROR_INVALID_CONNECTION, |
1093 | ++ "ifcfg path '%s' is not absolute", in_ifcfg); |
1094 | ++ return; |
1095 | ++ } |
1096 | ++ |
1097 | ++ ifcfg_path = utils_detect_ifcfg_path (in_ifcfg, TRUE); |
1098 | ++ if (!ifcfg_path) { |
1099 | ++ g_dbus_method_invocation_return_error (context, |
1100 | ++ NM_SETTINGS_ERROR, |
1101 | ++ NM_SETTINGS_ERROR_INVALID_CONNECTION, |
1102 | ++ "ifcfg path '%s' is not an ifcfg base file", in_ifcfg); |
1103 | ++ return; |
1104 | ++ } |
1105 | ++ |
1106 | ++ storage = nm_sett_util_storages_lookup_by_filename (&priv->storages, ifcfg_path); |
1107 | ++ if (!storage) { |
1108 | ++ g_dbus_method_invocation_return_error (context, |
1109 | ++ NM_SETTINGS_ERROR, |
1110 | ++ NM_SETTINGS_ERROR_INVALID_CONNECTION, |
1111 | ++ "ifcfg file '%s' unknown", in_ifcfg); |
1112 | ++ return; |
1113 | ++ } |
1114 | ++ |
1115 | ++ uuid = nms_ifcfg_rh_storage_get_uuid_opt (storage); |
1116 | ++ if (!uuid) { |
1117 | ++ g_dbus_method_invocation_return_error (context, |
1118 | ++ NM_SETTINGS_ERROR, |
1119 | ++ NM_SETTINGS_ERROR_INVALID_CONNECTION, |
1120 | ++ "ifcfg file '%s' not managed by NetworkManager", in_ifcfg); |
1121 | ++ return; |
1122 | ++ } |
1123 | ++ |
1124 | ++ /* It is ugly that the ifcfg-rh plugin needs to call back into NMSettings this |
1125 | ++ * way. |
1126 | ++ * There are alternatives (like invoking a signal), but they are all significant |
1127 | ++ * extra code (and performance overhead). So the quick and dirty solution here |
1128 | ++ * is likely to be simpler than getting this right (also from point of readability!). |
1129 | ++ */ |
1130 | ++ path = nm_settings_get_dbus_path_for_uuid (nm_settings_get (), uuid); |
1131 | ++ |
1132 | ++ if (!path) { |
1133 | ++ g_dbus_method_invocation_return_error (context, |
1134 | ++ NM_SETTINGS_ERROR, |
1135 | ++ NM_SETTINGS_ERROR_FAILED, |
1136 | ++ "unable to get the connection D-Bus path"); |
1137 | ++ return; |
1138 | ++ } |
1139 | ++ |
1140 | ++ g_dbus_method_invocation_return_value (context, |
1141 | ++ g_variant_new ("(so)", uuid, path)); |
1142 | ++} |
1143 | ++ |
1144 | ++/*****************************************************************************/ |
1145 | ++ |
1146 | ++static void |
1147 | ++_dbus_clear (NMSIfcfgRHPlugin *self) |
1148 | ++{ |
1149 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1150 | ++ guint id; |
1151 | ++ |
1152 | ++ nm_clear_g_signal_handler (priv->dbus.connection, &priv->dbus.signal_id); |
1153 | ++ |
1154 | ++ nm_clear_g_cancellable (&priv->dbus.cancellable); |
1155 | ++ |
1156 | ++ if ((id = nm_steal_int (&priv->dbus.regist_id))) { |
1157 | ++ if (!g_dbus_connection_unregister_object (priv->dbus.connection, id)) |
1158 | ++ _LOGW ("dbus: unexpected failure to unregister object"); |
1159 | ++ } |
1160 | ++ |
1161 | ++ g_clear_object (&priv->dbus.connection); |
1162 | ++} |
1163 | ++ |
1164 | ++static void |
1165 | ++_dbus_connection_closed (GDBusConnection *connection, |
1166 | ++ gboolean remote_peer_vanished, |
1167 | ++ GError *error, |
1168 | ++ gpointer user_data) |
1169 | ++{ |
1170 | ++ _LOGW ("dbus: %s bus closed", IFCFGRH1_BUS_NAME); |
1171 | ++ _dbus_clear (NMS_IFCFG_RH_PLUGIN (user_data)); |
1172 | ++ |
1173 | ++ /* Retry or recover? */ |
1174 | ++} |
1175 | ++ |
1176 | ++static void |
1177 | ++_method_call (GDBusConnection *connection, |
1178 | ++ const char *sender, |
1179 | ++ const char *object_path, |
1180 | ++ const char *interface_name, |
1181 | ++ const char *method_name, |
1182 | ++ GVariant *parameters, |
1183 | ++ GDBusMethodInvocation *invocation, |
1184 | ++ gpointer user_data) |
1185 | ++{ |
1186 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (user_data); |
1187 | ++ |
1188 | ++ if (nm_streq (interface_name, IFCFGRH1_IFACE1_NAME)) { |
1189 | ++ if (nm_streq (method_name, IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS)) { |
1190 | ++ const char *ifcfg; |
1191 | ++ |
1192 | ++ g_variant_get (parameters, "(&s)", &ifcfg); |
1193 | ++ impl_ifcfgrh_get_ifcfg_details (self, invocation, ifcfg); |
1194 | ++ return; |
1195 | ++ } |
1196 | ++ } |
1197 | ++ |
1198 | ++ g_dbus_method_invocation_return_error (invocation, |
1199 | ++ G_DBUS_ERROR, |
1200 | ++ G_DBUS_ERROR_UNKNOWN_METHOD, |
1201 | ++ "Unknown method %s", |
1202 | ++ method_name); |
1203 | ++} |
1204 | ++ |
1205 | ++static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO ( |
1206 | ++ IFCFGRH1_IFACE1_NAME, |
1207 | ++ .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( |
1208 | ++ NM_DEFINE_GDBUS_METHOD_INFO ( |
1209 | ++ IFCFGRH1_IFACE1_METHOD_GET_IFCFG_DETAILS, |
1210 | ++ .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( |
1211 | ++ NM_DEFINE_GDBUS_ARG_INFO ("ifcfg", "s"), |
1212 | ++ ), |
1213 | ++ .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( |
1214 | ++ NM_DEFINE_GDBUS_ARG_INFO ("uuid", "s"), |
1215 | ++ NM_DEFINE_GDBUS_ARG_INFO ("path", "o"), |
1216 | ++ ), |
1217 | ++ ), |
1218 | ++ ), |
1219 | ++); |
1220 | ++ |
1221 | ++static void |
1222 | ++_dbus_request_name_done (GObject *source_object, |
1223 | ++ GAsyncResult *res, |
1224 | ++ gpointer user_data) |
1225 | ++{ |
1226 | ++ GDBusConnection *connection = G_DBUS_CONNECTION (source_object); |
1227 | ++ NMSIfcfgRHPlugin *self; |
1228 | ++ NMSIfcfgRHPluginPrivate *priv; |
1229 | ++ gs_free_error GError *error = NULL; |
1230 | ++ gs_unref_variant GVariant *ret = NULL; |
1231 | ++ guint32 result; |
1232 | ++ |
1233 | ++ ret = g_dbus_connection_call_finish (connection, res, &error); |
1234 | ++ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
1235 | ++ return; |
1236 | ++ |
1237 | ++ self = NMS_IFCFG_RH_PLUGIN (user_data); |
1238 | ++ priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1239 | ++ |
1240 | ++ g_clear_object (&priv->dbus.cancellable); |
1241 | ++ |
1242 | ++ if (!ret) { |
1243 | ++ _LOGW ("dbus: couldn't acquire D-Bus service: %s", error->message); |
1244 | ++ _dbus_clear (self); |
1245 | ++ return; |
1246 | ++ } |
1247 | ++ |
1248 | ++ g_variant_get (ret, "(u)", &result); |
1249 | ++ |
1250 | ++ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { |
1251 | ++ _LOGW ("dbus: couldn't acquire ifcfgrh1 D-Bus service (already taken)"); |
1252 | ++ _dbus_clear (self); |
1253 | ++ return; |
1254 | ++ } |
1255 | ++ |
1256 | ++ { |
1257 | ++ static const GDBusInterfaceVTable interface_vtable = { |
1258 | ++ .method_call = _method_call, |
1259 | ++ }; |
1260 | ++ |
1261 | ++ priv->dbus.regist_id = g_dbus_connection_register_object (connection, |
1262 | ++ IFCFGRH1_OBJECT_PATH, |
1263 | ++ interface_info, |
1264 | ++ NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable), |
1265 | ++ self, |
1266 | ++ NULL, |
1267 | ++ &error); |
1268 | ++ if (!priv->dbus.regist_id) { |
1269 | ++ _LOGW ("dbus: couldn't register D-Bus service: %s", error->message); |
1270 | ++ _dbus_clear (self); |
1271 | ++ return; |
1272 | ++ } |
1273 | ++ } |
1274 | ++ |
1275 | ++ _LOGD ("dbus: acquired D-Bus service %s and exported %s object", |
1276 | ++ IFCFGRH1_BUS_NAME, |
1277 | ++ IFCFGRH1_OBJECT_PATH); |
1278 | ++} |
1279 | ++ |
1280 | ++static void |
1281 | ++_dbus_create_done (GObject *source_object, |
1282 | ++ GAsyncResult *res, |
1283 | ++ gpointer user_data) |
1284 | ++{ |
1285 | ++ NMSIfcfgRHPlugin *self; |
1286 | ++ NMSIfcfgRHPluginPrivate *priv; |
1287 | ++ gs_free_error GError *error = NULL; |
1288 | ++ GDBusConnection *connection; |
1289 | ++ |
1290 | ++ connection = g_dbus_connection_new_for_address_finish (res, &error); |
1291 | ++ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
1292 | ++ return; |
1293 | ++ |
1294 | ++ self = NMS_IFCFG_RH_PLUGIN (user_data); |
1295 | ++ priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1296 | ++ |
1297 | ++ g_clear_object (&priv->dbus.cancellable); |
1298 | ++ |
1299 | ++ if (!connection) { |
1300 | ++ _LOGW ("dbus: couldn't initialize system bus: %s", error->message); |
1301 | ++ return; |
1302 | ++ } |
1303 | ++ |
1304 | ++ priv->dbus.connection = connection; |
1305 | ++ priv->dbus.cancellable = g_cancellable_new (); |
1306 | ++ |
1307 | ++ priv->dbus.signal_id = g_signal_connect (priv->dbus.connection, |
1308 | ++ "closed", |
1309 | ++ G_CALLBACK (_dbus_connection_closed), |
1310 | ++ self); |
1311 | ++ |
1312 | ++ g_dbus_connection_call (priv->dbus.connection, |
1313 | ++ DBUS_SERVICE_DBUS, |
1314 | ++ DBUS_PATH_DBUS, |
1315 | ++ DBUS_INTERFACE_DBUS, |
1316 | ++ "RequestName", |
1317 | ++ g_variant_new ("(su)", |
1318 | ++ IFCFGRH1_BUS_NAME, |
1319 | ++ DBUS_NAME_FLAG_DO_NOT_QUEUE), |
1320 | ++ G_VARIANT_TYPE ("(u)"), |
1321 | ++ G_DBUS_CALL_FLAGS_NONE, |
1322 | ++ -1, |
1323 | ++ priv->dbus.cancellable, |
1324 | ++ _dbus_request_name_done, |
1325 | ++ self); |
1326 | ++} |
1327 | ++ |
1328 | ++static void |
1329 | ++_dbus_setup (NMSIfcfgRHPlugin *self) |
1330 | ++{ |
1331 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1332 | ++ gs_free char *address = NULL; |
1333 | ++ gs_free_error GError *error = NULL; |
1334 | ++ |
1335 | ++ _dbus_clear (self); |
1336 | ++ |
1337 | ++ address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, NULL, &error); |
1338 | ++ if (address == NULL) { |
1339 | ++ _LOGW ("dbus: failed getting address for system bus: %s", error->message); |
1340 | ++ return; |
1341 | ++ } |
1342 | ++ |
1343 | ++ priv->dbus.cancellable = g_cancellable_new (); |
1344 | ++ |
1345 | ++ g_dbus_connection_new_for_address (address, |
1346 | ++ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
1347 | ++ | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, |
1348 | ++ NULL, |
1349 | ++ priv->dbus.cancellable, |
1350 | ++ _dbus_create_done, |
1351 | ++ self); |
1352 | ++} |
1353 | ++ |
1354 | ++static void |
1355 | ++config_changed_cb (NMConfig *config, |
1356 | ++ NMConfigData *config_data, |
1357 | ++ NMConfigChangeFlags changes, |
1358 | ++ NMConfigData *old_data, |
1359 | ++ NMSIfcfgRHPlugin *self) |
1360 | ++{ |
1361 | ++ NMSIfcfgRHPluginPrivate *priv; |
1362 | ++ |
1363 | ++ /* If the dbus connection for some reason is borked the D-Bus service |
1364 | ++ * won't be offered. |
1365 | ++ * |
1366 | ++ * On SIGHUP and SIGUSR1 try to re-connect to D-Bus. So in the unlikely |
1367 | ++ * event that the D-Bus connection is broken, that allows for recovery |
1368 | ++ * without need for restarting NetworkManager. */ |
1369 | ++ if (!NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_CAUSE_SIGHUP |
1370 | ++ | NM_CONFIG_CHANGE_CAUSE_SIGUSR1)) |
1371 | ++ return; |
1372 | ++ |
1373 | ++ priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1374 | ++ if ( !priv->dbus.connection |
1375 | ++ && !priv->dbus.cancellable) |
1376 | ++ _dbus_setup (self); |
1377 | ++} |
1378 | ++ |
1379 | ++/*****************************************************************************/ |
1380 | ++ |
1381 | ++static void |
1382 | ++nms_ifcfg_rh_plugin_init (NMSIfcfgRHPlugin *self) |
1383 | ++{ |
1384 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1385 | ++ |
1386 | ++ priv->config = g_object_ref (nm_config_get ()); |
1387 | ++ |
1388 | ++ priv->unmanaged_specs = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); |
1389 | ++ priv->unrecognized_specs = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); |
1390 | ++ |
1391 | ++ priv->storages = (NMSettUtilStorages) NM_SETT_UTIL_STORAGES_INIT (priv->storages, nms_ifcfg_rh_storage_destroy); |
1392 | ++} |
1393 | ++ |
1394 | ++static void |
1395 | ++constructed (GObject *object) |
1396 | ++{ |
1397 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (object); |
1398 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1399 | ++ |
1400 | ++ G_OBJECT_CLASS (nms_ifcfg_rh_plugin_parent_class)->constructed (object); |
1401 | ++ |
1402 | ++ g_signal_connect (priv->config, |
1403 | ++ NM_CONFIG_SIGNAL_CONFIG_CHANGED, |
1404 | ++ G_CALLBACK (config_changed_cb), |
1405 | ++ self); |
1406 | ++ |
1407 | ++ _dbus_setup (self); |
1408 | ++} |
1409 | ++ |
1410 | ++static void |
1411 | ++dispose (GObject *object) |
1412 | ++{ |
1413 | ++ NMSIfcfgRHPlugin *self = NMS_IFCFG_RH_PLUGIN (object); |
1414 | ++ NMSIfcfgRHPluginPrivate *priv = NMS_IFCFG_RH_PLUGIN_GET_PRIVATE (self); |
1415 | ++ |
1416 | ++ if (priv->config) |
1417 | ++ g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); |
1418 | ++ |
1419 | ++ /* FIXME(shutdown) we need a stop method so that we can unregistering the D-Bus service |
1420 | ++ * when NMSettings is shutting down, and not when the instance gets destroyed. */ |
1421 | ++ _dbus_clear (self); |
1422 | ++ |
1423 | ++ nm_sett_util_storages_clear (&priv->storages); |
1424 | ++ |
1425 | ++ g_clear_object (&priv->config); |
1426 | ++ |
1427 | ++ G_OBJECT_CLASS (nms_ifcfg_rh_plugin_parent_class)->dispose (object); |
1428 | ++ |
1429 | ++ nm_clear_pointer (&priv->unmanaged_specs, g_hash_table_destroy); |
1430 | ++ nm_clear_pointer (&priv->unrecognized_specs, g_hash_table_destroy); |
1431 | ++} |
1432 | ++ |
1433 | ++static void |
1434 | ++nms_ifcfg_rh_plugin_class_init (NMSIfcfgRHPluginClass *klass) |
1435 | ++{ |
1436 | ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); |
1437 | ++ NMSettingsPluginClass *plugin_class = NM_SETTINGS_PLUGIN_CLASS (klass); |
1438 | ++ |
1439 | ++ object_class->constructed = constructed; |
1440 | ++ object_class->dispose = dispose; |
1441 | ++ |
1442 | ++ plugin_class->plugin_name = "ifcfg-rh"; |
1443 | ++ plugin_class->get_unmanaged_specs = get_unmanaged_specs; |
1444 | ++ plugin_class->get_unrecognized_specs = get_unrecognized_specs; |
1445 | ++ plugin_class->reload_connections = reload_connections; |
1446 | ++ plugin_class->load_connections = load_connections; |
1447 | ++ plugin_class->load_connections_done = load_connections_done; |
1448 | ++ plugin_class->add_connection = add_connection; |
1449 | ++ plugin_class->update_connection = update_connection; |
1450 | ++ plugin_class->delete_connection = delete_connection; |
1451 | ++} |
1452 | ++ |
1453 | ++/*****************************************************************************/ |
1454 | ++ |
1455 | ++G_MODULE_EXPORT NMSettingsPlugin * |
1456 | ++nm_settings_plugin_factory (void) |
1457 | ++{ |
1458 | ++ return g_object_new (NMS_TYPE_IFCFG_RH_PLUGIN, NULL); |
1459 | ++} |
1460 | +diff --git a/src/settings/plugins/netplan/nms-netplan-plugin.h b/src/settings/plugins/netplan/nms-netplan-plugin.h |
1461 | +new file mode 100644 |
1462 | +index 0000000000000000000000000000000000000000..a226b323049f42da29a4a001d28874bb6e687a55 |
1463 | +--- /dev/null |
1464 | ++++ b/src/settings/plugins/netplan/nms-netplan-plugin.h |
1465 | +@@ -0,0 +1,25 @@ |
1466 | ++// SPDX-License-Identifier: GPL-2.0+ |
1467 | ++/* NetworkManager system settings service |
1468 | ++ * |
1469 | ++ * Dan Williams <dcbw@redhat.com> |
1470 | ++ * Søren Sandmann <sandmann@daimi.au.dk> |
1471 | ++ * |
1472 | ++ * Copyright (C) 2007 - 2008 Red Hat, Inc. |
1473 | ++ */ |
1474 | ++ |
1475 | ++#ifndef __NMS_IFCFG_RH_PLUGIN_H__ |
1476 | ++#define __NMS_IFCFG_RH_PLUGIN_H__ |
1477 | ++ |
1478 | ++#define NMS_TYPE_IFCFG_RH_PLUGIN (nms_ifcfg_rh_plugin_get_type ()) |
1479 | ++#define NMS_IFCFG_RH_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMS_TYPE_IFCFG_RH_PLUGIN, NMSIfcfgRHPlugin)) |
1480 | ++#define NMS_IFCFG_RH_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMS_TYPE_IFCFG_RH_PLUGIN, NMSIfcfgRHPluginClass)) |
1481 | ++#define NMS_IS_IFCFG_RH_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMS_TYPE_IFCFG_RH_PLUGIN)) |
1482 | ++#define NMS_IS_IFCFG_RH_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMS_TYPE_IFCFG_RH_PLUGIN)) |
1483 | ++#define NMS_IFCFG_RH_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMS_TYPE_IFCFG_RH_PLUGIN, NMSIfcfgRHPluginClass)) |
1484 | ++ |
1485 | ++typedef struct _NMSIfcfgRHPlugin NMSIfcfgRHPlugin; |
1486 | ++typedef struct _NMSIfcfgRHPluginClass NMSIfcfgRHPluginClass; |
1487 | ++ |
1488 | ++GType nms_ifcfg_rh_plugin_get_type (void); |
1489 | ++ |
1490 | ++#endif /* __NMS_IFCFG_RH_PLUGIN_H__ */ |
1491 | +diff --git a/src/settings/plugins/netplan/nms-netplan-reader.c b/src/settings/plugins/netplan/nms-netplan-reader.c |
1492 | +new file mode 100644 |
1493 | +index 0000000000000000000000000000000000000000..f348ca473a2102dc3231d1485dc52250384783c1 |
1494 | +--- /dev/null |
1495 | ++++ b/src/settings/plugins/netplan/nms-netplan-reader.c |
1496 | +@@ -0,0 +1,5991 @@ |
1497 | ++// SPDX-License-Identifier: GPL-2.0+ |
1498 | ++/* NetworkManager system settings service |
1499 | ++ * |
1500 | ++ * Copyright 2008 - 2017 Red Hat, Inc. |
1501 | ++ */ |
1502 | ++ |
1503 | ++#include "nm-default.h" |
1504 | ++ |
1505 | ++#include "nms-ifcfg-rh-reader.h" |
1506 | ++ |
1507 | ++#include <stdlib.h> |
1508 | ++#include <sys/types.h> |
1509 | ++#include <sys/socket.h> |
1510 | ++#include <arpa/inet.h> |
1511 | ++#include <sys/wait.h> |
1512 | ++#include <sys/inotify.h> |
1513 | ++#include <sys/ioctl.h> |
1514 | ++#include <unistd.h> |
1515 | ++ |
1516 | ++#include "nm-glib-aux/nm-secret-utils.h" |
1517 | ++#include "nm-connection.h" |
1518 | ++#include "nm-dbus-interface.h" |
1519 | ++#include "nm-setting-connection.h" |
1520 | ++#include "nm-setting-ip4-config.h" |
1521 | ++#include "nm-setting-vlan.h" |
1522 | ++#include "nm-setting-ip6-config.h" |
1523 | ++#include "nm-setting-wired.h" |
1524 | ++#include "nm-setting-wireless.h" |
1525 | ++#include "nm-setting-ethtool.h" |
1526 | ++#include "nm-setting-8021x.h" |
1527 | ++#include "nm-setting-bond.h" |
1528 | ++#include "nm-setting-team.h" |
1529 | ++#include "nm-setting-team-port.h" |
1530 | ++#include "nm-setting-bridge.h" |
1531 | ++#include "nm-setting-bridge-port.h" |
1532 | ++#include "nm-setting-dcb.h" |
1533 | ++#include "nm-setting-user.h" |
1534 | ++#include "nm-setting-proxy.h" |
1535 | ++#include "nm-setting-generic.h" |
1536 | ++#include "nm-core-internal.h" |
1537 | ++#include "nm-utils.h" |
1538 | ++#include "nm-libnm-core-intern/nm-ethtool-utils.h" |
1539 | ++ |
1540 | ++#include "platform/nm-platform.h" |
1541 | ++#include "NetworkManagerUtils.h" |
1542 | ++ |
1543 | ++#include "nms-ifcfg-rh-common.h" |
1544 | ++#include "nms-ifcfg-rh-utils.h" |
1545 | ++#include "shvar.h" |
1546 | ++ |
1547 | ++/*****************************************************************************/ |
1548 | ++ |
1549 | ++#define _NMLOG_DOMAIN LOGD_SETTINGS |
1550 | ++#define _NMLOG_PREFIX_NAME "ifcfg-rh" |
1551 | ++#define _NMLOG(level, ...) \ |
1552 | ++ G_STMT_START { \ |
1553 | ++ nm_log ((level), (_NMLOG_DOMAIN), NULL, NULL, \ |
1554 | ++ "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ |
1555 | ++ _NMLOG_PREFIX_NAME": " \ |
1556 | ++ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ |
1557 | ++ } G_STMT_END |
1558 | ++ |
1559 | ++#define PARSE_WARNING(...) _LOGW ("%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), " " _NM_UTILS_MACRO_REST(__VA_ARGS__)) |
1560 | ++ |
1561 | ++/*****************************************************************************/ |
1562 | ++ |
1563 | ++static char * |
1564 | ++get_full_file_path (const char *ifcfg_path, const char *file_path) |
1565 | ++{ |
1566 | ++ const char *base = file_path; |
1567 | ++ gs_free char *dirname = NULL; |
1568 | ++ char *p; |
1569 | ++ |
1570 | ++ g_return_val_if_fail (ifcfg_path != NULL, NULL); |
1571 | ++ g_return_val_if_fail (file_path != NULL, NULL); |
1572 | ++ |
1573 | ++ if (file_path[0] == '/') |
1574 | ++ return g_strdup (file_path); |
1575 | ++ |
1576 | ++ p = strrchr (file_path, '/'); |
1577 | ++ if (p) |
1578 | ++ base = p + 1; |
1579 | ++ |
1580 | ++ dirname = g_path_get_dirname (ifcfg_path); |
1581 | ++ return g_build_path ("/", dirname, base, NULL); |
1582 | ++} |
1583 | ++ |
1584 | ++/*****************************************************************************/ |
1585 | ++ |
1586 | ++static NMSettingSecretFlags |
1587 | ++_secret_read_ifcfg_flags (shvarFile *ifcfg, const char *flags_key) |
1588 | ++{ |
1589 | ++ NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; |
1590 | ++ gs_free char *val_free = NULL; |
1591 | ++ const char *val; |
1592 | ++ |
1593 | ++ nm_assert (flags_key); |
1594 | ++ nm_assert (g_str_has_suffix (flags_key, "_FLAGS")); |
1595 | ++ |
1596 | ++ val = svGetValueStr (ifcfg, flags_key, &val_free); |
1597 | ++ if (val) { |
1598 | ++ if (strstr (val, SECRET_FLAG_AGENT)) |
1599 | ++ flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; |
1600 | ++ if (strstr (val, SECRET_FLAG_NOT_SAVED)) |
1601 | ++ flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED; |
1602 | ++ if (strstr (val, SECRET_FLAG_NOT_REQUIRED)) |
1603 | ++ flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED; |
1604 | ++ } |
1605 | ++ return flags; |
1606 | ++} |
1607 | ++ |
1608 | ++static void |
1609 | ++_secret_read_ifcfg (shvarFile *ifcfg, |
1610 | ++ shvarFile *keys_ifcfg, |
1611 | ++ const char *name, |
1612 | ++ char **value, |
1613 | ++ NMSettingSecretFlags *flags) |
1614 | ++{ |
1615 | ++ char flags_key[250]; |
1616 | ++ |
1617 | ++ nm_sprintf_buf (flags_key, "%s_FLAGS", name); |
1618 | ++ |
1619 | ++ *flags = _secret_read_ifcfg_flags (ifcfg, flags_key); |
1620 | ++ |
1621 | ++ if (*flags != NM_SETTING_SECRET_FLAG_NONE) |
1622 | ++ *value = NULL; |
1623 | ++ else { |
1624 | ++ *value = svGetValue_cp (ifcfg, name); |
1625 | ++ if (!*value && keys_ifcfg) |
1626 | ++ *value = svGetValue_cp (keys_ifcfg, name); |
1627 | ++ } |
1628 | ++} |
1629 | ++ |
1630 | ++static void |
1631 | ++_secret_set_from_ifcfg (gpointer setting, |
1632 | ++ shvarFile *ifcfg, |
1633 | ++ shvarFile *keys_ifcfg, |
1634 | ++ const char *ifcfg_key, |
1635 | ++ const char *property_name) |
1636 | ++{ |
1637 | ++ nm_auto_free_secret char *secret = NULL; |
1638 | ++ NMSettingSecretFlags flags; |
1639 | ++ char flags_key[250]; |
1640 | ++ |
1641 | ++ nm_assert (NM_IS_SETTING (setting)); |
1642 | ++ |
1643 | ++ _secret_read_ifcfg (ifcfg, keys_ifcfg, ifcfg_key, &secret, &flags); |
1644 | ++ |
1645 | ++ g_object_set (setting, |
1646 | ++ property_name, |
1647 | ++ secret, |
1648 | ++ nm_sprintf_buf (flags_key, "%s-flags", property_name), |
1649 | ++ flags, |
1650 | ++ NULL); |
1651 | ++} |
1652 | ++ |
1653 | ++static gboolean |
1654 | ++_secret_password_raw_to_bytes (const char *ifcfg_key, |
1655 | ++ const char *password_raw, |
1656 | ++ GBytes **out_bytes, |
1657 | ++ GError **error) |
1658 | ++{ |
1659 | ++ nm_auto_free_secret_buf NMSecretBuf *secret = NULL; |
1660 | ++ gsize len; |
1661 | ++ |
1662 | ++ if (!password_raw) { |
1663 | ++ NM_SET_OUT (out_bytes, NULL); |
1664 | ++ return TRUE; |
1665 | ++ } |
1666 | ++ |
1667 | ++ if (password_raw[0] == '0' && password_raw[1] == 'x') |
1668 | ++ password_raw += 2; |
1669 | ++ |
1670 | ++ secret = nm_secret_buf_new (strlen (password_raw) / 2 + 3); |
1671 | ++ if (!nm_utils_hexstr2bin_full (password_raw, FALSE, FALSE, ":", 0, secret->bin, secret->len, &len)) { |
1672 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
1673 | ++ "Invalid hex password in %s", |
1674 | ++ ifcfg_key); |
1675 | ++ return FALSE; |
1676 | ++ } |
1677 | ++ |
1678 | ++ NM_SET_OUT (out_bytes, nm_secret_buf_to_gbytes_take (g_steal_pointer (&secret), len)); |
1679 | ++ return TRUE; |
1680 | ++} |
1681 | ++ |
1682 | ++/*****************************************************************************/ |
1683 | ++ |
1684 | ++static GBytes * |
1685 | ++_cert_get_cert_bytes (const char *ifcfg_path, |
1686 | ++ const char *value, |
1687 | ++ GError **error) |
1688 | ++{ |
1689 | ++ gs_free char *path = NULL; |
1690 | ++ |
1691 | ++ if (NM_STR_HAS_PREFIX (value, "pkcs11:")) |
1692 | ++ return _nm_setting_802_1x_cert_value_to_bytes (NM_SETTING_802_1X_CK_SCHEME_PKCS11, (guint8 *) value, -1, error); |
1693 | ++ |
1694 | ++ path = get_full_file_path (ifcfg_path, value); |
1695 | ++ return _nm_setting_802_1x_cert_value_to_bytes (NM_SETTING_802_1X_CK_SCHEME_PATH, (guint8 *) path, -1, error); |
1696 | ++} |
1697 | ++ |
1698 | ++static gboolean |
1699 | ++_cert_get_cert (shvarFile *ifcfg, |
1700 | ++ const char *ifcfg_key, |
1701 | ++ GBytes **out_cert, |
1702 | ++ NMSetting8021xCKScheme *out_scheme, |
1703 | ++ GError **error) |
1704 | ++{ |
1705 | ++ nm_auto_free_secret char *val_free = NULL; |
1706 | ++ const char *val; |
1707 | ++ gs_unref_bytes GBytes *cert = NULL; |
1708 | ++ GError *local = NULL; |
1709 | ++ NMSetting8021xCKScheme scheme; |
1710 | ++ |
1711 | ++ val = svGetValueStr (ifcfg, ifcfg_key, &val_free); |
1712 | ++ if (!val) { |
1713 | ++ NM_SET_OUT (out_cert, NULL); |
1714 | ++ NM_SET_OUT (out_scheme, NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); |
1715 | ++ return TRUE; |
1716 | ++ } |
1717 | ++ |
1718 | ++ cert = _cert_get_cert_bytes (svFileGetName (ifcfg), val, &local); |
1719 | ++ if (!cert) |
1720 | ++ goto err; |
1721 | ++ |
1722 | ++ scheme = _nm_setting_802_1x_cert_get_scheme (cert, &local); |
1723 | ++ if (scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) |
1724 | ++ goto err; |
1725 | ++ |
1726 | ++ NM_SET_OUT (out_cert, g_steal_pointer (&cert)); |
1727 | ++ NM_SET_OUT (out_scheme, scheme); |
1728 | ++ return TRUE; |
1729 | ++ |
1730 | ++err: |
1731 | ++ g_set_error (error, |
1732 | ++ NM_SETTINGS_ERROR, |
1733 | ++ NM_SETTINGS_ERROR_INVALID_CONNECTION, |
1734 | ++ "invalid certificate %s: %s", |
1735 | ++ ifcfg_key, |
1736 | ++ local->message); |
1737 | ++ g_error_free (local); |
1738 | ++ return FALSE; |
1739 | ++} |
1740 | ++ |
1741 | ++static gboolean |
1742 | ++_cert_set_from_ifcfg (gpointer setting, |
1743 | ++ shvarFile *ifcfg, |
1744 | ++ const char *ifcfg_key, |
1745 | ++ const char *property_name, |
1746 | ++ GBytes **out_cert, |
1747 | ++ GError **error) |
1748 | ++{ |
1749 | ++ gs_unref_bytes GBytes *cert = NULL; |
1750 | ++ |
1751 | ++ if (!_cert_get_cert (ifcfg, |
1752 | ++ ifcfg_key, |
1753 | ++ &cert, |
1754 | ++ NULL, |
1755 | ++ error)) |
1756 | ++ return FALSE; |
1757 | ++ |
1758 | ++ g_object_set (setting, property_name, cert, NULL); |
1759 | ++ |
1760 | ++ NM_SET_OUT (out_cert, g_steal_pointer (&cert)); |
1761 | ++ return TRUE; |
1762 | ++} |
1763 | ++ |
1764 | ++/*****************************************************************************/ |
1765 | ++ |
1766 | ++static void |
1767 | ++check_if_bond_slave (shvarFile *ifcfg, |
1768 | ++ NMSettingConnection *s_con) |
1769 | ++{ |
1770 | ++ gs_free char *value = NULL; |
1771 | ++ const char *v; |
1772 | ++ const char *master; |
1773 | ++ |
1774 | ++ v = svGetValueStr (ifcfg, "MASTER_UUID", &value); |
1775 | ++ if (!v) |
1776 | ++ v = svGetValueStr (ifcfg, "MASTER", &value); |
1777 | ++ |
1778 | ++ if (v) { |
1779 | ++ master = nm_setting_connection_get_master (s_con); |
1780 | ++ if (master) { |
1781 | ++ PARSE_WARNING ("Already configured as slave of %s. Ignoring MASTER{_UUID}=\"%s\"", |
1782 | ++ master, v); |
1783 | ++ return; |
1784 | ++ } |
1785 | ++ |
1786 | ++ g_object_set (s_con, |
1787 | ++ NM_SETTING_CONNECTION_MASTER, v, |
1788 | ++ NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME, |
1789 | ++ NULL); |
1790 | ++ } |
1791 | ++ |
1792 | ++ /* We should be checking for SLAVE=yes as well, but NM used to not set that, |
1793 | ++ * so for backward-compatibility, we don't check. |
1794 | ++ */ |
1795 | ++} |
1796 | ++ |
1797 | ++static void |
1798 | ++check_if_team_slave (shvarFile *ifcfg, |
1799 | ++ NMSettingConnection *s_con) |
1800 | ++{ |
1801 | ++ gs_free char *value = NULL; |
1802 | ++ const char *v; |
1803 | ++ const char *master; |
1804 | ++ |
1805 | ++ v = svGetValueStr (ifcfg, "TEAM_MASTER_UUID", &value); |
1806 | ++ if (!v) |
1807 | ++ v = svGetValueStr (ifcfg, "TEAM_MASTER", &value); |
1808 | ++ if (!v) |
1809 | ++ return; |
1810 | ++ |
1811 | ++ master = nm_setting_connection_get_master (s_con); |
1812 | ++ if (master) { |
1813 | ++ PARSE_WARNING ("Already configured as slave of %s. Ignoring TEAM_MASTER{_UUID}=\"%s\"", |
1814 | ++ master, v); |
1815 | ++ return; |
1816 | ++ } |
1817 | ++ |
1818 | ++ g_object_set (s_con, |
1819 | ++ NM_SETTING_CONNECTION_MASTER, v, |
1820 | ++ NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, |
1821 | ++ NULL); |
1822 | ++} |
1823 | ++ |
1824 | ++static char * |
1825 | ++make_connection_name (shvarFile *ifcfg, |
1826 | ++ const char *ifcfg_name, |
1827 | ++ const char *suggested, |
1828 | ++ const char *prefix) |
1829 | ++{ |
1830 | ++ char *full_name = NULL, *name; |
1831 | ++ |
1832 | ++ /* If the ifcfg file already has a NAME, always use that */ |
1833 | ++ name = svGetValueStr_cp (ifcfg, "NAME"); |
1834 | ++ if (name) |
1835 | ++ return name; |
1836 | ++ |
1837 | ++ /* Otherwise construct a new NAME */ |
1838 | ++ if (!prefix) |
1839 | ++ prefix = "System"; |
1840 | ++ |
1841 | ++ /* For cosmetic reasons, if the suggested name is the same as |
1842 | ++ * the ifcfg files name, don't use it. Mainly for wifi so that |
1843 | ++ * the SSID is shown in the connection ID instead of just "wlan0". |
1844 | ++ */ |
1845 | ++ if (suggested && strcmp (ifcfg_name, suggested)) |
1846 | ++ full_name = g_strdup_printf ("%s %s (%s)", prefix, suggested, ifcfg_name); |
1847 | ++ else |
1848 | ++ full_name = g_strdup_printf ("%s %s", prefix, ifcfg_name); |
1849 | ++ |
1850 | ++ return full_name; |
1851 | ++} |
1852 | ++ |
1853 | ++static NMSetting * |
1854 | ++make_connection_setting (const char *file, |
1855 | ++ shvarFile *ifcfg, |
1856 | ++ const char *type, |
1857 | ++ const char *suggested, |
1858 | ++ const char *prefix) |
1859 | ++{ |
1860 | ++ NMSettingConnection *s_con; |
1861 | ++ NMSettingConnectionLldp lldp; |
1862 | ++ const char *ifcfg_name = NULL; |
1863 | ++ gs_free char *new_id = NULL; |
1864 | ++ const char *uuid; |
1865 | ++ gs_free char *uuid_free = NULL; |
1866 | ++ gs_free char *value = NULL; |
1867 | ++ const char *v; |
1868 | ++ gs_free char *stable_id = NULL; |
1869 | ++ const char *const *iter; |
1870 | ++ int vint64, i_val; |
1871 | ++ |
1872 | ++ ifcfg_name = utils_get_ifcfg_name (file, TRUE); |
1873 | ++ if (!ifcfg_name) |
1874 | ++ return NULL; |
1875 | ++ |
1876 | ++ s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); |
1877 | ++ |
1878 | ++ new_id = make_connection_name (ifcfg, ifcfg_name, suggested, prefix); |
1879 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL); |
1880 | ++ |
1881 | ++ /* Try for a UUID key before falling back to hashing the file name */ |
1882 | ++ uuid = svGetValueStr (ifcfg, "UUID", &uuid_free); |
1883 | ++ if (!uuid) { |
1884 | ++ uuid_free = nm_utils_uuid_generate_from_string (svFileGetName (ifcfg), -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); |
1885 | ++ uuid = uuid_free; |
1886 | ++ } |
1887 | ++ |
1888 | ++ g_object_set (s_con, |
1889 | ++ NM_SETTING_CONNECTION_TYPE, type, |
1890 | ++ NM_SETTING_CONNECTION_UUID, uuid, |
1891 | ++ NM_SETTING_CONNECTION_STABLE_ID, svGetValue (ifcfg, "STABLE_ID", &stable_id), |
1892 | ++ NULL); |
1893 | ++ |
1894 | ++ v = svGetValueStr (ifcfg, "DEVICE", &value); |
1895 | ++ if (v) { |
1896 | ++ GError *error = NULL; |
1897 | ++ |
1898 | ++ if (nm_utils_is_valid_iface_name (v, &error)) { |
1899 | ++ g_object_set (s_con, |
1900 | ++ NM_SETTING_CONNECTION_INTERFACE_NAME, v, |
1901 | ++ NULL); |
1902 | ++ } else { |
1903 | ++ PARSE_WARNING ("invalid DEVICE name '%s': %s", v, error->message); |
1904 | ++ g_error_free (error); |
1905 | ++ } |
1906 | ++ } |
1907 | ++ |
1908 | ++ nm_clear_g_free (&value); |
1909 | ++ v = svGetValueStr (ifcfg, "LLDP", &value); |
1910 | ++ if (nm_streq0 (v, "rx")) |
1911 | ++ lldp = NM_SETTING_CONNECTION_LLDP_ENABLE_RX; |
1912 | ++ else |
1913 | ++ lldp = svParseBoolean (v, NM_SETTING_CONNECTION_LLDP_DEFAULT); |
1914 | ++ |
1915 | ++ /* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */ |
1916 | ++ g_object_set (s_con, |
1917 | ++ NM_SETTING_CONNECTION_AUTOCONNECT, |
1918 | ++ svGetValueBoolean (ifcfg, "ONBOOT", TRUE), |
1919 | ++ NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, |
1920 | ++ (int) svGetValueInt64 (ifcfg, "AUTOCONNECT_PRIORITY", 10, |
1921 | ++ NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN, |
1922 | ++ NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX, |
1923 | ++ NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT), |
1924 | ++ NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES, |
1925 | ++ (int) svGetValueInt64 (ifcfg, "AUTOCONNECT_RETRIES", 10, |
1926 | ++ -1, G_MAXINT32, -1), |
1927 | ++ NM_SETTING_CONNECTION_MULTI_CONNECT, |
1928 | ++ (gint) svGetValueInt64 (ifcfg, "MULTI_CONNECT", 10, |
1929 | ++ G_MININT32, G_MAXINT32, NM_CONNECTION_MULTI_CONNECT_DEFAULT), |
1930 | ++ NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, |
1931 | ++ svGetValueBoolean (ifcfg, "AUTOCONNECT_SLAVES", NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT), |
1932 | ++ NM_SETTING_CONNECTION_LLDP, lldp, |
1933 | ++ NULL); |
1934 | ++ |
1935 | ++ nm_clear_g_free (&value); |
1936 | ++ v = svGetValueStr (ifcfg, "USERS", &value); |
1937 | ++ if (v) { |
1938 | ++ gs_free const char **items = NULL; |
1939 | ++ |
1940 | ++ items = nm_utils_strsplit_set (v, " "); |
1941 | ++ for (iter = items; iter && *iter; iter++) { |
1942 | ++ if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL)) |
1943 | ++ PARSE_WARNING ("invalid USERS item '%s'", *iter); |
1944 | ++ } |
1945 | ++ } |
1946 | ++ |
1947 | ++ nm_clear_g_free (&value); |
1948 | ++ v = svGetValueStr (ifcfg, "ZONE", &value); |
1949 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, v, NULL); |
1950 | ++ |
1951 | ++ nm_clear_g_free (&value); |
1952 | ++ v = svGetValueStr (ifcfg, "SECONDARY_UUIDS", &value); |
1953 | ++ if (v) { |
1954 | ++ gs_free const char **items = NULL; |
1955 | ++ |
1956 | ++ items = nm_utils_strsplit_set (v, " \t"); |
1957 | ++ for (iter = items; iter && *iter; iter++) { |
1958 | ++ if (!nm_setting_connection_add_secondary (s_con, *iter)) |
1959 | ++ PARSE_WARNING ("secondary connection UUID '%s' already added", *iter); |
1960 | ++ } |
1961 | ++ } |
1962 | ++ |
1963 | ++ nm_clear_g_free (&value); |
1964 | ++ v = svGetValueStr (ifcfg, "BRIDGE_UUID", &value); |
1965 | ++ if (!v) |
1966 | ++ v = svGetValueStr (ifcfg, "BRIDGE", &value); |
1967 | ++ if (v) { |
1968 | ++ const char *old_value; |
1969 | ++ |
1970 | ++ if ((old_value = nm_setting_connection_get_master (s_con))) { |
1971 | ++ PARSE_WARNING ("Already configured as slave of %s. Ignoring BRIDGE=\"%s\"", |
1972 | ++ old_value, v); |
1973 | ++ } else { |
1974 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, v, NULL); |
1975 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, |
1976 | ++ NM_SETTING_BRIDGE_SETTING_NAME, NULL); |
1977 | ++ } |
1978 | ++ } |
1979 | ++ |
1980 | ++ check_if_bond_slave (ifcfg, s_con); |
1981 | ++ check_if_team_slave (ifcfg, s_con); |
1982 | ++ |
1983 | ++ nm_clear_g_free (&value); |
1984 | ++ v = svGetValueStr (ifcfg, "OVS_PORT_UUID", &value); |
1985 | ++ if (!v) |
1986 | ++ v = svGetValueStr (ifcfg, "OVS_PORT", &value); |
1987 | ++ if (v) { |
1988 | ++ const char *old_value; |
1989 | ++ |
1990 | ++ if ((old_value = nm_setting_connection_get_master (s_con))) { |
1991 | ++ PARSE_WARNING ("Already configured as slave of %s. Ignoring OVS_PORT=\"%s\"", |
1992 | ++ old_value, v); |
1993 | ++ } else { |
1994 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, v, NULL); |
1995 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, |
1996 | ++ NM_SETTING_OVS_PORT_SETTING_NAME, NULL); |
1997 | ++ } |
1998 | ++ } |
1999 | ++ |
2000 | ++ nm_clear_g_free (&value); |
2001 | ++ v = svGetValueStr (ifcfg, "GATEWAY_PING_TIMEOUT", &value); |
2002 | ++ if (v) { |
2003 | ++ gint64 tmp; |
2004 | ++ |
2005 | ++ tmp = _nm_utils_ascii_str_to_int64 (v, 10, 0, G_MAXINT32 - 1, -1); |
2006 | ++ if (tmp >= 0) { |
2007 | ++ if (tmp > 600) { |
2008 | ++ tmp = 600; |
2009 | ++ PARSE_WARNING ("invalid GATEWAY_PING_TIMEOUT time"); |
2010 | ++ } |
2011 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, (guint) tmp, NULL); |
2012 | ++ } else |
2013 | ++ PARSE_WARNING ("invalid GATEWAY_PING_TIMEOUT time"); |
2014 | ++ } |
2015 | ++ |
2016 | ++ switch (svGetValueBoolean (ifcfg, "CONNECTION_METERED", -1)) { |
2017 | ++ case TRUE: |
2018 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_METERED, NM_METERED_YES, NULL); |
2019 | ++ break; |
2020 | ++ case FALSE: |
2021 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_METERED, NM_METERED_NO, NULL); |
2022 | ++ break; |
2023 | ++ } |
2024 | ++ |
2025 | ++ vint64 = svGetValueInt64 (ifcfg, "AUTH_RETRIES", 10, -1, G_MAXINT32, -1); |
2026 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (int) vint64, NULL); |
2027 | ++ |
2028 | ++ nm_clear_g_free (&value); |
2029 | ++ v = svGetValueStr (ifcfg, "DEVTIMEOUT", &value); |
2030 | ++ if (v) { |
2031 | ++ vint64 = _nm_utils_ascii_str_to_int64 (v, 10, 0, ((gint64) G_MAXINT32) / 1000, -1); |
2032 | ++ if (vint64 != -1) |
2033 | ++ vint64 *= 1000; |
2034 | ++ else { |
2035 | ++ char *endptr; |
2036 | ++ double d; |
2037 | ++ |
2038 | ++ d = g_ascii_strtod (v, &endptr); |
2039 | ++ if ( errno == 0 |
2040 | ++ && endptr[0] == '\0' |
2041 | ++ && d >= 0.0) { |
2042 | ++ d *= 1000.0; |
2043 | ++ |
2044 | ++ /* We round. Yes, this is not correct to round IEEE 754 floats in general, |
2045 | ++ * but sufficient for our case where we know that NetworkManager wrote the |
2046 | ++ * setting with up to 3 digits for the milliseconds. */ |
2047 | ++ d += 0.5; |
2048 | ++ if ( d >= 0.0 |
2049 | ++ && d <= (double) G_MAXINT32) |
2050 | ++ vint64 = (gint64) d; |
2051 | ++ } |
2052 | ++ } |
2053 | ++ if (vint64 == -1) |
2054 | ++ PARSE_WARNING ("invalid DEVTIMEOUT setting"); |
2055 | ++ else |
2056 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, (int) vint64, NULL); |
2057 | ++ } |
2058 | ++ |
2059 | ++ i_val = NM_SETTING_CONNECTION_MDNS_DEFAULT; |
2060 | ++ if (!svGetValueEnum (ifcfg, "MDNS", |
2061 | ++ nm_setting_connection_mdns_get_type (), |
2062 | ++ &i_val, NULL)) |
2063 | ++ PARSE_WARNING ("invalid MDNS setting"); |
2064 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_MDNS, i_val, NULL); |
2065 | ++ |
2066 | ++ i_val = NM_SETTING_CONNECTION_LLMNR_DEFAULT; |
2067 | ++ if (!svGetValueEnum (ifcfg, "LLMNR", |
2068 | ++ nm_setting_connection_llmnr_get_type (), |
2069 | ++ &i_val, NULL)) |
2070 | ++ PARSE_WARNING ("invalid LLMNR setting"); |
2071 | ++ g_object_set (s_con, NM_SETTING_CONNECTION_LLMNR, i_val, NULL); |
2072 | ++ |
2073 | ++ return NM_SETTING (s_con); |
2074 | ++} |
2075 | ++ |
2076 | ++static gboolean |
2077 | ++read_ip4_address (shvarFile *ifcfg, |
2078 | ++ const char *tag, |
2079 | ++ gboolean *out_has_key, |
2080 | ++ guint32 *out_addr, |
2081 | ++ GError **error) |
2082 | ++{ |
2083 | ++ gs_free char *value_to_free = NULL; |
2084 | ++ const char *value; |
2085 | ++ in_addr_t a; |
2086 | ++ |
2087 | ++ nm_assert (ifcfg); |
2088 | ++ nm_assert (tag); |
2089 | ++ nm_assert (!error || !*error); |
2090 | ++ |
2091 | ++ value = svGetValueStr (ifcfg, tag, &value_to_free); |
2092 | ++ if (!value) { |
2093 | ++ NM_SET_OUT (out_has_key, FALSE); |
2094 | ++ NM_SET_OUT (out_addr, 0); |
2095 | ++ return TRUE; |
2096 | ++ } |
2097 | ++ |
2098 | ++ if (inet_pton (AF_INET, value, &a) != 1) { |
2099 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2100 | ++ "Invalid %s IP4 address '%s'", tag, value); |
2101 | ++ return FALSE; |
2102 | ++ } |
2103 | ++ |
2104 | ++ NM_SET_OUT (out_has_key, TRUE); |
2105 | ++ NM_SET_OUT (out_addr, a); |
2106 | ++ return TRUE; |
2107 | ++} |
2108 | ++ |
2109 | ++static gboolean |
2110 | ++is_any_ip4_address_defined (shvarFile *ifcfg, int *idx) |
2111 | ++{ |
2112 | ++ int i, ignore, *ret_idx; |
2113 | ++ |
2114 | ++ ret_idx = idx ?: &ignore; |
2115 | ++ |
2116 | ++ for (i = -1; i <= 2; i++) { |
2117 | ++ gs_free char *value = NULL; |
2118 | ++ char tag[256]; |
2119 | ++ |
2120 | ++ if (svGetValueStr (ifcfg, numbered_tag (tag, "IPADDR", i), &value)) { |
2121 | ++ *ret_idx = i; |
2122 | ++ return TRUE; |
2123 | ++ } |
2124 | ++ |
2125 | ++ if (svGetValueStr (ifcfg, numbered_tag (tag, "PREFIX", i), &value)) { |
2126 | ++ *ret_idx = i; |
2127 | ++ return TRUE; |
2128 | ++ } |
2129 | ++ |
2130 | ++ if (svGetValueStr (ifcfg, numbered_tag (tag, "NETMASK", i), &value)) { |
2131 | ++ *ret_idx = i; |
2132 | ++ return TRUE; |
2133 | ++ } |
2134 | ++ } |
2135 | ++ return FALSE; |
2136 | ++} |
2137 | ++ |
2138 | ++/* Returns TRUE on missing address or valid address */ |
2139 | ++static gboolean |
2140 | ++read_full_ip4_address (shvarFile *ifcfg, |
2141 | ++ gint32 which, |
2142 | ++ NMIPAddress *base_addr, |
2143 | ++ NMIPAddress **out_address, |
2144 | ++ char **out_gateway, |
2145 | ++ GError **error) |
2146 | ++{ |
2147 | ++ char tag[256]; |
2148 | ++ char prefix_tag[256]; |
2149 | ++ guint32 ipaddr; |
2150 | ++ gs_free char *value = NULL; |
2151 | ++ const char *v; |
2152 | ++ int prefix = 0; |
2153 | ++ gboolean has_key; |
2154 | ++ guint32 a; |
2155 | ++ char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; |
2156 | ++ |
2157 | ++ g_return_val_if_fail (which >= -1, FALSE); |
2158 | ++ g_return_val_if_fail (ifcfg != NULL, FALSE); |
2159 | ++ g_return_val_if_fail (out_address != NULL, FALSE); |
2160 | ++ g_return_val_if_fail (*out_address == NULL, FALSE); |
2161 | ++ g_return_val_if_fail (!error || !*error, FALSE); |
2162 | ++ |
2163 | ++ /* IP address */ |
2164 | ++ if (!read_ip4_address (ifcfg, |
2165 | ++ numbered_tag (tag, "IPADDR", which), |
2166 | ++ &has_key, &ipaddr, error)) |
2167 | ++ return FALSE; |
2168 | ++ if (!has_key) { |
2169 | ++ if (!base_addr) |
2170 | ++ return TRUE; |
2171 | ++ nm_ip_address_get_address_binary (base_addr, &ipaddr); |
2172 | ++ } |
2173 | ++ |
2174 | ++ /* Gateway */ |
2175 | ++ if (out_gateway && !*out_gateway) { |
2176 | ++ if (!read_ip4_address (ifcfg, |
2177 | ++ numbered_tag (tag, "GATEWAY", which), |
2178 | ++ &has_key, &a, error)) |
2179 | ++ return FALSE; |
2180 | ++ if (has_key) |
2181 | ++ *out_gateway = nm_utils_inet4_ntop_dup (a); |
2182 | ++ } |
2183 | ++ |
2184 | ++ /* Prefix */ |
2185 | ++ numbered_tag (prefix_tag, "PREFIX", which); |
2186 | ++ v = svGetValueStr (ifcfg, prefix_tag, &value); |
2187 | ++ if (v) { |
2188 | ++ prefix = _nm_utils_ascii_str_to_int64 (v, 10, 0, 32, -1); |
2189 | ++ if (prefix < 0) { |
2190 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2191 | ++ "Invalid IP4 prefix '%s'", v); |
2192 | ++ return FALSE; |
2193 | ++ } |
2194 | ++ } else { |
2195 | ++ /* Fall back to NETMASK if no PREFIX was specified */ |
2196 | ++ if (!read_ip4_address (ifcfg, |
2197 | ++ numbered_tag (tag, "NETMASK", which), |
2198 | ++ &has_key, &a, error)) |
2199 | ++ return FALSE; |
2200 | ++ if (has_key) |
2201 | ++ prefix = nm_utils_ip4_netmask_to_prefix (a); |
2202 | ++ else { |
2203 | ++ if (base_addr) |
2204 | ++ prefix = nm_ip_address_get_prefix (base_addr); |
2205 | ++ else { |
2206 | ++ /* Try to autodetermine the prefix for the address' class */ |
2207 | ++ prefix = _nm_utils_ip4_get_default_prefix (ipaddr); |
2208 | ++ PARSE_WARNING ("missing %s, assuming %s/%d", prefix_tag, nm_utils_inet4_ntop (ipaddr, inet_buf), prefix); |
2209 | ++ } |
2210 | ++ } |
2211 | ++ } |
2212 | ++ |
2213 | ++ *out_address = nm_ip_address_new_binary (AF_INET, &ipaddr, prefix, error); |
2214 | ++ if (*out_address) |
2215 | ++ return TRUE; |
2216 | ++ |
2217 | ++ return FALSE; |
2218 | ++} |
2219 | ++ |
2220 | ++/*****************************************************************************/ |
2221 | ++ |
2222 | ++static gboolean |
2223 | ++parse_route_line_is_comment (const char *line) |
2224 | ++{ |
2225 | ++ /* we obtained the line from a legacy route file. Here we skip |
2226 | ++ * empty lines and comments. |
2227 | ++ * |
2228 | ++ * initscripts compares: "$line" =~ '^[[:space:]]*(\#.*)?$' |
2229 | ++ */ |
2230 | ++ while (nm_utils_is_separator (line[0])) |
2231 | ++ line++; |
2232 | ++ if (NM_IN_SET (line[0], '\0', '#')) |
2233 | ++ return TRUE; |
2234 | ++ return FALSE; |
2235 | ++} |
2236 | ++ |
2237 | ++/*****************************************************************************/ |
2238 | ++ |
2239 | ++typedef struct { |
2240 | ++ const char *key; |
2241 | ++ |
2242 | ++ /* the element is not available in this case. */ |
2243 | ++ bool disabled:1; |
2244 | ++ |
2245 | ++ /* whether the element is to be ignored. Ignord is different from |
2246 | ++ * "disabled", because we still parse the option, but don't use it. */ |
2247 | ++ bool ignore:1; |
2248 | ++ |
2249 | ++ bool int_base_16:1; |
2250 | ++ |
2251 | ++ /* whether the command line option was found, and @v is |
2252 | ++ * initialized. */ |
2253 | ++ bool has:1; |
2254 | ++ |
2255 | ++ /* the type, one of PARSE_LINE_TYPE_* */ |
2256 | ++ char type; |
2257 | ++ |
2258 | ++ union { |
2259 | ++ guint8 uint8; |
2260 | ++ guint32 uint32; |
2261 | ++ struct { |
2262 | ++ guint32 uint32; |
2263 | ++ bool lock:1; |
2264 | ++ } uint32_with_lock; |
2265 | ++ struct { |
2266 | ++ NMIPAddr addr; |
2267 | ++ guint8 plen; |
2268 | ++ bool has_plen:1; |
2269 | ++ } addr; |
2270 | ++ } v; |
2271 | ++ |
2272 | ++} ParseLineInfo; |
2273 | ++ |
2274 | ++enum { |
2275 | ++ /* route attributes */ |
2276 | ++ PARSE_LINE_ATTR_ROUTE_TABLE, |
2277 | ++ PARSE_LINE_ATTR_ROUTE_SRC, |
2278 | ++ PARSE_LINE_ATTR_ROUTE_FROM, |
2279 | ++ PARSE_LINE_ATTR_ROUTE_TOS, |
2280 | ++ PARSE_LINE_ATTR_ROUTE_ONLINK, |
2281 | ++ PARSE_LINE_ATTR_ROUTE_WINDOW, |
2282 | ++ PARSE_LINE_ATTR_ROUTE_CWND, |
2283 | ++ PARSE_LINE_ATTR_ROUTE_INITCWND, |
2284 | ++ PARSE_LINE_ATTR_ROUTE_INITRWND, |
2285 | ++ PARSE_LINE_ATTR_ROUTE_MTU, |
2286 | ++ |
2287 | ++ /* iproute2 arguments that only matter when parsing the file. */ |
2288 | ++ PARSE_LINE_ATTR_ROUTE_TO, |
2289 | ++ PARSE_LINE_ATTR_ROUTE_VIA, |
2290 | ++ PARSE_LINE_ATTR_ROUTE_METRIC, |
2291 | ++ |
2292 | ++ /* iproute2 parameters that are well known and that we silently ignore. */ |
2293 | ++ PARSE_LINE_ATTR_ROUTE_DEV, |
2294 | ++}; |
2295 | ++ |
2296 | ++#define PARSE_LINE_TYPE_UINT8 '8' |
2297 | ++#define PARSE_LINE_TYPE_UINT32 'u' |
2298 | ++#define PARSE_LINE_TYPE_UINT32_WITH_LOCK 'l' |
2299 | ++#define PARSE_LINE_TYPE_ADDR 'a' |
2300 | ++#define PARSE_LINE_TYPE_ADDR_WITH_PREFIX 'p' |
2301 | ++#define PARSE_LINE_TYPE_IFNAME 'i' |
2302 | ++#define PARSE_LINE_TYPE_FLAG 'f' |
2303 | ++ |
2304 | ++/** |
2305 | ++ * parse_route_line: |
2306 | ++ * @line: the line to parse. This is either a line from the route-* or route6-* file, |
2307 | ++ * or the numbered OPTIONS setting. |
2308 | ++ * @addr_family: the address family. |
2309 | ++ * @options_route: (in-out): when line is from the OPTIONS setting, this is a pre-created |
2310 | ++ * route object that is completed with the settings from options. Otherwise, |
2311 | ++ * it shall point to %NULL and a new route is created and returned. |
2312 | ++ * @out_route: (out) (transfer-full) (allow-none): the parsed %NMIPRoute instance. |
2313 | ++ * In case a @options_route is passed in, it returns the input route that was modified |
2314 | ++ * in-place. But the caller must unref the returned route in either case. |
2315 | ++ * @error: the failure description. |
2316 | ++ * |
2317 | ++ * Parsing the route options line has two modes: one for the numbered OPTIONS |
2318 | ++ * setting, and one for initscript's handle_ip_file(), which takes the lines |
2319 | ++ * and passes them to `ip route add`. The modes are similar, but certain properties |
2320 | ++ * are not allowed for OPTIONS. |
2321 | ++ * The mode is differentiated by having an @options_route argument. |
2322 | ++ * |
2323 | ++ * Returns: returns a negative errno on failure. On success, it returns 0 |
2324 | ++ * and @out_route. |
2325 | ++ */ |
2326 | ++static int |
2327 | ++parse_route_line (const char *line, |
2328 | ++ int addr_family, |
2329 | ++ NMIPRoute *options_route, |
2330 | ++ NMIPRoute **out_route, |
2331 | ++ GError **error) |
2332 | ++{ |
2333 | ++ nm_auto_unref_ip_route NMIPRoute *route = NULL; |
2334 | ++ gs_free const char **words_free = NULL; |
2335 | ++ const char *const*words; |
2336 | ++ const char *s; |
2337 | ++ gsize i_words; |
2338 | ++ guint i; |
2339 | ++ char buf1[256]; |
2340 | ++ char buf2[256]; |
2341 | ++ ParseLineInfo infos[] = { |
2342 | ++ [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, |
2343 | ++ .type = PARSE_LINE_TYPE_UINT32, }, |
2344 | ++ [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, |
2345 | ++ .type = PARSE_LINE_TYPE_ADDR, }, |
2346 | ++ [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, |
2347 | ++ .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, |
2348 | ++ .disabled = (addr_family != AF_INET6), }, |
2349 | ++ [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, |
2350 | ++ .type = PARSE_LINE_TYPE_UINT8, |
2351 | ++ .int_base_16 = TRUE, |
2352 | ++ .ignore = (addr_family != AF_INET), }, |
2353 | ++ [PARSE_LINE_ATTR_ROUTE_ONLINK] = { .key = NM_IP_ROUTE_ATTRIBUTE_ONLINK, |
2354 | ++ .type = PARSE_LINE_TYPE_FLAG, |
2355 | ++ .ignore = (addr_family != AF_INET), }, |
2356 | ++ [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, |
2357 | ++ .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, |
2358 | ++ [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, |
2359 | ++ .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, |
2360 | ++ [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, |
2361 | ++ .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, |
2362 | ++ [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, |
2363 | ++ .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, |
2364 | ++ [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, |
2365 | ++ .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, |
2366 | ++ |
2367 | ++ [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", |
2368 | ++ .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, |
2369 | ++ .disabled = (options_route != NULL), }, |
2370 | ++ [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", |
2371 | ++ .type = PARSE_LINE_TYPE_ADDR, |
2372 | ++ .disabled = (options_route != NULL), }, |
2373 | ++ [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", |
2374 | ++ .type = PARSE_LINE_TYPE_UINT32, |
2375 | ++ .disabled = (options_route != NULL), }, |
2376 | ++ |
2377 | ++ [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", |
2378 | ++ .type = PARSE_LINE_TYPE_IFNAME, |
2379 | ++ .ignore = TRUE, |
2380 | ++ .disabled = (options_route != NULL), }, |
2381 | ++ }; |
2382 | ++ |
2383 | ++ nm_assert (line); |
2384 | ++ nm_assert_addr_family (addr_family); |
2385 | ++ nm_assert (!options_route || nm_ip_route_get_family (options_route) == addr_family); |
2386 | ++ |
2387 | ++ /* initscripts read the legacy route file line-by-line and |
2388 | ++ * use it as `ip route add $line`, thus doing split+glob. |
2389 | ++ * Splitting on IFS (which we consider '<space><tab><newline>') |
2390 | ++ * and globbing (which we obviously don't do). |
2391 | ++ * |
2392 | ++ * I think it's a mess, because it doesn't support escaping or |
2393 | ++ * quoting. In fact, it can only encode benign values. |
2394 | ++ * |
2395 | ++ * We also use the same form for the numbered OPTIONS |
2396 | ++ * variable. I think it's bad not to support any form of |
2397 | ++ * escaping. But do that for now. |
2398 | ++ * |
2399 | ++ * Maybe later we want to support some form of quotation here. |
2400 | ++ * Which of course, would be incompatible with initscripts. |
2401 | ++ */ |
2402 | ++ words_free = nm_utils_strsplit_set (line, " \t\n"); |
2403 | ++ |
2404 | ++ words = words_free ?: NM_PTRARRAY_EMPTY (const char *); |
2405 | ++ |
2406 | ++ for (i_words = 0; words[i_words]; ) { |
2407 | ++ const gsize i_words0 = i_words; |
2408 | ++ const char *const w = words[i_words0]; |
2409 | ++ ParseLineInfo *info; |
2410 | ++ gboolean unqualified_addr = FALSE; |
2411 | ++ |
2412 | ++ for (i = 0; i < G_N_ELEMENTS (infos); i++) { |
2413 | ++ info = &infos[i]; |
2414 | ++ |
2415 | ++ if (info->disabled) |
2416 | ++ continue; |
2417 | ++ |
2418 | ++ if (!nm_streq (w, info->key)) |
2419 | ++ continue; |
2420 | ++ |
2421 | ++ if (info->has) { |
2422 | ++ /* iproute2 for most arguments allows specifying them multiple times. |
2423 | ++ * Let's not do that. */ |
2424 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2425 | ++ "Duplicate option \"%s\"", w); |
2426 | ++ return -EINVAL; |
2427 | ++ } |
2428 | ++ |
2429 | ++ info->has = TRUE; |
2430 | ++ switch (info->type) { |
2431 | ++ case PARSE_LINE_TYPE_UINT8: |
2432 | ++ i_words++; |
2433 | ++ goto parse_line_type_uint8; |
2434 | ++ case PARSE_LINE_TYPE_UINT32: |
2435 | ++ i_words++; |
2436 | ++ goto parse_line_type_uint32; |
2437 | ++ case PARSE_LINE_TYPE_UINT32_WITH_LOCK: |
2438 | ++ i_words++; |
2439 | ++ goto parse_line_type_uint32_with_lock; |
2440 | ++ case PARSE_LINE_TYPE_ADDR: |
2441 | ++ i_words++; |
2442 | ++ goto parse_line_type_addr; |
2443 | ++ case PARSE_LINE_TYPE_ADDR_WITH_PREFIX: |
2444 | ++ i_words++; |
2445 | ++ goto parse_line_type_addr_with_prefix; |
2446 | ++ case PARSE_LINE_TYPE_IFNAME: |
2447 | ++ i_words++; |
2448 | ++ goto parse_line_type_ifname; |
2449 | ++ case PARSE_LINE_TYPE_FLAG: |
2450 | ++ i_words++; |
2451 | ++ goto next; |
2452 | ++ default: |
2453 | ++ nm_assert_not_reached (); |
2454 | ++ } |
2455 | ++ } |
2456 | ++ |
2457 | ++ /* "to" is also accepted unqualified... (once) */ |
2458 | ++ info = &infos[PARSE_LINE_ATTR_ROUTE_TO]; |
2459 | ++ if (!info->has && !info->disabled) { |
2460 | ++ unqualified_addr = TRUE; |
2461 | ++ info->has = TRUE; |
2462 | ++ goto parse_line_type_addr; |
2463 | ++ } |
2464 | ++ |
2465 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2466 | ++ "Unrecognized argument (\"to\" is duplicate or \"%s\" is garbage)", w); |
2467 | ++ return -EINVAL; |
2468 | ++ |
2469 | ++parse_line_type_uint8: |
2470 | ++ s = words[i_words]; |
2471 | ++ if (!s) |
2472 | ++ goto err_word_missing_argument; |
2473 | ++ info->v.uint8 = _nm_utils_ascii_str_to_int64 (s, |
2474 | ++ info->int_base_16 ? 16 : 10, |
2475 | ++ 0, |
2476 | ++ G_MAXUINT8, |
2477 | ++ 0);; |
2478 | ++ if (errno) { |
2479 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2480 | ++ "Argument for \"%s\" is not a valid number", w); |
2481 | ++ return -EINVAL; |
2482 | ++ } |
2483 | ++ i_words++; |
2484 | ++ goto next; |
2485 | ++ |
2486 | ++parse_line_type_uint32: |
2487 | ++parse_line_type_uint32_with_lock: |
2488 | ++ s = words[i_words]; |
2489 | ++ if (!s) |
2490 | ++ goto err_word_missing_argument; |
2491 | ++ if (info->type == PARSE_LINE_TYPE_UINT32_WITH_LOCK) { |
2492 | ++ if (nm_streq (s, "lock")) { |
2493 | ++ s = words[++i_words]; |
2494 | ++ if (!s) |
2495 | ++ goto err_word_missing_argument; |
2496 | ++ info->v.uint32_with_lock.lock = TRUE; |
2497 | ++ } else |
2498 | ++ info->v.uint32_with_lock.lock = FALSE; |
2499 | ++ info->v.uint32_with_lock.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0);; |
2500 | ++ } else { |
2501 | ++ info->v.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0); |
2502 | ++ } |
2503 | ++ if (errno) { |
2504 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2505 | ++ "Argument for \"%s\" is not a valid number", w); |
2506 | ++ return -EINVAL; |
2507 | ++ } |
2508 | ++ i_words++; |
2509 | ++ goto next; |
2510 | ++ |
2511 | ++parse_line_type_ifname: |
2512 | ++ s = words[i_words]; |
2513 | ++ if (!s) |
2514 | ++ goto err_word_missing_argument; |
2515 | ++ i_words++; |
2516 | ++ goto next; |
2517 | ++ |
2518 | ++parse_line_type_addr: |
2519 | ++parse_line_type_addr_with_prefix: |
2520 | ++ s = words[i_words]; |
2521 | ++ if (!s) |
2522 | ++ goto err_word_missing_argument; |
2523 | ++ { |
2524 | ++ int prefix = -1; |
2525 | ++ |
2526 | ++ if (info->type == PARSE_LINE_TYPE_ADDR) { |
2527 | ++ if (!nm_utils_parse_inaddr_bin (addr_family, |
2528 | ++ s, |
2529 | ++ NULL, |
2530 | ++ &info->v.addr.addr)) { |
2531 | ++ if ( info == &infos[PARSE_LINE_ATTR_ROUTE_VIA] |
2532 | ++ && nm_streq (s, "(null)")) { |
2533 | ++ /* Due to a bug, would older versions of NM write "via (null)" |
2534 | ++ * (rh#1452648). Workaround that, and accept it.*/ |
2535 | ++ memset (&info->v.addr.addr, 0, sizeof (info->v.addr.addr)); |
2536 | ++ } else { |
2537 | ++ if (unqualified_addr) { |
2538 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2539 | ++ "Unrecognized argument (inet prefix is expected rather then \"%s\")", w); |
2540 | ++ return -EINVAL; |
2541 | ++ } else { |
2542 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2543 | ++ "Argument for \"%s\" is not a valid IPv%c address", w, |
2544 | ++ addr_family == AF_INET ? '4' : '6'); |
2545 | ++ } |
2546 | ++ return -EINVAL; |
2547 | ++ } |
2548 | ++ } |
2549 | ++ } else { |
2550 | ++ nm_assert (info->type == PARSE_LINE_TYPE_ADDR_WITH_PREFIX); |
2551 | ++ if ( info == &infos[PARSE_LINE_ATTR_ROUTE_TO] |
2552 | ++ && nm_streq (s, "default")) { |
2553 | ++ memset (&info->v.addr.addr, 0, sizeof (info->v.addr.addr)); |
2554 | ++ prefix = 0; |
2555 | ++ } else if (!nm_utils_parse_inaddr_prefix_bin (addr_family, |
2556 | ++ s, |
2557 | ++ NULL, |
2558 | ++ &info->v.addr.addr, |
2559 | ++ &prefix)) { |
2560 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2561 | ++ "Argument for \"%s\" is not ADDR/PREFIX format", w); |
2562 | ++ return -EINVAL; |
2563 | ++ } |
2564 | ++ } |
2565 | ++ if (prefix == -1) |
2566 | ++ info->v.addr.has_plen = FALSE; |
2567 | ++ else { |
2568 | ++ info->v.addr.has_plen = TRUE; |
2569 | ++ info->v.addr.plen = prefix; |
2570 | ++ } |
2571 | ++ } |
2572 | ++ i_words++; |
2573 | ++ goto next; |
2574 | ++ |
2575 | ++err_word_missing_argument: |
2576 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2577 | ++ "Missing argument for \"%s\"", w); |
2578 | ++ return -EINVAL; |
2579 | ++next: |
2580 | ++ ; |
2581 | ++ } |
2582 | ++ |
2583 | ++ if (options_route) { |
2584 | ++ route = options_route; |
2585 | ++ nm_ip_route_ref (route); |
2586 | ++ } else { |
2587 | ++ ParseLineInfo *info_to = &infos[PARSE_LINE_ATTR_ROUTE_TO]; |
2588 | ++ ParseLineInfo *info_via = &infos[PARSE_LINE_ATTR_ROUTE_VIA]; |
2589 | ++ ParseLineInfo *info_metric = &infos[PARSE_LINE_ATTR_ROUTE_METRIC]; |
2590 | ++ guint prefix; |
2591 | ++ |
2592 | ++ if (!info_to->has) { |
2593 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2594 | ++ "Missing destination prefix"); |
2595 | ++ return -EINVAL; |
2596 | ++ } |
2597 | ++ |
2598 | ++ prefix = info_to->v.addr.has_plen |
2599 | ++ ? info_to->v.addr.plen |
2600 | ++ : (addr_family == AF_INET ? 32 : 128); |
2601 | ++ |
2602 | ++ route = nm_ip_route_new_binary (addr_family, |
2603 | ++ &info_to->v.addr.addr, |
2604 | ++ prefix, |
2605 | ++ info_via->has ? &info_via->v.addr.addr : NULL, |
2606 | ++ info_metric->has ? (gint64) info_metric->v.uint32 : (gint64) -1, |
2607 | ++ error); |
2608 | ++ info_to->has = FALSE; |
2609 | ++ info_via->has = FALSE; |
2610 | ++ info_metric->has = FALSE; |
2611 | ++ if (!route) |
2612 | ++ return -EINVAL; |
2613 | ++ } |
2614 | ++ |
2615 | ++ for (i = 0; i < G_N_ELEMENTS (infos); i++) { |
2616 | ++ ParseLineInfo *info = &infos[i]; |
2617 | ++ |
2618 | ++ if (!info->has) |
2619 | ++ continue; |
2620 | ++ if (info->ignore || info->disabled) |
2621 | ++ continue; |
2622 | ++ switch (info->type) { |
2623 | ++ case PARSE_LINE_TYPE_UINT8: |
2624 | ++ nm_ip_route_set_attribute (route, |
2625 | ++ info->key, |
2626 | ++ g_variant_new_byte (info->v.uint8)); |
2627 | ++ break; |
2628 | ++ case PARSE_LINE_TYPE_UINT32: |
2629 | ++ nm_ip_route_set_attribute (route, |
2630 | ++ info->key, |
2631 | ++ g_variant_new_uint32 (info->v.uint32)); |
2632 | ++ break; |
2633 | ++ case PARSE_LINE_TYPE_UINT32_WITH_LOCK: |
2634 | ++ if (info->v.uint32_with_lock.lock) { |
2635 | ++ nm_ip_route_set_attribute (route, |
2636 | ++ nm_sprintf_buf (buf1, "lock-%s", info->key), |
2637 | ++ g_variant_new_boolean (TRUE)); |
2638 | ++ } |
2639 | ++ nm_ip_route_set_attribute (route, |
2640 | ++ info->key, |
2641 | ++ g_variant_new_uint32 (info->v.uint32_with_lock.uint32)); |
2642 | ++ break; |
2643 | ++ case PARSE_LINE_TYPE_ADDR: |
2644 | ++ case PARSE_LINE_TYPE_ADDR_WITH_PREFIX: |
2645 | ++ nm_ip_route_set_attribute (route, |
2646 | ++ info->key, |
2647 | ++ g_variant_new_printf ("%s%s", |
2648 | ++ inet_ntop (addr_family, &info->v.addr.addr, buf1, sizeof (buf1)), |
2649 | ++ info->v.addr.has_plen |
2650 | ++ ? nm_sprintf_buf (buf2, "/%u", (unsigned) info->v.addr.plen) |
2651 | ++ : "")); |
2652 | ++ break; |
2653 | ++ case PARSE_LINE_TYPE_FLAG: |
2654 | ++ /* NOTE: the flag (for "onlink") only allows to explicitly set "TRUE". |
2655 | ++ * There is no way to express an explicit "FALSE" setting |
2656 | ++ * of this attribute, hence, the file format cannot encode |
2657 | ++ * that configuration. */ |
2658 | ++ nm_ip_route_set_attribute (route, |
2659 | ++ info->key, |
2660 | ++ g_variant_new_boolean (TRUE)); |
2661 | ++ break; |
2662 | ++ default: |
2663 | ++ nm_assert_not_reached (); |
2664 | ++ break; |
2665 | ++ } |
2666 | ++ } |
2667 | ++ |
2668 | ++ nm_assert (_nm_ip_route_attribute_validate_all (route)); |
2669 | ++ |
2670 | ++ NM_SET_OUT (out_route, g_steal_pointer (&route)); |
2671 | ++ return 0; |
2672 | ++} |
2673 | ++ |
2674 | ++/* Returns TRUE on missing route or valid route */ |
2675 | ++static gboolean |
2676 | ++read_one_ip4_route (shvarFile *ifcfg, |
2677 | ++ guint32 which, |
2678 | ++ NMIPRoute **out_route, |
2679 | ++ GError **error) |
2680 | ++{ |
2681 | ++ char tag[256]; |
2682 | ++ char netmask_tag[256]; |
2683 | ++ guint32 dest; |
2684 | ++ guint32 next_hop; |
2685 | ++ guint32 netmask; |
2686 | ++ gboolean has_key; |
2687 | ++ const char *v; |
2688 | ++ gs_free char *value = NULL; |
2689 | ++ gint64 prefix, metric; |
2690 | ++ char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; |
2691 | ++ |
2692 | ++ g_return_val_if_fail (ifcfg != NULL, FALSE); |
2693 | ++ g_return_val_if_fail (out_route && !*out_route, FALSE); |
2694 | ++ g_return_val_if_fail (!error || !*error, FALSE); |
2695 | ++ |
2696 | ++ /* Destination */ |
2697 | ++ if (!read_ip4_address (ifcfg, |
2698 | ++ numbered_tag (tag, "ADDRESS", which), |
2699 | ++ &has_key, &dest, error)) |
2700 | ++ return FALSE; |
2701 | ++ if (!has_key) { |
2702 | ++ /* missing route = success */ |
2703 | ++ *out_route = NULL; |
2704 | ++ return TRUE; |
2705 | ++ } |
2706 | ++ |
2707 | ++ /* Next hop */ |
2708 | ++ if (!read_ip4_address (ifcfg, |
2709 | ++ numbered_tag (tag, "GATEWAY", which), |
2710 | ++ NULL, &next_hop, error)) |
2711 | ++ return FALSE; |
2712 | ++ /* We don't make distinction between missing GATEWAY IP and 0.0.0.0 */ |
2713 | ++ |
2714 | ++ /* Prefix */ |
2715 | ++ if (!read_ip4_address (ifcfg, |
2716 | ++ numbered_tag (netmask_tag, "NETMASK", which), |
2717 | ++ &has_key, &netmask, error)) |
2718 | ++ return FALSE; |
2719 | ++ if (has_key) { |
2720 | ++ prefix = nm_utils_ip4_netmask_to_prefix (netmask); |
2721 | ++ if (netmask != _nm_utils_ip4_prefix_to_netmask (prefix)) { |
2722 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2723 | ++ "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, inet_buf)); |
2724 | ++ return FALSE; |
2725 | ++ } |
2726 | ++ } else { |
2727 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2728 | ++ "Missing IP4 route element '%s'", netmask_tag); |
2729 | ++ return FALSE; |
2730 | ++ } |
2731 | ++ |
2732 | ++ /* Metric */ |
2733 | ++ nm_clear_g_free (&value); |
2734 | ++ v = svGetValueStr (ifcfg, numbered_tag (tag, "METRIC", which), &value); |
2735 | ++ if (v) { |
2736 | ++ metric = _nm_utils_ascii_str_to_int64 (v, 10, 0, G_MAXUINT32, -1); |
2737 | ++ if (metric < 0) { |
2738 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2739 | ++ "Invalid IP4 route metric '%s'", v); |
2740 | ++ return FALSE; |
2741 | ++ } |
2742 | ++ } else |
2743 | ++ metric = -1; |
2744 | ++ |
2745 | ++ *out_route = nm_ip_route_new_binary (AF_INET, &dest, prefix, &next_hop, metric, error); |
2746 | ++ if (!*out_route) |
2747 | ++ return FALSE; |
2748 | ++ |
2749 | ++ /* Options */ |
2750 | ++ nm_clear_g_free (&value); |
2751 | ++ v = svGetValueStr (ifcfg, numbered_tag (tag, "OPTIONS", which), &value); |
2752 | ++ if (v) { |
2753 | ++ if (parse_route_line (v, AF_INET, *out_route, NULL, error) < 0) { |
2754 | ++ g_clear_pointer (out_route, nm_ip_route_unref); |
2755 | ++ return FALSE; |
2756 | ++ } |
2757 | ++ } |
2758 | ++ |
2759 | ++ return TRUE; |
2760 | ++} |
2761 | ++ |
2762 | ++static gboolean |
2763 | ++read_route_file (int addr_family, |
2764 | ++ const char *filename, |
2765 | ++ NMSettingIPConfig *s_ip, |
2766 | ++ GError **error) |
2767 | ++{ |
2768 | ++ gs_free char *contents = NULL; |
2769 | ++ char *contents_rest = NULL; |
2770 | ++ const char *line; |
2771 | ++ gsize len = 0; |
2772 | ++ gsize line_num; |
2773 | ++ |
2774 | ++ g_return_val_if_fail (filename, FALSE); |
2775 | ++ g_return_val_if_fail ( (addr_family == AF_INET && NM_IS_SETTING_IP4_CONFIG (s_ip)) |
2776 | ++ || (addr_family == AF_INET6 && NM_IS_SETTING_IP6_CONFIG (s_ip)), FALSE); |
2777 | ++ g_return_val_if_fail (!error || !*error, FALSE); |
2778 | ++ |
2779 | ++ if ( !g_file_get_contents (filename, &contents, &len, NULL) |
2780 | ++ || !len) { |
2781 | ++ return TRUE; /* missing/empty = success */ |
2782 | ++ } |
2783 | ++ |
2784 | ++ line_num = 0; |
2785 | ++ for (line = strtok_r (contents, "\n", &contents_rest); |
2786 | ++ line; |
2787 | ++ line = strtok_r (NULL, "\n", &contents_rest)) { |
2788 | ++ nm_auto_unref_ip_route NMIPRoute *route = NULL; |
2789 | ++ gs_free_error GError *local = NULL; |
2790 | ++ int e; |
2791 | ++ |
2792 | ++ line_num++; |
2793 | ++ |
2794 | ++ if (parse_route_line_is_comment (line)) |
2795 | ++ continue; |
2796 | ++ |
2797 | ++ e = parse_route_line (line, addr_family, NULL, &route, &local); |
2798 | ++ |
2799 | ++ if (e < 0) { |
2800 | ++ if (e == -ERANGE) |
2801 | ++ PARSE_WARNING ("ignoring manual default route: '%s' (%s)", line, filename); |
2802 | ++ else { |
2803 | ++ /* we accept all unrecognized lines, because otherwise we would reject the |
2804 | ++ * entire connection. */ |
2805 | ++ PARSE_WARNING ("ignoring invalid route at \"%s\" (%s:%lu): %s", line, filename, (long unsigned) line_num, local->message); |
2806 | ++ } |
2807 | ++ continue; |
2808 | ++ } |
2809 | ++ |
2810 | ++ if (!nm_setting_ip_config_add_route (s_ip, route)) |
2811 | ++ PARSE_WARNING ("duplicate IPv%c route", addr_family == AF_INET ? '4' : '6'); |
2812 | ++ } |
2813 | ++ |
2814 | ++ return TRUE; |
2815 | ++} |
2816 | ++ |
2817 | ++static void |
2818 | ++parse_dns_options (NMSettingIPConfig *ip_config, const char *value) |
2819 | ++{ |
2820 | ++ gs_free const char **options = NULL; |
2821 | ++ const char *const *item; |
2822 | ++ |
2823 | ++ g_return_if_fail (ip_config); |
2824 | ++ |
2825 | ++ if (!value) |
2826 | ++ return; |
2827 | ++ |
2828 | ++ if (!nm_setting_ip_config_has_dns_options (ip_config)) |
2829 | ++ nm_setting_ip_config_clear_dns_options (ip_config, TRUE); |
2830 | ++ |
2831 | ++ options = nm_utils_strsplit_set (value, " "); |
2832 | ++ if (options) { |
2833 | ++ for (item = options; *item; item++) { |
2834 | ++ if (!nm_setting_ip_config_add_dns_option (ip_config, *item)) |
2835 | ++ PARSE_WARNING ("can't add DNS option '%s'", *item); |
2836 | ++ } |
2837 | ++ } |
2838 | ++} |
2839 | ++ |
2840 | ++static gboolean |
2841 | ++parse_full_ip6_address (shvarFile *ifcfg, |
2842 | ++ const char *addr_str, |
2843 | ++ int i, |
2844 | ++ NMIPAddress **out_address, |
2845 | ++ GError **error) |
2846 | ++{ |
2847 | ++ NMIPAddress *addr; |
2848 | ++ NMIPAddr addr_bin; |
2849 | ++ int prefix; |
2850 | ++ |
2851 | ++ nm_assert (addr_str); |
2852 | ++ nm_assert (out_address && !*out_address); |
2853 | ++ nm_assert (!error || !*error); |
2854 | ++ |
2855 | ++ if (!nm_utils_parse_inaddr_prefix_bin (AF_INET6, |
2856 | ++ addr_str, |
2857 | ++ NULL, |
2858 | ++ &addr_bin, |
2859 | ++ &prefix)) { |
2860 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
2861 | ++ "Invalid IP6 address '%s'", addr_str); |
2862 | ++ return FALSE; |
2863 | ++ } |
2864 | ++ |
2865 | ++ if (prefix < 0) |
2866 | ++ prefix = 64; |
2867 | ++ |
2868 | ++ addr = nm_ip_address_new_binary (AF_INET6, &addr_bin, prefix, error); |
2869 | ++ if (!addr) |
2870 | ++ return FALSE; |
2871 | ++ |
2872 | ++ *out_address = addr; |
2873 | ++ return TRUE; |
2874 | ++} |
2875 | ++ |
2876 | ++static NMSetting * |
2877 | ++make_user_setting (shvarFile *ifcfg) |
2878 | ++{ |
2879 | ++ gboolean has_user_data = FALSE; |
2880 | ++ gs_unref_object NMSettingUser *s_user = NULL; |
2881 | ++ gs_unref_hashtable GHashTable *keys = NULL; |
2882 | ++ GHashTableIter iter; |
2883 | ++ const char *key; |
2884 | ++ nm_auto_free_gstring GString *str = NULL; |
2885 | ++ |
2886 | ++ keys = svGetKeys (ifcfg, SV_KEY_TYPE_USER); |
2887 | ++ if (!keys) |
2888 | ++ return NULL; |
2889 | ++ |
2890 | ++ g_hash_table_iter_init (&iter, keys); |
2891 | ++ while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) { |
2892 | ++ const char *value; |
2893 | ++ gs_free char *value_to_free = NULL; |
2894 | ++ |
2895 | ++ value = svGetValue (ifcfg, key, &value_to_free); |
2896 | ++ |
2897 | ++ if (!value) |
2898 | ++ continue; |
2899 | ++ |
2900 | ++ if (!str) |
2901 | ++ str = g_string_sized_new (100); |
2902 | ++ else |
2903 | ++ g_string_set_size (str, 0); |
2904 | ++ |
2905 | ++ if (!nms_ifcfg_rh_utils_user_key_decode (key + NM_STRLEN ("NM_USER_"), str)) |
2906 | ++ continue; |
2907 | ++ |
2908 | ++ if (!s_user) |
2909 | ++ s_user = NM_SETTING_USER (nm_setting_user_new ()); |
2910 | ++ |
2911 | ++ if (nm_setting_user_set_data (s_user, str->str, |
2912 | ++ value, NULL)) |
2913 | ++ has_user_data = TRUE; |
2914 | ++ } |
2915 | ++ |
2916 | ++ return has_user_data |
2917 | ++ ? NM_SETTING (g_steal_pointer (&s_user)) |
2918 | ++ : NULL; |
2919 | ++} |
2920 | ++ |
2921 | ++static NMSetting * |
2922 | ++make_match_setting (shvarFile *ifcfg) |
2923 | ++{ |
2924 | ++ NMSettingMatch *s_match = NULL; |
2925 | ++ gs_free const char **strv = NULL; |
2926 | ++ gs_free char *value = NULL; |
2927 | ++ const char *v; |
2928 | ++ gsize i; |
2929 | ++ |
2930 | ++ v = svGetValueStr (ifcfg, "MATCH_INTERFACE_NAME", &value); |
2931 | ++ if (!v) |
2932 | ++ return NULL; |
2933 | ++ |
2934 | ++ strv = nm_utils_escaped_tokens_split (v, NM_ASCII_SPACES); |
2935 | ++ if (strv) { |
2936 | ++ for (i = 0; strv[i]; i++) { |
2937 | ++ if (!s_match) |
2938 | ++ s_match = (NMSettingMatch *) nm_setting_match_new (); |
2939 | ++ nm_setting_match_add_interface_name (s_match, strv[i]); |
2940 | ++ } |
2941 | ++ } |
2942 | ++ |
2943 | ++ return (NMSetting *) s_match; |
2944 | ++} |
2945 | ++ |
2946 | ++static NMSetting * |
2947 | ++make_proxy_setting (shvarFile *ifcfg) |
2948 | ++{ |
2949 | ++ NMSettingProxy *s_proxy = NULL; |
2950 | ++ gs_free char *value = NULL; |
2951 | ++ const char *v; |
2952 | ++ NMSettingProxyMethod method; |
2953 | ++ |
2954 | ++ v = svGetValueStr (ifcfg, "PROXY_METHOD", &value); |
2955 | ++ if (!v) |
2956 | ++ return NULL; |
2957 | ++ |
2958 | ++ if (!g_ascii_strcasecmp (v, "auto")) |
2959 | ++ method = NM_SETTING_PROXY_METHOD_AUTO; |
2960 | ++ else |
2961 | ++ method = NM_SETTING_PROXY_METHOD_NONE; |
2962 | ++ |
2963 | ++ s_proxy = (NMSettingProxy *) nm_setting_proxy_new (); |
2964 | ++ |
2965 | ++ switch (method) { |
2966 | ++ case NM_SETTING_PROXY_METHOD_AUTO: |
2967 | ++ g_object_set (s_proxy, |
2968 | ++ NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_AUTO, |
2969 | ++ NULL); |
2970 | ++ |
2971 | ++ nm_clear_g_free (&value); |
2972 | ++ v = svGetValueStr (ifcfg, "PAC_URL", &value); |
2973 | ++ if (v) |
2974 | ++ g_object_set (s_proxy, NM_SETTING_PROXY_PAC_URL, v, NULL); |
2975 | ++ |
2976 | ++ nm_clear_g_free (&value); |
2977 | ++ v = svGetValueStr (ifcfg, "PAC_SCRIPT", &value); |
2978 | ++ if (v) |
2979 | ++ g_object_set (s_proxy, NM_SETTING_PROXY_PAC_SCRIPT, v, NULL); |
2980 | ++ |
2981 | ++ break; |
2982 | ++ case NM_SETTING_PROXY_METHOD_NONE: |
2983 | ++ g_object_set (s_proxy, |
2984 | ++ NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_NONE, |
2985 | ++ NULL); |
2986 | ++ break; |
2987 | ++ } |
2988 | ++ |
2989 | ++ if (svGetValueBoolean (ifcfg, "BROWSER_ONLY", FALSE)) |
2990 | ++ g_object_set (s_proxy, NM_SETTING_PROXY_BROWSER_ONLY, TRUE, NULL); |
2991 | ++ |
2992 | ++ return NM_SETTING (s_proxy); |
2993 | ++} |
2994 | ++ |
2995 | ++static NMSetting * |
2996 | ++make_ip4_setting (shvarFile *ifcfg, |
2997 | ++ shvarFile *network_ifcfg, |
2998 | ++ gboolean routes_read, |
2999 | ++ gboolean *out_has_defroute, |
3000 | ++ GError **error) |
3001 | ++{ |
3002 | ++ gs_unref_object NMSettingIPConfig *s_ip4 = NULL; |
3003 | ++ gs_free char *route_path = NULL; |
3004 | ++ gs_free char *value = NULL; |
3005 | ++ const char *v; |
3006 | ++ char *method; |
3007 | ++ gs_free char *dns_options_free = NULL; |
3008 | ++ const char *dns_options = NULL; |
3009 | ++ gs_free char *gateway = NULL; |
3010 | ++ int i; |
3011 | ++ guint32 a; |
3012 | ++ gboolean has_key; |
3013 | ++ shvarFile *route_ifcfg; |
3014 | ++ gboolean never_default; |
3015 | ++ gint64 timeout; |
3016 | ++ int priority; |
3017 | ++ const char *const *item; |
3018 | ++ guint32 route_table; |
3019 | ++ |
3020 | ++ nm_assert (out_has_defroute && !*out_has_defroute); |
3021 | ++ |
3022 | ++ s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); |
3023 | ++ |
3024 | ++ /* First check if DEFROUTE is set for this device; DEFROUTE has the |
3025 | ++ * opposite meaning from never-default. The default if DEFROUTE is not |
3026 | ++ * specified is DEFROUTE=yes which means that this connection can be used |
3027 | ++ * as a default route |
3028 | ++ */ |
3029 | ++ i = svGetValueBoolean (ifcfg, "DEFROUTE", -1); |
3030 | ++ if (i == -1) |
3031 | ++ never_default = FALSE; |
3032 | ++ else { |
3033 | ++ never_default = !i; |
3034 | ++ *out_has_defroute = TRUE; |
3035 | ++ } |
3036 | ++ |
3037 | ++ /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */ |
3038 | ++ if (network_ifcfg) { |
3039 | ++ gs_free char *gatewaydev_value = NULL; |
3040 | ++ const char *gatewaydev; |
3041 | ++ |
3042 | ++ /* Get the connection ifcfg device name and the global gateway device */ |
3043 | ++ v = svGetValueStr (ifcfg, "DEVICE", &value); |
3044 | ++ gatewaydev = svGetValueStr (network_ifcfg, "GATEWAYDEV", &gatewaydev_value); |
3045 | ++ dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free); |
3046 | ++ |
3047 | ++ /* If there was a global gateway device specified, then only connections |
3048 | ++ * for that device can be the default connection. |
3049 | ++ */ |
3050 | ++ if (gatewaydev && v) |
3051 | ++ never_default = !!strcmp (v, gatewaydev); |
3052 | ++ |
3053 | ++ nm_clear_g_free (&value); |
3054 | ++ } |
3055 | ++ |
3056 | ++ v = svGetValueStr (ifcfg, "BOOTPROTO", &value); |
3057 | ++ |
3058 | ++ if (!v || !*v || !g_ascii_strcasecmp (v, "none")) { |
3059 | ++ if (is_any_ip4_address_defined (ifcfg, NULL)) |
3060 | ++ method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; |
3061 | ++ else |
3062 | ++ method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; |
3063 | ++ } else if (!g_ascii_strcasecmp (v, "bootp") || !g_ascii_strcasecmp (v, "dhcp")) { |
3064 | ++ method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; |
3065 | ++ } else if (!g_ascii_strcasecmp (v, "static")) { |
3066 | ++ if (is_any_ip4_address_defined (ifcfg, NULL)) |
3067 | ++ method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; |
3068 | ++ else |
3069 | ++ method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; |
3070 | ++ } else if (!g_ascii_strcasecmp (v, "autoip")) { |
3071 | ++ method = NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL; |
3072 | ++ } else if (!g_ascii_strcasecmp (v, "shared")) { |
3073 | ++ method = NM_SETTING_IP4_CONFIG_METHOD_SHARED; |
3074 | ++ } else { |
3075 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
3076 | ++ "Unknown BOOTPROTO '%s'", v); |
3077 | ++ return NULL; |
3078 | ++ } |
3079 | ++ |
3080 | ++ /* the route table (policy routing) is ignored if we don't handle routes. */ |
3081 | ++ route_table = svGetValueInt64 (ifcfg, "IPV4_ROUTE_TABLE", 10, |
3082 | ++ 0, G_MAXUINT32, 0); |
3083 | ++ if ( route_table != 0 |
3084 | ++ && !routes_read) { |
3085 | ++ PARSE_WARNING ("'rule-' or 'rule6-' files are present; Policy routing (IPV4_ROUTE_TABLE) is ignored"); |
3086 | ++ route_table = 0; |
3087 | ++ } |
3088 | ++ |
3089 | ++ g_object_set (s_ip4, |
3090 | ++ NM_SETTING_IP_CONFIG_METHOD, method, |
3091 | ++ NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svGetValueBoolean (ifcfg, "PEERDNS", TRUE), |
3092 | ++ NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svGetValueBoolean (ifcfg, "PEERROUTES", TRUE), |
3093 | ++ NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default, |
3094 | ++ NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV4_FAILURE_FATAL", FALSE), |
3095 | ++ NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV4_ROUTE_METRIC", 10, |
3096 | ++ -1, G_MAXUINT32, -1), |
3097 | ++ NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) route_table, |
3098 | ++ NULL); |
3099 | ++ |
3100 | ++ if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) |
3101 | ++ return NM_SETTING (g_steal_pointer (&s_ip4)); |
3102 | ++ |
3103 | ++ /* Handle DHCP settings */ |
3104 | ++ nm_clear_g_free (&value); |
3105 | ++ v = svGetValueStr (ifcfg, "DHCP_HOSTNAME", &value); |
3106 | ++ if (v) |
3107 | ++ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, v, NULL); |
3108 | ++ |
3109 | ++ nm_clear_g_free (&value); |
3110 | ++ v = svGetValueStr (ifcfg, "DHCP_FQDN", &value); |
3111 | ++ if (v) { |
3112 | ++ g_object_set (s_ip4, |
3113 | ++ NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, NULL, |
3114 | ++ NM_SETTING_IP4_CONFIG_DHCP_FQDN, v, |
3115 | ++ NULL); |
3116 | ++ } |
3117 | ++ |
3118 | ++ g_object_set (s_ip4, |
3119 | ++ NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCP_SEND_HOSTNAME", TRUE), |
3120 | ++ NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, svGetValueInt64 (ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXINT32, 0), |
3121 | ++ NULL); |
3122 | ++ |
3123 | ++ nm_clear_g_free (&value); |
3124 | ++ v = svGetValueStr (ifcfg, "DHCP_CLIENT_ID", &value); |
3125 | ++ if (v) |
3126 | ++ g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, v, NULL); |
3127 | ++ |
3128 | ++ /* Read static IP addresses. |
3129 | ++ * Read them even for AUTO method - in this case the addresses are |
3130 | ++ * added to the automatic ones. Note that this is not currently supported by |
3131 | ++ * the legacy 'network' service (ifup-eth). |
3132 | ++ */ |
3133 | ++ for (i = -1;; i++) { |
3134 | ++ NMIPAddress *addr = NULL; |
3135 | ++ |
3136 | ++ /* gateway will only be set if still unset. Hence, we don't leak gateway |
3137 | ++ * here by calling read_full_ip4_address() repeatedly */ |
3138 | ++ if (!read_full_ip4_address (ifcfg, i, NULL, &addr, &gateway, error)) |
3139 | ++ return NULL; |
3140 | ++ |
3141 | ++ if (!addr) { |
3142 | ++ /* The first mandatory variable is 2-indexed (IPADDR2) |
3143 | ++ * Variables IPADDR, IPADDR0 and IPADDR1 are optional */ |
3144 | ++ if (i > 1) |
3145 | ++ break; |
3146 | ++ continue; |
3147 | ++ } |
3148 | ++ |
3149 | ++ if (!nm_setting_ip_config_add_address (s_ip4, addr)) |
3150 | ++ PARSE_WARNING ("duplicate IP4 address"); |
3151 | ++ nm_ip_address_unref (addr); |
3152 | ++ } |
3153 | ++ |
3154 | ++ /* Gateway */ |
3155 | ++ if (!gateway) { |
3156 | ++ if (network_ifcfg) { |
3157 | ++ gboolean read_success; |
3158 | ++ |
3159 | ++ read_success = read_ip4_address (network_ifcfg, "GATEWAY", &has_key, &a, error); |
3160 | ++ if (!read_success) |
3161 | ++ return NULL; |
3162 | ++ if (has_key) { |
3163 | ++ if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) { |
3164 | ++ gs_free char *f = g_path_get_basename (svFileGetName (ifcfg)); |
3165 | ++ PARSE_WARNING ("ignoring GATEWAY (/etc/sysconfig/network) for %s " |
3166 | ++ "because the connection has no static addresses", f); |
3167 | ++ } else |
3168 | ++ gateway = nm_utils_inet4_ntop_dup (a); |
3169 | ++ } |
3170 | ++ } |
3171 | ++ } |
3172 | ++ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL); |
3173 | ++ |
3174 | ++ if (gateway && never_default) |
3175 | ++ PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled"); |
3176 | ++ |
3177 | ++ /* We used to skip saving a lot of unused properties for the ipv4 shared method. |
3178 | ++ * We want now to persist them but... unfortunately loading DNS or DOMAIN options |
3179 | ++ * would cause a fail in the ipv4 verify() function. As we don't want any regression |
3180 | ++ * in the unlikely event that someone has a working ifcfg file for an IPv4 shared ip |
3181 | ++ * connection with a crafted "DNS" entry... don't load it. So we will avoid failing |
3182 | ++ * the connection) */ |
3183 | ++ if (!nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { |
3184 | ++ /* DNS servers |
3185 | ++ * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting()) |
3186 | ++ */ |
3187 | ++ for (i = 1; i <= 10; i++) { |
3188 | ++ char tag[256]; |
3189 | ++ |
3190 | ++ numbered_tag (tag, "DNS", i); |
3191 | ++ nm_clear_g_free (&value); |
3192 | ++ v = svGetValueStr (ifcfg, tag, &value); |
3193 | ++ if (v) { |
3194 | ++ if (nm_utils_ipaddr_valid (AF_INET, v)) { |
3195 | ++ if (!nm_setting_ip_config_add_dns (s_ip4, v)) |
3196 | ++ PARSE_WARNING ("duplicate DNS server %s", tag); |
3197 | ++ } else if (nm_utils_ipaddr_valid (AF_INET6, v)) { |
3198 | ++ /* Ignore IPv6 addresses */ |
3199 | ++ } else { |
3200 | ++ PARSE_WARNING ("invalid DNS server address %s", v); |
3201 | ++ return NULL; |
3202 | ++ } |
3203 | ++ } |
3204 | ++ } |
3205 | ++ |
3206 | ++ /* DNS searches */ |
3207 | ++ nm_clear_g_free (&value); |
3208 | ++ v = svGetValueStr (ifcfg, "DOMAIN", &value); |
3209 | ++ if (v) { |
3210 | ++ gs_free const char **searches = NULL; |
3211 | ++ |
3212 | ++ searches = nm_utils_strsplit_set (v, " "); |
3213 | ++ if (searches) { |
3214 | ++ for (item = searches; *item; item++) { |
3215 | ++ if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) |
3216 | ++ PARSE_WARNING ("duplicate DNS domain '%s'", *item); |
3217 | ++ } |
3218 | ++ } |
3219 | ++ } |
3220 | ++ } |
3221 | ++ |
3222 | ++ /* DNS options */ |
3223 | ++ nm_clear_g_free (&value); |
3224 | ++ parse_dns_options (s_ip4, svGetValue (ifcfg, "RES_OPTIONS", &value)); |
3225 | ++ parse_dns_options (s_ip4, dns_options); |
3226 | ++ |
3227 | ++ /* DNS priority */ |
3228 | ++ priority = svGetValueInt64 (ifcfg, "IPV4_DNS_PRIORITY", 10, G_MININT32, G_MAXINT32, 0); |
3229 | ++ g_object_set (s_ip4, |
3230 | ++ NM_SETTING_IP_CONFIG_DNS_PRIORITY, |
3231 | ++ priority, |
3232 | ++ NULL); |
3233 | ++ |
3234 | ++ /* Static routes - route-<name> file */ |
3235 | ++ route_path = utils_get_route_path (svFileGetName (ifcfg)); |
3236 | ++ |
3237 | ++ if (!routes_read) { |
3238 | ++ /* NOP */ |
3239 | ++ } else if (utils_has_route_file_new_syntax (route_path)) { |
3240 | ++ /* Parse route file in new syntax */ |
3241 | ++ route_ifcfg = utils_get_route_ifcfg (svFileGetName (ifcfg), FALSE); |
3242 | ++ if (route_ifcfg) { |
3243 | ++ for (i = 0;; i++) { |
3244 | ++ NMIPRoute *route = NULL; |
3245 | ++ |
3246 | ++ if (!read_one_ip4_route (route_ifcfg, i, &route, error)) { |
3247 | ++ svCloseFile (route_ifcfg); |
3248 | ++ return NULL; |
3249 | ++ } |
3250 | ++ |
3251 | ++ if (!route) |
3252 | ++ break; |
3253 | ++ |
3254 | ++ if (!nm_setting_ip_config_add_route (s_ip4, route)) |
3255 | ++ PARSE_WARNING ("duplicate IP4 route"); |
3256 | ++ nm_ip_route_unref (route); |
3257 | ++ } |
3258 | ++ svCloseFile (route_ifcfg); |
3259 | ++ } |
3260 | ++ } else { |
3261 | ++ if (!read_route_file (AF_INET, route_path, s_ip4, error)) |
3262 | ++ return NULL; |
3263 | ++ } |
3264 | ++ |
3265 | ++ /* Legacy value NM used for a while but is incorrect (rh #459370) */ |
3266 | ++ if ( !nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) |
3267 | ++ && !nm_setting_ip_config_get_num_dns_searches (s_ip4)) { |
3268 | ++ nm_clear_g_free (&value); |
3269 | ++ v = svGetValueStr (ifcfg, "SEARCH", &value); |
3270 | ++ if (v) { |
3271 | ++ gs_free const char **searches = NULL; |
3272 | ++ |
3273 | ++ searches = nm_utils_strsplit_set (v, " "); |
3274 | ++ if (searches) { |
3275 | ++ for (item = searches; *item; item++) { |
3276 | ++ if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) |
3277 | ++ PARSE_WARNING ("duplicate DNS search '%s'", *item); |
3278 | ++ } |
3279 | ++ } |
3280 | ++ } |
3281 | ++ } |
3282 | ++ |
3283 | ++ timeout = svGetValueInt64 (ifcfg, "ACD_TIMEOUT", 10, -1, NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, -2); |
3284 | ++ if (timeout == -2) { |
3285 | ++ timeout = svGetValueInt64 (ifcfg, "ARPING_WAIT", 10, -1, |
3286 | ++ NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX / 1000, -1); |
3287 | ++ if (timeout > 0) |
3288 | ++ timeout *= 1000; |
3289 | ++ } |
3290 | ++ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (int) timeout, NULL); |
3291 | ++ |
3292 | ++ return NM_SETTING (g_steal_pointer (&s_ip4)); |
3293 | ++} |
3294 | ++ |
3295 | ++static void |
3296 | ++read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *filename) |
3297 | ++{ |
3298 | ++ GDir *dir; |
3299 | ++ gs_free char *dirname = NULL; |
3300 | ++ gs_free char *base = NULL; |
3301 | ++ NMIPAddress *base_addr = NULL; |
3302 | ++ GError *err = NULL; |
3303 | ++ |
3304 | ++ g_return_if_fail (s_ip4 != NULL); |
3305 | ++ g_return_if_fail (filename != NULL); |
3306 | ++ |
3307 | ++ if (nm_setting_ip_config_get_num_addresses (s_ip4) > 0) |
3308 | ++ base_addr = nm_setting_ip_config_get_address (s_ip4, 0); |
3309 | ++ |
3310 | ++ dirname = g_path_get_dirname (filename); |
3311 | ++ nm_assert (dirname != NULL); |
3312 | ++ base = g_path_get_basename (filename); |
3313 | ++ nm_assert (base != NULL); |
3314 | ++ |
3315 | ++ dir = g_dir_open (dirname, 0, &err); |
3316 | ++ if (dir) { |
3317 | ++ const char *item; |
3318 | ++ NMIPAddress *addr; |
3319 | ++ gboolean ok; |
3320 | ++ |
3321 | ++ while ((item = g_dir_read_name (dir))) { |
3322 | ++ nm_auto_shvar_file_close shvarFile *parsed = NULL; |
3323 | ++ gs_free char *gateway = NULL; |
3324 | ++ gs_free char *device_value = NULL; |
3325 | ++ gs_free char *full_path = NULL; |
3326 | ++ const char *device; |
3327 | ++ const char *p; |
3328 | ++ |
3329 | ++ if (!utils_is_ifcfg_alias_file (item, base)) |
3330 | ++ continue; |
3331 | ++ |
3332 | ++ full_path = g_build_filename (dirname, item, NULL); |
3333 | ++ |
3334 | ++ p = strchr (item, ':'); |
3335 | ++ g_assert (p != NULL); /* we know this is true from utils_is_ifcfg_alias_file() */ |
3336 | ++ for (p++; *p; p++) { |
3337 | ++ if (!g_ascii_isalnum (*p) && *p != '_') |
3338 | ++ break; |
3339 | ++ } |
3340 | ++ if (*p) { |
3341 | ++ PARSE_WARNING ("ignoring alias file '%s' with invalid name", full_path); |
3342 | ++ continue; |
3343 | ++ } |
3344 | ++ |
3345 | ++ parsed = svOpenFile (full_path, &err); |
3346 | ++ if (!parsed) { |
3347 | ++ PARSE_WARNING ("couldn't parse alias file '%s': %s", full_path, err->message); |
3348 | ++ g_clear_error (&err); |
3349 | ++ continue; |
3350 | ++ } |
3351 | ++ |
3352 | ++ device = svGetValueStr (parsed, "DEVICE", &device_value); |
3353 | ++ if (!device) { |
3354 | ++ PARSE_WARNING ("alias file '%s' has no DEVICE", full_path); |
3355 | ++ continue; |
3356 | ++ } |
3357 | ++ /* We know that item starts with IFCFG_TAG from utils_is_ifcfg_alias_file() */ |
3358 | ++ if (strcmp (device, item + strlen (IFCFG_TAG)) != 0) { |
3359 | ++ PARSE_WARNING ("alias file '%s' has invalid DEVICE (%s) for filename", |
3360 | ++ full_path, device); |
3361 | ++ continue; |
3362 | ++ } |
3363 | ++ |
3364 | ++ addr = NULL; |
3365 | ++ ok = read_full_ip4_address (parsed, -1, base_addr, &addr, |
3366 | ++ read_defroute ? &gateway : NULL, |
3367 | ++ &err); |
3368 | ++ if (ok) { |
3369 | ++ nm_ip_address_set_attribute (addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL, g_variant_new_string (device)); |
3370 | ++ if (!nm_setting_ip_config_add_address (s_ip4, addr)) |
3371 | ++ PARSE_WARNING ("duplicate IP4 address in alias file %s", item); |
3372 | ++ if (nm_streq0 (nm_setting_ip_config_get_method (s_ip4), NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) |
3373 | ++ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL); |
3374 | ++ if (read_defroute) { |
3375 | ++ int i; |
3376 | ++ |
3377 | ++ if (gateway) { |
3378 | ++ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL); |
3379 | ++ read_defroute = FALSE; |
3380 | ++ } |
3381 | ++ i = svGetValueBoolean (parsed, "DEFROUTE", -1); |
3382 | ++ if (i != -1) { |
3383 | ++ g_object_set (s_ip4, |
3384 | ++ NM_SETTING_IP_CONFIG_NEVER_DEFAULT, (gboolean) !i, |
3385 | ++ NULL); |
3386 | ++ read_defroute = FALSE; |
3387 | ++ } |
3388 | ++ } |
3389 | ++ } else { |
3390 | ++ PARSE_WARNING ("error reading IP4 address from alias file '%s': %s", |
3391 | ++ full_path, err ? err->message : "no address"); |
3392 | ++ g_clear_error (&err); |
3393 | ++ } |
3394 | ++ nm_ip_address_unref (addr); |
3395 | ++ } |
3396 | ++ |
3397 | ++ g_dir_close (dir); |
3398 | ++ } else { |
3399 | ++ PARSE_WARNING ("can not read directory '%s': %s", dirname, err->message); |
3400 | ++ g_error_free (err); |
3401 | ++ } |
3402 | ++} |
3403 | ++ |
3404 | ++static NMSetting * |
3405 | ++make_ip6_setting (shvarFile *ifcfg, |
3406 | ++ shvarFile *network_ifcfg, |
3407 | ++ gboolean routes_read, |
3408 | ++ GError **error) |
3409 | ++{ |
3410 | ++ gs_unref_object NMSettingIPConfig *s_ip6 = NULL; |
3411 | ++ const char *v; |
3412 | ++ gs_free char *value = NULL; |
3413 | ++ gboolean ipv6init; |
3414 | ++ gboolean ipv6forwarding; |
3415 | ++ gboolean disabled; |
3416 | ++ gboolean dhcp6 = FALSE; |
3417 | ++ char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; |
3418 | ++ const char *ipv6addr, *ipv6addr_secondaries; |
3419 | ++ gs_free char *ipv6addr_to_free = NULL; |
3420 | ++ gs_free char *ipv6addr_secondaries_to_free = NULL; |
3421 | ++ gs_free const char **list = NULL; |
3422 | ++ const char *const *iter; |
3423 | ++ guint32 i; |
3424 | ++ int i_val; |
3425 | ++ GError *local = NULL; |
3426 | ++ int priority; |
3427 | ++ gboolean never_default = FALSE; |
3428 | ++ gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip; |
3429 | ++ NMSettingIP6ConfigPrivacy ip6_privacy_val; |
3430 | ++ guint32 route_table; |
3431 | ++ |
3432 | ++ s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); |
3433 | ++ |
3434 | ++ /* First check if IPV6_DEFROUTE is set for this device; IPV6_DEFROUTE has the |
3435 | ++ * opposite meaning from never-default. The default if IPV6_DEFROUTE is not |
3436 | ++ * specified is IPV6_DEFROUTE=yes which means that this connection can be used |
3437 | ++ * as a default route |
3438 | ++ */ |
3439 | ++ never_default = !svGetValueBoolean (ifcfg, "IPV6_DEFROUTE", TRUE); |
3440 | ++ |
3441 | ++ /* Then check if IPV6_DEFAULTGW or IPV6_DEFAULTDEV is specified; |
3442 | ++ * they are global and override IPV6_DEFROUTE |
3443 | ++ * When both are set, the device specified in IPV6_DEFAULTGW takes preference. |
3444 | ++ */ |
3445 | ++ if (network_ifcfg) { |
3446 | ++ const char *ipv6_defaultgw, *ipv6_defaultdev; |
3447 | ++ gs_free char *ipv6_defaultgw_to_free = NULL; |
3448 | ++ gs_free char *ipv6_defaultdev_to_free = NULL; |
3449 | ++ const char *default_dev = NULL; |
3450 | ++ |
3451 | ++ /* Get the connection ifcfg device name and the global default route device */ |
3452 | ++ nm_clear_g_free (&value); |
3453 | ++ v = svGetValueStr (ifcfg, "DEVICE", &value); |
3454 | ++ ipv6_defaultgw = svGetValueStr (network_ifcfg, "IPV6_DEFAULTGW", &ipv6_defaultgw_to_free); |
3455 | ++ ipv6_defaultdev = svGetValueStr (network_ifcfg, "IPV6_DEFAULTDEV", &ipv6_defaultdev_to_free); |
3456 | ++ |
3457 | ++ if (ipv6_defaultgw) { |
3458 | ++ default_dev = strchr (ipv6_defaultgw, '%'); |
3459 | ++ if (default_dev) |
3460 | ++ default_dev++; |
3461 | ++ } |
3462 | ++ if (!default_dev) |
3463 | ++ default_dev = ipv6_defaultdev; |
3464 | ++ |
3465 | ++ /* If there was a global default route device specified, then only connections |
3466 | ++ * for that device can be the default connection. |
3467 | ++ */ |
3468 | ++ if (default_dev && v) |
3469 | ++ never_default = !!strcmp (v, default_dev); |
3470 | ++ } |
3471 | ++ |
3472 | ++ /* Find out method property */ |
3473 | ++ /* Is IPV6 enabled? Set method to "ignored", when not enabled */ |
3474 | ++ disabled = svGetValueBoolean(ifcfg, "IPV6_DISABLED", FALSE); |
3475 | ++ nm_clear_g_free (&value); |
3476 | ++ v = svGetValueStr (ifcfg, "IPV6INIT", &value); |
3477 | ++ ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE); |
3478 | ++ if (!v) { |
3479 | ++ if (network_ifcfg) |
3480 | ++ ipv6init = svGetValueBoolean (network_ifcfg, "IPV6INIT", FALSE); |
3481 | ++ } |
3482 | ++ |
3483 | ++ if (disabled) |
3484 | ++ method = NM_SETTING_IP6_CONFIG_METHOD_DISABLED; |
3485 | ++ else if (!ipv6init) |
3486 | ++ method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; |
3487 | ++ else { |
3488 | ++ ipv6forwarding = svGetValueBoolean (ifcfg, "IPV6FORWARDING", FALSE); |
3489 | ++ nm_clear_g_free (&value); |
3490 | ++ v = svGetValueStr (ifcfg, "IPV6_AUTOCONF", &value); |
3491 | ++ dhcp6 = svGetValueBoolean (ifcfg, "DHCPV6C", FALSE); |
3492 | ++ |
3493 | ++ if (!g_strcmp0 (v, "shared")) |
3494 | ++ method = NM_SETTING_IP6_CONFIG_METHOD_SHARED; |
3495 | ++ else if (svParseBoolean (v, !ipv6forwarding)) |
3496 | ++ method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; |
3497 | ++ else if (dhcp6) |
3498 | ++ method = NM_SETTING_IP6_CONFIG_METHOD_DHCP; |
3499 | ++ else { |
3500 | ++ /* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */ |
3501 | ++ nm_clear_g_free (&value); |
3502 | ++ v = svGetValueStr (ifcfg, "IPV6ADDR", &value); |
3503 | ++ if (!v) { |
3504 | ++ nm_clear_g_free (&value); |
3505 | ++ v = svGetValueStr (ifcfg, "IPV6ADDR_SECONDARIES", &value); |
3506 | ++ } |
3507 | ++ |
3508 | ++ if (!v) |
3509 | ++ method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; |
3510 | ++ } |
3511 | ++ } |
3512 | ++ /* TODO - handle other methods */ |
3513 | ++ |
3514 | ++ /* Read IPv6 Privacy Extensions configuration */ |
3515 | ++ nm_clear_g_free (&value); |
3516 | ++ v = svGetValueStr (ifcfg, "IPV6_PRIVACY", &value); |
3517 | ++ if (v) { |
3518 | ++ ip6_privacy = svParseBoolean (v, FALSE); |
3519 | ++ if (!ip6_privacy) |
3520 | ++ ip6_privacy = (g_strcmp0 (v, "rfc4941") == 0) || |
3521 | ++ (g_strcmp0 (v, "rfc3041") == 0); |
3522 | ++ } |
3523 | ++ ip6_privacy_prefer_public_ip = svGetValueBoolean (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE); |
3524 | ++ ip6_privacy_val = v ? |
3525 | ++ (ip6_privacy ? |
3526 | ++ (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) : |
3527 | ++ NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) : |
3528 | ++ NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; |
3529 | ++ |
3530 | ++ /* the route table (policy routing) is ignored if we don't handle routes. */ |
3531 | ++ route_table = svGetValueInt64 (ifcfg, "IPV6_ROUTE_TABLE", 10, |
3532 | ++ 0, G_MAXUINT32, 0); |
3533 | ++ if ( route_table != 0 |
3534 | ++ && !routes_read) { |
3535 | ++ PARSE_WARNING ("'rule-' or 'rule6-' files are present; Policy routing (IPV6_ROUTE_TABLE) is ignored"); |
3536 | ++ route_table = 0; |
3537 | ++ } |
3538 | ++ |
3539 | ++ g_object_set (s_ip6, |
3540 | ++ NM_SETTING_IP_CONFIG_METHOD, method, |
3541 | ++ NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svGetValueBoolean (ifcfg, "IPV6_PEERDNS", TRUE), |
3542 | ++ NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svGetValueBoolean (ifcfg, "IPV6_PEERROUTES", TRUE), |
3543 | ++ NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default, |
3544 | ++ NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV6_FAILURE_FATAL", FALSE), |
3545 | ++ NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV6_ROUTE_METRIC", 10, |
3546 | ++ -1, G_MAXUINT32, -1), |
3547 | ++ NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) route_table, |
3548 | ++ NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val, |
3549 | ++ NULL); |
3550 | ++ |
3551 | ++ /* Don't bother to read IP, DNS and routes when IPv6 is disabled */ |
3552 | ++ if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, |
3553 | ++ NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) |
3554 | ++ return NM_SETTING (g_steal_pointer (&s_ip6)); |
3555 | ++ |
3556 | ++ nm_clear_g_free (&value); |
3557 | ++ v = svGetValueStr (ifcfg, "DHCPV6_DUID", &value); |
3558 | ++ if (v) |
3559 | ++ g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_DHCP_DUID, v, NULL); |
3560 | ++ |
3561 | ++ nm_clear_g_free (&value); |
3562 | ++ v = svGetValueStr (ifcfg, "DHCPV6_HOSTNAME", &value); |
3563 | ++ /* Use DHCP_HOSTNAME as fallback if it is in FQDN format and ipv6.method is |
3564 | ++ * auto or dhcp: this is required to support old ifcfg files |
3565 | ++ */ |
3566 | ++ if (!v && ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) |
3567 | ++ || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP))) { |
3568 | ++ nm_clear_g_free (&value); |
3569 | ++ v = svGetValueStr (ifcfg, "DHCP_HOSTNAME", &value); |
3570 | ++ if (v && !strchr (v, '.')) |
3571 | ++ v = NULL; |
3572 | ++ } |
3573 | ++ if (v) |
3574 | ++ g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, v, NULL); |
3575 | ++ |
3576 | ++ g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, |
3577 | ++ svGetValueBoolean (ifcfg, "DHCPV6_SEND_HOSTNAME", TRUE), NULL); |
3578 | ++ |
3579 | ++ /* Read static IP addresses. |
3580 | ++ * Read them even for AUTO and DHCP methods - in this case the addresses are |
3581 | ++ * added to the automatic ones. Note that this is not currently supported by |
3582 | ++ * the legacy 'network' service (ifup-eth). |
3583 | ++ */ |
3584 | ++ ipv6addr = svGetValueStr (ifcfg, "IPV6ADDR", &ipv6addr_to_free); |
3585 | ++ ipv6addr_secondaries = svGetValueStr (ifcfg, "IPV6ADDR_SECONDARIES", &ipv6addr_secondaries_to_free); |
3586 | ++ |
3587 | ++ nm_clear_g_free (&value); |
3588 | ++ value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL, |
3589 | ++ ipv6addr ?: "", |
3590 | ++ ipv6addr_secondaries ?: "", |
3591 | ++ NULL); |
3592 | ++ |
3593 | ++ list = nm_utils_strsplit_set (value, " "); |
3594 | ++ for (iter = list, i = 0; iter && *iter; iter++, i++) { |
3595 | ++ NMIPAddress *addr = NULL; |
3596 | ++ |
3597 | ++ if (!parse_full_ip6_address (ifcfg, *iter, i, &addr, error)) |
3598 | ++ return NULL; |
3599 | ++ |
3600 | ++ if (!nm_setting_ip_config_add_address (s_ip6, addr)) |
3601 | ++ PARSE_WARNING ("duplicate IP6 address"); |
3602 | ++ nm_ip_address_unref (addr); |
3603 | ++ } |
3604 | ++ |
3605 | ++ /* Gateway */ |
3606 | ++ if (nm_setting_ip_config_get_num_addresses (s_ip6)) { |
3607 | ++ nm_clear_g_free (&value); |
3608 | ++ v = svGetValueStr (ifcfg, "IPV6_DEFAULTGW", &value); |
3609 | ++ if (!v) { |
3610 | ++ /* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */ |
3611 | ++ if (network_ifcfg) { |
3612 | ++ nm_clear_g_free (&value); |
3613 | ++ v = svGetValueStr (network_ifcfg, "IPV6_DEFAULTGW", &value); |
3614 | ++ } |
3615 | ++ } |
3616 | ++ if (v) { |
3617 | ++ char *ptr; |
3618 | ++ if ((ptr = strchr (v, '%')) != NULL) |
3619 | ++ *ptr = '\0'; /* remove %interface prefix if present */ |
3620 | ++ if (!nm_utils_ipaddr_valid (AF_INET6, v)) { |
3621 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
3622 | ++ "Invalid IP6 address '%s'", v); |
3623 | ++ return NULL; |
3624 | ++ } |
3625 | ++ |
3626 | ++ g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, v, NULL); |
3627 | ++ } |
3628 | ++ } |
3629 | ++ |
3630 | ++ i_val = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; |
3631 | ++ if (!svGetValueEnum (ifcfg, "IPV6_ADDR_GEN_MODE", |
3632 | ++ nm_setting_ip6_config_addr_gen_mode_get_type (), |
3633 | ++ &i_val, &local)) { |
3634 | ++ PARSE_WARNING ("%s", local->message); |
3635 | ++ g_clear_error (&local); |
3636 | ++ } |
3637 | ++ g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, i_val, NULL); |
3638 | ++ |
3639 | ++ /* IPv6 tokenized interface identifier */ |
3640 | ++ nm_clear_g_free (&value); |
3641 | ++ v = svGetValueStr (ifcfg, "IPV6_TOKEN", &value); |
3642 | ++ if (v) |
3643 | ++ g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, v, NULL); |
3644 | ++ |
3645 | ++ /* DNS servers |
3646 | ++ * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting()) |
3647 | ++ */ |
3648 | ++ for (i = 1; i <= 10; i++) { |
3649 | ++ char tag[256]; |
3650 | ++ |
3651 | ++ numbered_tag (tag, "DNS", i); |
3652 | ++ nm_clear_g_free (&value); |
3653 | ++ v = svGetValueStr (ifcfg, tag, &value); |
3654 | ++ if (!v) { |
3655 | ++ /* all done */ |
3656 | ++ break; |
3657 | ++ } |
3658 | ++ |
3659 | ++ if (nm_utils_ipaddr_valid (AF_INET6, v)) { |
3660 | ++ if (!nm_setting_ip_config_add_dns (s_ip6, v)) |
3661 | ++ PARSE_WARNING ("duplicate DNS server %s", tag); |
3662 | ++ } else if (nm_utils_ipaddr_valid (AF_INET, v)) { |
3663 | ++ /* Ignore IPv4 addresses */ |
3664 | ++ } else { |
3665 | ++ PARSE_WARNING ("invalid DNS server address %s", v); |
3666 | ++ return NULL; |
3667 | ++ } |
3668 | ++ } |
3669 | ++ |
3670 | ++ if (!routes_read) { |
3671 | ++ /* NOP */ |
3672 | ++ } else { |
3673 | ++ gs_free char *route6_path = NULL; |
3674 | ++ |
3675 | ++ /* Read static routes from route6-<interface> file */ |
3676 | ++ route6_path = utils_get_route6_path (svFileGetName (ifcfg)); |
3677 | ++ if (!read_route_file (AF_INET6, route6_path, s_ip6, error)) |
3678 | ++ return NULL; |
3679 | ++ } |
3680 | ++ |
3681 | ++ /* DNS searches */ |
3682 | ++ nm_clear_g_free (&value); |
3683 | ++ v = svGetValueStr (ifcfg, "IPV6_DOMAIN", &value); |
3684 | ++ if (v) { |
3685 | ++ gs_free const char **searches = NULL; |
3686 | ++ |
3687 | ++ searches = nm_utils_strsplit_set (v, " "); |
3688 | ++ if (searches) { |
3689 | ++ for (iter = searches; *iter; iter++) { |
3690 | ++ if (!nm_setting_ip_config_add_dns_search (s_ip6, *iter)) |
3691 | ++ PARSE_WARNING ("duplicate DNS domain '%s'", *iter); |
3692 | ++ } |
3693 | ++ } |
3694 | ++ } |
3695 | ++ |
3696 | ++ /* DNS options */ |
3697 | ++ nm_clear_g_free (&value); |
3698 | ++ parse_dns_options (s_ip6, svGetValue (ifcfg, "IPV6_RES_OPTIONS", &value)); |
3699 | ++ |
3700 | ++ /* DNS priority */ |
3701 | ++ priority = svGetValueInt64 (ifcfg, "IPV6_DNS_PRIORITY", 10, G_MININT32, G_MAXINT32, 0); |
3702 | ++ g_object_set (s_ip6, |
3703 | ++ NM_SETTING_IP_CONFIG_DNS_PRIORITY, |
3704 | ++ priority, |
3705 | ++ NULL); |
3706 | ++ |
3707 | ++ return NM_SETTING (g_steal_pointer (&s_ip6)); |
3708 | ++} |
3709 | ++ |
3710 | ++static NMSetting * |
3711 | ++make_sriov_setting (shvarFile *ifcfg) |
3712 | ++{ |
3713 | ++ gs_unref_hashtable GHashTable *keys = NULL; |
3714 | ++ gs_unref_ptrarray GPtrArray *vfs = NULL; |
3715 | ++ int autoprobe_drivers; |
3716 | ++ NMSettingSriov *s_sriov; |
3717 | ++ gint64 total_vfs; |
3718 | ++ |
3719 | ++ |
3720 | ++ total_vfs = svGetValueInt64 (ifcfg, "SRIOV_TOTAL_VFS", 10, 0, G_MAXUINT32, -1); |
3721 | ++ |
3722 | ++ autoprobe_drivers = svGetValueInt64 (ifcfg, |
3723 | ++ "SRIOV_AUTOPROBE_DRIVERS", |
3724 | ++ 10, |
3725 | ++ NM_TERNARY_DEFAULT, |
3726 | ++ NM_TERNARY_TRUE, |
3727 | ++ -2); |
3728 | ++ |
3729 | ++ keys = svGetKeys (ifcfg, SV_KEY_TYPE_SRIOV_VF); |
3730 | ++ if (keys) { |
3731 | ++ GHashTableIter iter; |
3732 | ++ const char *key; |
3733 | ++ |
3734 | ++ g_hash_table_iter_init (&iter, keys); |
3735 | ++ while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) { |
3736 | ++ gs_free_error GError *error = NULL; |
3737 | ++ gs_free char *value_to_free = NULL; |
3738 | ++ const char *value; |
3739 | ++ NMSriovVF *vf; |
3740 | ++ |
3741 | ++ nm_assert (g_str_has_prefix (key, "SRIOV_VF")); |
3742 | ++ |
3743 | ++ value = svGetValue (ifcfg, key, &value_to_free); |
3744 | ++ if (!value) |
3745 | ++ continue; |
3746 | ++ |
3747 | ++ key += NM_STRLEN ("SRIOV_VF"); |
3748 | ++ |
3749 | ++ vf = _nm_utils_sriov_vf_from_strparts (key, value, TRUE, &error); |
3750 | ++ if (!vf) { |
3751 | ++ PARSE_WARNING ("ignoring invalid SR-IOV VF '%s %s': %s", |
3752 | ++ key, value, error->message); |
3753 | ++ continue; |
3754 | ++ } |
3755 | ++ if (!vfs) |
3756 | ++ vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref); |
3757 | ++ g_ptr_array_add (vfs, vf); |
3758 | ++ } |
3759 | ++ } |
3760 | ++ |
3761 | ++ /* Create the setting when at least one key is set */ |
3762 | ++ if ( total_vfs < 0 |
3763 | ++ && !vfs |
3764 | ++ && autoprobe_drivers < NM_TERNARY_DEFAULT) |
3765 | ++ return NULL; |
3766 | ++ |
3767 | ++ s_sriov = (NMSettingSriov *) nm_setting_sriov_new (); |
3768 | ++ |
3769 | ++ autoprobe_drivers = NM_MAX (autoprobe_drivers, NM_TERNARY_DEFAULT); |
3770 | ++ total_vfs = NM_MAX (total_vfs, 0); |
3771 | ++ |
3772 | ++ g_object_set (s_sriov, |
3773 | ++ NM_SETTING_SRIOV_TOTAL_VFS, (guint) total_vfs, |
3774 | ++ NM_SETTING_SRIOV_VFS, vfs, |
3775 | ++ NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, autoprobe_drivers, |
3776 | ++ NULL); |
3777 | ++ |
3778 | ++ return (NMSetting *) s_sriov; |
3779 | ++} |
3780 | ++ |
3781 | ++static NMSetting * |
3782 | ++make_tc_setting (shvarFile *ifcfg) |
3783 | ++{ |
3784 | ++ NMSettingTCConfig *s_tc = NULL; |
3785 | ++ char tag[256]; |
3786 | ++ int i; |
3787 | ++ |
3788 | ++ s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new (); |
3789 | ++ |
3790 | ++ for (i = 1;; i++) { |
3791 | ++ NMTCQdisc *qdisc = NULL; |
3792 | ++ gs_free char *value_to_free = NULL; |
3793 | ++ const char *value = NULL; |
3794 | ++ GError *local = NULL; |
3795 | ++ |
3796 | ++ value = svGetValueStr (ifcfg, numbered_tag (tag, "QDISC", i), &value_to_free); |
3797 | ++ if (!value) |
3798 | ++ break; |
3799 | ++ |
3800 | ++ qdisc = nm_utils_tc_qdisc_from_str (value, &local); |
3801 | ++ if (!qdisc) { |
3802 | ++ PARSE_WARNING ("ignoring bad tc qdisc: '%s': %s", value, local->message); |
3803 | ++ continue; |
3804 | ++ } |
3805 | ++ |
3806 | ++ if (!nm_setting_tc_config_add_qdisc (s_tc, qdisc)) |
3807 | ++ PARSE_WARNING ("duplicate tc qdisc"); |
3808 | ++ |
3809 | ++ nm_tc_qdisc_unref (qdisc); |
3810 | ++ } |
3811 | ++ |
3812 | ++ for (i = 1;; i++) { |
3813 | ++ NMTCTfilter *tfilter = NULL; |
3814 | ++ gs_free char *value_to_free = NULL; |
3815 | ++ const char *value = NULL; |
3816 | ++ GError *local = NULL; |
3817 | ++ |
3818 | ++ value = svGetValueStr (ifcfg, numbered_tag (tag, "FILTER", i), &value_to_free); |
3819 | ++ if (!value) |
3820 | ++ break; |
3821 | ++ |
3822 | ++ tfilter = nm_utils_tc_tfilter_from_str (value, &local); |
3823 | ++ if (!tfilter) { |
3824 | ++ PARSE_WARNING ("ignoring bad tc filter: '%s': %s", value, local->message); |
3825 | ++ continue; |
3826 | ++ } |
3827 | ++ |
3828 | ++ if (!nm_setting_tc_config_add_tfilter (s_tc, tfilter)) |
3829 | ++ PARSE_WARNING ("duplicate tc filter"); |
3830 | ++ |
3831 | ++ nm_tc_tfilter_unref (tfilter); |
3832 | ++ } |
3833 | ++ |
3834 | ++ if ( nm_setting_tc_config_get_num_qdiscs (s_tc) > 0 |
3835 | ++ || nm_setting_tc_config_get_num_tfilters (s_tc) > 0) |
3836 | ++ return NM_SETTING (s_tc); |
3837 | ++ |
3838 | ++ g_object_unref (s_tc); |
3839 | ++ return NULL; |
3840 | ++} |
3841 | ++ |
3842 | ++typedef struct { |
3843 | ++ const char *enable_key; |
3844 | ++ const char *advertise_key; |
3845 | ++ const char *willing_key; |
3846 | ++ const char *flags_prop; |
3847 | ++} DcbFlagsProperty; |
3848 | ++ |
3849 | ++enum { |
3850 | ++ DCB_APP_FCOE_FLAGS = 0, |
3851 | ++ DCB_APP_ISCSI_FLAGS = 1, |
3852 | ++ DCB_APP_FIP_FLAGS = 2, |
3853 | ++ DCB_PFC_FLAGS = 3, |
3854 | ++ DCB_PG_FLAGS = 4, |
3855 | ++}; |
3856 | ++ |
3857 | ++static DcbFlagsProperty dcb_flags_props[] = { |
3858 | ++ { KEY_DCB_APP_FCOE_ENABLE, KEY_DCB_APP_FCOE_ADVERTISE, KEY_DCB_APP_FCOE_WILLING, NM_SETTING_DCB_APP_FCOE_FLAGS }, |
3859 | ++ { KEY_DCB_APP_ISCSI_ENABLE, KEY_DCB_APP_ISCSI_ADVERTISE, KEY_DCB_APP_ISCSI_WILLING, NM_SETTING_DCB_APP_ISCSI_FLAGS }, |
3860 | ++ { KEY_DCB_APP_FIP_ENABLE, KEY_DCB_APP_FIP_ADVERTISE, KEY_DCB_APP_FIP_WILLING, NM_SETTING_DCB_APP_FIP_FLAGS }, |
3861 | ++ { KEY_DCB_PFC_ENABLE, KEY_DCB_PFC_ADVERTISE, KEY_DCB_PFC_WILLING, NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS }, |
3862 | ++ { KEY_DCB_PG_ENABLE, KEY_DCB_PG_ADVERTISE, KEY_DCB_PG_WILLING, NM_SETTING_DCB_PRIORITY_GROUP_FLAGS }, |
3863 | ++ { NULL }, |
3864 | ++}; |
3865 | ++ |
3866 | ++static NMSettingDcbFlags |
3867 | ++read_dcb_flags (shvarFile *ifcfg, DcbFlagsProperty *property) |
3868 | ++{ |
3869 | ++ NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; |
3870 | ++ |
3871 | ++ if (svGetValueBoolean (ifcfg, property->enable_key, FALSE)) |
3872 | ++ flags |= NM_SETTING_DCB_FLAG_ENABLE; |
3873 | ++ if (svGetValueBoolean (ifcfg, property->advertise_key, FALSE)) |
3874 | ++ flags |= NM_SETTING_DCB_FLAG_ADVERTISE; |
3875 | ++ if (svGetValueBoolean (ifcfg, property->willing_key, FALSE)) |
3876 | ++ flags |= NM_SETTING_DCB_FLAG_WILLING; |
3877 | ++ |
3878 | ++ return flags; |
3879 | ++} |
3880 | ++ |
3881 | ++static gboolean |
3882 | ++read_dcb_app (shvarFile *ifcfg, |
3883 | ++ NMSettingDcb *s_dcb, |
3884 | ++ const char *app, |
3885 | ++ DcbFlagsProperty *flags_prop, |
3886 | ++ const char *priority_prop, |
3887 | ++ GError **error) |
3888 | ++{ |
3889 | ++ NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; |
3890 | ++ gs_free char *value = NULL; |
3891 | ++ const char *v; |
3892 | ++ gboolean success = TRUE; |
3893 | ++ int priority = -1; |
3894 | ++ char key[255]; |
3895 | ++ |
3896 | ++ flags = read_dcb_flags (ifcfg, flags_prop); |
3897 | ++ |
3898 | ++ /* Priority */ |
3899 | ++ nm_sprintf_buf (key, "DCB_APP_%s_PRIORITY", app); |
3900 | ++ v = svGetValueStr (ifcfg, key, &value); |
3901 | ++ if (v) { |
3902 | ++ priority = _nm_utils_ascii_str_to_int64 (v, 0, 0, 7, -1); |
3903 | ++ if (priority < 0) { |
3904 | ++ success = FALSE; |
3905 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
3906 | ++ "Invalid %s value '%s' (expected 0 - 7)", |
3907 | ++ key, v); |
3908 | ++ } |
3909 | ++ |
3910 | ++ if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) |
3911 | ++ PARSE_WARNING ("ignoring DCB %s priority; app not enabled", app); |
3912 | ++ } |
3913 | ++ |
3914 | ++ if (success) { |
3915 | ++ g_object_set (G_OBJECT (s_dcb), |
3916 | ++ flags_prop->flags_prop, flags, |
3917 | ++ priority_prop, (guint) priority, |
3918 | ++ NULL); |
3919 | ++ } |
3920 | ++ |
3921 | ++ return success; |
3922 | ++} |
3923 | ++ |
3924 | ++typedef void (*DcbSetBoolFunc) (NMSettingDcb *, guint, gboolean); |
3925 | ++ |
3926 | ++static gboolean |
3927 | ++read_dcb_bool_array (shvarFile *ifcfg, |
3928 | ++ NMSettingDcb *s_dcb, |
3929 | ++ NMSettingDcbFlags flags, |
3930 | ++ const char *prop, |
3931 | ++ const char *desc, |
3932 | ++ DcbSetBoolFunc set_func, |
3933 | ++ GError **error) |
3934 | ++{ |
3935 | ++ gs_free char *value = NULL; |
3936 | ++ const char *v; |
3937 | ++ guint i; |
3938 | ++ |
3939 | ++ v = svGetValueStr (ifcfg, prop, &value); |
3940 | ++ if (!v) |
3941 | ++ return TRUE; |
3942 | ++ |
3943 | ++ if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { |
3944 | ++ PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc); |
3945 | ++ return TRUE; |
3946 | ++ } |
3947 | ++ |
3948 | ++ if (strlen (v) != 8) { |
3949 | ++ PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, v); |
3950 | ++ g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
3951 | ++ "boolean array must be 8 characters"); |
3952 | ++ return FALSE; |
3953 | ++ } |
3954 | ++ |
3955 | ++ /* All characters must be either 0 or 1 */ |
3956 | ++ for (i = 0; i < 8; i++) { |
3957 | ++ if (v[i] != '0' && v[i] != '1') { |
3958 | ++ PARSE_WARNING ("invalid %s value '%s': not all 0s and 1s", prop, v); |
3959 | ++ g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
3960 | ++ "invalid boolean digit"); |
3961 | ++ return FALSE; |
3962 | ++ } |
3963 | ++ set_func (s_dcb, i, (v[i] == '1')); |
3964 | ++ } |
3965 | ++ return TRUE; |
3966 | ++} |
3967 | ++ |
3968 | ++typedef void (*DcbSetUintFunc) (NMSettingDcb *, guint, guint); |
3969 | ++ |
3970 | ++static gboolean |
3971 | ++read_dcb_uint_array (shvarFile *ifcfg, |
3972 | ++ NMSettingDcb *s_dcb, |
3973 | ++ NMSettingDcbFlags flags, |
3974 | ++ const char *prop, |
3975 | ++ const char *desc, |
3976 | ++ gboolean f_allowed, |
3977 | ++ DcbSetUintFunc set_func, |
3978 | ++ GError **error) |
3979 | ++{ |
3980 | ++ gs_free char *val = NULL; |
3981 | ++ guint i; |
3982 | ++ |
3983 | ++ val = svGetValueStr_cp (ifcfg, prop); |
3984 | ++ if (!val) |
3985 | ++ return TRUE; |
3986 | ++ |
3987 | ++ if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { |
3988 | ++ PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc); |
3989 | ++ return TRUE; |
3990 | ++ } |
3991 | ++ |
3992 | ++ if (strlen (val) != 8) { |
3993 | ++ PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val); |
3994 | ++ g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
3995 | ++ "uint array must be 8 characters"); |
3996 | ++ return FALSE; |
3997 | ++ } |
3998 | ++ |
3999 | ++ /* All characters must be either 0 - 7 or (optionally) f */ |
4000 | ++ for (i = 0; i < 8; i++) { |
4001 | ++ if (val[i] >= '0' && val[i] <= '7') |
4002 | ++ set_func (s_dcb, i, val[i] - '0'); |
4003 | ++ else if (f_allowed && (val[i] == 'f' || val[i] == 'F')) |
4004 | ++ set_func (s_dcb, i, 15); |
4005 | ++ else { |
4006 | ++ PARSE_WARNING ("invalid %s value '%s': not 0 - 7%s", |
4007 | ++ prop, val, f_allowed ? " or 'f'" : ""); |
4008 | ++ g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4009 | ++ "invalid uint digit"); |
4010 | ++ return FALSE; |
4011 | ++ } |
4012 | ++ } |
4013 | ++ |
4014 | ++ return TRUE; |
4015 | ++} |
4016 | ++ |
4017 | ++static gboolean |
4018 | ++read_dcb_percent_array (shvarFile *ifcfg, |
4019 | ++ NMSettingDcb *s_dcb, |
4020 | ++ NMSettingDcbFlags flags, |
4021 | ++ const char *prop, |
4022 | ++ const char *desc, |
4023 | ++ gboolean sum_pct, |
4024 | ++ DcbSetUintFunc set_func, |
4025 | ++ GError **error) |
4026 | ++{ |
4027 | ++ gs_free char *val = NULL; |
4028 | ++ gs_free const char **split = NULL; |
4029 | ++ const char *const *iter; |
4030 | ++ guint i, sum = 0; |
4031 | ++ |
4032 | ++ val = svGetValueStr_cp (ifcfg, prop); |
4033 | ++ if (!val) |
4034 | ++ return TRUE; |
4035 | ++ |
4036 | ++ if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { |
4037 | ++ PARSE_WARNING ("ignoring %s; %s is not enabled", prop, desc); |
4038 | ++ return TRUE; |
4039 | ++ } |
4040 | ++ |
4041 | ++ split = nm_utils_strsplit_set (val, ","); |
4042 | ++ if (NM_PTRARRAY_LEN (split) != 8) { |
4043 | ++ PARSE_WARNING ("invalid %s percentage list value '%s'", prop, val); |
4044 | ++ g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4045 | ++ "percent array must be 8 elements"); |
4046 | ++ return FALSE; |
4047 | ++ } |
4048 | ++ |
4049 | ++ for (iter = split, i = 0; iter && *iter; iter++, i++) { |
4050 | ++ int tmp; |
4051 | ++ |
4052 | ++ tmp = _nm_utils_ascii_str_to_int64 (*iter, 0, 0, 100, -1); |
4053 | ++ if (tmp < 0) { |
4054 | ++ PARSE_WARNING ("invalid %s percentage value '%s'", prop, *iter); |
4055 | ++ g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4056 | ++ "invalid percent element"); |
4057 | ++ return FALSE; |
4058 | ++ } |
4059 | ++ set_func (s_dcb, i, (guint) tmp); |
4060 | ++ sum += (guint) tmp; |
4061 | ++ } |
4062 | ++ |
4063 | ++ if (sum_pct && (sum != 100)) { |
4064 | ++ PARSE_WARNING ("%s percentages do not equal 100%%", prop); |
4065 | ++ g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4066 | ++ "invalid percentage sum"); |
4067 | ++ return FALSE; |
4068 | ++ } |
4069 | ++ |
4070 | ++ return TRUE; |
4071 | ++} |
4072 | ++ |
4073 | ++static gboolean |
4074 | ++make_dcb_setting (shvarFile *ifcfg, |
4075 | ++ NMSetting **out_setting, |
4076 | ++ GError **error) |
4077 | ++{ |
4078 | ++ gs_unref_object NMSettingDcb *s_dcb = NULL; |
4079 | ++ gboolean dcb_on; |
4080 | ++ NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; |
4081 | ++ |
4082 | ++ g_return_val_if_fail (out_setting != NULL, FALSE); |
4083 | ++ |
4084 | ++ dcb_on = !!svGetValueBoolean (ifcfg, "DCB", FALSE); |
4085 | ++ if (!dcb_on) |
4086 | ++ return TRUE; |
4087 | ++ |
4088 | ++ s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); |
4089 | ++ |
4090 | ++ /* FCOE */ |
4091 | ++ if (!read_dcb_app (ifcfg, s_dcb, "FCOE", |
4092 | ++ &dcb_flags_props[DCB_APP_FCOE_FLAGS], |
4093 | ++ NM_SETTING_DCB_APP_FCOE_PRIORITY, |
4094 | ++ error)) { |
4095 | ++ return FALSE; |
4096 | ++ } |
4097 | ++ if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) { |
4098 | ++ gs_free char *val = NULL; |
4099 | ++ |
4100 | ++ val = svGetValueStr_cp (ifcfg, KEY_DCB_APP_FCOE_MODE); |
4101 | ++ if (val) { |
4102 | ++ if (NM_IN_STRSET (val, NM_SETTING_DCB_FCOE_MODE_FABRIC, |
4103 | ++ NM_SETTING_DCB_FCOE_MODE_VN2VN)) |
4104 | ++ g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_FCOE_MODE, val, NULL); |
4105 | ++ else { |
4106 | ++ PARSE_WARNING ("invalid FCoE mode '%s'", val); |
4107 | ++ g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4108 | ++ "invalid FCoE mode"); |
4109 | ++ return FALSE; |
4110 | ++ } |
4111 | ++ } |
4112 | ++ } |
4113 | ++ |
4114 | ++ /* iSCSI */ |
4115 | ++ if (!read_dcb_app (ifcfg, s_dcb, "ISCSI", |
4116 | ++ &dcb_flags_props[DCB_APP_ISCSI_FLAGS], |
4117 | ++ NM_SETTING_DCB_APP_ISCSI_PRIORITY, |
4118 | ++ error)) { |
4119 | ++ return FALSE; |
4120 | ++ } |
4121 | ++ |
4122 | ++ /* FIP */ |
4123 | ++ if (!read_dcb_app (ifcfg, s_dcb, "FIP", |
4124 | ++ &dcb_flags_props[DCB_APP_FIP_FLAGS], |
4125 | ++ NM_SETTING_DCB_APP_FIP_PRIORITY, |
4126 | ++ error)) { |
4127 | ++ return FALSE; |
4128 | ++ } |
4129 | ++ |
4130 | ++ /* Priority Flow Control */ |
4131 | ++ flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PFC_FLAGS]); |
4132 | ++ g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, flags, NULL); |
4133 | ++ |
4134 | ++ if (!read_dcb_bool_array (ifcfg, |
4135 | ++ s_dcb, |
4136 | ++ flags, |
4137 | ++ KEY_DCB_PFC_UP, |
4138 | ++ "PFC", |
4139 | ++ nm_setting_dcb_set_priority_flow_control, |
4140 | ++ error)) { |
4141 | ++ return FALSE; |
4142 | ++ } |
4143 | ++ |
4144 | ++ /* Priority Groups */ |
4145 | ++ flags = read_dcb_flags (ifcfg, &dcb_flags_props[DCB_PG_FLAGS]); |
4146 | ++ g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, flags, NULL); |
4147 | ++ |
4148 | ++ if (!read_dcb_uint_array (ifcfg, |
4149 | ++ s_dcb, |
4150 | ++ flags, |
4151 | ++ KEY_DCB_PG_ID, |
4152 | ++ "PGID", |
4153 | ++ TRUE, |
4154 | ++ nm_setting_dcb_set_priority_group_id, |
4155 | ++ error)) { |
4156 | ++ return FALSE; |
4157 | ++ } |
4158 | ++ |
4159 | ++ /* Group bandwidth */ |
4160 | ++ if (!read_dcb_percent_array (ifcfg, |
4161 | ++ s_dcb, |
4162 | ++ flags, |
4163 | ++ KEY_DCB_PG_PCT, |
4164 | ++ "PGPCT", |
4165 | ++ TRUE, |
4166 | ++ nm_setting_dcb_set_priority_group_bandwidth, |
4167 | ++ error)) { |
4168 | ++ return FALSE; |
4169 | ++ } |
4170 | ++ |
4171 | ++ /* Priority bandwidth */ |
4172 | ++ if (!read_dcb_percent_array (ifcfg, |
4173 | ++ s_dcb, |
4174 | ++ flags, |
4175 | ++ KEY_DCB_PG_UPPCT, |
4176 | ++ "UPPCT", |
4177 | ++ FALSE, |
4178 | ++ nm_setting_dcb_set_priority_bandwidth, |
4179 | ++ error)) { |
4180 | ++ return FALSE; |
4181 | ++ } |
4182 | ++ |
4183 | ++ /* Strict Bandwidth */ |
4184 | ++ if (!read_dcb_bool_array (ifcfg, |
4185 | ++ s_dcb, |
4186 | ++ flags, |
4187 | ++ KEY_DCB_PG_STRICT, |
4188 | ++ "STRICT", |
4189 | ++ nm_setting_dcb_set_priority_strict_bandwidth, |
4190 | ++ error)) { |
4191 | ++ return FALSE; |
4192 | ++ } |
4193 | ++ |
4194 | ++ if (!read_dcb_uint_array (ifcfg, |
4195 | ++ s_dcb, |
4196 | ++ flags, |
4197 | ++ KEY_DCB_PG_UP2TC, |
4198 | ++ "UP2TC", |
4199 | ++ FALSE, |
4200 | ++ nm_setting_dcb_set_priority_traffic_class, |
4201 | ++ error)) { |
4202 | ++ return FALSE; |
4203 | ++ } |
4204 | ++ |
4205 | ++ *out_setting = NM_SETTING (g_steal_pointer (&s_dcb)); |
4206 | ++ return TRUE; |
4207 | ++} |
4208 | ++ |
4209 | ++static gboolean |
4210 | ++add_one_wep_key (shvarFile *ifcfg, |
4211 | ++ const char *shvar_key, |
4212 | ++ guint8 key_idx, |
4213 | ++ gboolean passphrase, |
4214 | ++ NMSettingWirelessSecurity *s_wsec, |
4215 | ++ GError **error) |
4216 | ++{ |
4217 | ++ gs_free char *value_free = NULL; |
4218 | ++ const char *value; |
4219 | ++ const char *key = NULL; |
4220 | ++ |
4221 | ++ g_return_val_if_fail (ifcfg != NULL, FALSE); |
4222 | ++ g_return_val_if_fail (shvar_key != NULL, FALSE); |
4223 | ++ g_return_val_if_fail (key_idx <= 3, FALSE); |
4224 | ++ g_return_val_if_fail (s_wsec != NULL, FALSE); |
4225 | ++ |
4226 | ++ value = svGetValueStr (ifcfg, shvar_key, &value_free); |
4227 | ++ if (!value) |
4228 | ++ return TRUE; |
4229 | ++ |
4230 | ++ /* Validate keys */ |
4231 | ++ if (passphrase) { |
4232 | ++ if (value[0] && strlen (value) < 64) |
4233 | ++ key = value; |
4234 | ++ } else { |
4235 | ++ if (NM_IN_SET (strlen (value), 10, 26)) { |
4236 | ++ /* Hexadecimal WEP key */ |
4237 | ++ if (NM_STRCHAR_ANY (value, ch, !g_ascii_isxdigit (ch))) { |
4238 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4239 | ++ "Invalid hexadecimal WEP key."); |
4240 | ++ return FALSE; |
4241 | ++ } |
4242 | ++ key = value; |
4243 | ++ } else if ( !strncmp (value, "s:", 2) |
4244 | ++ && NM_IN_SET (strlen (value), 7, 15)) { |
4245 | ++ /* ASCII key */ |
4246 | ++ if (NM_STRCHAR_ANY (value + 2, ch, !g_ascii_isprint (ch))) { |
4247 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4248 | ++ "Invalid ASCII WEP key."); |
4249 | ++ return FALSE; |
4250 | ++ } |
4251 | ++ |
4252 | ++ /* Remove 's:' prefix. |
4253 | ++ * Don't convert to hex string. wpa_supplicant takes 'wep_key0' option over D-Bus as byte array |
4254 | ++ * and converts it to hex string itself. Even though we convert hex string keys into a bin string |
4255 | ++ * before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly, |
4256 | ++ * ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users. |
4257 | ++ */ |
4258 | ++ key = value + 2; |
4259 | ++ } |
4260 | ++ } |
4261 | ++ |
4262 | ++ if (!key) { |
4263 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4264 | ++ "Invalid WEP key length."); |
4265 | ++ return FALSE; |
4266 | ++ } |
4267 | ++ |
4268 | ++ nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); |
4269 | ++ return TRUE; |
4270 | ++} |
4271 | ++ |
4272 | ++static gboolean |
4273 | ++read_wep_keys (shvarFile *ifcfg, |
4274 | ++ NMWepKeyType key_type, |
4275 | ++ guint8 def_idx, |
4276 | ++ NMSettingWirelessSecurity *s_wsec, |
4277 | ++ GError **error) |
4278 | ++{ |
4279 | ++ if (key_type != NM_WEP_KEY_TYPE_PASSPHRASE) { |
4280 | ++ if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error)) |
4281 | ++ return FALSE; |
4282 | ++ if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error)) |
4283 | ++ return FALSE; |
4284 | ++ if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error)) |
4285 | ++ return FALSE; |
4286 | ++ if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error)) |
4287 | ++ return FALSE; |
4288 | ++ if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error)) |
4289 | ++ return FALSE; |
4290 | ++ } |
4291 | ++ |
4292 | ++ if (key_type != NM_WEP_KEY_TYPE_KEY) { |
4293 | ++ if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error)) |
4294 | ++ return FALSE; |
4295 | ++ if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error)) |
4296 | ++ return FALSE; |
4297 | ++ if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error)) |
4298 | ++ return FALSE; |
4299 | ++ if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error)) |
4300 | ++ return FALSE; |
4301 | ++ } |
4302 | ++ |
4303 | ++ return TRUE; |
4304 | ++} |
4305 | ++ |
4306 | ++static NMSetting * |
4307 | ++make_wep_setting (shvarFile *ifcfg, |
4308 | ++ const char *file, |
4309 | ++ GError **error) |
4310 | ++{ |
4311 | ++ gs_unref_object NMSettingWirelessSecurity *s_wsec = NULL; |
4312 | ++ gs_free char *value = NULL; |
4313 | ++ shvarFile *keys_ifcfg = NULL; |
4314 | ++ int default_key_idx = 0; |
4315 | ++ gboolean has_default_key = FALSE; |
4316 | ++ NMSettingSecretFlags key_flags; |
4317 | ++ |
4318 | ++ s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); |
4319 | ++ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL); |
4320 | ++ |
4321 | ++ value = svGetValueStr_cp (ifcfg, "DEFAULTKEY"); |
4322 | ++ if (value) { |
4323 | ++ default_key_idx = _nm_utils_ascii_str_to_int64 (value, 0, 1, 4, 0); |
4324 | ++ if (default_key_idx == 0) { |
4325 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4326 | ++ "Invalid default WEP key '%s'", value); |
4327 | ++ return NULL; |
4328 | ++ } |
4329 | ++ has_default_key = TRUE; |
4330 | ++ default_key_idx--; /* convert to [0...3] */ |
4331 | ++ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, (guint) default_key_idx, NULL); |
4332 | ++ nm_clear_g_free (&value); |
4333 | ++ } |
4334 | ++ |
4335 | ++ /* Read WEP key flags */ |
4336 | ++ key_flags = _secret_read_ifcfg_flags (ifcfg, "WEP_KEY_FLAGS"); |
4337 | ++ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, key_flags, NULL); |
4338 | ++ |
4339 | ++ /* Read keys in the ifcfg file if they are system-owned */ |
4340 | ++ if (key_flags == NM_SETTING_SECRET_FLAG_NONE) { |
4341 | ++ NMWepKeyType key_type; |
4342 | ++ const char *v; |
4343 | ++ gs_free char *to_free = NULL; |
4344 | ++ |
4345 | ++ v = svGetValueStr (ifcfg, "KEY_TYPE", &to_free); |
4346 | ++ if (!v) |
4347 | ++ key_type = NM_WEP_KEY_TYPE_UNKNOWN; |
4348 | ++ else if (nm_streq (v, "key")) |
4349 | ++ key_type = NM_WEP_KEY_TYPE_KEY; |
4350 | ++ else if (nm_streq (v, "passphrase")) |
4351 | ++ key_type = NM_WEP_KEY_TYPE_PASSPHRASE; |
4352 | ++ else { |
4353 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4354 | ++ "Invalid KEY_TYPE value '%s'", v); |
4355 | ++ return FALSE; |
4356 | ++ } |
4357 | ++ |
4358 | ++ if (!read_wep_keys (ifcfg, key_type, default_key_idx, s_wsec, error)) |
4359 | ++ return NULL; |
4360 | ++ |
4361 | ++ /* Try to get keys from the "shadow" key file */ |
4362 | ++ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); |
4363 | ++ if (keys_ifcfg) { |
4364 | ++ if (!read_wep_keys (keys_ifcfg, key_type, default_key_idx, s_wsec, error)) { |
4365 | ++ svCloseFile (keys_ifcfg); |
4366 | ++ return NULL; |
4367 | ++ } |
4368 | ++ svCloseFile (keys_ifcfg); |
4369 | ++ g_assert (error == NULL || *error == NULL); |
4370 | ++ } |
4371 | ++ |
4372 | ++ g_object_set (G_OBJECT (s_wsec), |
4373 | ++ NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, key_type, |
4374 | ++ NULL); |
4375 | ++ } |
4376 | ++ |
4377 | ++ value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); |
4378 | ++ if (value) { |
4379 | ++ gs_free char *lcase = NULL; |
4380 | ++ |
4381 | ++ lcase = g_ascii_strdown (value, -1); |
4382 | ++ nm_clear_g_free (&value); |
4383 | ++ |
4384 | ++ if (nm_streq (lcase, "open")) { |
4385 | ++ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); |
4386 | ++ } else if (nm_streq (lcase, "restricted")) { |
4387 | ++ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL); |
4388 | ++ } else { |
4389 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4390 | ++ "Invalid WEP authentication algorithm '%s'", |
4391 | ++ lcase); |
4392 | ++ return NULL; |
4393 | ++ } |
4394 | ++ } |
4395 | ++ |
4396 | ++ /* If no WEP keys were given, and the keys are not agent-owned, and no |
4397 | ++ * default WEP key index was given, then the connection is unencrypted. |
4398 | ++ */ |
4399 | ++ if ( !nm_setting_wireless_security_get_wep_key (s_wsec, 0) |
4400 | ++ && !nm_setting_wireless_security_get_wep_key (s_wsec, 1) |
4401 | ++ && !nm_setting_wireless_security_get_wep_key (s_wsec, 2) |
4402 | ++ && !nm_setting_wireless_security_get_wep_key (s_wsec, 3) |
4403 | ++ && (has_default_key == FALSE) |
4404 | ++ && (key_flags == NM_SETTING_SECRET_FLAG_NONE)) { |
4405 | ++ const char *auth_alg; |
4406 | ++ |
4407 | ++ auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); |
4408 | ++ if (auth_alg && !strcmp (auth_alg, "shared")) { |
4409 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4410 | ++ "WEP Shared Key authentication is invalid for " |
4411 | ++ "unencrypted connections."); |
4412 | ++ return NULL; |
4413 | ++ } |
4414 | ++ |
4415 | ++ /* Unencrypted */ |
4416 | ++ return NULL; |
4417 | ++ } |
4418 | ++ |
4419 | ++ return NM_SETTING (g_steal_pointer (&s_wsec)); |
4420 | ++} |
4421 | ++ |
4422 | ++static gboolean |
4423 | ++fill_wpa_ciphers (shvarFile *ifcfg, |
4424 | ++ NMSettingWirelessSecurity *wsec, |
4425 | ++ gboolean group, |
4426 | ++ gboolean adhoc) |
4427 | ++{ |
4428 | ++ gs_free char *value = NULL; |
4429 | ++ const char *p; |
4430 | ++ gs_free const char **list = NULL; |
4431 | ++ const char *const *iter; |
4432 | ++ int i = 0; |
4433 | ++ |
4434 | ++ p = svGetValueStr (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", &value); |
4435 | ++ if (!p) |
4436 | ++ return TRUE; |
4437 | ++ |
4438 | ++ list = nm_utils_strsplit_set (p, " "); |
4439 | ++ for (iter = list; iter && *iter; iter++, i++) { |
4440 | ++ if (!strcmp (*iter, "CCMP")) { |
4441 | ++ if (group) |
4442 | ++ nm_setting_wireless_security_add_group (wsec, "ccmp"); |
4443 | ++ else |
4444 | ++ nm_setting_wireless_security_add_pairwise (wsec, "ccmp"); |
4445 | ++ } else if (!strcmp (*iter, "TKIP")) { |
4446 | ++ if (group) |
4447 | ++ nm_setting_wireless_security_add_group (wsec, "tkip"); |
4448 | ++ else |
4449 | ++ nm_setting_wireless_security_add_pairwise (wsec, "tkip"); |
4450 | ++ } else if (group && !strcmp (*iter, "WEP104")) |
4451 | ++ nm_setting_wireless_security_add_group (wsec, "wep104"); |
4452 | ++ else if (group && !strcmp (*iter, "WEP40")) |
4453 | ++ nm_setting_wireless_security_add_group (wsec, "wep40"); |
4454 | ++ else { |
4455 | ++ PARSE_WARNING ("ignoring invalid %s cipher '%s'", |
4456 | ++ group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", |
4457 | ++ *iter); |
4458 | ++ } |
4459 | ++ } |
4460 | ++ |
4461 | ++ return TRUE; |
4462 | ++} |
4463 | ++ |
4464 | ++#define WPA_PMK_LEN 32 |
4465 | ++ |
4466 | ++static char * |
4467 | ++parse_wpa_psk (shvarFile *ifcfg, |
4468 | ++ const char *file, |
4469 | ++ GBytes *ssid, |
4470 | ++ GError **error) |
4471 | ++{ |
4472 | ++ shvarFile *keys_ifcfg; |
4473 | ++ gs_free char *psk = NULL; |
4474 | ++ size_t plen; |
4475 | ++ |
4476 | ++ /* Passphrase must be between 10 and 66 characters in length because WPA |
4477 | ++ * hex keys are exactly 64 characters (no quoting), and WPA passphrases |
4478 | ++ * are between 8 and 63 characters (inclusive), plus optional quoting if |
4479 | ++ * the passphrase contains spaces. |
4480 | ++ */ |
4481 | ++ |
4482 | ++ /* Try to get keys from the "shadow" key file */ |
4483 | ++ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); |
4484 | ++ if (keys_ifcfg) { |
4485 | ++ psk = svGetValueStr_cp (keys_ifcfg, "WPA_PSK"); |
4486 | ++ svCloseFile (keys_ifcfg); |
4487 | ++ } |
4488 | ++ |
4489 | ++ /* Fall back to the original ifcfg */ |
4490 | ++ if (!psk) |
4491 | ++ psk = svGetValueStr_cp (ifcfg, "WPA_PSK"); |
4492 | ++ |
4493 | ++ if (!psk) |
4494 | ++ return NULL; |
4495 | ++ |
4496 | ++ plen = strlen (psk); |
4497 | ++ |
4498 | ++ if (plen == 64) { |
4499 | ++ /* Verify the hex PSK; 64 digits */ |
4500 | ++ if (!NM_STRCHAR_ALL (psk, ch, g_ascii_isxdigit (ch))) { |
4501 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4502 | ++ "Invalid WPA_PSK (contains non-hexadecimal characters)"); |
4503 | ++ return NULL; |
4504 | ++ } |
4505 | ++ } else { |
4506 | ++ if (plen < 8 || plen > 63) { |
4507 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4508 | ++ "Invalid WPA_PSK (passphrases must be between " |
4509 | ++ "8 and 63 characters long (inclusive))"); |
4510 | ++ return NULL; |
4511 | ++ } |
4512 | ++ } |
4513 | ++ |
4514 | ++ return g_steal_pointer (&psk); |
4515 | ++} |
4516 | ++ |
4517 | ++static gboolean |
4518 | ++eap_simple_reader (const char *eap_method, |
4519 | ++ shvarFile *ifcfg, |
4520 | ++ shvarFile *keys_ifcfg, |
4521 | ++ NMSetting8021x *s_8021x, |
4522 | ++ gboolean phase2, |
4523 | ++ GError **error) |
4524 | ++{ |
4525 | ++ NMSettingSecretFlags flags; |
4526 | ++ gs_free char *identity_free = NULL; |
4527 | ++ nm_auto_free_secret char *password_raw_str = NULL; |
4528 | ++ gs_unref_bytes GBytes *password_raw_bytes = NULL; |
4529 | ++ |
4530 | ++ g_object_set (s_8021x, |
4531 | ++ NM_SETTING_802_1X_IDENTITY, |
4532 | ++ svGetValueStr (ifcfg, "IEEE_8021X_IDENTITY", &identity_free), |
4533 | ++ NULL); |
4534 | ++ |
4535 | ++ _secret_set_from_ifcfg (s_8021x, |
4536 | ++ ifcfg, |
4537 | ++ keys_ifcfg, |
4538 | ++ "IEEE_8021X_PASSWORD", |
4539 | ++ NM_SETTING_802_1X_PASSWORD); |
4540 | ++ |
4541 | ++ _secret_read_ifcfg (ifcfg, keys_ifcfg, "IEEE_8021X_PASSWORD_RAW", &password_raw_str, &flags); |
4542 | ++ if (!_secret_password_raw_to_bytes ("IEEE_8021X_PASSWORD_RAW", |
4543 | ++ password_raw_str, |
4544 | ++ &password_raw_bytes, |
4545 | ++ error)) |
4546 | ++ return FALSE; |
4547 | ++ |
4548 | ++ g_object_set (s_8021x, |
4549 | ++ NM_SETTING_802_1X_PASSWORD_RAW_FLAGS, |
4550 | ++ flags, |
4551 | ++ NM_SETTING_802_1X_PASSWORD_RAW, |
4552 | ++ password_raw_bytes, |
4553 | ++ NULL); |
4554 | ++ |
4555 | ++ return TRUE; |
4556 | ++} |
4557 | ++ |
4558 | ++static gboolean |
4559 | ++eap_tls_reader (const char *eap_method, |
4560 | ++ shvarFile *ifcfg, |
4561 | ++ shvarFile *keys_ifcfg, |
4562 | ++ NMSetting8021x *s_8021x, |
4563 | ++ gboolean phase2, |
4564 | ++ GError **error) |
4565 | ++{ |
4566 | ++ gs_unref_bytes GBytes *privkey = NULL; |
4567 | ++ gs_unref_bytes GBytes *client_cert = NULL; |
4568 | ++ gs_free char *identity_free = NULL; |
4569 | ++ gs_free char *value_to_free = NULL; |
4570 | ++ const char *client_cert_var; |
4571 | ++ const char *client_cert_prop; |
4572 | ++ NMSetting8021xCKFormat format; |
4573 | ++ |
4574 | ++ g_object_set (s_8021x, |
4575 | ++ NM_SETTING_802_1X_IDENTITY, |
4576 | ++ svGetValueStr (ifcfg, "IEEE_8021X_IDENTITY", &identity_free), |
4577 | ++ NULL); |
4578 | ++ |
4579 | ++ /* CA certificate */ |
4580 | ++ if (!_cert_set_from_ifcfg (s_8021x, |
4581 | ++ ifcfg, |
4582 | ++ phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT", |
4583 | ++ phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT : NM_SETTING_802_1X_CA_CERT, |
4584 | ++ NULL, |
4585 | ++ error)) |
4586 | ++ return FALSE; |
4587 | ++ _secret_set_from_ifcfg (s_8021x, |
4588 | ++ ifcfg, |
4589 | ++ keys_ifcfg, |
4590 | ++ phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD" : "IEEE_8021X_CA_CERT_PASSWORD", |
4591 | ++ phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD : NM_SETTING_802_1X_CA_CERT_PASSWORD); |
4592 | ++ |
4593 | ++ /* Private key */ |
4594 | ++ if (!_cert_set_from_ifcfg (s_8021x, |
4595 | ++ ifcfg, |
4596 | ++ phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY", |
4597 | ++ phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY : NM_SETTING_802_1X_PRIVATE_KEY, |
4598 | ++ &privkey, |
4599 | ++ error)) |
4600 | ++ return FALSE; |
4601 | ++ _secret_set_from_ifcfg (s_8021x, |
4602 | ++ ifcfg, |
4603 | ++ keys_ifcfg, |
4604 | ++ phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD" : "IEEE_8021X_PRIVATE_KEY_PASSWORD", |
4605 | ++ phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); |
4606 | ++ |
4607 | ++ /* Client certificate */ |
4608 | ++ client_cert_var = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT"; |
4609 | ++ client_cert_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT : NM_SETTING_802_1X_CLIENT_CERT; |
4610 | ++ if (!_cert_set_from_ifcfg (s_8021x, |
4611 | ++ ifcfg, |
4612 | ++ client_cert_var, |
4613 | ++ client_cert_prop, |
4614 | ++ &client_cert, |
4615 | ++ error)) |
4616 | ++ return FALSE; |
4617 | ++ _secret_set_from_ifcfg (s_8021x, |
4618 | ++ ifcfg, |
4619 | ++ keys_ifcfg, |
4620 | ++ phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD" : "IEEE_8021X_CLIENT_CERT_PASSWORD", |
4621 | ++ phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD); |
4622 | ++ |
4623 | ++ /* In the past when the private key and client certificate |
4624 | ++ * were the same PKCS #12 file we used to write only the |
4625 | ++ * private key variable. Still support that even if it means |
4626 | ++ * that we have to look into the file content, which makes |
4627 | ++ * the connection not self-contained. |
4628 | ++ */ |
4629 | ++ if ( !client_cert |
4630 | ++ && privkey |
4631 | ++ && !svGetValue (ifcfg, client_cert_var, &value_to_free)) { |
4632 | ++ if (phase2) |
4633 | ++ format = nm_setting_802_1x_get_phase2_private_key_format (s_8021x); |
4634 | ++ else |
4635 | ++ format = nm_setting_802_1x_get_private_key_format (s_8021x); |
4636 | ++ |
4637 | ++ if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) |
4638 | ++ g_object_set (s_8021x, client_cert_prop, privkey, NULL); |
4639 | ++ } |
4640 | ++ |
4641 | ++ return TRUE; |
4642 | ++} |
4643 | ++ |
4644 | ++static gboolean |
4645 | ++eap_peap_reader (const char *eap_method, |
4646 | ++ shvarFile *ifcfg, |
4647 | ++ shvarFile *keys_ifcfg, |
4648 | ++ NMSetting8021x *s_8021x, |
4649 | ++ gboolean phase2, |
4650 | ++ GError **error) |
4651 | ++{ |
4652 | ++ gs_free char *value = NULL; |
4653 | ++ const char *v; |
4654 | ++ gs_free const char **list = NULL; |
4655 | ++ const char *const *iter; |
4656 | ++ |
4657 | ++ if (!_cert_set_from_ifcfg (s_8021x, |
4658 | ++ ifcfg, |
4659 | ++ "IEEE_8021X_CA_CERT", |
4660 | ++ NM_SETTING_802_1X_CA_CERT, |
4661 | ++ NULL, |
4662 | ++ error)) |
4663 | ++ return FALSE; |
4664 | ++ _secret_set_from_ifcfg (s_8021x, |
4665 | ++ ifcfg, |
4666 | ++ keys_ifcfg, |
4667 | ++ "IEEE_8021X_CA_CERT_PASSWORD", |
4668 | ++ NM_SETTING_802_1X_CA_CERT_PASSWORD); |
4669 | ++ |
4670 | ++ nm_clear_g_free (&value); |
4671 | ++ v = svGetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", &value); |
4672 | ++ if (v) { |
4673 | ++ if (!strcmp (v, "0")) |
4674 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL); |
4675 | ++ else if (!strcmp (v, "1")) |
4676 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL); |
4677 | ++ else { |
4678 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4679 | ++ "Unknown IEEE_8021X_PEAP_VERSION value '%s'", |
4680 | ++ v); |
4681 | ++ return FALSE; |
4682 | ++ } |
4683 | ++ } |
4684 | ++ |
4685 | ++ if (svGetValueBoolean (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE)) |
4686 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL); |
4687 | ++ |
4688 | ++ nm_clear_g_free (&value); |
4689 | ++ v = svGetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY", &value); |
4690 | ++ if (v) |
4691 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, v, NULL); |
4692 | ++ |
4693 | ++ nm_clear_g_free (&value); |
4694 | ++ v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &value); |
4695 | ++ if (!v) { |
4696 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4697 | ++ "Missing IEEE_8021X_INNER_AUTH_METHODS."); |
4698 | ++ return FALSE; |
4699 | ++ } |
4700 | ++ |
4701 | ++ /* Handle options for the inner auth method */ |
4702 | ++ list = nm_utils_strsplit_set (v, " "); |
4703 | ++ iter = list; |
4704 | ++ if (iter) { |
4705 | ++ if (NM_IN_STRSET (*iter, "MSCHAPV2", |
4706 | ++ "MD5", |
4707 | ++ "GTC")) { |
4708 | ++ if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) |
4709 | ++ return FALSE; |
4710 | ++ } else if (nm_streq (*iter, "TLS")) { |
4711 | ++ if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) |
4712 | ++ return FALSE; |
4713 | ++ } else { |
4714 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4715 | ++ "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", |
4716 | ++ *iter); |
4717 | ++ return FALSE; |
4718 | ++ } |
4719 | ++ |
4720 | ++ { |
4721 | ++ gs_free char *lower = NULL; |
4722 | ++ |
4723 | ++ lower = g_ascii_strdown (*iter, -1); |
4724 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL); |
4725 | ++ } |
4726 | ++ } |
4727 | ++ |
4728 | ++ if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) { |
4729 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4730 | ++ "No valid IEEE_8021X_INNER_AUTH_METHODS found."); |
4731 | ++ return FALSE; |
4732 | ++ } |
4733 | ++ |
4734 | ++ return TRUE; |
4735 | ++} |
4736 | ++ |
4737 | ++static gboolean |
4738 | ++eap_ttls_reader (const char *eap_method, |
4739 | ++ shvarFile *ifcfg, |
4740 | ++ shvarFile *keys_ifcfg, |
4741 | ++ NMSetting8021x *s_8021x, |
4742 | ++ gboolean phase2, |
4743 | ++ GError **error) |
4744 | ++{ |
4745 | ++ gs_free char *inner_auth = NULL; |
4746 | ++ gs_free char *value = NULL; |
4747 | ++ const char *v; |
4748 | ++ gs_free const char **list = NULL; |
4749 | ++ const char *const *iter; |
4750 | ++ |
4751 | ++ if (!_cert_set_from_ifcfg (s_8021x, |
4752 | ++ ifcfg, |
4753 | ++ "IEEE_8021X_CA_CERT", |
4754 | ++ NM_SETTING_802_1X_CA_CERT, |
4755 | ++ NULL, |
4756 | ++ error)) |
4757 | ++ return FALSE; |
4758 | ++ _secret_set_from_ifcfg (s_8021x, |
4759 | ++ ifcfg, |
4760 | ++ keys_ifcfg, |
4761 | ++ "IEEE_8021X_CA_CERT_PASSWORD", |
4762 | ++ NM_SETTING_802_1X_CA_CERT_PASSWORD); |
4763 | ++ |
4764 | ++ nm_clear_g_free (&value); |
4765 | ++ v = svGetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY", &value); |
4766 | ++ if (v) |
4767 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, v, NULL); |
4768 | ++ |
4769 | ++ nm_clear_g_free (&value); |
4770 | ++ v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &value); |
4771 | ++ if (!v) { |
4772 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4773 | ++ "Missing IEEE_8021X_INNER_AUTH_METHODS."); |
4774 | ++ return FALSE; |
4775 | ++ } |
4776 | ++ |
4777 | ++ inner_auth = g_ascii_strdown (v, -1); |
4778 | ++ |
4779 | ++ /* Handle options for the inner auth method */ |
4780 | ++ list = nm_utils_strsplit_set (inner_auth, " "); |
4781 | ++ iter = list; |
4782 | ++ if (iter) { |
4783 | ++ if (NM_IN_STRSET (*iter, "mschapv2", |
4784 | ++ "mschap", |
4785 | ++ "pap", |
4786 | ++ "chap")) { |
4787 | ++ if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) |
4788 | ++ return FALSE; |
4789 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL); |
4790 | ++ } else if (nm_streq (*iter, "eap-tls")) { |
4791 | ++ if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) |
4792 | ++ return FALSE; |
4793 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL); |
4794 | ++ } else if (NM_IN_STRSET (*iter, "eap-mschapv2", |
4795 | ++ "eap-md5", |
4796 | ++ "eap-gtc")) { |
4797 | ++ if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) |
4798 | ++ return FALSE; |
4799 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + NM_STRLEN ("eap-")), NULL); |
4800 | ++ } else { |
4801 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4802 | ++ "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", |
4803 | ++ *iter); |
4804 | ++ return FALSE; |
4805 | ++ } |
4806 | ++ } |
4807 | ++ |
4808 | ++ return TRUE; |
4809 | ++} |
4810 | ++ |
4811 | ++static gboolean |
4812 | ++eap_fast_reader (const char *eap_method, |
4813 | ++ shvarFile *ifcfg, |
4814 | ++ shvarFile *keys_ifcfg, |
4815 | ++ NMSetting8021x *s_8021x, |
4816 | ++ gboolean phase2, |
4817 | ++ GError **error) |
4818 | ++{ |
4819 | ++ char *anon_ident = NULL; |
4820 | ++ char *pac_file = NULL; |
4821 | ++ char *real_pac_path = NULL; |
4822 | ++ char *inner_auth = NULL; |
4823 | ++ char *fast_provisioning = NULL; |
4824 | ++ char *lower; |
4825 | ++ gs_free const char **list = NULL; |
4826 | ++ const char *const *iter; |
4827 | ++ const char *pac_prov_str; |
4828 | ++ gboolean allow_unauth = FALSE, allow_auth = FALSE; |
4829 | ++ gboolean success = FALSE; |
4830 | ++ |
4831 | ++ pac_file = svGetValueStr_cp (ifcfg, "IEEE_8021X_PAC_FILE"); |
4832 | ++ if (pac_file) { |
4833 | ++ real_pac_path = get_full_file_path (svFileGetName (ifcfg), pac_file); |
4834 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL); |
4835 | ++ } |
4836 | ++ |
4837 | ++ fast_provisioning = svGetValueStr_cp (ifcfg, "IEEE_8021X_FAST_PROVISIONING"); |
4838 | ++ if (fast_provisioning) { |
4839 | ++ gs_free const char **list1 = NULL; |
4840 | ++ |
4841 | ++ list1 = nm_utils_strsplit_set (fast_provisioning, " \t"); |
4842 | ++ for (iter = list1; iter && *iter; iter++) { |
4843 | ++ if (strcmp (*iter, "allow-unauth") == 0) |
4844 | ++ allow_unauth = TRUE; |
4845 | ++ else if (strcmp (*iter, "allow-auth") == 0) |
4846 | ++ allow_auth = TRUE; |
4847 | ++ else { |
4848 | ++ PARSE_WARNING ("invalid IEEE_8021X_FAST_PROVISIONING '%s' " |
4849 | ++ "(space-separated list of these values [allow-auth, allow-unauth] expected)", |
4850 | ++ *iter); |
4851 | ++ } |
4852 | ++ } |
4853 | ++ } |
4854 | ++ pac_prov_str = allow_unauth ? (allow_auth ? "3" : "1") : (allow_auth ? "2" : "0"); |
4855 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, pac_prov_str, NULL); |
4856 | ++ |
4857 | ++ if (!pac_file && !(allow_unauth || allow_auth)) { |
4858 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4859 | ++ "IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled."); |
4860 | ++ goto done; |
4861 | ++ } |
4862 | ++ |
4863 | ++ anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY"); |
4864 | ++ if (anon_ident) |
4865 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL); |
4866 | ++ |
4867 | ++ inner_auth = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); |
4868 | ++ if (!inner_auth) { |
4869 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4870 | ++ "Missing IEEE_8021X_INNER_AUTH_METHODS."); |
4871 | ++ goto done; |
4872 | ++ } |
4873 | ++ |
4874 | ++ /* Handle options for the inner auth method */ |
4875 | ++ list = nm_utils_strsplit_set (inner_auth, " "); |
4876 | ++ iter = list; |
4877 | ++ if (iter) { |
4878 | ++ if ( !strcmp (*iter, "MSCHAPV2") |
4879 | ++ || !strcmp (*iter, "GTC")) { |
4880 | ++ if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) |
4881 | ++ goto done; |
4882 | ++ } else { |
4883 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4884 | ++ "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", |
4885 | ++ *iter); |
4886 | ++ goto done; |
4887 | ++ } |
4888 | ++ |
4889 | ++ lower = g_ascii_strdown (*iter, -1); |
4890 | ++ g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL); |
4891 | ++ g_free (lower); |
4892 | ++ } |
4893 | ++ |
4894 | ++ if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) { |
4895 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4896 | ++ "No valid IEEE_8021X_INNER_AUTH_METHODS found."); |
4897 | ++ goto done; |
4898 | ++ } |
4899 | ++ |
4900 | ++ success = TRUE; |
4901 | ++ |
4902 | ++done: |
4903 | ++ g_free (inner_auth); |
4904 | ++ g_free (fast_provisioning); |
4905 | ++ g_free (real_pac_path); |
4906 | ++ g_free (pac_file); |
4907 | ++ g_free (anon_ident); |
4908 | ++ return success; |
4909 | ++} |
4910 | ++ |
4911 | ++typedef struct { |
4912 | ++ const char *method; |
4913 | ++ gboolean (*reader) (const char *eap_method, |
4914 | ++ shvarFile *ifcfg, |
4915 | ++ shvarFile *keys_ifcfg, |
4916 | ++ NMSetting8021x *s_8021x, |
4917 | ++ gboolean phase2, |
4918 | ++ GError **error); |
4919 | ++ gboolean wifi_phase2_only; |
4920 | ++} EAPReader; |
4921 | ++ |
4922 | ++static EAPReader eap_readers[] = { |
4923 | ++ { "md5", eap_simple_reader, TRUE }, |
4924 | ++ { "pap", eap_simple_reader, TRUE }, |
4925 | ++ { "chap", eap_simple_reader, TRUE }, |
4926 | ++ { "mschap", eap_simple_reader, TRUE }, |
4927 | ++ { "mschapv2", eap_simple_reader, TRUE }, |
4928 | ++ { "leap", eap_simple_reader, FALSE }, |
4929 | ++ { "pwd", eap_simple_reader, FALSE }, |
4930 | ++ { "tls", eap_tls_reader, FALSE }, |
4931 | ++ { "peap", eap_peap_reader, FALSE }, |
4932 | ++ { "ttls", eap_ttls_reader, FALSE }, |
4933 | ++ { "fast", eap_fast_reader, FALSE }, |
4934 | ++ { NULL, NULL } |
4935 | ++}; |
4936 | ++ |
4937 | ++static void |
4938 | ++read_8021x_list_value (shvarFile *ifcfg, |
4939 | ++ const char *ifcfg_var_name, |
4940 | ++ NMSetting8021x *setting, |
4941 | ++ const char *prop_name) |
4942 | ++{ |
4943 | ++ gs_free char *value = NULL; |
4944 | ++ gs_free const char **strv = NULL; |
4945 | ++ const char *v; |
4946 | ++ |
4947 | ++ g_return_if_fail (ifcfg != NULL); |
4948 | ++ g_return_if_fail (ifcfg_var_name != NULL); |
4949 | ++ g_return_if_fail (prop_name != NULL); |
4950 | ++ |
4951 | ++ v = svGetValueStr (ifcfg, ifcfg_var_name, &value); |
4952 | ++ if (!v) |
4953 | ++ return; |
4954 | ++ |
4955 | ++ strv = nm_utils_strsplit_set (v, " \t"); |
4956 | ++ if (strv) |
4957 | ++ g_object_set (setting, prop_name, strv, NULL); |
4958 | ++} |
4959 | ++ |
4960 | ++static NMSetting8021x * |
4961 | ++fill_8021x (shvarFile *ifcfg, |
4962 | ++ const char *file, |
4963 | ++ const char *key_mgmt, |
4964 | ++ gboolean wifi, |
4965 | ++ GError **error) |
4966 | ++{ |
4967 | ++ nm_auto_shvar_file_close shvarFile *keys_ifcfg = NULL; |
4968 | ++ gs_unref_object NMSetting8021x *s_8021x = NULL; |
4969 | ++ gs_free char *value = NULL; |
4970 | ++ const char *v; |
4971 | ++ gs_free const char **list = NULL; |
4972 | ++ const char *const *iter; |
4973 | ++ gint64 timeout; |
4974 | ++ int i_val; |
4975 | ++ |
4976 | ++ v = svGetValueStr (ifcfg, "IEEE_8021X_EAP_METHODS", &value); |
4977 | ++ if (!v) { |
4978 | ++ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, |
4979 | ++ "Missing IEEE_8021X_EAP_METHODS for key management '%s'", |
4980 | ++ key_mgmt); |
4981 | ++ return NULL; |
4982 | ++ } |
4983 | ++ |
4984 | ++ list = nm_utils_strsplit_set (v, " "); |
4985 | ++ |
4986 | ++ s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); |
4987 | ++ |
4988 | ++ /* Read in the lookaside keys_ifcfg file, if present */ |
4989 | ++ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); |
4990 | ++ |
4991 | ++ /* Validate and handle each EAP method */ |
4992 | ++ for (iter = list; iter && *iter; iter++) { |
4993 | ++ EAPReader *eap = &eap_readers[0]; |
4994 | ++ gboolean found = FALSE; |
4995 | ++ gs_free char *lower = NULL; |
4996 | ++ |
4997 | ++ lower = g_ascii_strdown (*iter, -1); |
4998 | ++ while (eap->method) { |
4999 | ++ if (strcmp (eap->method, lower)) |
5000 | ++ goto next; |
FAILED: Continuous integration, rev:9f4ffcffb20 516c4648cfcb5b4 7ba4edecd0ef7e /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-build- prepare/ 529/ /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-build/ ARCHITECTURE= amd64/562/ console /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-build/ ARCHITECTURE= arm64/562 /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-build/ ARCHITECTURE= armhf/562 /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-build/ ARCHITECTURE= i386/562 /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-docs/ 1351 /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-cleanup/ 1093 /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-update- mp/1142/ console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- enablement/ job/snappy- hwe-snaps- snap-build- prepare/ 529/rebuild
https:/