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