Originally, nm-applet allowed CA certificate and the subject to be unset, and this may introduce a security issue (CVE-2006-7246).
This commit is to check the settings and to probe the RADIUS server if necessary. The probe result will be presented in a dialog to allow the user to decide whether to use the probed settings or not. https://bugzilla.gnome.org/show_bug.cgi?id=341323 --- src/applet-device-wifi.c | 5 + src/libnm-gtk/nm-wireless-dialog.c | 245 +++++++++++++++++++++++++++++ src/libnm-gtk/nm-wireless-dialog.h | 5 + src/wireless-security/wireless-security.c | 22 +++ src/wireless-security/wireless-security.h | 3 + 5 files changed, 280 insertions(+), 0 deletions(-) diff --git a/src/applet-device-wifi.c b/src/applet-device-wifi.c index 3781b86..deebf3e 100644 --- a/src/applet-device-wifi.c +++ b/src/applet-device-wifi.c @@ -381,6 +381,11 @@ more_info_wifi_dialog_response_cb (GtkDialog *foo, g_assert (connection); g_assert (device); + if (nma_wireless_dialog_need_cert_probe (dialog, connection)) { + nma_wireless_dialog_probe_cert (dialog); + return; + } + info->callback (connection, TRUE, FALSE, info->callback_data); /* Balance nma_wireless_dialog_get_connection() */ diff --git a/src/libnm-gtk/nm-wireless-dialog.c b/src/libnm-gtk/nm-wireless-dialog.c index 0d79f75..cf13160 100644 --- a/src/libnm-gtk/nm-wireless-dialog.c +++ b/src/libnm-gtk/nm-wireless-dialog.c @@ -79,6 +79,10 @@ typedef struct { GetSecretsInfo *secrets_info; gboolean disposed; + + /* For Server certificate probe */ + guint cert_id; + guint timeout_id; } NMAWirelessDialogPrivate; #define D_NAME_COLUMN 0 @@ -111,6 +115,242 @@ nma_wireless_dialog_get_nag_ignored (NMAWirelessDialog *self) return NMA_WIRELESS_DIALOG_GET_PRIVATE (self)->nag_ignored; } +gboolean +nma_wireless_dialog_need_cert_probe (NMAWirelessDialog *self, + NMConnection *connection) +{ + NMAWirelessDialogPrivate *priv; + NMSetting8021x *s_8021x; + NMSetting8021xCKScheme cert_scheme; + int i, num_eap; + char *subject, *cert_hash; + gboolean need_ca = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + + priv = NMA_WIRELESS_DIALOG_GET_PRIVATE (self); + + s_8021x = nm_connection_get_setting_802_1x (connection); + if (!s_8021x) + return FALSE; + + num_eap = nm_setting_802_1x_get_num_eap_methods (s_8021x); + for (i = 0; i < num_eap; i++) { + const char *eap; + eap = nm_setting_802_1x_get_eap_method (s_8021x, i); + if (g_strcmp0 (eap, "ttls") == 0 || g_strcmp0 (eap, "peap") == 0) { + need_ca = TRUE; + break; + } + } + + if (!need_ca) + return FALSE; + + subject = (char *)g_object_get_data (G_OBJECT (connection), NMA_SERVER_SUBJECT); + cert_hash = (char *)g_object_get_data (G_OBJECT (connection), NMA_SERVER_CERT_HASH); + cert_scheme = nm_setting_802_1x_get_ca_cert_scheme (s_8021x); + + if ( (!subject && !nm_setting_802_1x_get_subject_match (s_8021x)) + || (!cert_hash && (cert_scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN))) { + if (!priv->connection) { + priv->connection = connection; + } else if (priv->connection != connection) { + g_object_unref (priv->connection); + priv->connection = connection; + } + return TRUE; + } + + return FALSE; +} + +static gboolean +show_probe_result_dialog (GtkWindow *parent, + NMConnection *connection, + NMSetting8021x *s_8021x, + const char *subject, + const char *cert_hash) +{ + NMSettingWireless *s_wireless; + GtkWidget *notify_dialog, *content; + GtkWidget *grid; + GtkWidget *context, *label, *entry; + char *ssid, *string; + int response_id; + + s_wireless = nm_connection_get_setting_wireless (connection); + ssid = nm_utils_ssid_to_utf8 (nm_setting_wireless_get_ssid (s_wireless)); + + notify_dialog = gtk_dialog_new_with_buttons (ssid, parent, + GTK_DIALOG_MODAL, + GTK_STOCK_NO, GTK_RESPONSE_NO, + GTK_STOCK_YES, GTK_RESPONSE_YES, + NULL); + gtk_window_set_resizable (GTK_WINDOW (notify_dialog), FALSE); + content = gtk_dialog_get_content_area (GTK_DIALOG (notify_dialog)); + + grid = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (grid), 12); + gtk_container_set_border_width (GTK_CONTAINER (grid), 5); + gtk_container_add (GTK_CONTAINER (content), grid); + + entry = gtk_entry_new (); + gtk_editable_set_editable (GTK_EDITABLE (entry), FALSE); + if (!cert_hash) { + string = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s %s</span>\n\n%s\n%s", + _("Server Certificate Probed:"), + ssid, + _("The subject is going to be filled with the probe result."), + _("Do you agree?")); + label = gtk_label_new (_("Subject:")); + gtk_entry_set_text (GTK_ENTRY (entry), subject); + } else { + string = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s %s</span>\n\n%s\n%s", + _("Server Certificate Probed:"), + ssid, + _("The CA certificate is going to be filled with the probed server hash."), + _("Do you agree?")); + label = gtk_label_new (_("CA Certificate:")); + gtk_entry_set_text (GTK_ENTRY (entry), cert_hash); + } + context = gtk_label_new (string); + g_free (string); + g_free (ssid); + gtk_label_set_line_wrap (GTK_LABEL (context), TRUE); + gtk_label_set_use_markup (GTK_LABEL (context), TRUE); + gtk_grid_attach (GTK_GRID (grid), context, 0, 0, 10, 1); + gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1); + gtk_grid_attach (GTK_GRID (grid), entry, 1, 1, 9, 1); + + gtk_widget_show_all (notify_dialog); + + response_id = gtk_dialog_run (GTK_DIALOG (notify_dialog)); + + gtk_widget_destroy (notify_dialog); + + if (response_id == GTK_RESPONSE_YES) + return TRUE; + + return FALSE; +} + +static void +wireless_got_cert_cb (NMDeviceWifi *wifi, + GHashTable *cert, + gpointer user_data) +{ + NMAWirelessDialog *self = NMA_WIRELESS_DIALOG (user_data); + NMAWirelessDialogPrivate *priv; + NMSetting8021x *s_8021x; + const char *subject = NULL, *hash = NULL; + GValue *value; + gboolean response = FALSE; + + priv = NMA_WIRELESS_DIALOG_GET_PRIVATE (self); + + g_signal_handler_disconnect (NM_DEVICE_WIFI (priv->device), priv->cert_id); + if (priv->timeout_id) { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + + value = g_hash_table_lookup (cert, "subject"); + if (value && G_VALUE_HOLDS_STRING (value)) + subject = g_value_get_string (value); + + value = g_hash_table_lookup (cert, "cert_hash"); + if (value && G_VALUE_HOLDS_STRING (value)) + hash = g_value_get_string (value); + + if (!subject || !hash) + goto out; + + s_8021x = nm_connection_get_setting_802_1x (priv->connection); + if (s_8021x) { + NMSetting8021xCKScheme cert_scheme; + char *hash_path = NULL; + gboolean ret; + + cert_scheme = nm_setting_802_1x_get_ca_cert_scheme (s_8021x); + if (cert_scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) + hash_path = g_strconcat ("hash://server/sha256/", hash, NULL); + ret = show_probe_result_dialog (gtk_window_get_transient_for (GTK_WINDOW (self)), + priv->connection, + s_8021x, + subject, + hash_path); + if (!ret) { + g_free (hash_path); + goto out; + } + + g_object_set_data_full (G_OBJECT (priv->connection), + NMA_SERVER_SUBJECT, g_strdup (subject), + (GDestroyNotify) g_free); + g_object_set_data_full (G_OBJECT (priv->connection), + NMA_SERVER_CERT_HASH, hash_path, + (GDestroyNotify) g_free); + response = TRUE; + } +out: + if (response) + gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_OK); + else + gtk_widget_show (GTK_WIDGET (self)); +} + +static gboolean +wireless_cert_timeout_cb (gpointer user_data) +{ + NMAWirelessDialog *self = (NMAWirelessDialog *)user_data; + NMAWirelessDialogPrivate *priv; + + priv = NMA_WIRELESS_DIALOG_GET_PRIVATE (self); + + priv->timeout_id = 0; + + g_signal_handler_disconnect (NM_DEVICE_WIFI (priv->device), priv->cert_id); + + gtk_widget_show (GTK_WIDGET (self)); + + return FALSE; +} + +gboolean +nma_wireless_dialog_probe_cert (NMAWirelessDialog *self) +{ + NMAWirelessDialogPrivate *priv; + NMSettingWireless *s_wireless; + NMDeviceWifi *wifi; + guint id; + + g_return_val_if_fail (self != NULL, FALSE); + + priv = NMA_WIRELESS_DIALOG_GET_PRIVATE (self); + wifi = NM_DEVICE_WIFI (priv->device); + + s_wireless = nm_connection_get_setting_wireless (priv->connection); + if (!s_wireless || !nm_device_wifi_probe_cert (wifi, nm_setting_wireless_get_ssid (s_wireless))) + return FALSE; + + id = g_timeout_add_seconds (30, + (GSourceFunc)wireless_cert_timeout_cb, + (gpointer)self); + if (id <= 0) { + g_warning ("Failed to add timeout for server certificate probe"); + return FALSE; + } + priv->timeout_id = id; + + id = g_signal_connect (wifi, "cert-received", G_CALLBACK (wireless_got_cert_cb), self); + priv->cert_id = id; + + gtk_widget_hide (GTK_WIDGET (self)); + + return TRUE; +} + static void model_free (GtkTreeModel *model, guint col) { @@ -1187,6 +1427,9 @@ internal_init (NMAWirelessDialog *self, */ priv->revalidate_id = g_idle_add (revalidate, self); + priv->cert_id = 0; + priv->timeout_id = 0; + return TRUE; } @@ -1236,6 +1479,8 @@ nma_wireless_dialog_get_connection (NMAWirelessDialog *self, } nm_connection_add_setting (connection, (NMSetting *) s_wireless); + + priv->connection = g_object_ref (connection); } else connection = g_object_ref (priv->connection); diff --git a/src/libnm-gtk/nm-wireless-dialog.h b/src/libnm-gtk/nm-wireless-dialog.h index bee8711..9dc6057 100644 --- a/src/libnm-gtk/nm-wireless-dialog.h +++ b/src/libnm-gtk/nm-wireless-dialog.h @@ -76,5 +76,10 @@ void nma_wireless_dialog_set_nag_ignored (NMAWirelessDialog *dialog, gboolean ig gboolean nma_wireless_dialog_get_nag_ignored (NMAWirelessDialog *dialog); +gboolean nma_wireless_dialog_need_cert_probe (NMAWirelessDialog *dialog, + NMConnection *connection); + +gboolean nma_wireless_dialog_probe_cert (NMAWirelessDialog *dialog); + #endif /* NMA_WIRELESS_DIALOG_H */ diff --git a/src/wireless-security/wireless-security.c b/src/wireless-security/wireless-security.c index 8144789..0e74b70 100644 --- a/src/wireless-security/wireless-security.c +++ b/src/wireless-security/wireless-security.c @@ -451,9 +451,11 @@ ws_802_1x_fill_connection (WirelessSecurity *sec, NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; NMSetting8021x *s_8021x; + NMSetting8021xCKScheme cert_scheme; EAPMethod *eap = NULL; GtkTreeModel *model; GtkTreeIter iter; + char *subject, *cert_hash; s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS)); g_assert (s_wireless); @@ -476,6 +478,26 @@ ws_802_1x_fill_connection (WirelessSecurity *sec, eap_method_fill_connection (eap, connection); eap_method_unref (eap); + + /* Fetch subject and cert_hash from connection */ + subject = (char *)g_object_get_data (G_OBJECT (connection), NMA_SERVER_SUBJECT); + if (subject && !nm_setting_802_1x_get_subject_match (s_8021x)) + g_object_set (s_8021x, NM_SETTING_802_1X_SUBJECT_MATCH, subject, NULL); + + cert_hash = (char *)g_object_get_data (G_OBJECT (connection), NMA_SERVER_CERT_HASH); + cert_scheme = nm_setting_802_1x_get_ca_cert_scheme (s_8021x); + if (cert_hash && cert_scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { + NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; + GError *error = NULL; + if (!nm_setting_802_1x_set_ca_cert (s_8021x, + cert_hash, + NM_SETTING_802_1X_CK_SCHEME_HASH, + &format, + &error)) { + g_warning ("Couldn't set CA certificate '%s': %s", cert_hash, error ? error->message : "(unknown)"); + g_error_free (error); + } + } } void diff --git a/src/wireless-security/wireless-security.h b/src/wireless-security/wireless-security.h index 004fd6d..a1210ef 100644 --- a/src/wireless-security/wireless-security.h +++ b/src/wireless-security/wireless-security.h @@ -28,6 +28,9 @@ #include <nm-connection.h> +#define NMA_SERVER_SUBJECT "nma-server-subject" +#define NMA_SERVER_CERT_HASH "mna-server-cert-hash" + typedef struct _WirelessSecurity WirelessSecurity; typedef void (*WSChangedFunc) (WirelessSecurity *sec, gpointer user_data); -- 1.7.3.4 _______________________________________________ networkmanager-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/networkmanager-list
