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