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 program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Alternatively, this software may be distributed under the terms of BSD 11 * license. 12 * 13 * See README and COPYING for more details. 14 */ 15 16 #include "includes.h" 17 18 #include "common.h" 19 #include "../config.h" 20 #include "../wpa_supplicant_i.h" 21 #include "../wps_supplicant.h" 22 #include "../driver_i.h" 23 #include "../ap.h" 24 #include "dbus_new_helpers.h" 25 #include "dbus_new.h" 26 #include "dbus_new_handlers.h" 27 #include "dbus_dict_helpers.h" 28 29 30 struct wps_start_params { 31 int role; /* 0 - not set, 1 - enrollee, 2 - registrar */ 32 int type; /* 0 - not set, 1 - pin, 2 - pbc */ 33 u8 *bssid; 34 char *pin; 35 u8 *p2p_dev_addr; 36 }; 37 38 39 static int wpas_dbus_handler_wps_role(DBusMessage *message, 40 DBusMessageIter *entry_iter, 41 struct wps_start_params *params, 42 DBusMessage **reply) 43 { 44 DBusMessageIter variant_iter; 45 char *val; 46 47 dbus_message_iter_recurse(entry_iter, &variant_iter); 48 if (dbus_message_iter_get_arg_type(&variant_iter) != 49 DBUS_TYPE_STRING) { 50 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, " 51 "string required"); 52 *reply = wpas_dbus_error_invalid_args(message, 53 "Role must be a string"); 54 return -1; 55 } 56 dbus_message_iter_get_basic(&variant_iter, &val); 57 if (os_strcmp(val, "enrollee") == 0) 58 params->role = 1; 59 else if (os_strcmp(val, "registrar") == 0) 60 params->role = 2; 61 else { 62 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Uknown role %s", val); 63 *reply = wpas_dbus_error_invalid_args(message, val); 64 return -1; 65 } 66 return 0; 67 } 68 69 70 static int wpas_dbus_handler_wps_type(DBusMessage *message, 71 DBusMessageIter *entry_iter, 72 struct wps_start_params *params, 73 DBusMessage **reply) 74 { 75 DBusMessageIter variant_iter; 76 char *val; 77 78 dbus_message_iter_recurse(entry_iter, &variant_iter); 79 if (dbus_message_iter_get_arg_type(&variant_iter) != 80 DBUS_TYPE_STRING) { 81 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, " 82 "string required"); 83 *reply = wpas_dbus_error_invalid_args(message, 84 "Type must be a string"); 85 return -1; 86 } 87 dbus_message_iter_get_basic(&variant_iter, &val); 88 if (os_strcmp(val, "pin") == 0) 89 params->type = 1; 90 else if (os_strcmp(val, "pbc") == 0) 91 params->type = 2; 92 else { 93 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Unknown type %s", 94 val); 95 *reply = wpas_dbus_error_invalid_args(message, val); 96 return -1; 97 } 98 return 0; 99 } 100 101 102 static int wpas_dbus_handler_wps_bssid(DBusMessage *message, 103 DBusMessageIter *entry_iter, 104 struct wps_start_params *params, 105 DBusMessage **reply) 106 { 107 DBusMessageIter variant_iter, array_iter; 108 int len; 109 110 dbus_message_iter_recurse(entry_iter, &variant_iter); 111 if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY || 112 dbus_message_iter_get_element_type(&variant_iter) != 113 DBUS_TYPE_BYTE) { 114 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, " 115 "byte array required"); 116 *reply = wpas_dbus_error_invalid_args( 117 message, "Bssid must be a byte array"); 118 return -1; 119 } 120 dbus_message_iter_recurse(&variant_iter, &array_iter); 121 dbus_message_iter_get_fixed_array(&array_iter, ¶ms->bssid, &len); 122 if (len != ETH_ALEN) { 123 wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length " 124 "%d", len); 125 *reply = wpas_dbus_error_invalid_args(message, 126 "Bssid is wrong length"); 127 return -1; 128 } 129 return 0; 130 } 131 132 133 static int wpas_dbus_handler_wps_pin(DBusMessage *message, 134 DBusMessageIter *entry_iter, 135 struct wps_start_params *params, 136 DBusMessage **reply) 137 { 138 DBusMessageIter variant_iter; 139 140 dbus_message_iter_recurse(entry_iter, &variant_iter); 141 if (dbus_message_iter_get_arg_type(&variant_iter) != 142 DBUS_TYPE_STRING) { 143 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, " 144 "string required"); 145 *reply = wpas_dbus_error_invalid_args(message, 146 "Pin must be a string"); 147 return -1; 148 } 149 dbus_message_iter_get_basic(&variant_iter, ¶ms->pin); 150 return 0; 151 } 152 153 154 #ifdef CONFIG_P2P 155 static int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message, 156 DBusMessageIter *entry_iter, 157 struct wps_start_params *params, 158 DBusMessage **reply) 159 { 160 DBusMessageIter variant_iter, array_iter; 161 int len; 162 163 dbus_message_iter_recurse(entry_iter, &variant_iter); 164 if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY || 165 dbus_message_iter_get_element_type(&variant_iter) != 166 DBUS_TYPE_BYTE) { 167 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong " 168 "P2PDeviceAddress type, byte array required"); 169 *reply = wpas_dbus_error_invalid_args( 170 message, "P2PDeviceAddress must be a byte array"); 171 return -1; 172 } 173 dbus_message_iter_recurse(&variant_iter, &array_iter); 174 dbus_message_iter_get_fixed_array(&array_iter, ¶ms->p2p_dev_addr, 175 &len); 176 if (len != ETH_ALEN) { 177 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong " 178 "P2PDeviceAddress length %d", len); 179 *reply = wpas_dbus_error_invalid_args(message, 180 "P2PDeviceAddress " 181 "has wrong length"); 182 return -1; 183 } 184 return 0; 185 } 186 #endif /* CONFIG_P2P */ 187 188 189 static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key, 190 DBusMessageIter *entry_iter, 191 struct wps_start_params *params, 192 DBusMessage **reply) 193 { 194 if (os_strcmp(key, "Role") == 0) 195 return wpas_dbus_handler_wps_role(message, entry_iter, 196 params, reply); 197 else if (os_strcmp(key, "Type") == 0) 198 return wpas_dbus_handler_wps_type(message, entry_iter, 199 params, reply); 200 else if (os_strcmp(key, "Bssid") == 0) 201 return wpas_dbus_handler_wps_bssid(message, entry_iter, 202 params, reply); 203 else if (os_strcmp(key, "Pin") == 0) 204 return wpas_dbus_handler_wps_pin(message, entry_iter, 205 params, reply); 206 #ifdef CONFIG_P2P 207 else if (os_strcmp(key, "P2PDeviceAddress") == 0) 208 return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter, 209 params, reply); 210 #endif /* CONFIG_P2P */ 211 212 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key); 213 *reply = wpas_dbus_error_invalid_args(message, key); 214 return -1; 215 } 216 217 218 /** 219 * wpas_dbus_handler_wps_start - Start WPS configuration 220 * @message: Pointer to incoming dbus message 221 * @wpa_s: %wpa_supplicant data structure 222 * Returns: DBus message dictionary on success or DBus error on failure 223 * 224 * Handler for "Start" method call. DBus dictionary argument contains 225 * information about role (enrollee or registrar), authorization method 226 * (pin or push button) and optionally pin and bssid. Returned message 227 * has a dictionary argument which may contain newly generated pin (optional). 228 */ 229 DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message, 230 struct wpa_supplicant *wpa_s) 231 { 232 DBusMessage *reply = NULL; 233 DBusMessageIter iter, dict_iter, entry_iter; 234 struct wps_start_params params; 235 char *key; 236 char npin[9] = { '\0' }; 237 int ret; 238 239 os_memset(¶ms, 0, sizeof(params)); 240 dbus_message_iter_init(message, &iter); 241 242 dbus_message_iter_recurse(&iter, &dict_iter); 243 while (dbus_message_iter_get_arg_type(&dict_iter) == 244 DBUS_TYPE_DICT_ENTRY) { 245 dbus_message_iter_recurse(&dict_iter, &entry_iter); 246 247 dbus_message_iter_get_basic(&entry_iter, &key); 248 dbus_message_iter_next(&entry_iter); 249 250 if (wpas_dbus_handler_wps_start_entry(message, key, 251 &entry_iter, 252 ¶ms, &reply)) 253 return reply; 254 255 dbus_message_iter_next(&dict_iter); 256 } 257 258 if (params.role == 0) { 259 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified"); 260 return wpas_dbus_error_invalid_args(message, 261 "Role not specified"); 262 } else if (params.role == 1 && params.type == 0) { 263 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified"); 264 return wpas_dbus_error_invalid_args(message, 265 "Type not specified"); 266 } else if (params.role == 2 && params.pin == NULL) { 267 wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for " 268 "registrar role"); 269 return wpas_dbus_error_invalid_args( 270 message, "Pin required for registrar role."); 271 } 272 273 if (params.role == 2) 274 ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin, 275 NULL); 276 else if (params.type == 1) { 277 #ifdef CONFIG_AP 278 if (wpa_s->ap_iface) 279 ret = wpa_supplicant_ap_wps_pin(wpa_s, 280 params.bssid, 281 params.pin, 282 npin, sizeof(npin)); 283 else 284 #endif /* CONFIG_AP */ 285 { 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 } 292 } else { 293 #ifdef CONFIG_AP 294 if (wpa_s->ap_iface) 295 ret = wpa_supplicant_ap_wps_pbc(wpa_s, 296 params.bssid, 297 params.p2p_dev_addr); 298 else 299 #endif /* CONFIG_AP */ 300 ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0); 301 } 302 303 if (ret < 0) { 304 wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in " 305 "role %s and key %s", 306 (params.role == 1 ? "enrollee" : "registrar"), 307 (params.type == 0 ? "" : 308 (params.type == 1 ? "pin" : "pbc"))); 309 return wpas_dbus_error_unknown_error(message, 310 "WPS start failed"); 311 } 312 313 reply = dbus_message_new_method_return(message); 314 if (!reply) { 315 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 316 NULL); 317 } 318 319 dbus_message_iter_init_append(reply, &iter); 320 if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { 321 dbus_message_unref(reply); 322 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 323 NULL); 324 } 325 326 if (os_strlen(npin) > 0) { 327 if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) { 328 dbus_message_unref(reply); 329 return dbus_message_new_error(message, 330 DBUS_ERROR_NO_MEMORY, 331 NULL); 332 } 333 } 334 335 if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) { 336 dbus_message_unref(reply); 337 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 338 NULL); 339 } 340 341 return reply; 342 } 343 344 345 /** 346 * wpas_dbus_getter_process_credentials - Check if credentials are processed 347 * @message: Pointer to incoming dbus message 348 * @wpa_s: %wpa_supplicant data structure 349 * Returns: TRUE on success, FALSE on failure 350 * 351 * Getter for "ProcessCredentials" property. Returns returned boolean will be 352 * true if wps_cred_processing configuration field is not equal to 1 or false 353 * if otherwise. 354 */ 355 dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter, 356 DBusError *error, 357 void *user_data) 358 { 359 struct wpa_supplicant *wpa_s = user_data; 360 dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1); 361 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 362 &process, error); 363 } 364 365 366 /** 367 * wpas_dbus_setter_process_credentials - Set credentials_processed conf param 368 * @iter: Pointer to incoming dbus message iter 369 * @error: Location to store error on failure 370 * @user_data: Function specific data 371 * Returns: TRUE on success, FALSE on failure 372 * 373 * Setter for "ProcessCredentials" property. Sets credentials_processed on 2 374 * if boolean argument is true or on 1 if otherwise. 375 */ 376 dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter, 377 DBusError *error, 378 void *user_data) 379 { 380 struct wpa_supplicant *wpa_s = user_data; 381 dbus_bool_t process_credentials, old_pc; 382 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