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