summaryrefslogtreecommitdiffstats
path: root/hcid
diff options
context:
space:
mode:
authorUlisses Furquim <ulissesf@gmail.com>2006-11-01 17:15:06 +0000
committerUlisses Furquim <ulissesf@gmail.com>2006-11-01 17:15:06 +0000
commit5a9f38e575f61697083f72b593adc814d0229590 (patch)
tree75d83d845de72b06aad38619cec32c4aa5e9cc5a /hcid
parent66335427fb76c0f43b69cd77e74f0664b1119c04 (diff)
Add authorization part of the new Authorization API
Diffstat (limited to 'hcid')
-rw-r--r--hcid/dbus-security.c462
-rw-r--r--hcid/dbus-security.h12
2 files changed, 371 insertions, 103 deletions
diff --git a/hcid/dbus-security.c b/hcid/dbus-security.c
index 4d39e2f6..b15885b3 100644
--- a/hcid/dbus-security.c
+++ b/hcid/dbus-security.c
@@ -51,7 +51,6 @@ static struct passkey_agent *default_agent = NULL;
static struct authorization_agent *default_auth_agent = NULL;
static void release_agent(struct passkey_agent *agent);
-static void release_auth_agent(struct authorization_agent *agent);
static void send_cancel_request(struct pending_agent_request *req);
static void passkey_agent_free(struct passkey_agent *agent)
@@ -213,91 +212,6 @@ static int agent_cmp(const struct passkey_agent *a, const struct passkey_agent *
return 0;
}
-static void auth_agent_free(struct authorization_agent *agent)
-{
- /* FIXME: cancel all requests */
-
- if (!agent->exited)
- release_auth_agent(agent);
-
- if (agent->name)
- free(agent->name);
- if (agent->path)
- free(agent->path);
- if (agent->conn)
- dbus_connection_unref(agent->conn);
-
- free(agent);
-}
-
-static struct authorization_agent *auth_agent_new(DBusConnection *conn,
- const char *name,
- const char *path)
-{
- struct authorization_agent *agent;
-
- agent = malloc(sizeof(*agent));
- if (!agent)
- return NULL;
- memset(agent, 0, sizeof(*agent));
-
- agent->name = strdup(name);
- if (!agent->name)
- goto mem_fail;
-
- agent->path = strdup(path);
- if (!agent->path)
- goto mem_fail;
-
- agent->conn = dbus_connection_ref(conn);
-
- return agent;
-
-mem_fail:
- agent->exited = 1;
- auth_agent_free(agent);
- return NULL;
-}
-
-static void default_auth_agent_exited(const char *name, void *data)
-{
- debug("%s exited without unregistering the "
- "default authorization agent", name);
-
- if (!default_auth_agent || strcmp(name, default_auth_agent->name)) {
- /* This should never happen! */
- debug("default_auth_agent_exited: mismatch with "
- "actual default_auth_agent");
- return;
- }
-
- default_auth_agent->exited = 1;
- auth_agent_free(default_auth_agent);
- default_auth_agent = NULL;
-}
-
-static void release_auth_agent(struct authorization_agent *agent)
-{
- DBusMessage *message;
-
- debug("Releasing authorization agent %s, %s",
- agent->name, agent->path);
-
- message = dbus_message_new_method_call(agent->name, agent->path,
- "org.bluez.AuthorizationAgent", "Release");
- if (!message) {
- error("Couldn't allocate D-Bus message");
- return;
- }
-
- dbus_message_set_no_reply(message, TRUE);
- send_message_and_unref(agent->conn, message);
-
- if (agent == default_auth_agent)
- name_listener_remove(agent->conn, agent->name,
- (name_cb_t) default_auth_agent_exited, NULL);
-}
-
static DBusHandlerResult register_passkey_agent(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -477,6 +391,185 @@ static DBusHandlerResult unregister_default_passkey_agent(DBusConnection *conn,
return send_message_and_unref(conn, reply);
}
+static struct pend_auth_agent_req *pend_auth_agent_req_new(DBusMessage *msg,
+ struct authorization_agent *agent,
+ const char *adapter_path,
+ const char *address,
+ const char *service_path,
+ const char *action)
+{
+ struct pend_auth_agent_req *req;
+
+ req = malloc(sizeof(*req));
+ if (!req)
+ return NULL;
+ memset(req, 0, sizeof(*req));
+
+ req->adapter_path = strdup(adapter_path);
+ if (!req->adapter_path)
+ goto failed;
+
+ req->address = strdup(address);
+ if (!req->address)
+ goto failed;
+
+ req->service_path = strdup(service_path);
+ if (!req->service_path)
+ goto failed;
+
+ req->action = strdup(action);
+ if (!req->action)
+ goto failed;
+
+ req->agent = agent;
+ req->msg = dbus_message_ref(msg);
+
+ return req;
+
+failed:
+ if (req->adapter_path)
+ free(req->adapter_path);
+ if (req->address)
+ free(req->address);
+ if (req->service_path)
+ free(req->service_path);
+ free(req);
+
+ return NULL;
+}
+
+static void pend_auth_agent_req_free(struct pend_auth_agent_req *req)
+{
+ dbus_message_unref(req->msg);
+ free(req->adapter_path);
+ free(req->address);
+ free(req->service_path);
+ free(req->action);
+ if (req->call)
+ dbus_pending_call_unref(req->call);
+ free(req);
+}
+
+static void pend_auth_agent_req_cancel(struct pend_auth_agent_req *req)
+{
+ dbus_pending_call_cancel(req->call);
+ error_canceled(req->agent->conn, req->msg,
+ "Authorization process was canceled");
+}
+
+static void auth_agent_cancel_requests(struct authorization_agent *agent)
+{
+ struct slist *l;
+
+ for (l = agent->pending_requests; l != NULL; l = l->next) {
+ struct pend_auth_agent_req *req = l->data;
+ pend_auth_agent_req_cancel(req);
+ pend_auth_agent_req_free(req);
+ }
+}
+
+static void auth_agent_call_cancel(struct pend_auth_agent_req *req)
+{
+ struct authorization_agent *agent = req->agent;
+ DBusMessage *message;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.AuthorizationAgent", "Cancel");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &req->adapter_path,
+ DBUS_TYPE_STRING, &req->address,
+ DBUS_TYPE_STRING, &req->service_path,
+ DBUS_TYPE_STRING, &req->action,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_set_no_reply(message, TRUE);
+ send_message_and_unref(agent->conn, message);
+}
+
+static void auth_agent_free(struct authorization_agent *agent)
+{
+ free(agent->name);
+ free(agent->path);
+ dbus_connection_unref(agent->conn);
+ slist_free(agent->pending_requests);
+ free(agent);
+}
+
+static struct authorization_agent *auth_agent_new(DBusConnection *conn,
+ const char *name,
+ const char *path)
+{
+ struct authorization_agent *agent;
+
+ agent = malloc(sizeof(*agent));
+ if (!agent)
+ return NULL;
+ memset(agent, 0, sizeof(*agent));
+
+ agent->name = strdup(name);
+ if (!agent->name)
+ goto failed;
+
+ agent->path = strdup(path);
+ if (!agent->path)
+ goto failed;
+
+ agent->conn = dbus_connection_ref(conn);
+
+ return agent;
+
+failed:
+ if (agent->name)
+ free(agent->name);
+ free(agent);
+
+ return NULL;
+}
+
+static void default_auth_agent_exited(const char *name, void *data)
+{
+ debug("%s exited without unregistering the "
+ "default authorization agent", name);
+
+ if (!default_auth_agent || strcmp(name, default_auth_agent->name)) {
+ /* This should never happen! */
+ debug("default_auth_agent_exited: mismatch with "
+ "actual default_auth_agent");
+ return;
+ }
+
+ auth_agent_cancel_requests(default_auth_agent);
+ auth_agent_free(default_auth_agent);
+ default_auth_agent = NULL;
+}
+
+static void auth_agent_release(struct authorization_agent *agent)
+{
+ DBusMessage *message;
+
+ debug("Releasing authorization agent %s, %s",
+ agent->name, agent->path);
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.AuthorizationAgent", "Release");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return;
+ }
+
+ dbus_message_set_no_reply(message, TRUE);
+ send_message_and_unref(agent->conn, message);
+
+ if (agent == default_auth_agent)
+ name_listener_remove(agent->conn, agent->name,
+ (name_cb_t) default_auth_agent_exited, NULL);
+}
+
static DBusHandlerResult register_default_auth_agent(DBusConnection *conn,
DBusMessage *msg,
void *data)
@@ -511,7 +604,6 @@ static DBusHandlerResult register_default_auth_agent(DBusConnection *conn,
need_memory:
if (default_auth_agent) {
- default_auth_agent->exited = 1;
auth_agent_free(default_auth_agent);
default_auth_agent = NULL;
}
@@ -550,44 +642,207 @@ static DBusHandlerResult unregister_default_auth_agent(DBusConnection *conn,
info("Default authorization agent (%s, %s) unregistered",
default_auth_agent->name, default_auth_agent->path);
- default_auth_agent->exited = 1;
+ auth_agent_cancel_requests(default_auth_agent);
auth_agent_free(default_auth_agent);
default_auth_agent = NULL;
return send_message_and_unref(conn, reply);
}
+static void auth_agent_req_reply(DBusPendingCall *call, void *data)
+{
+ struct pend_auth_agent_req *req = data;
+ struct authorization_agent *agent = req->agent;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusMessage *message;
+ DBusError err;
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, reply)) {
+ error("Authorization agent replied with an error: %s, %s",
+ err.name, err.message);
+ dbus_error_free(&err);
+ goto reject;
+ }
+
+ dbus_error_init(&err);
+ if (!dbus_message_get_args(reply, &err, DBUS_TYPE_INVALID)) {
+ error("Wrong authorization agent reply signature: %s",
+ err.message);
+ dbus_error_free(&err);
+ goto reject;
+ }
+
+ message = dbus_message_new_method_return(req->msg);
+ if (!message)
+ goto reject;
+
+ send_message_and_unref(agent->conn, message);
+
+ goto done;
+
+reject:
+ error_rejected(agent->conn, req->msg);
+
+done:
+ dbus_message_unref(reply);
+
+ agent->pending_requests = slist_remove(agent->pending_requests, req);
+
+ pend_auth_agent_req_free(req);
+}
+
+static DBusPendingCall *auth_agent_call_authorize(struct authorization_agent *agent,
+ const char *adapter_path,
+ const char *address,
+ const char *service_path,
+ const char *action)
+{
+ DBusMessage *message;
+ DBusPendingCall *call;
+
+ message = dbus_message_new_method_call(agent->name, agent->path,
+ "org.bluez.AuthorizationAgent", "Authorize");
+ if (!message) {
+ error("Couldn't allocate D-Bus message");
+ return NULL;
+ }
+
+ dbus_message_append_args(message,
+ DBUS_TYPE_STRING, &adapter_path,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &service_path,
+ DBUS_TYPE_STRING, &action,
+ 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 DBusHandlerResult call_auth_agent(DBusMessage *msg,
+ struct authorization_agent *agent,
+ const char *adapter_path,
+ const char *address,
+ const char *service_path,
+ const char *action)
+{
+ struct pend_auth_agent_req *req;
+
+ req = pend_auth_agent_req_new(msg, agent, adapter_path,
+ address, service_path, action);
+ if (!req)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ req->call = auth_agent_call_authorize(agent, adapter_path, address,
+ service_path, action);
+ if (!req->call) {
+ pend_auth_agent_req_free(req);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ dbus_pending_call_set_notify(req->call,
+ auth_agent_req_reply, req, NULL);
+ agent->pending_requests = slist_append(agent->pending_requests, req);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
static DBusHandlerResult authorize_service(DBusConnection *conn,
DBusMessage *msg, void *data)
{
+ const char *service_path, *adapter_path, *address, *action;
struct service_agent *sagent;
- const char *service, *address, *action;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_STRING, &service_path,
DBUS_TYPE_STRING, &address,
DBUS_TYPE_STRING, &action,
DBUS_TYPE_INVALID))
- return error_invalid_arguments(conn, msg);
+ return error_rejected(conn, msg);
- if (!dbus_connection_get_object_path_data(conn, service, (void*) &sagent))
- return error_not_authorized(conn, msg);
+ adapter_path = dbus_message_get_path(msg);
+ if (!strcmp(adapter_path, BASE_PATH))
+ return error_rejected(conn, msg);
- /* Check if the connection id match */
- if (strcmp(dbus_message_get_sender(msg), sagent->id))
- return error_not_authorized(conn, msg);
+ if (!dbus_connection_get_object_path_data(conn, service_path,
+ (void *) &sagent))
+ return error_rejected(conn, msg);
- /* FIXME: Forward to the default authentication agent */
+ if (strcmp(dbus_message_get_sender(msg), sagent->id))
+ return error_rejected(conn, msg);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return call_auth_agent(msg, default_auth_agent, adapter_path,
+ address, service_path, action);
}
-static DBusHandlerResult cancel_service_authorization(DBusConnection *conn,
- DBusMessage *msg, void *data)
+static DBusHandlerResult auth_agent_send_cancel(DBusMessage *msg,
+ struct authorization_agent *agent,
+ const char *adapter_path,
+ const char *address,
+ const char *service_path,
+ const char *action)
{
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ struct pend_auth_agent_req *req = NULL;
+ DBusMessage *message;
+ struct slist *l;
+
+ for (l = agent->pending_requests; l != NULL; l = l->next) {
+ req = l->data;
+ if (!strcmp(adapter_path, req->adapter_path) &&
+ !strcmp(address, req->address) &&
+ !strcmp(service_path, req->service_path) &&
+ !strcmp(action, req->action))
+ break;
+ }
+
+ if (!req)
+ return error_does_not_exist(agent->conn, msg,
+ "No such authorization process");
+
+ message = dbus_message_new_method_return(msg);
+ if (!message)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ auth_agent_call_cancel(req);
+ pend_auth_agent_req_cancel(req);
+ pend_auth_agent_req_free(req);
+
+ return send_message_and_unref(agent->conn, message);
}
+static DBusHandlerResult cancel_authorization_process(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *service_path, *adapter_path, *address, *action;
+ struct service_agent *sagent;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &service_path,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &action,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
+
+ adapter_path = dbus_message_get_path(msg);
+ if (!strcmp(adapter_path, BASE_PATH))
+ return error_no_such_adapter(conn, msg);
+
+ if (!dbus_connection_get_object_path_data(conn, service_path,
+ (void *) &sagent))
+ return error_not_authorized(conn, msg);
+
+ if (strcmp(dbus_message_get_sender(msg), sagent->id))
+ return error_not_authorized(conn, msg);
+
+ return auth_agent_send_cancel(msg, default_auth_agent, adapter_path,
+ address, service_path, action);
+}
static struct service_data sec_services[] = {
{ "RegisterDefaultPasskeyAgent", register_default_passkey_agent },
@@ -597,7 +852,7 @@ static struct service_data sec_services[] = {
{ "RegisterDefaultAuthorizationAgent", register_default_auth_agent },
{ "UnregisterDefaultAuthorizationAgent", unregister_default_auth_agent },
{ "AuthorizeService", authorize_service },
- { "CancelAuthorizationProcess", cancel_service_authorization },
+ { "CancelAuthorizationProcess", cancel_authorization_process },
{ NULL, NULL }
};
@@ -1093,6 +1348,9 @@ void release_default_auth_agent(void)
if (!default_auth_agent)
return;
+ auth_agent_cancel_requests(default_auth_agent);
+ auth_agent_release(default_auth_agent);
+
auth_agent_free(default_auth_agent);
default_auth_agent = NULL;
}
diff --git a/hcid/dbus-security.h b/hcid/dbus-security.h
index 5b849374..2096437a 100644
--- a/hcid/dbus-security.h
+++ b/hcid/dbus-security.h
@@ -52,7 +52,17 @@ struct authorization_agent {
DBusConnection *conn;
char *name;
char *path;
- int exited;
+ struct slist *pending_requests;
+};
+
+struct pend_auth_agent_req {
+ DBusMessage *msg;
+ struct authorization_agent *agent;
+ char *adapter_path;
+ char *address;
+ char *service_path;
+ char *action;
+ DBusPendingCall *call;
};
DBusHandlerResult handle_security_method(DBusConnection *conn, DBusMessage *msg, void *data);