• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 #include <dbus/dbus.h>
11 
12 #include "common.h"
13 #include "eap_peer/eap_methods.h"
14 #include "common/ieee802_11_defs.h"
15 #include "eapol_supp/eapol_supp_sm.h"
16 #include "rsn_supp/wpa.h"
17 #include "../config.h"
18 #include "../wpa_supplicant_i.h"
19 #include "../driver_i.h"
20 #include "../notify.h"
21 #include "../wpas_glue.h"
22 #include "../bss.h"
23 #include "../scan.h"
24 #include "dbus_old.h"
25 #include "dbus_old_handlers.h"
26 #include "dbus_dict_helpers.h"
27 
28 /**
29  * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
30  * @message: Pointer to incoming dbus message this error refers to
31  * Returns: a dbus error message
32  *
33  * Convenience function to create and return an invalid options error
34  */
wpas_dbus_new_invalid_opts_error(DBusMessage * message,const char * arg)35 DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
36 					       const char *arg)
37 {
38 	DBusMessage *reply;
39 
40 	reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
41 				       "Did not receive correct message "
42 				       "arguments.");
43 	if (arg != NULL)
44 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
45 					 DBUS_TYPE_INVALID);
46 
47 	return reply;
48 }
49 
50 
51 /**
52  * wpas_dbus_new_success_reply - Return a new success reply message
53  * @message: Pointer to incoming dbus message this reply refers to
54  * Returns: a dbus message containing a single UINT32 that indicates
55  *          success (ie, a value of 1)
56  *
57  * Convenience function to create and return a success reply message
58  */
wpas_dbus_new_success_reply(DBusMessage * message)59 DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
60 {
61 	DBusMessage *reply;
62 	unsigned int success = 1;
63 
64 	reply = dbus_message_new_method_return(message);
65 	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
66 				 DBUS_TYPE_INVALID);
67 	return reply;
68 }
69 
70 
71 /**
72  * wpas_dbus_global_add_interface - Request registration of a network interface
73  * @message: Pointer to incoming dbus message
74  * @global: %wpa_supplicant global data structure
75  * Returns: The object path of the new interface object,
76  *          or a dbus error message with more information
77  *
78  * Handler function for "addInterface" method call. Handles requests
79  * by dbus clients to register a network interface that wpa_supplicant
80  * will manage.
81  */
wpas_dbus_global_add_interface(DBusMessage * message,struct wpa_global * global)82 DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
83 					     struct wpa_global *global)
84 {
85 	char *ifname = NULL;
86 	char *driver = NULL;
87 	char *driver_param = NULL;
88 	char *confname = NULL;
89 	char *bridge_ifname = NULL;
90 	DBusMessage *reply = NULL;
91 	DBusMessageIter iter;
92 
93 	dbus_message_iter_init(message, &iter);
94 
95 	/* First argument: interface name (DBUS_TYPE_STRING)
96 	 *    Required; must be non-zero length
97 	 */
98 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
99 		goto error;
100 	dbus_message_iter_get_basic(&iter, &ifname);
101 	if (!os_strlen(ifname))
102 		goto error;
103 
104 	/* Second argument: dict of options */
105 	if (dbus_message_iter_next(&iter)) {
106 		DBusMessageIter iter_dict;
107 		struct wpa_dbus_dict_entry entry;
108 
109 		if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
110 			goto error;
111 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
112 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
113 				goto error;
114 			if (!strcmp(entry.key, "driver") &&
115 			    (entry.type == DBUS_TYPE_STRING)) {
116 				os_free(driver);
117 				driver = os_strdup(entry.str_value);
118 				wpa_dbus_dict_entry_clear(&entry);
119 				if (driver == NULL)
120 					goto error;
121 			} else if (!strcmp(entry.key, "driver-params") &&
122 				   (entry.type == DBUS_TYPE_STRING)) {
123 				os_free(driver_param);
124 				driver_param = os_strdup(entry.str_value);
125 				wpa_dbus_dict_entry_clear(&entry);
126 				if (driver_param == NULL)
127 					goto error;
128 			} else if (!strcmp(entry.key, "config-file") &&
129 				   (entry.type == DBUS_TYPE_STRING)) {
130 				os_free(confname);
131 				confname = os_strdup(entry.str_value);
132 				wpa_dbus_dict_entry_clear(&entry);
133 				if (confname == NULL)
134 					goto error;
135 			} else if (!strcmp(entry.key, "bridge-ifname") &&
136 				   (entry.type == DBUS_TYPE_STRING)) {
137 				os_free(bridge_ifname);
138 				bridge_ifname = os_strdup(entry.str_value);
139 				wpa_dbus_dict_entry_clear(&entry);
140 				if (bridge_ifname == NULL)
141 					goto error;
142 			} else {
143 				wpa_dbus_dict_entry_clear(&entry);
144 				goto error;
145 			}
146 		}
147 	}
148 
149 	/*
150 	 * Try to get the wpa_supplicant record for this iface, return
151 	 * an error if we already control it.
152 	 */
153 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
154 		reply = dbus_message_new_error(message,
155 					       WPAS_ERROR_EXISTS_ERROR,
156 					       "wpa_supplicant already "
157 					       "controls this interface.");
158 	} else {
159 		struct wpa_supplicant *wpa_s;
160 		struct wpa_interface iface;
161 		os_memset(&iface, 0, sizeof(iface));
162 		iface.ifname = ifname;
163 		iface.driver = driver;
164 		iface.driver_param = driver_param;
165 		iface.confname = confname;
166 		iface.bridge_ifname = bridge_ifname;
167 		/* Otherwise, have wpa_supplicant attach to it. */
168 		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
169 			const char *path = wpa_s->dbus_path;
170 			reply = dbus_message_new_method_return(message);
171 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
172 			                         &path, DBUS_TYPE_INVALID);
173 		} else {
174 			reply = dbus_message_new_error(message,
175 						       WPAS_ERROR_ADD_ERROR,
176 						       "wpa_supplicant "
177 						       "couldn't grab this "
178 						       "interface.");
179 		}
180 	}
181 
182 out:
183 	os_free(driver);
184 	os_free(driver_param);
185 	os_free(confname);
186 	os_free(bridge_ifname);
187 	return reply;
188 
189 error:
190 	reply = wpas_dbus_new_invalid_opts_error(message, NULL);
191 	goto out;
192 }
193 
194 
195 /**
196  * wpas_dbus_global_remove_interface - Request deregistration of an interface
197  * @message: Pointer to incoming dbus message
198  * @global: wpa_supplicant global data structure
199  * Returns: a dbus message containing a UINT32 indicating success (1) or
200  *          failure (0), or returns a dbus error message with more information
201  *
202  * Handler function for "removeInterface" method call.  Handles requests
203  * by dbus clients to deregister a network interface that wpa_supplicant
204  * currently manages.
205  */
wpas_dbus_global_remove_interface(DBusMessage * message,struct wpa_global * global)206 DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
207 						struct wpa_global *global)
208 {
209 	struct wpa_supplicant *wpa_s;
210 	char *path;
211 	DBusMessage *reply = NULL;
212 
213 	if (!dbus_message_get_args(message, NULL,
214 				   DBUS_TYPE_OBJECT_PATH, &path,
215 				   DBUS_TYPE_INVALID)) {
216 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
217 		goto out;
218 	}
219 
220 	wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
221 	if (wpa_s == NULL) {
222 		reply = wpas_dbus_new_invalid_iface_error(message);
223 		goto out;
224 	}
225 
226 	if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
227 		reply = wpas_dbus_new_success_reply(message);
228 	} else {
229 		reply = dbus_message_new_error(message,
230 					       WPAS_ERROR_REMOVE_ERROR,
231 					       "wpa_supplicant couldn't "
232 					       "remove this interface.");
233 	}
234 
235 out:
236 	return reply;
237 }
238 
239 
240 /**
241  * wpas_dbus_global_get_interface - Get the object path for an interface name
242  * @message: Pointer to incoming dbus message
243  * @global: %wpa_supplicant global data structure
244  * Returns: The object path of the interface object,
245  *          or a dbus error message with more information
246  *
247  * Handler function for "getInterface" method call. Handles requests
248  * by dbus clients for the object path of an specific network interface.
249  */
wpas_dbus_global_get_interface(DBusMessage * message,struct wpa_global * global)250 DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
251 					     struct wpa_global *global)
252 {
253 	DBusMessage *reply = NULL;
254 	const char *ifname;
255 	const char *path;
256 	struct wpa_supplicant *wpa_s;
257 
258 	if (!dbus_message_get_args(message, NULL,
259 	                           DBUS_TYPE_STRING, &ifname,
260 	                           DBUS_TYPE_INVALID)) {
261 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
262 		goto out;
263 	}
264 
265 	wpa_s = wpa_supplicant_get_iface(global, ifname);
266 	if (wpa_s == NULL) {
267 		reply = wpas_dbus_new_invalid_iface_error(message);
268 		goto out;
269 	}
270 
271 	path = wpa_s->dbus_path;
272 	reply = dbus_message_new_method_return(message);
273 	dbus_message_append_args(reply,
274 	                         DBUS_TYPE_OBJECT_PATH, &path,
275 	                         DBUS_TYPE_INVALID);
276 
277 out:
278 	return reply;
279 }
280 
281 
282 /**
283  * wpas_dbus_global_set_debugparams- Set the debug params
284  * @message: Pointer to incoming dbus message
285  * @global: %wpa_supplicant global data structure
286  * Returns: a dbus message containing a UINT32 indicating success (1) or
287  *          failure (0), or returns a dbus error message with more information
288  *
289  * Handler function for "setDebugParams" method call. Handles requests
290  * by dbus clients for the object path of an specific network interface.
291  */
wpas_dbus_global_set_debugparams(DBusMessage * message,struct wpa_global * global)292 DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
293 					       struct wpa_global *global)
294 {
295 	DBusMessage *reply = NULL;
296 	int debug_level;
297 	dbus_bool_t debug_timestamp;
298 	dbus_bool_t debug_show_keys;
299 
300 	if (!dbus_message_get_args(message, NULL,
301 	                           DBUS_TYPE_INT32, &debug_level,
302 	                           DBUS_TYPE_BOOLEAN, &debug_timestamp,
303 	                           DBUS_TYPE_BOOLEAN, &debug_show_keys,
304 	                           DBUS_TYPE_INVALID)) {
305 		return wpas_dbus_new_invalid_opts_error(message, NULL);
306 	}
307 
308 	if (wpa_supplicant_set_debug_params(global, debug_level,
309 					    debug_timestamp ? 1 : 0,
310 					    debug_show_keys ? 1 : 0)) {
311 		return wpas_dbus_new_invalid_opts_error(message, NULL);
312 	}
313 
314 	reply = wpas_dbus_new_success_reply(message);
315 
316 	return reply;
317 }
318 
319 
320 /**
321  * wpas_dbus_iface_scan - Request a wireless scan on an interface
322  * @message: Pointer to incoming dbus message
323  * @wpa_s: wpa_supplicant structure for a network interface
324  * Returns: a dbus message containing a UINT32 indicating success (1) or
325  *          failure (0)
326  *
327  * Handler function for "scan" method call of a network device. Requests
328  * that wpa_supplicant perform a wireless scan as soon as possible
329  * on a particular wireless interface.
330  */
wpas_dbus_iface_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)331 DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
332 				   struct wpa_supplicant *wpa_s)
333 {
334 	wpa_s->scan_req = MANUAL_SCAN_REQ;
335 	wpa_supplicant_req_scan(wpa_s, 0, 0);
336 	return wpas_dbus_new_success_reply(message);
337 }
338 
339 
340 /**
341  * wpas_dbus_iface_scan_results - Get the results of a recent scan request
342  * @message: Pointer to incoming dbus message
343  * @wpa_s: wpa_supplicant structure for a network interface
344  * Returns: a dbus message containing a dbus array of objects paths, or returns
345  *          a dbus error message if not scan results could be found
346  *
347  * Handler function for "scanResults" method call of a network device. Returns
348  * a dbus message containing the object paths of wireless networks found.
349  */
wpas_dbus_iface_scan_results(DBusMessage * message,struct wpa_supplicant * wpa_s)350 DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
351 					   struct wpa_supplicant *wpa_s)
352 {
353 	DBusMessage *reply;
354 	DBusMessageIter iter;
355 	DBusMessageIter sub_iter;
356 	struct wpa_bss *bss;
357 
358 	/* Create and initialize the return message */
359 	reply = dbus_message_new_method_return(message);
360 	dbus_message_iter_init_append(reply, &iter);
361 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
362 					      DBUS_TYPE_OBJECT_PATH_AS_STRING,
363 					      &sub_iter))
364 		goto error;
365 
366 	/* Loop through scan results and append each result's object path */
367 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
368 		char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
369 		char *path = path_buf;
370 
371 		/* Construct the object path for this network.  Note that ':'
372 		 * is not a valid character in dbus object paths.
373 		 */
374 		os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
375 			    "%s/" WPAS_DBUS_BSSIDS_PART "/"
376 			    WPAS_DBUS_BSSID_FORMAT,
377 			    wpa_s->dbus_path, MAC2STR(bss->bssid));
378 		if (!dbus_message_iter_append_basic(&sub_iter,
379 						    DBUS_TYPE_OBJECT_PATH,
380 						    &path))
381 			goto error;
382 	}
383 
384 	if (!dbus_message_iter_close_container(&iter, &sub_iter))
385 		goto error;
386 
387 	return reply;
388 
389 error:
390 	dbus_message_unref(reply);
391 	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
392 				      "an internal error occurred returning scan results");
393 }
394 
395 
396 /**
397  * wpas_dbus_bssid_properties - Return the properties of a scanned network
398  * @message: Pointer to incoming dbus message
399  * @wpa_s: wpa_supplicant structure for a network interface
400  * @res: wpa_supplicant scan result for which to get properties
401  * Returns: a dbus message containing the properties for the requested network
402  *
403  * Handler function for "properties" method call of a scanned network.
404  * Returns a dbus message containing the the properties.
405  */
wpas_dbus_bssid_properties(DBusMessage * message,struct wpa_supplicant * wpa_s,struct wpa_bss * bss)406 DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
407 					 struct wpa_supplicant *wpa_s,
408 					 struct wpa_bss *bss)
409 {
410 	DBusMessage *reply;
411 	DBusMessageIter iter, iter_dict;
412 	const u8 *ie;
413 
414 	/* Dump the properties into a dbus message */
415 	reply = dbus_message_new_method_return(message);
416 
417 	dbus_message_iter_init_append(reply, &iter);
418 	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
419 		goto error;
420 
421 	if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
422 					     (const char *) bss->bssid,
423 					     ETH_ALEN))
424 		goto error;
425 
426 	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
427 	if (ie) {
428 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
429 						     (const char *) (ie + 2),
430 						     ie[1]))
431 			goto error;
432 	}
433 
434 	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
435 	if (ie) {
436 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
437 						     (const char *) ie,
438 						     ie[1] + 2))
439 			goto error;
440 	}
441 
442 	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
443 	if (ie) {
444 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
445 						     (const char *) ie,
446 						     ie[1] + 2))
447 			goto error;
448 	}
449 
450 	ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
451 	if (ie) {
452 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
453 						     (const char *) ie,
454 						     ie[1] + 2))
455 			goto error;
456 	}
457 
458 	if (bss->freq) {
459 		if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
460 						bss->freq))
461 			goto error;
462 	}
463 	if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
464 					 bss->caps))
465 		goto error;
466 	if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
467 	    !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
468 		goto error;
469 	if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
470 	    !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
471 		goto error;
472 	if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
473 	    !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
474 		goto error;
475 	if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
476 					wpa_bss_get_max_rate(bss) * 500000))
477 		goto error;
478 
479 	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
480 		goto error;
481 
482 	return reply;
483 
484 error:
485 	if (reply)
486 		dbus_message_unref(reply);
487 	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
488 				      "an internal error occurred returning "
489 				      "BSSID properties.");
490 }
491 
492 
493 /**
494  * wpas_dbus_iface_capabilities - Return interface capabilities
495  * @message: Pointer to incoming dbus message
496  * @wpa_s: wpa_supplicant structure for a network interface
497  * Returns: A dbus message containing a dict of strings
498  *
499  * Handler function for "capabilities" method call of an interface.
500  */
wpas_dbus_iface_capabilities(DBusMessage * message,struct wpa_supplicant * wpa_s)501 DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
502 					   struct wpa_supplicant *wpa_s)
503 {
504 	DBusMessage *reply = NULL;
505 	struct wpa_driver_capa capa;
506 	int res;
507 	DBusMessageIter iter, iter_dict;
508 	char **eap_methods;
509 	size_t num_items;
510 	dbus_bool_t strict = FALSE;
511 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
512 
513 	if (!dbus_message_get_args(message, NULL,
514 				   DBUS_TYPE_BOOLEAN, &strict,
515 				   DBUS_TYPE_INVALID))
516 		strict = FALSE;
517 
518 	reply = dbus_message_new_method_return(message);
519 
520 	dbus_message_iter_init_append(reply, &iter);
521 	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
522 		goto error;
523 
524 	/* EAP methods */
525 	eap_methods = eap_get_names_as_string_array(&num_items);
526 	if (eap_methods) {
527 		dbus_bool_t success = FALSE;
528 		size_t i = 0;
529 
530 		success = wpa_dbus_dict_append_string_array(
531 			&iter_dict, "eap", (const char **) eap_methods,
532 			num_items);
533 
534 		/* free returned method array */
535 		while (eap_methods[i])
536 			os_free(eap_methods[i++]);
537 		os_free(eap_methods);
538 
539 		if (!success)
540 			goto error;
541 	}
542 
543 	res = wpa_drv_get_capa(wpa_s, &capa);
544 
545 	/***** pairwise cipher */
546 	if (res < 0) {
547 		if (!strict) {
548 			const char *args[] = {"CCMP", "TKIP", "NONE"};
549 			if (!wpa_dbus_dict_append_string_array(
550 				    &iter_dict, "pairwise", args,
551 				    ARRAY_SIZE(args)))
552 				goto error;
553 		}
554 	} else {
555 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
556 						      &iter_dict_entry,
557 						      &iter_dict_val,
558 						      &iter_array))
559 			goto error;
560 
561 		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
562 			if (!wpa_dbus_dict_string_array_add_element(
563 				    &iter_array, "CCMP"))
564 				goto error;
565 		}
566 
567 		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
568 			if (!wpa_dbus_dict_string_array_add_element(
569 				    &iter_array, "TKIP"))
570 				goto error;
571 		}
572 
573 		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
574 			if (!wpa_dbus_dict_string_array_add_element(
575 				    &iter_array, "NONE"))
576 				goto error;
577 		}
578 
579 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
580 						    &iter_dict_entry,
581 						    &iter_dict_val,
582 						    &iter_array))
583 			goto error;
584 	}
585 
586 	/***** group cipher */
587 	if (res < 0) {
588 		if (!strict) {
589 			const char *args[] = {
590 				"CCMP", "TKIP", "WEP104", "WEP40"
591 			};
592 			if (!wpa_dbus_dict_append_string_array(
593 				    &iter_dict, "group", args,
594 				    ARRAY_SIZE(args)))
595 				goto error;
596 		}
597 	} else {
598 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
599 						      &iter_dict_entry,
600 						      &iter_dict_val,
601 						      &iter_array))
602 			goto error;
603 
604 		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
605 			if (!wpa_dbus_dict_string_array_add_element(
606 				    &iter_array, "CCMP"))
607 				goto error;
608 		}
609 
610 		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
611 			if (!wpa_dbus_dict_string_array_add_element(
612 				    &iter_array, "TKIP"))
613 				goto error;
614 		}
615 
616 		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
617 			if (!wpa_dbus_dict_string_array_add_element(
618 				    &iter_array, "WEP104"))
619 				goto error;
620 		}
621 
622 		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
623 			if (!wpa_dbus_dict_string_array_add_element(
624 				    &iter_array, "WEP40"))
625 				goto error;
626 		}
627 
628 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
629 						    &iter_dict_entry,
630 						    &iter_dict_val,
631 						    &iter_array))
632 			goto error;
633 	}
634 
635 	/***** key management */
636 	if (res < 0) {
637 		if (!strict) {
638 			const char *args[] = {
639 				"WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
640 				"NONE"
641 			};
642 			if (!wpa_dbus_dict_append_string_array(
643 				    &iter_dict, "key_mgmt", args,
644 				    ARRAY_SIZE(args)))
645 				goto error;
646 		}
647 	} else {
648 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
649 						      &iter_dict_entry,
650 						      &iter_dict_val,
651 						      &iter_array))
652 			goto error;
653 
654 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
655 							    "NONE"))
656 			goto error;
657 
658 		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
659 							    "IEEE8021X"))
660 			goto error;
661 
662 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
663 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
664 			if (!wpa_dbus_dict_string_array_add_element(
665 				    &iter_array, "WPA-EAP"))
666 				goto error;
667 		}
668 
669 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
670 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
671 			if (!wpa_dbus_dict_string_array_add_element(
672 				    &iter_array, "WPA-PSK"))
673 				goto error;
674 		}
675 
676 		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
677 			if (!wpa_dbus_dict_string_array_add_element(
678 				    &iter_array, "WPA-NONE"))
679 				goto error;
680 		}
681 
682 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
683 						    &iter_dict_entry,
684 						    &iter_dict_val,
685 						    &iter_array))
686 			goto error;
687 	}
688 
689 	/***** WPA protocol */
690 	if (res < 0) {
691 		if (!strict) {
692 			const char *args[] = { "RSN", "WPA" };
693 			if (!wpa_dbus_dict_append_string_array(
694 				    &iter_dict, "proto", args,
695 				    ARRAY_SIZE(args)))
696 				goto error;
697 		}
698 	} else {
699 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
700 						      &iter_dict_entry,
701 						      &iter_dict_val,
702 						      &iter_array))
703 			goto error;
704 
705 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
706 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
707 			if (!wpa_dbus_dict_string_array_add_element(
708 				    &iter_array, "RSN"))
709 				goto error;
710 		}
711 
712 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
713 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
714 			if (!wpa_dbus_dict_string_array_add_element(
715 				    &iter_array, "WPA"))
716 				goto error;
717 		}
718 
719 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
720 						    &iter_dict_entry,
721 						    &iter_dict_val,
722 						    &iter_array))
723 			goto error;
724 	}
725 
726 	/***** auth alg */
727 	if (res < 0) {
728 		if (!strict) {
729 			const char *args[] = { "OPEN", "SHARED", "LEAP" };
730 			if (!wpa_dbus_dict_append_string_array(
731 				    &iter_dict, "auth_alg", args,
732 				    ARRAY_SIZE(args)))
733 				goto error;
734 		}
735 	} else {
736 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
737 						      &iter_dict_entry,
738 						      &iter_dict_val,
739 						      &iter_array))
740 			goto error;
741 
742 		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
743 			if (!wpa_dbus_dict_string_array_add_element(
744 				    &iter_array, "OPEN"))
745 				goto error;
746 		}
747 
748 		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
749 			if (!wpa_dbus_dict_string_array_add_element(
750 				    &iter_array, "SHARED"))
751 				goto error;
752 		}
753 
754 		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
755 			if (!wpa_dbus_dict_string_array_add_element(
756 				    &iter_array, "LEAP"))
757 				goto error;
758 		}
759 
760 		if (!wpa_dbus_dict_end_string_array(&iter_dict,
761 						    &iter_dict_entry,
762 						    &iter_dict_val,
763 						    &iter_array))
764 			goto error;
765 	}
766 
767 	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
768 		goto error;
769 
770 	return reply;
771 
772 error:
773 	if (reply)
774 		dbus_message_unref(reply);
775 	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
776 				      "an internal error occurred returning "
777 				      "interface capabilities.");
778 }
779 
780 
781 /**
782  * wpas_dbus_iface_add_network - Add a new configured network
783  * @message: Pointer to incoming dbus message
784  * @wpa_s: wpa_supplicant structure for a network interface
785  * Returns: A dbus message containing the object path of the new network
786  *
787  * Handler function for "addNetwork" method call of a network interface.
788  */
wpas_dbus_iface_add_network(DBusMessage * message,struct wpa_supplicant * wpa_s)789 DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
790 					  struct wpa_supplicant *wpa_s)
791 {
792 	DBusMessage *reply = NULL;
793 	struct wpa_ssid *ssid;
794 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
795 
796 	ssid = wpa_config_add_network(wpa_s->conf);
797 	if (ssid == NULL) {
798 		reply = dbus_message_new_error(message,
799 					       WPAS_ERROR_ADD_NETWORK_ERROR,
800 					       "wpa_supplicant could not add "
801 					       "a network on this interface.");
802 		goto out;
803 	}
804 	wpas_notify_network_added(wpa_s, ssid);
805 	ssid->disabled = 1;
806 	wpa_config_set_network_defaults(ssid);
807 
808 	/* Construct the object path for this network. */
809 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
810 		    "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
811 		    wpa_s->dbus_path, ssid->id);
812 
813 	reply = dbus_message_new_method_return(message);
814 	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
815 				 &path, DBUS_TYPE_INVALID);
816 
817 out:
818 	return reply;
819 }
820 
821 
822 /**
823  * wpas_dbus_iface_remove_network - Remove a configured network
824  * @message: Pointer to incoming dbus message
825  * @wpa_s: wpa_supplicant structure for a network interface
826  * Returns: A dbus message containing a UINT32 indicating success (1) or
827  *          failure (0)
828  *
829  * Handler function for "removeNetwork" method call of a network interface.
830  */
wpas_dbus_iface_remove_network(DBusMessage * message,struct wpa_supplicant * wpa_s)831 DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
832 					     struct wpa_supplicant *wpa_s)
833 {
834 	DBusMessage *reply = NULL;
835 	const char *op;
836 	char *iface = NULL, *net_id = NULL;
837 	int id;
838 	struct wpa_ssid *ssid;
839 
840 	if (!dbus_message_get_args(message, NULL,
841 	                           DBUS_TYPE_OBJECT_PATH, &op,
842 	                           DBUS_TYPE_INVALID)) {
843 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
844 		goto out;
845 	}
846 
847 	/* Extract the network ID */
848 	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
849 	if (iface == NULL) {
850 		reply = wpas_dbus_new_invalid_network_error(message);
851 		goto out;
852 	}
853 
854 	/* Ensure the network is actually a child of this interface */
855 	if (os_strcmp(iface, wpa_s->dbus_path) != 0) {
856 		reply = wpas_dbus_new_invalid_network_error(message);
857 		goto out;
858 	}
859 
860 	id = strtoul(net_id, NULL, 10);
861 	ssid = wpa_config_get_network(wpa_s->conf, id);
862 	if (ssid == NULL) {
863 		reply = wpas_dbus_new_invalid_network_error(message);
864 		goto out;
865 	}
866 
867 	wpas_notify_network_removed(wpa_s, ssid);
868 
869 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
870 		reply = dbus_message_new_error(message,
871 					       WPAS_ERROR_REMOVE_NETWORK_ERROR,
872 					       "error removing the specified "
873 					       "on this interface.");
874 		goto out;
875 	}
876 
877 	if (ssid == wpa_s->current_ssid)
878 		wpa_supplicant_deauthenticate(wpa_s,
879 					      WLAN_REASON_DEAUTH_LEAVING);
880 	reply = wpas_dbus_new_success_reply(message);
881 
882 out:
883 	os_free(iface);
884 	os_free(net_id);
885 	return reply;
886 }
887 
888 
889 static const char *dont_quote[] = {
890 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
891 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
892 	"bssid", NULL
893 };
894 
895 
should_quote_opt(const char * key)896 static dbus_bool_t should_quote_opt(const char *key)
897 {
898 	int i = 0;
899 	while (dont_quote[i] != NULL) {
900 		if (strcmp(key, dont_quote[i]) == 0)
901 			return FALSE;
902 		i++;
903 	}
904 	return TRUE;
905 }
906 
907 
908 /**
909  * wpas_dbus_iface_set_network - Set options for a configured network
910  * @message: Pointer to incoming dbus message
911  * @wpa_s: wpa_supplicant structure for a network interface
912  * @ssid: wpa_ssid structure for a configured network
913  * Returns: a dbus message containing a UINT32 indicating success (1) or
914  *          failure (0)
915  *
916  * Handler function for "set" method call of a configured network.
917  */
wpas_dbus_iface_set_network(DBusMessage * message,struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)918 DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
919 					  struct wpa_supplicant *wpa_s,
920 					  struct wpa_ssid *ssid)
921 {
922 	DBusMessage *reply = NULL;
923 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
924 	DBusMessageIter	iter, iter_dict;
925 
926 	dbus_message_iter_init(message, &iter);
927 
928 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
929 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
930 		goto out;
931 	}
932 
933 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
934 		char *value = NULL;
935 		size_t size = 50;
936 		int ret;
937 
938 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
939 			reply = wpas_dbus_new_invalid_opts_error(message,
940 								 NULL);
941 			goto out;
942 		}
943 
944 		/* Type conversions, since wpa_supplicant wants strings */
945 		if (entry.type == DBUS_TYPE_ARRAY &&
946 		    entry.array_type == DBUS_TYPE_BYTE) {
947 			if (entry.array_len <= 0)
948 				goto error;
949 
950 			size = entry.array_len * 2 + 1;
951 			value = os_zalloc(size);
952 			if (value == NULL)
953 				goto error;
954 			ret = wpa_snprintf_hex(value, size,
955 					       (u8 *) entry.bytearray_value,
956 					       entry.array_len);
957 			if (ret <= 0)
958 				goto error;
959 		} else if (entry.type == DBUS_TYPE_STRING) {
960 			if (should_quote_opt(entry.key)) {
961 				size = os_strlen(entry.str_value);
962 				/* Zero-length option check */
963 				if (size <= 0)
964 					goto error;
965 				size += 3;  /* For quotes and terminator */
966 				value = os_zalloc(size);
967 				if (value == NULL)
968 					goto error;
969 				ret = os_snprintf(value, size, "\"%s\"",
970 						  entry.str_value);
971 				if (ret < 0 || (size_t) ret != (size - 1))
972 					goto error;
973 			} else {
974 				value = os_strdup(entry.str_value);
975 				if (value == NULL)
976 					goto error;
977 			}
978 		} else if (entry.type == DBUS_TYPE_UINT32) {
979 			value = os_zalloc(size);
980 			if (value == NULL)
981 				goto error;
982 			ret = os_snprintf(value, size, "%u",
983 					  entry.uint32_value);
984 			if (ret <= 0)
985 				goto error;
986 		} else if (entry.type == DBUS_TYPE_INT32) {
987 			value = os_zalloc(size);
988 			if (value == NULL)
989 				goto error;
990 			ret = os_snprintf(value, size, "%d",
991 					  entry.int32_value);
992 			if (ret <= 0)
993 				goto error;
994 		} else
995 			goto error;
996 
997 		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
998 			goto error;
999 
1000 		if ((os_strcmp(entry.key, "psk") == 0 &&
1001 		     value[0] == '"' && ssid->ssid_len) ||
1002 		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
1003 			wpa_config_update_psk(ssid);
1004 		else if (os_strcmp(entry.key, "priority") == 0)
1005 			wpa_config_update_prio_list(wpa_s->conf);
1006 
1007 		os_free(value);
1008 		wpa_dbus_dict_entry_clear(&entry);
1009 		continue;
1010 
1011 	error:
1012 		os_free(value);
1013 		reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
1014 		wpa_dbus_dict_entry_clear(&entry);
1015 		break;
1016 	}
1017 
1018 	if (!reply)
1019 		reply = wpas_dbus_new_success_reply(message);
1020 
1021 out:
1022 	return reply;
1023 }
1024 
1025 
1026 /**
1027  * wpas_dbus_iface_enable_network - Mark a configured network as enabled
1028  * @message: Pointer to incoming dbus message
1029  * @wpa_s: wpa_supplicant structure for a network interface
1030  * @ssid: wpa_ssid structure for a configured network
1031  * Returns: A dbus message containing a UINT32 indicating success (1) or
1032  *          failure (0)
1033  *
1034  * Handler function for "enable" method call of a configured network.
1035  */
wpas_dbus_iface_enable_network(DBusMessage * message,struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1036 DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
1037 					     struct wpa_supplicant *wpa_s,
1038 					     struct wpa_ssid *ssid)
1039 {
1040 	wpa_supplicant_enable_network(wpa_s, ssid);
1041 	return wpas_dbus_new_success_reply(message);
1042 }
1043 
1044 
1045 /**
1046  * wpas_dbus_iface_disable_network - Mark a configured network as disabled
1047  * @message: Pointer to incoming dbus message
1048  * @wpa_s: wpa_supplicant structure for a network interface
1049  * @ssid: wpa_ssid structure for a configured network
1050  * Returns: A dbus message containing a UINT32 indicating success (1) or
1051  *          failure (0)
1052  *
1053  * Handler function for "disable" method call of a configured network.
1054  */
wpas_dbus_iface_disable_network(DBusMessage * message,struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1055 DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
1056 					      struct wpa_supplicant *wpa_s,
1057 					      struct wpa_ssid *ssid)
1058 {
1059 	wpa_supplicant_disable_network(wpa_s, ssid);
1060 	return wpas_dbus_new_success_reply(message);
1061 }
1062 
1063 
1064 /**
1065  * wpas_dbus_iface_select_network - Attempt association with a configured network
1066  * @message: Pointer to incoming dbus message
1067  * @wpa_s: wpa_supplicant structure for a network interface
1068  * Returns: A dbus message containing a UINT32 indicating success (1) or
1069  *          failure (0)
1070  *
1071  * Handler function for "selectNetwork" method call of network interface.
1072  */
wpas_dbus_iface_select_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1073 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
1074 					     struct wpa_supplicant *wpa_s)
1075 {
1076 	DBusMessage *reply = NULL;
1077 	const char *op;
1078 	struct wpa_ssid *ssid;
1079 	char *iface_obj_path = NULL;
1080 	char *network = NULL;
1081 
1082 	if (os_strlen(dbus_message_get_signature(message)) == 0) {
1083 		/* Any network */
1084 		ssid = NULL;
1085 	} else {
1086 		int nid;
1087 
1088 		if (!dbus_message_get_args(message, NULL,
1089 					   DBUS_TYPE_OBJECT_PATH, &op,
1090 					   DBUS_TYPE_INVALID)) {
1091 			reply = wpas_dbus_new_invalid_opts_error(message,
1092 								 NULL);
1093 			goto out;
1094 		}
1095 
1096 		/* Extract the network number */
1097 		iface_obj_path = wpas_dbus_decompose_object_path(op,
1098 								 &network,
1099 								 NULL);
1100 		if (iface_obj_path == NULL) {
1101 			reply = wpas_dbus_new_invalid_iface_error(message);
1102 			goto out;
1103 		}
1104 		/* Ensure the object path really points to this interface */
1105 		if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
1106 			reply = wpas_dbus_new_invalid_network_error(message);
1107 			goto out;
1108 		}
1109 
1110 		nid = strtoul(network, NULL, 10);
1111 		if (errno == EINVAL) {
1112 			reply = wpas_dbus_new_invalid_network_error(message);
1113 			goto out;
1114 		}
1115 
1116 		ssid = wpa_config_get_network(wpa_s->conf, nid);
1117 		if (ssid == NULL) {
1118 			reply = wpas_dbus_new_invalid_network_error(message);
1119 			goto out;
1120 		}
1121 	}
1122 
1123 	/* Finally, associate with the network */
1124 	wpa_supplicant_select_network(wpa_s, ssid);
1125 
1126 	reply = wpas_dbus_new_success_reply(message);
1127 
1128 out:
1129 	os_free(iface_obj_path);
1130 	os_free(network);
1131 	return reply;
1132 }
1133 
1134 
1135 /**
1136  * wpas_dbus_iface_disconnect - Terminate the current connection
1137  * @message: Pointer to incoming dbus message
1138  * @wpa_s: wpa_supplicant structure for a network interface
1139  * Returns: A dbus message containing a UINT32 indicating success (1) or
1140  *          failure (0)
1141  *
1142  * Handler function for "disconnect" method call of network interface.
1143  */
wpas_dbus_iface_disconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)1144 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1145 					 struct wpa_supplicant *wpa_s)
1146 {
1147 	wpa_s->disconnected = 1;
1148 	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1149 
1150 	return wpas_dbus_new_success_reply(message);
1151 }
1152 
1153 
1154 /**
1155  * wpas_dbus_iface_set_ap_scan - Control roaming mode
1156  * @message: Pointer to incoming dbus message
1157  * @wpa_s: wpa_supplicant structure for a network interface
1158  * Returns: A dbus message containing a UINT32 indicating success (1) or
1159  *          failure (0)
1160  *
1161  * Handler function for "setAPScan" method call.
1162  */
wpas_dbus_iface_set_ap_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)1163 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1164 					  struct wpa_supplicant *wpa_s)
1165 {
1166 	DBusMessage *reply = NULL;
1167 	dbus_uint32_t ap_scan = 1;
1168 
1169 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1170 				   DBUS_TYPE_INVALID)) {
1171 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1172 		goto out;
1173 	}
1174 
1175 	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
1176 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1177 		goto out;
1178 	}
1179 
1180 	reply = wpas_dbus_new_success_reply(message);
1181 
1182 out:
1183 	return reply;
1184 }
1185 
1186 
1187 /**
1188  * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
1189  * @message: Pointer to incoming dbus message
1190  * @wpa_s: wpa_supplicant structure for a network interface
1191  * Returns: A dbus message containing a UINT32 indicating success (1) or
1192  *          failure (0)
1193  *
1194  * Handler function for "setSmartcardModules" method call.
1195  */
wpas_dbus_iface_set_smartcard_modules(DBusMessage * message,struct wpa_supplicant * wpa_s)1196 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
1197 	DBusMessage *message, struct wpa_supplicant *wpa_s)
1198 {
1199 	DBusMessageIter iter, iter_dict;
1200 	char *opensc_engine_path = NULL;
1201 	char *pkcs11_engine_path = NULL;
1202 	char *pkcs11_module_path = NULL;
1203 	struct wpa_dbus_dict_entry entry;
1204 
1205 	if (!dbus_message_iter_init(message, &iter))
1206 		goto error;
1207 
1208 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1209 		goto error;
1210 
1211 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1212 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1213 			goto error;
1214 		if (!strcmp(entry.key, "opensc_engine_path") &&
1215 		    (entry.type == DBUS_TYPE_STRING)) {
1216 			os_free(opensc_engine_path);
1217 			opensc_engine_path = os_strdup(entry.str_value);
1218 			if (opensc_engine_path == NULL)
1219 				goto error;
1220 		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
1221 			   (entry.type == DBUS_TYPE_STRING)) {
1222 			os_free(pkcs11_engine_path);
1223 			pkcs11_engine_path = os_strdup(entry.str_value);
1224 			if (pkcs11_engine_path == NULL)
1225 				goto error;
1226 		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
1227 				 (entry.type == DBUS_TYPE_STRING)) {
1228 			os_free(pkcs11_module_path);
1229 			pkcs11_module_path = os_strdup(entry.str_value);
1230 			if (pkcs11_module_path == NULL)
1231 				goto error;
1232 		} else {
1233 			wpa_dbus_dict_entry_clear(&entry);
1234 			goto error;
1235 		}
1236 		wpa_dbus_dict_entry_clear(&entry);
1237 	}
1238 
1239 	os_free(wpa_s->conf->opensc_engine_path);
1240 	wpa_s->conf->opensc_engine_path = opensc_engine_path;
1241 	os_free(wpa_s->conf->pkcs11_engine_path);
1242 	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
1243 	os_free(wpa_s->conf->pkcs11_module_path);
1244 	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
1245 
1246 	wpa_sm_set_eapol(wpa_s->wpa, NULL);
1247 	eapol_sm_deinit(wpa_s->eapol);
1248 	wpa_s->eapol = NULL;
1249 	wpa_supplicant_init_eapol(wpa_s);
1250 	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
1251 
1252 	return wpas_dbus_new_success_reply(message);
1253 
1254 error:
1255 	os_free(opensc_engine_path);
1256 	os_free(pkcs11_engine_path);
1257 	os_free(pkcs11_module_path);
1258 	return wpas_dbus_new_invalid_opts_error(message, NULL);
1259 }
1260 
1261 
1262 /**
1263  * wpas_dbus_iface_get_state - Get interface state
1264  * @message: Pointer to incoming dbus message
1265  * @wpa_s: wpa_supplicant structure for a network interface
1266  * Returns: A dbus message containing a STRING representing the current
1267  *          interface state
1268  *
1269  * Handler function for "state" method call.
1270  */
wpas_dbus_iface_get_state(DBusMessage * message,struct wpa_supplicant * wpa_s)1271 DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
1272 					struct wpa_supplicant *wpa_s)
1273 {
1274 	DBusMessage *reply = NULL;
1275 	const char *str_state;
1276 
1277 	reply = dbus_message_new_method_return(message);
1278 	if (reply != NULL) {
1279 		str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
1280 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
1281 					 DBUS_TYPE_INVALID);
1282 	}
1283 
1284 	return reply;
1285 }
1286 
1287 
1288 /**
1289  * wpas_dbus_iface_get_scanning - Get interface scanning state
1290  * @message: Pointer to incoming dbus message
1291  * @wpa_s: wpa_supplicant structure for a network interface
1292  * Returns: A dbus message containing whether the interface is scanning
1293  *
1294  * Handler function for "scanning" method call.
1295  */
wpas_dbus_iface_get_scanning(DBusMessage * message,struct wpa_supplicant * wpa_s)1296 DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
1297 					   struct wpa_supplicant *wpa_s)
1298 {
1299 	DBusMessage *reply = NULL;
1300 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
1301 
1302 	reply = dbus_message_new_method_return(message);
1303 	if (reply != NULL) {
1304 		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
1305 					 DBUS_TYPE_INVALID);
1306 	} else {
1307 		wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
1308 			   "scanning state");
1309 	}
1310 
1311 	return reply;
1312 }
1313 
1314 
1315 #ifndef CONFIG_NO_CONFIG_BLOBS
1316 
1317 /**
1318  * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
1319  * @message: Pointer to incoming dbus message
1320  * @wpa_s: %wpa_supplicant data structure
1321  * Returns: A dbus message containing a UINT32 indicating success (1) or
1322  *          failure (0)
1323  *
1324  * Asks wpa_supplicant to internally store a one or more binary blobs.
1325  */
wpas_dbus_iface_set_blobs(DBusMessage * message,struct wpa_supplicant * wpa_s)1326 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1327 					struct wpa_supplicant *wpa_s)
1328 {
1329 	DBusMessage *reply = NULL;
1330 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1331 	DBusMessageIter	iter, iter_dict;
1332 
1333 	dbus_message_iter_init(message, &iter);
1334 
1335 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1336 		return wpas_dbus_new_invalid_opts_error(message, NULL);
1337 
1338 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1339 		struct wpa_config_blob *blob;
1340 
1341 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1342 			reply = wpas_dbus_new_invalid_opts_error(message,
1343 								 NULL);
1344 			break;
1345 		}
1346 
1347 		if (entry.type != DBUS_TYPE_ARRAY ||
1348 		    entry.array_type != DBUS_TYPE_BYTE) {
1349 			reply = wpas_dbus_new_invalid_opts_error(
1350 				message, "Byte array expected.");
1351 			break;
1352 		}
1353 
1354 		if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1355 		    !strlen(entry.key)) {
1356 			reply = wpas_dbus_new_invalid_opts_error(
1357 				message, "Invalid array size.");
1358 			break;
1359 		}
1360 
1361 		blob = os_zalloc(sizeof(*blob));
1362 		if (blob == NULL) {
1363 			reply = dbus_message_new_error(
1364 				message, WPAS_ERROR_ADD_ERROR,
1365 				"Not enough memory to add blob.");
1366 			break;
1367 		}
1368 		blob->data = os_zalloc(entry.array_len);
1369 		if (blob->data == NULL) {
1370 			reply = dbus_message_new_error(
1371 				message, WPAS_ERROR_ADD_ERROR,
1372 				"Not enough memory to add blob data.");
1373 			os_free(blob);
1374 			break;
1375 		}
1376 
1377 		blob->name = os_strdup(entry.key);
1378 		blob->len = entry.array_len;
1379 		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1380 				entry.array_len);
1381 		if (blob->name == NULL || blob->data == NULL) {
1382 			wpa_config_free_blob(blob);
1383 			reply = dbus_message_new_error(
1384 				message, WPAS_ERROR_ADD_ERROR,
1385 				"Error adding blob.");
1386 			break;
1387 		}
1388 
1389 		/* Success */
1390 		if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
1391 			wpas_notify_blob_removed(wpa_s, blob->name);
1392 		wpa_config_set_blob(wpa_s->conf, blob);
1393 		wpas_notify_blob_added(wpa_s, blob->name);
1394 
1395 		wpa_dbus_dict_entry_clear(&entry);
1396 	}
1397 	wpa_dbus_dict_entry_clear(&entry);
1398 
1399 	return reply ? reply : wpas_dbus_new_success_reply(message);
1400 }
1401 
1402 
1403 /**
1404  * wpas_dbus_iface_remove_blob - Remove named binary blobs
1405  * @message: Pointer to incoming dbus message
1406  * @wpa_s: %wpa_supplicant data structure
1407  * Returns: A dbus message containing a UINT32 indicating success (1) or
1408  *          failure (0)
1409  *
1410  * Asks wpa_supplicant to remove one or more previously stored binary blobs.
1411  */
wpas_dbus_iface_remove_blobs(DBusMessage * message,struct wpa_supplicant * wpa_s)1412 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1413 					   struct wpa_supplicant *wpa_s)
1414 {
1415 	DBusMessageIter iter, array;
1416 	char *err_msg = NULL;
1417 
1418 	dbus_message_iter_init(message, &iter);
1419 
1420 	if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
1421 	    (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
1422 		return wpas_dbus_new_invalid_opts_error(message, NULL);
1423 
1424 	dbus_message_iter_recurse(&iter, &array);
1425 	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1426 		const char *name;
1427 
1428 		dbus_message_iter_get_basic(&array, &name);
1429 		if (!os_strlen(name))
1430 			err_msg = "Invalid blob name.";
1431 
1432 		if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
1433 			err_msg = "Error removing blob.";
1434 		else
1435 			wpas_notify_blob_removed(wpa_s, name);
1436 		dbus_message_iter_next(&array);
1437 	}
1438 
1439 	if (err_msg)
1440 		return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
1441 					      err_msg);
1442 
1443 	return wpas_dbus_new_success_reply(message);
1444 }
1445 
1446 #endif /* CONFIG_NO_CONFIG_BLOBS */
1447 
1448 
1449 /**
1450  * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
1451  * @message: Pointer to incoming dbus message
1452  * @wpa_s: %wpa_supplicant data structure
1453  * Returns: a dbus message containing a UINT32 indicating success (1) or
1454  *          failure (0), or returns a dbus error message with more information
1455  *
1456  * Handler function for "flush" method call. Handles requests for an
1457  * interface with an optional "age" parameter that specifies the minimum
1458  * age of a BSS to be flushed.
1459  */
wpas_dbus_iface_flush(DBusMessage * message,struct wpa_supplicant * wpa_s)1460 DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
1461 				    struct wpa_supplicant *wpa_s)
1462 {
1463 	int flush_age = 0;
1464 
1465 	if (os_strlen(dbus_message_get_signature(message)) != 0 &&
1466 	    !dbus_message_get_args(message, NULL,
1467 				   DBUS_TYPE_INT32, &flush_age,
1468 				   DBUS_TYPE_INVALID)) {
1469 		return wpas_dbus_new_invalid_opts_error(message, NULL);
1470 	}
1471 
1472 	if (flush_age == 0)
1473 		wpa_bss_flush(wpa_s);
1474 	else
1475 		wpa_bss_flush_by_age(wpa_s, flush_age);
1476 
1477 	return wpas_dbus_new_success_reply(message);
1478 }
1479