diff options
Diffstat (limited to 'hcid')
-rw-r--r-- | hcid/dbus-security.c | 221 | ||||
-rw-r--r-- | hcid/dbus.c | 2 | ||||
-rw-r--r-- | hcid/dbus.h | 6 |
3 files changed, 197 insertions, 32 deletions
diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c index f3113d14..7fe9e313 100644 --- a/hcid/dbus-security.c +++ b/hcid/dbus-security.c @@ -65,6 +65,165 @@ static void default_agent_exited(const char *name, void *data) default_agent = NULL; } +static void passkey_agent_free(struct passkey_agent *agent) +{ + if (!agent) + return; + if (agent->name) + free(agent->name); + if (agent->path) + free(agent->path); + if (agent->addr) + free(agent->addr); + free(agent); +} + +static struct passkey_agent *passkey_agent_new(const char *name, + const char *path, const char *addr) +{ + struct passkey_agent *agent; + + agent = malloc(sizeof(struct passkey_agent)); + if (!agent) + return NULL; + + memset(agent, 0, sizeof(struct passkey_agent)); + + agent->name = strdup(name); + if (!agent->name) + goto mem_fail; + + agent->path = strdup(path); + if (!agent->path) + goto mem_fail; + + if (addr) { + agent->addr = strdup(addr); + if (!agent->addr) + goto mem_fail; + } + + return agent; + +mem_fail: + passkey_agent_free(agent); + return NULL; +} + +static int agent_cmp(const struct passkey_agent *a, const struct passkey_agent *b) +{ + int ret; + + if (b->name) { + if (!a->name) + return -1; + ret = strcmp(a->name, b->name); + if (ret) + return ret; + } + + if (b->path) { + if (!a->path) + return -1; + ret = strcmp(a->path, b->path); + if (ret) + return ret; + } + + if (b->addr) { + if (!a->addr) + return -1; + ret = strcmp(a->addr, b->addr); + if (ret) + return ret; + } + + return 0; +} + +static DBusHandlerResult register_agent(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + char *path, *addr; + struct passkey_agent *agent, ref; + struct hci_dbus_data *adapter; + DBusMessage *reply; + + if (!data) { + error("register_agent called without any adapter info!"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + adapter = data; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &addr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + ref.name = (char *)dbus_message_get_sender(msg); + ref.addr = addr; + ref.path = path; + + if (slist_find(adapter->passkey_agents, &ref, (cmp_func_t)agent_cmp)) + return error_passkey_agent_already_exists(conn, msg); + + agent = passkey_agent_new(ref.name, path, addr); + if (!agent) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + reply = dbus_message_new_method_return(msg); + if (!reply) { + passkey_agent_free(agent); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + adapter->passkey_agents = slist_append(adapter->passkey_agents, agent); + + return send_reply_and_unref(conn, reply); +} + +static DBusHandlerResult unregister_agent(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + char *path, *addr; + struct hci_dbus_data *adapter; + struct slist *match; + struct passkey_agent ref; + DBusMessage *reply; + + if (!data) { + error("uregister_agent called without any adapter info!"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + adapter = data; + + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &addr, + DBUS_TYPE_INVALID)) + return error_invalid_arguments(conn, msg); + + ref.name = (char *)dbus_message_get_sender(msg); + ref.path = path; + ref.addr = addr; + + match = slist_find(adapter->passkey_agents, &ref, (cmp_func_t)agent_cmp); + if (!match) + return error_passkey_agent_does_not_exist(conn, msg); + + adapter->passkey_agents = slist_remove(adapter->passkey_agents, match->data); + passkey_agent_free(match->data); + + reply = dbus_message_new_method_return(msg); + if (!reply) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return send_reply_and_unref(conn, reply); +} + static DBusHandlerResult register_default_agent(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -79,20 +238,10 @@ static DBusHandlerResult register_default_agent(DBusConnection *conn, DBUS_TYPE_INVALID)) return error_invalid_arguments(conn, msg); - default_agent = malloc(sizeof(struct passkey_agent)); + default_agent = passkey_agent_new(dbus_message_get_sender(msg), path, NULL); if (!default_agent) goto need_memory; - memset(default_agent, 0, sizeof(struct passkey_agent)); - - default_agent->name = strdup(dbus_message_get_sender(msg)); - if (!default_agent->name) - goto need_memory; - - default_agent->path = strdup(path); - if (!default_agent->path) - goto need_memory; - reply = dbus_message_new_method_return(msg); if (!reply) goto need_memory; @@ -103,18 +252,11 @@ static DBusHandlerResult register_default_agent(DBusConnection *conn, info("Default passkey agent (%s, %s) registered", default_agent->name, default_agent->path); - dbus_connection_send(conn, reply, NULL); - dbus_message_unref(reply); - - return DBUS_HANDLER_RESULT_HANDLED; + return send_reply_and_unref(conn, reply); need_memory: if (default_agent) { - if (default_agent->name) - free(default_agent->name); - if (default_agent->path) - free(default_agent->path); - free(default_agent); + passkey_agent_free(default_agent); default_agent = NULL; } @@ -151,20 +293,17 @@ static DBusHandlerResult unregister_default_agent(DBusConnection *conn, info("Default passkey agent (%s, %s) unregistered", default_agent->name, default_agent->path); - free(default_agent->path); - free(default_agent->name); - free(default_agent); + passkey_agent_free(default_agent); default_agent = NULL; - dbus_connection_send(conn, reply, NULL); - dbus_message_unref(reply); - - return DBUS_HANDLER_RESULT_HANDLED; + return send_reply_and_unref(conn, reply); } static struct service_data sec_services[] = { { "RegisterDefaultPasskeyAgent", register_default_agent }, { "UnregisterDefaultPasskeyAgent", unregister_default_agent }, + { "RegisterPasskeyAgent", register_agent }, + { "UnregisterPasskeyAgent", unregister_agent }, { NULL, NULL } }; @@ -299,7 +438,31 @@ DBusHandlerResult handle_security_method(DBusConnection *conn, DBusMessage *msg, return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -int call_default_passkey_agent(int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba) +int handle_passkey_request(int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba) { - return call_passkey_agent(default_agent, dev, path, sba, dba); + struct passkey_agent *agent = default_agent; + struct hci_dbus_data *adapter = NULL; + struct slist *l; + char addr[18]; + void *data; + + dbus_connection_get_object_path_data(get_dbus_connection(), path, &data); + + if (!data) + goto done; + + adapter = data; + + ba2str(dba, addr); + + for (l = adapter->passkey_agents; l != NULL; l = l->next) { + struct passkey_agent *a = l->data; + if (!strcmp(a->addr, addr)) { + agent = a; + break; + } + } + +done: + return call_passkey_agent(agent, dev, path, sba, dba); } diff --git a/hcid/dbus.c b/hcid/dbus.c index 4efc7457..9341200e 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -433,7 +433,7 @@ void hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci) snprintf(path, sizeof(path), "%s/hci%d", ADAPTER_PATH, hci_devid(addr)); - call_default_passkey_agent(dev, path, sba, &ci->bdaddr); + handle_passkey_request(dev, path, sba, &ci->bdaddr); } void hcid_dbus_bonding_created_complete(bdaddr_t *local, bdaddr_t *peer, const uint8_t status) diff --git a/hcid/dbus.h b/hcid/dbus.h index 14011fa4..beb9accc 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -27,6 +27,7 @@ #include <stdint.h> #include <dbus/dbus.h> #include <bluetooth/bluetooth.h> +#include "list.h" #define BASE_PATH "/org/bluez" #define BASE_INTERFACE "org.bluez" @@ -76,9 +77,10 @@ struct hci_dbus_data { uint32_t timeout_hits; timeout_handler_func_t *timeout_handler; uint8_t mode; /* scan mode */ - uint8_t resolve_name; /* send name on discover process */ + int resolve_name; /* send name on discover process */ struct slist *discovered_devices; char *requestor_name; /* requestor unique name */ + struct slist *passkey_agents; }; struct passkey_agent { @@ -130,7 +132,7 @@ DBusHandlerResult handle_security_method(DBusConnection *conn, DBusMessage *msg, service_handler_func_t find_service_handler(struct service_data *services, DBusMessage *msg); -int call_default_passkey_agent(int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba); +int handle_passkey_request(int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba); static inline DBusHandlerResult send_reply_and_unref(DBusConnection *conn, DBusMessage *reply) { |