1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* vim: set ft=c ts=4 sts=4 sw=4 noexpandtab smartindent: */
3 
4 /* EAP-FAST authentication method (RFC4851)
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 2012 - 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 #include "helpers.h"
32 
33 #define I_NAME_COLUMN   0
34 #define I_METHOD_COLUMN 1
35 
36 struct _EAPMethodFAST {
37 	EAPMethod parent;
38 
39 	GtkSizeGroup *size_group;
40 	WirelessSecurity *sec_parent;
41 	gboolean is_editor;
42 };
43 
44 static void
destroy(EAPMethod * parent)45 destroy (EAPMethod *parent)
46 {
47 	EAPMethodFAST *method = (EAPMethodFAST *) parent;
48 
49 	if (method->size_group)
50 		g_object_unref (method->size_group);
51 }
52 
53 static gboolean
validate(EAPMethod * parent,GError ** error)54 validate (EAPMethod *parent, GError **error)
55 {
56 	GtkWidget *widget;
57 	GtkTreeModel *model;
58 	GtkTreeIter iter;
59 	EAPMethod *eap = NULL;
60 	const char *file;
61 	gboolean provisioning;
62 	gboolean valid = TRUE;
63 
64 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
65 	g_assert (widget);
66 	provisioning = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
67 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_button"));
68 	g_assert (widget);
69 	file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
70 	if (!provisioning && !file) {
71 		widget_set_error (widget);
72 		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing EAP-FAST PAC file"));
73 		valid = FALSE;
74 	} else
75 		widget_unset_error (widget);
76 
77 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
78 	g_assert (widget);
79 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
80 	gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
81 	gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
82 	g_assert (eap);
83 	valid = eap_method_validate (eap, valid ? error : NULL) && valid;
84 	eap_method_unref (eap);
85 	return valid;
86 }
87 
88 static void
add_to_size_group(EAPMethod * parent,GtkSizeGroup * group)89 add_to_size_group (EAPMethod *parent, GtkSizeGroup *group)
90 {
91 	EAPMethodFAST *method = (EAPMethodFAST *) parent;
92 	GtkWidget *widget;
93 	GtkTreeModel *model;
94 	GtkTreeIter iter;
95 	EAPMethod *eap;
96 
97 	if (method->size_group)
98 		g_object_unref (method->size_group);
99 	method->size_group = g_object_ref (group);
100 
101 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_anon_identity_label"));
102 	g_assert (widget);
103 	gtk_size_group_add_widget (group, widget);
104 
105 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_label"));
106 	g_assert (widget);
107 	gtk_size_group_add_widget (group, widget);
108 
109 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
110 	g_assert (widget);
111 	gtk_size_group_add_widget (group, widget);
112 
113 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_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_fast_inner_auth_combo"));
118 	g_assert (widget);
119 
120 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
121 	gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
122 	gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
123 	g_assert (eap);
124 	eap_method_add_to_size_group (eap, group);
125 	eap_method_unref (eap);
126 }
127 
128 static void
fill_connection(EAPMethod * parent,NMConnection * connection,NMSettingSecretFlags flags)129 fill_connection (EAPMethod *parent, NMConnection *connection, NMSettingSecretFlags flags)
130 {
131 	NMSetting8021x *s_8021x;
132 	GtkWidget *widget;
133 	const char *text;
134 	char *filename;
135 	EAPMethod *eap = NULL;
136 	GtkTreeModel *model;
137 	GtkTreeIter iter;
138 	gboolean enabled;
139 	int pac_provisioning = 0;
140 
141 	s_8021x = nm_connection_get_setting_802_1x (connection);
142 	g_assert (s_8021x);
143 
144 	nm_setting_802_1x_add_eap_method (s_8021x, "fast");
145 
146 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_anon_identity_entry"));
147 	g_assert (widget);
148 	text = gtk_entry_get_text (GTK_ENTRY (widget));
149 	if (text && strlen (text))
150 		g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, text, NULL);
151 
152 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_button"));
153 	g_assert (widget);
154 	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
155 	g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, filename, NULL);
156 
157 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
158 	enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
159 
160 	if (!enabled)
161 		g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "0", NULL);
162 	else {
163 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_combo"));
164 		pac_provisioning = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
165 
166 		switch (pac_provisioning) {
167 		case 0:  /* Anonymous */
168 			g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "1", NULL);
169 			break;
170 		case 1:  /* Authenticated */
171 			g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "2", NULL);
172 			break;
173 		case 2:  /* Both - anonymous and authenticated */
174 			g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "3", NULL);
175 			break;
176 		default: /* Should not happen */
177 			g_object_set (G_OBJECT (s_8021x), NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, "1", NULL);
178 			break;
179 		}
180 	}
181 
182 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
183 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
184 	gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter);
185 	gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
186 	g_assert (eap);
187 
188 	eap_method_fill_connection (eap, connection, flags);
189 	eap_method_unref (eap);
190 }
191 
192 static void
inner_auth_combo_changed_cb(GtkWidget * combo,gpointer user_data)193 inner_auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
194 {
195 	EAPMethod *parent = (EAPMethod *) user_data;
196 	EAPMethodFAST *method = (EAPMethodFAST *) parent;
197 	GtkWidget *vbox;
198 	EAPMethod *eap = NULL;
199 	GList *elt, *children;
200 	GtkTreeModel *model;
201 	GtkTreeIter iter;
202 	GtkWidget *eap_widget;
203 
204 	vbox = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_vbox"));
205 	g_assert (vbox);
206 
207 	/* Remove any previous wireless security widgets */
208 	children = gtk_container_get_children (GTK_CONTAINER (vbox));
209 	for (elt = children; elt; elt = g_list_next (elt))
210 		gtk_container_remove (GTK_CONTAINER (vbox), GTK_WIDGET (elt->data));
211 	g_list_free (children);
212 
213 	model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
214 	gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
215 	gtk_tree_model_get (model, &iter, I_METHOD_COLUMN, &eap, -1);
216 	g_assert (eap);
217 
218 	eap_widget = eap_method_get_widget (eap);
219 	g_assert (eap_widget);
220 	gtk_widget_unparent (eap_widget);
221 
222 	if (method->size_group)
223 		eap_method_add_to_size_group (eap, method->size_group);
224 	gtk_container_add (GTK_CONTAINER (vbox), eap_widget);
225 
226 	eap_method_unref (eap);
227 
228 	wireless_security_changed_cb (combo, method->sec_parent);
229 }
230 
231 static GtkWidget *
inner_auth_combo_init(EAPMethodFAST * method,NMConnection * connection,NMSetting8021x * s_8021x,gboolean secrets_only)232 inner_auth_combo_init (EAPMethodFAST *method,
233                        NMConnection *connection,
234                        NMSetting8021x *s_8021x,
235                        gboolean secrets_only)
236 {
237 	EAPMethod *parent = (EAPMethod *) method;
238 	GtkWidget *combo;
239 	GtkListStore *auth_model;
240 	GtkTreeIter iter;
241 	EAPMethodSimple *em_gtc;
242 	EAPMethodSimple *em_mschap_v2;
243 	guint32 active = 0;
244 	const char *phase2_auth = NULL;
245 	EAPMethodSimpleFlags simple_flags;
246 
247 	auth_model = gtk_list_store_new (2, G_TYPE_STRING, eap_method_get_type ());
248 
249 	if (s_8021x) {
250 		if (nm_setting_802_1x_get_phase2_auth (s_8021x))
251 			phase2_auth = nm_setting_802_1x_get_phase2_auth (s_8021x);
252 		else if (nm_setting_802_1x_get_phase2_autheap (s_8021x))
253 			phase2_auth = nm_setting_802_1x_get_phase2_autheap (s_8021x);
254 	}
255 
256 	simple_flags = EAP_METHOD_SIMPLE_FLAG_PHASE2;
257 	if (method->is_editor)
258 		simple_flags |= EAP_METHOD_SIMPLE_FLAG_IS_EDITOR;
259 	if (secrets_only)
260 		simple_flags |= EAP_METHOD_SIMPLE_FLAG_SECRETS_ONLY;
261 
262 	em_gtc = eap_method_simple_new (method->sec_parent,
263 	                                connection,
264 	                                EAP_METHOD_SIMPLE_TYPE_GTC,
265 	                                simple_flags);
266 	gtk_list_store_append (auth_model, &iter);
267 	gtk_list_store_set (auth_model, &iter,
268 	                    I_NAME_COLUMN, _("GTC"),
269 	                    I_METHOD_COLUMN, em_gtc,
270 	                    -1);
271 	eap_method_unref (EAP_METHOD (em_gtc));
272 
273 	/* Check for defaulting to GTC */
274 	if (phase2_auth && !strcasecmp (phase2_auth, "gtc"))
275 		active = 0;
276 
277 	em_mschap_v2 = eap_method_simple_new (method->sec_parent,
278 	                                      connection,
279 	                                      EAP_METHOD_SIMPLE_TYPE_MSCHAP_V2,
280 	                                      simple_flags);
281 	gtk_list_store_append (auth_model, &iter);
282 	gtk_list_store_set (auth_model, &iter,
283 	                    I_NAME_COLUMN, _("MSCHAPv2"),
284 	                    I_METHOD_COLUMN, em_mschap_v2,
285 	                    -1);
286 	eap_method_unref (EAP_METHOD (em_mschap_v2));
287 
288 	/* Check for defaulting to MSCHAPv2 */
289 	if (phase2_auth && !strcasecmp (phase2_auth, "mschapv2"))
290 		active = 1;
291 
292 	combo = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
293 	g_assert (combo);
294 
295 	gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (auth_model));
296 	g_object_unref (G_OBJECT (auth_model));
297 	gtk_combo_box_set_active (GTK_COMBO_BOX (combo), active);
298 
299 	g_signal_connect (G_OBJECT (combo), "changed",
300 	                  (GCallback) inner_auth_combo_changed_cb,
301 	                  method);
302 	return combo;
303 }
304 
305 static void
update_secrets(EAPMethod * parent,NMConnection * connection)306 update_secrets (EAPMethod *parent, NMConnection *connection)
307 {
308 	eap_method_phase2_update_secrets_helper (parent,
309 	                                         connection,
310 	                                         "eap_fast_inner_auth_combo",
311 	                                         I_METHOD_COLUMN);
312 }
313 
314 static void
pac_toggled_cb(GtkWidget * widget,gpointer user_data)315 pac_toggled_cb (GtkWidget *widget, gpointer user_data)
316 {
317 	EAPMethod *parent = (EAPMethod *) user_data;
318 	EAPMethodFAST *method = (EAPMethodFAST *) parent;
319 	gboolean enabled = FALSE;
320 	GtkWidget *provision_combo;
321 
322 	provision_combo = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_combo"));
323 	g_return_if_fail (provision_combo);
324 
325 	enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
326 
327 	gtk_widget_set_sensitive (provision_combo, enabled);
328 
329 	wireless_security_changed_cb (widget, method->sec_parent);
330 }
331 
332 EAPMethodFAST *
eap_method_fast_new(WirelessSecurity * ws_parent,NMConnection * connection,gboolean is_editor,gboolean secrets_only)333 eap_method_fast_new (WirelessSecurity *ws_parent,
334                      NMConnection *connection,
335                      gboolean is_editor,
336                      gboolean secrets_only)
337 {
338 	EAPMethod *parent;
339 	EAPMethodFAST *method;
340 	GtkWidget *widget;
341 	GtkFileFilter *filter;
342 	NMSetting8021x *s_8021x = NULL;
343 	const char *filename;
344 	gboolean provisioning_enabled = TRUE;
345 
346 	parent = eap_method_init (sizeof (EAPMethodFAST),
347 	                          validate,
348 	                          add_to_size_group,
349 	                          fill_connection,
350 	                          update_secrets,
351 	                          destroy,
352 	                          "/org/cinnamon/control-center/network/eap-method-fast.ui",
353 	                          "eap_fast_notebook",
354 	                          "eap_fast_anon_identity_entry",
355 	                          FALSE);
356 	if (!parent)
357 		return NULL;
358 
359 	parent->password_flags_name = NM_SETTING_802_1X_PASSWORD;
360 	method = (EAPMethodFAST *) 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 
368 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_combo"));
369 	g_assert (widget);
370 	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
371 	if (s_8021x) {
372 		const char *fast_prov;
373 
374 		fast_prov = nm_setting_802_1x_get_phase1_fast_provisioning (s_8021x);
375 		if (fast_prov) {
376 			if (!strcmp (fast_prov, "0"))
377 				provisioning_enabled = FALSE;
378 			else if (!strcmp (fast_prov, "1"))
379 				gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
380 			else if (!strcmp (fast_prov, "2"))
381 				gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 1);
382 			else if (!strcmp (fast_prov, "3"))
383 				gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 2);
384 		}
385 	}
386 	gtk_widget_set_sensitive (widget, provisioning_enabled);
387 	g_signal_connect (G_OBJECT (widget), "changed",
388 	                  (GCallback) wireless_security_changed_cb,
389 	                  ws_parent);
390 
391 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
392 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), provisioning_enabled);
393 	g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (pac_toggled_cb), parent);
394 
395 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_anon_identity_entry"));
396 	if (s_8021x && nm_setting_802_1x_get_anonymous_identity (s_8021x))
397 		gtk_entry_set_text (GTK_ENTRY (widget), nm_setting_802_1x_get_anonymous_identity (s_8021x));
398 	g_signal_connect (G_OBJECT (widget), "changed",
399 	                  (GCallback) wireless_security_changed_cb,
400 	                  ws_parent);
401 
402 	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_button"));
403 	g_assert (widget);
404 	gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
405 	gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget),
406 	                                   _("Choose a PAC file"));
407 	g_signal_connect (G_OBJECT (widget), "selection-changed",
408 	                  (GCallback) wireless_security_changed_cb,
409 	                  ws_parent);
410 
411 	filter = gtk_file_filter_new ();
412 	gtk_file_filter_add_pattern (filter, "*.pac");
413 	gtk_file_filter_set_name (filter, _("PAC files (*.pac)"));
414 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
415 	filter = gtk_file_filter_new ();
416 	gtk_file_filter_add_pattern (filter, "*");
417 	gtk_file_filter_set_name (filter, _("All files"));
418 	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
419 
420 	if (connection && s_8021x) {
421 		filename = nm_setting_802_1x_get_pac_file (s_8021x);
422 		if (filename)
423 			gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), filename);
424 	}
425 
426 	widget = inner_auth_combo_init (method, connection, s_8021x, secrets_only);
427 	inner_auth_combo_changed_cb (widget, (gpointer) method);
428 
429 	if (secrets_only) {
430 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_anon_identity_label"));
431 		gtk_widget_hide (widget);
432 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_anon_identity_entry"));
433 		gtk_widget_hide (widget);
434 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_checkbutton"));
435 		gtk_widget_hide (widget);
436 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_provision_combo"));
437 		gtk_widget_hide (widget);
438 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_label"));
439 		gtk_widget_hide (widget);
440 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_pac_file_button"));
441 		gtk_widget_hide (widget);
442 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_label"));
443 		gtk_widget_hide (widget);
444 		widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_fast_inner_auth_combo"));
445 		gtk_widget_hide (widget);
446 	}
447 
448 	return method;
449 }
450 
451