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 447