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