summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bluetooth/hcsecd
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2003-05-10 21:50:37 +0000
committerjulian <julian@FreeBSD.org>2003-05-10 21:50:37 +0000
commitfe2526340b1a2d7ed079617d2eca31aa6425d937 (patch)
tree6e0dee485a2a2757ceb37dde12c1fa3ef410e6b7 /usr.sbin/bluetooth/hcsecd
parentdc5734d94b071df224b65d45b95d9ae7c5d563ab (diff)
downloadFreeBSD-src-fe2526340b1a2d7ed079617d2eca31aa6425d937.zip
FreeBSD-src-fe2526340b1a2d7ed079617d2eca31aa6425d937.tar.gz
Part 2 of the commit if new bluetooth code.
Submitted by: Maksim Yevmenkin <m_evmenkin@yahoo.com> Approved by: re@
Diffstat (limited to 'usr.sbin/bluetooth/hcsecd')
-rw-r--r--usr.sbin/bluetooth/hcsecd/Makefile12
-rw-r--r--usr.sbin/bluetooth/hcsecd/hcsecd.8101
-rw-r--r--usr.sbin/bluetooth/hcsecd/hcsecd.c422
-rw-r--r--usr.sbin/bluetooth/hcsecd/hcsecd.conf64
-rw-r--r--usr.sbin/bluetooth/hcsecd/hcsecd.h57
-rw-r--r--usr.sbin/bluetooth/hcsecd/lexer.l95
-rw-r--r--usr.sbin/bluetooth/hcsecd/parser.y339
7 files changed, 1090 insertions, 0 deletions
diff --git a/usr.sbin/bluetooth/hcsecd/Makefile b/usr.sbin/bluetooth/hcsecd/Makefile
new file mode 100644
index 0000000..886010b
--- /dev/null
+++ b/usr.sbin/bluetooth/hcsecd/Makefile
@@ -0,0 +1,12 @@
+# $Id: Makefile,v 1.2 2003/03/15 03:07:42 max Exp $
+# $FreeBSD$
+
+DESTDIR= /usr/sbin/
+MANDIR= ../share/man/man
+PROG= hcsecd
+MAN8= hcsecd.8
+WARNS?= 1
+CFLAGS+= -g -I${.CURDIR}/../../../sys/netgraph/bluetooth/include
+SRCS= hcsecd.c lexer.l parser.y
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/hcsecd/hcsecd.8 b/usr.sbin/bluetooth/hcsecd/hcsecd.8
new file mode 100644
index 0000000..880ee1c
--- /dev/null
+++ b/usr.sbin/bluetooth/hcsecd/hcsecd.8
@@ -0,0 +1,101 @@
+.\" hcsecd.8
+.\"
+.\" 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.8,v 1.3 2003/04/27 19:45:32 max Exp $
+.\" $FreeBSD$
+.Dd November 16, 2002
+.Dt HCSECD 8
+.Os
+.Sh NAME
+.Nm hcsecd
+.Nd control link keys and PIN codes for Bluetooth devices
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar configfile
+.Op Fl d
+.Op Fl h
+.Sh DESCRIPTION
+The
+.Nm
+daemon controls link keys and PIN code for Bluetooth devices. It opens raw
+HCI socket and listens for the
+.Dv Link_Key_Request
+and
+.Dv PIN_Code_Request
+HCI events. Once appropriate HCI event has been received, the daemon will
+scan configuration file for matching entry. The remove device BD_ADDR is used
+as a key. If no matching entry was found then the default entry will be used.
+If no default entry was found than it is assumed no link key and no PIN code
+exist. For any given entry link key takes precedence over PIN code. If link key
+was not specified then it means device must generate link key from PIN code. If
+entry was found and has the link key (or PIN code) then
+the
+.Dv Link_Key_Request_Reply
+(or
+.Dv PIN_Code_Request_Reply
+) command will be sent back to the device. Otherwise the
+.Dv Link_Key_Request_Negative_Reply
+(or
+.Dv PIN_Code_Request_Negative_Reply
+) command will be sent back to the device.
+.Pp
+The
+.Nm
+daemon currently does not handle HCI
+.Dv Link_Key_Notification
+event and does not cache link keys created from the PIN codes. It means
+that the link key only exists while connection is opened. After the connection
+has been terminated the user will have to enter PIN code again.
+.Pp
+The command line options are as follows:
+.Bl -tag -width Ds
+.It Fl f Ar filename
+Name of configuration file. Default is
+.Pa /usr/local/etc/hcsecd.conf .
+.It Fl d
+Do not detach from the controlling terminal.
+.It Fl h
+Display usage message and exit.
+.El
+.Sh BUGS
+Currently there is no way to select link key or PIN code based on which local
+device received the request. Everything is based on remote device BD_ADDR.
+Also might implement interface for external helpers to obtain link keys and
+PIN codes.
+.Sh FILES
+.Bl -tag -width /etc/usbd.conf -compact
+.It Pa /usr/local/etc/hcsecd.conf
+.It Pa /var/run/hcsecd.pid
+.El
+.Sh SEE ALSO
+.Xr netgraph 3 ,
+.Xr netgraph 4 ,
+.Xr ng_hci 4 ,
+.Xr ng_btsocket 4 ,
+.Xr hccontrol 8 ,
+.Xr hcseriald 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
diff --git a/usr.sbin/bluetooth/hcsecd/hcsecd.c b/usr.sbin/bluetooth/hcsecd/hcsecd.c
new file mode 100644
index 0000000..0f72eb7
--- /dev/null
+++ b/usr.sbin/bluetooth/hcsecd/hcsecd.c
@@ -0,0 +1,422 @@
+/*
+ * hcsecd.c
+ *
+ * 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.c,v 1.3 2003/04/27 19:45:32 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <bitstring.h>
+#include <err.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <ng_l2cap.h>
+#include <ng_btsocket.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "hcsecd.h"
+
+#define HCSECD_BUFFER_SIZE 512
+#define HCSECD_IDENT "hcsecd"
+#define HCSECD_PIDFILE "/var/run/" HCSECD_IDENT ".pid"
+
+static int done = 0;
+
+static int process_pin_code_request_event
+ (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
+static int process_link_key_request_event
+ (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
+static int send_pin_code_reply
+ (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, char const *pin);
+static int send_link_key_reply
+ (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, u_int8_t *key);
+static void sigint
+ (int s);
+static void usage
+ (void);
+
+/* Main */
+int
+main(int argc, char *argv[])
+{
+ int n, detach, sock, size;
+ struct sigaction sa;
+ struct sockaddr_hci addr;
+ struct ng_btsocket_hci_raw_filter filter;
+ char buffer[HCSECD_BUFFER_SIZE];
+ ng_hci_event_pkt_t *event = NULL;
+
+ detach = 1;
+
+ while ((n = getopt(argc, argv, "df:h")) != -1) {
+ switch (n) {
+ case 'd':
+ detach = 0;
+ break;
+
+ case 'f':
+ config_file = optarg;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ /* NOT REACHED */
+ }
+ }
+
+ if (config_file == NULL)
+ usage();
+ /* NOT REACHED */
+
+ if (getuid() != 0)
+ errx(1, "** ERROR: You should run %s as privileged user!",
+ HCSECD_IDENT);
+
+ /* Set signal handlers */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sigint;
+ sa.sa_flags = SA_NOCLDWAIT;
+ if (sigaction(SIGINT, &sa, NULL) < 0)
+ err(1, "Could not sigaction(SIGINT)");
+ if (sigaction(SIGTERM, &sa, NULL) < 0)
+ err(1, "Could not sigaction(SIGINT)");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = read_config_file;
+ if (sigaction(SIGHUP, &sa, NULL) < 0)
+ err(1, "Could not sigaction(SIGHUP)");
+
+ /* Open socket and set filter */
+ sock = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
+ if (sock < 0)
+ err(1, "Could not create HCI socket");
+
+ memset(&filter, 0, sizeof(filter));
+ bit_set(filter.event_mask, NG_HCI_EVENT_PIN_CODE_REQ - 1);
+ bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_REQ - 1);
+
+ if (setsockopt(sock, SOL_HCI_RAW, SO_HCI_RAW_FILTER,
+ (void * const) &filter, sizeof(filter)) < 0)
+ err(1, "Could not set HCI socket filter");
+
+ if (detach)
+ if (daemon(0, 0) < 0)
+ err(1, "Could not daemon()ize");
+
+ openlog(HCSECD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
+
+ read_config_file(0);
+
+ if (detach) {
+ FILE *pid = NULL;
+
+ if ((pid = fopen(HCSECD_PIDFILE, "w")) == NULL) {
+ syslog(LOG_ERR, "Could not create PID file %s. %s (%d)",
+ HCSECD_PIDFILE, strerror(errno), errno);
+ exit(1);
+ }
+
+ fprintf(pid, "%d", getpid());
+ fclose(pid);
+ }
+
+ event = (ng_hci_event_pkt_t *) buffer;
+ while (!done) {
+ size = sizeof(addr);
+ n = recvfrom(sock, buffer, sizeof(buffer), 0,
+ (struct sockaddr *) &addr, &size);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+
+ syslog(LOG_ERR, "Could not receive from HCI socket. " \
+ "%s (%d)", strerror(errno), errno);
+ exit(1);
+ }
+
+ if (event->type != NG_HCI_EVENT_PKT) {
+ syslog(LOG_ERR, "Received unexpected HCI packet, " \
+ "type=%#x", event->type);
+ continue;
+ }
+
+ switch (event->event) {
+ case NG_HCI_EVENT_PIN_CODE_REQ:
+ process_pin_code_request_event(sock, &addr,
+ (bdaddr_p)(event + 1));
+ break;
+
+ case NG_HCI_EVENT_LINK_KEY_REQ:
+ process_link_key_request_event(sock, &addr,
+ (bdaddr_p)(event + 1));
+ break;
+
+ default:
+ syslog(LOG_ERR, "Received unexpected HCI event, " \
+ "event=%#x", event->event);
+ break;
+ }
+ }
+
+ if (detach)
+ if (remove(HCSECD_PIDFILE) < 0)
+ syslog(LOG_ERR, "Could not remove PID file %s. %s (%d)",
+ HCSECD_PIDFILE, strerror(errno), errno);
+
+ clean_config();
+ closelog();
+ close(sock);
+
+ return (0);
+}
+
+/* Process PIN_Code_Request event */
+static int
+process_pin_code_request_event(int sock, struct sockaddr_hci *addr,
+ bdaddr_p bdaddr)
+{
+ link_key_p key = NULL;
+
+ syslog(LOG_DEBUG, "Got PIN_Code_Request event from '%s', " \
+ "remote bdaddr %x:%x:%x:%x:%x:%x", addr->hci_node,
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+
+ if ((key = get_key(bdaddr, 0)) != NULL) {
+ syslog(LOG_DEBUG, "Found matching entry, " \
+ "remote bdaddr %x:%x:%x:%x:%x:%x, name '%s', " \
+ "PIN code %s",
+ key->bdaddr.b[5], key->bdaddr.b[4],
+ key->bdaddr.b[3], key->bdaddr.b[2],
+ key->bdaddr.b[1], key->bdaddr.b[0],
+ (key->name != NULL)? key->name : "No name",
+ (key->pin != NULL)? "exists" : "doesn't exist");
+
+ return (send_pin_code_reply(sock, addr, bdaddr, key->pin));
+ }
+
+ syslog(LOG_DEBUG, "Could not PIN code for remote bdaddr " \
+ "%x:%x:%x:%x:%x:%x",
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+
+ return (send_pin_code_reply(sock, addr, bdaddr, NULL));
+}
+
+/* Process Link_Key_Request event */
+static int
+process_link_key_request_event(int sock, struct sockaddr_hci *addr,
+ bdaddr_p bdaddr)
+{
+ link_key_p key = NULL;
+
+ syslog(LOG_DEBUG, "Got Link_Key_Request event from '%s', " \
+ "remote bdaddr %x:%x:%x:%x:%x:%x", addr->hci_node,
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+
+ if ((key = get_key(bdaddr, 0)) != NULL) {
+ syslog(LOG_DEBUG, "Found matching entry, " \
+ "remote bdaddr %x:%x:%x:%x:%x:%x, name '%s', " \
+ "link key %s",
+ key->bdaddr.b[5], key->bdaddr.b[4],
+ key->bdaddr.b[3], key->bdaddr.b[2],
+ key->bdaddr.b[1], key->bdaddr.b[0],
+ (key->name != NULL)? key->name : "No name",
+ (key->key != NULL)? "exists" : "doesn't exist");
+
+ return (send_link_key_reply(sock, addr, bdaddr, key->key));
+ }
+
+ syslog(LOG_DEBUG, "Could not find link key for remote bdaddr " \
+ "%x:%x:%x:%x:%x:%x",
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+
+ return (send_link_key_reply(sock, addr, bdaddr, NULL));
+}
+
+/* Send PIN_Code_[Negative]_Reply */
+static int
+send_pin_code_reply(int sock, struct sockaddr_hci *addr,
+ bdaddr_p bdaddr, char const *pin)
+{
+ u_int8_t buffer[HCSECD_BUFFER_SIZE];
+ ng_hci_cmd_pkt_t *cmd = NULL;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ cmd = (ng_hci_cmd_pkt_t *) buffer;
+ cmd->type = NG_HCI_CMD_PKT;
+
+ if (pin != NULL) {
+ ng_hci_pin_code_rep_cp *cp = NULL;
+
+ cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_PIN_CODE_REP));
+ cmd->length = sizeof(*cp);
+
+ cp = (ng_hci_pin_code_rep_cp *)(cmd + 1);
+ memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
+ strncpy(cp->pin, pin, sizeof(cp->pin));
+ cp->pin_size = strlen(cp->pin);
+
+ syslog(LOG_DEBUG, "Sending PIN_Code_Reply to '%s' " \
+ "for remote bdaddr %x:%x:%x:%x:%x:%x",
+ addr->hci_node,
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+ } else {
+ ng_hci_pin_code_neg_rep_cp *cp = NULL;
+
+ cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_PIN_CODE_NEG_REP));
+ cmd->length = sizeof(*cp);
+
+ cp = (ng_hci_pin_code_neg_rep_cp *)(cmd + 1);
+ memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
+
+ syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to '%s' " \
+ "for remote bdaddr %x:%x:%x:%x:%x:%x",
+ addr->hci_node,
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+ }
+
+again:
+ if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+ (struct sockaddr *) addr, sizeof(*addr)) < 0) {
+ if (errno == EINTR)
+ goto again;
+
+ syslog(LOG_ERR, "Could not send PIN code reply to '%s' " \
+ "for remote bdaddr %x:%x:%x:%x:%x:%x. %s (%d)",
+ addr->hci_node,
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0],
+ strerror(errno), errno);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Send Link_Key_[Negative]_Reply */
+static int
+send_link_key_reply(int sock, struct sockaddr_hci *addr,
+ bdaddr_p bdaddr, u_int8_t *key)
+{
+ u_int8_t buffer[HCSECD_BUFFER_SIZE];
+ ng_hci_cmd_pkt_t *cmd = NULL;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ cmd = (ng_hci_cmd_pkt_t *) buffer;
+ cmd->type = NG_HCI_CMD_PKT;
+
+ if (key != NULL) {
+ ng_hci_link_key_rep_cp *cp = NULL;
+
+ cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_LINK_KEY_REP));
+ cmd->length = sizeof(*cp);
+
+ cp = (ng_hci_link_key_rep_cp *)(cmd + 1);
+ memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
+ memcpy(&cp->key, key, sizeof(cp->key));
+
+ syslog(LOG_DEBUG, "Sending Link_Key_Reply to '%s' " \
+ "for remote bdaddr %x:%x:%x:%x:%x:%x",
+ addr->hci_node,
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+ } else {
+ ng_hci_link_key_neg_rep_cp *cp = NULL;
+
+ cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
+ NG_HCI_OCF_LINK_KEY_NEG_REP));
+ cmd->length = sizeof(*cp);
+
+ cp = (ng_hci_link_key_neg_rep_cp *)(cmd + 1);
+ memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
+
+ syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to '%s' " \
+ "for remote bdaddr %x:%x:%x:%x:%x:%x",
+ addr->hci_node,
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
+ }
+
+again:
+ if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
+ (struct sockaddr *) addr, sizeof(*addr)) < 0) {
+ if (errno == EINTR)
+ goto again;
+
+ syslog(LOG_ERR, "Could not send link key reply to '%s' " \
+ "for remote bdaddr %x:%x:%x:%x:%x:%x. %s (%d)",
+ addr->hci_node,
+ bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
+ bdaddr->b[2], bdaddr->b[1], bdaddr->b[0],
+ strerror(errno), errno);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Signal handler */
+static void
+sigint(int s)
+{
+ syslog(LOG_DEBUG, "Got signal %d, total number of signals %d",
+ s, ++ done);
+}
+
+/* Display usage and exit */
+static void
+usage(void)
+{
+ fprintf(stderr,
+"Usage: %s [-d] -f config_file [-h]\n" \
+"Where:\n" \
+"\t-d do not detach from terminal\n" \
+"\t-f config_file use <config_file>\n" \
+"\t-h display this message\n", HCSECD_IDENT);
+
+ exit(255);
+}
+
diff --git a/usr.sbin/bluetooth/hcsecd/hcsecd.conf b/usr.sbin/bluetooth/hcsecd/hcsecd.conf
new file mode 100644
index 0000000..127ce04
--- /dev/null
+++ b/usr.sbin/bluetooth/hcsecd/hcsecd.conf
@@ -0,0 +1,64 @@
+#
+# $Id: hcsecd.conf,v 1.1 2002/11/24 20:22:39 max Exp $
+# $FreeBSD$
+#
+# 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/usr.sbin/bluetooth/hcsecd/hcsecd.h b/usr.sbin/bluetooth/hcsecd/hcsecd.h
new file mode 100644
index 0000000..65820ed
--- /dev/null
+++ b/usr.sbin/bluetooth/hcsecd/hcsecd.h
@@ -0,0 +1,57 @@
+/*
+ * hcsecd.h
+ *
+ * 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.h,v 1.1 2002/11/24 20:22:39 max Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _HCSECD_H_
+#define _HCSECD_H_ 1
+
+struct link_key
+{
+ bdaddr_t bdaddr; /* remote device BDADDR */
+ char *name; /* remote device name */
+ u_int8_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
+
+void read_config_file(int s);
+void clean_config (void);
+link_key_p get_key (bdaddr_p bdaddr, int exact_match);
+
+#endif /* ndef _HCSECD_H_ */
+
diff --git a/usr.sbin/bluetooth/hcsecd/lexer.l b/usr.sbin/bluetooth/hcsecd/lexer.l
new file mode 100644
index 0000000..2430d7e
--- /dev/null
+++ b/usr.sbin/bluetooth/hcsecd/lexer.l
@@ -0,0 +1,95 @@
+%{
+/*
+ * 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$
+ */
+
+#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/bluetooth/hcsecd/parser.y b/usr.sbin/bluetooth/hcsecd/parser.y
new file mode 100644
index 0000000..750c068
--- /dev/null
+++ b/usr.sbin/bluetooth/hcsecd/parser.y
@@ -0,0 +1,339 @@
+%{
+/*
+ * 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.1 2002/11/24 20:22:39 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <ng_hci.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <syslog.h>
+#include "hcsecd.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 = "/usr/local/etc/hcsecd.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 %x:%x:%x:%x:%x:%x",
+ key->bdaddr.b[5],
+ key->bdaddr.b[4],
+ key->bdaddr.b[3],
+ key->bdaddr.b[2],
+ key->bdaddr.b[1],
+ key->bdaddr.b[0]);
+ 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
+ {
+ int a0, a1, a2, a3, a4, a5;
+
+ if (sscanf($2, "%x:%x:%x:%x:%x:%x",
+ &a5, &a4, &a3, &a2, &a1, &a0) != 6) {
+ syslog(LOG_ERR, "Cound not parse BDADDR " \
+ "'%s'", $2);
+ exit(1);
+ }
+
+ key->bdaddr.b[0] = (a0 & 0xff);
+ key->bdaddr.b[1] = (a1 & 0xff);
+ key->bdaddr.b[2] = (a2 & 0xff);
+ key->bdaddr.b[3] = (a3 & 0xff);
+ key->bdaddr.b[4] = (a4 & 0xff);
+ key->bdaddr.b[5] = (a5 & 0xff);
+ }
+ ;
+
+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 = (u_int8_t *) malloc(NG_HCI_KEY_SIZE);
+ if (key->key == NULL) {
+ syslog(LOG_ERR, "Could not allocate new " \
+ "link key");
+ exit(1);
+ }
+
+ memset(key->key, 0, NG_HCI_KEY_SIZE);
+
+ len = strlen($2) / 2;
+ if (len > NG_HCI_KEY_SIZE)
+ len = NG_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(int s)
+{
+ 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(NG_HCI_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 %x:%x:%x:%x:%x:%x " \
+"pin %s " \
+"key %s",
+ (key->name != NULL)? key->name : "noname",
+ key->bdaddr.b[5], key->bdaddr.b[4], key->bdaddr.b[3],
+ key->bdaddr.b[2], key->bdaddr.b[1], key->bdaddr.b[0],
+ (key->pin != NULL)? key->pin : "nopin",
+ (key->key != NULL)? buffer : "nokey");
+ }
+}
+#endif
+
+/* 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));
+}
+
OpenPOWER on IntegriCloud