diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2007-01-26 09:53:30 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2007-01-26 09:53:30 +0000 | 
| commit | 5753e415a5ef3308f1408ad07623ae07047faaf5 (patch) | |
| tree | 68a35ac9cfc9a37dadc07fd5afb0b4fd5ddfefba | |
| parent | 7671d152752e7daff9e27025d5d5365bb894fe07 (diff) | |
Add encryption support
| -rw-r--r-- | input/input-service.c | 82 | ||||
| -rw-r--r-- | input/server.c | 10 | ||||
| -rw-r--r-- | input/storage.c | 75 | ||||
| -rw-r--r-- | input/storage.h | 2 | 
4 files changed, 140 insertions, 29 deletions
| diff --git a/input/input-service.c b/input/input-service.c index c1df0a37..dbbdb877 100644 --- a/input/input-service.c +++ b/input/input-service.c @@ -60,6 +60,7 @@  #define L2CAP_PSM_HIDP_INTR		0x13  static DBusConnection *connection = NULL; +  const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb";  const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; @@ -68,6 +69,11 @@ struct input_device {  	struct hidp_connadd_req hidp;  }; +struct input_manager { +	bdaddr_t sba;		/* Local adapter BT address */ +	GSList *paths;		/* Input registered paths */ +}; +  struct pending_req {  	char *adapter_path;	/* Local adapter D-Bus path */  	bdaddr_t sba;		/* Local adapter BT address */ @@ -110,8 +116,8 @@ static void input_device_free(struct input_device *idev)  }  static struct pending_req *pending_req_new(DBusConnection *conn, -		DBusMessage *msg, const char *adapter_path, -		bdaddr_t *sba, bdaddr_t *dba) +				DBusMessage *msg, const char *adapter_path, +						bdaddr_t *sba, bdaddr_t *dba)  {  	struct pending_req *pr;  	pr = malloc(sizeof(struct pending_req)); @@ -357,7 +363,7 @@ static const char *create_input_path(uint8_t minor)  }  static int l2cap_connect(struct pending_connect *pc, -		unsigned short psm, GIOFunc cb) +					unsigned short psm, GIOFunc cb)  {  	GIOChannel *io;  	struct sockaddr_l2 addr; @@ -413,7 +419,7 @@ failed:  }  static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, -			struct pending_connect *pc) +						struct pending_connect *pc)  {  	struct input_device *idev;  	int ctl, isk, ret, err; @@ -431,7 +437,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond,  	isk = g_io_channel_unix_get_fd(chan);  	idev->hidp.intr_sock = isk; -	idev->hidp.idle_to = 1800; /* 30 sec */ +	idev->hidp.idle_to = 30 * 60;	/* 30 minutes */  	len = sizeof(ret);  	if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { @@ -452,11 +458,21 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond,  		error("Can't open HIDP control socket");  		goto failed;  	} + +	if (idev->hidp.subclass & 0x40) { +		err = encrypt_link(&pc->sba, &pc->dba); +		if (err < 0) { +			close(ctl); +			goto failed; +		} +	} +  	if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) {  		err = errno;  		close(ctl);  		goto failed;  	} +  	close(ctl);  	send_message_and_unref(pc->conn, @@ -466,6 +482,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond,  	g_io_channel_unref(chan);  	return FALSE; +  failed:  	if (isk > 0)  		close(isk); @@ -479,7 +496,7 @@ failed:  }  static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, -			struct pending_connect *pc) +						struct pending_connect *pc)  {  	struct input_device *idev;  	int ret, csk, err; @@ -511,6 +528,7 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond,  		error("connect(): %s (%d)", strerror(ret), ret);  		goto failed;  	} +  	/* Connect to the HID interrupt channel */  	if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR,  			(GIOFunc) interrupt_connect_cb) < 0) { @@ -550,7 +568,7 @@ static int disconnect(struct input_device *idev,  uint32_t flags)  	memset(&ci, 0, sizeof(struct hidp_conninfo));  	bacpy(&ci.bdaddr, &idev->dba);  	if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || -			(ci.state != BT_CONNECTED)) { +				(ci.state != BT_CONNECTED)) {  		errno = ENOTCONN;  		goto fail;  	} @@ -606,15 +624,17 @@ static int is_connected(bdaddr_t *dba)   * Input Device methods   */  static DBusHandlerResult device_connect(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_device *idev = data; +	struct input_manager *mgr;  	struct pending_connect *pc;  	if (is_connected(&idev->dba))  		return err_connection_failed(conn, msg, "Already connected"); -	pc = pending_connect_new(BDADDR_ANY, &idev->dba, conn, msg); +	dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); +	pc = pending_connect_new(&mgr->sba, &idev->dba, conn, msg);  	if (!pc)  		return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -629,7 +649,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn,  }  static DBusHandlerResult device_disconnect(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_device *idev = data; @@ -641,7 +661,7 @@ static DBusHandlerResult device_disconnect(DBusConnection *conn,  }  static DBusHandlerResult device_is_connected(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_device *idev = data;  	DBusMessage *reply; @@ -660,13 +680,13 @@ static DBusHandlerResult device_is_connected(DBusConnection *conn,  }  static DBusHandlerResult device_get_address(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_device *idev = data;  	DBusMessage *reply;  	char addr[18];  	const char *paddr = addr; -	 +  	ba2str(&idev->dba, addr);  	reply = dbus_message_new_method_return(msg); @@ -681,7 +701,7 @@ static DBusHandlerResult device_get_address(DBusConnection *conn,  }  static DBusHandlerResult device_get_name(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_device *idev = data;  	DBusMessage *reply; @@ -699,7 +719,7 @@ static DBusHandlerResult device_get_name(DBusConnection *conn,  }  static DBusHandlerResult device_get_product_id(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_device *idev = data;  	DBusMessage *reply; @@ -716,7 +736,7 @@ static DBusHandlerResult device_get_product_id(DBusConnection *conn,  }  static DBusHandlerResult device_get_vendor_id(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_device *idev = data;  	DBusMessage *reply; @@ -733,13 +753,13 @@ static DBusHandlerResult device_get_vendor_id(DBusConnection *conn,  }  static DBusHandlerResult device_set_timeout(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;  }  static DBusHandlerResult device_message(DBusConnection *conn, -		DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	const char *iface, *member; @@ -791,19 +811,16 @@ static const DBusObjectPathVTable device_table = {  /*   * Input Manager methods   */ -struct input_manager { -	bdaddr_t sba;		/* Local adapter BT address */ -	GSList *paths;		/* Input registered paths */ -}; -  static void input_manager_free(struct input_manager *mgr)  {  	if (!mgr)  		return; +  	if (mgr->paths) {  		g_slist_foreach(mgr->paths, (GFunc) free, NULL);  		g_slist_free(mgr->paths);  	} +  	free(mgr);  } @@ -876,7 +893,7 @@ static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr)  }  static int get_record(struct pending_req *pr, uint32_t handle, -			DBusPendingCallNotifyFunction cb) +					DBusPendingCallNotifyFunction cb)  {  	DBusMessage *msg;  	DBusPendingCall *pending; @@ -906,7 +923,7 @@ static int get_record(struct pending_req *pr, uint32_t handle,  }  static int get_handles(struct pending_req *pr, const char *uuid, -			DBusPendingCallNotifyFunction cb) +					DBusPendingCallNotifyFunction cb)  {  	DBusMessage *msg;  	DBusPendingCall *pending; @@ -1068,9 +1085,12 @@ static void pnp_record_reply(DBusPendingCall *call, void *data)  		else  			goto done;  	} +  	err_failed(pr->conn, pr->msg, "SDP error"); +  fail:  	pending_req_free(pr); +  done:  	dbus_message_unref(reply);  	dbus_pending_call_unref(call); @@ -1115,15 +1135,17 @@ static void pnp_handle_reply(DBusPendingCall *call, void *data)  	}  	goto done; +  fail:  	pending_req_free(pr); +  done:  	dbus_message_unref(reply);  	dbus_pending_call_unref(call);  }  static DBusHandlerResult manager_create_device(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_manager *mgr = data;  	struct input_device *idev; @@ -1186,6 +1208,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn,  		input_device_free(idev);  		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	} +  	dbus_message_append_args(reply,  			DBUS_TYPE_STRING, &path,  			DBUS_TYPE_INVALID); @@ -1194,7 +1217,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn,  }  static DBusHandlerResult manager_remove_device(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_manager *mgr = data;  	struct input_device *idev; @@ -1238,7 +1261,7 @@ static DBusHandlerResult manager_remove_device(DBusConnection *conn,  }  static DBusHandlerResult manager_list_devices(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	struct input_manager *mgr = data;  	DBusMessageIter iter, iter_array; @@ -1265,7 +1288,7 @@ static DBusHandlerResult manager_list_devices(DBusConnection *conn,  }  static DBusHandlerResult manager_message(DBusConnection *conn, -				DBusMessage *msg, void *data) +						DBusMessage *msg, void *data)  {  	const char *path, *iface, *member; @@ -1380,6 +1403,7 @@ int input_dbus_init(void)  	register_stored_inputs(connection, &sba);  	return 0; +  fail:  	input_manager_free(mgr); diff --git a/input/server.c b/input/server.c index 9e97490f..b140bb6b 100644 --- a/input/server.c +++ b/input/server.c @@ -34,6 +34,8 @@  #include <bluetooth/bluetooth.h>  #include <bluetooth/l2cap.h>  #include <bluetooth/hidp.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h>  #include <glib.h> @@ -98,6 +100,14 @@ static void create_device(struct session_data *session)  		goto cleanup;  	} +	if (req.subclass & 0x40) { +		if (encrypt_link(&session->src, &session->dst) < 0) { +			if (req.rd_data) +				free(req.rd_data); +			goto cleanup; +		} +	} +  	info("New input device %s (%s)", addr, req.name);  	err = ioctl(ctl, HIDPCONNADD, &req); diff --git a/input/storage.c b/input/storage.c index 0452a1e9..c46b8d82 100644 --- a/input/storage.c +++ b/input/storage.c @@ -35,12 +35,16 @@  #include <sys/file.h>  #include <sys/stat.h>  #include <sys/param.h> +#include <sys/ioctl.h>  #include <sys/socket.h>  #include <bluetooth/bluetooth.h>  #include <bluetooth/hidp.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h>  #include "textfile.h" +#include "logging.h"  #include "storage.h" @@ -170,3 +174,74 @@ int store_device_info(bdaddr_t *sba, bdaddr_t *dba, struct hidp_connadd_req *req  	return err;  } + +int encrypt_link(bdaddr_t *src, bdaddr_t *dst) +{ +	char filename[PATH_MAX + 1]; +	struct hci_conn_info_req *cr; +	int dd, err, dev_id; +	char addr[18], *str; + +	create_filename(filename, PATH_MAX, src, "linkkeys"); + +	ba2str(dst, addr); + +	str = textfile_get(filename, addr); +	if (!str) { +		error("Encryption link key not found"); +		return -ENOKEY; +	} + +	free(str); + +	cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info)); +	if (!cr) +		return -ENOMEM; + +	ba2str(src, addr); + +	dev_id = hci_devid(addr); +	if (dev_id < 0) { +		free(cr); +		return -errno; +	} + +	dd = hci_open_dev(dev_id); +	if (dd < 0) { +		free(cr); +		return -errno; +	} + +	memset(cr, 0, sizeof(*cr) + sizeof(struct hci_conn_info)); +	bacpy(&cr->bdaddr, dst); +	cr->type = ACL_LINK; + +	if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) +		goto fail; + +	if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 1000) < 0) { +		error("Link authentication failed: %s (%d)", +						strerror(errno), errno); +		goto fail; +	} + +	if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), 1, 1000) < 0) { +		error("Link encryption failed: %s (%d)", +						strerror(errno), errno); +		goto fail; +	} + +	free(cr); + +	hci_close_dev(dd); + +	return 0; + +fail: +	free(cr); + +	err = errno; +	hci_close_dev(dd); + +	return -err; +} diff --git a/input/storage.h b/input/storage.h index adec8bf4..68b5c535 100644 --- a/input/storage.h +++ b/input/storage.h @@ -31,3 +31,5 @@ int store_device_info(bdaddr_t *sba, bdaddr_t *dba,  int parse_stored_device_info(const char *str,  				struct hidp_connadd_req *req); + +int encrypt_link(bdaddr_t *src, bdaddr_t *dst); | 
