1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager system settings service
4 * Søren Sandmann <sandmann@daimi.au.dk>
5 * Dan Williams <dcbw@redhat.com>
6 * Tambet Ingo <tambet@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * (C) Copyright 2007 - 2011 Red Hat, Inc.
23 * (C) Copyright 2008 Novell, Inc.
26 #include "nm-default.h"
36 #include <selinux/selinux.h>
39 #include "nm-dbus-interface.h"
40 #include "nm-connection.h"
41 #include "nm-setting-8021x.h"
42 #include "nm-setting-bluetooth.h"
43 #include "nm-setting-cdma.h"
44 #include "nm-setting-connection.h"
45 #include "nm-setting-gsm.h"
46 #include "nm-setting-ip4-config.h"
47 #include "nm-setting-ip6-config.h"
48 #include "nm-setting-olpc-mesh.h"
49 #include "nm-setting-ppp.h"
50 #include "nm-setting-pppoe.h"
51 #include "nm-setting-serial.h"
52 #include "nm-setting-vpn.h"
53 #include "nm-setting-wired.h"
54 #include "nm-setting-adsl.h"
55 #include "nm-setting-wireless.h"
56 #include "nm-setting-wireless-security.h"
57 #include "nm-setting-bond.h"
59 #include "nm-core-internal.h"
61 #include "nm-device-ethernet.h"
62 #include "nm-settings.h"
63 #include "nm-settings-connection.h"
64 #include "nm-settings-plugin.h"
65 #include "nm-bus-manager.h"
66 #include "nm-auth-utils.h"
67 #include "nm-auth-subject.h"
68 #include "nm-session-monitor.h"
69 #include "plugins/keyfile/plugin.h"
70 #include "nm-agent-manager.h"
71 #include "nm-connection-provider.h"
72 #include "nm-config.h"
73 #include "nm-audit-manager.h"
74 #include "NetworkManagerUtils.h"
75 #include "nm-dispatcher.h"
77 #include "nmdbus-settings.h"
79 #define _NMLOG_DOMAIN LOGD_SETTINGS
80 #define _NMLOG_PREFIX_NAME "settings"
81 #define _NMLOG(level, ...) \
83 nm_log ((level), _NMLOG_DOMAIN, \
84 "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
85 _NMLOG_PREFIX_NAME": " \
86 _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
89 /* LINKER CRACKROCK */
90 #define EXPORT(sym) void * __export_##sym = &sym;
92 #include "nm-inotify-helper.h"
93 EXPORT(nm_inotify_helper_get_type)
94 EXPORT(nm_inotify_helper_get)
95 EXPORT(nm_inotify_helper_add_watch)
96 EXPORT(nm_inotify_helper_remove_watch)
98 EXPORT(nm_settings_connection_get_type)
99 EXPORT(nm_settings_connection_replace_settings)
100 EXPORT(nm_settings_connection_replace_and_commit)
101 /* END LINKER CRACKROCK */
103 #define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1"
104 #define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1"
105 #define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1"
107 #define HOSTNAME_FILE_DEFAULT "/etc/hostname"
108 #define HOSTNAME_FILE_UCASE_HOSTNAME "/etc/HOSTNAME"
109 #define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname"
110 #define IFCFG_DIR SYSCONFDIR "/sysconfig/network"
111 #define CONF_DHCP IFCFG_DIR "/dhcp"
113 #define PLUGIN_MODULE_PATH "plugin-module-path"
115 #if defined(HOSTNAME_PERSIST_SUSE)
116 #define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME
117 #elif defined(HOSTNAME_PERSIST_SLACKWARE)
118 #define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME
119 #elif defined(HOSTNAME_PERSIST_GENTOO)
120 #define HOSTNAME_FILE HOSTNAME_FILE_GENTOO
122 #define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT
125 static void claim_connection (NMSettings *self,
126 NMSettingsConnection *connection);
128 static void unmanaged_specs_changed (NMSettingsPlugin *config, gpointer user_data);
129 static void unrecognized_specs_changed (NMSettingsPlugin *config, gpointer user_data);
131 static void connection_provider_iface_init (NMConnectionProviderInterface *cp_iface);
133 G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, NM_TYPE_EXPORTED_OBJECT, 0,
134 G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_iface_init))
138 NMAgentManager *agent_mgr;
145 gboolean connections_loaded;
146 GHashTable *connections;
147 GSList *unmanaged_specs;
148 GSList *unrecognized_specs;
149 GSList *get_connections_cache;
152 gboolean startup_complete;
157 GFileMonitor *monitor;
158 GFileMonitor *dhcp_monitor;
160 gulong dhcp_monitor_id;
161 GDBusProxy *hostnamed_proxy;
165 #define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate))
170 CONNECTION_UPDATED_BY_USER,
172 CONNECTION_VISIBILITY_CHANGED,
175 NEW_CONNECTION, /* exported, not used internally */
178 static guint signals[LAST_SIGNAL] = { 0 };
182 PROP_UNMANAGED_SPECS,
186 PROP_STARTUP_COMPLETE,
192 check_startup_complete (NMSettings *self)
194 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
196 NMSettingsConnection *conn;
198 if (priv->startup_complete)
201 g_hash_table_iter_init (&iter, priv->connections);
202 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) {
203 if (!nm_settings_connection_get_ready (conn))
207 priv->startup_complete = TRUE;
208 g_object_notify (G_OBJECT (self), NM_SETTINGS_STARTUP_COMPLETE);
212 connection_ready_changed (NMSettingsConnection *conn,
216 NMSettings *self = NM_SETTINGS (user_data);
218 if (nm_settings_connection_get_ready (conn))
219 check_startup_complete (self);
223 plugin_connection_added (NMSettingsPlugin *config,
224 NMSettingsConnection *connection,
227 claim_connection (NM_SETTINGS (user_data), connection);
231 load_connections (NMSettings *self)
233 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
236 for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
237 NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
238 GSList *plugin_connections;
241 plugin_connections = nm_settings_plugin_get_connections (plugin);
243 // FIXME: ensure connections from plugins loaded with a lower priority
244 // get rejected when they conflict with connections from a higher
247 for (elt = plugin_connections; elt; elt = g_slist_next (elt))
248 claim_connection (self, NM_SETTINGS_CONNECTION (elt->data));
250 g_slist_free (plugin_connections);
252 g_signal_connect (plugin, NM_SETTINGS_PLUGIN_CONNECTION_ADDED,
253 G_CALLBACK (plugin_connection_added), self);
254 g_signal_connect (plugin, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED,
255 G_CALLBACK (unmanaged_specs_changed), self);
256 g_signal_connect (plugin, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED,
257 G_CALLBACK (unrecognized_specs_changed), self);
260 priv->connections_loaded = TRUE;
262 unmanaged_specs_changed (NULL, self);
263 unrecognized_specs_changed (NULL, self);
267 nm_settings_for_each_connection (NMSettings *self,
268 NMSettingsForEachFunc for_each_func,
271 NMSettingsPrivate *priv;
275 g_return_if_fail (NM_IS_SETTINGS (self));
276 g_return_if_fail (for_each_func != NULL);
278 priv = NM_SETTINGS_GET_PRIVATE (self);
280 g_hash_table_iter_init (&iter, priv->connections);
281 while (g_hash_table_iter_next (&iter, NULL, &data))
282 for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data);
286 impl_settings_list_connections (NMSettings *self,
287 GDBusMethodInvocation *context)
289 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
290 GPtrArray *connections;
294 connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1);
295 g_hash_table_iter_init (&iter, priv->connections);
296 while (g_hash_table_iter_next (&iter, &key, NULL))
297 g_ptr_array_add (connections, key);
298 g_ptr_array_add (connections, NULL);
300 g_dbus_method_invocation_return_value (context,
301 g_variant_new ("(^ao)", connections->pdata));
302 g_ptr_array_unref (connections);
305 NMSettingsConnection *
306 nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid)
308 NMSettingsPrivate *priv;
309 NMSettingsConnection *candidate;
312 g_return_val_if_fail (NM_IS_SETTINGS (self), NULL);
313 g_return_val_if_fail (uuid != NULL, NULL);
315 priv = NM_SETTINGS_GET_PRIVATE (self);
317 g_hash_table_iter_init (&iter, priv->connections);
318 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
319 if (g_strcmp0 (uuid, nm_settings_connection_get_uuid (candidate)) == 0)
327 impl_settings_get_connection_by_uuid (NMSettings *self,
328 GDBusMethodInvocation *context,
331 NMSettingsConnection *connection = NULL;
332 NMAuthSubject *subject = NULL;
333 GError *error = NULL;
334 char *error_desc = NULL;
336 connection = nm_settings_get_connection_by_uuid (self, uuid);
338 error = g_error_new_literal (NM_SETTINGS_ERROR,
339 NM_SETTINGS_ERROR_INVALID_CONNECTION,
340 "No connection with the UUID was found.");
344 subject = nm_auth_subject_new_unix_process_from_context (context);
346 error = g_error_new_literal (NM_SETTINGS_ERROR,
347 NM_SETTINGS_ERROR_PERMISSION_DENIED,
348 "Unable to determine UID of request.");
352 if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection),
355 error = g_error_new_literal (NM_SETTINGS_ERROR,
356 NM_SETTINGS_ERROR_PERMISSION_DENIED,
362 g_clear_object (&subject);
363 g_dbus_method_invocation_return_value (
365 g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection))));
370 g_dbus_method_invocation_take_error (context, error);
371 g_clear_object (&subject);
375 connection_sort (gconstpointer pa, gconstpointer pb)
377 NMConnection *a = NM_CONNECTION (pa);
378 NMSettingConnection *con_a;
379 NMConnection *b = NM_CONNECTION (pb);
380 NMSettingConnection *con_b;
381 guint64 ts_a = 0, ts_b = 0;
382 gboolean can_ac_a, can_ac_b;
384 con_a = nm_connection_get_setting_connection (a);
386 con_b = nm_connection_get_setting_connection (b);
389 can_ac_a = !!nm_setting_connection_get_autoconnect (con_a);
390 can_ac_b = !!nm_setting_connection_get_autoconnect (con_b);
391 if (can_ac_a != can_ac_b)
392 return can_ac_a ? -1 : 1;
394 nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pa), &ts_a);
395 nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pb), &ts_b);
398 else if (ts_a == ts_b)
403 /* Returns a list of NMSettingsConnections.
404 * The list is sorted in the order suitable for auto-connecting, i.e.
405 * first go connections with autoconnect=yes and most recent timestamp.
406 * Caller must free the list with g_slist_free().
409 nm_settings_get_connections (NMSettings *self)
412 gpointer data = NULL;
415 g_return_val_if_fail (NM_IS_SETTINGS (self), NULL);
417 g_hash_table_iter_init (&iter, NM_SETTINGS_GET_PRIVATE (self)->connections);
418 while (g_hash_table_iter_next (&iter, NULL, &data))
419 list = g_slist_insert_sorted (list, data, connection_sort);
423 NMSettingsConnection *
424 nm_settings_get_connection_by_path (NMSettings *self, const char *path)
426 NMSettingsPrivate *priv;
428 g_return_val_if_fail (NM_IS_SETTINGS (self), NULL);
429 g_return_val_if_fail (path != NULL, NULL);
431 priv = NM_SETTINGS_GET_PRIVATE (self);
433 return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path);
437 nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection)
439 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
443 g_hash_table_iter_init (&iter, priv->connections);
444 while (g_hash_table_iter_next (&iter, NULL, &data))
445 if (data == connection)
452 nm_settings_get_unmanaged_specs (NMSettings *self)
454 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
456 return priv->unmanaged_specs;
459 static NMSettingsPlugin *
460 get_plugin (NMSettings *self, guint32 capability)
462 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
465 g_return_val_if_fail (self != NULL, NULL);
467 /* Do any of the plugins support the given capability? */
468 for (iter = priv->plugins; iter; iter = iter->next) {
469 NMSettingsPluginCapabilities caps = NM_SETTINGS_PLUGIN_CAP_NONE;
471 g_object_get (G_OBJECT (iter->data), NM_SETTINGS_PLUGIN_CAPABILITIES, &caps, NULL);
472 if (NM_FLAGS_ALL (caps, capability))
473 return NM_SETTINGS_PLUGIN (iter->data);
479 #if defined(HOSTNAME_PERSIST_GENTOO)
481 read_hostname_gentoo (const char *path)
483 gchar *contents = NULL, *result = NULL, *tmp;
484 gchar **all_lines = NULL;
487 if (!g_file_get_contents (path, &contents, NULL, NULL))
489 all_lines = g_strsplit (contents, "\n", 0);
490 line_num = g_strv_length (all_lines);
491 for (i = 0; i < line_num; i++) {
492 g_strstrip (all_lines[i]);
493 if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
495 if (g_str_has_prefix (all_lines[i], "hostname=")) {
496 tmp = &all_lines[i][NM_STRLEN ("hostname=")];
497 result = g_shell_unquote (tmp, NULL);
501 g_strfreev (all_lines);
507 #if defined(HOSTNAME_PERSIST_SUSE)
509 hostname_is_dynamic (void)
513 gboolean dynamic = FALSE;
515 channel = g_io_channel_new_file (CONF_DHCP, "r", NULL);
519 while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
522 if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME="))
523 dynamic = strcmp (&str[NM_STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0;
528 g_io_channel_shutdown (channel, FALSE, NULL);
529 g_io_channel_unref (channel);
535 /* Returns an allocated string which the caller owns and must eventually free */
537 nm_settings_get_hostname (NMSettings *self)
539 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
540 char *hostname = NULL;
545 if (priv->hostname.hostnamed_proxy) {
546 hostname = g_strdup (priv->hostname.value);
550 #if defined(HOSTNAME_PERSIST_GENTOO)
551 hostname = read_hostname_gentoo (priv->hostname.file);
554 #if defined(HOSTNAME_PERSIST_SUSE)
555 if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ())
558 if (g_file_get_contents (priv->hostname.file, &hostname, NULL, NULL))
559 g_strchomp (hostname);
561 #endif /* HOSTNAME_PERSIST_GENTOO */
564 if (hostname && !hostname[0]) {
573 find_spec (GSList *spec_list, const char *spec)
577 for (iter = spec_list; iter; iter = g_slist_next (iter)) {
578 if (!strcmp ((const char *) iter->data, spec))
585 update_specs (NMSettings *self, GSList **specs_ptr,
586 GSList * (*get_specs_func) (NMSettingsPlugin *))
588 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
591 g_slist_free_full (*specs_ptr, g_free);
594 for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
595 GSList *specs, *specs_iter;
597 specs = get_specs_func (NM_SETTINGS_PLUGIN (iter->data));
598 for (specs_iter = specs; specs_iter; specs_iter = specs_iter->next) {
599 if (!find_spec (*specs_ptr, (const char *) specs_iter->data)) {
600 *specs_ptr = g_slist_prepend (*specs_ptr, specs_iter->data);
602 g_free (specs_iter->data);
605 g_slist_free (specs);
610 unmanaged_specs_changed (NMSettingsPlugin *config,
613 NMSettings *self = NM_SETTINGS (user_data);
614 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
616 update_specs (self, &priv->unmanaged_specs,
617 nm_settings_plugin_get_unmanaged_specs);
618 g_object_notify (G_OBJECT (self), NM_SETTINGS_UNMANAGED_SPECS);
622 unrecognized_specs_changed (NMSettingsPlugin *config,
625 NMSettings *self = NM_SETTINGS (user_data);
626 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
628 update_specs (self, &priv->unrecognized_specs,
629 nm_settings_plugin_get_unrecognized_specs);
633 add_plugin (NMSettings *self, NMSettingsPlugin *plugin)
635 NMSettingsPrivate *priv;
640 g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
641 g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (plugin), FALSE);
643 priv = NM_SETTINGS_GET_PRIVATE (self);
645 if (g_slist_find (priv->plugins, plugin)) {
646 /* don't add duplicates. */
650 priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
651 nm_settings_plugin_init (plugin);
653 g_object_get (G_OBJECT (plugin),
654 NM_SETTINGS_PLUGIN_NAME, &pname,
655 NM_SETTINGS_PLUGIN_INFO, &pinfo,
658 path = g_object_get_data (G_OBJECT (plugin), PLUGIN_MODULE_PATH);
660 _LOGI ("loaded plugin %s: %s%s%s%s", pname, pinfo,
661 NM_PRINT_FMT_QUOTED (path, " (", path, ")", ""));
669 find_plugin (GSList *list, const char *pname)
674 g_return_val_if_fail (pname != NULL, NULL);
676 for (iter = list; iter && !obj; iter = g_slist_next (iter)) {
677 NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
678 char *list_pname = NULL;
680 g_object_get (G_OBJECT (plugin),
681 NM_SETTINGS_PLUGIN_NAME,
684 if (list_pname && !strcmp (pname, list_pname))
685 obj = G_OBJECT (plugin);
694 add_keyfile_plugin (NMSettings *self)
696 gs_unref_object GObject *keyfile_plugin = NULL;
698 keyfile_plugin = nm_settings_keyfile_plugin_new ();
699 g_assert (keyfile_plugin);
700 if (!add_plugin (self, NM_SETTINGS_PLUGIN (keyfile_plugin)))
701 g_return_if_reached ();
705 load_plugins (NMSettings *self, const char **plugins, GError **error)
709 gboolean keyfile_added = FALSE;
710 gboolean success = TRUE;
711 gboolean add_ibft = FALSE;
712 gboolean has_no_ibft;
713 gssize idx_no_ibft, idx_ibft;
715 idx_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "ibft");
716 idx_no_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "no-ibft");
717 has_no_ibft = idx_no_ibft >= 0 && idx_no_ibft > idx_ibft;
718 #if WITH_SETTINGS_PLUGIN_IBFT
719 add_ibft = idx_no_ibft < 0 && idx_ibft < 0;
722 for (iter = plugins; iter && *iter; iter++) {
723 const char *pname = *iter;
726 if (!*pname || strchr (pname, '/')) {
727 _LOGW ("ignore invalid plugin \"%s\"", pname);
731 if (!strcmp (pname, "ifcfg-suse")) {
732 _LOGW ("skipping deprecated plugin ifcfg-suse");
736 if (!strcmp (pname, "no-ibft"))
738 if (has_no_ibft && !strcmp (pname, "ibft"))
741 /* keyfile plugin is built-in now */
742 if (strcmp (pname, "keyfile") == 0) {
743 if (!keyfile_added) {
744 add_keyfile_plugin (self);
745 keyfile_added = TRUE;
750 if (_nm_utils_strv_find_first ((char **) plugins,
753 /* the plugin is already mentioned in the list previously.
754 * Don't load a duplicate. */
758 if (find_plugin (list, pname))
764 gs_free char *full_name = NULL;
765 gs_free char *path = NULL;
766 GObject * (*factory_func) (void);
770 full_name = g_strdup_printf ("nm-settings-plugin-%s", pname);
771 path = g_module_build_path (NMPLUGINDIR, full_name);
773 if (stat (path, &st) != 0) {
775 _LOGW ("could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv));
778 if (!S_ISREG (st.st_mode)) {
779 _LOGW ("could not load plugin '%s' from file '%s': not a file", pname, path);
782 if (st.st_uid != 0) {
783 _LOGW ("could not load plugin '%s' from file '%s': file must be owned by root", pname, path);
786 if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
787 _LOGW ("could not load plugin '%s' from file '%s': invalid file permissions", pname, path);
791 plugin = g_module_open (path, G_MODULE_BIND_LOCAL);
793 _LOGW ("could not load plugin '%s' from file '%s': %s",
794 pname, path, g_module_error ());
798 /* errors after this point are fatal, because we loaded the shared library already. */
800 if (!g_module_symbol (plugin, "nm_settings_plugin_factory", (gpointer) (&factory_func))) {
801 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
802 "Could not find plugin '%s' factory function.",
805 g_module_close (plugin);
809 obj = (*factory_func) ();
810 if (!obj || !NM_IS_SETTINGS_PLUGIN (obj)) {
811 g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
812 "Plugin '%s' returned invalid system config object.",
815 g_module_close (plugin);
819 g_module_make_resident (plugin);
820 g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin);
821 g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free);
823 if (add_plugin (self, NM_SETTINGS_PLUGIN (obj)))
824 list = g_slist_append (list, obj);
826 g_object_unref (obj);
829 if (add_ibft && !strcmp (pname, "ifcfg-rh")) {
830 /* The plugin ibft is not explicitly mentioned but we just enabled "ifcfg-rh".
831 * Enable "ibft" by default after "ifcfg-rh". */
838 /* If keyfile plugin was not among configured plugins, add it as the last one */
840 add_keyfile_plugin (self);
842 g_slist_free_full (list, g_object_unref);
848 connection_updated (NMSettingsConnection *connection, gpointer user_data)
850 /* Re-emit for listeners like NMPolicy */
851 g_signal_emit (NM_SETTINGS (user_data),
852 signals[CONNECTION_UPDATED],
855 g_signal_emit_by_name (NM_SETTINGS (user_data), NM_CP_SIGNAL_CONNECTION_UPDATED, connection);
859 connection_updated_by_user (NMSettingsConnection *connection, gpointer user_data)
861 /* Re-emit for listeners like NMPolicy */
862 g_signal_emit (NM_SETTINGS (user_data),
863 signals[CONNECTION_UPDATED_BY_USER],
869 connection_visibility_changed (NMSettingsConnection *connection,
873 /* Re-emit for listeners like NMPolicy */
874 g_signal_emit (NM_SETTINGS (user_data),
875 signals[CONNECTION_VISIBILITY_CHANGED],
881 connection_removed (NMSettingsConnection *connection, gpointer user_data)
883 NMSettings *self = NM_SETTINGS (user_data);
884 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
885 const char *cpath = nm_connection_get_path (NM_CONNECTION (connection));
887 if (!g_hash_table_lookup (priv->connections, cpath))
888 g_return_if_reached ();
889 g_object_ref (connection);
891 /* Disconnect signal handlers, as plugins might still keep references
892 * to the connection (and thus the signal handlers would still be live)
893 * even after NMSettings has dropped all its references.
896 g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_removed), self);
897 g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated), self);
898 g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated_by_user), self);
899 g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_visibility_changed), self);
900 g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self);
901 g_object_unref (self);
903 /* Forget about the connection internally */
904 g_hash_table_remove (priv->connections, (gpointer) cpath);
907 g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection);
909 /* Re-emit for listeners like NMPolicy */
910 g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_REMOVED, connection);
911 g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS);
912 if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (connection)))
913 nm_exported_object_unexport (NM_EXPORTED_OBJECT (connection));
915 check_startup_complete (self);
917 g_object_unref (connection);
921 secret_agent_registered (NMAgentManager *agent_mgr,
922 NMSecretAgent *agent,
925 /* Re-emit for listeners like NMPolicy */
926 g_signal_emit (NM_SETTINGS (user_data),
927 signals[AGENT_REGISTERED],
932 #define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect"
933 #define NM_OPENCONNECT_KEY_GATEWAY "gateway"
934 #define NM_OPENCONNECT_KEY_COOKIE "cookie"
935 #define NM_OPENCONNECT_KEY_GWCERT "gwcert"
936 #define NM_OPENCONNECT_KEY_XMLCONFIG "xmlconfig"
937 #define NM_OPENCONNECT_KEY_LASTHOST "lasthost"
938 #define NM_OPENCONNECT_KEY_AUTOCONNECT "autoconnect"
939 #define NM_OPENCONNECT_KEY_CERTSIGS "certsigs"
942 openconnect_migrate_hack (NMConnection *connection)
945 NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NOT_SAVED;
947 /* Huge hack. There were some openconnect changes that needed to happen
948 * pretty late, too late to get into distros. Migration has already
949 * happened for many people, and their secret flags are wrong. But we
950 * don't want to requrie re-migration, so we have to fix it up here. Ugh.
953 s_vpn = nm_connection_get_setting_vpn (connection);
957 if (g_strcmp0 (nm_setting_vpn_get_service_type (s_vpn), NM_DBUS_SERVICE_OPENCONNECT) == 0) {
958 /* These are different for every login session, and should not be stored */
959 nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_GATEWAY, flags, NULL);
960 nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_COOKIE, flags, NULL);
961 nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_GWCERT, flags, NULL);
963 /* These are purely internal data for the auth-dialog, and should be stored */
965 nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_XMLCONFIG, flags, NULL);
966 nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_LASTHOST, flags, NULL);
967 nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_AUTOCONNECT, flags, NULL);
968 nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_CERTSIGS, flags, NULL);
973 claim_connection (NMSettings *self, NMSettingsConnection *connection)
975 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
976 GError *error = NULL;
980 NMSettingsConnection *existing;
982 g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
983 g_return_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
985 g_hash_table_iter_init (&iter, priv->connections);
986 while (g_hash_table_iter_next (&iter, NULL, &data)) {
987 /* prevent duplicates */
988 if (data == connection)
992 if (!nm_connection_normalize (NM_CONNECTION (connection), NULL, NULL, &error)) {
993 _LOGW ("plugin provided invalid connection: %s", error->message);
994 g_error_free (error);
998 existing = nm_settings_get_connection_by_uuid (self, nm_settings_connection_get_uuid (connection));
1000 /* Cannot add duplicate connections per UUID. Just return without action and
1003 * This means, that plugins must not provide duplicate connections (UUID).
1004 * In fact, none of the plugins currently would do that.
1006 * But globaly, over different setting plugins, there could be duplicates
1007 * without the individual plugins being aware. Don't handle that at all, just
1008 * error out. That should not happen unless the admin misconfigured the system
1009 * to create conflicting connections. */
1010 _LOGW ("plugin provided duplicate connection with UUID %s",
1011 nm_settings_connection_get_uuid (connection));
1015 /* Read timestamp from look-aside file and put it into the connection's data */
1016 nm_settings_connection_read_and_fill_timestamp (connection);
1018 /* Read seen-bssids from look-aside file and put it into the connection's data */
1019 nm_settings_connection_read_and_fill_seen_bssids (connection);
1021 /* Ensure it's initial visibility is up-to-date */
1022 nm_settings_connection_recheck_visibility (connection);
1024 /* Evil openconnect migration hack */
1025 openconnect_migrate_hack (NM_CONNECTION (connection));
1027 g_object_ref (self);
1028 g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED,
1029 G_CALLBACK (connection_removed), self);
1030 g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED,
1031 G_CALLBACK (connection_updated), self);
1032 g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_BY_USER,
1033 G_CALLBACK (connection_updated_by_user), self);
1034 g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_VISIBLE,
1035 G_CALLBACK (connection_visibility_changed),
1037 if (!priv->startup_complete) {
1038 g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_READY,
1039 G_CALLBACK (connection_ready_changed),
1043 /* Export the connection over D-Bus */
1044 g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
1045 path = nm_exported_object_export (NM_EXPORTED_OBJECT (connection));
1046 nm_connection_set_path (NM_CONNECTION (connection), path);
1048 g_hash_table_insert (priv->connections,
1049 (gpointer) nm_connection_get_path (NM_CONNECTION (connection)),
1050 g_object_ref (connection));
1052 nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ ");
1054 /* Only emit the individual connection-added signal after connections
1055 * have been initially loaded.
1057 if (priv->connections_loaded) {
1058 /* Internal added signal */
1059 g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection);
1060 g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_ADDED, connection);
1061 g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS);
1063 /* Exported D-Bus signal */
1064 g_signal_emit (self, signals[NEW_CONNECTION], 0, connection);
1069 * nm_settings_add_connection:
1070 * @self: the #NMSettings object
1071 * @connection: the source connection to create a new #NMSettingsConnection from
1072 * @save_to_disk: %TRUE to save the connection to disk immediately, %FALSE to
1074 * @error: on return, a location to store any errors that may occur
1076 * Creates a new #NMSettingsConnection for the given source @connection.
1077 * The returned object is owned by @self and the caller must reference
1078 * the object to continue using it.
1080 * Returns: the new #NMSettingsConnection or %NULL
1082 NMSettingsConnection *
1083 nm_settings_add_connection (NMSettings *self,
1084 NMConnection *connection,
1085 gboolean save_to_disk,
1088 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1090 NMSettingsConnection *added = NULL;
1091 GHashTableIter citer;
1092 NMConnection *candidate = NULL;
1094 /* Make sure a connection with this UUID doesn't already exist */
1095 g_hash_table_iter_init (&citer, priv->connections);
1096 while (g_hash_table_iter_next (&citer, NULL, (gpointer *) &candidate)) {
1097 if (g_strcmp0 (nm_connection_get_uuid (connection),
1098 nm_connection_get_uuid (candidate)) == 0) {
1099 g_set_error_literal (error,
1101 NM_SETTINGS_ERROR_UUID_EXISTS,
1102 "A connection with this UUID already exists.");
1107 /* 1) plugin writes the NMConnection to disk
1108 * 2) plugin creates a new NMSettingsConnection subclass with the settings
1109 * from the NMConnection and returns it to the settings service
1110 * 3) settings service exports the new NMSettingsConnection subclass
1111 * 4) plugin notices that something on the filesystem has changed
1112 * 5) plugin reads the changes and ignores them because they will
1113 * contain the same data as the connection it already knows about
1115 for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
1116 NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
1117 GError *add_error = NULL;
1119 added = nm_settings_plugin_add_connection (plugin, connection, save_to_disk, &add_error);
1121 claim_connection (self, added);
1124 _LOGD ("Failed to add %s/'%s': %s",
1125 nm_connection_get_uuid (connection),
1126 nm_connection_get_id (connection),
1127 add_error->message);
1128 g_clear_error (&add_error);
1131 g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
1132 "No plugin supported adding this connection");
1136 static NMConnection *
1137 _nm_connection_provider_add_connection (NMConnectionProvider *provider,
1138 NMConnection *connection,
1139 gboolean save_to_disk,
1142 g_assert (NM_IS_CONNECTION_PROVIDER (provider) && NM_IS_SETTINGS (provider));
1143 return NM_CONNECTION (nm_settings_add_connection (NM_SETTINGS (provider), connection, save_to_disk, error));
1147 secrets_filter_cb (NMSetting *setting,
1149 NMSettingSecretFlags flags,
1152 NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data);
1154 /* Returns TRUE to remove the secret */
1156 /* Can't use bitops with SECRET_FLAG_NONE so handle that specifically */
1157 if ( (flags == NM_SETTING_SECRET_FLAG_NONE)
1158 && (filter_flags == NM_SETTING_SECRET_FLAG_NONE))
1161 /* Otherwise if the secret has at least one of the desired flags keep it */
1162 return (flags & filter_flags) ? FALSE : TRUE;
1166 send_agent_owned_secrets (NMSettings *self,
1167 NMSettingsConnection *connection,
1168 NMAuthSubject *subject)
1170 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1171 NMConnection *for_agent;
1173 /* Dupe the connection so we can clear out non-agent-owned secrets,
1174 * as agent-owned secrets are the only ones we send back to be saved.
1175 * Only send secrets to agents of the same UID that called update too.
1177 for_agent = nm_simple_connection_new_clone (NM_CONNECTION (connection));
1178 nm_connection_clear_secrets_with_flags (for_agent,
1180 GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED));
1181 nm_agent_manager_save_secrets (priv->agent_mgr,
1182 nm_connection_get_path (NM_CONNECTION (connection)),
1185 g_object_unref (for_agent);
1189 pk_add_cb (NMAuthChain *chain,
1190 GError *chain_error,
1191 GDBusMethodInvocation *context,
1194 NMSettings *self = NM_SETTINGS (user_data);
1195 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1196 NMAuthCallResult result;
1197 GError *error = NULL;
1198 NMConnection *connection = NULL;
1199 NMSettingsConnection *added = NULL;
1200 NMSettingsAddCallback callback;
1201 gpointer callback_data;
1202 NMAuthSubject *subject;
1204 gboolean save_to_disk;
1208 priv->auths = g_slist_remove (priv->auths, chain);
1210 perm = nm_auth_chain_get_data (chain, "perm");
1212 result = nm_auth_chain_get_result (chain, perm);
1215 error = g_error_new (NM_SETTINGS_ERROR,
1216 NM_SETTINGS_ERROR_FAILED,
1217 "Error checking authorization: %s",
1218 chain_error->message);
1219 } else if (result != NM_AUTH_CALL_RESULT_YES) {
1220 error = g_error_new_literal (NM_SETTINGS_ERROR,
1221 NM_SETTINGS_ERROR_PERMISSION_DENIED,
1222 "Insufficient privileges.");
1225 connection = nm_auth_chain_get_data (chain, "connection");
1226 g_assert (connection);
1227 save_to_disk = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "save-to-disk"));
1228 added = nm_settings_add_connection (self, connection, save_to_disk, &error);
1231 callback = nm_auth_chain_get_data (chain, "callback");
1232 callback_data = nm_auth_chain_get_data (chain, "callback-data");
1233 subject = nm_auth_chain_get_data (chain, "subject");
1235 callback (self, added, error, context, subject, callback_data);
1237 /* Send agent-owned secrets to the agents */
1238 if (!error && added && nm_settings_has_connection (self, added))
1239 send_agent_owned_secrets (self, added, subject);
1241 g_clear_error (&error);
1242 nm_auth_chain_unref (chain);
1245 /* FIXME: remove if/when kernel supports adhoc wpa */
1247 is_adhoc_wpa (NMConnection *connection)
1249 NMSettingWireless *s_wifi;
1250 NMSettingWirelessSecurity *s_wsec;
1251 const char *mode, *key_mgmt;
1253 /* The kernel doesn't support Ad-Hoc WPA connections well at this time,
1254 * and turns them into open networks. It's been this way since at least
1255 * 2.6.30 or so; until that's fixed, disable WPA-protected Ad-Hoc networks.
1258 s_wifi = nm_connection_get_setting_wireless (connection);
1262 mode = nm_setting_wireless_get_mode (s_wifi);
1263 if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) != 0)
1266 s_wsec = nm_connection_get_setting_wireless_security (connection);
1270 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
1271 if (g_strcmp0 (key_mgmt, "wpa-none") != 0)
1278 nm_settings_add_connection_dbus (NMSettings *self,
1279 NMConnection *connection,
1280 gboolean save_to_disk,
1281 GDBusMethodInvocation *context,
1282 NMSettingsAddCallback callback,
1285 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1286 NMSettingConnection *s_con;
1287 NMAuthSubject *subject = NULL;
1289 GError *error = NULL, *tmp_error = NULL;
1290 char *error_desc = NULL;
1293 g_return_if_fail (connection != NULL);
1294 g_return_if_fail (context != NULL);
1296 /* Connection must be valid, of course */
1297 if (!nm_connection_verify (connection, &tmp_error)) {
1298 error = g_error_new (NM_SETTINGS_ERROR,
1299 NM_SETTINGS_ERROR_INVALID_CONNECTION,
1300 "The connection was invalid: %s",
1301 tmp_error->message);
1302 g_error_free (tmp_error);
1306 /* The kernel doesn't support Ad-Hoc WPA connections well at this time,
1307 * and turns them into open networks. It's been this way since at least
1308 * 2.6.30 or so; until that's fixed, disable WPA-protected Ad-Hoc networks.
1310 if (is_adhoc_wpa (connection)) {
1311 error = g_error_new_literal (NM_SETTINGS_ERROR,
1312 NM_SETTINGS_ERROR_INVALID_CONNECTION,
1313 "WPA Ad-Hoc disabled due to kernel bugs");
1317 /* Do any of the plugins support adding? */
1318 if (!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)) {
1319 error = g_error_new_literal (NM_SETTINGS_ERROR,
1320 NM_SETTINGS_ERROR_NOT_SUPPORTED,
1321 "None of the registered plugins support add.");
1325 subject = nm_auth_subject_new_unix_process_from_context (context);
1327 error = g_error_new_literal (NM_SETTINGS_ERROR,
1328 NM_SETTINGS_ERROR_PERMISSION_DENIED,
1329 "Unable to determine UID of request.");
1333 /* Ensure the caller's username exists in the connection's permissions,
1334 * or that the permissions is empty (ie, visible by everyone).
1336 if (!nm_auth_is_subject_in_acl (connection,
1339 error = g_error_new_literal (NM_SETTINGS_ERROR,
1340 NM_SETTINGS_ERROR_PERMISSION_DENIED,
1342 g_free (error_desc);
1346 /* If the caller is the only user in the connection's permissions, then
1347 * we use the 'modify.own' permission instead of 'modify.system'. If the
1348 * request affects more than just the caller, require 'modify.system'.
1350 s_con = nm_connection_get_setting_connection (connection);
1352 if (nm_setting_connection_get_num_permissions (s_con) == 1)
1353 perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN;
1355 perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM;
1357 /* Validate the user request */
1358 chain = nm_auth_chain_new_subject (subject, context, pk_add_cb, self);
1360 error = g_error_new_literal (NM_SETTINGS_ERROR,
1361 NM_SETTINGS_ERROR_PERMISSION_DENIED,
1362 "Unable to authenticate the request.");
1366 priv->auths = g_slist_append (priv->auths, chain);
1367 nm_auth_chain_add_call (chain, perm, TRUE);
1368 nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL);
1369 nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref);
1370 nm_auth_chain_set_data (chain, "callback", callback, NULL);
1371 nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);
1372 nm_auth_chain_set_data (chain, "subject", g_object_ref (subject), g_object_unref);
1373 nm_auth_chain_set_data (chain, "save-to-disk", GUINT_TO_POINTER (save_to_disk), NULL);
1377 callback (self, NULL, error, context, subject, user_data);
1379 g_clear_error (&error);
1380 g_clear_object (&subject);
1384 impl_settings_add_connection_add_cb (NMSettings *self,
1385 NMSettingsConnection *connection,
1387 GDBusMethodInvocation *context,
1388 NMAuthSubject *subject,
1392 g_dbus_method_invocation_return_gerror (context, error);
1393 nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, subject, error->message);
1395 g_dbus_method_invocation_return_value (
1397 g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection))));
1398 nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE,
1404 impl_settings_add_connection_helper (NMSettings *self,
1405 GDBusMethodInvocation *context,
1407 gboolean save_to_disk)
1409 NMConnection *connection;
1410 GError *error = NULL;
1412 connection = _nm_simple_connection_new_from_dbus (settings,
1413 NM_SETTING_PARSE_FLAGS_STRICT
1414 | NM_SETTING_PARSE_FLAGS_NORMALIZE,
1418 if (!nm_connection_verify_secrets (connection, &error))
1421 nm_settings_add_connection_dbus (self,
1425 impl_settings_add_connection_add_cb,
1427 g_object_unref (connection);
1433 g_dbus_method_invocation_take_error (context, error);
1437 impl_settings_add_connection (NMSettings *self,
1438 GDBusMethodInvocation *context,
1441 impl_settings_add_connection_helper (self, context, settings, TRUE);
1445 impl_settings_add_connection_unsaved (NMSettings *self,
1446 GDBusMethodInvocation *context,
1449 impl_settings_add_connection_helper (self, context, settings, FALSE);
1453 ensure_root (NMBusManager *dbus_mgr,
1454 GDBusMethodInvocation *context)
1457 GError *error = NULL;
1459 if (!nm_bus_manager_get_caller_info (dbus_mgr, context, NULL, &caller_uid, NULL)) {
1460 error = g_error_new_literal (NM_SETTINGS_ERROR,
1461 NM_SETTINGS_ERROR_PERMISSION_DENIED,
1462 "Unable to determine request UID.");
1463 g_dbus_method_invocation_take_error (context, error);
1466 if (caller_uid != 0) {
1467 error = g_error_new_literal (NM_SETTINGS_ERROR,
1468 NM_SETTINGS_ERROR_PERMISSION_DENIED,
1469 "Permission denied");
1470 g_dbus_method_invocation_take_error (context, error);
1478 impl_settings_load_connections (NMSettings *self,
1479 GDBusMethodInvocation *context,
1482 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1483 GPtrArray *failures;
1487 if (!ensure_root (nm_bus_manager_get (), context))
1490 failures = g_ptr_array_new ();
1492 for (i = 0; filenames[i]; i++) {
1493 for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
1494 NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
1496 if (nm_settings_plugin_load_connection (plugin, filenames[i]))
1501 if (!g_path_is_absolute (filenames[i]))
1502 _LOGW ("connection filename '%s' is not an absolute path", filenames[i]);
1503 g_ptr_array_add (failures, (char *) filenames[i]);
1507 g_ptr_array_add (failures, NULL);
1508 g_dbus_method_invocation_return_value (
1510 g_variant_new ("(b^as)",
1513 g_ptr_array_unref (failures);
1517 impl_settings_reload_connections (NMSettings *self,
1518 GDBusMethodInvocation *context)
1520 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1523 if (!ensure_root (nm_bus_manager_get (), context))
1526 for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
1527 NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
1529 nm_settings_plugin_reload_connections (plugin);
1532 g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE));
1537 NMSettingsSetHostnameCb cb;
1542 set_transient_hostname_done (GObject *object,
1546 GDBusProxy *proxy = G_DBUS_PROXY (object);
1547 gs_free SetHostnameInfo *info = user_data;
1548 gs_unref_variant GVariant *result = NULL;
1549 gs_free_error GError *error = NULL;
1551 result = g_dbus_proxy_call_finish (proxy, res, &error);
1554 _LOGW ("couldn't set the system hostname to '%s' using hostnamed: %s",
1555 info->hostname, error->message);
1558 info->cb (info->hostname, !error, info->user_data);
1559 g_free (info->hostname);
1563 nm_settings_set_transient_hostname (NMSettings *self,
1564 const char *hostname,
1565 NMSettingsSetHostnameCb cb,
1568 NMSettingsPrivate *priv;
1569 SetHostnameInfo *info;
1571 g_return_if_fail (NM_IS_SETTINGS (self));
1572 priv = NM_SETTINGS_GET_PRIVATE (self);
1574 if (!priv->hostname.hostnamed_proxy) {
1575 cb (hostname, FALSE, user_data);
1579 info = g_new0 (SetHostnameInfo, 1);
1580 info->hostname = g_strdup (hostname);
1582 info->user_data = user_data;
1584 g_dbus_proxy_call (priv->hostname.hostnamed_proxy,
1586 g_variant_new ("(sb)", hostname, FALSE),
1587 G_DBUS_CALL_FLAGS_NONE,
1590 set_transient_hostname_done,
1595 write_hostname (NMSettingsPrivate *priv, const char *hostname)
1599 gs_free_error GError *error = NULL;
1600 const char *file = priv->hostname.file;
1601 gs_free char *link_path = NULL;
1602 gs_unref_variant GVariant *var = NULL;
1603 struct stat file_stat;
1605 security_context_t se_ctx_prev = NULL, se_ctx = NULL;
1609 if (priv->hostname.hostnamed_proxy) {
1610 var = g_dbus_proxy_call_sync (priv->hostname.hostnamed_proxy,
1611 "SetStaticHostname",
1612 g_variant_new ("(sb)", hostname, FALSE),
1613 G_DBUS_CALL_FLAGS_NONE,
1618 _LOGW ("could not set hostname: %s", error->message);
1623 /* If the hostname file is a symbolic link, follow it to find where the
1624 * real file is located, otherwise g_file_set_contents will attempt to
1625 * replace the link with a plain file.
1627 if ( lstat (file, &file_stat) == 0
1628 && S_ISLNK (file_stat.st_mode)
1629 && (link_path = g_file_read_link (file, NULL)))
1633 /* Get default context for hostname file and set it for fscreate */
1634 if (stat (file, &file_stat) == 0)
1635 st_mode = file_stat.st_mode;
1636 matchpathcon (file, st_mode, &se_ctx);
1637 matchpathcon_fini ();
1638 getfscreatecon (&se_ctx_prev);
1639 setfscreatecon (se_ctx);
1642 #if defined (HOSTNAME_PERSIST_GENTOO)
1643 hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n"
1644 "hostname=\"%s\"\n", hostname);
1646 hostname_eol = g_strdup_printf ("%s\n", hostname);
1649 /* FIXME: g_file_set_contents() writes first to a temporary file
1650 * and renames it atomically. We should hack g_file_set_contents()
1651 * to set the SELINUX labels before renaming the file. */
1652 ret = g_file_set_contents (file, hostname_eol, -1, &error);
1655 /* Restore previous context and cleanup */
1656 setfscreatecon (se_ctx_prev);
1658 freecon (se_ctx_prev);
1661 g_free (hostname_eol);
1664 _LOGW ("could not save hostname to %s: %s", file, error->message);
1672 pk_hostname_cb (NMAuthChain *chain,
1673 GError *chain_error,
1674 GDBusMethodInvocation *context,
1677 NMSettings *self = NM_SETTINGS (user_data);
1678 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1679 NMAuthCallResult result;
1680 GError *error = NULL;
1681 const char *hostname;
1685 priv->auths = g_slist_remove (priv->auths, chain);
1687 result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
1689 /* If our NMSettingsConnection is already gone, do nothing */
1691 error = g_error_new (NM_SETTINGS_ERROR,
1692 NM_SETTINGS_ERROR_FAILED,
1693 "Error checking authorization: %s",
1694 chain_error->message);
1695 } else if (result != NM_AUTH_CALL_RESULT_YES) {
1696 error = g_error_new_literal (NM_SETTINGS_ERROR,
1697 NM_SETTINGS_ERROR_PERMISSION_DENIED,
1698 "Insufficient privileges.");
1700 hostname = nm_auth_chain_get_data (chain, "hostname");
1702 if (!write_hostname (priv, hostname)) {
1703 error = g_error_new_literal (NM_SETTINGS_ERROR,
1704 NM_SETTINGS_ERROR_FAILED,
1705 "Saving the hostname failed.");
1710 g_dbus_method_invocation_take_error (context, error);
1712 g_dbus_method_invocation_return_value (context, NULL);
1714 nm_auth_chain_unref (chain);
1718 validate_hostname (const char *hostname)
1721 gboolean dot = TRUE;
1723 if (!hostname || !hostname[0])
1726 for (p = hostname; *p; p++) {
1732 if (!g_ascii_isalnum (*p) && (*p != '-') && (*p != '_'))
1741 return (p - hostname <= HOST_NAME_MAX);
1745 impl_settings_save_hostname (NMSettings *self,
1746 GDBusMethodInvocation *context,
1747 const char *hostname)
1749 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1751 GError *error = NULL;
1753 /* Minimal validation of the hostname */
1754 if (!validate_hostname (hostname)) {
1755 error = g_error_new_literal (NM_SETTINGS_ERROR,
1756 NM_SETTINGS_ERROR_INVALID_HOSTNAME,
1757 "The hostname was too long or contained invalid characters.");
1761 chain = nm_auth_chain_new_context (context, pk_hostname_cb, self);
1763 error = g_error_new_literal (NM_SETTINGS_ERROR,
1764 NM_SETTINGS_ERROR_PERMISSION_DENIED,
1765 "Unable to authenticate the request.");
1769 priv->auths = g_slist_append (priv->auths, chain);
1770 nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
1771 nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free);
1775 g_dbus_method_invocation_take_error (context, error);
1779 hostname_maybe_changed (NMSettings *settings)
1781 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (settings);
1784 new_hostname = nm_settings_get_hostname (settings);
1786 if ( (new_hostname && !priv->hostname.value)
1787 || (!new_hostname && priv->hostname.value)
1788 || (priv->hostname.value && new_hostname && strcmp (priv->hostname.value, new_hostname))) {
1790 _LOGI ("hostname changed from %s%s%s to %s%s%s",
1791 NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"),
1792 NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)"));
1793 g_free (priv->hostname.value);
1794 priv->hostname.value = new_hostname;
1795 g_object_notify (G_OBJECT (settings), NM_SETTINGS_HOSTNAME);
1797 g_free (new_hostname);
1801 hostname_file_changed_cb (GFileMonitor *monitor,
1804 GFileMonitorEvent event_type,
1807 hostname_maybe_changed (user_data);
1811 have_connection_for_device (NMSettings *self, NMDevice *device)
1813 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
1814 GHashTableIter iter;
1816 NMSettingConnection *s_con;
1817 NMSettingWired *s_wired;
1818 const char *setting_hwaddr;
1819 const char *device_hwaddr;
1821 g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
1823 device_hwaddr = nm_device_get_hw_address (device);
1825 /* Find a wired connection locked to the given MAC address, if any */
1826 g_hash_table_iter_init (&iter, priv->connections);
1827 while (g_hash_table_iter_next (&iter, NULL, &data)) {
1828 NMConnection *connection = NM_CONNECTION (data);
1829 const char *ctype, *iface;
1831 if (!nm_device_check_connection_compatible (device, connection))
1834 s_con = nm_connection_get_setting_connection (connection);
1836 iface = nm_setting_connection_get_interface_name (s_con);
1837 if (iface && strcmp (iface, nm_device_get_iface (device)) != 0)
1840 ctype = nm_setting_connection_get_connection_type (s_con);
1841 if ( strcmp (ctype, NM_SETTING_WIRED_SETTING_NAME)
1842 && strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME))
1845 s_wired = nm_connection_get_setting_wired (connection);
1847 if (!s_wired && !strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) {
1848 /* No wired setting; therefore the PPPoE connection applies to any device */
1852 g_assert (s_wired != NULL);
1854 setting_hwaddr = nm_setting_wired_get_mac_address (s_wired);
1855 if (setting_hwaddr) {
1856 /* A connection mac-locked to this device */
1858 && nm_utils_hwaddr_matches (setting_hwaddr, -1, device_hwaddr, -1))
1861 /* A connection that applies to any wired device */
1866 /* See if there's a known non-NetworkManager configuration for the device */
1867 if (nm_device_spec_match_list (device, priv->unrecognized_specs))
1873 #define DEFAULT_WIRED_CONNECTION_TAG "default-wired-connection"
1874 #define DEFAULT_WIRED_DEVICE_TAG "default-wired-device"
1876 static void default_wired_clear_tag (NMSettings *self,
1878 NMSettingsConnection *connection,
1879 gboolean add_to_no_auto_default);
1882 default_wired_connection_removed_cb (NMSettingsConnection *connection, NMSettings *self)
1886 /* When the default wired connection is removed (either deleted or saved to
1887 * a new persistent connection by a plugin), write the MAC address of the
1888 * wired device to the config file and don't create a new default wired
1889 * connection for that device again.
1891 device = g_object_get_data (G_OBJECT (connection), DEFAULT_WIRED_DEVICE_TAG);
1893 default_wired_clear_tag (self, device, connection, TRUE);
1897 default_wired_connection_updated_by_user_cb (NMSettingsConnection *connection, NMSettings *self)
1901 /* The connection has been changed by the user, it should no longer be
1902 * considered a default wired connection, and should no longer affect
1903 * the no-auto-default configuration option.
1905 device = g_object_get_data (G_OBJECT (connection), DEFAULT_WIRED_DEVICE_TAG);
1907 default_wired_clear_tag (self, device, connection, FALSE);
1911 default_wired_clear_tag (NMSettings *self,
1913 NMSettingsConnection *connection,
1914 gboolean add_to_no_auto_default)
1916 g_return_if_fail (NM_IS_SETTINGS (self));
1917 g_return_if_fail (NM_IS_DEVICE (device));
1918 g_return_if_fail (NM_IS_CONNECTION (connection));
1919 g_return_if_fail (device == g_object_get_data (G_OBJECT (connection), DEFAULT_WIRED_DEVICE_TAG));
1920 g_return_if_fail (connection == g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG));
1922 g_object_set_data (G_OBJECT (connection), DEFAULT_WIRED_DEVICE_TAG, NULL);
1923 g_object_set_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG, NULL);
1925 g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_removed_cb), self);
1926 g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_updated_by_user_cb), self);
1928 if (add_to_no_auto_default)
1929 nm_config_set_no_auto_default_for_device (NM_SETTINGS_GET_PRIVATE (self)->config, device);
1933 device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
1935 NMConnection *connection;
1936 NMSettingsConnection *added;
1937 GError *error = NULL;
1939 if (!nm_device_is_real (device))
1942 g_signal_handlers_disconnect_by_func (device,
1943 G_CALLBACK (device_realized),
1946 /* If the device isn't managed or it already has a default wired connection,
1949 if ( !nm_device_get_managed (device, FALSE)
1950 || g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG)
1951 || have_connection_for_device (self, device))
1954 connection = nm_device_new_default_connection (device);
1958 /* Add the connection */
1959 added = nm_settings_add_connection (self, connection, FALSE, &error);
1960 g_object_unref (connection);
1963 _LOGW ("(%s) couldn't create default wired connection: %s",
1964 nm_device_get_iface (device),
1966 g_clear_error (&error);
1970 g_object_set_data (G_OBJECT (added), DEFAULT_WIRED_DEVICE_TAG, device);
1971 g_object_set_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG, added);
1973 g_signal_connect (added, NM_SETTINGS_CONNECTION_UPDATED_BY_USER,
1974 G_CALLBACK (default_wired_connection_updated_by_user_cb), self);
1975 g_signal_connect (added, NM_SETTINGS_CONNECTION_REMOVED,
1976 G_CALLBACK (default_wired_connection_removed_cb), self);
1978 _LOGI ("(%s): created default wired connection '%s'",
1979 nm_device_get_iface (device),
1980 nm_settings_connection_get_id (added));
1984 nm_settings_device_added (NMSettings *self, NMDevice *device)
1986 if (nm_device_is_real (device))
1987 device_realized (device, NULL, self);
1989 g_signal_connect_after (device, "notify::" NM_DEVICE_REAL,
1990 G_CALLBACK (device_realized),
1996 nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quitting)
1998 NMSettingsConnection *connection;
2000 g_signal_handlers_disconnect_by_func (device,
2001 G_CALLBACK (device_realized),
2004 connection = g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG);
2006 default_wired_clear_tag (self, device, connection, FALSE);
2008 /* Don't delete the default wired connection on shutdown, so that it
2009 * remains up and can be assumed if NM starts again.
2011 if (quitting == FALSE)
2012 nm_settings_connection_delete (connection, NULL, NULL);
2016 /***************************************************************/
2018 /* GCompareFunc helper for sorting "best" connections.
2019 * The function sorts connections in ascending timestamp order.
2020 * That means an older connection (lower timestamp) goes before
2024 nm_settings_sort_connections (gconstpointer a, gconstpointer b)
2026 NMSettingsConnection *ac = (NMSettingsConnection *) a;
2027 NMSettingsConnection *bc = (NMSettingsConnection *) b;
2028 guint64 ats = 0, bts = 0;
2037 /* In the future we may use connection priorities in addition to timestamps */
2038 nm_settings_connection_get_timestamp (ac, &ats);
2039 nm_settings_connection_get_timestamp (bc, &bts);
2049 get_best_connections (NMConnectionProvider *provider,
2050 guint max_requested,
2053 NMConnectionFilterFunc func,
2056 NMSettings *self = NM_SETTINGS (provider);
2057 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
2058 GSList *sorted = NULL;
2059 GHashTableIter iter;
2060 NMSettingsConnection *connection;
2064 g_hash_table_iter_init (&iter, priv->connections);
2065 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) {
2068 if (ctype1 && !nm_connection_is_type (NM_CONNECTION (connection), ctype1))
2070 if (ctype2 && !nm_connection_is_type (NM_CONNECTION (connection), ctype2))
2072 if (func && !func (provider, NM_CONNECTION (connection), func_data))
2075 /* Don't bother with a connection that's older than the oldest one in the list */
2076 if (max_requested && added >= max_requested) {
2077 nm_settings_connection_get_timestamp (connection, &cur_ts);
2078 if (cur_ts <= oldest)
2082 /* List is sorted with oldest first */
2083 sorted = g_slist_insert_sorted (sorted, connection, nm_settings_sort_connections);
2086 if (max_requested && added > max_requested) {
2087 /* Over the limit, remove the oldest one */
2088 sorted = g_slist_delete_link (sorted, sorted);
2092 nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (sorted->data), &oldest);
2095 return g_slist_reverse (sorted);
2098 static const GSList *
2099 get_connections (NMConnectionProvider *provider)
2101 GSList *list = NULL;
2102 NMSettings *self = NM_SETTINGS (provider);
2103 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
2105 list = _nm_utils_hash_values_to_slist (priv->connections);
2107 /* Cache the list every call so we can keep it 'const' for callers */
2108 g_slist_free (priv->get_connections_cache);
2109 priv->get_connections_cache = list;
2113 static NMConnection *
2114 cp_get_connection_by_uuid (NMConnectionProvider *provider, const char *uuid)
2116 return NM_CONNECTION (nm_settings_get_connection_by_uuid (NM_SETTINGS (provider), uuid));
2119 /***************************************************************/
2122 nm_settings_get_startup_complete (NMSettings *self)
2124 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
2126 return priv->startup_complete;
2129 /***************************************************************/
2132 hostnamed_properties_changed (GDBusProxy *proxy,
2133 GVariant *changed_properties,
2134 char **invalidated_properties,
2137 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (user_data);
2138 GVariant *v_hostname;
2139 const char *hostname;
2141 v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy,
2146 hostname = g_variant_get_string (v_hostname, NULL);
2148 if (g_strcmp0 (priv->hostname.value, hostname) != 0) {
2149 _LOGI ("hostname changed from %s%s%s to %s%s%s",
2150 NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"),
2151 NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)"));
2152 g_free (priv->hostname.value);
2153 priv->hostname.value = g_strdup (hostname);
2154 g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME);
2155 nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL);
2158 g_variant_unref (v_hostname);
2162 setup_hostname_file_monitors (NMSettings *self)
2164 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
2165 GFileMonitor *monitor;
2168 priv->hostname.file = HOSTNAME_FILE;
2169 priv->hostname.value = nm_settings_get_hostname (self);
2171 /* monitor changes to hostname file */
2172 file = g_file_new_for_path (priv->hostname.file);
2173 monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
2174 g_object_unref (file);
2176 priv->hostname.monitor_id = g_signal_connect (monitor, "changed",
2177 G_CALLBACK (hostname_file_changed_cb),
2179 priv->hostname.monitor = monitor;
2182 #if defined (HOSTNAME_PERSIST_SUSE)
2183 /* monitor changes to dhcp file to know whether the hostname is valid */
2184 file = g_file_new_for_path (CONF_DHCP);
2185 monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
2186 g_object_unref (file);
2188 priv->hostname.dhcp_monitor_id = g_signal_connect (monitor, "changed",
2189 G_CALLBACK (hostname_file_changed_cb),
2191 priv->hostname.dhcp_monitor = monitor;
2195 hostname_maybe_changed (self);
2199 nm_settings_new (void)
2202 NMSettingsPrivate *priv;
2204 self = g_object_new (NM_TYPE_SETTINGS, NULL);
2206 priv = NM_SETTINGS_GET_PRIVATE (self);
2208 priv->config = nm_config_get ();
2210 nm_exported_object_export (NM_EXPORTED_OBJECT (self));
2215 nm_settings_start (NMSettings *self, GError **error)
2217 NMSettingsPrivate *priv;
2220 GError *local_error = NULL;
2222 priv = NM_SETTINGS_GET_PRIVATE (self);
2224 /* Load the plugins; fail if a plugin is not found. */
2225 if (!load_plugins (self, nm_config_get_plugins (priv->config), error)) {
2226 g_object_unref (self);
2230 load_connections (self);
2231 check_startup_complete (self);
2233 proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL,
2234 HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH,
2235 HOSTNAMED_SERVICE_INTERFACE, NULL, &local_error);
2237 variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname");
2239 _LOGI ("hostname: using hostnamed");
2240 priv->hostname.hostnamed_proxy = proxy;
2241 g_signal_connect (proxy, "g-properties-changed",
2242 G_CALLBACK (hostnamed_properties_changed), self);
2243 hostnamed_properties_changed (proxy, NULL, NULL, self);
2244 g_variant_unref (variant);
2246 _LOGI ("hostname: couldn't get property from hostnamed");
2247 g_object_unref (proxy);
2250 _LOGI ("hostname: hostnamed not used as proxy creation failed with: %s",
2251 local_error->message);
2252 g_clear_error (&local_error);
2255 if (!priv->hostname.hostnamed_proxy)
2256 setup_hostname_file_monitors (self);
2258 priv->started = TRUE;
2259 g_object_notify (G_OBJECT (self), NM_SETTINGS_HOSTNAME);
2264 connection_provider_iface_init (NMConnectionProviderInterface *cp_iface)
2266 cp_iface->get_best_connections = get_best_connections;
2267 cp_iface->get_connections = get_connections;
2268 cp_iface->add_connection = _nm_connection_provider_add_connection;
2269 cp_iface->get_connection_by_uuid = cp_get_connection_by_uuid;
2273 nm_settings_init (NMSettings *self)
2275 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
2277 priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
2279 /* Hold a reference to the agent manager so it stays alive; the only
2280 * other holders are NMSettingsConnection objects which are often
2281 * transient, and we don't want the agent manager to get destroyed and
2284 priv->agent_mgr = g_object_ref (nm_agent_manager_get ());
2286 g_signal_connect (priv->agent_mgr, "agent-registered", G_CALLBACK (secret_agent_registered), self);
2290 dispose (GObject *object)
2292 NMSettings *self = NM_SETTINGS (object);
2293 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
2295 g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_unref);
2298 g_object_unref (priv->agent_mgr);
2300 if (priv->hostname.hostnamed_proxy) {
2301 g_signal_handlers_disconnect_by_func (priv->hostname.hostnamed_proxy,
2302 G_CALLBACK (hostnamed_properties_changed),
2304 g_clear_object (&priv->hostname.hostnamed_proxy);
2307 if (priv->hostname.monitor) {
2308 if (priv->hostname.monitor_id)
2309 g_signal_handler_disconnect (priv->hostname.monitor, priv->hostname.monitor_id);
2311 g_file_monitor_cancel (priv->hostname.monitor);
2312 g_clear_object (&priv->hostname.monitor);
2315 if (priv->hostname.dhcp_monitor) {
2316 if (priv->hostname.dhcp_monitor_id)
2317 g_signal_handler_disconnect (priv->hostname.dhcp_monitor,
2318 priv->hostname.dhcp_monitor_id);
2320 g_file_monitor_cancel (priv->hostname.dhcp_monitor);
2321 g_clear_object (&priv->hostname.dhcp_monitor);
2324 g_clear_pointer (&priv->hostname.value, g_free);
2326 G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object);
2330 finalize (GObject *object)
2332 NMSettings *self = NM_SETTINGS (object);
2333 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
2335 g_hash_table_destroy (priv->connections);
2336 g_slist_free (priv->get_connections_cache);
2338 g_slist_free_full (priv->unmanaged_specs, g_free);
2339 g_slist_free_full (priv->unrecognized_specs, g_free);
2341 g_slist_free_full (priv->plugins, g_object_unref);
2343 G_OBJECT_CLASS (nm_settings_parent_class)->finalize (object);
2347 get_property (GObject *object, guint prop_id,
2348 GValue *value, GParamSpec *pspec)
2350 NMSettings *self = NM_SETTINGS (object);
2351 NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
2352 const GSList *specs, *iter;
2353 GHashTableIter citer;
2358 case PROP_UNMANAGED_SPECS:
2359 array = g_ptr_array_new ();
2360 specs = nm_settings_get_unmanaged_specs (self);
2361 for (iter = specs; iter; iter = g_slist_next (iter))
2362 g_ptr_array_add (array, g_strdup (iter->data));
2363 g_ptr_array_add (array, NULL);
2364 g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE));
2367 g_value_take_string (value, nm_settings_get_hostname (self));
2369 /* Don't ever pass NULL through D-Bus */
2370 if (!g_value_get_string (value))
2371 g_value_set_static_string (value, "");
2373 case PROP_CAN_MODIFY:
2374 g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS));
2376 case PROP_CONNECTIONS:
2377 array = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1);
2378 g_hash_table_iter_init (&citer, priv->connections);
2379 while (g_hash_table_iter_next (&citer, (gpointer) &path, NULL))
2380 g_ptr_array_add (array, g_strdup (path));
2381 g_ptr_array_add (array, NULL);
2382 g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE));
2384 case PROP_STARTUP_COMPLETE:
2385 g_value_set_boolean (value, nm_settings_get_startup_complete (self));
2388 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2394 nm_settings_class_init (NMSettingsClass *class)
2396 GObjectClass *object_class = G_OBJECT_CLASS (class);
2397 NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (class);
2399 g_type_class_add_private (class, sizeof (NMSettingsPrivate));
2401 exported_object_class->export_path = NM_DBUS_PATH_SETTINGS;
2403 /* virtual methods */
2404 object_class->get_property = get_property;
2405 object_class->dispose = dispose;
2406 object_class->finalize = finalize;
2410 g_object_class_install_property
2411 (object_class, PROP_UNMANAGED_SPECS,
2412 g_param_spec_boxed (NM_SETTINGS_UNMANAGED_SPECS, "", "",
2415 G_PARAM_STATIC_STRINGS));
2417 g_object_class_install_property
2418 (object_class, PROP_HOSTNAME,
2419 g_param_spec_string (NM_SETTINGS_HOSTNAME, "", "",
2422 G_PARAM_STATIC_STRINGS));
2424 g_object_class_install_property
2425 (object_class, PROP_CAN_MODIFY,
2426 g_param_spec_boolean (NM_SETTINGS_CAN_MODIFY, "", "",
2429 G_PARAM_STATIC_STRINGS));
2431 g_object_class_install_property
2432 (object_class, PROP_CONNECTIONS,
2433 g_param_spec_boxed (NM_SETTINGS_CONNECTIONS, "", "",
2436 G_PARAM_STATIC_STRINGS));
2439 signals[CONNECTION_ADDED] =
2440 g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
2441 G_OBJECT_CLASS_TYPE (object_class),
2443 G_STRUCT_OFFSET (NMSettingsClass, connection_added),
2445 g_cclosure_marshal_VOID__OBJECT,
2446 G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
2448 signals[CONNECTION_UPDATED] =
2449 g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
2450 G_OBJECT_CLASS_TYPE (object_class),
2452 G_STRUCT_OFFSET (NMSettingsClass, connection_updated),
2454 g_cclosure_marshal_VOID__OBJECT,
2455 G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
2457 signals[CONNECTION_UPDATED_BY_USER] =
2458 g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER,
2459 G_OBJECT_CLASS_TYPE (object_class),
2463 g_cclosure_marshal_VOID__OBJECT,
2464 G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
2466 signals[CONNECTION_REMOVED] =
2467 g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
2468 G_OBJECT_CLASS_TYPE (object_class),
2470 G_STRUCT_OFFSET (NMSettingsClass, connection_removed),
2472 g_cclosure_marshal_VOID__OBJECT,
2473 G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
2475 signals[CONNECTION_VISIBILITY_CHANGED] =
2476 g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED,
2477 G_OBJECT_CLASS_TYPE (object_class),
2479 G_STRUCT_OFFSET (NMSettingsClass, connection_visibility_changed),
2481 g_cclosure_marshal_VOID__OBJECT,
2482 G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
2484 signals[AGENT_REGISTERED] =
2485 g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED,
2486 G_OBJECT_CLASS_TYPE (object_class),
2488 G_STRUCT_OFFSET (NMSettingsClass, agent_registered),
2490 g_cclosure_marshal_VOID__OBJECT,
2491 G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT);
2494 signals[NEW_CONNECTION] =
2495 g_signal_new ("new-connection",
2496 G_OBJECT_CLASS_TYPE (object_class),
2497 G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
2498 g_cclosure_marshal_VOID__OBJECT,
2499 G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
2501 nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class),
2502 NMDBUS_TYPE_SETTINGS_SKELETON,
2503 "ListConnections", impl_settings_list_connections,
2504 "GetConnectionByUuid", impl_settings_get_connection_by_uuid,
2505 "AddConnection", impl_settings_add_connection,
2506 "AddConnectionUnsaved", impl_settings_add_connection_unsaved,
2507 "LoadConnections", impl_settings_load_connections,
2508 "ReloadConnections", impl_settings_reload_connections,
2509 "SaveHostname", impl_settings_save_hostname,