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