diff options
| author | Michael Biebl <biebl@debian.org> | 2016-01-20 16:26:51 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2016-01-20 16:26:51 +0100 |
| commit | 494f296a3baab08522617b24b1f126d8f9a17502 (patch) | |
| tree | c8ef32fb0dd1c4ff35a0b38e787abb58692de0cd /src/settings/nm-settings.c | |
| parent | 54f6333410ffd570e62717d9e77c5c987175e397 (diff) | |
Imported Upstream version 1.1.90 upstream/1.1.90
Diffstat (limited to 'src/settings/nm-settings.c')
| -rw-r--r-- | src/settings/nm-settings.c | 1017 |
1 files changed, 661 insertions, 356 deletions
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index f20bc71b..f6f8c374 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -31,10 +31,11 @@ #include <string.h> #include <gmodule.h> #include <pwd.h> -#include <dbus/dbus.h> -#include <dbus/dbus-glib-lowlevel.h> -#include "gsystem-local-alloc.h" +#if HAVE_SELINUX +#include <selinux/selinux.h> +#endif + #include <nm-dbus-interface.h> #include <nm-connection.h> #include <nm-setting-8021x.h> @@ -58,12 +59,11 @@ #include "nm-core-internal.h" #include "nm-device-ethernet.h" -#include "nm-dbus-glib-types.h" #include "nm-settings.h" #include "nm-settings-connection.h" -#include "nm-system-config-interface.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" +#include "nm-settings-plugin.h" +#include "nm-default.h" +#include "nm-bus-manager.h" #include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "nm-session-monitor.h" @@ -71,7 +71,11 @@ #include "nm-agent-manager.h" #include "nm-connection-provider.h" #include "nm-config.h" +#include "nm-audit-manager.h" #include "NetworkManagerUtils.h" +#include "nm-dispatcher.h" + +#include "nmdbus-settings.h" #define LOG(level, ...) \ G_STMT_START { \ @@ -94,52 +98,39 @@ EXPORT(nm_settings_connection_replace_settings) EXPORT(nm_settings_connection_replace_and_commit) /* END LINKER CRACKROCK */ -#define PLUGIN_MODULE_PATH "plugin-module-path" - -static void claim_connection (NMSettings *self, - NMSettingsConnection *connection); - -static gboolean impl_settings_list_connections (NMSettings *self, - GPtrArray **connections, - GError **error); - -static void impl_settings_get_connection_by_uuid (NMSettings *self, - const char *uuid, - DBusGMethodInvocation *context); +#define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1" +#define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1" +#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1" -static void impl_settings_add_connection (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context); +#define HOSTNAME_FILE_DEFAULT "/etc/hostname" +#define HOSTNAME_FILE_SUSE "/etc/HOSTNAME" +#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname" +#define IFCFG_DIR SYSCONFDIR "/sysconfig/network" +#define CONF_DHCP IFCFG_DIR "/dhcp" -static void impl_settings_add_connection_unsaved (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context); - -static void impl_settings_load_connections (NMSettings *self, - char **filenames, - DBusGMethodInvocation *context); - -static void impl_settings_reload_connections (NMSettings *self, - DBusGMethodInvocation *context); +#define PLUGIN_MODULE_PATH "plugin-module-path" -static void impl_settings_save_hostname (NMSettings *self, - const char *hostname, - DBusGMethodInvocation *context); +#if defined(HOSTNAME_PERSIST_SUSE) +#define HOSTNAME_FILE HOSTNAME_FILE_SUSE +#elif defined(HOSTNAME_PERSIST_GENTOO) +#define HOSTNAME_FILE HOSTNAME_FILE_GENTOO +#else +#define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT +#endif -#include "nm-settings-glue.h" +static void claim_connection (NMSettings *self, + NMSettingsConnection *connection); -static void unmanaged_specs_changed (NMSystemConfigInterface *config, gpointer user_data); -static void unrecognized_specs_changed (NMSystemConfigInterface *config, gpointer user_data); +static void unmanaged_specs_changed (NMSettingsPlugin *config, gpointer user_data); +static void unrecognized_specs_changed (NMSettingsPlugin *config, gpointer user_data); -static void connection_provider_init (NMConnectionProvider *cp_class); +static void connection_provider_iface_init (NMConnectionProviderInterface *cp_iface); -G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_init)) +G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, NM_TYPE_EXPORTED_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_iface_init)) typedef struct { - NMDBusManager *dbus_mgr; - NMAgentManager *agent_mgr; NMConfig *config; @@ -153,13 +144,23 @@ typedef struct { GSList *unrecognized_specs; GSList *get_connections_cache; + gboolean started; gboolean startup_complete; + + struct { + char *value; + char *file; + GFileMonitor *monitor; + GFileMonitor *dhcp_monitor; + gulong monitor_id; + gulong dhcp_monitor_id; + GDBusProxy *hostnamed_proxy; + } hostname; } NMSettingsPrivate; #define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate)) enum { - PROPERTIES_CHANGED, CONNECTION_ADDED, CONNECTION_UPDATED, CONNECTION_UPDATED_BY_USER, @@ -215,7 +216,7 @@ connection_ready_changed (NMSettingsConnection *conn, } static void -plugin_connection_added (NMSystemConfigInterface *config, +plugin_connection_added (NMSettingsPlugin *config, NMSettingsConnection *connection, gpointer user_data) { @@ -229,11 +230,11 @@ load_connections (NMSettings *self) GSList *iter; for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); GSList *plugin_connections; GSList *elt; - plugin_connections = nm_system_config_interface_get_connections (plugin); + plugin_connections = nm_settings_plugin_get_connections (plugin); // FIXME: ensure connections from plugins loaded with a lower priority // get rejected when they conflict with connections from a higher @@ -244,11 +245,11 @@ load_connections (NMSettings *self) g_slist_free (plugin_connections); - g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, + g_signal_connect (plugin, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, G_CALLBACK (plugin_connection_added), self); - g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED, + g_signal_connect (plugin, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED, G_CALLBACK (unmanaged_specs_changed), self); - g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED, + g_signal_connect (plugin, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED, G_CALLBACK (unrecognized_specs_changed), self); } @@ -277,20 +278,24 @@ nm_settings_for_each_connection (NMSettings *self, for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data); } -static gboolean +static void impl_settings_list_connections (NMSettings *self, - GPtrArray **connections, - GError **error) + GDBusMethodInvocation *context) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GPtrArray *connections; GHashTableIter iter; gpointer key; - *connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); + connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, &key, NULL)) - g_ptr_array_add (*connections, g_strdup ((const char *) key)); - return TRUE; + g_ptr_array_add (connections, key); + g_ptr_array_add (connections, NULL); + + g_dbus_method_invocation_return_value (context, + g_variant_new ("(^ao)", connections->pdata)); + g_ptr_array_unref (connections); } NMSettingsConnection * @@ -307,7 +312,7 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid) g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) { - if (g_strcmp0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate))) == 0) + if (g_strcmp0 (uuid, nm_settings_connection_get_uuid (candidate)) == 0) return candidate; } @@ -316,8 +321,8 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid) static void impl_settings_get_connection_by_uuid (NMSettings *self, - const char *uuid, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + const char *uuid) { NMSettingsConnection *connection = NULL; NMAuthSubject *subject = NULL; @@ -341,7 +346,6 @@ impl_settings_get_connection_by_uuid (NMSettings *self, } if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection), - nm_session_monitor_get (), subject, &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, @@ -352,13 +356,14 @@ impl_settings_get_connection_by_uuid (NMSettings *self, } g_clear_object (&subject); - dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection))); + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection)))); return; error: g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); g_clear_object (&subject); } @@ -424,53 +429,8 @@ nm_settings_get_connection_by_path (NMSettings *self, const char *path) return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path); } -static char* -uscore_to_wincaps (const char *uscore) -{ - const char *p; - GString *str; - gboolean last_was_uscore; - - last_was_uscore = TRUE; - - str = g_string_new (NULL); - p = uscore; - while (p && *p) { - if (*p == '-' || *p == '_') - last_was_uscore = TRUE; - else { - if (last_was_uscore) { - g_string_append_c (str, g_ascii_toupper (*p)); - last_was_uscore = FALSE; - } else - g_string_append_c (str, *p); - } - ++p; - } - - return g_string_free (str, FALSE); -} - -static void -notify (GObject *object, GParamSpec *pspec) -{ - GValue *value; - GHashTable *hash; - - value = g_slice_new0 (GValue); - hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); - - g_value_init (value, pspec->value_type); - g_object_get_property (object, pspec->name, value); - g_hash_table_insert (hash, uscore_to_wincaps (pspec->name), value); - g_signal_emit (object, signals[PROPERTIES_CHANGED], 0, hash); - g_hash_table_destroy (hash); - g_value_unset (value); - g_slice_free (GValue, value); -} - gboolean -nm_settings_has_connection (NMSettings *self, NMConnection *connection) +nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GHashTableIter iter; @@ -492,7 +452,7 @@ nm_settings_get_unmanaged_specs (NMSettings *self) return priv->unmanaged_specs; } -static NMSystemConfigInterface * +static NMSettingsPlugin * get_plugin (NMSettings *self, guint32 capability) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); @@ -500,42 +460,109 @@ get_plugin (NMSettings *self, guint32 capability) g_return_val_if_fail (self != NULL, NULL); - /* Do any of the plugins support setting the hostname? */ + /* Do any of the plugins support the given capability? */ for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; + NMSettingsPluginCapabilities caps = NM_SETTINGS_PLUGIN_CAP_NONE; - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); + g_object_get (G_OBJECT (iter->data), NM_SETTINGS_PLUGIN_CAPABILITIES, &caps, NULL); if (NM_FLAGS_ALL (caps, capability)) - return NM_SYSTEM_CONFIG_INTERFACE (iter->data); + return NM_SETTINGS_PLUGIN (iter->data); } return NULL; } +#if defined(HOSTNAME_PERSIST_GENTOO) +static gchar * +read_hostname_gentoo (const char *path) +{ + gchar *contents = NULL, *result = NULL, *tmp; + gchar **all_lines = NULL; + guint line_num, i; + + if (!g_file_get_contents (path, &contents, NULL, NULL)) + return NULL; + all_lines = g_strsplit (contents, "\n", 0); + line_num = g_strv_length (all_lines); + for (i = 0; i < line_num; i++) { + g_strstrip (all_lines[i]); + if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') + continue; + if (g_str_has_prefix (all_lines[i], "hostname=")) { + tmp = &all_lines[i][STRLEN ("hostname=")]; + result = g_shell_unquote (tmp, NULL); + break; + } + } + g_strfreev (all_lines); + g_free (contents); + return result; +} +#endif + +#if defined(HOSTNAME_PERSIST_SUSE) +static gboolean +hostname_is_dynamic (void) +{ + GIOChannel *channel; + char *str = NULL; + gboolean dynamic = FALSE; + + channel = g_io_channel_new_file (CONF_DHCP, "r", NULL); + if (!channel) + return dynamic; + + while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) { + if (str) { + g_strstrip (str); + if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME=")) + dynamic = strcmp (&str[STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0; + g_free (str); + } + } + + g_io_channel_shutdown (channel, FALSE, NULL); + g_io_channel_unref (channel); + + return dynamic; +} +#endif + /* Returns an allocated string which the caller owns and must eventually free */ char * nm_settings_get_hostname (NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GSList *iter; char *hostname = NULL; - /* Hostname returned is the hostname returned from the first plugin - * that provides one. - */ - for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, &hostname, NULL); - if (hostname && strlen (hostname)) - return hostname; - g_free (hostname); - } + if (!priv->started) + return NULL; + + if (priv->hostname.hostnamed_proxy) { + hostname = g_strdup (priv->hostname.value); + goto out; } - return NULL; +#if defined(HOSTNAME_PERSIST_GENTOO) + hostname = read_hostname_gentoo (priv->hostname.file); +#else + +#if defined(HOSTNAME_PERSIST_SUSE) + if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ()) + return NULL; +#endif + if (g_file_get_contents (priv->hostname.file, &hostname, NULL, NULL)) + g_strchomp (hostname); + +#endif /* HOSTNAME_PERSIST_GENTOO */ + +out: + if (hostname && !hostname[0]) { + g_free (hostname); + hostname = NULL; + } + + return hostname; } static gboolean @@ -552,7 +579,7 @@ find_spec (GSList *spec_list, const char *spec) static void update_specs (NMSettings *self, GSList **specs_ptr, - GSList * (*get_specs_func) (NMSystemConfigInterface *)) + GSList * (*get_specs_func) (NMSettingsPlugin *)) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; @@ -563,7 +590,7 @@ update_specs (NMSettings *self, GSList **specs_ptr, for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { GSList *specs, *specs_iter; - specs = get_specs_func (NM_SYSTEM_CONFIG_INTERFACE (iter->data)); + specs = get_specs_func (NM_SETTINGS_PLUGIN (iter->data)); for (specs_iter = specs; specs_iter; specs_iter = specs_iter->next) { if (!find_spec (*specs_ptr, (const char *) specs_iter->data)) { *specs_ptr = g_slist_prepend (*specs_ptr, specs_iter->data); @@ -576,58 +603,52 @@ update_specs (NMSettings *self, GSList **specs_ptr, } static void -unmanaged_specs_changed (NMSystemConfigInterface *config, +unmanaged_specs_changed (NMSettingsPlugin *config, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); update_specs (self, &priv->unmanaged_specs, - nm_system_config_interface_get_unmanaged_specs); + nm_settings_plugin_get_unmanaged_specs); g_object_notify (G_OBJECT (self), NM_SETTINGS_UNMANAGED_SPECS); } static void -unrecognized_specs_changed (NMSystemConfigInterface *config, +unrecognized_specs_changed (NMSettingsPlugin *config, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); update_specs (self, &priv->unrecognized_specs, - nm_system_config_interface_get_unrecognized_specs); -} - -static void -hostname_changed (NMSystemConfigInterface *config, - GParamSpec *pspec, - gpointer user_data) -{ - g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME); + nm_settings_plugin_get_unrecognized_specs); } -static void -add_plugin (NMSettings *self, NMSystemConfigInterface *plugin) +static gboolean +add_plugin (NMSettings *self, NMSettingsPlugin *plugin) { NMSettingsPrivate *priv; char *pname = NULL; char *pinfo = NULL; const char *path; - g_return_if_fail (NM_IS_SETTINGS (self)); - g_return_if_fail (NM_IS_SYSTEM_CONFIG_INTERFACE (plugin)); + g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); + g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (plugin), FALSE); priv = NM_SETTINGS_GET_PRIVATE (self); - priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin)); - - g_signal_connect (plugin, "notify::hostname", G_CALLBACK (hostname_changed), self); + if (g_slist_find (priv->plugins, plugin)) { + /* don't add duplicates. */ + return FALSE; + } - nm_system_config_interface_init (plugin, NULL); + priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin)); + nm_settings_plugin_init (plugin); g_object_get (G_OBJECT (plugin), - NM_SYSTEM_CONFIG_INTERFACE_NAME, &pname, - NM_SYSTEM_CONFIG_INTERFACE_INFO, &pinfo, + NM_SETTINGS_PLUGIN_NAME, &pname, + NM_SETTINGS_PLUGIN_INFO, &pinfo, NULL); path = g_object_get_data (G_OBJECT (plugin), PLUGIN_MODULE_PATH); @@ -636,6 +657,8 @@ add_plugin (NMSettings *self, NMSystemConfigInterface *plugin) NM_PRINT_FMT_QUOTED (path, " (", path, ")", "")); g_free (pname); g_free (pinfo); + + return TRUE; } static GObject * @@ -647,11 +670,11 @@ find_plugin (GSList *list, const char *pname) g_return_val_if_fail (pname != NULL, NULL); for (iter = list; iter && !obj; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); char *list_pname = NULL; g_object_get (G_OBJECT (plugin), - NM_SYSTEM_CONFIG_INTERFACE_NAME, + NM_SETTINGS_PLUGIN_NAME, &list_pname, NULL); if (list_pname && !strcmp (pname, list_pname)) @@ -666,11 +689,12 @@ find_plugin (GSList *list, const char *pname) static void add_keyfile_plugin (NMSettings *self) { - GObject *keyfile_plugin; + gs_unref_object GObject *keyfile_plugin = NULL; keyfile_plugin = nm_settings_keyfile_plugin_new (); g_assert (keyfile_plugin); - add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (keyfile_plugin)); + if (!add_plugin (self, NM_SETTINGS_PLUGIN (keyfile_plugin))) + g_return_if_reached (); } static gboolean @@ -680,26 +704,34 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) const char **iter; gboolean keyfile_added = FALSE; gboolean success = TRUE; + gboolean add_ibft = FALSE; + gboolean has_no_ibft; + gssize idx_no_ibft, idx_ibft; + + idx_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "ibft"); + idx_no_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "no-ibft"); + has_no_ibft = idx_no_ibft >= 0 && idx_no_ibft > idx_ibft; +#if WITH_SETTINGS_PLUGIN_IBFT + add_ibft = idx_no_ibft < 0 && idx_ibft < 0; +#endif for (iter = plugins; iter && *iter; iter++) { - GModule *plugin; - gs_free char *full_name = NULL; - gs_free char *path = NULL; - const char *pname; + const char *pname = *iter; GObject *obj; - GObject * (*factory_func) (void); - struct stat st; - int errsv; - - pname = *iter; if (!*pname || strchr (pname, '/')) { LOG (LOGL_WARN, "ignore invalid plugin \"%s\"", pname); continue; } - obj = find_plugin (list, pname); - if (obj) + if (!strcmp (pname, "ifcfg-suse")) { + LOG (LOGL_WARN, "skipping deprecated plugin ifcfg-suse"); + continue; + } + + if (!strcmp (pname, "no-ibft")) + continue; + if (has_no_ibft && !strcmp (pname, "ibft")) continue; /* keyfile plugin is built-in now */ @@ -711,61 +743,92 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) continue; } - full_name = g_strdup_printf ("nm-settings-plugin-%s", pname); - path = g_module_build_path (NMPLUGINDIR, full_name); - - if (stat (path, &st) != 0) { - errsv = errno; - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv)); - continue; - } - if (!S_ISREG (st.st_mode)) { - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': not a file", pname, path); - continue; - } - if (st.st_uid != 0) { - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': file must be owned by root", pname, path); - continue; - } - if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': invalid file permissions", pname, path); + if (_nm_utils_strv_find_first ((char **) plugins, + iter - plugins, + pname) >= 0) { + /* the plugin is already mentioned in the list previously. + * Don't load a duplicate. */ continue; } - plugin = g_module_open (path, G_MODULE_BIND_LOCAL); - if (!plugin) { - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", - pname, path, g_module_error ()); + if (find_plugin (list, pname)) continue; - } - /* errors after this point are fatal, because we loaded the shared library already. */ +load_plugin: + { + GModule *plugin; + gs_free char *full_name = NULL; + gs_free char *path = NULL; + GObject * (*factory_func) (void); + struct stat st; + int errsv; + + full_name = g_strdup_printf ("nm-settings-plugin-%s", pname); + path = g_module_build_path (NMPLUGINDIR, full_name); + + if (stat (path, &st) != 0) { + errsv = errno; + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv)); + goto next; + } + if (!S_ISREG (st.st_mode)) { + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': not a file", pname, path); + goto next; + } + if (st.st_uid != 0) { + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': file must be owned by root", pname, path); + goto next; + } + if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': invalid file permissions", pname, path); + goto next; + } - if (!g_module_symbol (plugin, "nm_system_config_factory", (gpointer) (&factory_func))) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Could not find plugin '%s' factory function.", - pname); - success = FALSE; - g_module_close (plugin); - break; - } + plugin = g_module_open (path, G_MODULE_BIND_LOCAL); + if (!plugin) { + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", + pname, path, g_module_error ()); + goto next; + } - obj = (*factory_func) (); - if (!obj || !NM_IS_SYSTEM_CONFIG_INTERFACE (obj)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Plugin '%s' returned invalid system config object.", - pname); - success = FALSE; - g_module_close (plugin); - break; - } + /* errors after this point are fatal, because we loaded the shared library already. */ - g_module_make_resident (plugin); - g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin); - g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free); - path = NULL; - add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (obj)); - list = g_slist_append (list, obj); + if (!g_module_symbol (plugin, "nm_settings_plugin_factory", (gpointer) (&factory_func))) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Could not find plugin '%s' factory function.", + pname); + success = FALSE; + g_module_close (plugin); + break; + } + + obj = (*factory_func) (); + if (!obj || !NM_IS_SETTINGS_PLUGIN (obj)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Plugin '%s' returned invalid system config object.", + pname); + success = FALSE; + g_module_close (plugin); + break; + } + + g_module_make_resident (plugin); + g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin); + g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free); + path = NULL; + if (add_plugin (self, NM_SETTINGS_PLUGIN (obj))) + list = g_slist_append (list, obj); + else + g_object_unref (obj); + } +next: + if (add_ibft && !strcmp (pname, "ifcfg-rh")) { + /* The plugin ibft is not explicitly mentioned but we just enabled "ifcfg-rh". + * Enable "ibft" by default after "ifcfg-rh". */ + pname = "ibft"; + add_ibft = FALSE; + goto load_plugin; + } } /* If keyfile plugin was not among configured plugins, add it as the last one */ @@ -819,7 +882,6 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) if (!g_hash_table_lookup (priv->connections, cpath)) g_return_if_reached (); - g_object_ref (connection); /* Disconnect signal handlers, as plugins might still keep references @@ -832,6 +894,7 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated_by_user), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_visibility_changed), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self); + g_object_unref (self); /* Forget about the connection internally */ g_hash_table_remove (priv->connections, (gpointer) cpath); @@ -842,6 +905,8 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) /* Re-emit for listeners like NMPolicy */ g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_REMOVED, connection); g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS); + if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (connection))) + nm_exported_object_unexport (NM_EXPORTED_OBJECT (connection)); check_startup_complete (self); @@ -904,11 +969,10 @@ static void claim_connection (NMSettings *self, NMSettingsConnection *connection) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - static guint32 ec_counter = 0; GError *error = NULL; GHashTableIter iter; gpointer data; - char *path; + const char *path; NMSettingsConnection *existing; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); @@ -928,7 +992,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) return; } - existing = nm_settings_get_connection_by_uuid (self, nm_connection_get_uuid (NM_CONNECTION (connection))); + existing = nm_settings_get_connection_by_uuid (self, nm_settings_connection_get_uuid (connection)); if (existing) { /* Cannot add duplicate connections per UUID. Just return without action and * log a warning. @@ -941,7 +1005,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) * error out. That should not happen unless the admin misconfigured the system * to create conflicting connections. */ nm_log_warn (LOGD_SETTINGS, "plugin provided duplicate connection with UUID %s", - nm_connection_get_uuid (NM_CONNECTION (connection))); + nm_settings_connection_get_uuid (connection)); return; } @@ -957,6 +1021,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) /* Evil openconnect migration hack */ openconnect_migrate_hack (NM_CONNECTION (connection)); + g_object_ref (self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, G_CALLBACK (connection_removed), self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED, @@ -974,10 +1039,8 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) /* Export the connection over D-Bus */ g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); - path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, ec_counter++); + path = nm_exported_object_export (NM_EXPORTED_OBJECT (connection)); nm_connection_set_path (NM_CONNECTION (connection), path); - nm_dbus_manager_register_object (priv->dbus_mgr, path, G_OBJECT (connection)); - g_free (path); g_hash_table_insert (priv->connections, (gpointer) nm_connection_get_path (NM_CONNECTION (connection)), @@ -1047,10 +1110,10 @@ nm_settings_add_connection (NMSettings *self, * contain the same data as the connection it already knows about */ for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); GError *add_error = NULL; - added = nm_system_config_interface_add_connection (plugin, connection, save_to_disk, &add_error); + added = nm_settings_plugin_add_connection (plugin, connection, save_to_disk, &add_error); if (added) { claim_connection (self, added); return added; @@ -1112,21 +1175,24 @@ send_agent_owned_secrets (NMSettings *self, nm_connection_clear_secrets_with_flags (for_agent, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); - nm_agent_manager_save_secrets (priv->agent_mgr, for_agent, subject); + nm_agent_manager_save_secrets (priv->agent_mgr, + nm_connection_get_path (NM_CONNECTION (connection)), + for_agent, + subject); g_object_unref (for_agent); } static void pk_add_cb (NMAuthChain *chain, GError *chain_error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthCallResult result; GError *error = NULL; - NMConnection *connection; + NMConnection *connection = NULL; NMSettingsConnection *added = NULL; NMSettingsAddCallback callback; gpointer callback_data; @@ -1163,10 +1229,10 @@ pk_add_cb (NMAuthChain *chain, callback_data = nm_auth_chain_get_data (chain, "callback-data"); subject = nm_auth_chain_get_data (chain, "subject"); - callback (self, added, error, context, callback_data); + callback (self, added, error, context, subject, callback_data); /* Send agent-owned secrets to the agents */ - if (!error && added) + if (!error && added && nm_settings_has_connection (self, added)) send_agent_owned_secrets (self, added, subject); g_clear_error (&error); @@ -1207,11 +1273,11 @@ is_adhoc_wpa (NMConnection *connection) void nm_settings_add_connection_dbus (NMSettings *self, - NMConnection *connection, - gboolean save_to_disk, - DBusGMethodInvocation *context, - NMSettingsAddCallback callback, - gpointer user_data) + NMConnection *connection, + gboolean save_to_disk, + GDBusMethodInvocation *context, + NMSettingsAddCallback callback, + gpointer user_data) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMSettingConnection *s_con; @@ -1246,7 +1312,7 @@ nm_settings_add_connection_dbus (NMSettings *self, } /* Do any of the plugins support adding? */ - if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) { + if (!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED, "None of the registered plugins support add."); @@ -1265,7 +1331,6 @@ nm_settings_add_connection_dbus (NMSettings *self, * or that the permissions is empty (ie, visible by everyone). */ if (!nm_auth_is_subject_in_acl (connection, - nm_session_monitor_get (), subject, &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, @@ -1306,7 +1371,7 @@ nm_settings_add_connection_dbus (NMSettings *self, done: if (error) - callback (self, NULL, error, context, user_data); + callback (self, NULL, error, context, subject, user_data); g_clear_error (&error); g_clear_object (&subject); @@ -1316,29 +1381,37 @@ static void impl_settings_add_connection_add_cb (NMSettings *self, NMSettingsConnection *connection, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + NMAuthSubject *subject, gpointer user_data) { - if (error) - dbus_g_method_return_error (context, error); - else - dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection))); + if (error) { + g_dbus_method_invocation_return_gerror (context, error); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, subject, error->message); + } else { + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection)))); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE, + subject, NULL); + } } static void impl_settings_add_connection_helper (NMSettings *self, - GHashTable *settings, - gboolean save_to_disk, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + GVariant *settings, + gboolean save_to_disk) { NMConnection *connection; - GVariant *dict; GError *error = NULL; - dict = nm_utils_connection_hash_to_dict (settings); - connection = nm_simple_connection_new_from_dbus (dict, &error); - g_variant_unref (dict); + connection = nm_simple_connection_new_from_dbus (settings, &error); + if (connection) { + if (!nm_connection_verify_secrets (connection, &error)) + goto failure; + nm_settings_add_connection_dbus (self, connection, save_to_disk, @@ -1346,50 +1419,49 @@ impl_settings_add_connection_helper (NMSettings *self, impl_settings_add_connection_add_cb, NULL); g_object_unref (connection); - } else { - g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); + return; } + +failure: + g_assert (error); + g_dbus_method_invocation_take_error (context, error); } static void impl_settings_add_connection (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + GVariant *settings) { - impl_settings_add_connection_helper (self, settings, TRUE, context); + impl_settings_add_connection_helper (self, context, settings, TRUE); } static void impl_settings_add_connection_unsaved (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + GVariant *settings) { - impl_settings_add_connection_helper (self, settings, FALSE, context); + impl_settings_add_connection_helper (self, context, settings, FALSE); } static gboolean -ensure_root (NMDBusManager *dbus_mgr, - DBusGMethodInvocation *context) +ensure_root (NMBusManager *dbus_mgr, + GDBusMethodInvocation *context) { gulong caller_uid; GError *error = NULL; - if (!nm_dbus_manager_get_caller_info (dbus_mgr, context, NULL, &caller_uid, NULL)) { + if (!nm_bus_manager_get_caller_info (dbus_mgr, context, NULL, &caller_uid, NULL)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Unable to determine request UID."); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); return FALSE; } if (caller_uid != 0) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Permission denied"); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); return FALSE; } @@ -1398,24 +1470,24 @@ ensure_root (NMDBusManager *dbus_mgr, static void impl_settings_load_connections (NMSettings *self, - char **filenames, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + char **filenames) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GPtrArray *failures; GSList *iter; int i; - if (!ensure_root (priv->dbus_mgr, context)) + if (!ensure_root (nm_bus_manager_get (), context)) return; failures = g_ptr_array_new (); for (i = 0; filenames[i]; i++) { for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); - if (nm_system_config_interface_load_connection (plugin, filenames[i])) + if (nm_settings_plugin_load_connection (plugin, filenames[i])) break; } @@ -1427,40 +1499,110 @@ impl_settings_load_connections (NMSettings *self, } g_ptr_array_add (failures, NULL); - dbus_g_method_return (context, failures->len == 1, failures->pdata); + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(b^as)", + failures->len == 1, + failures->pdata)); g_ptr_array_unref (failures); } static void impl_settings_reload_connections (NMSettings *self, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; - if (!ensure_root (priv->dbus_mgr, context)) + if (!ensure_root (nm_bus_manager_get (), context)) return; for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); - nm_system_config_interface_reload_connections (plugin); + nm_settings_plugin_reload_connections (plugin); } - dbus_g_method_return (context, TRUE); + g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE)); +} + +static gboolean +write_hostname (NMSettingsPrivate *priv, const char *hostname) +{ + char *hostname_eol; + gboolean ret; + gs_free_error GError *error = NULL; + const char *file = priv->hostname.file; + gs_unref_variant GVariant *var = NULL; +#if HAVE_SELINUX + security_context_t se_ctx_prev = NULL, se_ctx = NULL; + struct stat file_stat = { .st_mode = 0 }; + mode_t st_mode = 0; +#endif + + if (priv->hostname.hostnamed_proxy) { + var = g_dbus_proxy_call_sync (priv->hostname.hostnamed_proxy, + "SetStaticHostname", + g_variant_new ("(sb)", hostname, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error) + nm_log_warn (LOGD_SETTINGS, "Could not set hostname: %s", error->message); + + return !error; + } + +#if HAVE_SELINUX + /* Get default context for hostname file and set it for fscreate */ + if (stat (file, &file_stat) == 0) + st_mode = file_stat.st_mode; + matchpathcon (file, st_mode, &se_ctx); + matchpathcon_fini (); + getfscreatecon (&se_ctx_prev); + setfscreatecon (se_ctx); +#endif + +#if defined (HOSTNAME_PERSIST_GENTOO) + hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n" + "hostname=\"%s\"\n", hostname); +#else + hostname_eol = g_strdup_printf ("%s\n", hostname); +#endif + + /* FIXME: g_file_set_contents() writes first to a temporary file + * and renames it atomically. We should hack g_file_set_contents() + * to set the SELINUX labels before renaming the file. */ + ret = g_file_set_contents (file, hostname_eol, -1, &error); + +#if HAVE_SELINUX + /* Restore previous context and cleanup */ + setfscreatecon (se_ctx_prev); + freecon (se_ctx); + freecon (se_ctx_prev); +#endif + + g_free (hostname_eol); + + if (!ret) { + nm_log_warn (LOGD_SETTINGS, "Could not save hostname to %s: %s", file, error->message); + return FALSE; + } + + return TRUE; } static void pk_hostname_cb (NMAuthChain *chain, GError *chain_error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthCallResult result; GError *error = NULL; - GSList *iter; const char *hostname; g_assert (context); @@ -1480,30 +1622,20 @@ pk_hostname_cb (NMAuthChain *chain, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Insufficient privileges."); } else { - /* Set the hostname in all plugins */ hostname = nm_auth_chain_get_data (chain, "hostname"); - for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - /* error will be cleared if any plugin supports saving the hostname */ + if (!write_hostname (priv, hostname)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Saving the hostname failed."); - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { - g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, hostname, NULL); - g_clear_error (&error); - } } } if (error) - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_take_error (context, error); else - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); - g_clear_error (&error); nm_auth_chain_unref (chain); } @@ -1536,8 +1668,8 @@ validate_hostname (const char *hostname) static void impl_settings_save_hostname (NMSettings *self, - const char *hostname, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + const char *hostname) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthChain *chain; @@ -1551,14 +1683,6 @@ impl_settings_save_hostname (NMSettings *self, goto done; } - /* Do any of the plugins support setting the hostname? */ - if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) { - error = g_error_new_literal (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_NOT_SUPPORTED, - "None of the registered plugins support setting the hostname."); - goto done; - } - chain = nm_auth_chain_new_context (context, pk_hostname_cb, self); if (!chain) { error = g_error_new_literal (NM_SETTINGS_ERROR, @@ -1573,8 +1697,39 @@ impl_settings_save_hostname (NMSettings *self, done: if (error) - dbus_g_method_return_error (context, error); - g_clear_error (&error); + g_dbus_method_invocation_take_error (context, error); +} + +static void +hostname_maybe_changed (NMSettings *settings) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (settings); + char *new_hostname; + + new_hostname = nm_settings_get_hostname (settings); + + if ( (new_hostname && !priv->hostname.value) + || (!new_hostname && priv->hostname.value) + || (priv->hostname.value && new_hostname && strcmp (priv->hostname.value, new_hostname))) { + + nm_log_info (LOGD_SETTINGS, "hostname changed from %s%s%s to %s%s%s", + NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"), + NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)")); + g_free (priv->hostname.value); + priv->hostname.value = new_hostname; + g_object_notify (G_OBJECT (settings), NM_SETTINGS_HOSTNAME); + } else + g_free (new_hostname); +} + +static void +hostname_file_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + hostname_maybe_changed (user_data); } static gboolean @@ -1699,13 +1854,20 @@ default_wired_clear_tag (NMSettings *self, nm_config_set_no_auto_default_for_device (NM_SETTINGS_GET_PRIVATE (self)->config, device); } -void -nm_settings_device_added (NMSettings *self, NMDevice *device) +static void +device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self) { NMConnection *connection; NMSettingsConnection *added; GError *error = NULL; + if (!nm_device_is_real (device)) + return; + + g_signal_handlers_disconnect_by_func (device, + G_CALLBACK (device_realized), + self); + /* If the device isn't managed or it already has a default wired connection, * ignore it. */ @@ -1740,7 +1902,19 @@ nm_settings_device_added (NMSettings *self, NMDevice *device) nm_log_info (LOGD_SETTINGS, "(%s): created default wired connection '%s'", nm_device_get_iface (device), - nm_connection_get_id (NM_CONNECTION (added))); + nm_settings_connection_get_id (added)); +} + +void +nm_settings_device_added (NMSettings *self, NMDevice *device) +{ + if (nm_device_is_real (device)) + device_realized (device, NULL, self); + else { + g_signal_connect_after (device, "notify::" NM_DEVICE_REAL, + G_CALLBACK (device_realized), + self); + } } void @@ -1748,6 +1922,10 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quittin { NMSettingsConnection *connection; + g_signal_handlers_disconnect_by_func (device, + G_CALLBACK (device_realized), + self); + connection = g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG); if (connection) { default_wired_clear_tag (self, device, connection, FALSE); @@ -1875,8 +2053,75 @@ nm_settings_get_startup_complete (NMSettings *self) /***************************************************************/ +static void +hostnamed_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + char **invalidated_properties, + gpointer user_data) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (user_data); + GVariant *v_hostname; + const char *hostname; + + v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy, + "StaticHostname"); + if (!v_hostname) + return; + + hostname = g_variant_get_string (v_hostname, NULL); + + if (g_strcmp0 (priv->hostname.value, hostname) != 0) { + nm_log_info (LOGD_SETTINGS, "hostname changed from %s%s%s to %s%s%s", + NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"), + NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)")); + g_free (priv->hostname.value); + priv->hostname.value = g_strdup (hostname); + g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME); + nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL); + } + + g_variant_unref (v_hostname); +} + +static void +setup_hostname_file_monitors (NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GFileMonitor *monitor; + GFile *file; + + priv->hostname.file = HOSTNAME_FILE; + priv->hostname.value = nm_settings_get_hostname (self); + + /* monitor changes to hostname file */ + file = g_file_new_for_path (priv->hostname.file); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + if (monitor) { + priv->hostname.monitor_id = g_signal_connect (monitor, "changed", + G_CALLBACK (hostname_file_changed_cb), + self); + priv->hostname.monitor = monitor; + } + +#if defined (HOSTNAME_PERSIST_SUSE) + /* monitor changes to dhcp file to know whether the hostname is valid */ + file = g_file_new_for_path (CONF_DHCP); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + if (monitor) { + priv->hostname.dhcp_monitor_id = g_signal_connect (monitor, "changed", + G_CALLBACK (hostname_file_changed_cb), + self); + priv->hostname.dhcp_monitor = monitor; + } +#endif + + hostname_maybe_changed (self); +} + NMSettings * -nm_settings_new (GError **error) +nm_settings_new (void) { NMSettings *self; NMSettingsPrivate *priv; @@ -1886,28 +2131,67 @@ nm_settings_new (GError **error) priv = NM_SETTINGS_GET_PRIVATE (self); priv->config = nm_config_get (); - priv->dbus_mgr = nm_dbus_manager_get (); + + nm_exported_object_export (NM_EXPORTED_OBJECT (self)); + return self; +} + +gboolean +nm_settings_start (NMSettings *self, GError **error) +{ + NMSettingsPrivate *priv; + GDBusProxy *proxy; + GVariant *variant; + GError *local_error = NULL; + + priv = NM_SETTINGS_GET_PRIVATE (self); /* Load the plugins; fail if a plugin is not found. */ if (!load_plugins (self, nm_config_get_plugins (priv->config), error)) { g_object_unref (self); - return NULL; + return FALSE; } load_connections (self); check_startup_complete (self); - nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self); - return self; + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, + HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH, + HOSTNAMED_SERVICE_INTERFACE, NULL, &local_error); + if (proxy) { + variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname"); + if (variant) { + nm_log_info (LOGD_SETTINGS, "hostname: using hostnamed"); + priv->hostname.hostnamed_proxy = proxy; + g_signal_connect (proxy, "g-properties-changed", + G_CALLBACK (hostnamed_properties_changed), self); + hostnamed_properties_changed (proxy, NULL, NULL, self); + g_variant_unref (variant); + } else { + nm_log_info (LOGD_SETTINGS, "hostname: couldn't get property from hostnamed"); + g_object_unref (proxy); + } + } else { + nm_log_info (LOGD_SETTINGS, "hostname: hostnamed not used as proxy creation failed with: %s", + local_error->message); + g_clear_error (&local_error); + } + + if (!priv->hostname.hostnamed_proxy) + setup_hostname_file_monitors (self); + + priv->started = TRUE; + g_object_notify (G_OBJECT (self), NM_SETTINGS_HOSTNAME); + return TRUE; } static void -connection_provider_init (NMConnectionProvider *cp_class) +connection_provider_iface_init (NMConnectionProviderInterface *cp_iface) { - cp_class->get_best_connections = get_best_connections; - cp_class->get_connections = get_connections; - cp_class->add_connection = _nm_connection_provider_add_connection; - cp_class->get_connection_by_uuid = cp_get_connection_by_uuid; + cp_iface->get_best_connections = get_best_connections; + cp_iface->get_connections = get_connections; + cp_iface->add_connection = _nm_connection_provider_add_connection; + cp_iface->get_connection_by_uuid = cp_get_connection_by_uuid; } static void @@ -1936,10 +2220,34 @@ dispose (GObject *object) g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_unref); priv->auths = NULL; - priv->dbus_mgr = NULL; - g_object_unref (priv->agent_mgr); + if (priv->hostname.hostnamed_proxy) { + g_signal_handlers_disconnect_by_func (priv->hostname.hostnamed_proxy, + G_CALLBACK (hostnamed_properties_changed), + self); + g_clear_object (&priv->hostname.hostnamed_proxy); + } + + if (priv->hostname.monitor) { + if (priv->hostname.monitor_id) + g_signal_handler_disconnect (priv->hostname.monitor, priv->hostname.monitor_id); + + g_file_monitor_cancel (priv->hostname.monitor); + g_clear_object (&priv->hostname.monitor); + } + + if (priv->hostname.dhcp_monitor) { + if (priv->hostname.dhcp_monitor_id) + g_signal_handler_disconnect (priv->hostname.dhcp_monitor, + priv->hostname.dhcp_monitor_id); + + g_file_monitor_cancel (priv->hostname.dhcp_monitor); + g_clear_object (&priv->hostname.dhcp_monitor); + } + + g_clear_pointer (&priv->hostname.value, g_free); + G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object); } @@ -1962,22 +2270,23 @@ finalize (GObject *object) static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); const GSList *specs, *iter; - GSList *copy = NULL; GHashTableIter citer; GPtrArray *array; const char *path; switch (prop_id) { case PROP_UNMANAGED_SPECS: + array = g_ptr_array_new (); specs = nm_settings_get_unmanaged_specs (self); for (iter = specs; iter; iter = g_slist_next (iter)) - copy = g_slist_append (copy, g_strdup (iter->data)); - g_value_take_boxed (value, copy); + g_ptr_array_add (array, g_strdup (iter->data)); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_HOSTNAME: g_value_take_string (value, nm_settings_get_hostname (self)); @@ -1987,14 +2296,15 @@ get_property (GObject *object, guint prop_id, g_value_set_static_string (value, ""); break; case PROP_CAN_MODIFY: - g_value_set_boolean (value, !!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)); + g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)); break; case PROP_CONNECTIONS: - array = g_ptr_array_sized_new (g_hash_table_size (priv->connections)); + array = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); g_hash_table_iter_init (&citer, priv->connections); while (g_hash_table_iter_next (&citer, (gpointer) &path, NULL)) g_ptr_array_add (array, g_strdup (path)); - g_value_take_boxed (value, array); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_STARTUP_COMPLETE: g_value_set_boolean (value, nm_settings_get_startup_complete (self)); @@ -2009,11 +2319,13 @@ static void nm_settings_class_init (NMSettingsClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); - + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (class); + g_type_class_add_private (class, sizeof (NMSettingsPrivate)); + exported_object_class->export_path = NM_DBUS_PATH_SETTINGS; + /* virtual methods */ - object_class->notify = notify; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; @@ -2023,7 +2335,7 @@ nm_settings_class_init (NMSettingsClass *class) g_object_class_install_property (object_class, PROP_UNMANAGED_SPECS, g_param_spec_boxed (NM_SETTINGS_UNMANAGED_SPECS, "", "", - DBUS_TYPE_G_LIST_OF_STRING, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -2044,19 +2356,11 @@ nm_settings_class_init (NMSettingsClass *class) g_object_class_install_property (object_class, PROP_CONNECTIONS, g_param_spec_boxed (NM_SETTINGS_CONNECTIONS, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /* signals */ - signals[PROPERTIES_CHANGED] = - g_signal_new ("properties-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsClass, properties_changed), - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT); signals[CONNECTION_ADDED] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_ADDED, G_OBJECT_CLASS_TYPE (object_class), @@ -2064,7 +2368,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, connection_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[CONNECTION_UPDATED] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, @@ -2073,7 +2377,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, connection_updated), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[CONNECTION_UPDATED_BY_USER] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER, @@ -2082,7 +2386,7 @@ nm_settings_class_init (NMSettingsClass *class) 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[CONNECTION_REMOVED] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, @@ -2091,7 +2395,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, connection_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[CONNECTION_VISIBILITY_CHANGED] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, @@ -2100,7 +2404,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, connection_visibility_changed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[AGENT_REGISTERED] = g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED, @@ -2109,7 +2413,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, agent_registered), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT); signals[NEW_CONNECTION] = @@ -2117,16 +2421,17 @@ nm_settings_class_init (NMSettingsClass *class) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - dbus_g_error_domain_register (NM_SETTINGS_ERROR, - NM_DBUS_INTERFACE_SETTINGS, - NM_TYPE_SETTINGS_ERROR); - dbus_g_error_domain_register (NM_CONNECTION_ERROR, - NM_DBUS_INTERFACE_SETTINGS_CONNECTION, - NM_TYPE_CONNECTION_ERROR); - - dbus_g_object_type_install_info (NM_TYPE_SETTINGS, &dbus_glib_nm_settings_object_info); - + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class), + NMDBUS_TYPE_SETTINGS_SKELETON, + "ListConnections", impl_settings_list_connections, + "GetConnectionByUuid", impl_settings_get_connection_by_uuid, + "AddConnection", impl_settings_add_connection, + "AddConnectionUnsaved", impl_settings_add_connection_unsaved, + "LoadConnections", impl_settings_load_connections, + "ReloadConnections", impl_settings_reload_connections, + "SaveHostname", impl_settings_save_hostname, + NULL); } |