1 /* 2 * WPA Supplicant / dbus-based control interface 3 * Copyright (c) 2006, Dan Williams <dcbw (at) redhat.com> and Red Hat, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 #include <dbus/dbus.h> 11 12 #include "common.h" 13 #include "eap_peer/eap_methods.h" 14 #include "common/ieee802_11_defs.h" 15 #include "eapol_supp/eapol_supp_sm.h" 16 #include "rsn_supp/wpa.h" 17 #include "../config.h" 18 #include "../wpa_supplicant_i.h" 19 #include "../driver_i.h" 20 #include "../notify.h" 21 #include "../wpas_glue.h" 22 #include "../bss.h" 23 #include "../scan.h" 24 #include "dbus_old.h" 25 #include "dbus_old_handlers.h" 26 #include "dbus_dict_helpers.h" 27 28 /** 29 * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message 30 * @message: Pointer to incoming dbus message this error refers to 31 * Returns: a dbus error message 32 * 33 * Convenience function to create and return an invalid options error 34 */ 35 DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message, 36 const char *arg) 37 { 38 DBusMessage *reply; 39 40 reply = dbus_message_new_error( 41 message, WPAS_ERROR_INVALID_OPTS, 42 "Did not receive correct message arguments."); 43 if (arg != NULL) 44 dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, 45 DBUS_TYPE_INVALID); 46 47 return reply; 48 } 49 50 51 /** 52 * wpas_dbus_new_success_reply - Return a new success reply message 53 * @message: Pointer to incoming dbus message this reply refers to 54 * Returns: a dbus message containing a single UINT32 that indicates 55 * success (ie, a value of 1) 56 * 57 * Convenience function to create and return a success reply message 58 */ 59 DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message) 60 { 61 DBusMessage *reply; 62 unsigned int success = 1; 63 64 reply = dbus_message_new_method_return(message); 65 dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success, 66 DBUS_TYPE_INVALID); 67 return reply; 68 } 69 70 71 /** 72 * wpas_dbus_global_add_interface - Request registration of a network interface 73 * @message: Pointer to incoming dbus message 74 * @global: %wpa_supplicant global data structure 75 * Returns: The object path of the new interface object, 76 * or a dbus error message with more information 77 * 78 * Handler function for "addInterface" method call. Handles requests 79 * by dbus clients to register a network interface that wpa_supplicant 80 * will manage. 81 */ 82 DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message, 83 struct wpa_global *global) 84 { 85 char *ifname = NULL; 86 char *driver = NULL; 87 char *driver_param = NULL; 88 char *confname = NULL; 89 char *bridge_ifname = NULL; 90 DBusMessage *reply = NULL; 91 DBusMessageIter iter; 92 93 dbus_message_iter_init(message, &iter); 94 95 /* First argument: interface name (DBUS_TYPE_STRING) 96 * Required; must be non-zero length 97 */ 98 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) 99 goto error; 100 dbus_message_iter_get_basic(&iter, &ifname); 101 if (!os_strlen(ifname)) 102 goto error; 103 104 /* Second argument: dict of options */ 105 if (dbus_message_iter_next(&iter)) { 106 DBusMessageIter iter_dict; 107 struct wpa_dbus_dict_entry entry; 108 109 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) 110 goto error; 111 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 112 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 113 goto error; 114 if (!strcmp(entry.key, "driver") && 115 entry.type == DBUS_TYPE_STRING) { 116 os_free(driver); 117 driver = os_strdup(entry.str_value); 118 wpa_dbus_dict_entry_clear(&entry); 119 if (driver == NULL) 120 goto error; 121 } else if (!strcmp(entry.key, "driver-params") && 122 entry.type == DBUS_TYPE_STRING) { 123 os_free(driver_param); 124 driver_param = os_strdup(entry.str_value); 125 wpa_dbus_dict_entry_clear(&entry); 126 if (driver_param == NULL) 127 goto error; 128 } else if (!strcmp(entry.key, "config-file") && 129 entry.type == DBUS_TYPE_STRING) { 130 os_free(confname); 131 confname = os_strdup(entry.str_value); 132 wpa_dbus_dict_entry_clear(&entry); 133 if (confname == NULL) 134 goto error; 135 } else if (!strcmp(entry.key, "bridge-ifname") && 136 entry.type == DBUS_TYPE_STRING) { 137 os_free(bridge_ifname); 138 bridge_ifname = os_strdup(entry.str_value); 139 wpa_dbus_dict_entry_clear(&entry); 140 if (bridge_ifname == NULL) 141 goto error; 142 } else { 143 wpa_dbus_dict_entry_clear(&entry); 144 goto error; 145 } 146 } 147 } 148 149 /* 150 * Try to get the wpa_supplicant record for this iface, return 151 * an error if we already control it. 152 */ 153 if (wpa_supplicant_get_iface(global, ifname) != NULL) { 154 reply = dbus_message_new_error( 155 message, WPAS_ERROR_EXISTS_ERROR, 156 "wpa_supplicant already controls this interface."); 157 } else { 158 struct wpa_supplicant *wpa_s; 159 struct wpa_interface iface; 160 161 os_memset(&iface, 0, sizeof(iface)); 162 iface.ifname = ifname; 163 iface.driver = driver; 164 iface.driver_param = driver_param; 165 iface.confname = confname; 166 iface.bridge_ifname = bridge_ifname; 167 /* Otherwise, have wpa_supplicant attach to it. */ 168 wpa_s = wpa_supplicant_add_iface(global, &iface, NULL); 169 if (wpa_s && wpa_s->dbus_path) { 170 const char *path = wpa_s->dbus_path; 171 172 reply = dbus_message_new_method_return(message); 173 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, 174 &path, DBUS_TYPE_INVALID); 175 } else { 176 reply = dbus_message_new_error( 177 message, WPAS_ERROR_ADD_ERROR, 178 "wpa_supplicant couldn't grab this interface."); 179 } 180 } 181 182 out: 183 os_free(driver); 184 os_free(driver_param); 185 os_free(confname); 186 os_free(bridge_ifname); 187 return reply; 188 189 error: 190 reply = wpas_dbus_new_invalid_opts_error(message, NULL); 191 goto out; 192 } 193 194 195 /** 196 * wpas_dbus_global_remove_interface - Request deregistration of an interface 197 * @message: Pointer to incoming dbus message 198 * @global: wpa_supplicant global data structure 199 * Returns: a dbus message containing a UINT32 indicating success (1) or 200 * failure (0), or returns a dbus error message with more information 201 * 202 * Handler function for "removeInterface" method call. Handles requests 203 * by dbus clients to deregister a network interface that wpa_supplicant 204 * currently manages. 205 */ 206 DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message, 207 struct wpa_global *global) 208 { 209 struct wpa_supplicant *wpa_s; 210 char *path; 211 DBusMessage *reply = NULL; 212 213 if (!dbus_message_get_args(message, NULL, 214 DBUS_TYPE_OBJECT_PATH, &path, 215 DBUS_TYPE_INVALID)) { 216 reply = wpas_dbus_new_invalid_opts_error(message, NULL); 217 goto out; 218 } 219 220 wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path); 221 if (wpa_s == NULL) { 222 reply = wpas_dbus_new_invalid_iface_error(message); 223 goto out; 224 } 225 226 if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) { 227 reply = wpas_dbus_new_success_reply(message); 228 } else { 229 reply = dbus_message_new_error( 230 message, WPAS_ERROR_REMOVE_ERROR, 231 "wpa_supplicant couldn't remove this interface."); 232 } 233 234 out: 235 return reply; 236 } 237 238 239 /** 240 * wpas_dbus_global_get_interface - Get the object path for an interface name 241 * @message: Pointer to incoming dbus message 242 * @global: %wpa_supplicant global data structure 243 * Returns: The object path of the interface object, 244 * or a dbus error message with more information 245 * 246 * Handler function for "getInterface" method call. Handles requests 247 * by dbus clients for the object path of an specific network interface. 248 */ 249 DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message, 250 struct wpa_global *global) 251 { 252 DBusMessage *reply = NULL; 253 const char *ifname; 254 const char *path; 255 struct wpa_supplicant *wpa_s; 256 257 if (!dbus_message_get_args(message, NULL, 258 DBUS_TYPE_STRING, &ifname, 259 DBUS_TYPE_INVALID)) { 260 reply = wpas_dbus_new_invalid_opts_error(message, NULL); 261 goto out; 262 } 263 264 wpa_s = wpa_supplicant_get_iface(global, ifname); 265 if (wpa_s == NULL || !wpa_s->dbus_path) { 266 reply = wpas_dbus_new_invalid_iface_error(message); 267 goto out; 268 } 269 270 path = wpa_s->dbus_path; 271 reply = dbus_message_new_method_return(message); 272 dbus_message_append_args(reply, 273 DBUS_TYPE_OBJECT_PATH, &path, 274 DBUS_TYPE_INVALID); 275 276 out: 277 return reply; 278 } 279 280 281 /** 282 * wpas_dbus_global_set_debugparams- Set the debug params 283 * @message: Pointer to incoming dbus message 284 * @global: %wpa_supplicant global data structure 285 * Returns: a dbus message containing a UINT32 indicating success (1) or 286 * failure (0), or returns a dbus error message with more information 287 * 288 * Handler function for "setDebugParams" method call. Handles requests 289 * by dbus clients for the object path of an specific network interface. 290 */ 291 DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message, 292 struct wpa_global *global) 293 { 294 DBusMessage *reply = NULL; 295 int debug_level; 296 dbus_bool_t debug_timestamp; 297 dbus_bool_t debug_show_keys; 298 299 if (!dbus_message_get_args(message, NULL, 300 DBUS_TYPE_INT32, &debug_level, 301 DBUS_TYPE_BOOLEAN, &debug_timestamp, 302 DBUS_TYPE_BOOLEAN, &debug_show_keys, 303 DBUS_TYPE_INVALID)) { 304 return wpas_dbus_new_invalid_opts_error(message, NULL); 305 } 306 307 if (wpa_supplicant_set_debug_params(global, debug_level, 308 debug_timestamp ? 1 : 0, 309 debug_show_keys ? 1 : 0)) { 310 return wpas_dbus_new_invalid_opts_error(message, NULL); 311 } 312 313 reply = wpas_dbus_new_success_reply(message); 314 315 return reply; 316 } 317 318 319 /** 320 * wpas_dbus_iface_scan - Request a wireless scan on an interface 321 * @message: Pointer to incoming dbus message 322 * @wpa_s: wpa_supplicant structure for a network interface 323 * Returns: a dbus message containing a UINT32 indicating success (1) or 324 * failure (0) 325 * 326 * Handler function for "scan" method call of a network device. Requests 327 * that wpa_supplicant perform a wireless scan as soon as possible 328 * on a particular wireless interface. 329 */ 330 DBusMessage * wpas_dbus_iface_scan(DBusMessage *message, 331 struct wpa_supplicant *wpa_s) 332 { 333 wpa_s->scan_req = MANUAL_SCAN_REQ; 334 wpa_supplicant_req_scan(wpa_s, 0, 0); 335 return wpas_dbus_new_success_reply(message); 336 } 337 338 339 /** 340 * wpas_dbus_iface_scan_results - Get the results of a recent scan request 341 * @message: Pointer to incoming dbus message 342 * @wpa_s: wpa_supplicant structure for a network interface 343 * Returns: a dbus message containing a dbus array of objects paths, or returns 344 * a dbus error message if not scan results could be found 345 * 346 * Handler function for "scanResults" method call of a network device. Returns 347 * a dbus message containing the object paths of wireless networks found. 348 */ 349 DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message, 350 struct wpa_supplicant *wpa_s) 351 { 352 DBusMessage *reply; 353 DBusMessageIter iter; 354 DBusMessageIter sub_iter; 355 struct wpa_bss *bss; 356 357 if (!wpa_s->dbus_path) 358 return dbus_message_new_error(message, 359 WPAS_ERROR_INTERNAL_ERROR, 360 "no D-Bus interface available"); 361 362 /* Create and initialize the return message */ 363 reply = dbus_message_new_method_return(message); 364 dbus_message_iter_init_append(reply, &iter); 365 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 366 DBUS_TYPE_OBJECT_PATH_AS_STRING, 367 &sub_iter)) 368 goto error; 369 370 /* Loop through scan results and append each result's object path */ 371 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { 372 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX]; 373 char *path = path_buf; 374 375 /* Construct the object path for this network. Note that ':' 376 * is not a valid character in dbus object paths. 377 */ 378 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, 379 "%s/" WPAS_DBUS_BSSIDS_PART "/" 380 WPAS_DBUS_BSSID_FORMAT, 381 wpa_s->dbus_path, MAC2STR(bss->bssid)); 382 if (!dbus_message_iter_append_basic(&sub_iter, 383 DBUS_TYPE_OBJECT_PATH, 384 &path)) 385 goto error; 386 } 387 388 if (!dbus_message_iter_close_container(&iter, &sub_iter)) 389 goto error; 390 391 return reply; 392 393 error: 394 dbus_message_unref(reply); 395 return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, 396 "an internal error occurred returning scan results"); 397 } 398 399 400 /** 401 * wpas_dbus_bssid_properties - Return the properties of a scanned network 402 * @message: Pointer to incoming dbus message 403 * @wpa_s: wpa_supplicant structure for a network interface 404 * @res: wpa_supplicant scan result for which to get properties 405 * Returns: a dbus message containing the properties for the requested network 406 * 407 * Handler function for "properties" method call of a scanned network. 408 * Returns a dbus message containing the the properties. 409 */ 410 DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, 411 struct wpa_supplicant *wpa_s, 412 struct wpa_bss *bss) 413 { 414 DBusMessage *reply; 415 DBusMessageIter iter, iter_dict; 416 const u8 *wpa_ie, *rsn_ie, *wps_ie; 417 418 /* Dump the properties into a dbus message */ 419 reply = dbus_message_new_method_return(message); 420 421 wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); 422 rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); 423 wps_ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE); 424 425 dbus_message_iter_init_append(reply, &iter); 426 if (!wpa_dbus_dict_open_write(&iter, &iter_dict) || 427 !wpa_dbus_dict_append_byte_array(&iter_dict, "bssid", 428 (const char *) bss->bssid, 429 ETH_ALEN) || 430 !wpa_dbus_dict_append_byte_array(&iter_dict, "ssid", 431 (const char *) bss->ssid, 432 bss->ssid_len) || 433 (wpa_ie && 434 !wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie", 435 (const char *) wpa_ie, 436 wpa_ie[1] + 2)) || 437 (rsn_ie && 438 !wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie", 439 (const char *) rsn_ie, 440 rsn_ie[1] + 2)) || 441 (wps_ie && 442 !wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie", 443 (const char *) wps_ie, 444 wps_ie[1] + 2)) || 445 (bss->freq && 446 !wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) || 447 !wpa_dbus_dict_append_uint16(&iter_dict, "capabilities", 448 bss->caps) || 449 (!(bss->flags & WPA_BSS_QUAL_INVALID) && 450 !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) || 451 (!(bss->flags & WPA_BSS_NOISE_INVALID) && 452 !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) || 453 (!(bss->flags & WPA_BSS_LEVEL_INVALID) && 454 !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) || 455 !wpa_dbus_dict_append_int32(&iter_dict, "maxrate", 456 wpa_bss_get_max_rate(bss) * 500000) || 457 !wpa_dbus_dict_close_write(&iter, &iter_dict)) { 458 if (reply) 459 dbus_message_unref(reply); 460 reply = dbus_message_new_error( 461 message, WPAS_ERROR_INTERNAL_ERROR, 462 "an internal error occurred returning BSSID properties."); 463 } 464 465 return reply; 466 } 467 468 469 /** 470 * wpas_dbus_iface_capabilities - Return interface capabilities 471 * @message: Pointer to incoming dbus message 472 * @wpa_s: wpa_supplicant structure for a network interface 473 * Returns: A dbus message containing a dict of strings 474 * 475 * Handler function for "capabilities" method call of an interface. 476 */ 477 DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message, 478 struct wpa_supplicant *wpa_s) 479 { 480 DBusMessage *reply = NULL; 481 struct wpa_driver_capa capa; 482 int res; 483 DBusMessageIter iter, iter_dict; 484 char **eap_methods; 485 size_t num_items; 486 dbus_bool_t strict = FALSE; 487 DBusMessageIter iter_dict_entry, iter_dict_val, iter_array; 488 489 if (!dbus_message_get_args(message, NULL, 490 DBUS_TYPE_BOOLEAN, &strict, 491 DBUS_TYPE_INVALID)) 492 strict = FALSE; 493 494 reply = dbus_message_new_method_return(message); 495 496 dbus_message_iter_init_append(reply, &iter); 497 if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) 498 goto error; 499 500 /* EAP methods */ 501 eap_methods = eap_get_names_as_string_array(&num_items); 502 if (eap_methods) { 503 dbus_bool_t success; 504 size_t i = 0; 505 506 success = wpa_dbus_dict_append_string_array( 507 &iter_dict, "eap", (const char **) eap_methods, 508 num_items); 509 510 /* free returned method array */ 511 while (eap_methods[i]) 512 os_free(eap_methods[i++]); 513 os_free(eap_methods); 514 515 if (!success) 516 goto error; 517 } 518 519 res = wpa_drv_get_capa(wpa_s, &capa); 520 521 /***** pairwise cipher */ 522 if (res < 0) { 523 if (!strict) { 524 const char *args[] = {"CCMP", "TKIP", "NONE"}; 525 526 if (!wpa_dbus_dict_append_string_array( 527 &iter_dict, "pairwise", args, 528 ARRAY_SIZE(args))) 529 goto error; 530 } 531 } else { 532 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise", 533 &iter_dict_entry, 534 &iter_dict_val, 535 &iter_array) || 536 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) && 537 !wpa_dbus_dict_string_array_add_element( 538 &iter_array, "CCMP")) || 539 ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && 540 !wpa_dbus_dict_string_array_add_element( 541 &iter_array, "TKIP")) || 542 ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) && 543 !wpa_dbus_dict_string_array_add_element( 544 &iter_array, "NONE")) || 545 !wpa_dbus_dict_end_string_array(&iter_dict, 546 &iter_dict_entry, 547 &iter_dict_val, 548 &iter_array)) 549 goto error; 550 } 551 552 /***** group cipher */ 553 if (res < 0) { 554 if (!strict) { 555 const char *args[] = { 556 "CCMP", "TKIP", "WEP104", "WEP40" 557 }; 558 559 if (!wpa_dbus_dict_append_string_array( 560 &iter_dict, "group", args, 561 ARRAY_SIZE(args))) 562 goto error; 563 } 564 } else { 565 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group", 566 &iter_dict_entry, 567 &iter_dict_val, 568 &iter_array)) 569 goto error; 570 571 if (((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) && 572 !wpa_dbus_dict_string_array_add_element( 573 &iter_array, "CCMP")) || 574 ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && 575 !wpa_dbus_dict_string_array_add_element( 576 &iter_array, "TKIP")) || 577 ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) && 578 !wpa_dbus_dict_string_array_add_element( 579 &iter_array, "WEP104")) || 580 ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) && 581 !wpa_dbus_dict_string_array_add_element( 582 &iter_array, "WEP40")) || 583 !wpa_dbus_dict_end_string_array(&iter_dict, 584 &iter_dict_entry, 585 &iter_dict_val, 586 &iter_array)) 587 goto error; 588 } 589 590 /***** key management */ 591 if (res < 0) { 592 if (!strict) { 593 const char *args[] = { 594 "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE", 595 "NONE" 596 }; 597 if (!wpa_dbus_dict_append_string_array( 598 &iter_dict, "key_mgmt", args, 599 ARRAY_SIZE(args))) 600 goto error; 601 } 602 } else { 603 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt", 604 &iter_dict_entry, 605 &iter_dict_val, 606 &iter_array) || 607 !wpa_dbus_dict_string_array_add_element(&iter_array, 608 "NONE") || 609 !wpa_dbus_dict_string_array_add_element(&iter_array, 610 "IEEE8021X") || 611 ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 612 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) && 613 !wpa_dbus_dict_string_array_add_element( 614 &iter_array, "WPA-EAP")) || 615 ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | 616 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) && 617 !wpa_dbus_dict_string_array_add_element( 618 &iter_array, "WPA-PSK")) || 619 ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) && 620 !wpa_dbus_dict_string_array_add_element( 621 &iter_array, "WPA-NONE")) || 622 !wpa_dbus_dict_end_string_array(&iter_dict, 623 &iter_dict_entry, 624 &iter_dict_val, 625 &iter_array)) 626 goto error; 627 } 628 629 /***** WPA protocol */ 630 if (res < 0) { 631 if (!strict) { 632 const char *args[] = { "RSN", "WPA" }; 633 634 if (!wpa_dbus_dict_append_string_array( 635 &iter_dict, "proto", args, 636 ARRAY_SIZE(args))) 637 goto error; 638 } 639 } else { 640 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto", 641 &iter_dict_entry, 642 &iter_dict_val, 643 &iter_array) || 644 ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 645 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) && 646 !wpa_dbus_dict_string_array_add_element( 647 &iter_array, "RSN")) || 648 ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 649 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) && 650 !wpa_dbus_dict_string_array_add_element( 651 &iter_array, "WPA")) || 652 !wpa_dbus_dict_end_string_array(&iter_dict, 653 &iter_dict_entry, 654 &iter_dict_val, 655 &iter_array)) 656 goto error; 657 } 658 659 /***** auth alg */ 660 if (res < 0) { 661 if (!strict) { 662 const char *args[] = { "OPEN", "SHARED", "LEAP" }; 663 664 if (!wpa_dbus_dict_append_string_array( 665 &iter_dict, "auth_alg", args, 666 ARRAY_SIZE(args))) 667 goto error; 668 } 669 } else { 670 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg", 671 &iter_dict_entry, 672 &iter_dict_val, 673 &iter_array) || 674 ((capa.auth & WPA_DRIVER_AUTH_OPEN) && 675 !wpa_dbus_dict_string_array_add_element( 676 &iter_array, "OPEN")) || 677 ((capa.auth & WPA_DRIVER_AUTH_SHARED) && 678 !wpa_dbus_dict_string_array_add_element( 679 &iter_array, "SHARED")) || 680 ((capa.auth & WPA_DRIVER_AUTH_LEAP) && 681 !wpa_dbus_dict_string_array_add_element( 682 &iter_array, "LEAP")) || 683 !wpa_dbus_dict_end_string_array(&iter_dict, 684 &iter_dict_entry, 685 &iter_dict_val, 686 &iter_array)) 687 goto error; 688 } 689 690 if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) 691 goto error; 692 693 return reply; 694 695 error: 696 if (reply) 697 dbus_message_unref(reply); 698 return dbus_message_new_error( 699 message, WPAS_ERROR_INTERNAL_ERROR, 700 "an internal error occurred returning interface capabilities."); 701 } 702 703 704 /** 705 * wpas_dbus_iface_add_network - Add a new configured network 706 * @message: Pointer to incoming dbus message 707 * @wpa_s: wpa_supplicant structure for a network interface 708 * Returns: A dbus message containing the object path of the new network 709 * 710 * Handler function for "addNetwork" method call of a network interface. 711 */ 712 DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message, 713 struct wpa_supplicant *wpa_s) 714 { 715 DBusMessage *reply = NULL; 716 struct wpa_ssid *ssid = NULL; 717 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; 718 719 if (wpa_s->dbus_path) 720 ssid = wpa_config_add_network(wpa_s->conf); 721 if (ssid == NULL) { 722 reply = dbus_message_new_error( 723 message, WPAS_ERROR_ADD_NETWORK_ERROR, 724 "wpa_supplicant could not add a network on this interface."); 725 goto out; 726 } 727 wpas_notify_network_added(wpa_s, ssid); 728 ssid->disabled = 1; 729 wpa_config_set_network_defaults(ssid); 730 731 /* Construct the object path for this network. */ 732 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, 733 "%s/" WPAS_DBUS_NETWORKS_PART "/%d", 734 wpa_s->dbus_path, ssid->id); 735 736 reply = dbus_message_new_method_return(message); 737 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, 738 &path, DBUS_TYPE_INVALID); 739 740 out: 741 return reply; 742 } 743 744 745 /** 746 * wpas_dbus_iface_remove_network - Remove a configured network 747 * @message: Pointer to incoming dbus message 748 * @wpa_s: wpa_supplicant structure for a network interface 749 * Returns: A dbus message containing a UINT32 indicating success (1) or 750 * failure (0) 751 * 752 * Handler function for "removeNetwork" method call of a network interface. 753 */ 754 DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message, 755 struct wpa_supplicant *wpa_s) 756 { 757 DBusMessage *reply = NULL; 758 const char *op; 759 char *iface = NULL, *net_id = NULL; 760 int id; 761 struct wpa_ssid *ssid; 762 763 if (!dbus_message_get_args(message, NULL, 764 DBUS_TYPE_OBJECT_PATH, &op, 765 DBUS_TYPE_INVALID)) { 766 reply = wpas_dbus_new_invalid_opts_error(message, NULL); 767 goto out; 768 } 769 770 /* Extract the network ID */ 771 iface = wpas_dbus_decompose_object_path(op, &net_id, NULL); 772 if (iface == NULL || net_id == NULL) { 773 reply = wpas_dbus_new_invalid_network_error(message); 774 goto out; 775 } 776 777 /* Ensure the network is actually a child of this interface */ 778 if (!wpa_s->dbus_path || os_strcmp(iface, wpa_s->dbus_path) != 0) { 779 reply = wpas_dbus_new_invalid_network_error(message); 780 goto out; 781 } 782 783 id = strtoul(net_id, NULL, 10); 784 ssid = wpa_config_get_network(wpa_s->conf, id); 785 if (ssid == NULL) { 786 reply = wpas_dbus_new_invalid_network_error(message); 787 goto out; 788 } 789 790 wpas_notify_network_removed(wpa_s, ssid); 791 792 if (ssid == wpa_s->current_ssid) 793 wpa_supplicant_deauthenticate(wpa_s, 794 WLAN_REASON_DEAUTH_LEAVING); 795 796 if (wpa_config_remove_network(wpa_s->conf, id) < 0) { 797 reply = dbus_message_new_error( 798 message, WPAS_ERROR_REMOVE_NETWORK_ERROR, 799 "error removing the specified on this interface."); 800 goto out; 801 } 802 803 reply = wpas_dbus_new_success_reply(message); 804 805 out: 806 os_free(iface); 807 os_free(net_id); 808 return reply; 809 } 810 811 812 static const char * const dont_quote[] = { 813 "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", 814 "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", 815 "bssid", "scan_freq", "freq_list", NULL 816 }; 817 818 819 static dbus_bool_t should_quote_opt(const char *key) 820 { 821 int i = 0; 822 823 while (dont_quote[i] != NULL) { 824 if (os_strcmp(key, dont_quote[i]) == 0) 825 return FALSE; 826 i++; 827 } 828 return TRUE; 829 } 830 831 832 /** 833 * wpas_dbus_iface_set_network - Set options for a configured network 834 * @message: Pointer to incoming dbus message 835 * @wpa_s: wpa_supplicant structure for a network interface 836 * @ssid: wpa_ssid structure for a configured network 837 * Returns: a dbus message containing a UINT32 indicating success (1) or 838 * failure (0) 839 * 840 * Handler function for "set" method call of a configured network. 841 */ 842 DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message, 843 struct wpa_supplicant *wpa_s, 844 struct wpa_ssid *ssid) 845 { 846 DBusMessage *reply = NULL; 847 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; 848 DBusMessageIter iter, iter_dict; 849 850 dbus_message_iter_init(message, &iter); 851 852 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) { 853 reply = wpas_dbus_new_invalid_opts_error(message, NULL); 854 goto out; 855 } 856 857 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 858 char *value = NULL; 859 size_t size = 50; 860 int ret; 861 862 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { 863 reply = wpas_dbus_new_invalid_opts_error(message, 864 NULL); 865 goto out; 866 } 867 868 /* Type conversions, since wpa_supplicant wants strings */ 869 if (entry.type == DBUS_TYPE_ARRAY && 870 entry.array_type == DBUS_TYPE_BYTE) { 871 if (entry.array_len <= 0) 872 goto error; 873 874 size = entry.array_len * 2 + 1; 875 value = os_zalloc(size); 876 if (value == NULL) 877 goto error; 878 ret = wpa_snprintf_hex(value, size, 879 (u8 *) entry.bytearray_value, 880 entry.array_len); 881 if (ret <= 0) 882 goto error; 883 } else if (entry.type == DBUS_TYPE_STRING) { 884 if (should_quote_opt(entry.key)) { 885 size = os_strlen(entry.str_value); 886 /* Zero-length option check */ 887 if (size == 0) 888 goto error; 889 size += 3; /* For quotes and terminator */ 890 value = os_zalloc(size); 891 if (value == NULL) 892 goto error; 893 ret = os_snprintf(value, size, "\"%s\"", 894 entry.str_value); 895 if (os_snprintf_error(size, ret)) 896 goto error; 897 } else { 898 value = os_strdup(entry.str_value); 899 if (value == NULL) 900 goto error; 901 } 902 } else if (entry.type == DBUS_TYPE_UINT32) { 903 value = os_zalloc(size); 904 if (value == NULL) 905 goto error; 906 ret = os_snprintf(value, size, "%u", 907 entry.uint32_value); 908 if (os_snprintf_error(size, ret)) 909 goto error; 910 } else if (entry.type == DBUS_TYPE_INT32) { 911 value = os_zalloc(size); 912 if (value == NULL) 913 goto error; 914 ret = os_snprintf(value, size, "%d", 915 entry.int32_value); 916 if (os_snprintf_error(size, ret)) 917 goto error; 918 } else 919 goto error; 920 921 if (wpa_config_set(ssid, entry.key, value, 0) < 0) 922 goto error; 923 924 if ((os_strcmp(entry.key, "psk") == 0 && 925 value[0] == '"' && ssid->ssid_len) || 926 (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) 927 wpa_config_update_psk(ssid); 928 else if (os_strcmp(entry.key, "priority") == 0) 929 wpa_config_update_prio_list(wpa_s->conf); 930 931 os_free(value); 932 wpa_dbus_dict_entry_clear(&entry); 933 continue; 934 935 error: 936 os_free(value); 937 reply = wpas_dbus_new_invalid_opts_error(message, entry.key); 938 wpa_dbus_dict_entry_clear(&entry); 939 break; 940 } 941 942 if (!reply) 943 reply = wpas_dbus_new_success_reply(message); 944 945 out: 946 return reply; 947 } 948 949 950 /** 951 * wpas_dbus_iface_enable_network - Mark a configured network as enabled 952 * @message: Pointer to incoming dbus message 953 * @wpa_s: wpa_supplicant structure for a network interface 954 * @ssid: wpa_ssid structure for a configured network 955 * Returns: A dbus message containing a UINT32 indicating success (1) or 956 * failure (0) 957 * 958 * Handler function for "enable" method call of a configured network. 959 */ 960 DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message, 961 struct wpa_supplicant *wpa_s, 962 struct wpa_ssid *ssid) 963 { 964 wpa_supplicant_enable_network(wpa_s, ssid); 965 return wpas_dbus_new_success_reply(message); 966 } 967 968 969 /** 970 * wpas_dbus_iface_disable_network - Mark a configured network as disabled 971 * @message: Pointer to incoming dbus message 972 * @wpa_s: wpa_supplicant structure for a network interface 973 * @ssid: wpa_ssid structure for a configured network 974 * Returns: A dbus message containing a UINT32 indicating success (1) or 975 * failure (0) 976 * 977 * Handler function for "disable" method call of a configured network. 978 */ 979 DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message, 980 struct wpa_supplicant *wpa_s, 981 struct wpa_ssid *ssid) 982 { 983 wpa_supplicant_disable_network(wpa_s, ssid); 984 return wpas_dbus_new_success_reply(message); 985 } 986 987 988 /** 989 * wpas_dbus_iface_select_network - Attempt association with a configured network 990 * @message: Pointer to incoming dbus message 991 * @wpa_s: wpa_supplicant structure for a network interface 992 * Returns: A dbus message containing a UINT32 indicating success (1) or 993 * failure (0) 994 * 995 * Handler function for "selectNetwork" method call of network interface. 996 */ 997 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message, 998 struct wpa_supplicant *wpa_s) 999 { 1000 DBusMessage *reply = NULL; 1001 const char *op; 1002 struct wpa_ssid *ssid; 1003 char *iface_obj_path = NULL; 1004 char *network = NULL; 1005 1006 if (os_strlen(dbus_message_get_signature(message)) == 0) { 1007 /* Any network */ 1008 ssid = NULL; 1009 } else { 1010 int nid; 1011 1012 if (!dbus_message_get_args(message, NULL, 1013 DBUS_TYPE_OBJECT_PATH, &op, 1014 DBUS_TYPE_INVALID)) { 1015 reply = wpas_dbus_new_invalid_opts_error(message, 1016 NULL); 1017 goto out; 1018 } 1019 1020 /* Extract the network number */ 1021 iface_obj_path = wpas_dbus_decompose_object_path(op, 1022 &network, 1023 NULL); 1024 if (iface_obj_path == NULL) { 1025 reply = wpas_dbus_new_invalid_iface_error(message); 1026 goto out; 1027 } 1028 /* Ensure the object path really points to this interface */ 1029 if (network == NULL || !wpa_s->dbus_path || 1030 os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) { 1031 reply = wpas_dbus_new_invalid_network_error(message); 1032 goto out; 1033 } 1034 1035 nid = strtoul(network, NULL, 10); 1036 if (errno == EINVAL) { 1037 reply = wpas_dbus_new_invalid_network_error(message); 1038 goto out; 1039 } 1040 1041 ssid = wpa_config_get_network(wpa_s->conf, nid); 1042 if (ssid == NULL) { 1043 reply = wpas_dbus_new_invalid_network_error(message); 1044 goto out; 1045 } 1046 } 1047 1048 /* Finally, associate with the network */ 1049 wpa_supplicant_select_network(wpa_s, ssid); 1050 1051 reply = wpas_dbus_new_success_reply(message); 1052 1053 out: 1054 os_free(iface_obj_path); 1055 os_free(network); 1056 return reply; 1057 } 1058 1059 1060 /** 1061 * wpas_dbus_iface_disconnect - Terminate the current connection 1062 * @message: Pointer to incoming dbus message 1063 * @wpa_s: wpa_supplicant structure for a network interface 1064 * Returns: A dbus message containing a UINT32 indicating success (1) or 1065 * failure (0) 1066 * 1067 * Handler function for "disconnect" method call of network interface. 1068 */ 1069 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message, 1070 struct wpa_supplicant *wpa_s) 1071 { 1072 wpa_s->disconnected = 1; 1073 wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); 1074 1075 return wpas_dbus_new_success_reply(message); 1076 } 1077 1078 1079 /** 1080 * wpas_dbus_iface_set_ap_scan - Control roaming mode 1081 * @message: Pointer to incoming dbus message 1082 * @wpa_s: wpa_supplicant structure for a network interface 1083 * Returns: A dbus message containing a UINT32 indicating success (1) or 1084 * failure (0) 1085 * 1086 * Handler function for "setAPScan" method call. 1087 */ 1088 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message, 1089 struct wpa_supplicant *wpa_s) 1090 { 1091 DBusMessage *reply = NULL; 1092 dbus_uint32_t ap_scan = 1; 1093 1094 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan, 1095 DBUS_TYPE_INVALID)) { 1096 reply = wpas_dbus_new_invalid_opts_error(message, NULL); 1097 goto out; 1098 } 1099 1100 if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { 1101 reply = wpas_dbus_new_invalid_opts_error(message, NULL); 1102 goto out; 1103 } 1104 1105 reply = wpas_dbus_new_success_reply(message); 1106 1107 out: 1108 return reply; 1109 } 1110 1111 1112 /** 1113 * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths 1114 * @message: Pointer to incoming dbus message 1115 * @wpa_s: wpa_supplicant structure for a network interface 1116 * Returns: A dbus message containing a UINT32 indicating success (1) or 1117 * failure (0) 1118 * 1119 * Handler function for "setSmartcardModules" method call. 1120 */ 1121 DBusMessage * wpas_dbus_iface_set_smartcard_modules( 1122 DBusMessage *message, struct wpa_supplicant *wpa_s) 1123 { 1124 DBusMessageIter iter, iter_dict; 1125 char *opensc_engine_path = NULL; 1126 char *pkcs11_engine_path = NULL; 1127 char *pkcs11_module_path = NULL; 1128 struct wpa_dbus_dict_entry entry; 1129 1130 if (!dbus_message_iter_init(message, &iter)) 1131 goto error; 1132 1133 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) 1134 goto error; 1135 1136 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1137 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 1138 goto error; 1139 if (!strcmp(entry.key, "opensc_engine_path") && 1140 entry.type == DBUS_TYPE_STRING) { 1141 os_free(opensc_engine_path); 1142 opensc_engine_path = os_strdup(entry.str_value); 1143 wpa_dbus_dict_entry_clear(&entry); 1144 if (opensc_engine_path == NULL) 1145 goto error; 1146 } else if (!strcmp(entry.key, "pkcs11_engine_path") && 1147 entry.type == DBUS_TYPE_STRING) { 1148 os_free(pkcs11_engine_path); 1149 pkcs11_engine_path = os_strdup(entry.str_value); 1150 wpa_dbus_dict_entry_clear(&entry); 1151 if (pkcs11_engine_path == NULL) 1152 goto error; 1153 } else if (!strcmp(entry.key, "pkcs11_module_path") && 1154 entry.type == DBUS_TYPE_STRING) { 1155 os_free(pkcs11_module_path); 1156 pkcs11_module_path = os_strdup(entry.str_value); 1157 wpa_dbus_dict_entry_clear(&entry); 1158 if (pkcs11_module_path == NULL) 1159 goto error; 1160 } else { 1161 wpa_dbus_dict_entry_clear(&entry); 1162 goto error; 1163 } 1164 } 1165 1166 os_free(wpa_s->conf->opensc_engine_path); 1167 wpa_s->conf->opensc_engine_path = opensc_engine_path; 1168 os_free(wpa_s->conf->pkcs11_engine_path); 1169 wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path; 1170 os_free(wpa_s->conf->pkcs11_module_path); 1171 wpa_s->conf->pkcs11_module_path = pkcs11_module_path; 1172 1173 wpa_sm_set_eapol(wpa_s->wpa, NULL); 1174 eapol_sm_deinit(wpa_s->eapol); 1175 wpa_s->eapol = NULL; 1176 wpa_supplicant_init_eapol(wpa_s); 1177 wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); 1178 1179 return wpas_dbus_new_success_reply(message); 1180 1181 error: 1182 os_free(opensc_engine_path); 1183 os_free(pkcs11_engine_path); 1184 os_free(pkcs11_module_path); 1185 return wpas_dbus_new_invalid_opts_error(message, NULL); 1186 } 1187 1188 1189 /** 1190 * wpas_dbus_iface_get_state - Get interface state 1191 * @message: Pointer to incoming dbus message 1192 * @wpa_s: wpa_supplicant structure for a network interface 1193 * Returns: A dbus message containing a STRING representing the current 1194 * interface state 1195 * 1196 * Handler function for "state" method call. 1197 */ 1198 DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message, 1199 struct wpa_supplicant *wpa_s) 1200 { 1201 DBusMessage *reply = NULL; 1202 const char *str_state; 1203 1204 reply = dbus_message_new_method_return(message); 1205 if (reply != NULL) { 1206 str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); 1207 dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state, 1208 DBUS_TYPE_INVALID); 1209 } 1210 1211 return reply; 1212 } 1213 1214 1215 /** 1216 * wpas_dbus_iface_get_scanning - Get interface scanning state 1217 * @message: Pointer to incoming dbus message 1218 * @wpa_s: wpa_supplicant structure for a network interface 1219 * Returns: A dbus message containing whether the interface is scanning 1220 * 1221 * Handler function for "scanning" method call. 1222 */ 1223 DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message, 1224 struct wpa_supplicant *wpa_s) 1225 { 1226 DBusMessage *reply = NULL; 1227 dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; 1228 1229 reply = dbus_message_new_method_return(message); 1230 if (reply != NULL) { 1231 dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning, 1232 DBUS_TYPE_INVALID); 1233 } else { 1234 wpa_printf(MSG_ERROR, 1235 "dbus: Not enough memory to return scanning state"); 1236 } 1237 1238 return reply; 1239 } 1240 1241 1242 #ifndef CONFIG_NO_CONFIG_BLOBS 1243 1244 /** 1245 * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates) 1246 * @message: Pointer to incoming dbus message 1247 * @wpa_s: %wpa_supplicant data structure 1248 * Returns: A dbus message containing a UINT32 indicating success (1) or 1249 * failure (0) 1250 * 1251 * Asks wpa_supplicant to internally store a one or more binary blobs. 1252 */ 1253 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message, 1254 struct wpa_supplicant *wpa_s) 1255 { 1256 DBusMessage *reply = NULL; 1257 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; 1258 DBusMessageIter iter, iter_dict; 1259 1260 dbus_message_iter_init(message, &iter); 1261 1262 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) 1263 return wpas_dbus_new_invalid_opts_error(message, NULL); 1264 1265 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1266 struct wpa_config_blob *blob; 1267 1268 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { 1269 reply = wpas_dbus_new_invalid_opts_error(message, 1270 NULL); 1271 break; 1272 } 1273 1274 if (entry.type != DBUS_TYPE_ARRAY || 1275 entry.array_type != DBUS_TYPE_BYTE) { 1276 reply = wpas_dbus_new_invalid_opts_error( 1277 message, "Byte array expected."); 1278 break; 1279 } 1280 1281 if ((entry.array_len <= 0) || (entry.array_len > 65536) || 1282 !strlen(entry.key)) { 1283 reply = wpas_dbus_new_invalid_opts_error( 1284 message, "Invalid array size."); 1285 break; 1286 } 1287 1288 blob = os_zalloc(sizeof(*blob)); 1289 if (blob == NULL) { 1290 reply = dbus_message_new_error( 1291 message, WPAS_ERROR_ADD_ERROR, 1292 "Not enough memory to add blob."); 1293 break; 1294 } 1295 blob->data = os_zalloc(entry.array_len); 1296 if (blob->data == NULL) { 1297 reply = dbus_message_new_error( 1298 message, WPAS_ERROR_ADD_ERROR, 1299 "Not enough memory to add blob data."); 1300 os_free(blob); 1301 break; 1302 } 1303 1304 blob->name = os_strdup(entry.key); 1305 blob->len = entry.array_len; 1306 os_memcpy(blob->data, (u8 *) entry.bytearray_value, 1307 entry.array_len); 1308 if (blob->name == NULL) { 1309 wpa_config_free_blob(blob); 1310 reply = dbus_message_new_error( 1311 message, WPAS_ERROR_ADD_ERROR, 1312 "Error adding blob."); 1313 break; 1314 } 1315 1316 /* Success */ 1317 if (!wpa_config_remove_blob(wpa_s->conf, blob->name)) 1318 wpas_notify_blob_removed(wpa_s, blob->name); 1319 wpa_config_set_blob(wpa_s->conf, blob); 1320 wpas_notify_blob_added(wpa_s, blob->name); 1321 1322 wpa_dbus_dict_entry_clear(&entry); 1323 } 1324 wpa_dbus_dict_entry_clear(&entry); 1325 1326 return reply ? reply : wpas_dbus_new_success_reply(message); 1327 } 1328 1329 1330 /** 1331 * wpas_dbus_iface_remove_blob - Remove named binary blobs 1332 * @message: Pointer to incoming dbus message 1333 * @wpa_s: %wpa_supplicant data structure 1334 * Returns: A dbus message containing a UINT32 indicating success (1) or 1335 * failure (0) 1336 * 1337 * Asks wpa_supplicant to remove one or more previously stored binary blobs. 1338 */ 1339 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message, 1340 struct wpa_supplicant *wpa_s) 1341 { 1342 DBusMessageIter iter, array; 1343 char *err_msg = NULL; 1344 1345 dbus_message_iter_init(message, &iter); 1346 1347 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || 1348 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) 1349 return wpas_dbus_new_invalid_opts_error(message, NULL); 1350 1351 dbus_message_iter_recurse(&iter, &array); 1352 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) { 1353 const char *name; 1354 1355 dbus_message_iter_get_basic(&array, &name); 1356 if (!os_strlen(name)) 1357 err_msg = "Invalid blob name."; 1358 else if (wpa_config_remove_blob(wpa_s->conf, name) != 0) 1359 err_msg = "Error removing blob."; 1360 else 1361 wpas_notify_blob_removed(wpa_s, name); 1362 dbus_message_iter_next(&array); 1363 } 1364 1365 if (err_msg) 1366 return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR, 1367 err_msg); 1368 1369 return wpas_dbus_new_success_reply(message); 1370 } 1371 1372 #endif /* CONFIG_NO_CONFIG_BLOBS */ 1373 1374 1375 /** 1376 * wpas_dbus_iface_flush - Clear BSS of old or all inactive entries 1377 * @message: Pointer to incoming dbus message 1378 * @wpa_s: %wpa_supplicant data structure 1379 * Returns: a dbus message containing a UINT32 indicating success (1) or 1380 * failure (0), or returns a dbus error message with more information 1381 * 1382 * Handler function for "flush" method call. Handles requests for an 1383 * interface with an optional "age" parameter that specifies the minimum 1384 * age of a BSS to be flushed. 1385 */ 1386 DBusMessage * wpas_dbus_iface_flush(DBusMessage *message, 1387 struct wpa_supplicant *wpa_s) 1388 { 1389 int flush_age = 0; 1390 1391 if (os_strlen(dbus_message_get_signature(message)) != 0 && 1392 !dbus_message_get_args(message, NULL, 1393 DBUS_TYPE_INT32, &flush_age, 1394 DBUS_TYPE_INVALID)) { 1395 return wpas_dbus_new_invalid_opts_error(message, NULL); 1396 } 1397 1398 if (flush_age == 0) 1399 wpa_bss_flush(wpa_s); 1400 else 1401 wpa_bss_flush_by_age(wpa_s, flush_age); 1402 1403 return wpas_dbus_new_success_reply(message); 1404 } 1405