📄 dbus-security.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg@nokia.com> * * * 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 <config.h>#endif#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/sdp.h>#include <glib.h>#include <dbus/dbus.h>#include "adapter.h"#include "dbus.h"#include "dbus-helper.h"#include "hcid.h"#include "dbus-common.h"#include "dbus-service.h"#include "dbus-error.h"#include "error.h"#include "dbus-security.h"#include "dbus-hci.h"#define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */#define AGENT_TIMEOUT (10 * 60 * 1000) /* 10 minutes */struct passkey_agent { struct adapter *adapter; DBusConnection *conn; char *addr; char *name; char *path; GSList *pending_requests; int exited; guint timeout;};struct pending_agent_request { struct passkey_agent *agent; int dev; bdaddr_t sba; bdaddr_t bda; char *path; DBusPendingCall *call; int old_if; char *pin;};struct authorization_agent { DBusConnection *conn; char *name; char *path; GSList *pending_requests;};struct auth_agent_req { DBusMessage *msg; struct authorization_agent *agent; char *adapter_path; char *address; char *service_path; char *uuid; DBusPendingCall *call;};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 send_cancel_request(struct pending_agent_request *req);static void passkey_agent_free(struct passkey_agent *agent){ GSList *l; if (!agent) return; for (l = agent->pending_requests; l != NULL; l = l->next) { struct pending_agent_request *req = l->data; hci_send_cmd(req->dev, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, &req->bda); send_cancel_request(req); } if (agent->timeout) g_source_remove(agent->timeout); if (!agent->exited) release_agent(agent); g_free(agent->name); g_free(agent->path); g_free(agent->addr); if (agent->conn) dbus_connection_unref(agent->conn); g_slist_free(agent->pending_requests); g_free(agent);}static void agent_exited(const char *name, struct adapter *adapter){ GSList *cur, *next; debug("Passkey agent %s exited without calling Unregister", name); for (cur = adapter->passkey_agents; cur != NULL; cur = next) { struct passkey_agent *agent = cur->data; next = cur->next; if (strcmp(agent->name, name)) continue; agent->exited = 1; adapter->passkey_agents = g_slist_remove(adapter->passkey_agents, agent); passkey_agent_free(agent); }}static gboolean agent_timeout(struct passkey_agent *agent){ struct adapter *adapter = agent->adapter; debug("Passkey Agent at %s, %s timed out", agent->name, agent->path); if (adapter) adapter->passkey_agents = g_slist_remove(adapter->passkey_agents, agent); agent->timeout = 0; passkey_agent_free(agent); return FALSE;}static void default_agent_exited(const char *name, void *data){ debug("%s exited without unregistering the default passkey agent", name); if (!default_agent || strcmp(name, default_agent->name)) { /* This should never happen (there's a bug in the code if it does) */ debug("default_agent_exited: mismatch with actual default_agent"); return; } default_agent->exited = 1; passkey_agent_free(default_agent); default_agent = NULL;}static struct passkey_agent *passkey_agent_new(struct adapter *adapter, DBusConnection *conn, const char *name, const char *path, const char *addr){ struct passkey_agent *agent; agent = g_new0(struct passkey_agent, 1); agent->adapter = adapter; agent->name = g_strdup(name); agent->path = g_strdup(path); if (addr) agent->addr = g_strdup(addr); agent->conn = dbus_connection_ref(conn); return agent;}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_passkey_agent(DBusConnection *conn, DBusMessage *msg, void *data){ struct passkey_agent *agent, ref; struct adapter *adapter; DBusMessage *reply; const char *path, *addr; if (!data) { error("register_passkey_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, NULL); if ((check_address(addr) < 0) || (path[0] != '/')) return error_invalid_arguments(conn, msg, NULL); memset(&ref, 0, sizeof(ref)); ref.name = (char *) dbus_message_get_sender(msg); ref.addr = (char *) addr; ref.path = (char *) path; if (g_slist_find_custom(adapter->passkey_agents, &ref, (GCompareFunc) agent_cmp)) return error_passkey_agent_already_exists(conn, msg); agent = passkey_agent_new(adapter, conn, ref.name, path, addr); if (!agent) return DBUS_HANDLER_RESULT_NEED_MEMORY; reply = dbus_message_new_method_return(msg); if (!reply) { agent->exited = 1; passkey_agent_free(agent); return DBUS_HANDLER_RESULT_NEED_MEMORY; } /* Only add a name listener if there isn't one already for this name */ ref.addr = NULL; ref.path = NULL; if (!g_slist_find_custom(adapter->passkey_agents, &ref, (GCompareFunc) agent_cmp)) name_listener_add(conn, ref.name, (name_cb_t) agent_exited, adapter); agent->timeout = g_timeout_add(AGENT_TIMEOUT, (GSourceFunc)agent_timeout, agent); adapter->passkey_agents = g_slist_append(adapter->passkey_agents, agent); return send_message_and_unref(conn, reply);}static DBusHandlerResult unregister_passkey_agent(DBusConnection *conn, DBusMessage *msg, void *data){ struct adapter *adapter; GSList *match; struct passkey_agent ref, *agent; DBusMessage *reply; const char *path, *addr; if (!data) { error("unregister_passkey_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, NULL); memset(&ref, 0, sizeof(ref)); ref.name = (char *) dbus_message_get_sender(msg); ref.path = (char *) path; ref.addr = (char *) addr; match = g_slist_find_custom(adapter->passkey_agents, &ref, (GCompareFunc) agent_cmp); if (!match) return error_passkey_agent_does_not_exist(conn, msg); agent = match->data; name_listener_remove(agent->conn, agent->name, (name_cb_t) agent_exited, adapter); adapter->passkey_agents = g_slist_remove(adapter->passkey_agents, agent); agent->exited = 1; passkey_agent_free(agent); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; return send_message_and_unref(conn, reply);}static DBusHandlerResult register_default_passkey_agent(DBusConnection *conn, DBusMessage *msg, void *data){ DBusMessage *reply; const char *path; if (default_agent) return error_passkey_agent_already_exists(conn, msg); if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID)) return error_invalid_arguments(conn, msg, NULL); default_agent = passkey_agent_new(NULL, conn, dbus_message_get_sender(msg), path, NULL); if (!default_agent) goto need_memory; reply = dbus_message_new_method_return(msg); if (!reply) goto need_memory; name_listener_add(conn, default_agent->name, (name_cb_t) default_agent_exited, NULL); info("Default passkey agent (%s, %s) registered", default_agent->name, default_agent->path); return send_message_and_unref(conn, reply);need_memory: if (default_agent) { default_agent->exited = 1; passkey_agent_free(default_agent); default_agent = NULL; } return DBUS_HANDLER_RESULT_NEED_MEMORY;}static DBusHandlerResult unregister_default_passkey_agent(DBusConnection *conn, DBusMessage *msg, void *data){ DBusMessage *reply; const char *path, *name; if (!default_agent) return error_passkey_agent_does_not_exist(conn, msg); if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID)) return error_invalid_arguments(conn, msg, NULL); name = dbus_message_get_sender(msg); if (strcmp(name, default_agent->name) || strcmp(path, default_agent->path)) return error_passkey_agent_does_not_exist(conn, msg); reply = dbus_message_new_method_return(msg); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; name_listener_remove(conn, default_agent->name, (name_cb_t) default_agent_exited, NULL); info("Default passkey agent (%s, %s) unregistered", default_agent->name, default_agent->path); default_agent->exited = 1; passkey_agent_free(default_agent); default_agent = NULL; return send_message_and_unref(conn, reply);}static struct auth_agent_req *auth_agent_req_new(DBusMessage *msg, struct authorization_agent *agent, const char *adapter_path, const char *address, const char *service_path, const char *uuid){ struct auth_agent_req *req; req = g_new0(struct auth_agent_req, 1); req->agent = agent; req->msg = dbus_message_ref(msg); req->adapter_path = g_strdup(adapter_path); req->address = g_strdup(address); req->service_path = g_strdup(service_path); req->uuid = g_strdup(uuid); return req;}static void auth_agent_req_free(struct auth_agent_req *req){ dbus_message_unref(req->msg); g_free(req->adapter_path); g_free(req->address); g_free(req->service_path); g_free(req->uuid); if (req->call) dbus_pending_call_unref(req->call); g_free(req);}static void auth_agent_req_cancel(struct auth_agent_req *req){ dbus_pending_call_cancel(req->call); error_canceled(req->agent->conn, req->msg,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -