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 450