/* * * bluez-tools - a set of tools to manage bluetooth devices for linux * * Copyright (C) 2010-2011 Alexander Orlenko * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "agent-helper.h" static const gchar *_bt_agent_introspect_xml = "\n\t\n\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\n\t\n\n"; static guint _bt_agent_registration_id = 0; static GHashTable *_pin_hash_table = NULL; static gboolean _interactive = TRUE; static GMainLoop *_mainloop = NULL; static void _bt_agent_g_destroy_notify(gpointer data); static void _bt_agent_method_call_func(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data); static const gchar *_find_device_pin(const gchar *device_path); static void _bt_agent_method_call_func(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { // g_print("%s%s\n", method_name, g_variant_print(parameters, FALSE)); if (g_strcmp0(method_name, "AuthorizeService") == 0) { // Return void g_dbus_method_invocation_return_value(invocation, NULL); } else if (g_strcmp0(method_name, "Cancel") == 0) { if (_interactive) g_print("Request canceled\n"); // Return void g_dbus_method_invocation_return_value(invocation, NULL); } else if (g_strcmp0(method_name, "DisplayPasskey") == 0) { GError *error = NULL; Device *device_obj = device_new(g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL)); const gchar *pin = _find_device_pin(device_get_dbus_object_path(device_obj)); if (_interactive) g_print("Device: %s (%s)\n", device_get_alias(device_obj, &error), device_get_address(device_obj, &error)); if (error) { g_critical("Failed to get remote device's MAC address: %s", error->message); g_error_free(error); } g_object_unref(device_obj); if (_interactive) { g_print("Passkey: %u, entered: %u\n", g_variant_get_uint32(g_variant_get_child_value(parameters, 1)), g_variant_get_uint16(g_variant_get_child_value(parameters, 2))); g_dbus_method_invocation_return_value(invocation, NULL); return; } else if (pin != NULL) { /* OK, device found */ g_dbus_method_invocation_return_value(invocation, NULL); return; } g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Pairing rejected"); } else if (g_strcmp0(method_name, "DisplayPinCode") == 0) { GError *error = NULL; Device *device_obj = device_new(g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL)); const gchar *pin = _find_device_pin(device_get_dbus_object_path(device_obj)); const gchar *pincode = g_variant_get_string(g_variant_get_child_value(parameters, 1), NULL); if (_interactive) g_print("Device: %s (%s)\n", device_get_alias(device_obj, &error), device_get_address(device_obj, &error)); if (error) { g_critical("Failed to get remote device's MAC address: %s", error->message); g_error_free(error); } g_object_unref(device_obj); /* Try to use found PIN */ if (pin != NULL) { if (g_strcmp0(pin, "*") == 0 || g_strcmp0(pin, pincode) == 0) { if (_interactive) g_print("Pin code confirmed\n"); g_dbus_method_invocation_return_value(invocation, NULL); } else g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Passkey does not match"); return; } else if (_interactive) { g_print("Confirm pin code: %s (yes/no)? ", pincode); gchar yn[4] = {0,}; errno = 0; if (scanf("%3s", yn) == EOF && errno) g_warning("%s\n", strerror(errno)); if(g_ascii_strcasecmp(yn, "yes") == 0 || g_ascii_strcasecmp(yn, "y") == 0) g_dbus_method_invocation_return_value(invocation, NULL); else g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Passkey does not match"); return; } g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Pairing rejected"); } else if (g_strcmp0(method_name, "Release") == 0) { agent_need_unregister = FALSE; if(_mainloop) if (g_main_loop_is_running(_mainloop)) g_main_loop_quit(_mainloop); g_print("Agent released\n"); // Return void g_dbus_method_invocation_return_value(invocation, NULL); } else if (g_strcmp0(method_name, "RequestAuthorization") == 0) { GError *error = NULL; Device *device_obj = device_new(g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL)); if (_interactive) g_print("Device: %s (%s)\n", device_get_alias(device_obj, &error), device_get_address(device_obj, &error)); if(error) { g_critical("Failed to get remote device's MAC address: %s", error->message); g_error_free(error); } g_object_unref(device_obj); if (_interactive) { g_print("Authorize this device pairing (yes/no)? "); gchar yn[4] = {0,}; errno = 0; if (scanf("%3s", yn) == EOF && errno) g_warning("%s\n", strerror(errno)); if(g_ascii_strcasecmp(yn, "yes") == 0 || g_ascii_strcasecmp(yn, "y") == 0) g_dbus_method_invocation_return_value(invocation, NULL); else g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Pairing rejected"); return; } g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Pairing rejected"); } else if (g_strcmp0(method_name, "RequestConfirmation") == 0) { GError *error = NULL; Device *device_obj = device_new(g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL)); guint32 passkey = g_variant_get_uint32(g_variant_get_child_value(parameters, 1)); const gchar *pin = _find_device_pin(device_get_dbus_object_path(device_obj)); if (_interactive) g_print("Device: %s (%s)\n", device_get_alias(device_obj, &error), device_get_address(device_obj, &error)); if(error) { g_critical("Failed to get remote device's MAC address: %s", error->message); g_error_free(error); } g_object_unref(device_obj); /* Try to use found PIN */ if (pin != NULL) { guint32 passkey_t; sscanf(pin, "%u", &passkey_t); if (g_strcmp0(pin, "*") == 0 || passkey_t == passkey) { if (_interactive) g_print("Passkey confirmed\n"); g_dbus_method_invocation_return_value(invocation, NULL); } else g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Passkey does not match"); return; } else if (_interactive) { g_print("Confirm passkey: %u (yes/no)? ", passkey); gchar yn[4] = {0,}; errno = 0; if (scanf("%3s", yn) == EOF && errno) g_warning("%s\n", strerror(errno)); if(g_ascii_strcasecmp(yn, "yes") == 0 || g_ascii_strcasecmp(yn, "y") == 0) g_dbus_method_invocation_return_value(invocation, NULL); else g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Passkey does not match"); return; } g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "Passkey does not match"); } else if (g_strcmp0(method_name, "RequestPasskey") == 0) { GError *error = NULL; Device *device_obj = device_new(g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL)); const gchar *pin = _find_device_pin(device_get_dbus_object_path(device_obj)); guint32 ret = 0; if (_interactive) g_print("Device: %s (%s)\n", device_get_alias(device_obj, &error), device_get_address(device_obj, &error)); if(error) { g_critical("Failed to get remote device's MAC address: %s", error->message); g_error_free(error); } g_object_unref(device_obj); /* Try to use found PIN */ if (pin != NULL) { if (_interactive) g_print("Passkey found\n"); sscanf(pin, "%u", &ret); g_dbus_method_invocation_return_value(invocation, g_variant_new_uint32(ret)); return; } else if (_interactive) { g_print("Enter passkey: "); errno = 0; if (scanf("%u", &ret) == EOF && errno) g_warning("%s\n", strerror(errno)); g_dbus_method_invocation_return_value(invocation, g_variant_new_uint32(ret)); return; } g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "No passkey inputted"); } else if (g_strcmp0(method_name, "RequestPinCode") == 0) { GError *error = NULL; Device *device_obj = device_new(g_variant_get_string(g_variant_get_child_value(parameters, 0), NULL)); const gchar *pin = _find_device_pin(device_get_dbus_object_path(device_obj)); const gchar ret[16]; if (_interactive) g_print("Device: %s (%s)\n", device_get_alias(device_obj, &error), device_get_address(device_obj, &error)); if(error) { g_critical("Failed to get remote device's MAC address: %s", error->message); g_error_free(error); } g_object_unref(device_obj); /* Try to use found PIN */ if (pin != NULL) { if (_interactive) g_print("Passkey found\n"); sscanf(pin, "%s", &ret); g_dbus_method_invocation_return_value(invocation, g_variant_new_string(ret)); return; } else if (_interactive) { g_print("Enter passkey: "); errno = 0; if (scanf("%s", &ret) == EOF && errno) g_warning("%s\n", strerror(errno)); GVariant* vars[1]; vars[0] = g_variant_new_string(ret); g_dbus_method_invocation_return_value(invocation, g_variant_new_tuple(vars, 1)); return; } g_dbus_method_invocation_return_dbus_error(invocation, "org.bluez.Error.Rejected", "No passkey inputted"); } } static void _bt_agent_g_destroy_notify(gpointer data) { g_free(data); } static const gchar *_find_device_pin(const gchar *device_path) { if (_pin_hash_table) { GError *error = NULL; Device *device = device_new(device_path); const gchar *pin_by_addr = g_hash_table_lookup(_pin_hash_table, device_get_address(device, &error)); const gchar *pin_by_alias = g_hash_table_lookup(_pin_hash_table, device_get_alias(device, &error)); if(error) { g_critical("Failed to get remote device's MAC address: %s", error->message); g_error_free(error); } g_object_unref(device); const gchar *pin_all = g_hash_table_lookup(_pin_hash_table, "*"); if (pin_by_addr) return pin_by_addr; else if (pin_by_alias) return pin_by_alias; else if (pin_all) return pin_all; } return NULL; } void register_agent_callbacks(gboolean interactive_console, GHashTable *pin_dictonary, gpointer main_loop_object, GError **error) { GDBusInterfaceVTable bt_agent_table; memset(&bt_agent_table, 0x0, sizeof(bt_agent_table)); if(pin_dictonary) _pin_hash_table = pin_dictonary; if(main_loop_object) _mainloop = (GMainLoop *) main_loop_object; _interactive = interactive_console; GDBusNodeInfo *bt_agent_node_info = g_dbus_node_info_new_for_xml(_bt_agent_introspect_xml, error); GDBusInterfaceInfo *bt_agent_interface_info = g_dbus_node_info_lookup_interface(bt_agent_node_info, AGENT_DBUS_INTERFACE); bt_agent_table.method_call = _bt_agent_method_call_func; _bt_agent_registration_id = g_dbus_connection_register_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, error), AGENT_PATH, bt_agent_interface_info, &bt_agent_table, NULL, _bt_agent_g_destroy_notify, error); g_dbus_node_info_unref(bt_agent_node_info); } void unregister_agent_callbacks(GError **error) { if (_bt_agent_registration_id) g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, error), _bt_agent_registration_id); }