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