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