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