wifi/iwd: handle forgetting connection profiles

Watch for connection-removed events and delete corresponding IWD network
configs if found.  This mainly changes anything for 802.1X networks
where the deleted NM connections might annoyingly re-appear after a
restart.  For PSK networks though it'll make IWD forget the password
which, until now, would be remembered by IWD even if it was removed or
changed in the NM profile, which is a bug.

This is still fragile because we don't handle "connection-updated"
events so the data->mirror_connection pointer for a known network record
may after some time point to an NMSettingsConnection with a different
SSID or security type and there are corner cases where the IWD-side
profile will not be forgotten.  At least I'm trying to make sure we
don't crash and don't wrongly remove any IWD profile which could also be
annoying for complicated EAP configs.
This commit is contained in:
Andrew Zaborowski
2018-10-18 19:51:48 +02:00
committed by Thomas Haller
parent b98f269b91
commit bea6c40367

View File

@@ -48,6 +48,7 @@ typedef struct {
typedef struct {
NMManager *manager;
NMSettings *settings;
GCancellable *cancellable;
gboolean running;
GDBusObjectManager *object_manager;
@@ -363,17 +364,18 @@ set_device_dbus_object (NMIwdManager *self, GDBusProxy *proxy,
nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object);
}
/* Create an in-memory NMConnection for a WPA2-Enterprise network that
* has been preprovisioned with an IWD config file so that NM autoconnect
* mechanism and the clients know this networks needs no additional EAP
* configuration from the user. Only do this if no existing connection
* SSID and security type match that network yet.
/* Look up an existing NMSettingsConnection for a WPA2-Enterprise network
* that has been preprovisioned with an IWD config file, or create a new
* in-memory connection object so that NM autoconnect mechanism and the
* clients know this networks needs no additional EAP configuration from
* the user.
*/
static NMSettingsConnection *
mirror_8021x_connection (NMIwdManager *self,
const char *name)
const char *name,
gboolean create_new)
{
NMSettings *settings = NM_SETTINGS_GET;
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
NMSettingsConnection *const*iter;
gs_unref_object NMConnection *connection = NULL;
NMSettingsConnection *settings_connection = NULL;
@@ -382,7 +384,7 @@ mirror_8021x_connection (NMIwdManager *self,
GError *error = NULL;
gs_unref_bytes GBytes *new_ssid = NULL;
for (iter = nm_settings_get_connections (settings, NULL); *iter; iter++) {
for (iter = nm_settings_get_connections (priv->settings, NULL); *iter; iter++) {
NMSettingsConnection *sett_conn = *iter;
NMConnection *conn = nm_settings_connection_get_connection (sett_conn);
NMIwdNetworkSecurity security;
@@ -418,11 +420,12 @@ mirror_8021x_connection (NMIwdManager *self,
settings_connection = sett_conn;
}
/* We already have an NMSettingsConnection matching this
/* If we already have an NMSettingsConnection matching this
* KnownNetwork, whether it's saved or an in-memory connection
* potentially created by ourselves. Nothing to do here.
* potentially created by ourselves then we have nothing left to
* do here.
*/
if (settings_connection)
if (settings_connection || !create_new)
return settings_connection;
connection = nm_simple_connection_new ();
@@ -464,7 +467,7 @@ mirror_8021x_connection (NMIwdManager *self,
if (!nm_connection_normalize (connection, NULL, NULL, NULL))
return NULL;
settings_connection = nm_settings_add_connection (settings, connection,
settings_connection = nm_settings_add_connection (priv->settings, connection,
FALSE, &error);
if (!settings_connection) {
_LOGW ("failed to add a mirror NMConnection for IWD's Known Network '%s': %s",
@@ -556,7 +559,7 @@ interface_added (GDBusObjectManager *object_manager, GDBusObject *object,
}
if (security == NM_IWD_NETWORK_SECURITY_8021X) {
sett_conn = mirror_8021x_connection (self, name);
sett_conn = mirror_8021x_connection (self, name, TRUE);
if ( sett_conn
&& sett_conn != data->mirror_connection) {
@@ -614,6 +617,55 @@ interface_removed (GDBusObjectManager *object_manager, GDBusObject *object,
}
}
static void
connection_removed (NMSettings *settings,
NMSettingsConnection *sett_conn,
gpointer user_data)
{
NMIwdManager *self = user_data;
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
NMConnection *conn = nm_settings_connection_get_connection (sett_conn);
NMSettingWireless *s_wireless;
gboolean mapped;
KnownNetworkData *data;
KnownNetworkId id;
id.security = nm_wifi_connection_get_iwd_security (conn, &mapped);
if (!mapped)
return;
s_wireless = nm_connection_get_setting_wireless (conn);
id.name = _nm_utils_ssid_to_utf8 (nm_setting_wireless_get_ssid (s_wireless));
data = g_hash_table_lookup (priv->known_networks, &id);
g_free ((char *) id.name);
if (!data)
return;
if (id.security == NM_IWD_NETWORK_SECURITY_8021X) {
NMSettingsConnection *new_mirror_conn;
if (data->mirror_connection != sett_conn)
return;
g_clear_object (&data->mirror_connection);
/* Don't call Forget for an 8021x network until there's no
* longer *any* matching NMSettingsConnection (debatable)
*/
new_mirror_conn = mirror_8021x_connection (self, id.name, FALSE);
if (new_mirror_conn) {
data->mirror_connection = g_object_ref (new_mirror_conn);
return;
}
}
if (!priv->running)
return;
g_dbus_proxy_call (data->known_network, "Forget",
NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
}
static gboolean
_om_has_name_owner (GDBusObjectManager *object_manager)
{
@@ -845,6 +897,10 @@ nm_iwd_manager_init (NMIwdManager *self)
g_signal_connect (priv->manager, NM_MANAGER_DEVICE_ADDED,
G_CALLBACK (device_added), self);
priv->settings = g_object_ref (nm_settings_get ());
g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
G_CALLBACK (connection_removed), self);
priv->cancellable = g_cancellable_new ();
priv->known_networks = g_hash_table_new_full ((GHashFunc) known_network_id_hash,
@@ -865,6 +921,14 @@ dispose (GObject *object)
nm_clear_g_cancellable (&priv->cancellable);
if (priv->settings) {
g_signal_handlers_disconnect_by_data (priv->settings, self);
g_clear_object (&priv->settings);
}
/* This may trigger mirror connection removals so it happens
* after the g_signal_handlers_disconnect_by_data above.
*/
nm_clear_pointer (&priv->known_networks, g_hash_table_destroy);
if (priv->manager) {