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