Home | History | Annotate | Download | only in dbus
      1 /*
      2  * WPA Supplicant / dbus-based control interface (WPS)
      3  * Copyright (c) 2006, Dan Williams <dcbw (at) redhat.com> and Red Hat, Inc.
      4  * Copyright (c) 2009, Witold Sowa <witold.sowa (at) gmail.com>
      5  *
      6  * This software may be distributed under the terms of the BSD license.
      7  * See README for more details.
      8  */
      9 
     10 #include "includes.h"
     11 
     12 #include "common.h"
     13 #include "../config.h"
     14 #include "../wpa_supplicant_i.h"
     15 #include "../wps_supplicant.h"
     16 #include "../driver_i.h"
     17 #include "../ap.h"
     18 #include "dbus_new_helpers.h"
     19 #include "dbus_new.h"
     20 #include "dbus_new_handlers.h"
     21 #include "dbus_dict_helpers.h"
     22 
     23 
     24 struct wps_start_params {
     25 	int role; /* 0 - not set, 1 - enrollee, 2 - registrar */
     26 	int type; /* 0 - not set, 1 - pin,      2 - pbc       */
     27 	u8 *bssid;
     28 	char *pin;
     29 	u8 *p2p_dev_addr;
     30 };
     31 
     32 
     33 static int wpas_dbus_handler_wps_role(DBusMessage *message,
     34 				      DBusMessageIter *entry_iter,
     35 				      struct wps_start_params *params,
     36 				      DBusMessage **reply)
     37 {
     38 	DBusMessageIter variant_iter;
     39 	char *val;
     40 
     41 	dbus_message_iter_recurse(entry_iter, &variant_iter);
     42 	if (dbus_message_iter_get_arg_type(&variant_iter) !=
     43 	    DBUS_TYPE_STRING) {
     44 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, "
     45 			   "string required");
     46 		*reply = wpas_dbus_error_invalid_args(message,
     47 						      "Role must be a string");
     48 		return -1;
     49 	}
     50 	dbus_message_iter_get_basic(&variant_iter, &val);
     51 	if (os_strcmp(val, "enrollee") == 0)
     52 		params->role = 1;
     53 	else if (os_strcmp(val, "registrar") == 0)
     54 		params->role = 2;
     55 	else {
     56 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Uknown role %s", val);
     57 		*reply = wpas_dbus_error_invalid_args(message, val);
     58 		return -1;
     59 	}
     60 	return 0;
     61 }
     62 
     63 
     64 static int wpas_dbus_handler_wps_type(DBusMessage *message,
     65 				      DBusMessageIter *entry_iter,
     66 				      struct wps_start_params *params,
     67 				      DBusMessage **reply)
     68 {
     69 	DBusMessageIter variant_iter;
     70 	char *val;
     71 
     72 	dbus_message_iter_recurse(entry_iter, &variant_iter);
     73 	if (dbus_message_iter_get_arg_type(&variant_iter) !=
     74 	    DBUS_TYPE_STRING) {
     75 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, "
     76 			   "string required");
     77 		*reply = wpas_dbus_error_invalid_args(message,
     78 						      "Type must be a string");
     79 		return -1;
     80 	}
     81 	dbus_message_iter_get_basic(&variant_iter, &val);
     82 	if (os_strcmp(val, "pin") == 0)
     83 		params->type = 1;
     84 	else if (os_strcmp(val, "pbc") == 0)
     85 		params->type = 2;
     86 	else {
     87 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Unknown type %s",
     88 			   val);
     89 		*reply = wpas_dbus_error_invalid_args(message, val);
     90 		return -1;
     91 	}
     92 	return 0;
     93 }
     94 
     95 
     96 static int wpas_dbus_handler_wps_bssid(DBusMessage *message,
     97 				       DBusMessageIter *entry_iter,
     98 				       struct wps_start_params *params,
     99 				       DBusMessage **reply)
    100 {
    101 	DBusMessageIter variant_iter, array_iter;
    102 	int len;
    103 
    104 	dbus_message_iter_recurse(entry_iter, &variant_iter);
    105 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
    106 	    dbus_message_iter_get_element_type(&variant_iter) !=
    107 	    DBUS_TYPE_BYTE) {
    108 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
    109 			   "byte array required");
    110 		*reply = wpas_dbus_error_invalid_args(
    111 			message, "Bssid must be a byte array");
    112 		return -1;
    113 	}
    114 	dbus_message_iter_recurse(&variant_iter, &array_iter);
    115 	dbus_message_iter_get_fixed_array(&array_iter, &params->bssid, &len);
    116 	if (len != ETH_ALEN) {
    117 		wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length "
    118 			   "%d", len);
    119 		*reply = wpas_dbus_error_invalid_args(message,
    120 						      "Bssid is wrong length");
    121 		return -1;
    122 	}
    123 	return 0;
    124 }
    125 
    126 
    127 static int wpas_dbus_handler_wps_pin(DBusMessage *message,
    128 				     DBusMessageIter *entry_iter,
    129 				     struct wps_start_params *params,
    130 				     DBusMessage **reply)
    131 {
    132 	DBusMessageIter variant_iter;
    133 
    134 	dbus_message_iter_recurse(entry_iter, &variant_iter);
    135 	if (dbus_message_iter_get_arg_type(&variant_iter) !=
    136 	    DBUS_TYPE_STRING) {
    137 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, "
    138 			   "string required");
    139 		*reply = wpas_dbus_error_invalid_args(message,
    140 						      "Pin must be a string");
    141 		return -1;
    142 	}
    143 	dbus_message_iter_get_basic(&variant_iter, &params->pin);
    144 	return 0;
    145 }
    146 
    147 
    148 #ifdef CONFIG_P2P
    149 static int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message,
    150 					      DBusMessageIter *entry_iter,
    151 					      struct wps_start_params *params,
    152 					      DBusMessage **reply)
    153 {
    154 	DBusMessageIter variant_iter, array_iter;
    155 	int len;
    156 
    157 	dbus_message_iter_recurse(entry_iter, &variant_iter);
    158 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
    159 	    dbus_message_iter_get_element_type(&variant_iter) !=
    160 	    DBUS_TYPE_BYTE) {
    161 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
    162 			   "P2PDeviceAddress type, byte array required");
    163 		*reply = wpas_dbus_error_invalid_args(
    164 			message, "P2PDeviceAddress must be a byte array");
    165 		return -1;
    166 	}
    167 	dbus_message_iter_recurse(&variant_iter, &array_iter);
    168 	dbus_message_iter_get_fixed_array(&array_iter, &params->p2p_dev_addr,
    169 					  &len);
    170 	if (len != ETH_ALEN) {
    171 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
    172 			   "P2PDeviceAddress length %d", len);
    173 		*reply = wpas_dbus_error_invalid_args(message,
    174 						      "P2PDeviceAddress "
    175 						      "has wrong length");
    176 		return -1;
    177 	}
    178 	return 0;
    179 }
    180 #endif /* CONFIG_P2P */
    181 
    182 
    183 static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key,
    184 					     DBusMessageIter *entry_iter,
    185 					     struct wps_start_params *params,
    186 					     DBusMessage **reply)
    187 {
    188 	if (os_strcmp(key, "Role") == 0)
    189 		return wpas_dbus_handler_wps_role(message, entry_iter,
    190 						  params, reply);
    191 	else if (os_strcmp(key, "Type") == 0)
    192 		return wpas_dbus_handler_wps_type(message, entry_iter,
    193 						  params, reply);
    194 	else if (os_strcmp(key, "Bssid") == 0)
    195 		return wpas_dbus_handler_wps_bssid(message, entry_iter,
    196 						   params, reply);
    197 	else if (os_strcmp(key, "Pin") == 0)
    198 		return wpas_dbus_handler_wps_pin(message, entry_iter,
    199 						 params, reply);
    200 #ifdef CONFIG_P2P
    201 	else if (os_strcmp(key, "P2PDeviceAddress") == 0)
    202 		return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter,
    203 							  params, reply);
    204 #endif /* CONFIG_P2P */
    205 
    206 	wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key);
    207 	*reply = wpas_dbus_error_invalid_args(message, key);
    208 	return -1;
    209 }
    210 
    211 
    212 /**
    213  * wpas_dbus_handler_wps_start - Start WPS configuration
    214  * @message: Pointer to incoming dbus message
    215  * @wpa_s: %wpa_supplicant data structure
    216  * Returns: DBus message dictionary on success or DBus error on failure
    217  *
    218  * Handler for "Start" method call. DBus dictionary argument contains
    219  * information about role (enrollee or registrar), authorization method
    220  * (pin or push button) and optionally pin and bssid. Returned message
    221  * has a dictionary argument which may contain newly generated pin (optional).
    222  */
    223 DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
    224 					  struct wpa_supplicant *wpa_s)
    225 {
    226 	DBusMessage *reply = NULL;
    227 	DBusMessageIter iter, dict_iter, entry_iter;
    228 	struct wps_start_params params;
    229 	char *key;
    230 	char npin[9] = { '\0' };
    231 	int ret;
    232 
    233 	os_memset(&params, 0, sizeof(params));
    234 	dbus_message_iter_init(message, &iter);
    235 
    236 	dbus_message_iter_recurse(&iter, &dict_iter);
    237 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
    238 	       DBUS_TYPE_DICT_ENTRY) {
    239 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
    240 
    241 		dbus_message_iter_get_basic(&entry_iter, &key);
    242 		dbus_message_iter_next(&entry_iter);
    243 
    244 		if (wpas_dbus_handler_wps_start_entry(message, key,
    245 						      &entry_iter,
    246 						      &params, &reply))
    247 			return reply;
    248 
    249 		dbus_message_iter_next(&dict_iter);
    250 	}
    251 
    252 	if (params.role == 0) {
    253 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified");
    254 		return wpas_dbus_error_invalid_args(message,
    255 						    "Role not specified");
    256 	} else if (params.role == 1 && params.type == 0) {
    257 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified");
    258 		return wpas_dbus_error_invalid_args(message,
    259 						    "Type not specified");
    260 	} else if (params.role == 2 && params.pin == NULL) {
    261 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for "
    262 			   "registrar role");
    263 		return wpas_dbus_error_invalid_args(
    264 			message, "Pin required for registrar role.");
    265 	}
    266 
    267 	if (params.role == 2)
    268 		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
    269 					 NULL);
    270 	else if (params.type == 1) {
    271 #ifdef CONFIG_AP
    272 		if (wpa_s->ap_iface)
    273 			ret = wpa_supplicant_ap_wps_pin(wpa_s,
    274 							params.bssid,
    275 							params.pin,
    276 							npin, sizeof(npin), 0);
    277 		else
    278 #endif /* CONFIG_AP */
    279 		{
    280 			ret = wpas_wps_start_pin(wpa_s, params.bssid,
    281 						 params.pin, 0,
    282 						 DEV_PW_DEFAULT);
    283 			if (ret > 0)
    284 				os_snprintf(npin, sizeof(npin), "%08d", ret);
    285 		}
    286 	} else {
    287 #ifdef CONFIG_AP
    288 		if (wpa_s->ap_iface)
    289 			ret = wpa_supplicant_ap_wps_pbc(wpa_s,
    290 							params.bssid,
    291 							params.p2p_dev_addr);
    292 		else
    293 #endif /* CONFIG_AP */
    294 		ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
    295 	}
    296 
    297 	if (ret < 0) {
    298 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
    299 			   "role %s and key %s",
    300 			   (params.role == 1 ? "enrollee" : "registrar"),
    301 			   (params.type == 0 ? "" :
    302 			    (params.type == 1 ? "pin" : "pbc")));
    303 		return wpas_dbus_error_unknown_error(message,
    304 						     "WPS start failed");
    305 	}
    306 
    307 	reply = dbus_message_new_method_return(message);
    308 	if (!reply) {
    309 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
    310 					      NULL);
    311 	}
    312 
    313 	dbus_message_iter_init_append(reply, &iter);
    314 	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
    315 		dbus_message_unref(reply);
    316 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
    317 					      NULL);
    318 	}
    319 
    320 	if (os_strlen(npin) > 0) {
    321 		if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) {
    322 			dbus_message_unref(reply);
    323 			return dbus_message_new_error(message,
    324 						      DBUS_ERROR_NO_MEMORY,
    325 						      NULL);
    326 		}
    327 	}
    328 
    329 	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
    330 		dbus_message_unref(reply);
    331 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
    332 					      NULL);
    333 	}
    334 
    335 	return reply;
    336 }
    337 
    338 
    339 /**
    340  * wpas_dbus_getter_process_credentials - Check if credentials are processed
    341  * @message: Pointer to incoming dbus message
    342  * @wpa_s: %wpa_supplicant data structure
    343  * Returns: TRUE on success, FALSE on failure
    344  *
    345  * Getter for "ProcessCredentials" property. Returns returned boolean will be
    346  * true if wps_cred_processing configuration field is not equal to 1 or false
    347  * if otherwise.
    348  */
    349 dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
    350 						 DBusError *error,
    351 						 void *user_data)
    352 {
    353 	struct wpa_supplicant *wpa_s = user_data;
    354 	dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
    355 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
    356 						&process, error);
    357 }
    358 
    359 
    360 /**
    361  * wpas_dbus_setter_process_credentials - Set credentials_processed conf param
    362  * @iter: Pointer to incoming dbus message iter
    363  * @error: Location to store error on failure
    364  * @user_data: Function specific data
    365  * Returns: TRUE on success, FALSE on failure
    366  *
    367  * Setter for "ProcessCredentials" property. Sets credentials_processed on 2
    368  * if boolean argument is true or on 1 if otherwise.
    369  */
    370 dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
    371 						 DBusError *error,
    372 						 void *user_data)
    373 {
    374 	struct wpa_supplicant *wpa_s = user_data;
    375 	dbus_bool_t process_credentials, old_pc;
    376 
    377 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
    378 					      &process_credentials))
    379 		return FALSE;
    380 
    381 	old_pc = (wpa_s->conf->wps_cred_processing != 1);
    382 	wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
    383 
    384 	if ((wpa_s->conf->wps_cred_processing != 1) != old_pc)
    385 		wpa_dbus_mark_property_changed(wpa_s->global->dbus,
    386 					       wpa_s->dbus_new_path,
    387 					       WPAS_DBUS_NEW_IFACE_WPS,
    388 					       "ProcessCredentials");
    389 
    390 	return TRUE;
    391 }
    392 
    393 
    394 /**
    395  * wpas_dbus_getter_config_methods - Get current WPS configuration methods
    396  * @iter: Pointer to incoming dbus message iter
    397  * @error: Location to store error on failure
    398  * @user_data: Function specific data
    399  * Returns: TRUE on success, FALSE on failure
    400  *
    401  * Getter for "ConfigMethods" property. Returned boolean will be true if
    402  * providing the relevant string worked, or false otherwise.
    403  */
    404 dbus_bool_t wpas_dbus_getter_config_methods(DBusMessageIter *iter,
    405 					    DBusError *error,
    406 					    void *user_data)
    407 {
    408 	struct wpa_supplicant *wpa_s = user_data;
    409 	char *methods = wpa_s->conf->config_methods;
    410 
    411 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
    412 						&methods, error);
    413 }
    414 
    415 
    416 /**
    417  * wpas_dbus_setter_config_methods - Set WPS configuration methods
    418  * @iter: Pointer to incoming dbus message iter
    419  * @error: Location to store error on failure
    420  * @user_data: Function specific data
    421  * Returns: TRUE on success, FALSE on failure
    422  *
    423  * Setter for "ConfigMethods" property. Sets the methods string, apply such
    424  * change and returns true on success. Returns false otherwise.
    425  */
    426 dbus_bool_t wpas_dbus_setter_config_methods(DBusMessageIter *iter,
    427 					    DBusError *error,
    428 					    void *user_data)
    429 {
    430 	struct wpa_supplicant *wpa_s = user_data;
    431 	char *methods, *new_methods;
    432 
    433 	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
    434 					      &methods))
    435 		return FALSE;
    436 
    437 	new_methods = os_strdup(methods);
    438 	if (!new_methods)
    439 		return FALSE;
    440 
    441 	os_free(wpa_s->conf->config_methods);
    442 	wpa_s->conf->config_methods = new_methods;
    443 
    444 	wpa_s->conf->changed_parameters |= CFG_CHANGED_CONFIG_METHODS;
    445 	wpa_supplicant_update_config(wpa_s);
    446 
    447 	return TRUE;
    448 }
    449