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