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 <dbus/dbus.h> 18 19 #include "common.h" 20 #include "eloop.h" 21 #include "wpa.h" 22 #include "wpa_supplicant.h" 23 #include "config.h" 24 #include "eapol_sm.h" 25 #include "wpa_supplicant_i.h" 26 #include "ctrl_iface_dbus.h" 27 #include "ctrl_iface_dbus_handlers.h" 28 #include "l2_packet.h" 29 #include "preauth.h" 30 #include "wpa_ctrl.h" 31 #include "eap.h" 32 33 #define _DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR) 34 #define DBUS_VER(major, minor) ((major) << 8 | (minor)) 35 36 #if _DBUS_VERSION < DBUS_VER(1,1) 37 #define dbus_watch_get_unix_fd dbus_watch_get_fd 38 #endif 39 40 41 struct ctrl_iface_dbus_priv { 42 DBusConnection *con; 43 int should_dispatch; 44 struct wpa_global *global; 45 46 u32 next_objid; 47 }; 48 49 50 static void process_watch(struct ctrl_iface_dbus_priv *iface, 51 DBusWatch *watch, eloop_event_type type) 52 { 53 dbus_connection_ref(iface->con); 54 55 iface->should_dispatch = 0; 56 57 if (type == EVENT_TYPE_READ) 58 dbus_watch_handle(watch, DBUS_WATCH_READABLE); 59 else if (type == EVENT_TYPE_WRITE) 60 dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); 61 else if (type == EVENT_TYPE_EXCEPTION) 62 dbus_watch_handle(watch, DBUS_WATCH_ERROR); 63 64 if (iface->should_dispatch) { 65 while (dbus_connection_get_dispatch_status(iface->con) == 66 DBUS_DISPATCH_DATA_REMAINS) 67 dbus_connection_dispatch(iface->con); 68 iface->should_dispatch = 0; 69 } 70 71 dbus_connection_unref(iface->con); 72 } 73 74 75 static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx) 76 { 77 process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION); 78 } 79 80 81 static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx) 82 { 83 process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ); 84 } 85 86 87 static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx) 88 { 89 process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE); 90 } 91 92 93 static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface, 94 DBusWatch *watch) 95 { 96 unsigned int flags; 97 int fd; 98 99 if (!dbus_watch_get_enabled(watch)) 100 return; 101 102 flags = dbus_watch_get_flags(watch); 103 fd = dbus_watch_get_unix_fd(watch); 104 105 eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, 106 iface, watch); 107 108 if (flags & DBUS_WATCH_READABLE) { 109 eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, 110 iface, watch); 111 } 112 if (flags & DBUS_WATCH_WRITABLE) { 113 eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, 114 iface, watch); 115 } 116 117 dbus_watch_set_data(watch, iface, NULL); 118 } 119 120 121 static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface, 122 DBusWatch *watch) 123 { 124 unsigned int flags; 125 int fd; 126 127 flags = dbus_watch_get_flags(watch); 128 fd = dbus_watch_get_unix_fd(watch); 129 130 eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); 131 132 if (flags & DBUS_WATCH_READABLE) 133 eloop_unregister_sock(fd, EVENT_TYPE_READ); 134 if (flags & DBUS_WATCH_WRITABLE) 135 eloop_unregister_sock(fd, EVENT_TYPE_WRITE); 136 137 dbus_watch_set_data(watch, NULL, NULL); 138 } 139 140 141 static dbus_bool_t add_watch(DBusWatch *watch, void *data) 142 { 143 connection_setup_add_watch(data, watch); 144 return TRUE; 145 } 146 147 148 static void remove_watch(DBusWatch *watch, void *data) 149 { 150 connection_setup_remove_watch(data, watch); 151 } 152 153 154 static void watch_toggled(DBusWatch *watch, void *data) 155 { 156 if (dbus_watch_get_enabled(watch)) 157 add_watch(watch, data); 158 else 159 remove_watch(watch, data); 160 } 161 162 163 static void process_timeout(void *eloop_ctx, void *sock_ctx) 164 { 165 DBusTimeout *timeout = sock_ctx; 166 167 dbus_timeout_handle(timeout); 168 } 169 170 171 static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface, 172 DBusTimeout *timeout) 173 { 174 if (!dbus_timeout_get_enabled(timeout)) 175 return; 176 177 eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, 178 process_timeout, iface, timeout); 179 180 dbus_timeout_set_data(timeout, iface, NULL); 181 } 182 183 184 static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface, 185 DBusTimeout *timeout) 186 { 187 eloop_cancel_timeout(process_timeout, iface, timeout); 188 dbus_timeout_set_data(timeout, NULL, NULL); 189 } 190 191 192 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) 193 { 194 if (!dbus_timeout_get_enabled(timeout)) 195 return TRUE; 196 197 connection_setup_add_timeout(data, timeout); 198 199 return TRUE; 200 } 201 202 203 static void remove_timeout(DBusTimeout *timeout, void *data) 204 { 205 connection_setup_remove_timeout(data, timeout); 206 } 207 208 209 static void timeout_toggled(DBusTimeout *timeout, void *data) 210 { 211 if (dbus_timeout_get_enabled(timeout)) 212 add_timeout(timeout, data); 213 else 214 remove_timeout(timeout, data); 215 } 216 217 218 static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx) 219 { 220 struct ctrl_iface_dbus_priv *iface = signal_ctx; 221 222 if (sig != SIGPOLL || !iface->con) 223 return; 224 225 if (dbus_connection_get_dispatch_status(iface->con) != 226 DBUS_DISPATCH_DATA_REMAINS) 227 return; 228 229 /* Only dispatch once - we do not want to starve other events */ 230 dbus_connection_ref(iface->con); 231 dbus_connection_dispatch(iface->con); 232 dbus_connection_unref(iface->con); 233 } 234 235 236 /** 237 * wakeup_main - Attempt to wake our mainloop up 238 * @data: dbus control interface private data 239 * 240 * Try to wake up the main eloop so it will process 241 * dbus events that may have happened. 242 */ 243 static void wakeup_main(void *data) 244 { 245 struct ctrl_iface_dbus_priv *iface = data; 246 247 /* Use SIGPOLL to break out of the eloop select() */ 248 raise(SIGPOLL); 249 iface->should_dispatch = 1; 250 } 251 252 253 /** 254 * connection_setup_wakeup_main - Tell dbus about our wakeup_main function 255 * @iface: dbus control interface private data 256 * Returns: 0 on success, -1 on failure 257 * 258 * Register our wakeup_main handler with dbus 259 */ 260 static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface) 261 { 262 if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface)) 263 return -1; 264 265 dbus_connection_set_wakeup_main_function(iface->con, wakeup_main, 266 iface, NULL); 267 268 return 0; 269 } 270 271 272 /** 273 * wpa_supplicant_dbus_next_objid - Return next available object id 274 * @iface: dbus control interface private data 275 * Returns: Object id 276 */ 277 u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface) 278 { 279 return iface->next_objid++; 280 } 281 282 283 /** 284 * wpas_dbus_decompose_object_path - Decompose an interface object path into parts 285 * @path: The dbus object path 286 * @network: (out) the configured network this object path refers to, if any 287 * @bssid: (out) the scanned bssid this object path refers to, if any 288 * Returns: The object path of the network interface this path refers to 289 * 290 * For a given object path, decomposes the object path into object id, network, 291 * and BSSID parts, if those parts exist. 292 */ 293 char * wpas_dbus_decompose_object_path(const char *path, char **network, 294 char **bssid) 295 { 296 const unsigned int dev_path_prefix_len = 297 strlen(WPAS_DBUS_PATH_INTERFACES "/"); 298 char *obj_path_only; 299 char *next_sep; 300 301 /* Be a bit paranoid about path */ 302 if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", 303 dev_path_prefix_len)) 304 return NULL; 305 306 /* Ensure there's something at the end of the path */ 307 if ((path + dev_path_prefix_len)[0] == '\0') 308 return NULL; 309 310 obj_path_only = strdup(path); 311 if (obj_path_only == NULL) 312 return NULL; 313 314 next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); 315 if (next_sep != NULL) { 316 const char *net_part = strstr(next_sep, 317 WPAS_DBUS_NETWORKS_PART "/"); 318 const char *bssid_part = strstr(next_sep, 319 WPAS_DBUS_BSSIDS_PART "/"); 320 321 if (network && net_part) { 322 /* Deal with a request for a configured network */ 323 const char *net_name = net_part + 324 strlen(WPAS_DBUS_NETWORKS_PART "/"); 325 *network = NULL; 326 if (strlen(net_name)) 327 *network = strdup(net_name); 328 } else if (bssid && bssid_part) { 329 /* Deal with a request for a scanned BSSID */ 330 const char *bssid_name = bssid_part + 331 strlen(WPAS_DBUS_BSSIDS_PART "/"); 332 if (strlen(bssid_name)) 333 *bssid = strdup(bssid_name); 334 else 335 *bssid = NULL; 336 } 337 338 /* Cut off interface object path before "/" */ 339 *next_sep = '\0'; 340 } 341 342 return obj_path_only; 343 } 344 345 346 /** 347 * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message 348 * @message: Pointer to incoming dbus message this error refers to 349 * Returns: A dbus error message 350 * 351 * Convenience function to create and return an invalid interface error 352 */ 353 DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) 354 { 355 return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, 356 "wpa_supplicant knows nothing about " 357 "this interface."); 358 } 359 360 361 /** 362 * wpas_dbus_new_invalid_network_error - Return a new invalid network error message 363 * @message: Pointer to incoming dbus message this error refers to 364 * Returns: a dbus error message 365 * 366 * Convenience function to create and return an invalid network error 367 */ 368 DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) 369 { 370 return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, 371 "The requested network does not exist."); 372 } 373 374 375 /** 376 * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message 377 * @message: Pointer to incoming dbus message this error refers to 378 * Returns: a dbus error message 379 * 380 * Convenience function to create and return an invalid bssid error 381 */ 382 static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) 383 { 384 return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, 385 "The BSSID requested was invalid."); 386 } 387 388 389 /** 390 * wpas_dispatch_network_method - dispatch messages for configured networks 391 * @message: the incoming dbus message 392 * @wpa_s: a network interface's data 393 * @network_id: id of the configured network we're interested in 394 * Returns: a reply dbus message, or a dbus error message 395 * 396 * This function dispatches all incoming dbus messages for configured networks. 397 */ 398 static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, 399 struct wpa_supplicant *wpa_s, 400 int network_id) 401 { 402 DBusMessage *reply = NULL; 403 const char *method = dbus_message_get_member(message); 404 struct wpa_ssid *ssid; 405 406 ssid = wpa_config_get_network(wpa_s->conf, network_id); 407 if (ssid == NULL) 408 return wpas_dbus_new_invalid_network_error(message); 409 410 if (!strcmp(method, "set")) 411 reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); 412 else if (!strcmp(method, "enable")) 413 reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); 414 else if (!strcmp(method, "disable")) 415 reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); 416 417 return reply; 418 } 419 420 421 /** 422 * wpas_dispatch_bssid_method - dispatch messages for scanned networks 423 * @message: the incoming dbus message 424 * @wpa_s: a network interface's data 425 * @bssid: bssid of the scanned network we're interested in 426 * Returns: a reply dbus message, or a dbus error message 427 * 428 * This function dispatches all incoming dbus messages for scanned networks. 429 */ 430 static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, 431 struct wpa_supplicant *wpa_s, 432 const char *bssid) 433 { 434 DBusMessage *reply = NULL; 435 const char *method = dbus_message_get_member(message); 436 struct wpa_scan_result * res = NULL; 437 int i; 438 439 /* Ensure we actually have scan data */ 440 if (wpa_s->scan_results == NULL && 441 wpa_supplicant_get_scan_results(wpa_s) < 0) { 442 reply = wpas_dbus_new_invalid_bssid_error(message); 443 goto out; 444 } 445 446 /* Find the bssid's scan data */ 447 for (i = 0; i < wpa_s->num_scan_results; i++) { 448 struct wpa_scan_result * search_res = &wpa_s->scan_results[i]; 449 char mac_str[18]; 450 451 memset(mac_str, 0, sizeof(mac_str)); 452 snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT, 453 MAC2STR(search_res->bssid)); 454 if (!strcmp(bssid, mac_str)) { 455 res = search_res; 456 } 457 } 458 459 if (!res) { 460 reply = wpas_dbus_new_invalid_bssid_error(message); 461 goto out; 462 } 463 464 /* Dispatch the method call against the scanned bssid */ 465 if (!strcmp(method, "properties")) 466 reply = wpas_dbus_bssid_properties(message, wpa_s, res); 467 468 out: 469 return reply; 470 } 471 472 473 /** 474 * wpas_iface_message_handler - Dispatch messages for interfaces or networks 475 * @connection: Connection to the system message bus 476 * @message: An incoming dbus message 477 * @user_data: A pointer to a dbus control interface data structure 478 * Returns: Whether or not the message was handled 479 * 480 * This function dispatches all incoming dbus messages for network interfaces, 481 * or objects owned by them, such as scanned BSSIDs and configured networks. 482 */ 483 static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, 484 DBusMessage *message, 485 void *user_data) 486 { 487 struct wpa_supplicant *wpa_s = user_data; 488 const char *method = dbus_message_get_member(message); 489 const char *path = dbus_message_get_path(message); 490 const char *msg_interface = dbus_message_get_interface(message); 491 char *iface_obj_path = NULL; 492 char *network = NULL; 493 char *bssid = NULL; 494 DBusMessage *reply = NULL; 495 496 /* Caller must specify a message interface */ 497 if (!msg_interface) 498 goto out; 499 500 iface_obj_path = wpas_dbus_decompose_object_path(path, &network, 501 &bssid); 502 if (iface_obj_path == NULL) { 503 reply = wpas_dbus_new_invalid_iface_error(message); 504 goto out; 505 } 506 507 /* Make sure the message's object path actually refers to the 508 * wpa_supplicant structure it's supposed to (which is wpa_s) 509 */ 510 if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, 511 iface_obj_path) != wpa_s) { 512 reply = wpas_dbus_new_invalid_iface_error(message); 513 goto out; 514 } 515 516 if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { 517 /* A method for one of this interface's configured networks */ 518 int nid = strtoul(network, NULL, 10); 519 if (errno != EINVAL) 520 reply = wpas_dispatch_network_method(message, wpa_s, 521 nid); 522 else 523 reply = wpas_dbus_new_invalid_network_error(message); 524 } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { 525 /* A method for one of this interface's scanned BSSIDs */ 526 reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); 527 } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { 528 /* A method for an interface only. */ 529 if (!strcmp(method, "scan")) 530 reply = wpas_dbus_iface_scan(message, wpa_s); 531 else if (!strcmp(method, "scanResults")) 532 reply = wpas_dbus_iface_scan_results(message, wpa_s); 533 else if (!strcmp(method, "addNetwork")) 534 reply = wpas_dbus_iface_add_network(message, wpa_s); 535 else if (!strcmp(method, "removeNetwork")) 536 reply = wpas_dbus_iface_remove_network(message, wpa_s); 537 else if (!strcmp(method, "selectNetwork")) 538 reply = wpas_dbus_iface_select_network(message, wpa_s); 539 else if (!strcmp(method, "capabilities")) 540 reply = wpas_dbus_iface_capabilities(message, wpa_s); 541 else if (!strcmp(method, "disconnect")) 542 reply = wpas_dbus_iface_disconnect(message, wpa_s); 543 else if (!strcmp(method, "setAPScan")) 544 reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); 545 else if (!strcmp(method, "state")) 546 reply = wpas_dbus_iface_get_state(message, wpa_s); 547 else if (!strcmp(method, "setBlobs")) 548 reply = wpas_dbus_iface_set_blobs(message, wpa_s); 549 else if (!strcmp(method, "removeBlobs")) 550 reply = wpas_dbus_iface_remove_blobs(message, wpa_s); 551 } 552 553 /* If the message was handled, send back the reply */ 554 if (reply) { 555 dbus_connection_send(connection, reply, NULL); 556 dbus_message_unref(reply); 557 } 558 559 out: 560 free(iface_obj_path); 561 free(network); 562 free(bssid); 563 return reply ? DBUS_HANDLER_RESULT_HANDLED : 564 DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 565 } 566 567 568 /** 569 * wpas_message_handler - dispatch incoming dbus messages 570 * @connection: connection to the system message bus 571 * @message: an incoming dbus message 572 * @user_data: a pointer to a dbus control interface data structure 573 * Returns: whether or not the message was handled 574 * 575 * This function dispatches all incoming dbus messages to the correct 576 * handlers, depending on what the message's target object path is, 577 * and what the method call is. 578 */ 579 static DBusHandlerResult wpas_message_handler(DBusConnection *connection, 580 DBusMessage *message, void *user_data) 581 { 582 struct ctrl_iface_dbus_priv *ctrl_iface = user_data; 583 const char *method; 584 const char *path; 585 const char *msg_interface; 586 DBusMessage *reply = NULL; 587 588 method = dbus_message_get_member(message); 589 path = dbus_message_get_path(message); 590 msg_interface = dbus_message_get_interface(message); 591 if (!method || !path || !ctrl_iface || !msg_interface) 592 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 593 594 /* Validate the method interface */ 595 if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) 596 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 597 598 if (!strcmp(path, WPAS_DBUS_PATH)) { 599 /* dispatch methods against our global dbus interface here */ 600 if (!strcmp(method, "addInterface")) { 601 reply = wpas_dbus_global_add_interface( 602 message, ctrl_iface->global); 603 } else if (!strcmp(method, "removeInterface")) { 604 reply = wpas_dbus_global_remove_interface( 605 message, ctrl_iface->global); 606 } else if (!strcmp(method, "getInterface")) { 607 reply = wpas_dbus_global_get_interface( 608 message, ctrl_iface->global); 609 } 610 } 611 612 /* If the message was handled, send back the reply */ 613 if (reply) { 614 dbus_connection_send(connection, reply, NULL); 615 dbus_message_unref(reply); 616 } 617 618 return reply ? DBUS_HANDLER_RESULT_HANDLED : 619 DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 620 } 621 622 623 /** 624 * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal 625 * @wpa_s: %wpa_supplicant network interface data 626 * Returns: 0 on success, -1 on failure 627 * 628 * Notify listeners that this interface has updated scan results. 629 */ 630 void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) 631 { 632 struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface; 633 DBusMessage *signal; 634 const char *path; 635 636 /* Do nothing if the control interface is not turned on */ 637 if (iface == NULL) 638 return; 639 640 path = wpa_supplicant_get_dbus_path(wpa_s); 641 if (path == NULL) { 642 perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " 643 "interface didn't have a dbus path"); 644 wpa_printf(MSG_ERROR, 645 "wpa_supplicant_dbus_notify_scan_results[dbus]: " 646 "interface didn't have a dbus path; can't send " 647 "scan result signal."); 648 return; 649 } 650 signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, 651 "ScanResultsAvailable"); 652 if (signal == NULL) { 653 perror("wpa_supplicant_dbus_notify_scan_results[dbus]: " 654 "couldn't create dbus signal; likely out of memory"); 655 wpa_printf(MSG_ERROR, "dbus control interface: not enough " 656 "memory to send scan results signal."); 657 return; 658 } 659 dbus_connection_send(iface->con, signal, NULL); 660 dbus_message_unref(signal); 661 } 662 663 664 /** 665 * wpa_supplicant_dbus_notify_state_change - Send a state change signal 666 * @wpa_s: %wpa_supplicant network interface data 667 * @new_state: new state wpa_supplicant is entering 668 * @old_state: old state wpa_supplicant is leaving 669 * Returns: 0 on success, -1 on failure 670 * 671 * Notify listeners that wpa_supplicant has changed state 672 */ 673 void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, 674 wpa_states new_state, 675 wpa_states old_state) 676 { 677 struct ctrl_iface_dbus_priv *iface; 678 DBusMessage *signal = NULL; 679 const char *path; 680 const char *new_state_str, *old_state_str; 681 682 /* Do nothing if the control interface is not turned on */ 683 if (wpa_s->global == NULL) 684 return; 685 iface = wpa_s->global->dbus_ctrl_iface; 686 if (iface == NULL) 687 return; 688 689 /* Only send signal if state really changed */ 690 if (new_state == old_state) 691 return; 692 693 path = wpa_supplicant_get_dbus_path(wpa_s); 694 if (path == NULL) { 695 perror("wpa_supplicant_dbus_notify_state_change[dbus]: " 696 "interface didn't have a dbus path"); 697 wpa_printf(MSG_ERROR, 698 "wpa_supplicant_dbus_notify_state_change[dbus]: " 699 "interface didn't have a dbus path; can't send " 700 "signal."); 701 return; 702 } 703 signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, 704 "StateChange"); 705 if (signal == NULL) { 706 perror("wpa_supplicant_dbus_notify_state_change[dbus]: " 707 "couldn't create dbus signal; likely out of memory"); 708 wpa_printf(MSG_ERROR, 709 "wpa_supplicant_dbus_notify_state_change[dbus]: " 710 "couldn't create dbus signal; likely out of " 711 "memory."); 712 return; 713 } 714 715 new_state_str = wpa_supplicant_state_txt(new_state); 716 old_state_str = wpa_supplicant_state_txt(old_state); 717 if (new_state_str == NULL || old_state_str == NULL) { 718 perror("wpa_supplicant_dbus_notify_state_change[dbus]: " 719 "couldn't convert state strings"); 720 wpa_printf(MSG_ERROR, 721 "wpa_supplicant_dbus_notify_state_change[dbus]: " 722 "couldn't convert state strings."); 723 goto out; 724 } 725 726 if (!dbus_message_append_args(signal, 727 DBUS_TYPE_STRING, &new_state_str, 728 DBUS_TYPE_STRING, &old_state_str, 729 DBUS_TYPE_INVALID)) { 730 perror("wpa_supplicant_dbus_notify_state_change[dbus]: " 731 "not enough memory to construct state change signal."); 732 wpa_printf(MSG_ERROR, 733 "wpa_supplicant_dbus_notify_state_change[dbus]: " 734 "not enough memory to construct state change " 735 "signal."); 736 goto out; 737 } 738 dbus_connection_send(iface->con, signal, NULL); 739 740 out: 741 dbus_message_unref(signal); 742 } 743 744 745 /** 746 * integrate_with_eloop - Register our mainloop integration with dbus 747 * @connection: connection to the system message bus 748 * @iface: a dbus control interface data structure 749 * Returns: 0 on success, -1 on failure 750 * 751 * We register our mainloop integration functions with dbus here. 752 */ 753 static int integrate_with_eloop(DBusConnection *connection, 754 struct ctrl_iface_dbus_priv *iface) 755 { 756 if (!dbus_connection_set_watch_functions(connection, add_watch, 757 remove_watch, watch_toggled, 758 iface, NULL)) { 759 perror("dbus_connection_set_watch_functions[dbus]"); 760 wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); 761 return -1; 762 } 763 764 if (!dbus_connection_set_timeout_functions(connection, add_timeout, 765 remove_timeout, 766 timeout_toggled, iface, 767 NULL)) { 768 perror("dbus_connection_set_timeout_functions[dbus]"); 769 wpa_printf(MSG_ERROR, "Not enough memory to set up dbus."); 770 return -1; 771 } 772 773 if (connection_setup_wakeup_main(iface) < 0) { 774 perror("connection_setup_wakeup_main[dbus]"); 775 wpa_printf(MSG_ERROR, "Could not setup main wakeup function."); 776 return -1; 777 } 778 779 return 0; 780 } 781 782 783 /** 784 * dispatch_initial_dbus_messages - Dispatch initial dbus messages after 785 * claiming bus name 786 * @eloop_ctx: the DBusConnection to dispatch on 787 * @timeout_ctx: unused 788 * 789 * If clients are quick to notice that wpa_supplicant claimed its bus name, 790 * there may have been messages that came in before initialization was 791 * all finished. Dispatch those here. 792 */ 793 static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx) 794 { 795 DBusConnection *con = eloop_ctx; 796 797 while (dbus_connection_get_dispatch_status(con) == 798 DBUS_DISPATCH_DATA_REMAINS) 799 dbus_connection_dispatch(con); 800 } 801 802 803 /** 804 * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface 805 * @global: Pointer to global data from wpa_supplicant_init() 806 * Returns: Pointer to dbus_ctrl_iface date or %NULL on failure 807 * 808 * Initialize the dbus control interface and start receiving commands from 809 * external programs over the bus. 810 */ 811 struct ctrl_iface_dbus_priv * 812 wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global) 813 { 814 struct ctrl_iface_dbus_priv *iface; 815 DBusError error; 816 int ret = -1; 817 DBusObjectPathVTable wpas_vtable = { 818 NULL, &wpas_message_handler, NULL, NULL, NULL, NULL 819 }; 820 821 iface = wpa_zalloc(sizeof(struct ctrl_iface_dbus_priv)); 822 if (iface == NULL) 823 return NULL; 824 825 iface->global = global; 826 827 /* Get a reference to the system bus */ 828 dbus_error_init(&error); 829 iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); 830 dbus_error_free(&error); 831 if (!iface->con) { 832 perror("dbus_bus_get[ctrl_iface_dbus]"); 833 wpa_printf(MSG_ERROR, "Could not acquire the system bus."); 834 goto fail; 835 } 836 837 /* Tell dbus about our mainloop integration functions */ 838 if (integrate_with_eloop(iface->con, iface)) 839 goto fail; 840 841 /* Register the message handler for the global dbus interface */ 842 if (!dbus_connection_register_object_path(iface->con, 843 WPAS_DBUS_PATH, &wpas_vtable, 844 iface)) { 845 perror("dbus_connection_register_object_path[dbus]"); 846 wpa_printf(MSG_ERROR, "Could not set up DBus message " 847 "handler."); 848 goto fail; 849 } 850 851 /* Register our service with the message bus */ 852 dbus_error_init(&error); 853 switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, 854 0, &error)) { 855 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: 856 ret = 0; 857 break; 858 case DBUS_REQUEST_NAME_REPLY_EXISTS: 859 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: 860 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: 861 perror("dbus_bus_request_name[dbus]"); 862 wpa_printf(MSG_ERROR, "Could not request DBus service name: " 863 "already registered."); 864 break; 865 default: 866 perror("dbus_bus_request_name[dbus]"); 867 wpa_printf(MSG_ERROR, "Could not request DBus service name: " 868 "%s %s.", error.name, error.message); 869 break; 870 } 871 dbus_error_free(&error); 872 873 if (ret != 0) 874 goto fail; 875 876 wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE 877 "'."); 878 879 /* 880 * Dispatch initial DBus messages that may have come in since the bus 881 * name was claimed above. Happens when clients are quick to notice the 882 * wpa_supplicant service. 883 * 884 * FIXME: is there a better solution to this problem? 885 */ 886 eloop_register_timeout(0, 50, dispatch_initial_dbus_messages, 887 iface->con, NULL); 888 889 return iface; 890 891 fail: 892 wpa_supplicant_dbus_ctrl_iface_deinit(iface); 893 return NULL; 894 } 895 896 897 /** 898 * wpa_supplicant_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface 899 * @iface: Pointer to dbus private data from 900 * wpa_supplicant_dbus_ctrl_iface_init() 901 * 902 * Deinitialize the dbus control interface that was initialized with 903 * wpa_supplicant_dbus_ctrl_iface_init(). 904 */ 905 void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface) 906 { 907 if (iface == NULL) 908 return; 909 910 if (iface->con) { 911 eloop_cancel_timeout(dispatch_initial_dbus_messages, 912 iface->con, NULL); 913 dbus_connection_set_watch_functions(iface->con, NULL, NULL, 914 NULL, NULL, NULL); 915 dbus_connection_set_timeout_functions(iface->con, NULL, NULL, 916 NULL, NULL, NULL); 917 dbus_connection_unref(iface->con); 918 } 919 920 memset(iface, 0, sizeof(struct ctrl_iface_dbus_priv)); 921 free(iface); 922 } 923 924 925 /** 926 * wpas_dbus_register_new_iface - Register a new interface with dbus 927 * @global: Global %wpa_supplicant data 928 * @wpa_s: %wpa_supplicant interface description structure to register 929 * Returns: 0 on success, -1 on error 930 * 931 * Registers a new interface with dbus and assigns it a dbus object path. 932 */ 933 int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) 934 { 935 struct ctrl_iface_dbus_priv *ctrl_iface = 936 wpa_s->global->dbus_ctrl_iface; 937 DBusConnection * con; 938 u32 next; 939 DBusObjectPathVTable vtable = { 940 NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL 941 }; 942 char *path; 943 int ret = -1; 944 945 /* Do nothing if the control interface is not turned on */ 946 if (ctrl_iface == NULL) 947 return 0; 948 949 con = ctrl_iface->con; 950 next = wpa_supplicant_dbus_next_objid(ctrl_iface); 951 952 /* Create and set the interface's object path */ 953 path = wpa_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 954 if (path == NULL) 955 return -1; 956 snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, 957 WPAS_DBUS_PATH_INTERFACES "/%u", 958 next); 959 if (wpa_supplicant_set_dbus_path(wpa_s, path)) { 960 wpa_printf(MSG_DEBUG, 961 "Failed to set dbus path for interface %s", 962 wpa_s->ifname); 963 goto out; 964 } 965 966 /* Register the message handler for the interface functions */ 967 if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) { 968 perror("wpas_dbus_register_iface [dbus]"); 969 wpa_printf(MSG_ERROR, "Could not set up DBus message " 970 "handler for interface %s.", wpa_s->ifname); 971 goto out; 972 } 973 ret = 0; 974 975 out: 976 free(path); 977 return ret; 978 } 979 980 981 /** 982 * wpas_dbus_unregister_iface - Unregister an interface from dbus 983 * @wpa_s: wpa_supplicant interface structure 984 * Returns: 0 on success, -1 on failure 985 * 986 * Unregisters the interface with dbus 987 */ 988 int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) 989 { 990 struct ctrl_iface_dbus_priv *ctrl_iface; 991 DBusConnection *con; 992 const char *path; 993 994 /* Do nothing if the control interface is not turned on */ 995 if (wpa_s == NULL || wpa_s->global == NULL) 996 return 0; 997 ctrl_iface = wpa_s->global->dbus_ctrl_iface; 998 if (ctrl_iface == NULL) 999 return 0; 1000 1001 con = ctrl_iface->con; 1002 path = wpa_supplicant_get_dbus_path(wpa_s); 1003 1004 if (!dbus_connection_unregister_object_path(con, path)) 1005 return -1; 1006 1007 free(wpa_s->dbus_path); 1008 wpa_s->dbus_path = NULL; 1009 1010 return 0; 1011 } 1012 1013 1014 /** 1015 * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface 1016 * @global: Pointer to global data from wpa_supplicant_init() 1017 * @path: Pointer to a dbus object path representing an interface 1018 * Returns: Pointer to the interface or %NULL if not found 1019 */ 1020 struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( 1021 struct wpa_global *global, const char *path) 1022 { 1023 struct wpa_supplicant *wpa_s; 1024 1025 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 1026 if (strcmp(wpa_s->dbus_path, path) == 0) 1027 return wpa_s; 1028 } 1029 return NULL; 1030 } 1031 1032 1033 /** 1034 * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface 1035 * @wpa_s: wpa_supplicant interface structure 1036 * @path: dbus path to set on the interface 1037 * Returns: 0 on succes, -1 on error 1038 */ 1039 int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s, 1040 const char *path) 1041 { 1042 u32 len = strlen (path); 1043 if (len >= WPAS_DBUS_OBJECT_PATH_MAX) 1044 return -1; 1045 if (wpa_s->dbus_path) 1046 return -1; 1047 wpa_s->dbus_path = strdup(path); 1048 return 0; 1049 } 1050 1051 1052 /** 1053 * wpa_supplicant_get_dbus_path - Get an interface's dbus path 1054 * @wpa_s: %wpa_supplicant interface structure 1055 * Returns: Interface's dbus object path, or %NULL on error 1056 */ 1057 const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s) 1058 { 1059 return wpa_s->dbus_path; 1060 } 1061