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