1 /* 2 * WPA Supplicant / dbus-based control interface (WPS) 3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. 4 * Copyright (c) 2009, Witold Sowa <witold.sowa@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, ¶ms->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, ¶ms->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, ¶ms->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(¶ms, 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 ¶ms, &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