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