From fe2526340b1a2d7ed079617d2eca31aa6425d937 Mon Sep 17 00:00:00 2001 From: julian Date: Sat, 10 May 2003 21:50:37 +0000 Subject: Part 2 of the commit if new bluetooth code. Submitted by: Maksim Yevmenkin Approved by: re@ --- usr.sbin/bluetooth/hcsecd/Makefile | 12 + usr.sbin/bluetooth/hcsecd/hcsecd.8 | 101 ++++++++ usr.sbin/bluetooth/hcsecd/hcsecd.c | 422 ++++++++++++++++++++++++++++++++++ usr.sbin/bluetooth/hcsecd/hcsecd.conf | 64 ++++++ usr.sbin/bluetooth/hcsecd/hcsecd.h | 57 +++++ usr.sbin/bluetooth/hcsecd/lexer.l | 95 ++++++++ usr.sbin/bluetooth/hcsecd/parser.y | 339 +++++++++++++++++++++++++++ 7 files changed, 1090 insertions(+) create mode 100644 usr.sbin/bluetooth/hcsecd/Makefile create mode 100644 usr.sbin/bluetooth/hcsecd/hcsecd.8 create mode 100644 usr.sbin/bluetooth/hcsecd/hcsecd.c create mode 100644 usr.sbin/bluetooth/hcsecd/hcsecd.conf create mode 100644 usr.sbin/bluetooth/hcsecd/hcsecd.h create mode 100644 usr.sbin/bluetooth/hcsecd/lexer.l create mode 100644 usr.sbin/bluetooth/hcsecd/parser.y (limited to 'usr.sbin/bluetooth/hcsecd') 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 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 +.\" 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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \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 + * 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 + * 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 +#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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#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 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)); +} + -- cgit v1.1