From 7b1d74d73ff16ce989e1ef28d06ca231a491c4ec Mon Sep 17 00:00:00 2001 From: tron Date: Wed, 26 Jul 2006 11:00:07 +0000 Subject: [PATCH] Bluetooth fixes by Iain Hibbert: Remove bluetooth.conf stuff from bthcid(8), and use XML with proplib(3) for keyfile. Also, associate keys with local and remote address. --- usr.sbin/bthcid/Makefile | 6 +- usr.sbin/bthcid/bthcid.8 | 37 +++---- usr.sbin/bthcid/bthcid.c | 12 +-- usr.sbin/bthcid/bthcid.h | 8 +- usr.sbin/bthcid/client.c | 6 +- usr.sbin/bthcid/config.c | 216 +++++++++++++++++++++++++++------------ 6 files changed, 176 insertions(+), 109 deletions(-) diff --git a/usr.sbin/bthcid/Makefile b/usr.sbin/bthcid/Makefile index 43f5be406dd1..a1d96ce0e546 100644 --- a/usr.sbin/bthcid/Makefile +++ b/usr.sbin/bthcid/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.1 2006/06/19 15:44:56 gdamore Exp $ +# $NetBSD: Makefile,v 1.2 2006/07/26 11:00:07 tron Exp $ PROG= bthcid MAN= bthcid.8 @@ -6,7 +6,7 @@ SRCS= bthcid.c hci.c client.c config.c CPPFLAGS+= -D_BTHCID_ -DPADD+= ${LIBBLUETOOTH} ${LIBEVENT} ${LIBUTIL} -LDADD+= -lbluetooth -levent -lutil +DPADD+= ${LIBBLUETOOTH} ${LIBEVENT} ${LIBPROP} ${LIBUTIL} +LDADD+= -lbluetooth -levent -lprop -lutil .include diff --git a/usr.sbin/bthcid/bthcid.8 b/usr.sbin/bthcid/bthcid.8 index 7b2b72516454..af8b30cfaad8 100644 --- a/usr.sbin/bthcid/bthcid.8 +++ b/usr.sbin/bthcid/bthcid.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: bthcid.8,v 1.1 2006/06/19 15:44:56 gdamore Exp $ +.\" $NetBSD: bthcid.8,v 1.2 2006/07/26 11:00:07 tron Exp $ .\" .\" Copyright (c) 2006 Itronix Inc. .\" All rights reserved. @@ -52,7 +52,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: bthcid.8,v 1.1 2006/06/19 15:44:56 gdamore Exp $ +.\" $Id: bthcid.8,v 1.2 2006/07/26 11:00:07 tron Exp $ .\" $FreeBSD: src/usr.sbin/bluetooth/hcsecd/hcsecd.8,v 1.6 2006/02/11 15:36:37 markus Exp $ .\" .Dd November 16, 2002 @@ -64,7 +64,6 @@ .Sh SYNOPSIS .Nm .Op Fl fn -.Op Fl c Ar config_file .Op Fl d Ar device .Op Fl m Ar mode .Op Fl s Ar socket_name @@ -74,18 +73,15 @@ The .Nm daemon manages link keys and PIN codes for Bluetooth devices. -It opens a raw HCI socket and listens for the following HCI events at the -.Ar device -address given, if any. +It opens a raw HCI socket and listens for the following HCI events. .Pp .Bl -tag -width XXXX -compact .It Dv Link_Key_Request .Nm -scans first the +scans the .Pa /var/db/bthcid.keys file for a cached link key matching the remote device BD_ADDR and, if -none is found, further scans the configuration file. When a link key -has been found, the +found, the .Dv Link_Key_Request_Reply will be sent back to the device, otherwise the .Dv Link_Key_Request_Negative_Reply @@ -100,9 +96,8 @@ link keys file, which will be created if it does not already exist. .It Dv PIN_Code_Request The .Nm -daemon first checks its cached PINs, then the configuration file -for a matching remote device entry. -When no PIN is found, the +daemon checks its PIN cache for a matching remote device entry. +If no PIN is found, the .Nm daemon will send a message to any PIN clients that have registered, with the device details and a timeout value. @@ -123,10 +118,6 @@ utility. .Pp The command line options are as follows: .Bl -tag -width XXXX -.It Fl c Ar config_file -Specify the name of the configuration file. -The default is -.Pa /etc/bluetooth/bluetooth.conf . .It Fl d Ar device Specify the local Bluetooth device address. The default is BDADDR_ANY. .It Fl f @@ -144,14 +135,12 @@ Specify the socket name to listen on for PIN clients. The default path is .El .Sh FILES .Bl -tag -compact -.It Pa /etc/bluetooth/bluetooth.conf .It Pa /var/db/bthcid.keys .It Pa /var/run/bthcid .It Pa /var/run/bthcid.pid .El .Sh SEE ALSO .Xr bluetooth 4 , -.Xr bluetooth.conf 5 , .Xr btconfig 8 , .Xr btpin 1 .Sh AUTHORS @@ -171,13 +160,13 @@ with its present name and extended to support PIN clients by under the sponsorship of .An Itronix, Inc. .Sh BUGS -Currently there is no way to select the link key based on -which local device received the request. -.Pp -Everything is based on the remote device BD_ADDR. -.Pp -Currently the only way to make the +The only way to make the .Nm daemon forget a link key is to edit the .Pa /var/db/bthcid.keys file by hand. +.Pp +The only way to specify link keys (useful when multiple operating +systems are used on the same hardware), is to edit the +.Pa /var/db/bthcid.keys +file by hand. diff --git a/usr.sbin/bthcid/bthcid.c b/usr.sbin/bthcid/bthcid.c index 599add8b0fe2..4915c3278026 100644 --- a/usr.sbin/bthcid/bthcid.c +++ b/usr.sbin/bthcid/bthcid.c @@ -1,4 +1,4 @@ -/* $NetBSD: bthcid.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */ +/* $NetBSD: bthcid.c,v 1.2 2006/07/26 11:00:07 tron Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -33,7 +33,7 @@ __COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc.\n" "@(#) Copyright (c) 2001-2002 Maksim Yevmenkin \n" "All rights reserved.\n"); -__RCSID("$NetBSD: bthcid.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $"); +__RCSID("$NetBSD: bthcid.c,v 1.2 2006/07/26 11:00:07 tron Exp $"); #include #include @@ -49,8 +49,6 @@ __RCSID("$NetBSD: bthcid.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $"); #include "bthcid.h" -const char *key_file = "/var/db/bthcid.keys"; -const char *config_file = NULL; const char *socket_name = BTHCID_SOCKET_NAME; int detach = 1; @@ -71,12 +69,8 @@ main(int argc, char *argv[]) bdaddr_copy(&bdaddr, BDADDR_ANY); mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; - while ((ch = getopt(argc, argv, "c:d:fm:ns:h")) != -1) { + while ((ch = getopt(argc, argv, "d:fm:ns:h")) != -1) { switch (ch) { - case 'c': - config_file = optarg; - break; - case 'd': if (!bt_devaddr(optarg, &bdaddr)) err(EXIT_FAILURE, "%s", optarg); diff --git a/usr.sbin/bthcid/bthcid.h b/usr.sbin/bthcid/bthcid.h index 22e33c68e4e8..a0f20de823c3 100644 --- a/usr.sbin/bthcid/bthcid.h +++ b/usr.sbin/bthcid/bthcid.h @@ -1,4 +1,4 @@ -/* $NetBSD: bthcid.h,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */ +/* $NetBSD: bthcid.h,v 1.2 2006/07/26 11:00:07 tron Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -61,18 +61,14 @@ typedef struct { #ifdef _BTHCID_ -extern const char *key_file; -extern const char *config_file; - /* config.c */ -uint8_t *lookup_pin (bdaddr_t *, bdaddr_t *); uint8_t *lookup_key (bdaddr_t *, bdaddr_t *); void save_key (bdaddr_t *, bdaddr_t *, uint8_t *); /* client.c */ int init_control (const char *, mode_t); int send_client_request (bdaddr_t *, bdaddr_t *, int); -uint8_t *lookup_item (bdaddr_t *, bdaddr_t *); +uint8_t *lookup_pin (bdaddr_t *, bdaddr_t *); /* hci.c */ int init_hci (bdaddr_t *); diff --git a/usr.sbin/bthcid/client.c b/usr.sbin/bthcid/client.c index e75568c550e7..415b155685d3 100644 --- a/usr.sbin/bthcid/client.c +++ b/usr.sbin/bthcid/client.c @@ -1,4 +1,4 @@ -/* $NetBSD: client.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */ +/* $NetBSD: client.c,v 1.2 2006/07/26 11:00:07 tron Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -30,7 +30,7 @@ */ #include -__RCSID("$NetBSD: client.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $"); +__RCSID("$NetBSD: client.c,v 1.2 2006/07/26 11:00:07 tron Exp $"); #include #include @@ -313,7 +313,7 @@ process_item(int fd, short ev, void *arg) /* lookup PIN in item cache */ uint8_t * -lookup_item(bdaddr_t *laddr, bdaddr_t *raddr) +lookup_pin(bdaddr_t *laddr, bdaddr_t *raddr) { struct item *item; diff --git a/usr.sbin/bthcid/config.c b/usr.sbin/bthcid/config.c index ca308a95611a..8ba698593627 100644 --- a/usr.sbin/bthcid/config.c +++ b/usr.sbin/bthcid/config.c @@ -1,4 +1,4 @@ -/* $NetBSD: config.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $ */ +/* $NetBSD: config.c,v 1.2 2006/07/26 11:00:07 tron Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -30,104 +30,192 @@ */ #include -__RCSID("$NetBSD: config.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $"); +__RCSID("$NetBSD: config.c,v 1.2 2006/07/26 11:00:07 tron Exp $"); #include +#include #include #include #include #include +#include #include #include #include #include "bthcid.h" -static bt_cfgentry_t *cfg = NULL; +static const char *key_file = "/var/db/bthcid.keys"; +static const char *new_key_file = "/var/db/bthcid.keys.new"; +static prop_dictionary_t +load_keys(void) +{ + prop_dictionary_t dict; + char *xml; + off_t len; + int fd; + + fd = open(key_file, O_RDONLY, 0); + if (fd < 0) + return NULL; + + len = lseek(fd, 0, SEEK_END); + if (len == 0) { + close(fd); + return NULL; + } + + xml = malloc(len); + if (xml == NULL) { + close(fd); + return NULL; + } + + (void)lseek(fd, 0, SEEK_SET); + if (read(fd, xml, len) != len) { + free(xml); + close(fd); + return NULL; + } + + dict = prop_dictionary_internalize(xml); + free(xml); + close(fd); + return dict; +} + +/* + * Look up key in keys file. We store a dictionary for each + * remote address, and inside that we have a data object for + * each local address containing the key. + */ uint8_t * lookup_key(bdaddr_t *laddr, bdaddr_t *raddr) { - bt_handle_t handle; + static uint8_t key[HCI_KEY_SIZE]; + prop_dictionary_t cfg; + prop_object_t obj; - if (cfg != NULL) { - bt_freeconfig(cfg); - cfg = NULL; - } - - handle = bt_openconfig(key_file); - if (handle == NULL) + cfg = load_keys(); + if (cfg == NULL) return NULL; - cfg = bt_getconfig(handle, raddr); - bt_closeconfig(handle); - - if (cfg == NULL) { - handle = bt_openconfig(config_file); - if (handle == NULL) - return NULL; - - cfg = bt_getconfig(handle, raddr); - bt_closeconfig(handle); + obj = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL)); + if (obj == NULL || prop_object_type(obj) != PROP_TYPE_DICTIONARY) { + prop_object_release(cfg); + return NULL; } - if (cfg != NULL) - return cfg->key; - - return NULL; -} - -uint8_t * -lookup_pin(bdaddr_t *laddr, bdaddr_t *raddr) -{ - bt_handle_t handle; - - if (cfg != NULL) { - bt_freeconfig(cfg); - cfg = NULL; + obj = prop_dictionary_get(obj, bt_ntoa(raddr, NULL)); + if (obj == NULL || prop_object_type(obj) != PROP_TYPE_DATA + || prop_data_size(obj) != sizeof(key)) { + prop_object_release(cfg); + return NULL; } - handle = bt_openconfig(config_file); - if (handle != NULL) { - cfg = bt_getconfig(handle, raddr); - bt_closeconfig(handle); - - if (cfg != NULL && cfg->pin != NULL) - return cfg->pin; - } - - return lookup_item(laddr, raddr); + memcpy(key, prop_data_data_nocopy(obj), sizeof(key)); + prop_object_release(cfg); + return key; } void save_key(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t *key) { - static const char hex[] = "0123456789abcdef"; - char buffer[100], keybuf[HCI_KEY_SIZE * 2 + 1]; - int fd, n, i; + prop_dictionary_t cfg, dev; + prop_data_t dat; + char *xml; + int fd; + size_t len; - fd = open(key_file, O_WRONLY|O_APPEND|O_CREAT|O_EXLOCK, 0600); - if (fd < 0) { - syslog(LOG_ERR, "Cannot open keyfile %s. %s (%d)", - key_file, strerror(errno), errno); + cfg = load_keys(); + if (cfg == NULL) { + cfg = prop_dictionary_create(); + if (cfg == NULL) { + syslog(LOG_ERR, "prop_dictionary_create() failed. %s (%d)", + strerror(errno), errno); + return; + } + } + + dev = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL)); + if (dev == NULL) { + dev = prop_dictionary_create(); + if (dev == NULL) { + syslog(LOG_ERR, "prop_dictionary_create() failed. %s (%d)", + strerror(errno), errno); + + prop_object_release(cfg); + return; + } + + if (!prop_dictionary_set(cfg, bt_ntoa(laddr, NULL), dev)) { + syslog(LOG_ERR, "prop_dictionary_set() failed. %s (%d)", + strerror(errno), errno); + + prop_object_release(dev); + prop_object_release(cfg); + return; + } + } + + dat = prop_data_create_data_nocopy(key, HCI_KEY_SIZE); + if (dat == NULL) { + syslog(LOG_ERR, "Cannot create data object. %s (%d)", + strerror(errno), errno); + + prop_object_release(cfg); return; } - for (n = i = 0 ; i < HCI_KEY_SIZE ; i++) { - keybuf[n++] = hex[(key[i] >> 4) & 0xf]; - keybuf[n++] = hex[key[i] & 0xf]; + if (!prop_dictionary_set(dev, bt_ntoa(raddr, NULL), dat)) { + syslog(LOG_ERR, "prop_dictionary_set() failed. %s (%d)", + strerror(errno), errno); + + prop_object_release(dat); + prop_object_release(cfg); + return; } - keybuf[n] = '\0'; - n = snprintf(buffer, sizeof(buffer), - "\ndevice {\n" - "\tbdaddr %s;\n" - "\tkey 0x%s;\n" - "}\n", - bt_ntoa(raddr, NULL), - keybuf); + xml = prop_dictionary_externalize(cfg); + if (xml == NULL) { + syslog(LOG_ERR, "prop_dictionary_externalize() failed. %s (%d)", + strerror(errno), errno); - write(fd, buffer, (size_t)n); + prop_object_release(cfg); + return; + } + + prop_object_release(cfg); + + fd = open(new_key_file, O_WRONLY|O_TRUNC|O_CREAT|O_EXLOCK, 0600); + if (fd < 0) { + syslog(LOG_ERR, "Cannot open new keyfile %s. %s (%d)", + key_file, strerror(errno), errno); + + free(xml); + return; + } + + len = strlen(xml); + if (write(fd, xml, len) != len) { + syslog(LOG_ERR, "Write of keyfile failed. %s (%d)", + strerror(errno), errno); + + free(xml); + close(fd); + unlink(new_key_file); + return; + } + + free(xml); close(fd); + + if (rename(new_key_file, key_file) < 0) { + syslog(LOG_ERR, "rename(%s, %s) failed. %s (%d)", + new_key_file, key_file, strerror(errno), errno); + + unlink(new_key_file); + } }