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