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
main(int argc,char * argv[])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
process_pin_code_request_event(int sock,struct sockaddr_hci * addr,bdaddr_p bdaddr)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
process_link_key_request_event(int sock,struct sockaddr_hci * addr,bdaddr_p bdaddr)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
send_pin_code_reply(int sock,struct sockaddr_hci * addr,bdaddr_p bdaddr,char const * pin)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
send_link_key_reply(int sock,struct sockaddr_hci * addr,bdaddr_p bdaddr,uint8_t * key)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
process_link_key_notification_event(int sock,struct sockaddr_hci * addr,ng_hci_link_key_notification_ep * ep)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
sighup(int s)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
sigint(int s)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
usage(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