]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bluetooth/hcsecd/hcsecd.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / usr.sbin / bluetooth / hcsecd / hcsecd.c
1 /*-
2  * hcsecd.c
3  *
4  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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  * $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
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
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
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
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
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
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
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
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
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