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