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