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