1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/* NetworkManager Applet -- allow user control over networking
4
* Dan Williams <dcbw@redhat.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License along
17
* with this program; if not, write to the Free Software Foundation, Inc.,
18
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
* Copyright 2007 - 2014 Red Hat, Inc.
23
#include "nm-default.h"
28
#include "eap-method.h"
29
#include "wireless-security.h"
31
#include "nma-ui-utils.h"
34
struct _EAPMethodTLS {
37
gboolean editing_connection;
42
show_toggled_cb (GtkCheckButton *button, EAPMethod *method)
47
widget = GTK_WIDGET (gtk_builder_get_object (method->builder, "eap_tls_private_key_password_entry"));
50
visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
51
gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
55
validate (EAPMethod *parent, GError **error)
57
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
59
const char *password, *identity;
63
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_entry"));
65
identity = gtk_entry_get_text (GTK_ENTRY (widget));
66
if (!identity || !strlen (identity)) {
67
widget_set_error (widget);
68
g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP-TLS identity"));
71
widget_unset_error (widget);
74
if (!eap_method_validate_filepicker (parent->builder, "eap_tls_ca_cert_button", TYPE_CA_CERT, NULL, NULL, &local)) {
75
widget_set_error (GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_button")));
77
g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid EAP-TLS CA certificate: %s"), local->message);
80
g_clear_error (&local);
81
} else if (eap_method_ca_cert_required (parent->builder, "eap_tls_ca_cert_not_required_checkbox", "eap_tls_ca_cert_button")) {
82
widget_set_error (GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_button")));
84
g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid EAP-TLS CA certificate: no certificate specified"));
89
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_password_entry"));
91
password = gtk_entry_get_text (GTK_ENTRY (widget));
93
if (!eap_method_validate_filepicker (parent->builder,
94
"eap_tls_private_key_button",
100
g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid EAP-TLS private-key: %s"), local->message);
103
g_clear_error (&local);
104
widget_set_error (GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_button")));
107
if (format != NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
108
if (!eap_method_validate_filepicker (parent->builder, "eap_tls_user_cert_button", TYPE_CLIENT_CERT, NULL, NULL, &local)) {
110
g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid EAP-TLS user-certificate: %s"), local->message);
113
g_clear_error (&local);
114
widget_set_error (GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_user_cert_button")));
122
ca_cert_not_required_toggled (GtkWidget *ignored, gpointer user_data)
124
EAPMethod *parent = user_data;
126
eap_method_ca_cert_not_required_toggled (parent->builder, "eap_tls_ca_cert_not_required_checkbox", "eap_tls_ca_cert_button");
130
add_to_size_group (EAPMethod *parent, GtkSizeGroup *group)
134
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_not_required_checkbox"));
136
gtk_size_group_add_widget (group, widget);
138
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_label"));
140
gtk_size_group_add_widget (group, widget);
142
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_user_cert_label"));
144
gtk_size_group_add_widget (group, widget);
146
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_label"));
148
gtk_size_group_add_widget (group, widget);
150
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_label"));
152
gtk_size_group_add_widget (group, widget);
154
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_password_label"));
156
gtk_size_group_add_widget (group, widget);
160
fill_connection (EAPMethod *parent, NMConnection *connection, NMSettingSecretFlags flags)
162
EAPMethodTLS *method = (EAPMethodTLS *) parent;
163
NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
164
NMSetting8021x *s_8021x;
165
NMSettingSecretFlags secret_flags;
166
GtkWidget *widget, *passwd_entry;
167
char *ca_filename, *pk_filename, *cc_filename;
168
const char *password = NULL;
169
GError *error = NULL;
170
gboolean ca_cert_error = FALSE;
172
s_8021x = nm_connection_get_setting_802_1x (connection);
176
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "tls", NULL);
178
nm_setting_802_1x_add_eap_method (s_8021x, "tls");
180
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_entry"));
182
g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, gtk_entry_get_text (GTK_ENTRY (widget)), NULL);
184
/* TLS private key */
185
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_password_entry"));
187
password = gtk_entry_get_text (GTK_ENTRY (widget));
189
passwd_entry = widget;
191
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_button"));
193
pk_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
194
g_assert (pk_filename);
196
if (parent->phase2) {
197
if (!nm_setting_802_1x_set_phase2_private_key (s_8021x, pk_filename, password, NM_SETTING_802_1X_CK_SCHEME_PATH, &format, &error)) {
198
g_warning ("Couldn't read phase2 private key '%s': %s", pk_filename, error ? error->message : "(unknown)");
199
g_clear_error (&error);
202
if (!nm_setting_802_1x_set_private_key (s_8021x, pk_filename, password, NM_SETTING_802_1X_CK_SCHEME_PATH, &format, &error)) {
203
g_warning ("Couldn't read private key '%s': %s", pk_filename, error ? error->message : "(unknown)");
204
g_clear_error (&error);
207
g_free (pk_filename);
209
/* Save 802.1X password flags to the connection */
210
secret_flags = nma_utils_menu_to_secret_flags (passwd_entry);
211
nm_setting_set_secret_flags (NM_SETTING (s_8021x), parent->password_flags_name,
214
/* Update secret flags and popup when editing the connection */
215
if (method->editing_connection) {
216
nma_utils_update_password_storage (passwd_entry, secret_flags,
217
NM_SETTING (s_8021x), parent->password_flags_name);
220
/* TLS client certificate */
221
if (format != NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
222
/* If the key is pkcs#12 nm_setting_802_1x_set_private_key() already
223
* set the client certificate for us.
225
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_user_cert_button"));
227
cc_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
228
g_assert (cc_filename);
230
format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
231
if (parent->phase2) {
232
if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, cc_filename, NM_SETTING_802_1X_CK_SCHEME_PATH, &format, &error)) {
233
g_warning ("Couldn't read phase2 client certificate '%s': %s", cc_filename, error ? error->message : "(unknown)");
234
g_clear_error (&error);
237
if (!nm_setting_802_1x_set_client_cert (s_8021x, cc_filename, NM_SETTING_802_1X_CK_SCHEME_PATH, &format, &error)) {
238
g_warning ("Couldn't read client certificate '%s': %s", cc_filename, error ? error->message : "(unknown)");
239
g_clear_error (&error);
242
g_free (cc_filename);
245
/* TLS CA certificate */
246
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_button"));
248
ca_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
250
format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
251
if (parent->phase2) {
252
if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, ca_filename, NM_SETTING_802_1X_CK_SCHEME_PATH, &format, &error)) {
253
g_warning ("Couldn't read phase2 CA certificate '%s': %s", ca_filename, error ? error->message : "(unknown)");
254
g_clear_error (&error);
255
ca_cert_error = TRUE;
258
if (!nm_setting_802_1x_set_ca_cert (s_8021x, ca_filename, NM_SETTING_802_1X_CK_SCHEME_PATH, &format, &error)) {
259
g_warning ("Couldn't read CA certificate '%s': %s", ca_filename, error ? error->message : "(unknown)");
260
g_clear_error (&error);
261
ca_cert_error = TRUE;
264
eap_method_ca_cert_ignore_set (parent, connection, ca_filename, ca_cert_error);
265
g_free (ca_filename);
269
private_key_picker_helper (EAPMethod *parent, const char *filename, gboolean changed)
271
NMSetting8021x *setting;
272
NMSetting8021xCKFormat cert_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
273
const char *password;
276
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_password_entry"));
278
password = gtk_entry_get_text (GTK_ENTRY (widget));
280
setting = (NMSetting8021x *) nm_setting_802_1x_new ();
281
nm_setting_802_1x_set_private_key (setting, filename, password, NM_SETTING_802_1X_CK_SCHEME_PATH, &cert_format, NULL);
282
g_object_unref (setting);
284
/* With PKCS#12, the client cert must be the same as the private key */
285
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_user_cert_button"));
286
if (cert_format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
287
gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (widget));
288
gtk_widget_set_sensitive (widget, FALSE);
290
gtk_widget_set_sensitive (widget, TRUE);
292
/* Warn the user if the private key is unencrypted */
293
if (!eap_method_is_encrypted_private_key (filename)) {
296
GtkWindow *parent_window = NULL;
298
toplevel = gtk_widget_get_toplevel (parent->ui_widget);
299
if (gtk_widget_is_toplevel (toplevel))
300
parent_window = GTK_WINDOW (toplevel);
302
dialog = gtk_message_dialog_new (parent_window,
303
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
307
_("Unencrypted private keys are insecure"));
308
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
310
_("The selected private key does not appear to be protected by a password. This could allow your security credentials to be compromised. Please select a password-protected private key.\n\n(You can password-protect your private key with openssl)"));
311
gtk_dialog_run (GTK_DIALOG (dialog));
312
gtk_widget_destroy (dialog);
317
private_key_picker_file_set_cb (GtkWidget *chooser, gpointer user_data)
319
EAPMethod *parent = (EAPMethod *) user_data;
322
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
324
private_key_picker_helper (parent, filename, TRUE);
328
static void reset_filter (GtkWidget *widget, GParamSpec *spec, gpointer user_data)
330
if (!gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (widget))) {
331
g_signal_handlers_block_by_func (widget, reset_filter, user_data);
332
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), GTK_FILE_FILTER (user_data));
333
g_signal_handlers_unblock_by_func (widget, reset_filter, user_data);
337
typedef const char * (*PathFunc) (NMSetting8021x *setting);
338
typedef NMSetting8021xCKScheme (*SchemeFunc) (NMSetting8021x *setting);
341
setup_filepicker (GtkBuilder *builder,
344
WirelessSecurity *ws_parent,
346
NMSetting8021x *s_8021x,
347
SchemeFunc scheme_func,
350
gboolean client_cert)
353
GtkFileFilter *filter;
354
const char *filename = NULL;
356
widget = GTK_WIDGET (gtk_builder_get_object (builder, name));
358
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
359
gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget), title);
361
if (s_8021x && path_func && scheme_func) {
362
if (scheme_func (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
363
filename = path_func (s_8021x);
365
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), filename);
369
/* Connect a special handler for private keys to intercept PKCS#12 key types
370
* and desensitize the user cert button.
373
g_signal_connect (G_OBJECT (widget), "selection-changed",
374
(GCallback) private_key_picker_file_set_cb,
377
private_key_picker_helper (parent, filename, FALSE);
380
g_signal_connect (G_OBJECT (widget), "selection-changed",
381
(GCallback) wireless_security_changed_cb,
384
filter = eap_method_default_file_chooser_filter_new (privkey);
385
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
387
/* For some reason, GTK+ calls set_current_filter (..., NULL) from
388
* gtkfilechooserdefault.c::show_and_select_files_finished_loading() on our
389
* dialog; so force-reset the filter to what we want it to be whenever
393
g_signal_connect (G_OBJECT (widget), "notify::filter", (GCallback) reset_filter, filter);
397
update_secrets (EAPMethod *parent, NMConnection *connection)
399
NMSetting8021x *s_8021x;
400
HelperSecretFunc password_func;
401
SchemeFunc scheme_func;
403
const char *filename;
406
if (parent->phase2) {
407
password_func = (HelperSecretFunc) nm_setting_802_1x_get_phase2_private_key_password;
408
scheme_func = nm_setting_802_1x_get_phase2_private_key_scheme;
409
path_func = nm_setting_802_1x_get_phase2_private_key_path;
411
password_func = (HelperSecretFunc) nm_setting_802_1x_get_private_key_password;
412
scheme_func = nm_setting_802_1x_get_private_key_scheme;
413
path_func = nm_setting_802_1x_get_private_key_path;
416
helper_fill_secret_entry (connection,
418
"eap_tls_private_key_password_entry",
419
NM_TYPE_SETTING_802_1X,
422
/* Set the private key filepicker button path if we have a private key */
423
s_8021x = nm_connection_get_setting_802_1x (connection);
424
if (s_8021x && (scheme_func (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH)) {
425
filename = path_func (s_8021x);
427
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_button"));
429
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), filename);
435
eap_method_tls_new (WirelessSecurity *ws_parent,
436
NMConnection *connection,
438
gboolean secrets_only)
440
EAPMethodTLS *method;
443
NMSetting8021x *s_8021x = NULL;
444
gboolean ca_not_required = FALSE;
446
parent = eap_method_init (sizeof (EAPMethodTLS),
452
"/org/freedesktop/network-manager-applet/eap-method-tls.ui",
454
"eap_tls_identity_entry",
459
parent->password_flags_name = phase2 ?
460
NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD :
461
NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD;
462
method = (EAPMethodTLS *) parent;
463
method->editing_connection = secrets_only ? FALSE : TRUE;
466
s_8021x = nm_connection_get_setting_802_1x (connection);
468
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_not_required_checkbox"));
470
g_signal_connect (G_OBJECT (widget), "toggled",
471
(GCallback) ca_cert_not_required_toggled,
473
g_signal_connect (G_OBJECT (widget), "toggled",
474
(GCallback) wireless_security_changed_cb,
477
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_entry"));
479
g_signal_connect (G_OBJECT (widget), "changed",
480
(GCallback) wireless_security_changed_cb,
482
if (s_8021x && nm_setting_802_1x_get_identity (s_8021x))
483
gtk_entry_set_text (GTK_ENTRY (widget), nm_setting_802_1x_get_identity (s_8021x));
485
setup_filepicker (parent->builder, "eap_tls_user_cert_button",
486
_("Choose your personal certificate"),
487
ws_parent, parent, s_8021x,
488
phase2 ? nm_setting_802_1x_get_phase2_client_cert_scheme : nm_setting_802_1x_get_client_cert_scheme,
489
phase2 ? nm_setting_802_1x_get_phase2_client_cert_path : nm_setting_802_1x_get_client_cert_path,
491
setup_filepicker (parent->builder, "eap_tls_ca_cert_button",
492
_("Choose a Certificate Authority certificate"),
493
ws_parent, parent, s_8021x,
494
phase2 ? nm_setting_802_1x_get_phase2_ca_cert_scheme : nm_setting_802_1x_get_ca_cert_scheme,
495
phase2 ? nm_setting_802_1x_get_phase2_ca_cert_path : nm_setting_802_1x_get_ca_cert_path,
497
setup_filepicker (parent->builder, "eap_tls_private_key_button",
498
_("Choose your private key"),
499
ws_parent, parent, s_8021x,
500
phase2 ? nm_setting_802_1x_get_phase2_private_key_scheme : nm_setting_802_1x_get_private_key_scheme,
501
phase2 ? nm_setting_802_1x_get_phase2_private_key_path : nm_setting_802_1x_get_private_key_path,
504
if (connection && eap_method_ca_cert_ignore_get (parent, connection)) {
505
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_button"));
506
ca_not_required = !gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
508
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_not_required_checkbox"));
509
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), ca_not_required);
511
/* Fill secrets, if any */
513
update_secrets (parent, connection);
515
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_password_entry"));
517
g_signal_connect (G_OBJECT (widget), "changed",
518
(GCallback) wireless_security_changed_cb,
521
/* Create password-storage popup menu for password entry under entry's secondary icon */
522
nma_utils_setup_password_storage (widget, 0, (NMSetting *) s_8021x, parent->password_flags_name,
523
FALSE, secrets_only);
525
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_eaptls"));
527
g_signal_connect (G_OBJECT (widget), "toggled",
528
(GCallback) show_toggled_cb,
532
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_identity_entry"));
533
gtk_widget_set_sensitive (widget, FALSE);
534
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_user_cert_label"));
535
gtk_widget_hide (widget);
536
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_user_cert_button"));
537
gtk_widget_hide (widget);
538
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_label"));
539
gtk_widget_hide (widget);
540
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_private_key_button"));
541
gtk_widget_hide (widget);
542
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_label"));
543
gtk_widget_hide (widget);
544
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_button"));
545
gtk_widget_hide (widget);
546
widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_tls_ca_cert_not_required_checkbox"));
547
gtk_widget_hide (widget);