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