gnome-control-center/panels/network/wireless-security/eap-method-simple.c
Bastien Nocera 4663ba2fac network: Fix crash opening "Hidden network" dialogue
Both the Network panel and libnma expect UI resources in the
same location, which will cause problems when the Network panel loads
its own version that doesn't quite match up to the code used in libnma.

This fixes a crash when nma_wifi_dialog_new_for_hidden() is called and
libnma expects a domain widget to be present, which it isn't in our
version of the UI files.

https://bugzilla.gnome.org/show_bug.cgi?id=785099
2018-03-12 14:39:10 +01:00

366 lines
13 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 "helpers.h"
#include "nma-ui-utils.h"
#include "utils.h"
struct _EAPMethodSimple {
EAPMethod parent;
WirelessSecurity *ws_parent;
EAPMethodSimpleType type;
EAPMethodSimpleFlags flags;
GtkEntry *username_entry;
GtkEntry *password_entry;
GtkToggleButton *show_password;
guint idle_func_id;
};
static void
show_toggled_cb (GtkToggleButton *button, EAPMethodSimple *method)
{
gboolean visible;
visible = gtk_toggle_button_get_active (button);
gtk_entry_set_visibility (method->password_entry, visible);
}
static gboolean
always_ask_selected (GtkEntry *passwd_entry)
{
return !!( nma_utils_menu_to_secret_flags (GTK_WIDGET (passwd_entry))
& NM_SETTING_SECRET_FLAG_NOT_SAVED);
}
static gboolean
validate (EAPMethod *parent, GError **error)
{
EAPMethodSimple *method = (EAPMethodSimple *)parent;
const char *text;
gboolean ret = TRUE;
text = gtk_entry_get_text (method->username_entry);
if (!text || !strlen (text)) {
widget_set_error (GTK_WIDGET (method->username_entry));
g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP username"));
ret = FALSE;
} else
widget_unset_error (GTK_WIDGET (method->username_entry));
/* Check if the password should always be requested */
if (always_ask_selected (method->password_entry))
widget_unset_error (GTK_WIDGET (method->password_entry));
else {
text = gtk_entry_get_text (method->password_entry);
if (!text || !strlen (text)) {
widget_set_error (GTK_WIDGET (method->password_entry));
if (ret) {
g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP password"));
ret = FALSE;
}
} else
widget_unset_error (GTK_WIDGET (method->password_entry));
}
return ret;
}
static void
add_to_size_group (EAPMethod *parent, GtkSizeGroup *group)
{
GtkWidget *widget;
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_username_label"));
g_assert (widget);
gtk_size_group_add_widget (group, widget);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_password_label"));
g_assert (widget);
gtk_size_group_add_widget (group, widget);
}
typedef struct {
const char *name;
gboolean autheap_allowed;
} EapType;
/* Indexed by EAP_METHOD_SIMPLE_TYPE_* */
static const EapType eap_table[EAP_METHOD_SIMPLE_TYPE_LAST] = {
[EAP_METHOD_SIMPLE_TYPE_PAP] = { "pap", FALSE },
[EAP_METHOD_SIMPLE_TYPE_MSCHAP] = { "mschap", FALSE },
[EAP_METHOD_SIMPLE_TYPE_MSCHAP_V2] = { "mschapv2", TRUE },
[EAP_METHOD_SIMPLE_TYPE_PLAIN_MSCHAP_V2] = { "mschapv2", FALSE },
[EAP_METHOD_SIMPLE_TYPE_MD5] = { "md5", TRUE },
[EAP_METHOD_SIMPLE_TYPE_PWD] = { "pwd", TRUE },
[EAP_METHOD_SIMPLE_TYPE_CHAP] = { "chap", FALSE },
[EAP_METHOD_SIMPLE_TYPE_GTC] = { "gtc", TRUE },
};
static void
fill_connection (EAPMethod *parent, NMConnection *connection, NMSettingSecretFlags prev_flags)
{
EAPMethodSimple *method = (EAPMethodSimple *) parent;
NMSetting8021x *s_8021x;
gboolean not_saved = FALSE;
NMSettingSecretFlags flags;
const EapType *eap_type;
s_8021x = nm_connection_get_setting_802_1x (connection);
g_assert (s_8021x);
/* If this is the main EAP method, clear any existing methods because the
* user-selected on will replace it.
*/
if (parent->phase2 == FALSE)
nm_setting_802_1x_clear_eap_methods (s_8021x);
eap_type = &eap_table[method->type];
if (parent->phase2) {
/* If the outer EAP method (TLS, TTLS, PEAP, etc) allows inner/phase2
* EAP methods (which only TTLS allows) *and* the inner/phase2 method
* supports being an inner EAP method, then set PHASE2_AUTHEAP.
* Otherwise the inner/phase2 method goes into PHASE2_AUTH.
*/
if ((method->flags & EAP_METHOD_SIMPLE_FLAG_AUTHEAP_ALLOWED) && eap_type->autheap_allowed) {
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, eap_type->name, NULL);
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, NULL, NULL);
} else {
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, eap_type->name, NULL);
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, NULL, NULL);
}
} else
nm_setting_802_1x_add_eap_method (s_8021x, eap_type->name);
g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, gtk_entry_get_text (method->username_entry), NULL);
/* Save the password always ask setting */
not_saved = always_ask_selected (method->password_entry);
flags = nma_utils_menu_to_secret_flags (GTK_WIDGET (method->password_entry));
nm_setting_set_secret_flags (NM_SETTING (s_8021x), NM_SETTING_802_1X_PASSWORD, flags, NULL);
/* Fill the connection's password if we're in the applet so that it'll get
* back to NM. From the editor though, since the connection isn't going
* back to NM in response to a GetSecrets() call, we don't save it if the
* user checked "Always Ask".
*/
if (!(method->flags & EAP_METHOD_SIMPLE_FLAG_IS_EDITOR) || not_saved == FALSE)
g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, gtk_entry_get_text (method->password_entry), NULL);
/* Update secret flags and popup when editing the connection */
if (!(method->flags & EAP_METHOD_SIMPLE_FLAG_SECRETS_ONLY)) {
GtkWidget *passwd_entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_password_entry"));
g_assert (passwd_entry);
nma_utils_update_password_storage (passwd_entry, flags,
NM_SETTING (s_8021x), parent->password_flags_name);
}
}
static void
update_secrets (EAPMethod *parent, NMConnection *connection)
{
helper_fill_secret_entry (connection,
parent->builder,
"eap_simple_password_entry",
NM_TYPE_SETTING_802_1X,
(HelperSecretFunc) nm_setting_802_1x_get_password);
}
static gboolean
stuff_changed (EAPMethodSimple *method)
{
wireless_security_changed_cb (NULL, method->ws_parent);
method->idle_func_id = 0;
return FALSE;
}
static void
password_storage_changed (GObject *entry,
GParamSpec *pspec,
EAPMethodSimple *method)
{
gboolean always_ask;
gboolean secrets_only = method->flags & EAP_METHOD_SIMPLE_FLAG_SECRETS_ONLY;
always_ask = always_ask_selected (method->password_entry);
if (always_ask && !secrets_only) {
/* we always clear this button and do not restore it
* (because we want to hide the password). */
gtk_toggle_button_set_active (method->show_password, FALSE);
}
gtk_widget_set_sensitive (GTK_WIDGET (method->show_password),
!always_ask || secrets_only);
if (!method->idle_func_id)
method->idle_func_id = g_idle_add ((GSourceFunc) stuff_changed, method);
}
/* Set the UI fields for user, password, always_ask and show_password to the
* values as provided by method->ws_parent. */
static void
set_userpass_ui (EAPMethodSimple *method)
{
if (method->ws_parent->username)
gtk_entry_set_text (method->username_entry, method->ws_parent->username);
else
gtk_entry_set_text (method->username_entry, "");
if (method->ws_parent->password && !method->ws_parent->always_ask)
gtk_entry_set_text (method->password_entry, method->ws_parent->password);
else
gtk_entry_set_text (method->password_entry, "");
gtk_toggle_button_set_active (method->show_password, method->ws_parent->show_password);
password_storage_changed (NULL, NULL, method);
}
static void
widgets_realized (GtkWidget *widget, EAPMethodSimple *method)
{
set_userpass_ui (method);
}
static void
widgets_unrealized (GtkWidget *widget, EAPMethodSimple *method)
{
wireless_security_set_userpass (method->ws_parent,
gtk_entry_get_text (method->username_entry),
gtk_entry_get_text (method->password_entry),
always_ask_selected (method->password_entry),
gtk_toggle_button_get_active (method->show_password));
}
static void
destroy (EAPMethod *parent)
{
EAPMethodSimple *method = (EAPMethodSimple *) parent;
GtkWidget *widget;
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_notebook"));
g_assert (widget);
g_signal_handlers_disconnect_by_data (widget, method);
g_signal_handlers_disconnect_by_data (method->username_entry, method->ws_parent);
g_signal_handlers_disconnect_by_data (method->password_entry, method->ws_parent);
g_signal_handlers_disconnect_by_data (method->password_entry, method);
g_signal_handlers_disconnect_by_data (method->show_password, method);
nm_clear_g_source (&method->idle_func_id);
}
EAPMethodSimple *
eap_method_simple_new (WirelessSecurity *ws_parent,
NMConnection *connection,
EAPMethodSimpleType type,
EAPMethodSimpleFlags flags)
{
EAPMethod *parent;
EAPMethodSimple *method;
GtkWidget *widget;
NMSetting8021x *s_8021x = NULL;
parent = eap_method_init (sizeof (EAPMethodSimple),
validate,
add_to_size_group,
fill_connection,
update_secrets,
destroy,
"/org/gnome/ControlCenter/network/eap-method-simple.ui",
"eap_simple_notebook",
"eap_simple_username_entry",
flags & EAP_METHOD_SIMPLE_FLAG_PHASE2);
if (!parent)
return NULL;
parent->password_flags_name = NM_SETTING_802_1X_PASSWORD;
method = (EAPMethodSimple *) parent;
method->ws_parent = ws_parent;
method->flags = flags;
method->type = type;
g_assert (type < EAP_METHOD_SIMPLE_TYPE_LAST);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_notebook"));
g_assert (widget);
g_signal_connect (G_OBJECT (widget), "realize",
(GCallback) widgets_realized,
method);
g_signal_connect (G_OBJECT (widget), "unrealize",
(GCallback) widgets_unrealized,
method);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_username_entry"));
g_assert (widget);
method->username_entry = GTK_ENTRY (widget);
g_signal_connect (G_OBJECT (widget), "changed",
(GCallback) wireless_security_changed_cb,
ws_parent);
if (method->flags & EAP_METHOD_SIMPLE_FLAG_SECRETS_ONLY)
gtk_widget_set_sensitive (widget, FALSE);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_simple_password_entry"));
g_assert (widget);
method->password_entry = GTK_ENTRY (widget);
g_signal_connect (G_OBJECT (widget), "changed",
(GCallback) wireless_security_changed_cb,
ws_parent);
/* Create password-storage popup menu for password entry under entry's secondary icon */
if (connection)
s_8021x = nm_connection_get_setting_802_1x (connection);
nma_utils_setup_password_storage (widget, 0, (NMSetting *) s_8021x, parent->password_flags_name,
FALSE, flags & EAP_METHOD_SIMPLE_FLAG_SECRETS_ONLY);
g_signal_connect (method->password_entry, "notify::secondary-icon-name",
G_CALLBACK (password_storage_changed),
method);
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_eapsimple"));
g_assert (widget);
method->show_password = GTK_TOGGLE_BUTTON (widget);
g_signal_connect (G_OBJECT (widget), "toggled",
(GCallback) show_toggled_cb,
method);
/* Initialize the UI fields with the security settings from method->ws_parent.
* This will be done again when the widget gets realized. It must be done here as well,
* because the outer dialog will ask to 'validate' the connection before the security tab
* is shown/realized (to enable the 'Apply' button).
* As 'validate' accesses the contents of the UI fields, they must be initialized now, even
* if the widgets are not yet visible. */
set_userpass_ui (method);
return method;
}