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.
This commit is contained in:
tron 2006-07-26 11:00:07 +00:00
parent 1d78709e65
commit 7b1d74d73f
6 changed files with 176 additions and 109 deletions

View File

@ -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 PROG= bthcid
MAN= bthcid.8 MAN= bthcid.8
@ -6,7 +6,7 @@ SRCS= bthcid.c hci.c client.c config.c
CPPFLAGS+= -D_BTHCID_ CPPFLAGS+= -D_BTHCID_
DPADD+= ${LIBBLUETOOTH} ${LIBEVENT} ${LIBUTIL} DPADD+= ${LIBBLUETOOTH} ${LIBEVENT} ${LIBPROP} ${LIBUTIL}
LDADD+= -lbluetooth -levent -lutil LDADD+= -lbluetooth -levent -lprop -lutil
.include <bsd.prog.mk> .include <bsd.prog.mk>

View File

@ -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. .\" Copyright (c) 2006 Itronix Inc.
.\" All rights reserved. .\" All rights reserved.
@ -52,7 +52,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" 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 $ .\" $FreeBSD: src/usr.sbin/bluetooth/hcsecd/hcsecd.8,v 1.6 2006/02/11 15:36:37 markus Exp $
.\" .\"
.Dd November 16, 2002 .Dd November 16, 2002
@ -64,7 +64,6 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl fn .Op Fl fn
.Op Fl c Ar config_file
.Op Fl d Ar device .Op Fl d Ar device
.Op Fl m Ar mode .Op Fl m Ar mode
.Op Fl s Ar socket_name .Op Fl s Ar socket_name
@ -74,18 +73,15 @@
The The
.Nm .Nm
daemon manages link keys and PIN codes for Bluetooth devices. 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 It opens a raw HCI socket and listens for the following HCI events.
.Ar device
address given, if any.
.Pp .Pp
.Bl -tag -width XXXX -compact .Bl -tag -width XXXX -compact
.It Dv Link_Key_Request .It Dv Link_Key_Request
.Nm .Nm
scans first the scans the
.Pa /var/db/bthcid.keys .Pa /var/db/bthcid.keys
file for a cached link key matching the remote device BD_ADDR and, if 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 found, the
has been found, the
.Dv Link_Key_Request_Reply .Dv Link_Key_Request_Reply
will be sent back to the device, otherwise the will be sent back to the device, otherwise the
.Dv Link_Key_Request_Negative_Reply .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 .It Dv PIN_Code_Request
The The
.Nm .Nm
daemon first checks its cached PINs, then the configuration file daemon checks its PIN cache for a matching remote device entry.
for a matching remote device entry. If no PIN is found, the
When no PIN is found, the
.Nm .Nm
daemon will send a message to any PIN clients that have daemon will send a message to any PIN clients that have
registered, with the device details and a timeout value. registered, with the device details and a timeout value.
@ -123,10 +118,6 @@ utility.
.Pp .Pp
The command line options are as follows: The command line options are as follows:
.Bl -tag -width XXXX .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 .It Fl d Ar device
Specify the local Bluetooth device address. The default is BDADDR_ANY. Specify the local Bluetooth device address. The default is BDADDR_ANY.
.It Fl f .It Fl f
@ -144,14 +135,12 @@ Specify the socket name to listen on for PIN clients. The default path is
.El .El
.Sh FILES .Sh FILES
.Bl -tag -compact .Bl -tag -compact
.It Pa /etc/bluetooth/bluetooth.conf
.It Pa /var/db/bthcid.keys .It Pa /var/db/bthcid.keys
.It Pa /var/run/bthcid .It Pa /var/run/bthcid
.It Pa /var/run/bthcid.pid .It Pa /var/run/bthcid.pid
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr bluetooth 4 , .Xr bluetooth 4 ,
.Xr bluetooth.conf 5 ,
.Xr btconfig 8 , .Xr btconfig 8 ,
.Xr btpin 1 .Xr btpin 1
.Sh AUTHORS .Sh AUTHORS
@ -171,13 +160,13 @@ with its present name and extended to support PIN clients by
under the sponsorship of under the sponsorship of
.An Itronix, Inc. .An Itronix, Inc.
.Sh BUGS .Sh BUGS
Currently there is no way to select the link key based on The only way to make the
which local device received the request.
.Pp
Everything is based on the remote device BD_ADDR.
.Pp
Currently the only way to make the
.Nm .Nm
daemon forget a link key is to edit the daemon forget a link key is to edit the
.Pa /var/db/bthcid.keys .Pa /var/db/bthcid.keys
file by hand. 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.

View File

@ -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. * Copyright (c) 2006 Itronix Inc.
@ -33,7 +33,7 @@
__COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc.\n" __COPYRIGHT("@(#) Copyright (c) 2006 Itronix, Inc.\n"
"@(#) Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>\n" "@(#) Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>\n"
"All rights reserved.\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 <sys/param.h> #include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -49,8 +49,6 @@ __RCSID("$NetBSD: bthcid.c,v 1.1 2006/06/19 15:44:56 gdamore Exp $");
#include "bthcid.h" #include "bthcid.h"
const char *key_file = "/var/db/bthcid.keys";
const char *config_file = NULL;
const char *socket_name = BTHCID_SOCKET_NAME; const char *socket_name = BTHCID_SOCKET_NAME;
int detach = 1; int detach = 1;
@ -71,12 +69,8 @@ main(int argc, char *argv[])
bdaddr_copy(&bdaddr, BDADDR_ANY); bdaddr_copy(&bdaddr, BDADDR_ANY);
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 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) { switch (ch) {
case 'c':
config_file = optarg;
break;
case 'd': case 'd':
if (!bt_devaddr(optarg, &bdaddr)) if (!bt_devaddr(optarg, &bdaddr))
err(EXIT_FAILURE, "%s", optarg); err(EXIT_FAILURE, "%s", optarg);

View File

@ -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. * Copyright (c) 2006 Itronix Inc.
@ -61,18 +61,14 @@ typedef struct {
#ifdef _BTHCID_ #ifdef _BTHCID_
extern const char *key_file;
extern const char *config_file;
/* config.c */ /* config.c */
uint8_t *lookup_pin (bdaddr_t *, bdaddr_t *);
uint8_t *lookup_key (bdaddr_t *, bdaddr_t *); uint8_t *lookup_key (bdaddr_t *, bdaddr_t *);
void save_key (bdaddr_t *, bdaddr_t *, uint8_t *); void save_key (bdaddr_t *, bdaddr_t *, uint8_t *);
/* client.c */ /* client.c */
int init_control (const char *, mode_t); int init_control (const char *, mode_t);
int send_client_request (bdaddr_t *, bdaddr_t *, int); 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 */ /* hci.c */
int init_hci (bdaddr_t *); int init_hci (bdaddr_t *);

View File

@ -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. * Copyright (c) 2006 Itronix Inc.
@ -30,7 +30,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__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 <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/queue.h> #include <sys/queue.h>
@ -313,7 +313,7 @@ process_item(int fd, short ev, void *arg)
/* lookup PIN in item cache */ /* lookup PIN in item cache */
uint8_t * uint8_t *
lookup_item(bdaddr_t *laddr, bdaddr_t *raddr) lookup_pin(bdaddr_t *laddr, bdaddr_t *raddr)
{ {
struct item *item; struct item *item;

View File

@ -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. * Copyright (c) 2006 Itronix Inc.
@ -30,104 +30,192 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__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 <sys/time.h> #include <sys/time.h>
#include <prop/proplib.h>
#include <bluetooth.h> #include <bluetooth.h>
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <syslog.h> #include <syslog.h>
#include <unistd.h> #include <unistd.h>
#include "bthcid.h" #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 * uint8_t *
lookup_key(bdaddr_t *laddr, bdaddr_t *raddr) 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) { cfg = load_keys();
bt_freeconfig(cfg); if (cfg == NULL)
cfg = NULL;
}
handle = bt_openconfig(key_file);
if (handle == NULL)
return NULL; return NULL;
cfg = bt_getconfig(handle, raddr); obj = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL));
bt_closeconfig(handle); if (obj == NULL || prop_object_type(obj) != PROP_TYPE_DICTIONARY) {
prop_object_release(cfg);
if (cfg == NULL) {
handle = bt_openconfig(config_file);
if (handle == NULL)
return NULL; return NULL;
cfg = bt_getconfig(handle, raddr);
bt_closeconfig(handle);
} }
if (cfg != NULL) obj = prop_dictionary_get(obj, bt_ntoa(raddr, NULL));
return cfg->key; if (obj == NULL || prop_object_type(obj) != PROP_TYPE_DATA
|| prop_data_size(obj) != sizeof(key)) {
prop_object_release(cfg);
return NULL; return NULL;
}
uint8_t *
lookup_pin(bdaddr_t *laddr, bdaddr_t *raddr)
{
bt_handle_t handle;
if (cfg != NULL) {
bt_freeconfig(cfg);
cfg = NULL;
} }
handle = bt_openconfig(config_file); memcpy(key, prop_data_data_nocopy(obj), sizeof(key));
if (handle != NULL) { prop_object_release(cfg);
cfg = bt_getconfig(handle, raddr); return key;
bt_closeconfig(handle);
if (cfg != NULL && cfg->pin != NULL)
return cfg->pin;
}
return lookup_item(laddr, raddr);
} }
void void
save_key(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t *key) save_key(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t *key)
{ {
static const char hex[] = "0123456789abcdef"; prop_dictionary_t cfg, dev;
char buffer[100], keybuf[HCI_KEY_SIZE * 2 + 1]; prop_data_t dat;
int fd, n, i; char *xml;
int fd;
size_t len;
fd = open(key_file, O_WRONLY|O_APPEND|O_CREAT|O_EXLOCK, 0600); cfg = load_keys();
if (fd < 0) { if (cfg == NULL) {
syslog(LOG_ERR, "Cannot open keyfile %s. %s (%d)", cfg = prop_dictionary_create();
key_file, strerror(errno), errno); if (cfg == NULL) {
syslog(LOG_ERR, "prop_dictionary_create() failed. %s (%d)",
strerror(errno), errno);
return; return;
} }
for (n = i = 0 ; i < HCI_KEY_SIZE ; i++) {
keybuf[n++] = hex[(key[i] >> 4) & 0xf];
keybuf[n++] = hex[key[i] & 0xf];
} }
keybuf[n] = '\0';
n = snprintf(buffer, sizeof(buffer), dev = prop_dictionary_get(cfg, bt_ntoa(laddr, NULL));
"\ndevice {\n" if (dev == NULL) {
"\tbdaddr %s;\n" dev = prop_dictionary_create();
"\tkey 0x%s;\n" if (dev == NULL) {
"}\n", syslog(LOG_ERR, "prop_dictionary_create() failed. %s (%d)",
bt_ntoa(raddr, NULL), strerror(errno), errno);
keybuf);
write(fd, buffer, (size_t)n); 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;
}
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;
}
xml = prop_dictionary_externalize(cfg);
if (xml == NULL) {
syslog(LOG_ERR, "prop_dictionary_externalize() failed. %s (%d)",
strerror(errno), errno);
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); 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);
}
} }