From: Hasso Tepper Date: Wed, 30 Jan 2008 14:10:19 +0000 (+0000) Subject: Add bthcid(8) - Bluetooth Link Key/PIN Code Manager and btpin(1) Bluetooth X-Git-Tag: v2.0.1~1240 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/2b25616984972531b2d090f762ea61df7c5d1ab0 Add bthcid(8) - Bluetooth Link Key/PIN Code Manager and btpin(1) Bluetooth PIN utility. Obtained-from: NetBSD with modifications --- diff --git a/etc/bluetooth/bthcid.conf b/etc/bluetooth/bthcid.conf new file mode 100644 index 0000000000..0aaf4c5fa4 --- /dev/null +++ b/etc/bluetooth/bthcid.conf @@ -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; +# } + diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index eae5c63447..dc5274d021 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -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 @@ -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 index 0000000000..a8b67aad26 --- /dev/null +++ b/etc/rc.d/bthcid @@ -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" diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index a33b7b8d6f..4a6e368afb 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -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 index 0000000000..fd67c17665 --- /dev/null +++ b/usr.sbin/bthcid/Makefile @@ -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 diff --git a/usr.sbin/bthcid/bthcid.8 b/usr.sbin/bthcid/bthcid.8 new file mode 100644 index 0000000000..2168e25854 --- /dev/null +++ b/usr.sbin/bthcid/bthcid.8 @@ -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 +.\" 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 index 0000000000..3530c2c443 --- /dev/null +++ b/usr.sbin/bthcid/bthcid.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include */ + +#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 index 0000000000..e4fc4a5218 --- /dev/null +++ b/usr.sbin/bthcid/bthcid.conf.5 @@ -0,0 +1,132 @@ +.\" Copyright (c) 2001-2002 Maksim Yevmenkin +.\" 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 index 0000000000..802f9d6975 --- /dev/null +++ b/usr.sbin/bthcid/bthcid.h @@ -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 + +/* 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 index 0000000000..1646d992ac --- /dev/null +++ b/usr.sbin/bthcid/client.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..3af5c49c6d --- /dev/null +++ b/usr.sbin/bthcid/config.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..68333c2e4f --- /dev/null +++ b/usr.sbin/bthcid/hci.c @@ -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 + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000000..8edee72bf9 --- /dev/null +++ b/usr.sbin/bthcid/lexer.l @@ -0,0 +1,96 @@ +%{ +/* + * lexer.l + * + * Copyright (c) 2001-2002 Maksim Yevmenkin + * 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 +#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 index 0000000000..1565c54ecb --- /dev/null +++ b/usr.sbin/bthcid/parser.y @@ -0,0 +1,434 @@ +%{ +/* + * parser.y + * + * Copyright (c) 2001-2002 Maksim Yevmenkin + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 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 index 0000000000..9e3ba9e7a9 --- /dev/null +++ b/usr.sbin/btpin/Makefile @@ -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 diff --git a/usr.sbin/btpin/btpin.1 b/usr.sbin/btpin/btpin.1 new file mode 100644 index 0000000000..5e91c2f473 --- /dev/null +++ b/usr.sbin/btpin/btpin.1 @@ -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 index 0000000000..c0a3ea6ba4 --- /dev/null +++ b/usr.sbin/btpin/btpin.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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); +}