$search
00001 /* 00002 * WPA Supplicant / dbus-based control interface 00003 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 #include <dbus/dbus.h> 00017 00018 #include "common.h" 00019 #include "eloop.h" 00020 #include "wps/wps.h" 00021 #include "../config.h" 00022 #include "../wpa_supplicant_i.h" 00023 #include "../bss.h" 00024 #include "dbus_old.h" 00025 #include "dbus_old_handlers.h" 00026 #include "dbus_common.h" 00027 #include "dbus_common_i.h" 00028 00029 00040 char * wpas_dbus_decompose_object_path(const char *path, char **network, 00041 char **bssid) 00042 { 00043 const unsigned int dev_path_prefix_len = 00044 strlen(WPAS_DBUS_PATH_INTERFACES "/"); 00045 char *obj_path_only; 00046 char *next_sep; 00047 00048 /* Be a bit paranoid about path */ 00049 if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", 00050 dev_path_prefix_len)) 00051 return NULL; 00052 00053 /* Ensure there's something at the end of the path */ 00054 if ((path + dev_path_prefix_len)[0] == '\0') 00055 return NULL; 00056 00057 obj_path_only = os_strdup(path); 00058 if (obj_path_only == NULL) 00059 return NULL; 00060 00061 next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); 00062 if (next_sep != NULL) { 00063 const char *net_part = strstr(next_sep, 00064 WPAS_DBUS_NETWORKS_PART "/"); 00065 const char *bssid_part = strstr(next_sep, 00066 WPAS_DBUS_BSSIDS_PART "/"); 00067 00068 if (network && net_part) { 00069 /* Deal with a request for a configured network */ 00070 const char *net_name = net_part + 00071 strlen(WPAS_DBUS_NETWORKS_PART "/"); 00072 *network = NULL; 00073 if (strlen(net_name)) 00074 *network = os_strdup(net_name); 00075 } else if (bssid && bssid_part) { 00076 /* Deal with a request for a scanned BSSID */ 00077 const char *bssid_name = bssid_part + 00078 strlen(WPAS_DBUS_BSSIDS_PART "/"); 00079 if (strlen(bssid_name)) 00080 *bssid = os_strdup(bssid_name); 00081 else 00082 *bssid = NULL; 00083 } 00084 00085 /* Cut off interface object path before "/" */ 00086 *next_sep = '\0'; 00087 } 00088 00089 return obj_path_only; 00090 } 00091 00092 00100 DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) 00101 { 00102 return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, 00103 "wpa_supplicant knows nothing about " 00104 "this interface."); 00105 } 00106 00107 00115 DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) 00116 { 00117 return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, 00118 "The requested network does not exist."); 00119 } 00120 00121 00129 static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) 00130 { 00131 return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, 00132 "The BSSID requested was invalid."); 00133 } 00134 00135 00145 static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, 00146 struct wpa_supplicant *wpa_s, 00147 int network_id) 00148 { 00149 DBusMessage *reply = NULL; 00150 const char *method = dbus_message_get_member(message); 00151 struct wpa_ssid *ssid; 00152 00153 ssid = wpa_config_get_network(wpa_s->conf, network_id); 00154 if (ssid == NULL) 00155 return wpas_dbus_new_invalid_network_error(message); 00156 00157 if (!strcmp(method, "set")) 00158 reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); 00159 else if (!strcmp(method, "enable")) 00160 reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); 00161 else if (!strcmp(method, "disable")) 00162 reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); 00163 00164 return reply; 00165 } 00166 00167 00177 static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, 00178 struct wpa_supplicant *wpa_s, 00179 const char *bssid_txt) 00180 { 00181 u8 bssid[ETH_ALEN]; 00182 struct wpa_bss *bss; 00183 00184 if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0) 00185 return wpas_dbus_new_invalid_bssid_error(message); 00186 00187 bss = wpa_bss_get_bssid(wpa_s, bssid); 00188 if (bss == NULL) 00189 return wpas_dbus_new_invalid_bssid_error(message); 00190 00191 /* Dispatch the method call against the scanned bssid */ 00192 if (os_strcmp(dbus_message_get_member(message), "properties") == 0) 00193 return wpas_dbus_bssid_properties(message, wpa_s, bss); 00194 00195 return NULL; 00196 } 00197 00198 00209 static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, 00210 DBusMessage *message, 00211 void *user_data) 00212 { 00213 struct wpa_supplicant *wpa_s = user_data; 00214 const char *method = dbus_message_get_member(message); 00215 const char *path = dbus_message_get_path(message); 00216 const char *msg_interface = dbus_message_get_interface(message); 00217 char *iface_obj_path = NULL; 00218 char *network = NULL; 00219 char *bssid = NULL; 00220 DBusMessage *reply = NULL; 00221 00222 /* Caller must specify a message interface */ 00223 if (!msg_interface) 00224 goto out; 00225 00226 iface_obj_path = wpas_dbus_decompose_object_path(path, &network, 00227 &bssid); 00228 if (iface_obj_path == NULL) { 00229 reply = wpas_dbus_new_invalid_iface_error(message); 00230 goto out; 00231 } 00232 00233 /* Make sure the message's object path actually refers to the 00234 * wpa_supplicant structure it's supposed to (which is wpa_s) 00235 */ 00236 if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, 00237 iface_obj_path) != wpa_s) { 00238 reply = wpas_dbus_new_invalid_iface_error(message); 00239 goto out; 00240 } 00241 00242 if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { 00243 /* A method for one of this interface's configured networks */ 00244 int nid = strtoul(network, NULL, 10); 00245 if (errno != EINVAL) 00246 reply = wpas_dispatch_network_method(message, wpa_s, 00247 nid); 00248 else 00249 reply = wpas_dbus_new_invalid_network_error(message); 00250 } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { 00251 /* A method for one of this interface's scanned BSSIDs */ 00252 reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); 00253 } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { 00254 /* A method for an interface only. */ 00255 if (!strcmp(method, "scan")) 00256 reply = wpas_dbus_iface_scan(message, wpa_s); 00257 else if (!strcmp(method, "scanResults")) 00258 reply = wpas_dbus_iface_scan_results(message, wpa_s); 00259 else if (!strcmp(method, "addNetwork")) 00260 reply = wpas_dbus_iface_add_network(message, wpa_s); 00261 else if (!strcmp(method, "removeNetwork")) 00262 reply = wpas_dbus_iface_remove_network(message, wpa_s); 00263 else if (!strcmp(method, "selectNetwork")) 00264 reply = wpas_dbus_iface_select_network(message, wpa_s); 00265 else if (!strcmp(method, "capabilities")) 00266 reply = wpas_dbus_iface_capabilities(message, wpa_s); 00267 else if (!strcmp(method, "disconnect")) 00268 reply = wpas_dbus_iface_disconnect(message, wpa_s); 00269 else if (!strcmp(method, "setAPScan")) 00270 reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); 00271 else if (!strcmp(method, "setSmartcardModules")) 00272 reply = wpas_dbus_iface_set_smartcard_modules(message, 00273 wpa_s); 00274 else if (!strcmp(method, "state")) 00275 reply = wpas_dbus_iface_get_state(message, wpa_s); 00276 else if (!strcmp(method, "scanning")) 00277 reply = wpas_dbus_iface_get_scanning(message, wpa_s); 00278 else if (!strcmp(method, "setBlobs")) 00279 reply = wpas_dbus_iface_set_blobs(message, wpa_s); 00280 else if (!strcmp(method, "removeBlobs")) 00281 reply = wpas_dbus_iface_remove_blobs(message, wpa_s); 00282 #ifdef CONFIG_WPS 00283 else if (!os_strcmp(method, "wpsPbc")) 00284 reply = wpas_dbus_iface_wps_pbc(message, wpa_s); 00285 else if (!os_strcmp(method, "wpsPin")) 00286 reply = wpas_dbus_iface_wps_pin(message, wpa_s); 00287 else if (!os_strcmp(method, "wpsReg")) 00288 reply = wpas_dbus_iface_wps_reg(message, wpa_s); 00289 #endif /* CONFIG_WPS */ 00290 } 00291 00292 /* If the message was handled, send back the reply */ 00293 if (reply) { 00294 if (!dbus_message_get_no_reply(message)) 00295 dbus_connection_send(connection, reply, NULL); 00296 dbus_message_unref(reply); 00297 } 00298 00299 out: 00300 os_free(iface_obj_path); 00301 os_free(network); 00302 os_free(bssid); 00303 return reply ? DBUS_HANDLER_RESULT_HANDLED : 00304 DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00305 } 00306 00307 00319 static DBusHandlerResult wpas_message_handler(DBusConnection *connection, 00320 DBusMessage *message, void *user_data) 00321 { 00322 struct wpas_dbus_priv *ctrl_iface = user_data; 00323 const char *method; 00324 const char *path; 00325 const char *msg_interface; 00326 DBusMessage *reply = NULL; 00327 00328 method = dbus_message_get_member(message); 00329 path = dbus_message_get_path(message); 00330 msg_interface = dbus_message_get_interface(message); 00331 if (!method || !path || !ctrl_iface || !msg_interface) 00332 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00333 00334 /* Validate the method interface */ 00335 if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) 00336 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00337 00338 if (!strcmp(path, WPAS_DBUS_PATH)) { 00339 /* dispatch methods against our global dbus interface here */ 00340 if (!strcmp(method, "addInterface")) { 00341 reply = wpas_dbus_global_add_interface( 00342 message, ctrl_iface->global); 00343 } else if (!strcmp(method, "removeInterface")) { 00344 reply = wpas_dbus_global_remove_interface( 00345 message, ctrl_iface->global); 00346 } else if (!strcmp(method, "getInterface")) { 00347 reply = wpas_dbus_global_get_interface( 00348 message, ctrl_iface->global); 00349 } else if (!strcmp(method, "setDebugParams")) { 00350 reply = wpas_dbus_global_set_debugparams( 00351 message, ctrl_iface->global); 00352 } 00353 } 00354 00355 /* If the message was handled, send back the reply */ 00356 if (reply) { 00357 if (!dbus_message_get_no_reply(message)) 00358 dbus_connection_send(connection, reply, NULL); 00359 dbus_message_unref(reply); 00360 } 00361 00362 return reply ? DBUS_HANDLER_RESULT_HANDLED : 00363 DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 00364 } 00365 00366 00374 void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) 00375 { 00376 struct wpas_dbus_priv *iface = wpa_s->global->dbus; 00377 DBusMessage *_signal; 00378 00379 /* Do nothing if the control interface is not turned on */ 00380 if (iface == NULL) 00381 return; 00382 00383 _signal = dbus_message_new_signal(wpa_s->dbus_path, 00384 WPAS_DBUS_IFACE_INTERFACE, 00385 "ScanResultsAvailable"); 00386 if (_signal == NULL) { 00387 wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " 00388 "results signal"); 00389 return; 00390 } 00391 dbus_connection_send(iface->con, _signal, NULL); 00392 dbus_message_unref(_signal); 00393 } 00394 00395 00405 void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, 00406 enum wpa_states new_state, 00407 enum wpa_states old_state) 00408 { 00409 struct wpas_dbus_priv *iface; 00410 DBusMessage *_signal = NULL; 00411 const char *new_state_str, *old_state_str; 00412 00413 /* Do nothing if the control interface is not turned on */ 00414 if (wpa_s->global == NULL) 00415 return; 00416 iface = wpa_s->global->dbus; 00417 if (iface == NULL) 00418 return; 00419 00420 /* Only send signal if state really changed */ 00421 if (new_state == old_state) 00422 return; 00423 00424 _signal = dbus_message_new_signal(wpa_s->dbus_path, 00425 WPAS_DBUS_IFACE_INTERFACE, 00426 "StateChange"); 00427 if (_signal == NULL) { 00428 wpa_printf(MSG_ERROR, 00429 "dbus: wpa_supplicant_dbus_notify_state_change: " 00430 "could not create dbus signal; likely out of " 00431 "memory"); 00432 return; 00433 } 00434 00435 new_state_str = wpa_supplicant_state_txt(new_state); 00436 old_state_str = wpa_supplicant_state_txt(old_state); 00437 if (new_state_str == NULL || old_state_str == NULL) { 00438 wpa_printf(MSG_ERROR, 00439 "dbus: wpa_supplicant_dbus_notify_state_change: " 00440 "Could not convert state strings"); 00441 goto out; 00442 } 00443 00444 if (!dbus_message_append_args(_signal, 00445 DBUS_TYPE_STRING, &new_state_str, 00446 DBUS_TYPE_STRING, &old_state_str, 00447 DBUS_TYPE_INVALID)) { 00448 wpa_printf(MSG_ERROR, 00449 "dbus: wpa_supplicant_dbus_notify_state_change: " 00450 "Not enough memory to construct state change " 00451 "signal"); 00452 goto out; 00453 } 00454 00455 dbus_connection_send(iface->con, _signal, NULL); 00456 00457 out: 00458 dbus_message_unref(_signal); 00459 } 00460 00461 00469 void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) 00470 { 00471 struct wpas_dbus_priv *iface = wpa_s->global->dbus; 00472 DBusMessage *_signal; 00473 dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; 00474 00475 /* Do nothing if the control interface is not turned on */ 00476 if (iface == NULL) 00477 return; 00478 00479 _signal = dbus_message_new_signal(wpa_s->dbus_path, 00480 WPAS_DBUS_IFACE_INTERFACE, 00481 "Scanning"); 00482 if (_signal == NULL) { 00483 wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " 00484 "results signal"); 00485 return; 00486 } 00487 00488 if (dbus_message_append_args(_signal, 00489 DBUS_TYPE_BOOLEAN, &scanning, 00490 DBUS_TYPE_INVALID)) { 00491 dbus_connection_send(iface->con, _signal, NULL); 00492 } else { 00493 wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct " 00494 "signal"); 00495 } 00496 dbus_message_unref(_signal); 00497 } 00498 00499 00500 #ifdef CONFIG_WPS 00501 void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, 00502 const struct wps_credential *cred) 00503 { 00504 struct wpas_dbus_priv *iface; 00505 DBusMessage *_signal = NULL; 00506 00507 /* Do nothing if the control interface is not turned on */ 00508 if (wpa_s->global == NULL) 00509 return; 00510 iface = wpa_s->global->dbus; 00511 if (iface == NULL) 00512 return; 00513 00514 _signal = dbus_message_new_signal(wpa_s->dbus_path, 00515 WPAS_DBUS_IFACE_INTERFACE, 00516 "WpsCred"); 00517 if (_signal == NULL) { 00518 wpa_printf(MSG_ERROR, 00519 "dbus: wpa_supplicant_dbus_notify_wps_cred: " 00520 "Could not create dbus signal; likely out of " 00521 "memory"); 00522 return; 00523 } 00524 00525 if (!dbus_message_append_args(_signal, 00526 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, 00527 &cred->cred_attr, cred->cred_attr_len, 00528 DBUS_TYPE_INVALID)) { 00529 wpa_printf(MSG_ERROR, 00530 "dbus: wpa_supplicant_dbus_notify_wps_cred: " 00531 "Not enough memory to construct signal"); 00532 goto out; 00533 } 00534 00535 dbus_connection_send(iface->con, _signal, NULL); 00536 00537 out: 00538 dbus_message_unref(_signal); 00539 } 00540 #else /* CONFIG_WPS */ 00541 void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, 00542 const struct wps_credential *cred) 00543 { 00544 } 00545 #endif /* CONFIG_WPS */ 00546 00547 00556 int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface) 00557 { 00558 DBusError error; 00559 int ret = -1; 00560 DBusObjectPathVTable wpas_vtable = { 00561 NULL, &wpas_message_handler, NULL, NULL, NULL, NULL 00562 }; 00563 00564 /* Register the message handler for the global dbus interface */ 00565 if (!dbus_connection_register_object_path(iface->con, 00566 WPAS_DBUS_PATH, &wpas_vtable, 00567 iface)) { 00568 wpa_printf(MSG_ERROR, "dbus: Could not set up message " 00569 "handler"); 00570 return -1; 00571 } 00572 00573 /* Register our service with the message bus */ 00574 dbus_error_init(&error); 00575 switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, 00576 0, &error)) { 00577 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: 00578 ret = 0; 00579 break; 00580 case DBUS_REQUEST_NAME_REPLY_EXISTS: 00581 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: 00582 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: 00583 wpa_printf(MSG_ERROR, "dbus: Could not request service name: " 00584 "already registered"); 00585 break; 00586 default: 00587 wpa_printf(MSG_ERROR, "dbus: Could not request service name: " 00588 "%s %s", error.name, error.message); 00589 break; 00590 } 00591 dbus_error_free(&error); 00592 00593 if (ret != 0) 00594 return -1; 00595 00596 wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE 00597 "'."); 00598 00599 return 0; 00600 } 00601 00602 00610 int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) 00611 { 00612 struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; 00613 DBusConnection * con; 00614 u32 next; 00615 DBusObjectPathVTable vtable = { 00616 NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL 00617 }; 00618 00619 /* Do nothing if the control interface is not turned on */ 00620 if (ctrl_iface == NULL) 00621 return 0; 00622 00623 con = ctrl_iface->con; 00624 next = ctrl_iface->next_objid++; 00625 00626 /* Create and set the interface's object path */ 00627 wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 00628 if (wpa_s->dbus_path == NULL) 00629 return -1; 00630 os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX, 00631 WPAS_DBUS_PATH_INTERFACES "/%u", 00632 next); 00633 00634 /* Register the message handler for the interface functions */ 00635 if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable, 00636 wpa_s)) { 00637 wpa_printf(MSG_ERROR, "dbus: Could not set up message " 00638 "handler for interface %s", wpa_s->ifname); 00639 return -1; 00640 } 00641 00642 return 0; 00643 } 00644 00645 00653 int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) 00654 { 00655 struct wpas_dbus_priv *ctrl_iface; 00656 DBusConnection *con; 00657 00658 /* Do nothing if the control interface is not turned on */ 00659 if (wpa_s == NULL || wpa_s->global == NULL) 00660 return 0; 00661 ctrl_iface = wpa_s->global->dbus; 00662 if (ctrl_iface == NULL) 00663 return 0; 00664 00665 con = ctrl_iface->con; 00666 if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path)) 00667 return -1; 00668 00669 os_free(wpa_s->dbus_path); 00670 wpa_s->dbus_path = NULL; 00671 00672 return 0; 00673 } 00674 00675 00682 struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( 00683 struct wpa_global *global, const char *path) 00684 { 00685 struct wpa_supplicant *wpa_s; 00686 00687 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 00688 if (strcmp(wpa_s->dbus_path, path) == 0) 00689 return wpa_s; 00690 } 00691 return NULL; 00692 }