Add bthcid(8) - Bluetooth Link Key/PIN Code Manager and btpin(1) Bluetooth
authorHasso Tepper <hasso@dragonflybsd.org>
Wed, 30 Jan 2008 14:10:19 +0000 (14:10 +0000)
committerHasso Tepper <hasso@dragonflybsd.org>
Wed, 30 Jan 2008 14:10:19 +0000 (14:10 +0000)
PIN utility.

Obtained-from: NetBSD with modifications

17 files changed:
etc/bluetooth/bthcid.conf [new file with mode: 0644]
etc/rc.d/Makefile
etc/rc.d/bthcid [new file with mode: 0644]
usr.sbin/Makefile
usr.sbin/bthcid/Makefile [new file with mode: 0644]
usr.sbin/bthcid/bthcid.8 [new file with mode: 0644]
usr.sbin/bthcid/bthcid.c [new file with mode: 0644]
usr.sbin/bthcid/bthcid.conf.5 [new file with mode: 0644]
usr.sbin/bthcid/bthcid.h [new file with mode: 0644]
usr.sbin/bthcid/client.c [new file with mode: 0644]
usr.sbin/bthcid/config.c [new file with mode: 0644]
usr.sbin/bthcid/hci.c [new file with mode: 0644]
usr.sbin/bthcid/lexer.l [new file with mode: 0644]
usr.sbin/bthcid/parser.y [new file with mode: 0644]
usr.sbin/btpin/Makefile [new file with mode: 0644]
usr.sbin/btpin/btpin.1 [new file with mode: 0644]
usr.sbin/btpin/btpin.c [new file with mode: 0644]

diff --git a/etc/bluetooth/bthcid.conf b/etc/bluetooth/bthcid.conf
new file mode 100644 (file)
index 0000000..0aaf4c5
--- /dev/null
@@ -0,0 +1,63 @@
+# $FreeBSD: src/usr.sbin/bluetooth/hcsecd/hcsecd.conf,v 1.1 2003/05/10 21:50:35 julian Exp $
+# $DragonFly: src/etc/bluetooth/bthcid.conf,v 1.1 2008/01/30 14:10:19 hasso Exp $
+#
+# HCI security daemon configuration file
+#
+# Format:
+#
+# device {
+#      option  value ;
+# }
+#
+# Possible options and values
+#
+# Options      Values
+# ----------------------------------
+# bdaddr       xx:xx:xx:xx:xx:xx ;     - remote device BD_ADDR
+# name                 "any char" ;            - to set user friendly device name
+# key          0x11223344 | nokey ;    - to set link key for the device
+# pin          "secret" | nopin ;      - to PIN code for the device
+#
+# Notes:
+#
+#      Currently there is no way to select keys/PIN code based on which
+#      local device received the request. Everything is based on remote
+#      device BD_ADDR.
+#
+#      "nokey" means that no link key has been defined and we should 
+#              send Link_Key_Negative_Reply command to the device.
+#
+#      "nopin" means that no PIN code has been defined and we should 
+#              send PIN_Code_Negative_Reply command to the device
+#
+
+# Default entry applied if no better match found 
+# It MUST have 00:00:00:00:00:00 as bdaddr
+device {
+       bdaddr  00:00:00:00:00:00;
+       name    "Default entry";
+       key     nokey;
+       pin     nopin;
+}
+
+# device {
+#      bdaddr  00:80:37:5e:4d:d4;
+#      name    "Ericsson T68 phone";
+#      key     nokey;
+#      pin     "0000"; # PIN code (string up to 16 character)
+# }
+# 
+# device {
+#      bdaddr  00:01:03:fc:6e:ec;
+#      name    "3COM PCCARD";
+#      key     nokey;
+#      pin     "0000";
+# }
+# 
+# device {
+#      bdaddr  00:11:22:33:44:55;
+#      name    "Dummy";
+#      key     0x00112233445566778899aabbccddeeff; # 16 bytes key (hex string)
+#      pin     nopin;
+# }
+
index eae5c63..dc5274d 100644 (file)
@@ -1,6 +1,6 @@
 # $NetBSD: Makefile,v 1.16 2001/01/14 15:37:22 minoura Exp $
 # $FreeBSD: src/etc/rc.d/Makefile,v 1.20 2003/06/29 05:15:57 mtm Exp $
-# $DragonFly: src/etc/rc.d/Makefile,v 1.26 2008/01/20 11:23:35 swildner Exp $
+# $DragonFly: src/etc/rc.d/Makefile,v 1.27 2008/01/30 14:10:19 hasso Exp $
 
 .include <bsd.own.mk>
 
@@ -8,7 +8,7 @@
 #
 FILES= DAEMON LOGIN NETWORKING SERVERS abi accounting addswap adjkerntz \
        amd apm apmd atm1 atm2.sh atm3.sh \
-       battd bootconf bootparams btconfig ccd cleanvar \
+       battd bootconf bootparams btconfig bthcid ccd cleanvar \
        cleartmp cron dhclient dhcpd dhcrelay diskless dmesg dumpon \
        fsck ftpd hostapd hostname \
        inetd initdiskless initrandom ip6fw ipfilter ipfs ipfw ipmon \
diff --git a/etc/rc.d/bthcid b/etc/rc.d/bthcid
new file mode 100644 (file)
index 0000000..a8b67aa
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# $NetBSD: bthcid,v 1.1 2006/06/19 15:44:36 gdamore Exp $
+# $DragonFly: src/etc/rc.d/bthcid,v 1.1 2008/01/30 14:10:19 hasso Exp $
+
+# PROVIDE: bthcid
+# REQUIRE: bluetooth
+# BEFORE: LOGIN
+
+$rc_subr_loaded . /etc/rc.subr
+
+name="bthcid"
+rcvar=$name
+
+command="/usr/sbin/${name}"
+pidfile="/var/run/${name}.pid"
+
+load_rc_config $name
+run_rc_command "$1"
index a33b7b8..4a6e368 100644 (file)
@@ -1,6 +1,6 @@
 #      From: @(#)Makefile      5.20 (Berkeley) 6/12/93
 # $FreeBSD: src/usr.sbin/Makefile,v 1.183.2.14 2003/04/16 11:01:51 ru Exp $
-# $DragonFly: src/usr.sbin/Makefile,v 1.37 2008/01/06 21:51:30 hasso Exp $
+# $DragonFly: src/usr.sbin/Makefile,v 1.38 2008/01/30 14:10:19 hasso Exp $
 
 .include "../sys/platform/${MACHINE_PLATFORM}/Makefile.inc"
 
@@ -20,6 +20,8 @@ SUBDIR= 802_11 \
        authpf \
        bootparamd \
        btconfig \
+       bthcid \
+       btpin \
        burncd \
        cdcontrol \
        chkgrp \
diff --git a/usr.sbin/bthcid/Makefile b/usr.sbin/bthcid/Makefile
new file mode 100644 (file)
index 0000000..fd67c17
--- /dev/null
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.4 2007/05/28 12:06:34 tls Exp $
+# $DragonFly: src/usr.sbin/bthcid/Makefile,v 1.1 2008/01/30 14:10:19 hasso Exp $
+
+PROG=          bthcid
+MAN=           bthcid.8 bthcid.conf.5
+SRCS=          bthcid.c hci.c client.c config.c lexer.l parser.y
+
+DPADD+=                ${LIBBLUETOOTH} ${LIBEVENT} ${LIBUTIL}
+LDADD+=                -lbluetooth -levent -lutil
+CFLAGS+=       -I${.CURDIR}/../../sys -I${.CURDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bthcid/bthcid.8 b/usr.sbin/bthcid/bthcid.8
new file mode 100644 (file)
index 0000000..2168e25
--- /dev/null
@@ -0,0 +1,174 @@
+.\" $NetBSD: bthcid.8,v 1.5 2006/10/03 02:04:42 wiz Exp $
+.\" $DragonFly: src/usr.sbin/bthcid/bthcid.8,v 1.1 2008/01/30 14:10:19 hasso Exp $
+.\"
+.\" Copyright (c) 2006 Itronix Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of Itronix Inc. may not be used to endorse
+.\"    or promote products derived from this software without specific
+.\"    prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: bthcid.8,v 1.1.1.1 2007/11/20 11:56:11 griffin Exp $
+.\" $FreeBSD: src/usr.sbin/bluetooth/hcsecd/hcsecd.8,v 1.6 2006/02/11 15:36:37 markus Exp $
+.\"
+.Dd September 29, 2006
+.Dt BTHCID 8
+.Os
+.Sh NAME
+.Nm bthcid
+.Nd Bluetooth Link Key/PIN Code Manager
+.Sh SYNOPSIS
+.Nm
+.Op Fl fn
+.Op Fl d Ar device
+.Op Fl m Ar mode
+.Op Fl s Ar socket_name
+.Nm
+.Op Fl h
+.Sh DESCRIPTION
+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.
+.Pp
+.Bl -tag -width XXXX -compact
+.It Dv Link_Key_Request
+.Nm
+scans the
+.Pa /var/db/bthcid.keys
+file for a cached link key matching the remote device BD_ADDR and, if
+found, the
+.Dv Link_Key_Request_Reply
+will be sent back to the device, otherwise the
+.Dv Link_Key_Request_Negative_Reply
+will be sent.
+.Pp
+.It Dv Link_Key_Notification
+When a new link key is created by the device, it will be cached for future
+use in the
+.Pa /var/db/bthcid.keys
+link keys file, which will be created if it does not already exist.
+.Pp
+.It Dv PIN_Code_Request
+The
+.Nm
+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.
+When no clients are available or the timeout has expired,
+.Nm
+will send a
+.Dv PIN_Code_Request_Negative_Reply
+back to the device.
+When a PIN is found, or if a client responds within the timeout period, a
+.Dv PIN_Code_Request_Reply
+will be sent back to the device.
+.Pp
+PINs received from clients will be cached for 5 minutes until used, and may be added
+to the cache prior to pairing with the
+.Xr btpin 1
+utility.
+.El
+.Pp
+The command line options are as follows:
+.Bl -tag -width XXXX
+.It Fl d Ar device
+Specify the local Bluetooth device address.
+The default is BDADDR_ANY.
+.It Fl f
+Run in foreground (do not detach).
+.It Fl h
+Display usage message and exit.
+.It Fl m
+Specify the file mode access bits for the PIN client socket.
+The default is to allow readwrite access to user and group (0660).
+.It Fl n
+Do not listen for PIN clients.
+.It Fl s Ar socket_name
+Specify the socket name to listen on for PIN clients.
+The default path is
+.Pa /var/run/bthcid .
+.El
+.Sh FILES
+.Bl -tag -compact
+.It Pa /var/db/bthcid.keys
+.It Pa /var/run/bthcid
+.It Pa /var/run/bthcid.pid
+.El
+.Sh SEE ALSO
+.Xr btpin 1 ,
+.Xr bluetooth 4 ,
+.Xr btconfig 8
+.Sh HISTORY
+The
+.Nm
+daemon first appeared in
+.Fx 5.3
+as
+.Ic hcsecd .
+It was ported to
+.Nx 4.0
+with its present name and extended to support PIN clients by
+.An Iain Hibbert
+under the sponsorship of Itronix, Inc.
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+.An Iain Hibbert
+.Sh BUGS
+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
new file mode 100644 (file)
index 0000000..3530c2c
--- /dev/null
@@ -0,0 +1,195 @@
+/* $NetBSD: bthcid.c,v 1.3 2007/01/25 20:33:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/bthcid/bthcid.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+/*#include <util.h>*/
+
+#include "bthcid.h"
+
+const  char    *socket_name = BTHCID_SOCKET_NAME;
+       int      detach = 1;
+
+static struct event    sighup_ev;
+static struct event    sigint_ev;
+static struct event    sigterm_ev;
+
+static void    process_signal(int, short, void *);
+static void    usage(void);
+
+int
+main(int argc, char *argv[])
+{
+       bdaddr_t        bdaddr;
+       int             ch;
+       mode_t          mode;
+
+       bdaddr_copy(&bdaddr, BDADDR_ANY);
+       mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+
+       while ((ch = getopt(argc, argv, "d:fm:ns:h")) != -1) {
+               switch (ch) {
+               case 'd':
+                       if (!bt_devaddr(optarg, &bdaddr))
+                               err(EXIT_FAILURE, "%s", optarg);
+                       break;
+
+               case 'f':
+                       detach = 0;
+                       break;
+
+               case 'm':
+                       mode = atoi(optarg);
+                       break;
+
+               case 'n':
+                       socket_name = NULL;
+                       break;
+
+               case 's':
+                       socket_name = optarg;
+                       break;
+
+               case 'h':
+               default:
+                       usage();
+                       /* NOT REACHED */
+               }
+       }
+
+       if (getuid() != 0)
+               errx(EXIT_FAILURE,
+                   "** ERROR: You should run %s as privileged user!",
+                   getprogname());
+
+       if (detach)
+               if (daemon(0, 0) < 0)
+                       err(EXIT_FAILURE, "Could not daemon()ize");
+
+       openlog(getprogname(), LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_DAEMON);
+
+       event_init();
+
+       signal_set(&sigterm_ev, SIGTERM, process_signal, NULL);
+       if (signal_add(&sigterm_ev, NULL) < 0) {
+               syslog(LOG_ERR, "signal_add(sigterm_ev)");
+               exit(EXIT_FAILURE);
+       }
+
+       signal_set(&sigint_ev, SIGINT, process_signal, NULL);
+       if (signal_add(&sigint_ev, NULL) < 0) {
+               syslog(LOG_ERR, "signal_add(sigint_ev)");
+               exit(EXIT_FAILURE);
+       }
+
+       signal_set(&sighup_ev, SIGHUP, process_signal, NULL);
+       if (signal_add(&sighup_ev, NULL) < 0) {
+               syslog(LOG_ERR, "signal_add(sighup_ev)");
+               exit(EXIT_FAILURE);
+       }
+
+       if (init_hci(&bdaddr) < 0) {
+               syslog(LOG_ERR, "init_hci(%s)", bt_ntoa(&bdaddr, NULL));
+               exit(EXIT_FAILURE);
+       }
+
+       if (init_control(socket_name, mode) < 0) {
+               syslog(LOG_ERR, "init_control(%s)", socket_name);
+               exit(EXIT_FAILURE);
+       }
+
+       if (detach && pidfile(NULL) < 0) {
+               syslog(LOG_ERR, "Could not create PID file: %m");
+               exit(EXIT_FAILURE);
+       }
+
+       read_config_file();
+       read_keys_file();
+
+       event_dispatch();
+
+       /* NOTREACHED */
+       /* gcc fodder */
+       exit(EXIT_FAILURE);
+}
+
+static void
+process_signal(int s, short e, void *arg)
+{
+       if (s == SIGHUP) {
+               syslog(LOG_DEBUG, "Got SIGHUP (%d). Dumping and rereading config", s);
+               dump_keys_file();
+               read_config_file();
+               read_keys_file();               
+               return;
+       }
+       
+
+
+       syslog(LOG_DEBUG, "Exiting on signal %d", s);
+
+       if (socket_name)
+               unlink(socket_name);
+
+       clean_config();
+       closelog();
+       exit(EXIT_FAILURE);
+
+}
+
+/* Display usage and exit */
+static void
+usage(void)
+{
+
+       fprintf(stderr,
+           "Usage: %s [-fhn] [-c config] [-d devaddr] [-m mode] [-s path]\n"
+           "Where:\n"
+           "\t-c config   specify config filename\n"
+           "\t-d device   specify device address\n"
+           "\t-f          run in foreground\n"
+           "\t-m mode     specify socket permissions\n"
+           "\t-n          do not listen for clients\n"
+           "\t-s path     specify client socket pathname\n"
+           "\t-h          display this message\n",
+           getprogname());
+
+       exit(EXIT_FAILURE);
+}
diff --git a/usr.sbin/bthcid/bthcid.conf.5 b/usr.sbin/bthcid/bthcid.conf.5
new file mode 100644 (file)
index 0000000..e4fc4a5
--- /dev/null
@@ -0,0 +1,132 @@
+.\" Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: hcsecd.conf.5,v 1.1 2003/05/26 22:49:23 max Exp $
+.\" $FreeBSD: src/usr.sbin/bluetooth/hcsecd/hcsecd.conf.5,v 1.2 2004/06/13 18:03:40 ru Exp $
+.\" $DragonFly: src/usr.sbin/bthcid/bthcid.conf.5,v 1.1 2008/01/30 14:10:19 hasso Exp $
+.\"
+.Dd May 26, 2003
+.Dt BTHCID.CONF 5
+.Os
+.Sh NAME
+.Nm bthcid.conf
+.Nd
+.Xr bthcid 8
+configuration file
+.Sh DESCRIPTION
+The
+.Nm
+file is the configuration file for the
+.Xr bthcid 8
+Bluetooth link keys/PIN codes management daemon.
+.Pp
+The
+.Nm
+file is a free-form
+.Tn ASCII
+text file.
+It is parsed by the recursive-descent parser built into
+.Xr bthcid 8 .
+The file may contain extra tabs and newlines for formatting purposes.
+Keywords in the file are case-sensitive.
+Comments may be placed anywhere within the file (except within quotes).
+Comments begin with the
+.Ql #
+character and end at the end of the line.
+.Sh FILE FORMAT
+The
+.Nm
+file consists of a list of
+.Cm device
+entries.
+Each
+.Cm device
+entry defines a link key or PIN code for a remote Bluetooth device.
+Each remote Bluetooth device is identified by its unique BD_ADDR.
+.Pp
+The
+.Cm device
+entry
+.Pp
+.Cm device
+{
+.Cm option Ar argument ;
+.Oo
+.Cm option Ar argument ;
+.Oc
+}
+.Pp
+The following section describes all supported options and arguments.
+.Bl -tag -width indent
+.It Cm bdaddr Ar BD_ADDR
+Specify remote device BD_ADDR for the entry.
+.It Cm name Ar device_name
+Specify user friendly name for the entry.
+Name is a string in straight double quotes.
+.It Cm key Ar link_key
+Specify link key for the entry.
+Link key is hexadecimal string up to 32 characters in length starting with
+.Ql 0x .
+.It Cm key nokey
+Specify no link key for the entry.
+.It Cm pin Ar PIN_code
+Specify PIN code for the entry.
+PIN code is a string up to 16 characters in length in straight double quotes.
+.It Cm pin nopin
+Specify no PIN code for the entry.
+.El
+.Sh EXAMPLES
+A sample
+.Nm
+file:
+.Bd -literal
+# Default entry is applied if no better match found
+# It MUST have 00:00:00:00:00:00 as bdaddr
+device {
+        bdaddr  00:00:00:00:00:00;
+        name    "Default entry";
+        key     nokey;
+        pin     nopin;
+}
+
+# Ericsson T68 phone
+device {
+        bdaddr  00:80:37:5e:4d:d4;
+        name    "Ericsson T68 phone";
+        key     nokey;
+        pin     "0000"; # PIN code
+}
+
+# Dummy device
+device {
+        bdaddr  00:11:22:33:44:55;
+        name    "Dummy";
+        key     0x00112233445566778899aabbccddeeff; # 16 bytes key
+        pin     nopin;
+}
+.Ed
+.Sh SEE ALSO
+.Xr bthcid 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.sbin/bthcid/bthcid.h b/usr.sbin/bthcid/bthcid.h
new file mode 100644 (file)
index 0000000..802f9d6
--- /dev/null
@@ -0,0 +1,85 @@
+/* $NetBSD: bthcid.h,v 1.3 2006/09/26 19:18:19 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/bthcid/bthcid.h,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _BTHCID_H_
+#define _BTHCID_H_     1
+
+#include <sys/queue.h>
+
+/* config.c */
+uint8_t                *lookup_key             (bdaddr_t *, bdaddr_t *);
+void            save_key               (bdaddr_t *, bdaddr_t *, uint8_t *);
+void            create_dict(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t * key);
+
+/* client.c */
+int             init_control           (const char *, mode_t);
+int             send_client_request    (bdaddr_t *, bdaddr_t *, int);
+uint8_t                *lookup_pin             (bdaddr_t *, bdaddr_t *);
+
+/* hci.c */
+int             init_hci               (bdaddr_t *);
+int             send_pin_code_reply    (int, struct sockaddr_bt *, bdaddr_t *, uint8_t *);
+
+#define BTHCID_BUFFER_SIZE     512
+#define BTHCID_IDENT           "bthcid"
+#define BTHCID_PIDFILE         "/var/run/" BTHCID_IDENT ".pid"
+#define BTHCID_KEYSFILE                "/var/db/"  BTHCID_IDENT ".keys"
+
+struct link_key
+{
+       bdaddr_t                 bdaddr; /* remote device BDADDR */
+       char                    *name;   /* remote device name */
+       uint8_t                 *key;    /* link key (or NULL if no key) */
+       char                    *pin;    /* pin (or NULL if no pin) */
+       LIST_ENTRY(link_key)     next;   /* link to the next */
+};
+typedef struct link_key                link_key_t;
+typedef struct link_key *      link_key_p;
+
+extern char    *config_file;
+
+#if __config_debug__
+void           dump_config     (void);
+#endif
+
+#ifndef bdaddr_p 
+#define bdaddr_p bdaddr_t *
+#endif
+
+void           read_config_file(void);
+void           clean_config    (void);
+link_key_p     get_key         (bdaddr_p bdaddr, int exact_match);
+
+int            read_keys_file  (void);
+int            dump_keys_file  (void);
+
+#endif /* _BTHCID_H_ */
diff --git a/usr.sbin/bthcid/client.c b/usr.sbin/bthcid/client.c
new file mode 100644 (file)
index 0000000..1646d99
--- /dev/null
@@ -0,0 +1,346 @@
+/* $NetBSD: client.c,v 1.4 2006/09/29 20:06:11 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/bthcid/client.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "bthcid.h"
+
+/*
+ * A client is anybody who connects to our control socket to
+ * receive PIN requests.
+ */
+struct client {
+       struct event            ev;
+       int                     fd;             /* client descriptor */
+       LIST_ENTRY(client)      next;
+};
+
+/*
+ * PIN cache items are made when we have sent a client pin
+ * request. The event is used to expire the item.
+ */
+struct item {
+       struct event     ev;
+       bdaddr_t         laddr;                 /* local device BDADDR */
+       bdaddr_t         raddr;                 /* remote device BDADDR */
+       uint8_t          pin[HCI_PIN_SIZE];     /* PIN */
+       int              hci;                   /* HCI socket */
+       LIST_ENTRY(item) next;
+};
+
+static struct event            control_ev;
+
+static LIST_HEAD(,client)      client_list;
+static LIST_HEAD(,item)                item_list;
+
+static void process_control    (int, short, void *);
+static void process_client     (int, short, void *);
+static void process_item       (int, short, void *);
+
+#define PIN_REQUEST_TIMEOUT    30      /* Request is valid */
+#define PIN_TIMEOUT            300     /* PIN is valid */
+
+int
+init_control(const char *name, mode_t mode)
+{
+       struct sockaddr_un      un;
+       int                     ctl;
+
+       LIST_INIT(&client_list);
+       LIST_INIT(&item_list);
+
+       if (name == NULL)
+               return 0;
+
+       if (unlink(name) < 0 && errno != ENOENT)
+               return -1;
+
+       ctl = socket(PF_LOCAL, SOCK_STREAM, 0);
+       if (ctl < 0)
+               return -1;
+
+       memset(&un, 0, sizeof(un));
+       un.sun_len = sizeof(un);
+       un.sun_family = AF_LOCAL;
+       strlcpy(un.sun_path, name, sizeof(un.sun_path));
+       if (bind(ctl, (struct sockaddr *)&un, sizeof(un)) < 0) {
+               close(ctl);
+               return -1;
+       }
+
+       if (chmod(name, mode) < 0) {
+               close(ctl);
+               unlink(name);
+               return -1;
+       }
+
+       if (listen(ctl, 10) < 0) {
+               close(ctl);
+               unlink(name);
+               return -1;
+       }
+
+       event_set(&control_ev, ctl, EV_READ | EV_PERSIST, process_control, NULL);
+       if (event_add(&control_ev, NULL) < 0) {
+               close(ctl);
+               unlink(name);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* Process control socket event */
+static void
+process_control(int sock, short ev, void *arg)
+{
+       struct sockaddr_un      un;
+       socklen_t               n;
+       int                     fd;
+       struct client           *cl;
+
+       n = sizeof(un);
+       fd = accept(sock, (struct sockaddr *)&un, &n);
+       if (fd < 0) {
+               syslog(LOG_ERR, "Could not accept PIN client connection");
+               return;
+       }
+
+       n = 1;
+       if (ioctl(fd, FIONBIO, &n) < 0) {
+               syslog(LOG_ERR, "Could not set non blocking IO for client");
+               close(fd);
+               return;
+       }
+
+       cl = malloc(sizeof(struct client));
+       if (cl == NULL) {
+               syslog(LOG_ERR, "Could not malloc client");
+               close(fd);
+               return;
+       }
+
+       memset(cl, 0, sizeof(struct client));
+       cl->fd = fd;
+
+       event_set(&cl->ev, fd, EV_READ | EV_PERSIST, process_client, cl);
+       if (event_add(&cl->ev, NULL) < 0) {
+               syslog(LOG_ERR, "Could not add client event");
+               free(cl);
+               close(fd);
+               return;
+       }
+
+       syslog(LOG_DEBUG, "New Client");
+       LIST_INSERT_HEAD(&client_list, cl, next);
+}
+
+/* Process client response packet */
+static void
+process_client(int sock, short ev, void *arg)
+{
+       bthcid_pin_response_t    rp;
+       struct timeval           tv;
+       struct sockaddr_bt       sa;
+       struct client           *cl = arg;
+       struct item             *item;
+       int                      n;
+
+       n = recv(sock, &rp, sizeof(rp), 0);
+       if (n != sizeof(rp)) {
+               if (n != 0)
+                       syslog(LOG_ERR, "Bad Client");
+
+               close(sock);
+               LIST_REMOVE(cl, next);
+               free(cl);
+
+               syslog(LOG_DEBUG, "Client Closed");
+               return;
+       }
+
+       syslog(LOG_DEBUG, "Received PIN for %s", bt_ntoa(&rp.raddr, NULL));
+
+       LIST_FOREACH(item, &item_list, next) {
+               if (bdaddr_same(&rp.laddr, &item->laddr) == 0
+                   || bdaddr_same(&rp.raddr, &item->raddr) == 0)
+                       continue;
+
+               evtimer_del(&item->ev);
+               if (item->hci != -1) {
+                       memset(&sa, 0, sizeof(sa));
+                       sa.bt_len = sizeof(sa);
+                       sa.bt_family = AF_BLUETOOTH;
+                       bdaddr_copy(&sa.bt_bdaddr, &item->laddr);
+
+                       send_pin_code_reply(item->hci, &sa, &item->raddr, rp.pin);
+                       LIST_REMOVE(item, next);
+                       free(item);
+                       return;
+               }
+               goto newpin;
+       }
+
+       item = malloc(sizeof(struct item));
+       if (item == NULL) {
+               syslog(LOG_ERR, "Item allocation failed");
+               return;
+       }
+
+       memset(item, 0, sizeof(struct item));
+       bdaddr_copy(&item->laddr, &rp.laddr);
+       bdaddr_copy(&item->raddr, &rp.raddr);
+       evtimer_set(&item->ev, process_item, item);
+       LIST_INSERT_HEAD(&item_list, item, next);
+
+newpin:
+       syslog(LOG_DEBUG, "Caching PIN for %s", bt_ntoa(&rp.raddr, NULL));
+
+       memcpy(item->pin, rp.pin, HCI_PIN_SIZE);
+       item->hci = -1;
+
+       tv.tv_sec = PIN_TIMEOUT;
+       tv.tv_usec = 0;
+
+       if (evtimer_add(&item->ev, &tv) < 0) {
+               syslog(LOG_ERR, "Cannot add event timer for item");
+               LIST_REMOVE(item, next);
+               free(item);
+       }
+}
+
+/* Send PIN request to client */
+int
+send_client_request(bdaddr_t *laddr, bdaddr_t *raddr, int hci)
+{
+       bthcid_pin_request_t     cp;
+       struct client           *cl;
+       struct item             *item;
+       int                      n = 0;
+       struct timeval           tv;
+
+       memset(&cp, 0, sizeof(cp));
+       bdaddr_copy(&cp.laddr, laddr);
+       bdaddr_copy(&cp.raddr, raddr);
+       cp.time = PIN_REQUEST_TIMEOUT;
+
+       LIST_FOREACH(cl, &client_list, next) {
+               if (send(cl->fd, &cp, sizeof(cp), 0) != sizeof(cp))
+                       syslog(LOG_ERR, "send PIN request failed");
+               else
+                       n++;
+       }
+
+       if (n == 0)
+               return 0;
+
+       syslog(LOG_DEBUG, "Sent PIN requests to %d client%s.",
+                               n, (n == 1 ? "" : "s"));
+
+       item = malloc(sizeof(struct item));
+       if (item == NULL) {
+               syslog(LOG_ERR, "Cannot allocate PIN request item");
+               return 0;
+       }
+
+       memset(item, 0, sizeof(struct item));
+       bdaddr_copy(&item->laddr, laddr);
+       bdaddr_copy(&item->raddr, raddr);
+       item->hci = hci;
+       evtimer_set(&item->ev, process_item, item);
+
+       tv.tv_sec = cp.time;
+       tv.tv_usec = 0;
+
+       if (evtimer_add(&item->ev, &tv) < 0) {
+               syslog(LOG_ERR, "Cannot add request timer");
+               free(item);
+               return 0;
+       }
+
+       LIST_INSERT_HEAD(&item_list, item, next);
+       return 1;
+}
+
+/* Process item event (by expiring it) */
+static void
+process_item(int fd, short ev, void *arg)
+{
+       struct item *item = arg;
+
+       syslog(LOG_DEBUG, "PIN for %s expired", bt_ntoa(&item->raddr, NULL));
+       LIST_REMOVE(item, next);
+       evtimer_del(&item->ev);
+       free(item);
+}
+
+/* lookup PIN in item cache */
+uint8_t *
+lookup_pin(bdaddr_t *laddr, bdaddr_t *raddr)
+{
+       static uint8_t pin[HCI_PIN_SIZE];
+       struct item *item;
+
+       LIST_FOREACH(item, &item_list, next) {
+               if (bdaddr_same(raddr, &item->raddr) == 0)
+                       continue;
+
+               if (bdaddr_same(laddr, &item->laddr) == 0
+                   && bdaddr_any(&item->laddr) == 0)
+                       continue;
+
+               if (item->hci >= 0)
+                       break;
+
+               syslog(LOG_DEBUG, "Matched PIN from cache");
+               memcpy(pin, item->pin, sizeof(pin));
+
+               LIST_REMOVE(item, next);
+               evtimer_del(&item->ev);
+               free(item);
+
+               return pin;
+       }
+
+       return NULL;
+}
diff --git a/usr.sbin/bthcid/config.c b/usr.sbin/bthcid/config.c
new file mode 100644 (file)
index 0000000..3af5c49
--- /dev/null
@@ -0,0 +1,142 @@
+/* $NetBSD: config.c,v 1.4 2007/01/25 20:33:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/bthcid/config.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/time.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "bthcid.h"
+
+static const char *key_file = "/var/db/bthcid.keys";
+static const char *new_key_file = "/var/db/bthcid.keys.new";
+
+/*
+ * 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)
+{
+       link_key_p      key = NULL;
+
+       syslog(LOG_DEBUG, "Got Link_Key_Request event from '%s', " \
+                       "remote bdaddr %s", bt_ntoa(laddr, NULL),
+                       bt_ntoa(raddr, NULL));
+
+       if ((key = get_key(raddr, 0)) != NULL) {
+               syslog(LOG_DEBUG, "Found matching entry, " \
+                               "remote bdaddr %s, name '%s', link key %s",
+                               bt_ntoa(&key->bdaddr, NULL),
+                               (key->name != NULL)? key->name : "No name",
+                               (key->key != NULL)? "exists" : "doesn't exist");
+               return key->key;
+       }
+
+       syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
+                       bt_ntoa(raddr, NULL));
+       return NULL;
+}
+
+/*
+ * Look up pin 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 pin.
+ */
+uint8_t *
+lookup_pin_conf(bdaddr_t *laddr, bdaddr_t *raddr)
+{
+       link_key_p      key = NULL;
+
+       syslog(LOG_DEBUG, "Got Link_Pin_Request event from '%s', " \
+                       "remote bdaddr %s", bt_ntoa(laddr, NULL),
+                       bt_ntoa(raddr, NULL));
+
+       if ((key = get_key(raddr, 0)) != NULL) {
+               syslog(LOG_DEBUG, "Found matching entry, " \
+                               "remote bdaddr %s, name '%s', pin %s",
+                               bt_ntoa(&key->bdaddr, NULL),
+                               (key->name != NULL)? key->name : "No name",
+                               (key->pin != NULL)? "exists" : "doesn't exist");
+               return key->pin;
+       }
+
+       syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
+                       bt_ntoa(raddr, NULL));
+       return NULL;
+}
+
+
+void
+save_key(bdaddr_t *laddr, bdaddr_t *raddr, uint8_t * key)
+{
+       link_key_p      lkey = NULL;
+
+       syslog(LOG_DEBUG, "Got Link_Key_Notification event from '%s', " \
+                       "remote bdaddr %s", bt_ntoa(laddr, NULL),
+                       bt_ntoa(raddr, NULL));
+
+       if ((lkey = get_key(raddr, 1)) == NULL) {
+               syslog(LOG_ERR, "Could not find entry for remote bdaddr %s",
+                               bt_ntoa(raddr, NULL));
+               return;
+       }
+       
+       syslog(LOG_DEBUG, "Updating link key for the entry, " \
+                       "remote bdaddr %s, name '%s', link key %s",
+                       bt_ntoa(&lkey->bdaddr, NULL),
+                       (lkey->name != NULL)? lkey->name : "No name",
+                       (lkey->key != NULL)? "exists" : "doesn't exist");
+
+       if (lkey->key == NULL) {
+               lkey->key = (uint8_t *) malloc(HCI_KEY_SIZE);
+               if (lkey->key == NULL) {
+                       syslog(LOG_ERR, "Could not allocate link key");
+                       exit(1);
+               }
+       }
+
+       memcpy(lkey->key, key, HCI_KEY_SIZE);
+
+       dump_keys_file();
+       read_config_file();
+       read_keys_file();
+       
+       return;
+}
+
diff --git a/usr.sbin/bthcid/hci.c b/usr.sbin/bthcid/hci.c
new file mode 100644 (file)
index 0000000..68333c2
--- /dev/null
@@ -0,0 +1,357 @@
+/* $NetBSD: hci.c,v 1.2 2007/01/25 20:33:41 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/bthcid/hci.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <event.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "bthcid.h"
+
+static struct event    hci_ev;
+
+static void process_hci
+               (int, short, void *);
+
+static int process_pin_code_request_event
+               (int, struct sockaddr_bt *, bdaddr_t *);
+static int process_link_key_request_event
+               (int, struct sockaddr_bt *, bdaddr_t *);
+static int process_link_key_notification_event
+               (int, struct sockaddr_bt *, hci_link_key_notification_ep *);
+
+static int send_link_key_reply
+               (int, struct sockaddr_bt *, bdaddr_t *, uint8_t *);
+static int send_hci_cmd
+               (int, struct sockaddr_bt *, uint16_t, size_t, void *);
+
+static char dev_name[HCI_DEVNAME_SIZE];
+
+/* Initialise HCI Events */
+int
+init_hci(bdaddr_t *bdaddr)
+{
+       struct sockaddr_bt      sa;
+       struct hci_filter       filter;
+       int                     hci;
+
+       hci = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (hci < 0)
+               return -1;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.bt_len = sizeof(sa);
+       sa.bt_family = AF_BLUETOOTH;
+       bdaddr_copy(&sa.bt_bdaddr, bdaddr);
+       if (bind(hci, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
+               close(hci);
+               return -1;
+       }
+
+       memset(&filter, 0, sizeof(filter));
+       hci_filter_set(HCI_EVENT_PIN_CODE_REQ, &filter);
+       hci_filter_set(HCI_EVENT_LINK_KEY_REQ, &filter);
+       hci_filter_set(HCI_EVENT_LINK_KEY_NOTIFICATION, &filter);
+
+       if (setsockopt(hci, BTPROTO_HCI, SO_HCI_EVT_FILTER,
+                       (const void *)&filter, sizeof(filter)) < 0) {
+               close(hci);
+               return -1;
+       }
+
+       event_set(&hci_ev, hci, EV_READ | EV_PERSIST, process_hci, NULL);
+       if (event_add(&hci_ev, NULL) < 0) {
+               close(hci);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* Process an HCI event */
+static void
+process_hci(int sock, short ev, void *arg)
+{
+       char                     buffer[HCI_EVENT_PKT_SIZE];
+       hci_event_hdr_t         *event = (hci_event_hdr_t *)buffer;
+       struct sockaddr_bt       addr;
+       int                      n;
+       socklen_t                size;
+
+       size = sizeof(addr);
+       n = recvfrom(sock, buffer, sizeof(buffer), 0,
+                       (struct sockaddr *) &addr, &size);
+       if (n < 0) {
+               syslog(LOG_ERR, "Could not receive from HCI socket: %m");
+               return;
+       }
+
+       if (event->type != HCI_EVENT_PKT) {
+               syslog(LOG_ERR, "Received unexpected HCI packet, "
+                               "type=%#x", event->type);
+
+               return;
+       }
+
+       if (!bt_devname(dev_name, &addr.bt_bdaddr))
+               strlcpy(dev_name, "unknown", sizeof(dev_name));
+
+       switch (event->event) {
+       case HCI_EVENT_PIN_CODE_REQ:
+               process_pin_code_request_event(sock, &addr,
+                                           (bdaddr_t *)(event + 1));
+               break;
+
+       case HCI_EVENT_LINK_KEY_REQ:
+               process_link_key_request_event(sock, &addr,
+                                           (bdaddr_t *)(event + 1));
+               break;
+
+       case HCI_EVENT_LINK_KEY_NOTIFICATION:
+               process_link_key_notification_event(sock, &addr,
+                       (hci_link_key_notification_ep *)(event + 1));
+               break;
+
+       default:
+               syslog(LOG_ERR, "Received unexpected HCI event, "
+                               "event=%#x", event->event);
+               break;
+       }
+
+       return;
+}
+
+/* Process PIN_Code_Request event */
+static int
+process_pin_code_request_event(int sock, struct sockaddr_bt *addr,
+               bdaddr_t *bdaddr)
+{
+#warning TODO: Add search pin in config file   
+
+       uint8_t *pin;
+       char    *pin2;
+
+       syslog(LOG_DEBUG, "Got PIN_Code_Request event from %s, "
+                         "remote bdaddr %s",
+                         dev_name,
+                         bt_ntoa(bdaddr, NULL));
+
+       pin = lookup_pin(&addr->bt_bdaddr, bdaddr);
+       if (pin != NULL)
+               return send_pin_code_reply(sock, addr, bdaddr, pin);
+       
+       pin2 = lookup_pin_conf(&addr->bt_bdaddr, bdaddr);
+       if (pin2 != NULL) {
+               return send_pin_code_reply(sock, addr, bdaddr, pin2);
+       }
+       
+       if (send_client_request(&addr->bt_bdaddr, bdaddr, sock) == 0)
+               return send_pin_code_reply(sock, addr, bdaddr, NULL);
+
+       return 0;
+}
+
+/* Process Link_Key_Request event */
+static int
+process_link_key_request_event(int sock, struct sockaddr_bt *addr,
+               bdaddr_t *bdaddr)
+{
+       uint8_t         *key;
+
+       syslog(LOG_DEBUG,
+               "Got Link_Key_Request event from %s, remote bdaddr %s",
+               dev_name, bt_ntoa(bdaddr, NULL));
+
+       key = lookup_key(&addr->bt_bdaddr, bdaddr);
+
+       if (key != NULL) {
+               syslog(LOG_DEBUG, "Found Key, remote bdaddr %s",
+                               bt_ntoa(bdaddr, NULL));
+
+               return send_link_key_reply(sock, addr, bdaddr, key);
+       }
+
+       syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
+                       bt_ntoa(bdaddr, NULL));
+
+       return send_link_key_reply(sock, addr, bdaddr, NULL);
+}
+
+/* Send PIN_Code_[Negative]_Reply */
+int
+send_pin_code_reply(int sock, struct sockaddr_bt *addr,
+       bdaddr_t *bdaddr, uint8_t *pin)
+{
+       int     n;
+
+       if (pin != NULL) {
+               hci_pin_code_rep_cp      cp;
+
+               syslog(LOG_DEBUG, "Sending PIN_Code_Reply to %s "
+                                 "for remote bdaddr %s",
+                                 dev_name,
+                                 bt_ntoa(bdaddr, NULL));
+
+               bdaddr_copy(&cp.bdaddr, bdaddr);
+               memcpy(cp.pin, pin, HCI_PIN_SIZE);
+
+               n = HCI_PIN_SIZE;
+               while (n > 0 && pin[n - 1] == 0)
+                       n--;
+               cp.pin_size = n;
+
+               n = send_hci_cmd(sock, addr,
+                               HCI_CMD_PIN_CODE_REP, sizeof(cp), &cp);
+
+       } else {
+               syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to %s "
+                                 "for remote bdaddr %s",
+                                 dev_name,
+                                 bt_ntoa(bdaddr, NULL));
+
+               n = send_hci_cmd(sock, addr, HCI_CMD_PIN_CODE_NEG_REP,
+                                       sizeof(bdaddr_t), bdaddr);
+       }
+
+       if (n < 0) {
+               syslog(LOG_ERR, "Could not send PIN code reply to %s "
+                               "for remote bdaddr %s: %m",
+                               dev_name,
+                               bt_ntoa(bdaddr, NULL));
+
+               return -1;
+       }
+
+       return 0;
+}
+
+/* Send Link_Key_[Negative]_Reply */
+static int
+send_link_key_reply(int sock, struct sockaddr_bt *addr,
+               bdaddr_t *bdaddr, uint8_t *key)
+{
+       int     n;
+
+       if (key != NULL) {
+               hci_link_key_rep_cp     cp;
+
+               bdaddr_copy(&cp.bdaddr, bdaddr);
+               memcpy(&cp.key, key, sizeof(cp.key));
+
+               syslog(LOG_DEBUG, "Sending Link_Key_Reply to %s "
+                               "for remote bdaddr %s",
+                               dev_name, bt_ntoa(bdaddr, NULL));
+
+               n = send_hci_cmd(sock, addr, HCI_CMD_LINK_KEY_REP, sizeof(cp), &cp);
+       } else {
+               hci_link_key_neg_rep_cp cp;
+
+               bdaddr_copy(&cp.bdaddr, bdaddr);
+
+               syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to %s "
+                               "for remote bdaddr %s",
+                               dev_name, bt_ntoa(bdaddr, NULL));
+
+               n = send_hci_cmd(sock, addr, HCI_CMD_LINK_KEY_NEG_REP, sizeof(cp), &cp);
+       }
+
+       if (n < 0) {
+               syslog(LOG_ERR, "Could not send link key reply to %s "
+                               "for remote bdaddr %s: %m",
+                               dev_name, bt_ntoa(bdaddr, NULL));
+               return -1;
+       }
+
+       return 0;
+}
+
+/* Process Link_Key_Notification event */
+static int
+process_link_key_notification_event(int sock, struct sockaddr_bt *addr,
+               hci_link_key_notification_ep *ep)
+{
+
+       syslog(LOG_DEBUG, "Got Link_Key_Notification event from %s, "
+                       "remote bdaddr %s",
+                       dev_name,
+                       bt_ntoa(&ep->bdaddr, NULL));
+
+       save_key(&addr->bt_bdaddr, &ep->bdaddr, ep->key);
+       return 0;
+}
+
+/* Send HCI Command Packet to socket */
+static int
+send_hci_cmd(int sock, struct sockaddr_bt *sa, uint16_t opcode, size_t len, void *buf)
+{
+       char msg[HCI_CMD_PKT_SIZE];
+       hci_cmd_hdr_t *h = (hci_cmd_hdr_t *)msg;
+
+       h->type = HCI_CMD_PKT;
+       h->opcode = htole16(opcode);
+       h->length = len;
+
+       if (len > 0)
+               memcpy(msg + sizeof(hci_cmd_hdr_t), buf, len);
+
+       return sendto(sock, msg, sizeof(hci_cmd_hdr_t) + len, 0,
+                       (struct sockaddr *)sa, sizeof(*sa));
+}
diff --git a/usr.sbin/bthcid/lexer.l b/usr.sbin/bthcid/lexer.l
new file mode 100644 (file)
index 0000000..8edee72
--- /dev/null
@@ -0,0 +1,96 @@
+%{
+/*
+ * lexer.l
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: lexer.l,v 1.1 2002/11/24 20:22:39 max Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/hcsecd/lexer.l,v 1.1 2003/05/10 21:50:35 julian Exp $
+ * $DragonFly: src/usr.sbin/bthcid/lexer.l,v 1.1 2008/01/30 14:10:19 hasso Exp $
+ */
+
+#include <string.h>
+#include "parser.h"
+%}
+
+%option yylineno noyywrap nounput
+
+delim          [ \t\n]
+ws             {delim}+
+empty          {delim}*
+comment                \#.*
+
+hexdigit       [0-9a-fA-F]
+hexbyte                {hexdigit}{hexdigit}
+
+device_word    device
+bdaddr_word    bdaddr
+name_word      name
+key_word       key
+nokey_word     nokey
+pin_word       pin
+nopin_word     nopin
+
+bdaddrstring   {hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}:{hexbyte}
+hexstring      0x{hexbyte}+
+string         \".+\"
+
+%%
+
+\;             return (';');
+\:             return (':');
+\{             return ('{');
+\}             return ('}');
+
+{ws}           ;
+{empty}                ;
+{comment}      ;
+
+{device_word}  return (T_DEVICE);
+{bdaddr_word}  return (T_BDADDR);
+{name_word}    return (T_NAME);
+{key_word}     return (T_KEY);
+{nokey_word}   return (T_NOKEY);
+{pin_word}     return (T_PIN);
+{nopin_word}   return (T_NOPIN);
+
+{bdaddrstring} {
+               yylval.string = yytext;
+               return (T_BDADDRSTRING);
+               }
+
+{hexstring}    {
+               yylval.string = &yytext[2];
+               return (T_HEXSTRING);
+               }
+
+{string}       {
+               yytext[strlen(yytext) - 1] = 0;
+               yylval.string = &yytext[1];
+               return (T_STRING);
+               }
+
+%%
+
diff --git a/usr.sbin/bthcid/parser.y b/usr.sbin/bthcid/parser.y
new file mode 100644 (file)
index 0000000..1565c54
--- /dev/null
@@ -0,0 +1,434 @@
+%{
+/*
+ * parser.y
+ *
+ * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: parser.y,v 1.5 2003/06/07 21:22:30 max Exp $
+ * $FreeBSD: src/usr.sbin/bluetooth/hcsecd/parser.y,v 1.4 2004/09/14 20:04:33 emax Exp $
+ * $DragonFly: src/usr.sbin/bthcid/parser.y,v 1.1 2008/01/30 14:10:19 hasso Exp $
+ */
+
+#include <sys/fcntl.h>
+#include <sys/queue.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "bthcid.h"
+
+       int     yyparse  (void);
+       int     yylex    (void);
+
+static void    free_key (link_key_p key);
+static int     hexa2int4(char *a);
+static int     hexa2int8(char *a);
+
+extern int                      yylineno;
+static LIST_HEAD(, link_key)    link_keys;
+       char                    *config_file = "/etc/bluetooth/bthcid.conf";
+
+static link_key_p               key = NULL;
+%}
+
+%union {
+       char    *string;
+}
+
+%token <string> T_BDADDRSTRING T_HEXSTRING T_STRING
+%token T_DEVICE T_BDADDR T_NAME T_KEY T_PIN T_NOKEY T_NOPIN T_JUNK
+
+%%
+
+config:                line
+               | config line
+               ;
+
+line:          T_DEVICE
+                       {
+                       key = (link_key_p) malloc(sizeof(*key));
+                       if (key == NULL) {
+                               syslog(LOG_ERR, "Could not allocate new " \
+                                               "config entry");
+                               exit(1);
+                       }
+
+                       memset(key, 0, sizeof(*key));
+                       }
+               '{' options '}'
+                       {
+                       if (get_key(&key->bdaddr, 1) != NULL) {
+                               syslog(LOG_ERR, "Ignoring duplicated entry " \
+                                               "for bdaddr %s",
+                                               bt_ntoa(&key->bdaddr, NULL));
+                               free_key(key);
+                       } else 
+                               LIST_INSERT_HEAD(&link_keys, key, next);
+
+                       key = NULL;
+                       }
+               ;
+
+options:       option ';'
+               | options option ';'
+               ;
+
+option:                bdaddr
+               | name
+               | key
+               | pin
+               ;
+
+bdaddr:                T_BDADDR T_BDADDRSTRING
+                       {
+                       if (!bt_aton($2, &key->bdaddr)) {
+                               syslog(LOG_ERR, "Cound not parse BD_ADDR " \
+                                               "'%s'", $2);
+                               exit(1);
+                       }
+                       }
+               ;
+
+name:          T_NAME T_STRING
+                       {
+                       if (key->name != NULL)
+                               free(key->name);
+
+                       key->name = strdup($2);
+                       if (key->name == NULL) {
+                               syslog(LOG_ERR, "Could not allocate new " \
+                                               "device name");
+                               exit(1);
+                       }
+                       }
+               ;
+
+key:           T_KEY T_HEXSTRING
+                       {
+                       int     i, len;
+
+                       if (key->key != NULL)
+                               free(key->key);
+
+                       key->key = (uint8_t *) malloc(HCI_KEY_SIZE);
+                       if (key->key == NULL) {
+                               syslog(LOG_ERR, "Could not allocate new " \
+                                               "link key");
+                               exit(1);
+                       }
+
+                       memset(key->key, 0, HCI_KEY_SIZE);
+
+                       len = strlen($2) / 2;
+                       if (len > HCI_KEY_SIZE)
+                               len = HCI_KEY_SIZE;
+
+                       for (i = 0; i < len; i ++)
+                               key->key[i] = hexa2int8((char *)($2) + 2*i);
+                       }
+               | T_KEY T_NOKEY
+                       {
+                       if (key->key != NULL)
+                               free(key->key);
+
+                       key->key = NULL;
+                       }
+               ;
+
+pin:           T_PIN T_STRING
+                       {
+                       if (key->pin != NULL)
+                               free(key->pin);
+
+                       key->pin = strdup($2);
+                       if (key->pin == NULL) {
+                               syslog(LOG_ERR, "Could not allocate new " \
+                                               "PIN code");
+                               exit(1);
+                       }
+                       }
+               | T_PIN T_NOPIN
+                       {
+                       if (key->pin != NULL)
+                               free(key->pin);
+
+                       key->pin = NULL;
+                       }
+               ;
+
+%%
+
+/* Display parser error message */
+void
+yyerror(char const *message)
+{
+       syslog(LOG_ERR, "%s in line %d", message, yylineno);
+}
+
+/* Re-read config file */
+void
+read_config_file(void)
+{
+       extern FILE     *yyin;
+
+       if (config_file == NULL) {
+               syslog(LOG_ERR, "Unknown config file name!");
+               exit(1);
+       }
+
+       if ((yyin = fopen(config_file, "r")) == NULL) {
+               syslog(LOG_ERR, "Could not open config file '%s'. %s (%d)",
+                               config_file, strerror(errno), errno);
+               exit(1);
+       }
+
+       clean_config();
+       if (yyparse() < 0) {
+               syslog(LOG_ERR, "Could not parse config file '%s'",config_file);
+               exit(1);
+       }
+
+       fclose(yyin);
+       yyin = NULL;
+
+#if __config_debug__
+       dump_config();
+#endif
+}
+
+/* Clean config */
+void
+clean_config(void)
+{
+       link_key_p      key = NULL;
+
+       while ((key = LIST_FIRST(&link_keys)) != NULL) {
+               LIST_REMOVE(key, next);
+               free_key(key);
+       }
+}
+
+/* Find link key entry in the list. Return exact or default match */
+link_key_p
+get_key(bdaddr_p bdaddr, int exact_match)
+{
+       link_key_p      key = NULL, defkey = NULL;
+
+       LIST_FOREACH(key, &link_keys, next) {
+               if (memcmp(bdaddr, &key->bdaddr, sizeof(key->bdaddr)) == 0)
+                       break;
+
+               if (!exact_match)
+                       if (memcmp(BDADDR_ANY, &key->bdaddr,
+                                       sizeof(key->bdaddr)) == 0)
+                               defkey = key;
+       }
+
+       return ((key != NULL)? key : defkey);
+}
+
+#if __config_debug__
+/* Dump config */
+void
+dump_config(void)
+{
+       link_key_p      key = NULL;
+       char            buffer[64];
+
+       LIST_FOREACH(key, &link_keys, next) {
+               if (key->key != NULL)
+                       snprintf(buffer, sizeof(buffer),
+"0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+                               key->key[0], key->key[1], key->key[2],
+                               key->key[3], key->key[4], key->key[5],
+                               key->key[6], key->key[7], key->key[8],
+                               key->key[9], key->key[10], key->key[11],
+                               key->key[12], key->key[13], key->key[14],
+                               key->key[15]);
+
+               syslog(LOG_DEBUG, 
+"device %s " \
+"bdaddr %s " \
+"pin %s " \
+"key %s",
+                       (key->name != NULL)? key->name : "noname",
+                       bt_ntoa(&key->bdaddr, NULL),
+                       (key->pin != NULL)? key->pin : "nopin",
+                       (key->key != NULL)? buffer : "nokey");
+       }
+}
+#endif
+
+/* Read keys file */
+int
+read_keys_file(void)
+{
+       FILE            *f = NULL;
+       link_key_t      *key = NULL;
+       char             buf[BTHCID_BUFFER_SIZE], *p = NULL, *cp = NULL;
+       bdaddr_t         bdaddr;
+       int              i, len;
+
+       if ((f = fopen(BTHCID_KEYSFILE, "r")) == NULL) {
+               if (errno == ENOENT)
+                       return (0);
+
+               syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n",
+                               BTHCID_KEYSFILE, strerror(errno), errno);
+
+               return (-1);
+       }
+
+       while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
+               if (*p == '#')
+                       continue;
+               if ((cp = strpbrk(p, " ")) == NULL)
+                       continue;
+
+               *cp++ = '\0';
+
+               if (!bt_aton(p, &bdaddr))
+                       continue;
+
+               if ((key = get_key(&bdaddr, 1)) == NULL)
+                       continue;
+
+               if (key->key == NULL) {
+                       key->key = (uint8_t *) malloc(HCI_KEY_SIZE);
+                       if (key->key == NULL) {
+                               syslog(LOG_ERR, "Could not allocate link key");
+                               exit(1);
+                       }
+               }
+
+               memset(key->key, 0, HCI_KEY_SIZE);
+
+               len = strlen(cp) / 2;
+               if (len > HCI_KEY_SIZE)
+                       len = HCI_KEY_SIZE;
+
+               for (i = 0; i < len; i ++)
+                       key->key[i] = hexa2int8(cp + 2*i);
+
+               syslog(LOG_DEBUG, "Restored link key for the entry, " \
+                               "remote bdaddr %s, name '%s'",
+                               bt_ntoa(&key->bdaddr, NULL),
+                               (key->name != NULL)? key->name : "No name");
+       }
+
+       fclose(f);
+
+       return (0);
+}
+
+/* Dump keys file */
+int
+dump_keys_file(void)
+{
+       link_key_p      key = NULL;
+       char            tmp[PATH_MAX], buf[BTHCID_BUFFER_SIZE];
+       int             f;
+
+       snprintf(tmp, sizeof(tmp), "%s.tmp", BTHCID_KEYSFILE);
+       if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) {
+               syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n",
+                               tmp, strerror(errno), errno);
+               return (-1);
+       }
+
+       LIST_FOREACH(key, &link_keys, next) {
+               if (key->key == NULL)
+                       continue;
+
+               snprintf(buf, sizeof(buf),
+"%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                       bt_ntoa(&key->bdaddr, NULL),
+                       key->key[0],  key->key[1],  key->key[2],  key->key[3],
+                       key->key[4],  key->key[5],  key->key[6],  key->key[7],
+                       key->key[8],  key->key[9],  key->key[10], key->key[11],
+                       key->key[12], key->key[13], key->key[14], key->key[15]);
+
+               if (write(f, buf, strlen(buf)) < 0) {
+                       syslog(LOG_ERR, "Could not write temp keys file. " \
+                                       "%s (%d)\n", strerror(errno), errno);
+                       break;
+               }
+       }
+
+       close(f);
+
+       if (rename(tmp, BTHCID_KEYSFILE) < 0) {
+               syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n",
+                               tmp, BTHCID_KEYSFILE, strerror(errno), errno);
+               unlink(tmp);
+               return (-1);
+       }
+
+       return (0);
+}
+
+/* Free key entry */
+static void
+free_key(link_key_p key)
+{
+       if (key->name != NULL)
+               free(key->name);
+       if (key->key != NULL)
+               free(key->key);
+       if (key->pin != NULL)
+               free(key->pin);
+
+       memset(key, 0, sizeof(*key));
+       free(key);
+}
+
+/* Convert hex ASCII to int4 */
+static int
+hexa2int4(char *a)
+{
+       if ('0' <= *a && *a <= '9')
+               return (*a - '0');
+
+       if ('A' <= *a && *a <= 'F')
+               return (*a - 'A' + 0xa);
+
+       if ('a' <= *a && *a <= 'f')
+               return (*a - 'a' + 0xa);
+
+       syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a);
+       exit(1);
+}
+
+/* Convert hex ASCII to int8 */
+static int
+hexa2int8(char *a)
+{
+       return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
+}
+
diff --git a/usr.sbin/btpin/Makefile b/usr.sbin/btpin/Makefile
new file mode 100644 (file)
index 0000000..9e3ba9e
--- /dev/null
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.2 2006/09/26 19:18:19 plunky Exp $
+# $DragonFly: src/usr.sbin/btpin/Attic/Makefile,v 1.1 2008/01/30 14:10:19 hasso Exp $
+
+PROG=          btpin
+SRCS=          btpin.c
+MAN=           btpin.1
+
+CFLAGS+=       -I${.CURDIR}/../../sys
+DPADD+=                ${LIBBLUETOOTH}
+LDADD+=                -lbluetooth
+WARNS?=                6
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/btpin/btpin.1 b/usr.sbin/btpin/btpin.1
new file mode 100644 (file)
index 0000000..5e91c2f
--- /dev/null
@@ -0,0 +1,92 @@
+.\" $NetBSD: btpin.1,v 1.6 2007/09/24 19:29:01 plunky Exp $
+.\" $DragonFly: src/usr.sbin/btpin/Attic/btpin.1,v 1.1 2008/01/30 14:10:19 hasso Exp $
+.\"
+.\" Copyright (c) 2006 Itronix Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. The name of Itronix Inc. may not be used to endorse
+.\"    or promote products derived from this software without specific
+.\"    prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+.\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+.\" ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd September 24, 2007
+.Dt BTPIN 1
+.Os
+.Sh NAME
+.Nm btpin
+.Nd Bluetooth PIN utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl d Ar device
+.Op Fl s Ar path
+.Brq Fl p Ar pin | Fl r Op Fl l Ar len
+.Fl a Ar address
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to register a temporary PIN with the
+.Xr bthcid 8
+daemon for the purposes of pairing Bluetooth devices.
+The PIN will be valid for 5 minutes or until used, whichever comes first.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a Ar address
+Specify the remote device address.
+The address can be specified as BD_ADDR or a name.
+If a name was specified, the
+.Nm
+utility attempts to resolve the name via
+.Xr bt_gethostbyname 3 .
+.It Fl d Ar device
+Specify the local device address.
+The device can be specified by BD_ADDR or device name.
+See
+.Xr btconfig 8
+for a list of devices available.
+If no device is specified, the PIN will be valid for any local device.
+.It Fl l Ar len
+Specify length of PIN to generate, where 1 \*[Le]
+.Ar len
+\*[Le] 16.
+.It Fl p Ar pin
+The PIN to register.
+The PIN may be up to 16 bytes in length.
+.It Fl r
+Generate a random PIN, the default length is 4 bytes.
+.It Fl s Ar path
+Specify path to the control socket.
+The default path is
+.Pa /var/run/bthcid .
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh FILES
+.Bl -tag -compact
+.Pa /var/run/bthcid
+.El
+.Sh SEE ALSO
+.Xr btconfig 8 ,
+.Xr bthcid 8
+.Sh AUTHORS
+.An Iain Hibbert
+for Itronix, Inc
diff --git a/usr.sbin/btpin/btpin.c b/usr.sbin/btpin/btpin.c
new file mode 100644 (file)
index 0000000..c0a3ea6
--- /dev/null
@@ -0,0 +1,153 @@
+/* $NetBSD: btpin.c,v 1.3 2007/04/14 09:28:39 plunky Exp $ */
+/* $DragonFly: src/usr.sbin/btpin/Attic/btpin.c,v 1.1 2008/01/30 14:10:19 hasso Exp $ */
+
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Iain Hibbert for Itronix Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Itronix Inc. may not be used to endorse
+ *    or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/un.h>
+#include <bluetooth.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+int  main(int, char *[]);
+void usage(void);
+
+int
+main(int ac, char *av[])
+{
+       bthcid_pin_response_t rp;
+       struct sockaddr_un un;
+       char *pin = NULL;
+       int ch, s, len;
+
+       memset(&rp, 0, sizeof(rp));
+       len = -1;
+
+       memset(&un, 0, sizeof(un));
+       un.sun_len = sizeof(un);
+       un.sun_family = AF_LOCAL;
+       strlcpy(un.sun_path, BTHCID_SOCKET_NAME, sizeof(un.sun_path));
+
+       while ((ch = getopt(ac, av, "a:d:l:p:rs:")) != EOF) {
+               switch (ch) {
+               case 'a':
+                       if (!bt_aton(optarg, &rp.raddr)) {
+                               struct hostent  *he = NULL;
+
+                               if ((he = bt_gethostbyname(optarg)) == NULL)
+                                       errx(EXIT_FAILURE, "%s: %s", optarg,
+                                                       hstrerror(h_errno));
+
+                               bdaddr_copy(&rp.raddr, (bdaddr_t *)he->h_addr);
+                       }
+                       break;
+
+               case 'd':
+                       if (!bt_devaddr(optarg, &rp.laddr))
+                               err(EXIT_FAILURE, "%s", optarg);
+
+                       break;
+
+               case 'l':
+                       len = atoi(optarg);
+                       if (len < 1 || len > HCI_PIN_SIZE)
+                               errx(EXIT_FAILURE, "Invalid PIN length");
+
+                       break;
+
+               case 'p':
+                       pin = optarg;
+                       break;
+
+               case 'r':
+                       if (len == -1)
+                               len = 4;
+
+                       break;
+
+               case 's':
+                       strlcpy(un.sun_path, optarg, sizeof(un.sun_path));
+                       break;
+
+               default:
+                       usage();
+               }
+       }
+
+       if (bdaddr_any(&rp.raddr))
+               usage();
+
+       if (pin == NULL) {
+               if (len == -1)
+                       usage();
+
+               srandom(time(NULL));
+
+               pin = (char *)rp.pin;
+               while (len-- > 0)
+                       *pin++ = '0' + (random() % 10);
+
+               printf("PIN: %.*s\n", HCI_PIN_SIZE, rp.pin);
+       } else {
+               if (len != -1)
+                       usage();
+
+               strncpy((char *)rp.pin, pin, HCI_PIN_SIZE);
+       }
+
+       s = socket(PF_LOCAL, SOCK_STREAM, 0);
+       if (s < 0)
+               err(EXIT_FAILURE, "socket");
+
+       if (connect(s, (struct sockaddr *)&un, sizeof(un)) < 0)
+               err(EXIT_FAILURE, "connect(\"%s\")", un.sun_path);
+       
+       if (send(s, &rp, sizeof(rp), 0) != sizeof(rp))
+               err(EXIT_FAILURE, "send");
+
+       close(s);
+       exit(EXIT_SUCCESS);
+}
+
+void
+usage(void)
+{
+
+       fprintf(stderr,
+               "usage: %s [-d device] [-s socket] {-p pin | -r [-l len]} -a addr\n"
+               "", getprogname());
+
+       exit(EXIT_FAILURE);
+}