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 448