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, ¶ms->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, ¶ms->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, ¶ms->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(¶ms, 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 ¶ms, &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