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