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