1 /*-
2 * hcsecd.c
3 *
4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 *
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>
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
main(int argc,char * argv[])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
process_pin_code_request_event(int sock,struct sockaddr_hci * addr,bdaddr_p bdaddr)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
process_link_key_request_event(int sock,struct sockaddr_hci * addr,bdaddr_p bdaddr)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
send_pin_code_reply(int sock,struct sockaddr_hci * addr,bdaddr_p bdaddr,char const * pin)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
send_link_key_reply(int sock,struct sockaddr_hci * addr,bdaddr_p bdaddr,uint8_t * key)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
process_link_key_notification_event(int sock,struct sockaddr_hci * addr,ng_hci_link_key_notification_ep * ep)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
sighup(int s)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
sigint(int s)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
usage(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