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_config_add_network(wpa_s->conf);
    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 	wpas_notify_network_added(wpa_s, ssid);
    728 	ssid->disabled = 1;
    729 	wpa_config_set_network_defaults(ssid);
    730 
    731 	/* Construct the object path for this network. */
    732 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
    733 		    "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
    734 		    wpa_s->dbus_path, ssid->id);
    735 
    736 	reply = dbus_message_new_method_return(message);
    737 	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
    738 				 &path, DBUS_TYPE_INVALID);
    739 
    740 out:
    741 	return reply;
    742 }
    743 
    744 
    745 /**
    746  * wpas_dbus_iface_remove_network - Remove a configured network
    747  * @message: Pointer to incoming dbus message
    748  * @wpa_s: wpa_supplicant structure for a network interface
    749  * Returns: A dbus message containing a UINT32 indicating success (1) or
    750  *          failure (0)
    751  *
    752  * Handler function for "removeNetwork" method call of a network interface.
    753  */
    754 DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
    755 					     struct wpa_supplicant *wpa_s)
    756 {
    757 	DBusMessage *reply = NULL;
    758 	const char *op;
    759 	char *iface = NULL, *net_id = NULL;
    760 	int id;
    761 	struct wpa_ssid *ssid;
    762 
    763 	if (!dbus_message_get_args(message, NULL,
    764 				   DBUS_TYPE_OBJECT_PATH, &op,
    765 				   DBUS_TYPE_INVALID)) {
    766 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
    767 		goto out;
    768 	}
    769 
    770 	/* Extract the network ID */
    771 	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
    772 	if (iface == NULL || net_id == NULL) {
    773 		reply = wpas_dbus_new_invalid_network_error(message);
    774 		goto out;
    775 	}
    776 
    777 	/* Ensure the network is actually a child of this interface */
    778 	if (!wpa_s->dbus_path || os_strcmp(iface, wpa_s->dbus_path) != 0) {
    779 		reply = wpas_dbus_new_invalid_network_error(message);
    780 		goto out;
    781 	}
    782 
    783 	id = strtoul(net_id, NULL, 10);
    784 	ssid = wpa_config_get_network(wpa_s->conf, id);
    785 	if (ssid == NULL) {
    786 		reply = wpas_dbus_new_invalid_network_error(message);
    787 		goto out;
    788 	}
    789 
    790 	wpas_notify_network_removed(wpa_s, ssid);
    791 
    792 	if (ssid == wpa_s->current_ssid)
    793 		wpa_supplicant_deauthenticate(wpa_s,
    794 					      WLAN_REASON_DEAUTH_LEAVING);
    795 
    796 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
    797 		reply = dbus_message_new_error(
    798 			message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
    799 			"error removing the specified on this interface.");
    800 		goto out;
    801 	}
    802 
    803 	reply = wpas_dbus_new_success_reply(message);
    804 
    805 out:
    806 	os_free(iface);
    807 	os_free(net_id);
    808 	return reply;
    809 }
    810 
    811 
    812 static const char * const dont_quote[] = {
    813 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
    814 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
    815 	"bssid", "scan_freq", "freq_list", NULL
    816 };
    817 
    818 
    819 static dbus_bool_t should_quote_opt(const char *key)
    820 {
    821 	int i = 0;
    822 
    823 	while (dont_quote[i] != NULL) {
    824 		if (os_strcmp(key, dont_quote[i]) == 0)
    825 			return FALSE;
    826 		i++;
    827 	}
    828 	return TRUE;
    829 }
    830 
    831 
    832 /**
    833  * wpas_dbus_iface_set_network - Set options for a configured network
    834  * @message: Pointer to incoming dbus message
    835  * @wpa_s: wpa_supplicant structure for a network interface
    836  * @ssid: wpa_ssid structure for a configured network
    837  * Returns: a dbus message containing a UINT32 indicating success (1) or
    838  *          failure (0)
    839  *
    840  * Handler function for "set" method call of a configured network.
    841  */
    842 DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
    843 					  struct wpa_supplicant *wpa_s,
    844 					  struct wpa_ssid *ssid)
    845 {
    846 	DBusMessage *reply = NULL;
    847 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
    848 	DBusMessageIter	iter, iter_dict;
    849 
    850 	dbus_message_iter_init(message, &iter);
    851 
    852 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
    853 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
    854 		goto out;
    855 	}
    856 
    857 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    858 		char *value = NULL;
    859 		size_t size = 50;
    860 		int ret;
    861 
    862 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
    863 			reply = wpas_dbus_new_invalid_opts_error(message,
    864 								 NULL);
    865 			goto out;
    866 		}
    867 
    868 		/* Type conversions, since wpa_supplicant wants strings */
    869 		if (entry.type == DBUS_TYPE_ARRAY &&
    870 		    entry.array_type == DBUS_TYPE_BYTE) {
    871 			if (entry.array_len <= 0)
    872 				goto error;
    873 
    874 			size = entry.array_len * 2 + 1;
    875 			value = os_zalloc(size);
    876 			if (value == NULL)
    877 				goto error;
    878 			ret = wpa_snprintf_hex(value, size,
    879 					       (u8 *) entry.bytearray_value,
    880 					       entry.array_len);
    881 			if (ret <= 0)
    882 				goto error;
    883 		} else if (entry.type == DBUS_TYPE_STRING) {
    884 			if (should_quote_opt(entry.key)) {
    885 				size = os_strlen(entry.str_value);
    886 				/* Zero-length option check */
    887 				if (size == 0)
    888 					goto error;
    889 				size += 3;  /* For quotes and terminator */
    890 				value = os_zalloc(size);
    891 				if (value == NULL)
    892 					goto error;
    893 				ret = os_snprintf(value, size, "\"%s\"",
    894 						  entry.str_value);
    895 				if (os_snprintf_error(size, ret))
    896 					goto error;
    897 			} else {
    898 				value = os_strdup(entry.str_value);
    899 				if (value == NULL)
    900 					goto error;
    901 			}
    902 		} else if (entry.type == DBUS_TYPE_UINT32) {
    903 			value = os_zalloc(size);
    904 			if (value == NULL)
    905 				goto error;
    906 			ret = os_snprintf(value, size, "%u",
    907 					  entry.uint32_value);
    908 			if (os_snprintf_error(size, ret))
    909 				goto error;
    910 		} else if (entry.type == DBUS_TYPE_INT32) {
    911 			value = os_zalloc(size);
    912 			if (value == NULL)
    913 				goto error;
    914 			ret = os_snprintf(value, size, "%d",
    915 					  entry.int32_value);
    916 			if (os_snprintf_error(size, ret))
    917 				goto error;
    918 		} else
    919 			goto error;
    920 
    921 		if (wpa_config_set(ssid, entry.key, value, 0) < 0)
    922 			goto error;
    923 
    924 		if ((os_strcmp(entry.key, "psk") == 0 &&
    925 		     value[0] == '"' && ssid->ssid_len) ||
    926 		    (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
    927 			wpa_config_update_psk(ssid);
    928 		else if (os_strcmp(entry.key, "priority") == 0)
    929 			wpa_config_update_prio_list(wpa_s->conf);
    930 
    931 		os_free(value);
    932 		wpa_dbus_dict_entry_clear(&entry);
    933 		continue;
    934 
    935 	error:
    936 		os_free(value);
    937 		reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
    938 		wpa_dbus_dict_entry_clear(&entry);
    939 		break;
    940 	}
    941 
    942 	if (!reply)
    943 		reply = wpas_dbus_new_success_reply(message);
    944 
    945 out:
    946 	return reply;
    947 }
    948 
    949 
    950 /**
    951  * wpas_dbus_iface_enable_network - Mark a configured network as enabled
    952  * @message: Pointer to incoming dbus message
    953  * @wpa_s: wpa_supplicant structure for a network interface
    954  * @ssid: wpa_ssid structure for a configured network
    955  * Returns: A dbus message containing a UINT32 indicating success (1) or
    956  *          failure (0)
    957  *
    958  * Handler function for "enable" method call of a configured network.
    959  */
    960 DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
    961 					     struct wpa_supplicant *wpa_s,
    962 					     struct wpa_ssid *ssid)
    963 {
    964 	wpa_supplicant_enable_network(wpa_s, ssid);
    965 	return wpas_dbus_new_success_reply(message);
    966 }
    967 
    968 
    969 /**
    970  * wpas_dbus_iface_disable_network - Mark a configured network as disabled
    971  * @message: Pointer to incoming dbus message
    972  * @wpa_s: wpa_supplicant structure for a network interface
    973  * @ssid: wpa_ssid structure for a configured network
    974  * Returns: A dbus message containing a UINT32 indicating success (1) or
    975  *          failure (0)
    976  *
    977  * Handler function for "disable" method call of a configured network.
    978  */
    979 DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
    980 					      struct wpa_supplicant *wpa_s,
    981 					      struct wpa_ssid *ssid)
    982 {
    983 	wpa_supplicant_disable_network(wpa_s, ssid);
    984 	return wpas_dbus_new_success_reply(message);
    985 }
    986 
    987 
    988 /**
    989  * wpas_dbus_iface_select_network - Attempt association with a configured network
    990  * @message: Pointer to incoming dbus message
    991  * @wpa_s: wpa_supplicant structure for a network interface
    992  * Returns: A dbus message containing a UINT32 indicating success (1) or
    993  *          failure (0)
    994  *
    995  * Handler function for "selectNetwork" method call of network interface.
    996  */
    997 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
    998 					     struct wpa_supplicant *wpa_s)
    999 {
   1000 	DBusMessage *reply = NULL;
   1001 	const char *op;
   1002 	struct wpa_ssid *ssid;
   1003 	char *iface_obj_path = NULL;
   1004 	char *network = NULL;
   1005 
   1006 	if (os_strlen(dbus_message_get_signature(message)) == 0) {
   1007 		/* Any network */
   1008 		ssid = NULL;
   1009 	} else {
   1010 		int nid;
   1011 
   1012 		if (!dbus_message_get_args(message, NULL,
   1013 					   DBUS_TYPE_OBJECT_PATH, &op,
   1014 					   DBUS_TYPE_INVALID)) {
   1015 			reply = wpas_dbus_new_invalid_opts_error(message,
   1016 								 NULL);
   1017 			goto out;
   1018 		}
   1019 
   1020 		/* Extract the network number */
   1021 		iface_obj_path = wpas_dbus_decompose_object_path(op,
   1022 								 &network,
   1023 								 NULL);
   1024 		if (iface_obj_path == NULL) {
   1025 			reply = wpas_dbus_new_invalid_iface_error(message);
   1026 			goto out;
   1027 		}
   1028 		/* Ensure the object path really points to this interface */
   1029 		if (network == NULL || !wpa_s->dbus_path ||
   1030 		    os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
   1031 			reply = wpas_dbus_new_invalid_network_error(message);
   1032 			goto out;
   1033 		}
   1034 
   1035 		nid = strtoul(network, NULL, 10);
   1036 		if (errno == EINVAL) {
   1037 			reply = wpas_dbus_new_invalid_network_error(message);
   1038 			goto out;
   1039 		}
   1040 
   1041 		ssid = wpa_config_get_network(wpa_s->conf, nid);
   1042 		if (ssid == NULL) {
   1043 			reply = wpas_dbus_new_invalid_network_error(message);
   1044 			goto out;
   1045 		}
   1046 	}
   1047 
   1048 	/* Finally, associate with the network */
   1049 	wpa_supplicant_select_network(wpa_s, ssid);
   1050 
   1051 	reply = wpas_dbus_new_success_reply(message);
   1052 
   1053 out:
   1054 	os_free(iface_obj_path);
   1055 	os_free(network);
   1056 	return reply;
   1057 }
   1058 
   1059 
   1060 /**
   1061  * wpas_dbus_iface_disconnect - Terminate the current connection
   1062  * @message: Pointer to incoming dbus message
   1063  * @wpa_s: wpa_supplicant structure for a network interface
   1064  * Returns: A dbus message containing a UINT32 indicating success (1) or
   1065  *          failure (0)
   1066  *
   1067  * Handler function for "disconnect" method call of network interface.
   1068  */
   1069 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
   1070 					 struct wpa_supplicant *wpa_s)
   1071 {
   1072 	wpa_s->disconnected = 1;
   1073 	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
   1074 
   1075 	return wpas_dbus_new_success_reply(message);
   1076 }
   1077 
   1078 
   1079 /**
   1080  * wpas_dbus_iface_set_ap_scan - Control roaming mode
   1081  * @message: Pointer to incoming dbus message
   1082  * @wpa_s: wpa_supplicant structure for a network interface
   1083  * Returns: A dbus message containing a UINT32 indicating success (1) or
   1084  *          failure (0)
   1085  *
   1086  * Handler function for "setAPScan" method call.
   1087  */
   1088 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
   1089 					  struct wpa_supplicant *wpa_s)
   1090 {
   1091 	DBusMessage *reply = NULL;
   1092 	dbus_uint32_t ap_scan = 1;
   1093 
   1094 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
   1095 				   DBUS_TYPE_INVALID)) {
   1096 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
   1097 		goto out;
   1098 	}
   1099 
   1100 	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
   1101 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
   1102 		goto out;
   1103 	}
   1104 
   1105 	reply = wpas_dbus_new_success_reply(message);
   1106 
   1107 out:
   1108 	return reply;
   1109 }
   1110 
   1111 
   1112 /**
   1113  * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
   1114  * @message: Pointer to incoming dbus message
   1115  * @wpa_s: wpa_supplicant structure for a network interface
   1116  * Returns: A dbus message containing a UINT32 indicating success (1) or
   1117  *          failure (0)
   1118  *
   1119  * Handler function for "setSmartcardModules" method call.
   1120  */
   1121 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
   1122 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   1123 {
   1124 	DBusMessageIter iter, iter_dict;
   1125 	char *opensc_engine_path = NULL;
   1126 	char *pkcs11_engine_path = NULL;
   1127 	char *pkcs11_module_path = NULL;
   1128 	struct wpa_dbus_dict_entry entry;
   1129 
   1130 	if (!dbus_message_iter_init(message, &iter))
   1131 		goto error;
   1132 
   1133 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
   1134 		goto error;
   1135 
   1136 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1137 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   1138 			goto error;
   1139 		if (!strcmp(entry.key, "opensc_engine_path") &&
   1140 		    entry.type == DBUS_TYPE_STRING) {
   1141 			os_free(opensc_engine_path);
   1142 			opensc_engine_path = os_strdup(entry.str_value);
   1143 			wpa_dbus_dict_entry_clear(&entry);
   1144 			if (opensc_engine_path == NULL)
   1145 				goto error;
   1146 		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
   1147 			   entry.type == DBUS_TYPE_STRING) {
   1148 			os_free(pkcs11_engine_path);
   1149 			pkcs11_engine_path = os_strdup(entry.str_value);
   1150 			wpa_dbus_dict_entry_clear(&entry);
   1151 			if (pkcs11_engine_path == NULL)
   1152 				goto error;
   1153 		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
   1154 				 entry.type == DBUS_TYPE_STRING) {
   1155 			os_free(pkcs11_module_path);
   1156 			pkcs11_module_path = os_strdup(entry.str_value);
   1157 			wpa_dbus_dict_entry_clear(&entry);
   1158 			if (pkcs11_module_path == NULL)
   1159 				goto error;
   1160 		} else {
   1161 			wpa_dbus_dict_entry_clear(&entry);
   1162 			goto error;
   1163 		}
   1164 	}
   1165 
   1166 	os_free(wpa_s->conf->opensc_engine_path);
   1167 	wpa_s->conf->opensc_engine_path = opensc_engine_path;
   1168 	os_free(wpa_s->conf->pkcs11_engine_path);
   1169 	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
   1170 	os_free(wpa_s->conf->pkcs11_module_path);
   1171 	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
   1172 
   1173 	wpa_sm_set_eapol(wpa_s->wpa, NULL);
   1174 	eapol_sm_deinit(wpa_s->eapol);
   1175 	wpa_s->eapol = NULL;
   1176 	wpa_supplicant_init_eapol(wpa_s);
   1177 	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
   1178 
   1179 	return wpas_dbus_new_success_reply(message);
   1180 
   1181 error:
   1182 	os_free(opensc_engine_path);
   1183 	os_free(pkcs11_engine_path);
   1184 	os_free(pkcs11_module_path);
   1185 	return wpas_dbus_new_invalid_opts_error(message, NULL);
   1186 }
   1187 
   1188 
   1189 /**
   1190  * wpas_dbus_iface_get_state - Get interface state
   1191  * @message: Pointer to incoming dbus message
   1192  * @wpa_s: wpa_supplicant structure for a network interface
   1193  * Returns: A dbus message containing a STRING representing the current
   1194  *          interface state
   1195  *
   1196  * Handler function for "state" method call.
   1197  */
   1198 DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
   1199 					struct wpa_supplicant *wpa_s)
   1200 {
   1201 	DBusMessage *reply = NULL;
   1202 	const char *str_state;
   1203 
   1204 	reply = dbus_message_new_method_return(message);
   1205 	if (reply != NULL) {
   1206 		str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
   1207 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
   1208 					 DBUS_TYPE_INVALID);
   1209 	}
   1210 
   1211 	return reply;
   1212 }
   1213 
   1214 
   1215 /**
   1216  * wpas_dbus_iface_get_scanning - Get interface scanning state
   1217  * @message: Pointer to incoming dbus message
   1218  * @wpa_s: wpa_supplicant structure for a network interface
   1219  * Returns: A dbus message containing whether the interface is scanning
   1220  *
   1221  * Handler function for "scanning" method call.
   1222  */
   1223 DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
   1224 					   struct wpa_supplicant *wpa_s)
   1225 {
   1226 	DBusMessage *reply = NULL;
   1227 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
   1228 
   1229 	reply = dbus_message_new_method_return(message);
   1230 	if (reply != NULL) {
   1231 		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
   1232 					 DBUS_TYPE_INVALID);
   1233 	} else {
   1234 		wpa_printf(MSG_ERROR,
   1235 			   "dbus: Not enough memory to return scanning state");
   1236 	}
   1237 
   1238 	return reply;
   1239 }
   1240 
   1241 
   1242 #ifndef CONFIG_NO_CONFIG_BLOBS
   1243 
   1244 /**
   1245  * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
   1246  * @message: Pointer to incoming dbus message
   1247  * @wpa_s: %wpa_supplicant data structure
   1248  * Returns: A dbus message containing a UINT32 indicating success (1) or
   1249  *          failure (0)
   1250  *
   1251  * Asks wpa_supplicant to internally store a one or more binary blobs.
   1252  */
   1253 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
   1254 					struct wpa_supplicant *wpa_s)
   1255 {
   1256 	DBusMessage *reply = NULL;
   1257 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
   1258 	DBusMessageIter	iter, iter_dict;
   1259 
   1260 	dbus_message_iter_init(message, &iter);
   1261 
   1262 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
   1263 		return wpas_dbus_new_invalid_opts_error(message, NULL);
   1264 
   1265 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1266 		struct wpa_config_blob *blob;
   1267 
   1268 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
   1269 			reply = wpas_dbus_new_invalid_opts_error(message,
   1270 								 NULL);
   1271 			break;
   1272 		}
   1273 
   1274 		if (entry.type != DBUS_TYPE_ARRAY ||
   1275 		    entry.array_type != DBUS_TYPE_BYTE) {
   1276 			reply = wpas_dbus_new_invalid_opts_error(
   1277 				message, "Byte array expected.");
   1278 			break;
   1279 		}
   1280 
   1281 		if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
   1282 		    !strlen(entry.key)) {
   1283 			reply = wpas_dbus_new_invalid_opts_error(
   1284 				message, "Invalid array size.");
   1285 			break;
   1286 		}
   1287 
   1288 		blob = os_zalloc(sizeof(*blob));
   1289 		if (blob == NULL) {
   1290 			reply = dbus_message_new_error(
   1291 				message, WPAS_ERROR_ADD_ERROR,
   1292 				"Not enough memory to add blob.");
   1293 			break;
   1294 		}
   1295 		blob->data = os_zalloc(entry.array_len);
   1296 		if (blob->data == NULL) {
   1297 			reply = dbus_message_new_error(
   1298 				message, WPAS_ERROR_ADD_ERROR,
   1299 				"Not enough memory to add blob data.");
   1300 			os_free(blob);
   1301 			break;
   1302 		}
   1303 
   1304 		blob->name = os_strdup(entry.key);
   1305 		blob->len = entry.array_len;
   1306 		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
   1307 				entry.array_len);
   1308 		if (blob->name == NULL) {
   1309 			wpa_config_free_blob(blob);
   1310 			reply = dbus_message_new_error(
   1311 				message, WPAS_ERROR_ADD_ERROR,
   1312 				"Error adding blob.");
   1313 			break;
   1314 		}
   1315 
   1316 		/* Success */
   1317 		if (!wpa_config_remove_blob(wpa_s->conf, blob->name))
   1318 			wpas_notify_blob_removed(wpa_s, blob->name);
   1319 		wpa_config_set_blob(wpa_s->conf, blob);
   1320 		wpas_notify_blob_added(wpa_s, blob->name);
   1321 
   1322 		wpa_dbus_dict_entry_clear(&entry);
   1323 	}
   1324 	wpa_dbus_dict_entry_clear(&entry);
   1325 
   1326 	return reply ? reply : wpas_dbus_new_success_reply(message);
   1327 }
   1328 
   1329 
   1330 /**
   1331  * wpas_dbus_iface_remove_blob - Remove named binary blobs
   1332  * @message: Pointer to incoming dbus message
   1333  * @wpa_s: %wpa_supplicant data structure
   1334  * Returns: A dbus message containing a UINT32 indicating success (1) or
   1335  *          failure (0)
   1336  *
   1337  * Asks wpa_supplicant to remove one or more previously stored binary blobs.
   1338  */
   1339 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
   1340 					   struct wpa_supplicant *wpa_s)
   1341 {
   1342 	DBusMessageIter iter, array;
   1343 	char *err_msg = NULL;
   1344 
   1345 	dbus_message_iter_init(message, &iter);
   1346 
   1347 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
   1348 	    dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
   1349 		return wpas_dbus_new_invalid_opts_error(message, NULL);
   1350 
   1351 	dbus_message_iter_recurse(&iter, &array);
   1352 	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
   1353 		const char *name;
   1354 
   1355 		dbus_message_iter_get_basic(&array, &name);
   1356 		if (!os_strlen(name))
   1357 			err_msg = "Invalid blob name.";
   1358 		else if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
   1359 			err_msg = "Error removing blob.";
   1360 		else
   1361 			wpas_notify_blob_removed(wpa_s, name);
   1362 		dbus_message_iter_next(&array);
   1363 	}
   1364 
   1365 	if (err_msg)
   1366 		return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
   1367 					      err_msg);
   1368 
   1369 	return wpas_dbus_new_success_reply(message);
   1370 }
   1371 
   1372 #endif /* CONFIG_NO_CONFIG_BLOBS */
   1373 
   1374 
   1375 /**
   1376  * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
   1377  * @message: Pointer to incoming dbus message
   1378  * @wpa_s: %wpa_supplicant data structure
   1379  * Returns: a dbus message containing a UINT32 indicating success (1) or
   1380  *          failure (0), or returns a dbus error message with more information
   1381  *
   1382  * Handler function for "flush" method call. Handles requests for an
   1383  * interface with an optional "age" parameter that specifies the minimum
   1384  * age of a BSS to be flushed.
   1385  */
   1386 DBusMessage * wpas_dbus_iface_flush(DBusMessage *message,
   1387 				    struct wpa_supplicant *wpa_s)
   1388 {
   1389 	int flush_age = 0;
   1390 
   1391 	if (os_strlen(dbus_message_get_signature(message)) != 0 &&
   1392 	    !dbus_message_get_args(message, NULL,
   1393 				   DBUS_TYPE_INT32, &flush_age,
   1394 				   DBUS_TYPE_INVALID)) {
   1395 		return wpas_dbus_new_invalid_opts_error(message, NULL);
   1396 	}
   1397 
   1398 	if (flush_age == 0)
   1399 		wpa_bss_flush(wpa_s);
   1400 	else
   1401 		wpa_bss_flush_by_age(wpa_s, flush_age);
   1402 
   1403 	return wpas_dbus_new_success_reply(message);
   1404 }
   1405