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