gnome-control-center/panels/network/wireless-security/eap-method-peap.c
2019-09-13 14:20:50 +12:00

447 lines
16 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager Applet -- allow user control over networking
*
* Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright 2007 - 2014 Red Hat, Inc.
*/
#include "nm-default.h"
#include <ctype.h>
#include <string.h>
#include "eap-method.h"
#include "wireless-security.h"
#include "utils.h"
#define I_NAME_COLUMN 0
#define I_METHOD_COLUMN 1
struct _EAPMethodPEAP {
EAPMethod parent;
GtkSizeGroup *size_group;
WirelessSecurity *sec_parent;
gboolean is_editor;
};
static void
destroy (EAPMethod *parent)
{
EAPMethodPEAP *method = (EAPMethodPEAP *) parent;
if (method->size_group)
g_object_unref (method->size_group);
}
static gboolean
validate (EAPMethod *parent, GError **error)
{
GtkWidget *widget;
GtkTreeModel *model;
GtkTreeIter iter;
EAPMethod *eap = NULL;
gboolean valid = FALSE;
g_autoptr(GError) local_error = NULL;
if (!eap_method_validate_filepicker (parent->builder, "eap_peap_ca_cert_button", TYPE_CA_CERT, NULL, NULL, &local_error)) {
g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid EAP-PEAP CA certificate: %s"), local_error->message);
return FALSE;
}
if (eap_method_ca_cert_required (parent->builder, "eap_peap_ca_cert_not_required_checkbox", "eap_peap_ca_cert_button")) {
g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid EAP-PEAP CA certificate: no certificate specified"));
return FALSE;
}
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
g_assert (widget);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
g_assert (eap);
valid = eap_method_validate (eap, error);
eap_method_unref (eap);
return valid;
}
static void
ca_cert_not_required_toggled (GtkWidget *ignored, gpointer user_data)
{
EAPMethod *parent = user_data;
eap_method_ca_cert_not_required_toggled (parent->builder, "eap_peap_ca_cert_not_required_checkbox", "eap_peap_ca_cert_button");
}
static void
add_to_size_group (EAPMethod *parent, GtkSizeGroup *group)
{
EAPMethodPEAP *method = (EAPMethodPEAP *) parent;
GtkWidget *widget;
GtkTreeModel *model;
GtkTreeIter iter;
EAPMethod *eap;
if (method->size_group)
g_object_unref (method->size_group);
method->size_group = g_object_ref (group);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_not_required_checkbox"));
g_assert (widget);
gtk_size_group_add_widget (group, widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_label"));
g_assert (widget);
gtk_size_group_add_widget (group, widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_label"));
g_assert (widget);
gtk_size_group_add_widget (group, widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_label"));
g_assert (widget);
gtk_size_group_add_widget (group, widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_label"));
g_assert (widget);
gtk_size_group_add_widget (group, widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
g_assert (widget);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
g_assert (eap);
eap_method_add_to_size_group (eap, group);
eap_method_unref (eap);
}
static void
fill_connection (EAPMethod *parent, NMConnection *connection, NMSettingSecretFlags flags)
{
NMSetting8021x *s_8021x;
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
GtkWidget *widget;
const char *text;
g_autofree gchar *filename = NULL;
EAPMethod *eap = NULL;
GtkTreeModel *model;
GtkTreeIter iter;
int peapver_active = 0;
g_autoptr(GError) error = NULL;
gboolean ca_cert_error = FALSE;
s_8021x = nm_connection_get_setting_802_1x (connection);
g_assert (s_8021x);
nm_setting_802_1x_add_eap_method (s_8021x, "peap");
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_entry"));
g_assert (widget);
text = gtk_entry_get_text (GTK_ENTRY (widget));
if (text && strlen (text))
g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, text, NULL);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_button"));
g_assert (widget);
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
if (!nm_setting_802_1x_set_ca_cert (s_8021x, filename, NM_SETTING_802_1X_CK_SCHEME_PATH, &format, &error)) {
g_warning ("Couldn't read CA certificate '%s': %s", filename, error ? error->message : "(unknown)");
ca_cert_error = TRUE;
}
eap_method_ca_cert_ignore_set (parent, connection, filename, ca_cert_error);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
peapver_active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
switch (peapver_active) {
case 1: /* PEAP v0 */
g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
break;
case 2: /* PEAP v1 */
g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL);
break;
default: /* Automatic */
g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, NULL, NULL);
break;
}
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
g_assert (eap);
eap_method_fill_connection (eap, connection, flags);
eap_method_unref (eap);
}
static void
inner_auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
{
EAPMethod *parent = (EAPMethod *) user_data;
EAPMethodPEAP *method = (EAPMethodPEAP *) parent;
GtkWidget *vbox;
EAPMethod *eap = NULL;
GList *elt, *children;
GtkTreeModel *model;
GtkTreeIter iter;
GtkWidget *eap_widget;
vbox = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_vbox"));
g_assert (vbox);
/* Remove any previous wireless security widgets */
children = gtk_container_get_children (GTK_CONTAINER (vbox));
for (elt = children; elt; elt = g_list_next (elt))
gtk_container_remove (GTK_CONTAINER (vbox), GTK_WIDGET (elt->data));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
g_assert (eap);
eap_widget = eap_method_get_widget (eap);
g_assert (eap_widget);
gtk_widget_unparent (eap_widget);
if (method->size_group)
eap_method_add_to_size_group (eap, method->size_group);
gtk_container_add (GTK_CONTAINER (vbox), eap_widget);
eap_method_unref (eap);
wireless_security_changed_cb (combo, method->sec_parent);
}
static GtkWidget *
inner_auth_combo_init (EAPMethodPEAP *method,
NMConnection *connection,
NMSetting8021x *s_8021x,
gboolean secrets_only)
{
EAPMethod *parent = (EAPMethod *) method;
GtkWidget *combo;
GtkListStore *auth_model;
GtkTreeIter iter;
EAPMethodSimple *em_mschap_v2;
EAPMethodSimple *em_md5;
EAPMethodSimple *em_gtc;
guint32 active = 0;
const char *phase2_auth = NULL;
EAPMethodSimpleFlags simple_flags;
auth_model = gtk_list_store_new (2, G_TYPE_STRING, eap_method_get_type ());
if (s_8021x) {
if (nm_setting_802_1x_get_phase2_auth (s_8021x))
phase2_auth = nm_setting_802_1x_get_phase2_auth (s_8021x);
else if (nm_setting_802_1x_get_phase2_autheap (s_8021x))
phase2_auth = nm_setting_802_1x_get_phase2_autheap (s_8021x);
}
simple_flags = EAP_METHOD_SIMPLE_FLAG_PHASE2;
if (method->is_editor)
simple_flags |= EAP_METHOD_SIMPLE_FLAG_IS_EDITOR;
if (secrets_only)
simple_flags |= EAP_METHOD_SIMPLE_FLAG_SECRETS_ONLY;
em_mschap_v2 = eap_method_simple_new (method->sec_parent,
connection,
EAP_METHOD_SIMPLE_TYPE_MSCHAP_V2,
simple_flags);
gtk_list_store_append (auth_model, &iter);
gtk_list_store_set (auth_model, &iter,
I_NAME_COLUMN, _("MSCHAPv2"),
I_METHOD_COLUMN, em_mschap_v2,
-1);
eap_method_unref (EAP_METHOD (em_mschap_v2));
/* Check for defaulting to MSCHAPv2 */
if (phase2_auth && !strcasecmp (phase2_auth, "mschapv2"))
active = 0;
em_md5 = eap_method_simple_new (method->sec_parent,
connection,
EAP_METHOD_SIMPLE_TYPE_MD5,
simple_flags);
gtk_list_store_append (auth_model, &iter);
gtk_list_store_set (auth_model, &iter,
I_NAME_COLUMN, _("MD5"),
I_METHOD_COLUMN, em_md5,
-1);
eap_method_unref (EAP_METHOD (em_md5));
/* Check for defaulting to MD5 */
if (phase2_auth && !strcasecmp (phase2_auth, "md5"))
active = 1;
em_gtc = eap_method_simple_new (method->sec_parent,
connection,
EAP_METHOD_SIMPLE_TYPE_GTC,
simple_flags);
gtk_list_store_append (auth_model, &iter);
gtk_list_store_set (auth_model, &iter,
I_NAME_COLUMN, _("GTC"),
I_METHOD_COLUMN, em_gtc,
-1);
eap_method_unref (EAP_METHOD (em_gtc));
/* Check for defaulting to GTC */
if (phase2_auth && !strcasecmp (phase2_auth, "gtc"))
active = 2;
combo = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
g_assert (combo);
gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (auth_model));
g_object_unref (G_OBJECT (auth_model));
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
g_signal_connect (G_OBJECT (combo), "changed",
(GCallback) inner_auth_combo_changed_cb,
method);
return combo;
}
static void
update_secrets (EAPMethod *parent, NMConnection *connection)
{
eap_method_phase2_update_secrets_helper (parent,
connection,
"eap_peap_inner_auth_combo",
I_METHOD_COLUMN);
}
EAPMethodPEAP *
eap_method_peap_new (WirelessSecurity *ws_parent,
NMConnection *connection,
gboolean is_editor,
gboolean secrets_only)
{
EAPMethod *parent;
EAPMethodPEAP *method;
GtkWidget *widget, *widget_ca_not_required_checkbox;
GtkFileFilter *filter;
NMSetting8021x *s_8021x = NULL;
const char *filename;
parent = eap_method_init (sizeof (EAPMethodPEAP),
validate,
add_to_size_group,
fill_connection,
update_secrets,
destroy,
"/org/gnome/ControlCenter/network/eap-method-peap.ui",
"eap_peap_notebook",
"eap_peap_anon_identity_entry",
FALSE);
if (!parent)
return NULL;
parent->password_flags_name = NM_SETTING_802_1X_PASSWORD;
method = (EAPMethodPEAP *) parent;
method->sec_parent = ws_parent;
method->is_editor = is_editor;
if (connection)
s_8021x = nm_connection_get_setting_802_1x (connection);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_not_required_checkbox"));
g_assert (widget);
g_signal_connect (G_OBJECT (widget), "toggled",
(GCallback) ca_cert_not_required_toggled,
parent);
g_signal_connect (G_OBJECT (widget), "toggled",
(GCallback) wireless_security_changed_cb,
ws_parent);
widget_ca_not_required_checkbox = widget;
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_button"));
g_assert (widget);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget),
_("Choose a Certificate Authority certificate"));
g_signal_connect (G_OBJECT (widget), "selection-changed",
(GCallback) wireless_security_changed_cb,
ws_parent);
filter = eap_method_default_file_chooser_filter_new (FALSE);
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
if (connection && s_8021x) {
filename = NULL;
if (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
filename = nm_setting_802_1x_get_ca_cert_path (s_8021x);
if (filename)
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), filename);
}
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget_ca_not_required_checkbox),
!filename && eap_method_ca_cert_ignore_get (parent, connection));
}
widget = inner_auth_combo_init (method, connection, s_8021x, secrets_only);
inner_auth_combo_changed_cb (widget, (gpointer) method);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
g_assert (widget);
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
if (s_8021x) {
const char *peapver;
peapver = nm_setting_802_1x_get_phase1_peapver (s_8021x);
if (peapver) {
/* Index 0 is "Automatic" */
if (!strcmp (peapver, "0"))
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1);
else if (!strcmp (peapver, "1"))
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2);
}
}
g_signal_connect (G_OBJECT (widget), "changed",
(GCallback) wireless_security_changed_cb,
ws_parent);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_entry"));
if (s_8021x && nm_setting_802_1x_get_anonymous_identity (s_8021x))
gtk_entry_set_text (GTK_ENTRY (widget), nm_setting_802_1x_get_anonymous_identity (s_8021x));
g_signal_connect (G_OBJECT (widget), "changed",
(GCallback) wireless_security_changed_cb,
ws_parent);
if (secrets_only) {
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_label"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_entry"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_label"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_button"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_not_required_checkbox"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_label"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_label"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
gtk_widget_hide (widget);
}
return method;
}