1214501Srpaulo/* 2214501Srpaulo * WPA Supplicant / dbus-based control interface (WPS) 3214501Srpaulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. 4214501Srpaulo * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> 5214501Srpaulo * 6252190Srpaulo * This software may be distributed under the terms of the BSD license. 7252190Srpaulo * See README for more details. 8214501Srpaulo */ 9214501Srpaulo 10214501Srpaulo#include "includes.h" 11214501Srpaulo 12214501Srpaulo#include "common.h" 13214501Srpaulo#include "../config.h" 14214501Srpaulo#include "../wpa_supplicant_i.h" 15214501Srpaulo#include "../wps_supplicant.h" 16252190Srpaulo#include "../driver_i.h" 17252190Srpaulo#include "../ap.h" 18214501Srpaulo#include "dbus_new_helpers.h" 19214501Srpaulo#include "dbus_new.h" 20214501Srpaulo#include "dbus_new_handlers.h" 21214501Srpaulo#include "dbus_dict_helpers.h" 22214501Srpaulo 23214501Srpaulo 24214501Srpaulostruct wps_start_params { 25214501Srpaulo int role; /* 0 - not set, 1 - enrollee, 2 - registrar */ 26214501Srpaulo int type; /* 0 - not set, 1 - pin, 2 - pbc */ 27214501Srpaulo u8 *bssid; 28214501Srpaulo char *pin; 29252190Srpaulo u8 *p2p_dev_addr; 30214501Srpaulo}; 31214501Srpaulo 32214501Srpaulo 33214501Srpaulostatic int wpas_dbus_handler_wps_role(DBusMessage *message, 34214501Srpaulo DBusMessageIter *entry_iter, 35214501Srpaulo struct wps_start_params *params, 36214501Srpaulo DBusMessage **reply) 37214501Srpaulo{ 38214501Srpaulo DBusMessageIter variant_iter; 39214501Srpaulo char *val; 40214501Srpaulo 41214501Srpaulo dbus_message_iter_recurse(entry_iter, &variant_iter); 42214501Srpaulo if (dbus_message_iter_get_arg_type(&variant_iter) != 43214501Srpaulo DBUS_TYPE_STRING) { 44214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, " 45214501Srpaulo "string required"); 46214501Srpaulo *reply = wpas_dbus_error_invalid_args(message, 47214501Srpaulo "Role must be a string"); 48214501Srpaulo return -1; 49214501Srpaulo } 50214501Srpaulo dbus_message_iter_get_basic(&variant_iter, &val); 51214501Srpaulo if (os_strcmp(val, "enrollee") == 0) 52214501Srpaulo params->role = 1; 53214501Srpaulo else if (os_strcmp(val, "registrar") == 0) 54214501Srpaulo params->role = 2; 55214501Srpaulo else { 56214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Uknown role %s", val); 57214501Srpaulo *reply = wpas_dbus_error_invalid_args(message, val); 58214501Srpaulo return -1; 59214501Srpaulo } 60214501Srpaulo return 0; 61214501Srpaulo} 62214501Srpaulo 63214501Srpaulo 64214501Srpaulostatic int wpas_dbus_handler_wps_type(DBusMessage *message, 65214501Srpaulo DBusMessageIter *entry_iter, 66214501Srpaulo struct wps_start_params *params, 67214501Srpaulo DBusMessage **reply) 68214501Srpaulo{ 69214501Srpaulo DBusMessageIter variant_iter; 70214501Srpaulo char *val; 71214501Srpaulo 72214501Srpaulo dbus_message_iter_recurse(entry_iter, &variant_iter); 73214501Srpaulo if (dbus_message_iter_get_arg_type(&variant_iter) != 74214501Srpaulo DBUS_TYPE_STRING) { 75214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, " 76214501Srpaulo "string required"); 77214501Srpaulo *reply = wpas_dbus_error_invalid_args(message, 78214501Srpaulo "Type must be a string"); 79214501Srpaulo return -1; 80214501Srpaulo } 81214501Srpaulo dbus_message_iter_get_basic(&variant_iter, &val); 82214501Srpaulo if (os_strcmp(val, "pin") == 0) 83214501Srpaulo params->type = 1; 84214501Srpaulo else if (os_strcmp(val, "pbc") == 0) 85214501Srpaulo params->type = 2; 86214501Srpaulo else { 87214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Unknown type %s", 88214501Srpaulo val); 89214501Srpaulo *reply = wpas_dbus_error_invalid_args(message, val); 90214501Srpaulo return -1; 91214501Srpaulo } 92214501Srpaulo return 0; 93214501Srpaulo} 94214501Srpaulo 95214501Srpaulo 96214501Srpaulostatic int wpas_dbus_handler_wps_bssid(DBusMessage *message, 97214501Srpaulo DBusMessageIter *entry_iter, 98214501Srpaulo struct wps_start_params *params, 99214501Srpaulo DBusMessage **reply) 100214501Srpaulo{ 101214501Srpaulo DBusMessageIter variant_iter, array_iter; 102214501Srpaulo int len; 103214501Srpaulo 104214501Srpaulo dbus_message_iter_recurse(entry_iter, &variant_iter); 105214501Srpaulo if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY || 106214501Srpaulo dbus_message_iter_get_element_type(&variant_iter) != 107252190Srpaulo DBUS_TYPE_BYTE) { 108214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, " 109214501Srpaulo "byte array required"); 110214501Srpaulo *reply = wpas_dbus_error_invalid_args( 111214501Srpaulo message, "Bssid must be a byte array"); 112214501Srpaulo return -1; 113214501Srpaulo } 114214501Srpaulo dbus_message_iter_recurse(&variant_iter, &array_iter); 115214501Srpaulo dbus_message_iter_get_fixed_array(&array_iter, ¶ms->bssid, &len); 116214501Srpaulo if (len != ETH_ALEN) { 117214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length " 118214501Srpaulo "%d", len); 119214501Srpaulo *reply = wpas_dbus_error_invalid_args(message, 120214501Srpaulo "Bssid is wrong length"); 121214501Srpaulo return -1; 122214501Srpaulo } 123214501Srpaulo return 0; 124214501Srpaulo} 125214501Srpaulo 126214501Srpaulo 127214501Srpaulostatic int wpas_dbus_handler_wps_pin(DBusMessage *message, 128214501Srpaulo DBusMessageIter *entry_iter, 129214501Srpaulo struct wps_start_params *params, 130214501Srpaulo DBusMessage **reply) 131214501Srpaulo{ 132214501Srpaulo DBusMessageIter variant_iter; 133214501Srpaulo 134214501Srpaulo dbus_message_iter_recurse(entry_iter, &variant_iter); 135214501Srpaulo if (dbus_message_iter_get_arg_type(&variant_iter) != 136214501Srpaulo DBUS_TYPE_STRING) { 137214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, " 138214501Srpaulo "string required"); 139214501Srpaulo *reply = wpas_dbus_error_invalid_args(message, 140214501Srpaulo "Pin must be a string"); 141214501Srpaulo return -1; 142214501Srpaulo } 143214501Srpaulo dbus_message_iter_get_basic(&variant_iter, ¶ms->pin); 144214501Srpaulo return 0; 145214501Srpaulo} 146214501Srpaulo 147214501Srpaulo 148252190Srpaulo#ifdef CONFIG_P2P 149252190Srpaulostatic int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message, 150252190Srpaulo DBusMessageIter *entry_iter, 151252190Srpaulo struct wps_start_params *params, 152252190Srpaulo DBusMessage **reply) 153252190Srpaulo{ 154252190Srpaulo DBusMessageIter variant_iter, array_iter; 155252190Srpaulo int len; 156252190Srpaulo 157252190Srpaulo dbus_message_iter_recurse(entry_iter, &variant_iter); 158252190Srpaulo if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY || 159252190Srpaulo dbus_message_iter_get_element_type(&variant_iter) != 160252190Srpaulo DBUS_TYPE_BYTE) { 161252190Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong " 162252190Srpaulo "P2PDeviceAddress type, byte array required"); 163252190Srpaulo *reply = wpas_dbus_error_invalid_args( 164252190Srpaulo message, "P2PDeviceAddress must be a byte array"); 165252190Srpaulo return -1; 166252190Srpaulo } 167252190Srpaulo dbus_message_iter_recurse(&variant_iter, &array_iter); 168252190Srpaulo dbus_message_iter_get_fixed_array(&array_iter, ¶ms->p2p_dev_addr, 169252190Srpaulo &len); 170252190Srpaulo if (len != ETH_ALEN) { 171252190Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong " 172252190Srpaulo "P2PDeviceAddress length %d", len); 173252190Srpaulo *reply = wpas_dbus_error_invalid_args(message, 174252190Srpaulo "P2PDeviceAddress " 175252190Srpaulo "has wrong length"); 176252190Srpaulo return -1; 177252190Srpaulo } 178252190Srpaulo return 0; 179252190Srpaulo} 180252190Srpaulo#endif /* CONFIG_P2P */ 181252190Srpaulo 182252190Srpaulo 183214501Srpaulostatic int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key, 184214501Srpaulo DBusMessageIter *entry_iter, 185214501Srpaulo struct wps_start_params *params, 186214501Srpaulo DBusMessage **reply) 187214501Srpaulo{ 188214501Srpaulo if (os_strcmp(key, "Role") == 0) 189214501Srpaulo return wpas_dbus_handler_wps_role(message, entry_iter, 190214501Srpaulo params, reply); 191214501Srpaulo else if (os_strcmp(key, "Type") == 0) 192214501Srpaulo return wpas_dbus_handler_wps_type(message, entry_iter, 193214501Srpaulo params, reply); 194214501Srpaulo else if (os_strcmp(key, "Bssid") == 0) 195214501Srpaulo return wpas_dbus_handler_wps_bssid(message, entry_iter, 196214501Srpaulo params, reply); 197214501Srpaulo else if (os_strcmp(key, "Pin") == 0) 198214501Srpaulo return wpas_dbus_handler_wps_pin(message, entry_iter, 199214501Srpaulo params, reply); 200252190Srpaulo#ifdef CONFIG_P2P 201252190Srpaulo else if (os_strcmp(key, "P2PDeviceAddress") == 0) 202252190Srpaulo return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter, 203252190Srpaulo params, reply); 204252190Srpaulo#endif /* CONFIG_P2P */ 205214501Srpaulo 206214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key); 207214501Srpaulo *reply = wpas_dbus_error_invalid_args(message, key); 208214501Srpaulo return -1; 209214501Srpaulo} 210214501Srpaulo 211214501Srpaulo 212214501Srpaulo/** 213214501Srpaulo * wpas_dbus_handler_wps_start - Start WPS configuration 214214501Srpaulo * @message: Pointer to incoming dbus message 215214501Srpaulo * @wpa_s: %wpa_supplicant data structure 216214501Srpaulo * Returns: DBus message dictionary on success or DBus error on failure 217214501Srpaulo * 218214501Srpaulo * Handler for "Start" method call. DBus dictionary argument contains 219214501Srpaulo * information about role (enrollee or registrar), authorization method 220214501Srpaulo * (pin or push button) and optionally pin and bssid. Returned message 221214501Srpaulo * has a dictionary argument which may contain newly generated pin (optional). 222214501Srpaulo */ 223214501SrpauloDBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, 224214501Srpaulo struct wpa_supplicant *wpa_s) 225214501Srpaulo{ 226214501Srpaulo DBusMessage *reply = NULL; 227214501Srpaulo DBusMessageIter iter, dict_iter, entry_iter; 228214501Srpaulo struct wps_start_params params; 229214501Srpaulo char *key; 230214501Srpaulo char npin[9] = { '\0' }; 231214501Srpaulo int ret; 232214501Srpaulo 233214501Srpaulo os_memset(¶ms, 0, sizeof(params)); 234214501Srpaulo dbus_message_iter_init(message, &iter); 235214501Srpaulo 236214501Srpaulo dbus_message_iter_recurse(&iter, &dict_iter); 237214501Srpaulo while (dbus_message_iter_get_arg_type(&dict_iter) == 238214501Srpaulo DBUS_TYPE_DICT_ENTRY) { 239214501Srpaulo dbus_message_iter_recurse(&dict_iter, &entry_iter); 240214501Srpaulo 241214501Srpaulo dbus_message_iter_get_basic(&entry_iter, &key); 242214501Srpaulo dbus_message_iter_next(&entry_iter); 243214501Srpaulo 244214501Srpaulo if (wpas_dbus_handler_wps_start_entry(message, key, 245214501Srpaulo &entry_iter, 246214501Srpaulo ¶ms, &reply)) 247214501Srpaulo return reply; 248214501Srpaulo 249214501Srpaulo dbus_message_iter_next(&dict_iter); 250214501Srpaulo } 251214501Srpaulo 252214501Srpaulo if (params.role == 0) { 253214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified"); 254214501Srpaulo return wpas_dbus_error_invalid_args(message, 255214501Srpaulo "Role not specified"); 256214501Srpaulo } else if (params.role == 1 && params.type == 0) { 257214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified"); 258214501Srpaulo return wpas_dbus_error_invalid_args(message, 259214501Srpaulo "Type not specified"); 260214501Srpaulo } else if (params.role == 2 && params.pin == NULL) { 261214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for " 262214501Srpaulo "registrar role"); 263214501Srpaulo return wpas_dbus_error_invalid_args( 264214501Srpaulo message, "Pin required for registrar role."); 265214501Srpaulo } 266214501Srpaulo 267214501Srpaulo if (params.role == 2) 268214501Srpaulo ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin, 269214501Srpaulo NULL); 270214501Srpaulo else if (params.type == 1) { 271252190Srpaulo#ifdef CONFIG_AP 272252190Srpaulo if (wpa_s->ap_iface) 273252190Srpaulo ret = wpa_supplicant_ap_wps_pin(wpa_s, 274252190Srpaulo params.bssid, 275252190Srpaulo params.pin, 276252190Srpaulo npin, sizeof(npin), 0); 277252190Srpaulo else 278252190Srpaulo#endif /* CONFIG_AP */ 279252190Srpaulo { 280252190Srpaulo ret = wpas_wps_start_pin(wpa_s, params.bssid, 281252190Srpaulo params.pin, 0, 282252190Srpaulo DEV_PW_DEFAULT); 283252190Srpaulo if (ret > 0) 284252190Srpaulo os_snprintf(npin, sizeof(npin), "%08d", ret); 285252190Srpaulo } 286252190Srpaulo } else { 287252190Srpaulo#ifdef CONFIG_AP 288252190Srpaulo if (wpa_s->ap_iface) 289252190Srpaulo ret = wpa_supplicant_ap_wps_pbc(wpa_s, 290252190Srpaulo params.bssid, 291252190Srpaulo params.p2p_dev_addr); 292252190Srpaulo else 293252190Srpaulo#endif /* CONFIG_AP */ 294252190Srpaulo ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0); 295252190Srpaulo } 296214501Srpaulo 297214501Srpaulo if (ret < 0) { 298214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in " 299214501Srpaulo "role %s and key %s", 300214501Srpaulo (params.role == 1 ? "enrollee" : "registrar"), 301214501Srpaulo (params.type == 0 ? "" : 302214501Srpaulo (params.type == 1 ? "pin" : "pbc"))); 303214501Srpaulo return wpas_dbus_error_unknown_error(message, 304214501Srpaulo "WPS start failed"); 305214501Srpaulo } 306214501Srpaulo 307214501Srpaulo reply = dbus_message_new_method_return(message); 308214501Srpaulo if (!reply) { 309214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 310214501Srpaulo NULL); 311214501Srpaulo } 312214501Srpaulo 313214501Srpaulo dbus_message_iter_init_append(reply, &iter); 314214501Srpaulo if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { 315214501Srpaulo dbus_message_unref(reply); 316214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 317214501Srpaulo NULL); 318214501Srpaulo } 319214501Srpaulo 320214501Srpaulo if (os_strlen(npin) > 0) { 321214501Srpaulo if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) { 322214501Srpaulo dbus_message_unref(reply); 323214501Srpaulo return dbus_message_new_error(message, 324214501Srpaulo DBUS_ERROR_NO_MEMORY, 325214501Srpaulo NULL); 326214501Srpaulo } 327214501Srpaulo } 328214501Srpaulo 329214501Srpaulo if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) { 330214501Srpaulo dbus_message_unref(reply); 331214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 332214501Srpaulo NULL); 333214501Srpaulo } 334214501Srpaulo 335214501Srpaulo return reply; 336214501Srpaulo} 337214501Srpaulo 338214501Srpaulo 339214501Srpaulo/** 340214501Srpaulo * wpas_dbus_getter_process_credentials - Check if credentials are processed 341214501Srpaulo * @message: Pointer to incoming dbus message 342214501Srpaulo * @wpa_s: %wpa_supplicant data structure 343252190Srpaulo * Returns: TRUE on success, FALSE on failure 344214501Srpaulo * 345214501Srpaulo * Getter for "ProcessCredentials" property. Returns returned boolean will be 346214501Srpaulo * true if wps_cred_processing configuration field is not equal to 1 or false 347214501Srpaulo * if otherwise. 348214501Srpaulo */ 349252190Srpaulodbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, 350252190Srpaulo DBusError *error, 351252190Srpaulo void *user_data) 352214501Srpaulo{ 353252190Srpaulo struct wpa_supplicant *wpa_s = user_data; 354214501Srpaulo dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1); 355252190Srpaulo return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 356252190Srpaulo &process, error); 357214501Srpaulo} 358214501Srpaulo 359214501Srpaulo 360214501Srpaulo/** 361214501Srpaulo * wpas_dbus_setter_process_credentials - Set credentials_processed conf param 362252190Srpaulo * @iter: Pointer to incoming dbus message iter 363252190Srpaulo * @error: Location to store error on failure 364252190Srpaulo * @user_data: Function specific data 365252190Srpaulo * Returns: TRUE on success, FALSE on failure 366214501Srpaulo * 367214501Srpaulo * Setter for "ProcessCredentials" property. Sets credentials_processed on 2 368214501Srpaulo * if boolean argument is true or on 1 if otherwise. 369214501Srpaulo */ 370252190Srpaulodbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, 371252190Srpaulo DBusError *error, 372252190Srpaulo void *user_data) 373214501Srpaulo{ 374252190Srpaulo struct wpa_supplicant *wpa_s = user_data; 375214501Srpaulo dbus_bool_t process_credentials, old_pc; 376214501Srpaulo 377252190Srpaulo if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 378252190Srpaulo &process_credentials)) 379252190Srpaulo return FALSE; 380214501Srpaulo 381214501Srpaulo old_pc = (wpa_s->conf->wps_cred_processing != 1); 382214501Srpaulo wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1); 383214501Srpaulo 384214501Srpaulo if ((wpa_s->conf->wps_cred_processing != 1) != old_pc) 385214501Srpaulo wpa_dbus_mark_property_changed(wpa_s->global->dbus, 386214501Srpaulo wpa_s->dbus_new_path, 387214501Srpaulo WPAS_DBUS_NEW_IFACE_WPS, 388214501Srpaulo "ProcessCredentials"); 389214501Srpaulo 390252190Srpaulo return TRUE; 391214501Srpaulo} 392