1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager Applet -- allow user control over networking
3 *
4 * Dan Williams <dcbw@redhat.com>
5 *
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.
10 *
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.
15 *
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.
19 *
20 * Copyright 2007 - 2014 Red Hat, Inc.
21 */
22
23 #include "nm-default.h"
24
25 #include <ctype.h>
26 #include <string.h>
27
28 #include "eap-method.h"
29 #include "wireless-security.h"
30 #include "utils.h"
31
32 #define I_NAME_COLUMN 0
33 #define I_METHOD_COLUMN 1
34
35 struct _EAPMethodPEAP {
36 EAPMethod parent;
37
38 GtkSizeGroup *size_group;
39 WirelessSecurity *sec_parent;
40 gboolean is_editor;
41 };
42
43 static void
destroy(EAPMethod * parent)44 destroy (EAPMethod *parent)
45 {
46 EAPMethodPEAP *method = (EAPMethodPEAP *) parent;
47
48 if (method->size_group)
49 g_object_unref (method->size_group);
50 }
51
52 static gboolean
validate(EAPMethod * parent,GError ** error)53 validate (EAPMethod *parent, GError **error)
54 {
55 GtkWidget *widget;
56 GtkTreeModel *model;
57 GtkTreeIter iter;
58 EAPMethod *eap = NULL;
59 gboolean valid = FALSE;
60 GError *local = NULL;
61
62 if (!eap_method_validate_filepicker (parent->builder, "eap_peap_ca_cert_button", TYPE_CA_CERT, NULL, NULL, &local)) {
63 g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid EAP-PEAP CA certificate: %s"), local->message);
64 g_clear_error (&local);
65 return FALSE;
66 }
67 if (eap_method_ca_cert_required (parent->builder, "eap_peap_ca_cert_not_required_checkbox", "eap_peap_ca_cert_button")) {
68 g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("invalid EAP-PEAP CA certificate: no certificate specified"));
69 return FALSE;
70 }
71
72 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
73 g_assert (widget);
74
75 model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
76 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
77 gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
78 g_assert (eap);
79 valid = eap_method_validate (eap, error);
80 eap_method_unref (eap);
81 return valid;
82 }
83
84 static void
ca_cert_not_required_toggled(GtkWidget * ignored,gpointer user_data)85 ca_cert_not_required_toggled (GtkWidget *ignored, gpointer user_data)
86 {
87 EAPMethod *parent = user_data;
88
89 eap_method_ca_cert_not_required_toggled (parent->builder, "eap_peap_ca_cert_not_required_checkbox", "eap_peap_ca_cert_button");
90 }
91
92 static void
add_to_size_group(EAPMethod * parent,GtkSizeGroup * group)93 add_to_size_group (EAPMethod *parent, GtkSizeGroup *group)
94 {
95 EAPMethodPEAP *method = (EAPMethodPEAP *) parent;
96 GtkWidget *widget;
97 GtkTreeModel *model;
98 GtkTreeIter iter;
99 EAPMethod *eap;
100
101 if (method->size_group)
102 g_object_unref (method->size_group);
103 method->size_group = g_object_ref (group);
104
105 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_not_required_checkbox"));
106 g_assert (widget);
107 gtk_size_group_add_widget (group, widget);
108
109 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_label"));
110 g_assert (widget);
111 gtk_size_group_add_widget (group, widget);
112
113 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_label"));
114 g_assert (widget);
115 gtk_size_group_add_widget (group, widget);
116
117 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_label"));
118 g_assert (widget);
119 gtk_size_group_add_widget (group, widget);
120
121 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_label"));
122 g_assert (widget);
123 gtk_size_group_add_widget (group, widget);
124
125 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
126 g_assert (widget);
127
128 model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
129 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
130 gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
131 g_assert (eap);
132 eap_method_add_to_size_group (eap, group);
133 eap_method_unref (eap);
134 }
135
136 static void
fill_connection(EAPMethod * parent,NMConnection * connection,NMSettingSecretFlags flags)137 fill_connection (EAPMethod *parent, NMConnection *connection, NMSettingSecretFlags flags)
138 {
139 NMSetting8021x *s_8021x;
140 NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
141 GtkWidget *widget;
142 const char *text;
143 char *filename;
144 EAPMethod *eap = NULL;
145 GtkTreeModel *model;
146 GtkTreeIter iter;
147 int peapver_active = 0;
148 GError *error = NULL;
149 gboolean ca_cert_error = FALSE;
150
151 s_8021x = nm_connection_get_setting_802_1x (connection);
152 g_assert (s_8021x);
153
154 nm_setting_802_1x_add_eap_method (s_8021x, "peap");
155
156 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_entry"));
157 g_assert (widget);
158 text = gtk_entry_get_text (GTK_ENTRY (widget));
159 if (text && strlen (text))
160 g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, text, NULL);
161
162 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_button"));
163 g_assert (widget);
164 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
165 if (!nm_setting_802_1x_set_ca_cert (s_8021x, filename, NM_SETTING_802_1X_CK_SCHEME_PATH, &format, &error)) {
166 g_warning ("Couldn't read CA certificate '%s': %s", filename, error ? error->message : "(unknown)");
167 g_clear_error (&error);
168 ca_cert_error = TRUE;
169 }
170 eap_method_ca_cert_ignore_set (parent, connection, filename, ca_cert_error);
171 g_free (filename);
172
173 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
174 peapver_active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
175 switch (peapver_active) {
176 case 1: /* PEAP v0 */
177 g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
178 break;
179 case 2: /* PEAP v1 */
180 g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL);
181 break;
182 default: /* Automatic */
183 g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_PEAPVER, NULL, NULL);
184 break;
185 }
186
187 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
188 model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
189 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
190 gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
191 g_assert (eap);
192
193 eap_method_fill_connection (eap, connection, flags);
194 eap_method_unref (eap);
195 }
196 static void
inner_auth_combo_changed_cb(GtkWidget * combo,gpointer user_data)197 inner_auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
198 {
199 EAPMethod *parent = (EAPMethod *) user_data;
200 EAPMethodPEAP *method = (EAPMethodPEAP *) parent;
201 GtkWidget *vbox;
202 EAPMethod *eap = NULL;
203 GList *elt, *children;
204 GtkTreeModel *model;
205 GtkTreeIter iter;
206 GtkWidget *eap_widget;
207
208 vbox = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_vbox"));
209 g_assert (vbox);
210
211 /* Remove any previous wireless security widgets */
212 children = gtk_container_get_children (GTK_CONTAINER (vbox));
213 for (elt = children; elt; elt = g_list_next (elt))
214 gtk_container_remove (GTK_CONTAINER (vbox), GTK_WIDGET (elt->data));
215
216 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
217 gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
218 gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
219 g_assert (eap);
220
221 eap_widget = eap_method_get_widget (eap);
222 g_assert (eap_widget);
223 gtk_widget_unparent (eap_widget);
224
225 if (method->size_group)
226 eap_method_add_to_size_group (eap, method->size_group);
227 gtk_container_add (GTK_CONTAINER (vbox), eap_widget);
228
229 eap_method_unref (eap);
230
231 wireless_security_changed_cb (combo, method->sec_parent);
232 }
233
234 static GtkWidget *
inner_auth_combo_init(EAPMethodPEAP * method,NMConnection * connection,NMSetting8021x * s_8021x,gboolean secrets_only)235 inner_auth_combo_init (EAPMethodPEAP *method,
236 NMConnection *connection,
237 NMSetting8021x *s_8021x,
238 gboolean secrets_only)
239 {
240 EAPMethod *parent = (EAPMethod *) method;
241 GtkWidget *combo;
242 GtkListStore *auth_model;
243 GtkTreeIter iter;
244 EAPMethodSimple *em_mschap_v2;
245 EAPMethodSimple *em_md5;
246 EAPMethodSimple *em_gtc;
247 guint32 active = 0;
248 const char *phase2_auth = NULL;
249 EAPMethodSimpleFlags simple_flags;
250
251 auth_model = gtk_list_store_new (2, G_TYPE_STRING, eap_method_get_type ());
252
253 if (s_8021x) {
254 if (nm_setting_802_1x_get_phase2_auth (s_8021x))
255 phase2_auth = nm_setting_802_1x_get_phase2_auth (s_8021x);
256 else if (nm_setting_802_1x_get_phase2_autheap (s_8021x))
257 phase2_auth = nm_setting_802_1x_get_phase2_autheap (s_8021x);
258 }
259
260 simple_flags = EAP_METHOD_SIMPLE_FLAG_PHASE2;
261 if (method->is_editor)
262 simple_flags |= EAP_METHOD_SIMPLE_FLAG_IS_EDITOR;
263 if (secrets_only)
264 simple_flags |= EAP_METHOD_SIMPLE_FLAG_SECRETS_ONLY;
265
266 em_mschap_v2 = eap_method_simple_new (method->sec_parent,
267 connection,
268 EAP_METHOD_SIMPLE_TYPE_MSCHAP_V2,
269 simple_flags);
270 gtk_list_store_append (auth_model, &iter);
271 gtk_list_store_set (auth_model, &iter,
272 I_NAME_COLUMN, _("MSCHAPv2"),
273 I_METHOD_COLUMN, em_mschap_v2,
274 -1);
275 eap_method_unref (EAP_METHOD (em_mschap_v2));
276
277 /* Check for defaulting to MSCHAPv2 */
278 if (phase2_auth && !strcasecmp (phase2_auth, "mschapv2"))
279 active = 0;
280
281 em_md5 = eap_method_simple_new (method->sec_parent,
282 connection,
283 EAP_METHOD_SIMPLE_TYPE_MD5,
284 simple_flags);
285 gtk_list_store_append (auth_model, &iter);
286 gtk_list_store_set (auth_model, &iter,
287 I_NAME_COLUMN, _("MD5"),
288 I_METHOD_COLUMN, em_md5,
289 -1);
290 eap_method_unref (EAP_METHOD (em_md5));
291
292 /* Check for defaulting to MD5 */
293 if (phase2_auth && !strcasecmp (phase2_auth, "md5"))
294 active = 1;
295
296 em_gtc = eap_method_simple_new (method->sec_parent,
297 connection,
298 EAP_METHOD_SIMPLE_TYPE_GTC,
299 simple_flags);
300 gtk_list_store_append (auth_model, &iter);
301 gtk_list_store_set (auth_model, &iter,
302 I_NAME_COLUMN, _("GTC"),
303 I_METHOD_COLUMN, em_gtc,
304 -1);
305 eap_method_unref (EAP_METHOD (em_gtc));
306
307 /* Check for defaulting to GTC */
308 if (phase2_auth && !strcasecmp (phase2_auth, "gtc"))
309 active = 2;
310
311 combo = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
312 g_assert (combo);
313
314 gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (auth_model));
315 g_object_unref (G_OBJECT (auth_model));
316 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
317
318 g_signal_connect (G_OBJECT (combo), "changed",
319 (GCallback) inner_auth_combo_changed_cb,
320 method);
321 return combo;
322 }
323
324 static void
update_secrets(EAPMethod * parent,NMConnection * connection)325 update_secrets (EAPMethod *parent, NMConnection *connection)
326 {
327 eap_method_phase2_update_secrets_helper (parent,
328 connection,
329 "eap_peap_inner_auth_combo",
330 I_METHOD_COLUMN);
331 }
332
333 EAPMethodPEAP *
eap_method_peap_new(WirelessSecurity * ws_parent,NMConnection * connection,gboolean is_editor,gboolean secrets_only)334 eap_method_peap_new (WirelessSecurity *ws_parent,
335 NMConnection *connection,
336 gboolean is_editor,
337 gboolean secrets_only)
338 {
339 EAPMethod *parent;
340 EAPMethodPEAP *method;
341 GtkWidget *widget, *widget_ca_not_required_checkbox;
342 GtkFileFilter *filter;
343 NMSetting8021x *s_8021x = NULL;
344 const char *filename;
345
346 parent = eap_method_init (sizeof (EAPMethodPEAP),
347 validate,
348 add_to_size_group,
349 fill_connection,
350 update_secrets,
351 destroy,
352 "/org/cinnamon/control-center/network/eap-method-peap.ui",
353 "eap_peap_notebook",
354 "eap_peap_anon_identity_entry",
355 FALSE);
356 if (!parent)
357 return NULL;
358
359 parent->password_flags_name = NM_SETTING_802_1X_PASSWORD;
360 method = (EAPMethodPEAP *) parent;
361 method->sec_parent = ws_parent;
362 method->is_editor = is_editor;
363
364 if (connection)
365 s_8021x = nm_connection_get_setting_802_1x (connection);
366
367 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_not_required_checkbox"));
368 g_assert (widget);
369 g_signal_connect (G_OBJECT (widget), "toggled",
370 (GCallback) ca_cert_not_required_toggled,
371 parent);
372 g_signal_connect (G_OBJECT (widget), "toggled",
373 (GCallback) wireless_security_changed_cb,
374 ws_parent);
375 widget_ca_not_required_checkbox = widget;
376
377 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_button"));
378 g_assert (widget);
379 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
380 gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget),
381 _("Choose a Certificate Authority certificate"));
382 g_signal_connect (G_OBJECT (widget), "selection-changed",
383 (GCallback) wireless_security_changed_cb,
384 ws_parent);
385 filter = eap_method_default_file_chooser_filter_new (FALSE);
386 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
387 if (connection && s_8021x) {
388 filename = NULL;
389 if (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH) {
390 filename = nm_setting_802_1x_get_ca_cert_path (s_8021x);
391 if (filename)
392 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), filename);
393 }
394 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget_ca_not_required_checkbox),
395 !filename && eap_method_ca_cert_ignore_get (parent, connection));
396 }
397
398 widget = inner_auth_combo_init (method, connection, s_8021x, secrets_only);
399 inner_auth_combo_changed_cb (widget, (gpointer) method);
400
401 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
402 g_assert (widget);
403 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
404 if (s_8021x) {
405 const char *peapver;
406
407 peapver = nm_setting_802_1x_get_phase1_peapver (s_8021x);
408 if (peapver) {
409 /* Index 0 is "Automatic" */
410 if (!strcmp (peapver, "0"))
411 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1);
412 else if (!strcmp (peapver, "1"))
413 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2);
414 }
415 }
416 g_signal_connect (G_OBJECT (widget), "changed",
417 (GCallback) wireless_security_changed_cb,
418 ws_parent);
419
420 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_entry"));
421 if (s_8021x && nm_setting_802_1x_get_anonymous_identity (s_8021x))
422 gtk_entry_set_text (GTK_ENTRY (widget), nm_setting_802_1x_get_anonymous_identity (s_8021x));
423 g_signal_connect (G_OBJECT (widget), "changed",
424 (GCallback) wireless_security_changed_cb,
425 ws_parent);
426
427 if (secrets_only) {
428 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_label"));
429 gtk_widget_hide (widget);
430 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_anon_identity_entry"));
431 gtk_widget_hide (widget);
432 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_label"));
433 gtk_widget_hide (widget);
434 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_button"));
435 gtk_widget_hide (widget);
436 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_ca_cert_not_required_checkbox"));
437 gtk_widget_hide (widget);
438 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_label"));
439 gtk_widget_hide (widget);
440 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_inner_auth_combo"));
441 gtk_widget_hide (widget);
442 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_label"));
443 gtk_widget_hide (widget);
444 widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_version_combo"));
445 gtk_widget_hide (widget);
446 }
447
448 return method;
449 }
450
451