1 %{ 2 /* 3 * parser.y 4 * 5 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Id: parser.y,v 1.5 2003/06/07 21:22:30 max Exp $ 30 * $FreeBSD$ 31 */ 32 33 #include <sys/fcntl.h> 34 #include <sys/queue.h> 35 #define L2CAP_SOCKET_CHECKED 36 #include <bluetooth.h> 37 #include <errno.h> 38 #include <limits.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <stdarg.h> 42 #include <string.h> 43 #include <syslog.h> 44 #include <unistd.h> 45 #include "hcsecd.h" 46 47 int yyparse (void); 48 int yylex (void); 49 50 static void free_key (link_key_p key); 51 static int hexa2int4(char *a); 52 static int hexa2int8(char *a); 53 54 extern int yylineno; 55 static LIST_HEAD(, link_key) link_keys; 56 char *config_file = "/etc/bluetooth/hcsecd.conf"; 57 58 static link_key_p key = NULL; 59 %} 60 61 %union { 62 char *string; 63 } 64 65 %token <string> T_BDADDRSTRING T_HEXSTRING T_STRING 66 %token T_DEVICE T_BDADDR T_NAME T_KEY T_PIN T_NOKEY T_NOPIN T_JUNK 67 68 %% 69 70 config: line 71 | config line 72 ; 73 74 line: T_DEVICE 75 { 76 key = (link_key_p) malloc(sizeof(*key)); 77 if (key == NULL) { 78 syslog(LOG_ERR, "Could not allocate new " \ 79 "config entry"); 80 exit(1); 81 } 82 83 memset(key, 0, sizeof(*key)); 84 } 85 '{' options '}' 86 { 87 if (get_key(&key->bdaddr, 1) != NULL) { 88 syslog(LOG_ERR, "Ignoring duplicated entry " \ 89 "for bdaddr %s", 90 bt_ntoa(&key->bdaddr, NULL)); 91 free_key(key); 92 } else 93 LIST_INSERT_HEAD(&link_keys, key, next); 94 95 key = NULL; 96 } 97 ; 98 99 options: option ';' 100 | options option ';' 101 ; 102 103 option: bdaddr 104 | name 105 | key 106 | pin 107 ; 108 109 bdaddr: T_BDADDR T_BDADDRSTRING 110 { 111 if (!bt_aton($2, &key->bdaddr)) { 112 syslog(LOG_ERR, "Cound not parse BD_ADDR " \ 113 "'%s'", $2); 114 exit(1); 115 } 116 } 117 ; 118 119 name: T_NAME T_STRING 120 { 121 if (key->name != NULL) 122 free(key->name); 123 124 key->name = strdup($2); 125 if (key->name == NULL) { 126 syslog(LOG_ERR, "Could not allocate new " \ 127 "device name"); 128 exit(1); 129 } 130 } 131 ; 132 133 key: T_KEY T_HEXSTRING 134 { 135 int i, len; 136 137 if (key->key != NULL) 138 free(key->key); 139 140 key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE); 141 if (key->key == NULL) { 142 syslog(LOG_ERR, "Could not allocate new " \ 143 "link key"); 144 exit(1); 145 } 146 147 memset(key->key, 0, NG_HCI_KEY_SIZE); 148 149 len = strlen($2) / 2; 150 if (len > NG_HCI_KEY_SIZE) 151 len = NG_HCI_KEY_SIZE; 152 153 for (i = 0; i < len; i ++) 154 key->key[i] = hexa2int8((char *)($2) + 2*i); 155 } 156 | T_KEY T_NOKEY 157 { 158 if (key->key != NULL) 159 free(key->key); 160 161 key->key = NULL; 162 } 163 ; 164 165 pin: T_PIN T_STRING 166 { 167 if (key->pin != NULL) 168 free(key->pin); 169 170 key->pin = strdup($2); 171 if (key->pin == NULL) { 172 syslog(LOG_ERR, "Could not allocate new " \ 173 "PIN code"); 174 exit(1); 175 } 176 } 177 | T_PIN T_NOPIN 178 { 179 if (key->pin != NULL) 180 free(key->pin); 181 182 key->pin = NULL; 183 } 184 ; 185 186 %% 187 188 /* Display parser error message */ 189 void 190 yyerror(char const *message) 191 { 192 syslog(LOG_ERR, "%s in line %d", message, yylineno); 193 } 194 195 /* Re-read config file */ 196 void 197 read_config_file(void) 198 { 199 extern FILE *yyin; 200 201 if (config_file == NULL) { 202 syslog(LOG_ERR, "Unknown config file name!"); 203 exit(1); 204 } 205 206 if ((yyin = fopen(config_file, "r")) == NULL) { 207 syslog(LOG_ERR, "Could not open config file '%s'. %s (%d)", 208 config_file, strerror(errno), errno); 209 exit(1); 210 } 211 212 clean_config(); 213 if (yyparse() < 0) { 214 syslog(LOG_ERR, "Could not parse config file '%s'",config_file); 215 exit(1); 216 } 217 218 fclose(yyin); 219 yyin = NULL; 220 221 #if __config_debug__ 222 dump_config(); 223 #endif 224 } 225 226 /* Clean config */ 227 void 228 clean_config(void) 229 { 230 link_key_p key = NULL; 231 232 while ((key = LIST_FIRST(&link_keys)) != NULL) { 233 LIST_REMOVE(key, next); 234 free_key(key); 235 } 236 } 237 238 /* Find link key entry in the list. Return exact or default match */ 239 link_key_p 240 get_key(bdaddr_p bdaddr, int exact_match) 241 { 242 link_key_p key = NULL, defkey = NULL; 243 244 LIST_FOREACH(key, &link_keys, next) { 245 if (memcmp(bdaddr, &key->bdaddr, sizeof(key->bdaddr)) == 0) 246 break; 247 248 if (!exact_match) 249 if (memcmp(NG_HCI_BDADDR_ANY, &key->bdaddr, 250 sizeof(key->bdaddr)) == 0) 251 defkey = key; 252 } 253 254 return ((key != NULL)? key : defkey); 255 } 256 257 #if __config_debug__ 258 /* Dump config */ 259 void 260 dump_config(void) 261 { 262 link_key_p key = NULL; 263 char buffer[64]; 264 265 LIST_FOREACH(key, &link_keys, next) { 266 if (key->key != NULL) 267 snprintf(buffer, sizeof(buffer), 268 "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 269 key->key[0], key->key[1], key->key[2], 270 key->key[3], key->key[4], key->key[5], 271 key->key[6], key->key[7], key->key[8], 272 key->key[9], key->key[10], key->key[11], 273 key->key[12], key->key[13], key->key[14], 274 key->key[15]); 275 276 syslog(LOG_DEBUG, 277 "device %s " \ 278 "bdaddr %s " \ 279 "pin %s " \ 280 "key %s", 281 (key->name != NULL)? key->name : "noname", 282 bt_ntoa(&key->bdaddr, NULL), 283 (key->pin != NULL)? key->pin : "nopin", 284 (key->key != NULL)? buffer : "nokey"); 285 } 286 } 287 #endif 288 289 /* Read keys file */ 290 int 291 read_keys_file(void) 292 { 293 FILE *f = NULL; 294 link_key_t *key = NULL; 295 char buf[HCSECD_BUFFER_SIZE], *p = NULL, *cp = NULL; 296 bdaddr_t bdaddr; 297 int i, len; 298 299 if ((f = fopen(HCSECD_KEYSFILE, "r")) == NULL) { 300 if (errno == ENOENT) 301 return (0); 302 303 syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n", 304 HCSECD_KEYSFILE, strerror(errno), errno); 305 306 return (-1); 307 } 308 309 while ((p = fgets(buf, sizeof(buf), f)) != NULL) { 310 if (*p == '#') 311 continue; 312 if ((cp = strpbrk(p, " ")) == NULL) 313 continue; 314 315 *cp++ = '\0'; 316 317 if (!bt_aton(p, &bdaddr)) 318 continue; 319 320 if ((key = get_key(&bdaddr, 1)) == NULL) 321 continue; 322 323 if (key->key == NULL) { 324 key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE); 325 if (key->key == NULL) { 326 syslog(LOG_ERR, "Could not allocate link key"); 327 exit(1); 328 } 329 } 330 331 memset(key->key, 0, NG_HCI_KEY_SIZE); 332 333 len = strlen(cp) / 2; 334 if (len > NG_HCI_KEY_SIZE) 335 len = NG_HCI_KEY_SIZE; 336 337 for (i = 0; i < len; i ++) 338 key->key[i] = hexa2int8(cp + 2*i); 339 340 syslog(LOG_DEBUG, "Restored link key for the entry, " \ 341 "remote bdaddr %s, name '%s'", 342 bt_ntoa(&key->bdaddr, NULL), 343 (key->name != NULL)? key->name : "No name"); 344 } 345 346 fclose(f); 347 348 return (0); 349 } 350 351 /* Dump keys file */ 352 int 353 dump_keys_file(void) 354 { 355 link_key_p key = NULL; 356 char tmp[PATH_MAX], buf[HCSECD_BUFFER_SIZE]; 357 int f; 358 359 snprintf(tmp, sizeof(tmp), "%s.tmp", HCSECD_KEYSFILE); 360 if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) { 361 syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n", 362 tmp, strerror(errno), errno); 363 return (-1); 364 } 365 366 LIST_FOREACH(key, &link_keys, next) { 367 if (key->key == NULL) 368 continue; 369 370 snprintf(buf, sizeof(buf), 371 "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", 372 bt_ntoa(&key->bdaddr, NULL), 373 key->key[0], key->key[1], key->key[2], key->key[3], 374 key->key[4], key->key[5], key->key[6], key->key[7], 375 key->key[8], key->key[9], key->key[10], key->key[11], 376 key->key[12], key->key[13], key->key[14], key->key[15]); 377 378 if (write(f, buf, strlen(buf)) < 0) { 379 syslog(LOG_ERR, "Could not write temp keys file. " \ 380 "%s (%d)\n", strerror(errno), errno); 381 break; 382 } 383 } 384 385 close(f); 386 387 if (rename(tmp, HCSECD_KEYSFILE) < 0) { 388 syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n", 389 tmp, HCSECD_KEYSFILE, strerror(errno), errno); 390 unlink(tmp); 391 return (-1); 392 } 393 394 return (0); 395 } 396 397 /* Free key entry */ 398 static void 399 free_key(link_key_p key) 400 { 401 if (key->name != NULL) 402 free(key->name); 403 if (key->key != NULL) 404 free(key->key); 405 if (key->pin != NULL) 406 free(key->pin); 407 408 memset(key, 0, sizeof(*key)); 409 free(key); 410 } 411 412 /* Convert hex ASCII to int4 */ 413 static int 414 hexa2int4(char *a) 415 { 416 if ('0' <= *a && *a <= '9') 417 return (*a - '0'); 418 419 if ('A' <= *a && *a <= 'F') 420 return (*a - 'A' + 0xa); 421 422 if ('a' <= *a && *a <= 'f') 423 return (*a - 'a' + 0xa); 424 425 syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a); 426 exit(1); 427 } 428 429 /* Convert hex ASCII to int8 */ 430 static int 431 hexa2int8(char *a) 432 { 433 return ((hexa2int4(a) << 4) | hexa2int4(a + 1)); 434 } 435 436