xref: /freebsd/usr.sbin/bluetooth/hcsecd/hcsecd.c (revision ab40f58ccfe6c07ebefddc72f4661a52fe746353)
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$
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 
48 static int	done = 0;
49 
50 static int process_pin_code_request_event
51 	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
52 static int process_link_key_request_event
53 	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr);
54 static int send_pin_code_reply
55 	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, char const *pin);
56 static int send_link_key_reply
57 	(int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, uint8_t *key);
58 static int process_link_key_notification_event
59 	(int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep);
60 static void sighup
61 	(int s);
62 static void sigint
63 	(int s);
64 static void usage
65 	(void);
66 
67 /* Main */
68 int
69 main(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 */
212 static int
213 process_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 */
239 static int
240 process_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 */
266 static int
267 send_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 
308 again:
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 */
325 static int
326 send_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 
366 again:
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 */
383 static int
384 process_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 */
419 static void
420 sighup(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 
429 static void
430 sigint(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 */
437 static void
438 usage(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