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