hcsecd.c revision 330449
1/*-
2 * hcsecd.c
3 *
4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 *
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id: hcsecd.c,v 1.6 2003/08/18 19:19:55 max Exp $
31 * $FreeBSD: stable/11/usr.sbin/bluetooth/hcsecd/hcsecd.c 330449 2018-03-05 07:26:05Z eadler $
32 */
33
34#include <sys/queue.h>
35#define L2CAP_SOCKET_CHECKED
36#include <bluetooth.h>
37#include <err.h>
38#include <errno.h>
39#include <signal.h>
40#include <stdarg.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <syslog.h>
45#include <unistd.h>
46#include "hcsecd.h"
47
48static int	done = 0;
49
50static int process_pin_code_request_event
51	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
52static int process_link_key_request_event
53	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
54static int send_pin_code_reply
55	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, char const *pin);
56static int send_link_key_reply
57	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, uint8_t *key);
58static int process_link_key_notification_event
59	(int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep);
60static void sighup
61	(int s);
62static void sigint
63	(int s);
64static void usage
65	(void);
66
67/* Main */
68int
69main(int argc, char *argv[])
70{
71	int					 n, detach, sock;
72	socklen_t				 size;
73	struct sigaction			 sa;
74	struct sockaddr_hci			 addr;
75	struct ng_btsocket_hci_raw_filter	 filter;
76	char					 buffer[HCSECD_BUFFER_SIZE];
77	ng_hci_event_pkt_t			*event = NULL;
78
79	detach = 1;
80
81	while ((n = getopt(argc, argv, "df:h")) != -1) {
82		switch (n) {
83		case 'd':
84			detach = 0;
85			break;
86
87		case 'f':
88			config_file = optarg;
89			break;
90
91		case 'h':
92		default:
93			usage();
94			/* NOT REACHED */
95		}
96	}
97
98	if (config_file == NULL)
99		usage();
100		/* NOT REACHED */
101
102	if (getuid() != 0)
103		errx(1, "** ERROR: You should run %s as privileged user!",
104			HCSECD_IDENT);
105
106	/* Set signal handlers */
107	memset(&sa, 0, sizeof(sa));
108	sa.sa_handler = sigint;
109	sa.sa_flags = SA_NOCLDWAIT;
110	if (sigaction(SIGINT, &sa, NULL) < 0)
111		err(1, "Could not sigaction(SIGINT)");
112	if (sigaction(SIGTERM, &sa, NULL) < 0)
113		err(1, "Could not sigaction(SIGINT)");
114
115	memset(&sa, 0, sizeof(sa));
116	sa.sa_handler = sighup;
117	if (sigaction(SIGHUP, &sa, NULL) < 0)
118		err(1, "Could not sigaction(SIGHUP)");
119
120	/* Open socket and set filter */
121	sock = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
122	if (sock < 0)
123		err(1, "Could not create HCI socket");
124
125	memset(&filter, 0, sizeof(filter));
126	bit_set(filter.event_mask, NG_HCI_EVENT_PIN_CODE_REQ - 1);
127	bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_REQ - 1);
128	bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1);
129
130	if (setsockopt(sock, SOL_HCI_RAW, SO_HCI_RAW_FILTER,
131			(void * const) &filter, sizeof(filter)) < 0)
132		err(1, "Could not set HCI socket filter");
133
134	if (detach && daemon(0, 0) < 0)
135		err(1, "Could not daemon()ize");
136
137	openlog(HCSECD_IDENT, LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON);
138
139	read_config_file();
140	read_keys_file();
141
142	if (detach) {
143		FILE	*pid = NULL;
144
145		if ((pid = fopen(HCSECD_PIDFILE, "w")) == NULL) {
146			syslog(LOG_ERR, "Could not create PID file %s. %s (%d)",
147					HCSECD_PIDFILE, strerror(errno), errno);
148			exit(1);
149		}
150
151		fprintf(pid, "%d", getpid());
152		fclose(pid);
153	}
154
155	event = (ng_hci_event_pkt_t *) buffer;
156	while (!done) {
157		size = sizeof(addr);
158		n = recvfrom(sock, buffer, sizeof(buffer), 0,
159				(struct sockaddr *) &addr, &size);
160		if (n < 0) {
161			if (errno == EINTR)
162				continue;
163
164			syslog(LOG_ERR, "Could not receive from HCI socket. " \
165					"%s (%d)", strerror(errno), errno);
166			exit(1);
167		}
168
169		if (event->type != NG_HCI_EVENT_PKT) {
170			syslog(LOG_ERR, "Received unexpected HCI packet, " \
171					"type=%#x", event->type);
172			continue;
173		}
174
175		switch (event->event) {
176		case NG_HCI_EVENT_PIN_CODE_REQ:
177			process_pin_code_request_event(sock, &addr,
178							(bdaddr_p)(event + 1));
179			break;
180
181		case NG_HCI_EVENT_LINK_KEY_REQ:
182			process_link_key_request_event(sock, &addr,
183							(bdaddr_p)(event + 1));
184			break;
185
186		case NG_HCI_EVENT_LINK_KEY_NOTIFICATION:
187			process_link_key_notification_event(sock, &addr,
188				(ng_hci_link_key_notification_ep *)(event + 1));
189			break;
190
191		default:
192			syslog(LOG_ERR, "Received unexpected HCI event, " \
193					"event=%#x", event->event);
194			break;
195		}
196	}
197
198	if (detach)
199		if (remove(HCSECD_PIDFILE) < 0)
200			syslog(LOG_ERR, "Could not remove PID file %s. %s (%d)",
201					HCSECD_PIDFILE, strerror(errno), errno);
202
203	dump_keys_file();
204	clean_config();
205	closelog();
206	close(sock);
207
208	return (0);
209}
210
211/* Process PIN_Code_Request event */
212static int
213process_pin_code_request_event(int sock, struct sockaddr_hci *addr,
214		bdaddr_p bdaddr)
215{
216	link_key_p	key = NULL;
217
218	syslog(LOG_DEBUG, "Got PIN_Code_Request event from '%s', " \
219			"remote bdaddr %s", addr->hci_node,
220			bt_ntoa(bdaddr, NULL));
221
222	if ((key = get_key(bdaddr, 0)) != NULL) {
223		syslog(LOG_DEBUG, "Found matching entry, " \
224				"remote bdaddr %s, name '%s', PIN code %s",
225				bt_ntoa(&key->bdaddr, NULL),
226				(key->name != NULL)? key->name : "No name",
227				(key->pin != NULL)? "exists" : "doesn't exist");
228
229		return (send_pin_code_reply(sock, addr, bdaddr, key->pin));
230	}
231
232	syslog(LOG_DEBUG, "Could not PIN code for remote bdaddr %s",
233			bt_ntoa(bdaddr, NULL));
234
235	return (send_pin_code_reply(sock, addr, bdaddr, NULL));
236}
237
238/* Process Link_Key_Request event */
239static int
240process_link_key_request_event(int sock, struct sockaddr_hci *addr,
241		bdaddr_p bdaddr)
242{
243	link_key_p	key = NULL;
244
245	syslog(LOG_DEBUG, "Got Link_Key_Request event from '%s', " \
246			"remote bdaddr %s", addr->hci_node,
247			bt_ntoa(bdaddr, NULL));
248
249	if ((key = get_key(bdaddr, 0)) != NULL) {
250		syslog(LOG_DEBUG, "Found matching entry, " \
251				"remote bdaddr %s, name '%s', link key %s",
252				bt_ntoa(&key->bdaddr, NULL),
253				(key->name != NULL)? key->name : "No name",
254				(key->key != NULL)? "exists" : "doesn't exist");
255
256		return (send_link_key_reply(sock, addr, bdaddr, key->key));
257	}
258
259	syslog(LOG_DEBUG, "Could not find link key for remote bdaddr %s",
260			bt_ntoa(bdaddr, NULL));
261
262	return (send_link_key_reply(sock, addr, bdaddr, NULL));
263}
264
265/* Send PIN_Code_[Negative]_Reply */
266static int
267send_pin_code_reply(int sock, struct sockaddr_hci *addr,
268		bdaddr_p bdaddr, char const *pin)
269{
270	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
271	ng_hci_cmd_pkt_t	*cmd = NULL;
272
273	memset(buffer, 0, sizeof(buffer));
274
275	cmd = (ng_hci_cmd_pkt_t *) buffer;
276	cmd->type = NG_HCI_CMD_PKT;
277
278	if (pin != NULL) {
279		ng_hci_pin_code_rep_cp	*cp = NULL;
280
281		cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
282						NG_HCI_OCF_PIN_CODE_REP));
283		cmd->length = sizeof(*cp);
284
285		cp = (ng_hci_pin_code_rep_cp *)(cmd + 1);
286		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
287		strncpy((char *) cp->pin, pin, sizeof(cp->pin));
288		cp->pin_size = strlen((char const *) cp->pin);
289
290		syslog(LOG_DEBUG, "Sending PIN_Code_Reply to '%s' " \
291				"for remote bdaddr %s",
292				addr->hci_node, bt_ntoa(bdaddr, NULL));
293	} else {
294		ng_hci_pin_code_neg_rep_cp	*cp = NULL;
295
296		cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
297						NG_HCI_OCF_PIN_CODE_NEG_REP));
298		cmd->length = sizeof(*cp);
299
300		cp = (ng_hci_pin_code_neg_rep_cp *)(cmd + 1);
301		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
302
303		syslog(LOG_DEBUG, "Sending PIN_Code_Negative_Reply to '%s' " \
304				"for remote bdaddr %s",
305				addr->hci_node, bt_ntoa(bdaddr, NULL));
306	}
307
308again:
309	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
310			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
311		if (errno == EINTR)
312			goto again;
313
314		syslog(LOG_ERR, "Could not send PIN code reply to '%s' " \
315				"for remote bdaddr %s. %s (%d)",
316				addr->hci_node, bt_ntoa(bdaddr, NULL),
317				strerror(errno), errno);
318		return (-1);
319	}
320
321	return (0);
322}
323
324/* Send Link_Key_[Negative]_Reply */
325static int
326send_link_key_reply(int sock, struct sockaddr_hci *addr,
327		bdaddr_p bdaddr, uint8_t *key)
328{
329	uint8_t			 buffer[HCSECD_BUFFER_SIZE];
330	ng_hci_cmd_pkt_t	*cmd = NULL;
331
332	memset(buffer, 0, sizeof(buffer));
333
334	cmd = (ng_hci_cmd_pkt_t *) buffer;
335	cmd->type = NG_HCI_CMD_PKT;
336
337	if (key != NULL) {
338		ng_hci_link_key_rep_cp	*cp = NULL;
339
340		cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
341						NG_HCI_OCF_LINK_KEY_REP));
342		cmd->length = sizeof(*cp);
343
344		cp = (ng_hci_link_key_rep_cp *)(cmd + 1);
345		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
346		memcpy(&cp->key, key, sizeof(cp->key));
347
348		syslog(LOG_DEBUG, "Sending Link_Key_Reply to '%s' " \
349				"for remote bdaddr %s",
350				addr->hci_node, bt_ntoa(bdaddr, NULL));
351	} else {
352		ng_hci_link_key_neg_rep_cp	*cp = NULL;
353
354		cmd->opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
355						NG_HCI_OCF_LINK_KEY_NEG_REP));
356		cmd->length = sizeof(*cp);
357
358		cp = (ng_hci_link_key_neg_rep_cp *)(cmd + 1);
359		memcpy(&cp->bdaddr, bdaddr, sizeof(cp->bdaddr));
360
361		syslog(LOG_DEBUG, "Sending Link_Key_Negative_Reply to '%s' " \
362				"for remote bdaddr %s",
363				addr->hci_node, bt_ntoa(bdaddr, NULL));
364	}
365
366again:
367	if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0,
368			(struct sockaddr *) addr, sizeof(*addr)) < 0) {
369		if (errno == EINTR)
370			goto again;
371
372		syslog(LOG_ERR, "Could not send link key reply to '%s' " \
373				"for remote bdaddr %s. %s (%d)",
374				addr->hci_node, bt_ntoa(bdaddr, NULL),
375				strerror(errno), errno);
376		return (-1);
377	}
378
379	return (0);
380}
381
382/* Process Link_Key_Notification event */
383static int
384process_link_key_notification_event(int sock, struct sockaddr_hci *addr,
385		ng_hci_link_key_notification_ep *ep)
386{
387	link_key_p	key = NULL;
388
389	syslog(LOG_DEBUG, "Got Link_Key_Notification event from '%s', " \
390			"remote bdaddr %s", addr->hci_node,
391			bt_ntoa(&ep->bdaddr, NULL));
392
393	if ((key = get_key(&ep->bdaddr, 1)) == NULL) {
394		syslog(LOG_ERR, "Could not find entry for remote bdaddr %s",
395				bt_ntoa(&ep->bdaddr, NULL));
396		return (-1);
397	}
398
399	syslog(LOG_DEBUG, "Updating link key for the entry, " \
400			"remote bdaddr %s, name '%s', link key %s",
401			bt_ntoa(&key->bdaddr, NULL),
402			(key->name != NULL)? key->name : "No name",
403			(key->key != NULL)? "exists" : "doesn't exist");
404
405	if (key->key == NULL) {
406		key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);
407		if (key->key == NULL) {
408			syslog(LOG_ERR, "Could not allocate link key");
409			exit(1);
410		}
411	}
412
413	memcpy(key->key, &ep->key, NG_HCI_KEY_SIZE);
414
415	return (0);
416}
417
418/* Signal handlers */
419static void
420sighup(int s)
421{
422	syslog(LOG_DEBUG, "Got SIGHUP (%d)", s);
423
424	dump_keys_file();
425	read_config_file();
426	read_keys_file();
427}
428
429static void
430sigint(int s)
431{
432	syslog(LOG_DEBUG, "Got signal %d, total number of signals %d",
433			s, ++ done);
434}
435
436/* Display usage and exit */
437static void
438usage(void)
439{
440	fprintf(stderr,
441"Usage: %s [-d] -f config_file [-h]\n" \
442"Where:\n" \
443"\t-d              do not detach from terminal\n" \
444"\t-f config_file  use <config_file>\n" \
445"\t-h              display this message\n", HCSECD_IDENT);
446
447	exit(255);
448}
449
450