diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index d8fce34d6e..1a23498322 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -497,17 +497,24 @@ no-auto-default=* iwd-config-path - If the value points to an existing directory, Network - Manager will attempt to write copies of new or modified - Wi-Fi connection profiles, converted into the IWD - format, into this directory thus making IWD connection - properties editable. This will only happen if the IWD - backend is active meaning that at least one Wi-Fi device - must exist. + If the value is "auto" (the default), IWD is queried for its + current state directory when it appears on D-Bus -- the + directory where IWD keeps its network configuration files -- + usually /var/lib/iwd. NetworkManager will then attempt to + write copies of new or modified Wi-Fi connection profiles, + converted into the IWD format, into this directory thus making + IWD connection properties editable. NM will overwrite existing + files without preserving their contents. - This allows editing connection profile settings such as - the 802.1x configuration using Network Manager clients. + The path can also be overriden by pointing to a specific + existing and writable directory. On the other hand setting + this to an empty string or any other value disables the + profile conversion mechanism. + + + This mechanism allows editing connection profile settings such + as the 802.1x configuration using NetworkManager clients. Without it such changes have no effect in IWD. diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index b65022c346..f904ece227 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -47,6 +47,7 @@ typedef struct { char * agent_path; GHashTable * known_networks; NMDeviceIwd * last_agent_call_device; + char * last_state_dir; } NMIwdManagerPrivate; struct _NMIwdManager { @@ -452,6 +453,21 @@ iwd_config_write(GKeyFile * config, return nm_utils_file_set_contents(filepath, data, length, 0600, times, NULL, error); } +static const char * +get_config_path(NMIwdManager *self) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + const char * path = nm_config_data_get_iwd_config_path(NM_CONFIG_GET_DATA); + + if (!path || nm_streq0(path, "auto")) + return priv->last_state_dir; + + if (path[0] != '\0' && g_file_test(path, G_FILE_TEST_IS_DIR)) + return path; + + return NULL; +} + static void sett_conn_changed(NMSettingsConnection * sett_conn, guint update_reason, @@ -487,8 +503,8 @@ sett_conn_changed(NMSettingsConnection * sett_conn, if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) return; - iwd_dir = nm_config_data_get_iwd_config_path(NM_CONFIG_GET_DATA); - if (!iwd_dir || iwd_dir[0] == '\0' || !g_file_test(iwd_dir, G_FILE_TEST_IS_DIR)) { + iwd_dir = get_config_path(nm_iwd_manager_get()); + if (!iwd_dir) { gboolean nm_autoconnectable = nm_setting_connection_get_autoconnect(s_conn); gboolean iwd_autoconnectable = get_property_bool(data->known_network, "AutoConnect", TRUE); @@ -1119,8 +1135,8 @@ try_delete_file: if (mirror_connection(self, &id, FALSE, NULL)) return; - iwd_dir = nm_config_data_get_iwd_config_path(NM_CONFIG_GET_DATA); - if (!iwd_dir || iwd_dir[0] == '\0' || !g_file_test(iwd_dir, G_FILE_TEST_IS_DIR)) + iwd_dir = get_config_path(self); + if (!iwd_dir) return; filename = nm_wifi_utils_get_iwd_config_filename(id.name, ssid_len, id.security); @@ -1147,8 +1163,8 @@ connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer if (!nm_streq(nm_settings_connection_get_connection_type(sett_conn), "802-11-wireless")) return; - iwd_dir = nm_config_data_get_iwd_config_path(NM_CONFIG_GET_DATA); - if (!iwd_dir || iwd_dir[0] == '\0' || !g_file_test(iwd_dir, G_FILE_TEST_IS_DIR)) + iwd_dir = get_config_path(self); + if (!iwd_dir) return; /* If this is a generated connection it may be ourselves creating it and @@ -1392,6 +1408,56 @@ object_compare_interfaces(gconstpointer a, gconstpointer b) return rank_a - rank_b; } +static void +get_daemon_info_cb(GObject *source, GAsyncResult *res, gpointer user_data) +{ + NMIwdManager * self = user_data; + NMIwdManagerPrivate *priv; + gs_unref_variant GVariant *properties = NULL; + gs_free_error GError *error = NULL; + GVariantIter * properties_iter; + const char * key; + GVariant * value; + + properties = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); + if (!properties) { + if (nm_utils_error_is_cancelled(error)) + return; + + nm_log_warn(LOGD_WIFI, "iwd: Daemon.GetInfo() failed: %s", error->message); + return; + } + + priv = NM_IWD_MANAGER_GET_PRIVATE(self); + + if (!g_variant_is_of_type(properties, G_VARIANT_TYPE("(a{sv})"))) { + _LOGE("Daemon.GetInfo returned type %s instead of (a{sv})", + g_variant_get_type_string(properties)); + return; + } + + g_variant_get(properties, "(a{sv})", &properties_iter); + + while (g_variant_iter_next(properties_iter, "{&sv}", &key, &value)) { + if (nm_streq(key, "StateDirectory")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { + _LOGE("Daemon.GetInfo property %s is typed '%s' instead of 's'", + key, + g_variant_get_type_string(value)); + goto next; + } + + nm_clear_g_free(&priv->last_state_dir); + priv->last_state_dir = g_variant_dup_string(value, NULL); + } + +next: + g_variant_unref(value); + } + + g_variant_iter_free(properties_iter); +} + static void got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) { @@ -1429,7 +1495,8 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) } if (_om_has_name_owner(object_manager)) { - GList *objects, *iter; + GList * objects, *iter; + gs_unref_object GDBusInterface *daemon = NULL; priv->running = true; @@ -1455,6 +1522,19 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) if (priv->agent_id) register_agent(self); + + daemon = g_dbus_object_manager_get_interface(object_manager, + "/net/connman/iwd", /* IWD 1.15+ */ + NM_IWD_DAEMON_INTERFACE); + if (daemon) + g_dbus_proxy_call(G_DBUS_PROXY(daemon), + "GetInfo", + g_variant_new("()"), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_daemon_info_cb, + self); } } @@ -1615,6 +1695,8 @@ dispose(GObject *object) priv->last_agent_call_device = NULL; + nm_clear_g_free(&priv->last_state_dir); + G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object); } diff --git a/src/core/devices/wifi/nm-iwd-manager.h b/src/core/devices/wifi/nm-iwd-manager.h index 466f67c766..e794e66127 100644 --- a/src/core/devices/wifi/nm-iwd-manager.h +++ b/src/core/devices/wifi/nm-iwd-manager.h @@ -13,6 +13,7 @@ #define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM #define NM_IWD_SERVICE "net.connman.iwd" +#define NM_IWD_DAEMON_INTERFACE "net.connman.iwd.Daemon" #define NM_IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager" #define NM_IWD_WIPHY_INTERFACE "net.connman.iwd.Adapter" #define NM_IWD_DEVICE_INTERFACE "net.connman.iwd.Device" diff --git a/src/core/devices/wifi/nm-wifi-utils.c b/src/core/devices/wifi/nm-wifi-utils.c index 9250e6dd42..c486d239a5 100644 --- a/src/core/devices/wifi/nm-wifi-utils.c +++ b/src/core/devices/wifi/nm-wifi-utils.c @@ -1057,7 +1057,7 @@ eap_certs_to_iwd_config(GKeyFile * file, : nm_setting_802_1x_get_ca_cert_scheme(s_8021x); NMSetting8021xCKScheme client_cert_scheme = phase2 ? nm_setting_802_1x_get_phase2_client_cert_scheme(s_8021x) - : nm_setting_802_1x_get_ca_cert_scheme(s_8021x); + : nm_setting_802_1x_get_client_cert_scheme(s_8021x); NMSetting8021xCKScheme key_scheme; NMSettingSecretFlags key_password_flags; const char * ca_path = phase2 ? nm_setting_802_1x_get_phase2_ca_path(s_8021x)