Path: blob/main/usr.sbin/bluetooth/hcsecd/hcsecd.c
103381 views
/*-1* hcsecd.c2*3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>6* All rights reserved.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF27* SUCH DAMAGE.28*29* $Id: hcsecd.c,v 1.6 2003/08/18 19:19:55 max Exp $30*/3132#include <sys/queue.h>33#define L2CAP_SOCKET_CHECKED34#include <bluetooth.h>35#include <err.h>36#include <errno.h>37#include <signal.h>38#include <stdarg.h>39#include <stdio.h>40#include <stdlib.h>41#include <string.h>42#include <syslog.h>43#include <unistd.h>44#include "hcsecd.h"4546static int done = 0;4748static int process_pin_code_request_event49(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);50static int process_link_key_request_event51(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);52static int send_pin_code_reply53(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, char const *pin);54static int send_link_key_reply55(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, uint8_t *key);56static int process_link_key_notification_event57(int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep);58static void sighup59(int s);60static void sigint61(int s);62static void usage63(void);6465/* Main */66int67main(int argc, char *argv[])68{69int n, detach, sock;70socklen_t size;71struct sigaction sa;72struct sockaddr_hci addr;73struct ng_btsocket_hci_raw_filter filter;74char buffer[HCSECD_BUFFER_SIZE];75ng_hci_event_pkt_t *event = NULL;7677detach = 1;7879while ((n = getopt(argc, argv, "df:h")) != -1) {80switch (n) {81case 'd':82detach = 0;83break;8485case 'f':86config_file = optarg;87break;8889case 'h':90default:91usage();92/* NOT REACHED */93}94}9596if (config_file == NULL)97usage();98/* NOT REACHED */99100if (getuid() != 0)101errx(1, "** ERROR: You should run %s as privileged user!",102HCSECD_IDENT);103104/* Set signal handlers */105memset(&sa, 0, sizeof(sa));106sa.sa_handler = sigint;107sa.sa_flags = SA_NOCLDWAIT;108if (sigaction(SIGINT, &sa, NULL) < 0)109err(1, "Could not sigaction(SIGINT)");110if (sigaction(SIGTERM, &sa, NULL) < 0)111err(1, "Could not sigaction(SIGINT)");112113memset(&sa, 0, sizeof(sa));114sa.sa_handler = sighup;115if (sigaction(SIGHUP, &sa, NULL) < 0)116err(1, "Could not sigaction(SIGHUP)");117118/* Open socket and set filter */119sock = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);120if (sock < 0)121err(1, "Could not create HCI socket");122123memset(&filter, 0, sizeof(filter));124bit_set(filter.event_mask, NG_HCI_EVENT_PIN_CODE_REQ - 1);125bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_REQ - 1);126bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1);127128if (setsockopt(sock, SOL_HCI_RAW, SO_HCI_RAW_FILTER,129(void * const) &filter, sizeof(filter)) < 0)130err(1, "Could not set HCI socket filter");131132if (detach && daemon(0, 0) < 0)133err(1, "Could not daemon()ize");134135openlog(HCSECD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);136137read_config_file();138read_keys_file();139140if (detach) {141FILE *pid = NULL;142143if ((pid = fopen(HCSECD_PIDFILE, "w")) == NULL) {144syslog(LOG_ERR, "Could not create PID file %s. %s (%d)",145HCSECD_PIDFILE, strerror(errno), errno);146exit(1);147}148149fprintf(pid, "%d", getpid());150fclose(pid);151}152153event = (ng_hci_event_pkt_t *) buffer;154while (!done) {155size = sizeof(addr);156n = recvfrom(sock, buffer, sizeof(buffer), 0,157(struct sockaddr *) &addr, &size);158if (n < 0) {159if (errno == EINTR)160continue;161162syslog(LOG_ERR, "Could not receive from HCI socket. " \163"%s (%d)", strerror(errno), errno);164exit(1);165}166167if (event->type != NG_HCI_EVENT_PKT) {168syslog(LOG_ERR, "Received unexpected HCI packet, " \169"type=%#x", event->type);170continue;171}172173switch (event->event) {174case NG_HCI_EVENT_PIN_CODE_REQ:175process_pin_code_request_event(sock, &addr,176(bdaddr_p)(event + 1));177break;178179case NG_HCI_EVENT_LINK_KEY_REQ:180process_link_key_request_event(sock, &addr,181(bdaddr_p)(event + 1));182break;183184case NG_HCI_EVENT_LINK_KEY_NOTIFICATION:185process_link_key_notification_event(sock, &addr,186(ng_hci_link_key_notification_ep *)(event + 1));187break;188189default:190syslog(LOG_ERR, "Received unexpected HCI event, " \191"event=%#x", event->event);192break;193}194}195196if (detach)197if (remove(HCSECD_PIDFILE) < 0)198syslog(LOG_ERR, "Could not remove PID file %s. %s (%d)",199HCSECD_PIDFILE, strerror(errno), errno);200201dump_keys_file();202clean_config();203closelog();204close(sock);205206return (0);207}208209/* Process PIN_Code_Request event */210static int211process_pin_code_request_event(int sock, struct sockaddr_hci *addr,212bdaddr_p bdaddr)213{214link_key_p key = NULL;215216syslog(LOG_DEBUG, "Got PIN_Code_Request event from '%s', " \217"remote bdaddr %s", addr->hci_node,218bt_ntoa(bdaddr, NULL));219220if ((key = get_key(bdaddr, 0)) != NULL) {221syslog(LOG_DEBUG, "Found matching entry, " \222"remote bdaddr %s, name '%s', PIN code %s",223bt_ntoa(&key->bdaddr, NULL),224(key->name != NULL)? key->name : "No name",225(key->pin != NULL)? "exists" : "doesn't exist");226227return (send_pin_code_reply(sock, addr, bdaddr, key->pin));228}229230syslog(LOG_DEBUG, "Could not PIN code for remote bdaddr %s",231bt_ntoa(bdaddr, NULL));232233return (send_pin_code_reply(sock, addr, bdaddr, NULL));234}235236/* Process Link_Key_Request event */237static int238process_link_key_request_event(int sock, struct sockaddr_hci *addr,239bdaddr_p bdaddr)240{241link_key_p key = NULL;242243syslog(LOG_DEBUG, "Got Link_Key_Request event from '%s', " \244"remote bdaddr %s", addr->hci_node,245bt_ntoa(bdaddr, NULL));246247if ((key = get_key(bdaddr, 0)) != NULL) {248syslog(LOG_DEBUG, "Found matching entry, " \249"remote bdaddr %s, name '%s', link key %s",250bt_ntoa(&key->bdaddr, NULL),251(key->name != NULL)? key->name : "No name",252(key->key != NULL)? "exists" : "doesn't exist");253254return (send_link_key_reply(sock, addr, bdaddr, key->key));255}256257syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",258bt_ntoa(bdaddr, NULL));259260return (send_link_key_reply(sock, addr, bdaddr, NULL));261}262263/* Send PIN_Code_[Negative]_Reply */264static int265send_pin_code_reply(int sock, struct sockaddr_hci *addr,266bdaddr_p bdaddr, char const *pin)267{268uint8_t buffer[HCSECD_BUFFER_SIZE];269ng_hci_cmd_pkt_t *cmd = NULL;270271memset(buffer, 0, sizeof(buffer));272273cmd = (ng_hci_cmd_pkt_t *) buffer;274cmd->type = NG_HCI_CMD_PKT;275276if (pin != NULL) {277ng_hci_pin_code_rep_cp *cp = NULL;278279cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,280NG_HCI_OCF_PIN_CODE_REP));281cmd->length = sizeof(*cp);282283cp = (ng_hci_pin_code_rep_cp *)(cmd + 1);284memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));285strncpy((char *) cp->pin, pin, sizeof(cp->pin));286cp->pin_size = strlen((char const *) cp->pin);287288syslog(LOG_DEBUG, "Sending PIN_Code_Reply to '%s' " \289"for remote bdaddr %s",290addr->hci_node, bt_ntoa(bdaddr, NULL));291} else {292ng_hci_pin_code_neg_rep_cp *cp = NULL;293294cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,295NG_HCI_OCF_PIN_CODE_NEG_REP));296cmd->length = sizeof(*cp);297298cp = (ng_hci_pin_code_neg_rep_cp *)(cmd + 1);299memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));300301syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to '%s' " \302"for remote bdaddr %s",303addr->hci_node, bt_ntoa(bdaddr, NULL));304}305306again:307if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,308(struct sockaddr *) addr, sizeof(*addr)) < 0) {309if (errno == EINTR)310goto again;311312syslog(LOG_ERR, "Could not send PIN code reply to '%s' " \313"for remote bdaddr %s. %s (%d)",314addr->hci_node, bt_ntoa(bdaddr, NULL),315strerror(errno), errno);316return (-1);317}318319return (0);320}321322/* Send Link_Key_[Negative]_Reply */323static int324send_link_key_reply(int sock, struct sockaddr_hci *addr,325bdaddr_p bdaddr, uint8_t *key)326{327uint8_t buffer[HCSECD_BUFFER_SIZE];328ng_hci_cmd_pkt_t *cmd = NULL;329330memset(buffer, 0, sizeof(buffer));331332cmd = (ng_hci_cmd_pkt_t *) buffer;333cmd->type = NG_HCI_CMD_PKT;334335if (key != NULL) {336ng_hci_link_key_rep_cp *cp = NULL;337338cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,339NG_HCI_OCF_LINK_KEY_REP));340cmd->length = sizeof(*cp);341342cp = (ng_hci_link_key_rep_cp *)(cmd + 1);343memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));344memcpy(&cp->key, key, sizeof(cp->key));345346syslog(LOG_DEBUG, "Sending Link_Key_Reply to '%s' " \347"for remote bdaddr %s",348addr->hci_node, bt_ntoa(bdaddr, NULL));349} else {350ng_hci_link_key_neg_rep_cp *cp = NULL;351352cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,353NG_HCI_OCF_LINK_KEY_NEG_REP));354cmd->length = sizeof(*cp);355356cp = (ng_hci_link_key_neg_rep_cp *)(cmd + 1);357memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));358359syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to '%s' " \360"for remote bdaddr %s",361addr->hci_node, bt_ntoa(bdaddr, NULL));362}363364again:365if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,366(struct sockaddr *) addr, sizeof(*addr)) < 0) {367if (errno == EINTR)368goto again;369370syslog(LOG_ERR, "Could not send link key reply to '%s' " \371"for remote bdaddr %s. %s (%d)",372addr->hci_node, bt_ntoa(bdaddr, NULL),373strerror(errno), errno);374return (-1);375}376377return (0);378}379380/* Process Link_Key_Notification event */381static int382process_link_key_notification_event(int sock, struct sockaddr_hci *addr,383ng_hci_link_key_notification_ep *ep)384{385link_key_p key = NULL;386387syslog(LOG_DEBUG, "Got Link_Key_Notification event from '%s', " \388"remote bdaddr %s", addr->hci_node,389bt_ntoa(&ep->bdaddr, NULL));390391if ((key = get_key(&ep->bdaddr, 1)) == NULL) {392syslog(LOG_ERR, "Could not find entry for remote bdaddr %s",393bt_ntoa(&ep->bdaddr, NULL));394return (-1);395}396397syslog(LOG_DEBUG, "Updating link key for the entry, " \398"remote bdaddr %s, name '%s', link key %s",399bt_ntoa(&key->bdaddr, NULL),400(key->name != NULL)? key->name : "No name",401(key->key != NULL)? "exists" : "doesn't exist");402403if (key->key == NULL) {404key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);405if (key->key == NULL) {406syslog(LOG_ERR, "Could not allocate link key");407exit(1);408}409}410411memcpy(key->key, &ep->key, NG_HCI_KEY_SIZE);412413return (0);414}415416/* Signal handlers */417static void418sighup(int s)419{420syslog(LOG_DEBUG, "Got SIGHUP (%d)", s);421422dump_keys_file();423read_config_file();424read_keys_file();425}426427static void428sigint(int s)429{430syslog(LOG_DEBUG, "Got signal %d, total number of signals %d",431s, ++ done);432}433434/* Display usage and exit */435static void436usage(void)437{438fprintf(stderr,439"Usage: %s [-d] -f config_file [-h]\n" \440"Where:\n" \441"\t-d do not detach from terminal\n" \442"\t-f config_file use <config_file>\n" \443"\t-h display this message\n", HCSECD_IDENT);444445exit(255);446}447448449450