diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2006-10-22 18:02:59 +0000 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2006-10-22 18:02:59 +0000 |
commit | efeb7aac353c1c35be86275690f3f8272a91a7d7 (patch) | |
tree | ab9ef10f9d2cc18c52810d722c1eb23a052378eb /hcid/dbus-security.c | |
parent | c6e02b7f95315f1dafa3a6489ea5f2f558ec56cf (diff) |
Implement the confirmation method
Diffstat (limited to 'hcid/dbus-security.c')
-rw-r--r-- | hcid/dbus-security.c | 216 |
1 files changed, 201 insertions, 15 deletions
diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c index 57891afe..19fb3ad1 100644 --- a/hcid/dbus-security.c +++ b/hcid/dbus-security.c @@ -393,6 +393,19 @@ static struct service_data sec_services[] = { { NULL, NULL } }; +DBusHandlerResult handle_security_method(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + service_handler_func_t handler; + + handler = find_service_handler(sec_services, msg); + + if (handler) + return handler(conn, msg, data); + + return error_unknown_method(conn, msg); +} + static DBusPendingCall *agent_request(const char *path, bdaddr_t *bda, struct passkey_agent *agent, dbus_bool_t numeric, int old_if) @@ -423,7 +436,7 @@ static DBusPendingCall *agent_request(const char *path, bdaddr_t *bda, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(agent->conn, message, - &call, REQUEST_TIMEOUT) == FALSE) { + &call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); dbus_message_unref(message); return NULL; @@ -570,18 +583,6 @@ failed: return -1; } -DBusHandlerResult handle_security_method(DBusConnection *conn, DBusMessage *msg, void *data) -{ - service_handler_func_t handler; - - handler = find_service_handler(sec_services, msg); - - if (handler) - return handler(conn, msg, data); - - return error_unknown_method(conn, msg); -} - int handle_passkey_request(DBusConnection *conn, int dev, const char *path, bdaddr_t *sba, bdaddr_t *dba) { @@ -617,14 +618,197 @@ done: return call_passkey_agent(conn, agent, dev, path, sba, dba); } -int handle_confirm_request(DBusConnection *conn, int dev, const char *path, - bdaddr_t *sba, bdaddr_t *dba, const char *pin) +static DBusPendingCall *agent_confirm(const char *path, bdaddr_t *bda, + struct passkey_agent *agent, + const char *value) +{ + DBusMessage *message; + DBusPendingCall *call; + char bda_str[18], *ptr = bda_str; + + message = dbus_message_new_method_call(agent->name, agent->path, + "org.bluez.PasskeyAgent", "Confirm"); + if (message == NULL) { + error("Couldn't allocate D-Bus message"); + return NULL; + } + + ba2str(bda, bda_str); + + dbus_message_append_args(message, + DBUS_TYPE_STRING, &path, + DBUS_TYPE_STRING, &ptr, + DBUS_TYPE_STRING, &value, + DBUS_TYPE_INVALID); + + if (dbus_connection_send_with_reply(agent->conn, message, + &call, REQUEST_TIMEOUT) == FALSE) { + error("D-Bus send failed"); + dbus_message_unref(message); + return NULL; + } + + return call; +} + +static void confirm_agent_reply(DBusPendingCall *call, void *user_data) { + struct pending_agent_request *req = user_data; + struct passkey_agent *agent = req->agent; + pin_code_reply_cp pr; + DBusMessage *message; + DBusError err; + dbus_bool_t result; + int len; + + /* steal_reply will always return non-NULL since the callback + * is only called after a reply has been received */ + message = dbus_pending_call_steal_reply(call); + + dbus_error_init(&err); + if (dbus_set_error_from_message(&err, message)) { + + error("Passkey agent replied with an error: %s, %s", + err.name, err.message); + + dbus_error_free(&err); + goto fail; + } + + dbus_error_init(&err); + if (!dbus_message_get_args(message, &err, + DBUS_TYPE_BOOLEAN, &result, + DBUS_TYPE_INVALID)) { + error("Wrong passkey reply signature: %s", err.message); + dbus_error_free(&err); + goto fail; + } + + len = strlen(req->pin); + + set_pin_length(&req->sba, len); + + memset(&pr, 0, sizeof(pr)); + bacpy(&pr.bdaddr, &req->bda); + memcpy(pr.pin_code, req->pin, len); + pr.pin_len = len; + hci_send_cmd(req->dev, OGF_LINK_CTL, + OCF_PIN_CODE_REPLY, PIN_CODE_REPLY_CP_SIZE, &pr); + + goto done; + +fail: + hci_send_cmd(req->dev, OGF_LINK_CTL, + OCF_PIN_CODE_NEG_REPLY, 6, &req->bda); + +done: + if (message) + dbus_message_unref(message); + + agent->pending_requests = slist_remove(agent->pending_requests, req); + dbus_pending_call_cancel(req->call); + if (req->call) + dbus_pending_call_unref(req->call); + if (req->pin) + free(req->pin); + free(req->path); + free(req); + + if (agent != default_agent) { + agent->adapter->passkey_agents = slist_remove(agent->adapter->passkey_agents, + agent); + passkey_agent_free(agent); + } +} + +static int call_confirm_agent(DBusConnection *conn, + struct passkey_agent *agent, int dev, + const char *path, bdaddr_t *sba, + bdaddr_t *dba, const char *pin) +{ + struct pending_agent_request *req = NULL; + + if (!agent) { + debug("call_passkey_agent(): no agent available"); + goto failed; + } + + debug("Calling PasskeyAgent.Confirm: name=%s, path=%s", + agent->name, agent->path); + + req = malloc(sizeof(struct pending_agent_request)); + if (!req) + goto failed; + memset(req, 0, sizeof(struct pending_agent_request)); + req->dev = dev; + bacpy(&req->sba, sba); + bacpy(&req->bda, dba); + req->agent = agent; + req->path = strdup(path); + if (!req->path) + goto failed; + req->pin = strdup(pin); + if (!req->pin) + goto failed; + + req->call = agent_confirm(path, dba, agent, pin); + if (!req->call) + goto failed; + + dbus_pending_call_set_notify(req->call, confirm_agent_reply, req, NULL); + + agent->pending_requests = slist_append(agent->pending_requests, req); + + return 0; + +failed: + if (req) { + if (req->pin) + free(req->pin); + free(req->path); + free(req); + } + hci_send_cmd(dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba); return -1; } +int handle_confirm_request(DBusConnection *conn, int dev, const char *path, + bdaddr_t *sba, bdaddr_t *dba, const char *pin) +{ + struct passkey_agent *agent = default_agent; + struct adapter *adapter = NULL; + struct slist *l; + char addr[18]; + void *data; + + dbus_connection_get_object_path_data(conn, path, &data); + + if (!data) + goto done; + + adapter = data; + + if (!bacmp(&adapter->agents_disabled, dba)) + goto done; + + ba2str(dba, addr); + + for (l = adapter->passkey_agents; l != NULL; l = l->next) { + struct passkey_agent *a = l->data; + if (a != default_agent && slist_length(a->pending_requests) >= 1) + continue; + if (!strcmp(a->addr, addr)) { + agent = a; + break; + } + } + +done: + return call_confirm_agent(conn, agent, dev, path, sba, dba, pin); +} + static void send_cancel_request(struct pending_agent_request *req) { DBusMessage *message; @@ -652,6 +836,8 @@ static void send_cancel_request(struct pending_agent_request *req) dbus_pending_call_cancel(req->call); dbus_pending_call_unref(req->call); + if (req->pin) + free(req->pin); free(req->path); free(req); } |