diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index d9d539114e..7beb44e96a 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -29,7 +29,9 @@ #include "nm-core-internal.h" #include "nm-manager.h" #include "nm-device-iwd.h" +#include "nm-wifi-utils.h" #include "nm-utils/nm-random-utils.h" +#include "settings/nm-settings.h" /*****************************************************************************/ @@ -41,6 +43,7 @@ typedef struct { typedef struct { GDBusProxy *known_network; + NMSettingsConnection *mirror_connection; } KnownNetworkData; typedef struct { @@ -311,6 +314,8 @@ known_network_data_free (KnownNetworkData *network) return; g_object_unref (network->known_network); + if (network->mirror_connection) + g_object_unref (network->mirror_connection); g_slice_free (KnownNetworkData, network); } @@ -349,6 +354,100 @@ 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. + */ +static void +mirror_8021x_connection (NMIwdManager *self, KnownNetworkId *id, + KnownNetworkData *data) +{ + NMSettings *settings = NM_SETTINGS_GET; + NMSettingsConnection *const *iter; + NMConnection *connection; + NMSettingsConnection *settings_connection; + char uuid[37]; + NMSetting *setting; + GBytes *ssid; + GError *error = NULL; + + for (iter = nm_settings_get_connections (settings, NULL); *iter; iter++) { + const NMSettingsConnection *conn = *iter; + NMIwdNetworkSecurity security; + gs_free char *name = NULL; + NMSettingWireless *s_wifi; + + security = nm_wifi_connection_get_iwd_security (NM_CONNECTION (conn), NULL); + if (security != NM_IWD_NETWORK_SECURITY_8021X) + continue; + + s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (conn)); + if (!s_wifi) + continue; + + ssid = nm_setting_wireless_get_ssid (s_wifi); + if (!ssid) + continue; + + name = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), + g_bytes_get_size (ssid)); + + /* 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. + */ + if (!strcmp (name, id->name)) + return; + } + + connection = nm_simple_connection_new (); + + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_CONNECTION, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_CONNECTION_ID, id->name, + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), + NM_SETTING_CONNECTION_READ_ONLY, TRUE, + NULL)); + nm_connection_add_setting (connection, setting); + + ssid = g_bytes_new (id->name, strlen (id->name)); + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_WIRELESS, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, + NULL)); + nm_connection_add_setting (connection, setting); + + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_WIRELESS_SECURITY, + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", + NULL)); + nm_connection_add_setting (connection, setting); + + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_802_1X, NULL)); + nm_setting_802_1x_add_eap_method (NM_SETTING_802_1X (setting), "external"); + nm_connection_add_setting (connection, setting); + + settings_connection = nm_settings_add_connection (settings, connection, + FALSE, &error); + g_object_unref (connection); + + if (!settings_connection) { + _LOGW ("failed to add a mirror NMConnection for IWD's Known Network '%s': %s", + id->name, NM_G_ERROR_MSG (error)); + g_clear_error (&error); + return; + } + + nm_settings_connection_set_flags (settings_connection, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | + NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED, + TRUE); + + data->mirror_connection = g_object_ref (settings_connection); +} + static void interface_added (GDBusObjectManager *object_manager, GDBusObject *object, GDBusInterface *interface, gpointer user_data) @@ -393,9 +492,13 @@ interface_added (GDBusObjectManager *object_manager, GDBusObject *object, id = known_network_id_new (name, security); - data = g_slice_new (KnownNetworkData); + data = g_slice_new0 (KnownNetworkData); data->known_network = (GDBusProxy *) g_object_ref (proxy); g_hash_table_insert (priv->known_networks, id, data); + + if (security == NM_IWD_NETWORK_SECURITY_8021X) + mirror_8021x_connection (self, id, data); + return; } } @@ -421,6 +524,7 @@ interface_removed (GDBusObjectManager *object_manager, GDBusObject *object, if (nm_streq (iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) { KnownNetworkId id; + KnownNetworkData *data; const char *type_str; type_str = get_property_string_or_null (proxy, "Type"); @@ -437,6 +541,27 @@ interface_removed (GDBusObjectManager *object_manager, GDBusObject *object, else return; + data = g_hash_table_lookup (priv->known_networks, &id); + if (!data) + return; + + if (data->mirror_connection) { + NMSettingsConnectionIntFlags flags; + NMSettingsConnection *mirror_connection = data->mirror_connection; + + flags = nm_settings_connection_get_flags (mirror_connection); + + /* If connection has not been saved since we created it + * in interface_added it too can be removed now. */ + if (flags & NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED) { + data->mirror_connection = NULL; + + nm_settings_connection_delete (mirror_connection, NULL); + + g_object_unref (mirror_connection); + } + } + g_hash_table_remove (priv->known_networks, &id); return; }