diff options
Diffstat (limited to 'src/settings/nm-settings.c')
| -rw-r--r-- | src/settings/nm-settings.c | 236 |
1 files changed, 137 insertions, 99 deletions
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 73c678a6..1f691c0b 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -25,6 +25,8 @@ #include "nm-default.h" +#include "nm-settings.h" + #include <unistd.h> #include <sys/stat.h> #include <errno.h> @@ -60,7 +62,6 @@ #include "nm-core-internal.h" #include "nm-device-ethernet.h" -#include "nm-settings.h" #include "nm-settings-connection.h" #include "nm-settings-plugin.h" #include "nm-bus-manager.h" @@ -69,7 +70,6 @@ #include "nm-session-monitor.h" #include "plugins/keyfile/plugin.h" #include "nm-agent-manager.h" -#include "nm-connection-provider.h" #include "nm-config.h" #include "nm-audit-manager.h" #include "NetworkManagerUtils.h" @@ -133,11 +133,11 @@ static void claim_connection (NMSettings *self, static void unmanaged_specs_changed (NMSettingsPlugin *config, gpointer user_data); static void unrecognized_specs_changed (NMSettingsPlugin *config, gpointer user_data); -static void connection_provider_iface_init (NMConnectionProviderInterface *cp_iface); - -G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, NM_TYPE_EXPORTED_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_iface_init)) +static void connection_ready_changed (NMSettingsConnection *conn, + GParamSpec *pspec, + gpointer user_data); +G_DEFINE_TYPE (NMSettings, nm_settings, NM_TYPE_EXPORTED_OBJECT); typedef struct { NMAgentManager *agent_mgr; @@ -149,9 +149,9 @@ typedef struct { GSList *plugins; gboolean connections_loaded; GHashTable *connections; + NMSettingsConnection **connections_cached_list; GSList *unmanaged_specs; GSList *unrecognized_specs; - GSList *get_connections_cache; gboolean started; gboolean startup_complete; @@ -204,6 +204,11 @@ check_startup_complete (NMSettings *self) return; } + /* the connection_ready_changed signal handler is no longer needed. */ + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) + g_signal_handlers_disconnect_by_func (conn, G_CALLBACK (connection_ready_changed), self); + priv->startup_complete = TRUE; _notify (self, PROP_STARTUP_COMPLETE); } @@ -258,7 +263,7 @@ load_connections (NMSettings *self) } priv->connections_loaded = TRUE; - g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS); + _notify (self, PROP_CONNECTIONS); unmanaged_specs_changed (NULL, self); unrecognized_specs_changed (NULL, self); @@ -275,7 +280,7 @@ nm_settings_for_each_connection (NMSettings *self, g_return_if_fail (NM_IS_SETTINGS (self)); g_return_if_fail (for_each_func != NULL); - + priv = NM_SETTINGS_GET_PRIVATE (self); g_hash_table_iter_init (&iter, priv->connections); @@ -401,13 +406,60 @@ connection_sort (gconstpointer pa, gconstpointer pb) return 1; } +/** + * nm_settings_get_connections: + * @self: the #NMSettings + * @out_len: (out): (allow-none): returns the number of returned + * connections. + * + * Returns: (transfer-none): a list of NMSettingsConnections. The list is + * unsorted and NULL terminated. The result is never %NULL, in case of no + * connections, it returns an empty list. + * The returned list is cached internally, only valid until the next + * NMSettings operation. + */ +NMSettingsConnection *const* +nm_settings_get_connections (NMSettings *self, guint *out_len) +{ + GHashTableIter iter; + NMSettingsPrivate *priv; + guint l, i; + NMSettingsConnection **v; + NMSettingsConnection *con; + + g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); + + priv = NM_SETTINGS_GET_PRIVATE (self); + + if (priv->connections_cached_list) { + NM_SET_OUT (out_len, g_hash_table_size (priv->connections)); + return priv->connections_cached_list; + } + + l = g_hash_table_size (priv->connections); + + v = g_new (NMSettingsConnection *, l + 1); + + i = 0; + g_hash_table_iter_init (&iter, priv->connections); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &con)) + v[i++] = con; + v[i] = NULL; + + nm_assert (i == l); + + NM_SET_OUT (out_len, l); + priv->connections_cached_list = v; + return v; +} + /* Returns a list of NMSettingsConnections. * The list is sorted in the order suitable for auto-connecting, i.e. * first go connections with autoconnect=yes and most recent timestamp. * Caller must free the list with g_slist_free(). */ GSList * -nm_settings_get_connections (NMSettings *self) +nm_settings_get_connections_sorted (NMSettings *self) { GHashTableIter iter; gpointer data = NULL; @@ -886,7 +938,6 @@ connection_updated (NMSettingsConnection *connection, gboolean by_user, gpointer 0, connection, by_user); - g_signal_emit_by_name (NM_SETTINGS (user_data), NM_CP_SIGNAL_CONNECTION_UPDATED, connection); } static void @@ -920,17 +971,18 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_removed), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated), 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); + if (!priv->startup_complete) + 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); + g_clear_pointer (&priv->connections_cached_list, g_free); /* Notify D-Bus */ g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection); /* Re-emit for listeners like NMPolicy */ - g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_REMOVED, connection); _notify (self, PROP_CONNECTIONS); if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (connection))) nm_exported_object_unexport (NM_EXPORTED_OBJECT (connection)); @@ -1069,6 +1121,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) g_hash_table_insert (priv->connections, (gpointer) nm_connection_get_path (NM_CONNECTION (connection)), g_object_ref (connection)); + g_clear_pointer (&priv->connections_cached_list, g_free); nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ "); @@ -1078,7 +1131,6 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) if (priv->connections_loaded) { /* Internal added signal */ g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection); - g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_ADDED, connection); _notify (self, PROP_CONNECTIONS); /* Exported D-Bus signal */ @@ -1154,16 +1206,6 @@ nm_settings_add_connection (NMSettings *self, return NULL; } -static NMConnection * -_nm_connection_provider_add_connection (NMConnectionProvider *provider, - NMConnection *connection, - gboolean save_to_disk, - GError **error) -{ - g_assert (NM_IS_CONNECTION_PROVIDER (provider) && NM_IS_SETTINGS (provider)); - return NM_CONNECTION (nm_settings_add_connection (NM_SETTINGS (provider), connection, save_to_disk, error)); -} - static gboolean secrets_filter_cb (NMSetting *setting, const char *secret, @@ -1411,12 +1453,12 @@ impl_settings_add_connection_add_cb (NMSettings *self, { 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); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, NULL, 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, + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE, NULL, subject, NULL); } } @@ -1470,31 +1512,6 @@ impl_settings_add_connection_unsaved (NMSettings *self, impl_settings_add_connection_helper (self, context, settings, FALSE); } -static gboolean -ensure_root (NMBusManager *dbus_mgr, - GDBusMethodInvocation *context) -{ - gulong caller_uid; - GError *error = 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."); - 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"); - g_dbus_method_invocation_take_error (context, error); - return FALSE; - } - - return TRUE; -} - static void impl_settings_load_connections (NMSettings *self, GDBusMethodInvocation *context, @@ -1505,7 +1522,15 @@ impl_settings_load_connections (NMSettings *self, GSList *iter; int i; - if (!ensure_root (nm_bus_manager_get (), context)) + /* The permission is already enforced by the D-Bus daemon, but we ensure + * that the caller is still alive so that clients are forced to wait and + * we'll be able to switch to polkit without breaking behavior. + */ + if (!nm_bus_manager_ensure_uid (nm_bus_manager_get (), + context, + G_MAXULONG, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED)) return; failures = g_ptr_array_new (); @@ -1541,7 +1566,15 @@ impl_settings_reload_connections (NMSettings *self, NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; - if (!ensure_root (nm_bus_manager_get (), context)) + /* The permission is already enforced by the D-Bus daemon, but we ensure + * that the caller is still alive so that clients are forced to wait and + * we'll be able to switch to polkit without breaking behavior. + */ + if (!nm_bus_manager_ensure_uid (nm_bus_manager_get (), + context, + G_MAXULONG, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED)) return; for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { @@ -1837,11 +1870,11 @@ have_connection_for_device (NMSettings *self, NMDevice *device) NMSettingConnection *s_con; NMSettingWired *s_wired; const char *setting_hwaddr; - const char *device_hwaddr; + const char *perm_hw_addr; g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); - device_hwaddr = nm_device_get_hw_address (device); + perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE); /* Find a wired connection locked to the given MAC address, if any */ g_hash_table_iter_init (&iter, priv->connections); @@ -1875,8 +1908,8 @@ have_connection_for_device (NMSettings *self, NMDevice *device) setting_hwaddr = nm_setting_wired_get_mac_address (s_wired); if (setting_hwaddr) { /* A connection mac-locked to this device */ - if ( device_hwaddr - && nm_utils_hwaddr_matches (setting_hwaddr, -1, device_hwaddr, -1)) + if ( perm_hw_addr + && nm_utils_hwaddr_matches (setting_hwaddr, -1, perm_hw_addr, -1)) return TRUE; } else { /* A connection that applies to any wired device */ @@ -2071,22 +2104,41 @@ nm_settings_sort_connections (gconstpointer a, gconstpointer b) return 0; } -static GSList * -get_best_connections (NMConnectionProvider *provider, - guint max_requested, - const char *ctype1, - const char *ctype2, - NMConnectionFilterFunc func, - gpointer func_data) +/** + * nm_settings_get_best_connections: + * @self: the #NMSetting + * @max_requested: if non-zero, the maximum number of connections to return + * @ctype1: an #NMSetting base type (eg NM_SETTING_WIRELESS_SETTING_NAME) to + * filter connections against + * @ctype2: a second #NMSetting base type (eg NM_SETTING_WIRELESS_SETTING_NAME) + * to filter connections against + * @func: caller-supplied function for filtering connections + * @func_data: caller-supplied data passed to @func + * + * Returns: a #GSList of #NMConnection objects in sorted order representing the + * "best" or highest-priority connections filtered by @ctype1 and/or @ctype2, + * and/or @func. Caller is responsible for freeing the returned #GSList, but + * the contained values do not need to be unreffed. + */ +GSList * +nm_settings_get_best_connections (NMSettings *self, + guint max_requested, + const char *ctype1, + const char *ctype2, + NMConnectionFilterFunc func, + gpointer func_data) { - NMSettings *self = NM_SETTINGS (provider); - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMSettingsPrivate *priv; GSList *sorted = NULL; GHashTableIter iter; NMSettingsConnection *connection; guint added = 0; guint64 oldest = 0; + g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); + + priv = NM_SETTINGS_GET_PRIVATE (self); + g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) { guint64 cur_ts = 0; @@ -2095,7 +2147,7 @@ get_best_connections (NMConnectionProvider *provider, continue; if (ctype2 && !nm_connection_is_type (NM_CONNECTION (connection), ctype2)) continue; - if (func && !func (provider, NM_CONNECTION (connection), func_data)) + if (func && !func (self, NM_CONNECTION (connection), func_data)) continue; /* Don't bother with a connection that's older than the oldest one in the list */ @@ -2121,27 +2173,6 @@ get_best_connections (NMConnectionProvider *provider, return g_slist_reverse (sorted); } -static const GSList * -get_connections (NMConnectionProvider *provider) -{ - GSList *list = NULL; - NMSettings *self = NM_SETTINGS (provider); - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - - list = _nm_utils_hash_values_to_slist (priv->connections); - - /* Cache the list every call so we can keep it 'const' for callers */ - g_slist_free (priv->get_connections_cache); - priv->get_connections_cache = list; - return list; -} - -static NMConnection * -cp_get_connection_by_uuid (NMConnectionProvider *provider, const char *uuid) -{ - return NM_CONNECTION (nm_settings_get_connection_by_uuid (NM_SETTINGS (provider), uuid)); -} - /***************************************************************/ gboolean @@ -2190,14 +2221,30 @@ setup_hostname_file_monitors (NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GFileMonitor *monitor; + const char *path = HOSTNAME_FILE; + char *link_path = NULL; + struct stat file_stat; GFile *file; priv->hostname.value = nm_settings_get_hostname (self); + /* resolve the path to the hostname file if it is a symbolic link */ + if ( lstat(path, &file_stat) == 0 + && S_ISLNK (file_stat.st_mode) + && (link_path = nm_utils_read_link_absolute (path, NULL))) { + path = link_path; + if ( lstat(link_path, &file_stat) == 0 + && S_ISLNK (file_stat.st_mode)) { + _LOGW ("only one level of symbolic link indirection is allowed when monitoring " + HOSTNAME_FILE); + } + } + /* monitor changes to hostname file */ - file = g_file_new_for_path (HOSTNAME_FILE); + file = g_file_new_for_path (path); monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); + g_free(link_path); if (monitor) { priv->hostname.monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (hostname_file_changed_cb), @@ -2287,15 +2334,6 @@ nm_settings_start (NMSettings *self, GError **error) } static void -connection_provider_iface_init (NMConnectionProviderInterface *cp_iface) -{ - 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 nm_settings_init (NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); @@ -2359,7 +2397,7 @@ finalize (GObject *object) NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); g_hash_table_destroy (priv->connections); - g_slist_free (priv->get_connections_cache); + g_clear_pointer (&priv->connections_cached_list, g_free); g_slist_free_full (priv->unmanaged_specs, g_free); g_slist_free_full (priv->unrecognized_specs, g_free); |