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