1114879Sjulian%{ 2114879Sjulian/* 3114879Sjulian * parser.y 4114879Sjulian * 5114879Sjulian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 6114879Sjulian * All rights reserved. 7114879Sjulian * 8114879Sjulian * Redistribution and use in source and binary forms, with or without 9114879Sjulian * modification, are permitted provided that the following conditions 10114879Sjulian * are met: 11114879Sjulian * 1. Redistributions of source code must retain the above copyright 12114879Sjulian * notice, this list of conditions and the following disclaimer. 13114879Sjulian * 2. Redistributions in binary form must reproduce the above copyright 14114879Sjulian * notice, this list of conditions and the following disclaimer in the 15114879Sjulian * documentation and/or other materials provided with the distribution. 16114879Sjulian * 17114879Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18114879Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19114879Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20114879Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21114879Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22114879Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23114879Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24114879Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25114879Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26114879Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27114879Sjulian * SUCH DAMAGE. 28114879Sjulian * 29121054Semax * $Id: parser.y,v 1.5 2003/06/07 21:22:30 max Exp $ 30114879Sjulian * $FreeBSD$ 31114879Sjulian */ 32114879Sjulian 33121054Semax#include <sys/fcntl.h> 34114879Sjulian#include <sys/queue.h> 35121054Semax#include <bluetooth.h> 36114879Sjulian#include <errno.h> 37121054Semax#include <limits.h> 38114879Sjulian#include <stdio.h> 39114879Sjulian#include <stdarg.h> 40114879Sjulian#include <string.h> 41114879Sjulian#include <syslog.h> 42135245Semax#include <unistd.h> 43114879Sjulian#include "hcsecd.h" 44114879Sjulian 45114879Sjulian int yyparse (void); 46114879Sjulian int yylex (void); 47114879Sjulian 48114879Sjulianstatic void free_key (link_key_p key); 49114879Sjulianstatic int hexa2int4(char *a); 50114879Sjulianstatic int hexa2int8(char *a); 51114879Sjulian 52114879Sjulianextern int yylineno; 53114879Sjulianstatic LIST_HEAD(, link_key) link_keys; 54121054Semax char *config_file = "/etc/bluetooth/hcsecd.conf"; 55114879Sjulian 56114879Sjulianstatic link_key_p key = NULL; 57114879Sjulian%} 58114879Sjulian 59114879Sjulian%union { 60114879Sjulian char *string; 61114879Sjulian} 62114879Sjulian 63114879Sjulian%token <string> T_BDADDRSTRING T_HEXSTRING T_STRING 64114879Sjulian%token T_DEVICE T_BDADDR T_NAME T_KEY T_PIN T_NOKEY T_NOPIN T_JUNK 65114879Sjulian 66114879Sjulian%% 67114879Sjulian 68114879Sjulianconfig: line 69114879Sjulian | config line 70114879Sjulian ; 71114879Sjulian 72114879Sjulianline: T_DEVICE 73114879Sjulian { 74114879Sjulian key = (link_key_p) malloc(sizeof(*key)); 75114879Sjulian if (key == NULL) { 76114879Sjulian syslog(LOG_ERR, "Could not allocate new " \ 77114879Sjulian "config entry"); 78114879Sjulian exit(1); 79114879Sjulian } 80114879Sjulian 81114879Sjulian memset(key, 0, sizeof(*key)); 82114879Sjulian } 83114879Sjulian '{' options '}' 84114879Sjulian { 85114879Sjulian if (get_key(&key->bdaddr, 1) != NULL) { 86114879Sjulian syslog(LOG_ERR, "Ignoring duplicated entry " \ 87121054Semax "for bdaddr %s", 88121054Semax bt_ntoa(&key->bdaddr, NULL)); 89114879Sjulian free_key(key); 90114879Sjulian } else 91114879Sjulian LIST_INSERT_HEAD(&link_keys, key, next); 92114879Sjulian 93114879Sjulian key = NULL; 94114879Sjulian } 95114879Sjulian ; 96114879Sjulian 97114879Sjulianoptions: option ';' 98114879Sjulian | options option ';' 99114879Sjulian ; 100114879Sjulian 101114879Sjulianoption: bdaddr 102114879Sjulian | name 103114879Sjulian | key 104114879Sjulian | pin 105114879Sjulian ; 106114879Sjulian 107114879Sjulianbdaddr: T_BDADDR T_BDADDRSTRING 108114879Sjulian { 109121054Semax if (!bt_aton($2, &key->bdaddr)) { 110133178Semax syslog(LOG_ERR, "Cound not parse BD_ADDR " \ 111114879Sjulian "'%s'", $2); 112114879Sjulian exit(1); 113114879Sjulian } 114114879Sjulian } 115114879Sjulian ; 116114879Sjulian 117114879Sjulianname: T_NAME T_STRING 118114879Sjulian { 119114879Sjulian if (key->name != NULL) 120114879Sjulian free(key->name); 121114879Sjulian 122114879Sjulian key->name = strdup($2); 123114879Sjulian if (key->name == NULL) { 124114879Sjulian syslog(LOG_ERR, "Could not allocate new " \ 125114879Sjulian "device name"); 126114879Sjulian exit(1); 127114879Sjulian } 128114879Sjulian } 129114879Sjulian ; 130114879Sjulian 131114879Sjuliankey: T_KEY T_HEXSTRING 132114879Sjulian { 133114879Sjulian int i, len; 134114879Sjulian 135114879Sjulian if (key->key != NULL) 136114879Sjulian free(key->key); 137114879Sjulian 138133178Semax key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE); 139114879Sjulian if (key->key == NULL) { 140114879Sjulian syslog(LOG_ERR, "Could not allocate new " \ 141114879Sjulian "link key"); 142114879Sjulian exit(1); 143114879Sjulian } 144114879Sjulian 145114879Sjulian memset(key->key, 0, NG_HCI_KEY_SIZE); 146114879Sjulian 147114879Sjulian len = strlen($2) / 2; 148114879Sjulian if (len > NG_HCI_KEY_SIZE) 149114879Sjulian len = NG_HCI_KEY_SIZE; 150114879Sjulian 151114879Sjulian for (i = 0; i < len; i ++) 152114879Sjulian key->key[i] = hexa2int8((char *)($2) + 2*i); 153114879Sjulian } 154114879Sjulian | T_KEY T_NOKEY 155114879Sjulian { 156114879Sjulian if (key->key != NULL) 157114879Sjulian free(key->key); 158114879Sjulian 159114879Sjulian key->key = NULL; 160114879Sjulian } 161114879Sjulian ; 162114879Sjulian 163114879Sjulianpin: T_PIN T_STRING 164114879Sjulian { 165114879Sjulian if (key->pin != NULL) 166114879Sjulian free(key->pin); 167114879Sjulian 168114879Sjulian key->pin = strdup($2); 169114879Sjulian if (key->pin == NULL) { 170114879Sjulian syslog(LOG_ERR, "Could not allocate new " \ 171114879Sjulian "PIN code"); 172114879Sjulian exit(1); 173114879Sjulian } 174114879Sjulian } 175114879Sjulian | T_PIN T_NOPIN 176114879Sjulian { 177114879Sjulian if (key->pin != NULL) 178114879Sjulian free(key->pin); 179114879Sjulian 180114879Sjulian key->pin = NULL; 181114879Sjulian } 182114879Sjulian ; 183114879Sjulian 184114879Sjulian%% 185114879Sjulian 186114879Sjulian/* Display parser error message */ 187114879Sjulianvoid 188114879Sjulianyyerror(char const *message) 189114879Sjulian{ 190114879Sjulian syslog(LOG_ERR, "%s in line %d", message, yylineno); 191114879Sjulian} 192114879Sjulian 193114879Sjulian/* Re-read config file */ 194114879Sjulianvoid 195121054Semaxread_config_file(void) 196114879Sjulian{ 197114879Sjulian extern FILE *yyin; 198114879Sjulian 199114879Sjulian if (config_file == NULL) { 200114879Sjulian syslog(LOG_ERR, "Unknown config file name!"); 201114879Sjulian exit(1); 202114879Sjulian } 203114879Sjulian 204114879Sjulian if ((yyin = fopen(config_file, "r")) == NULL) { 205114879Sjulian syslog(LOG_ERR, "Could not open config file '%s'. %s (%d)", 206114879Sjulian config_file, strerror(errno), errno); 207114879Sjulian exit(1); 208114879Sjulian } 209114879Sjulian 210114879Sjulian clean_config(); 211114879Sjulian if (yyparse() < 0) { 212114879Sjulian syslog(LOG_ERR, "Could not parse config file '%s'",config_file); 213114879Sjulian exit(1); 214114879Sjulian } 215114879Sjulian 216114879Sjulian fclose(yyin); 217114879Sjulian yyin = NULL; 218114879Sjulian 219114879Sjulian#if __config_debug__ 220114879Sjulian dump_config(); 221114879Sjulian#endif 222114879Sjulian} 223114879Sjulian 224114879Sjulian/* Clean config */ 225114879Sjulianvoid 226114879Sjulianclean_config(void) 227114879Sjulian{ 228114879Sjulian link_key_p key = NULL; 229114879Sjulian 230114879Sjulian while ((key = LIST_FIRST(&link_keys)) != NULL) { 231114879Sjulian LIST_REMOVE(key, next); 232114879Sjulian free_key(key); 233114879Sjulian } 234114879Sjulian} 235114879Sjulian 236114879Sjulian/* Find link key entry in the list. Return exact or default match */ 237114879Sjulianlink_key_p 238114879Sjulianget_key(bdaddr_p bdaddr, int exact_match) 239114879Sjulian{ 240114879Sjulian link_key_p key = NULL, defkey = NULL; 241114879Sjulian 242114879Sjulian LIST_FOREACH(key, &link_keys, next) { 243114879Sjulian if (memcmp(bdaddr, &key->bdaddr, sizeof(key->bdaddr)) == 0) 244114879Sjulian break; 245114879Sjulian 246114879Sjulian if (!exact_match) 247114879Sjulian if (memcmp(NG_HCI_BDADDR_ANY, &key->bdaddr, 248114879Sjulian sizeof(key->bdaddr)) == 0) 249114879Sjulian defkey = key; 250114879Sjulian } 251114879Sjulian 252114879Sjulian return ((key != NULL)? key : defkey); 253114879Sjulian} 254114879Sjulian 255114879Sjulian#if __config_debug__ 256114879Sjulian/* Dump config */ 257114879Sjulianvoid 258114879Sjuliandump_config(void) 259114879Sjulian{ 260114879Sjulian link_key_p key = NULL; 261114879Sjulian char buffer[64]; 262114879Sjulian 263114879Sjulian LIST_FOREACH(key, &link_keys, next) { 264114879Sjulian if (key->key != NULL) 265114879Sjulian snprintf(buffer, sizeof(buffer), 266114879Sjulian"0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 267114879Sjulian key->key[0], key->key[1], key->key[2], 268114879Sjulian key->key[3], key->key[4], key->key[5], 269114879Sjulian key->key[6], key->key[7], key->key[8], 270114879Sjulian key->key[9], key->key[10], key->key[11], 271114879Sjulian key->key[12], key->key[13], key->key[14], 272114879Sjulian key->key[15]); 273114879Sjulian 274114879Sjulian syslog(LOG_DEBUG, 275114879Sjulian"device %s " \ 276121054Semax"bdaddr %s " \ 277114879Sjulian"pin %s " \ 278114879Sjulian"key %s", 279114879Sjulian (key->name != NULL)? key->name : "noname", 280121054Semax bt_ntoa(&key->bdaddr, NULL), 281114879Sjulian (key->pin != NULL)? key->pin : "nopin", 282114879Sjulian (key->key != NULL)? buffer : "nokey"); 283114879Sjulian } 284114879Sjulian} 285114879Sjulian#endif 286114879Sjulian 287121054Semax/* Read keys file */ 288121054Semaxint 289121054Semaxread_keys_file(void) 290121054Semax{ 291121054Semax FILE *f = NULL; 292121054Semax link_key_t *key = NULL; 293121054Semax char buf[HCSECD_BUFFER_SIZE], *p = NULL, *cp = NULL; 294121054Semax bdaddr_t bdaddr; 295121054Semax int i, len; 296121054Semax 297121054Semax if ((f = fopen(HCSECD_KEYSFILE, "r")) == NULL) { 298121054Semax if (errno == ENOENT) 299121054Semax return (0); 300121054Semax 301121054Semax syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n", 302121054Semax HCSECD_KEYSFILE, strerror(errno), errno); 303121054Semax 304121054Semax return (-1); 305121054Semax } 306121054Semax 307121054Semax while ((p = fgets(buf, sizeof(buf), f)) != NULL) { 308121054Semax if (*p == '#') 309121054Semax continue; 310121054Semax if ((cp = strpbrk(p, " ")) == NULL) 311121054Semax continue; 312121054Semax 313121054Semax *cp++ = '\0'; 314121054Semax 315121054Semax if (!bt_aton(p, &bdaddr)) 316121054Semax continue; 317121054Semax 318121054Semax if ((key = get_key(&bdaddr, 1)) == NULL) 319121054Semax continue; 320121054Semax 321121054Semax if (key->key == NULL) { 322133178Semax key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE); 323121054Semax if (key->key == NULL) { 324121054Semax syslog(LOG_ERR, "Could not allocate link key"); 325121054Semax exit(1); 326121054Semax } 327121054Semax } 328121054Semax 329121054Semax memset(key->key, 0, NG_HCI_KEY_SIZE); 330121054Semax 331121054Semax len = strlen(cp) / 2; 332121054Semax if (len > NG_HCI_KEY_SIZE) 333121054Semax len = NG_HCI_KEY_SIZE; 334121054Semax 335121054Semax for (i = 0; i < len; i ++) 336121054Semax key->key[i] = hexa2int8(cp + 2*i); 337121054Semax 338121054Semax syslog(LOG_DEBUG, "Restored link key for the entry, " \ 339121054Semax "remote bdaddr %s, name '%s'", 340121054Semax bt_ntoa(&key->bdaddr, NULL), 341121054Semax (key->name != NULL)? key->name : "No name"); 342121054Semax } 343121054Semax 344121054Semax fclose(f); 345121054Semax 346121054Semax return (0); 347121054Semax} 348121054Semax 349121054Semax/* Dump keys file */ 350121054Semaxint 351121054Semaxdump_keys_file(void) 352121054Semax{ 353121054Semax link_key_p key = NULL; 354121054Semax char tmp[PATH_MAX], buf[HCSECD_BUFFER_SIZE]; 355121054Semax int f; 356121054Semax 357121054Semax snprintf(tmp, sizeof(tmp), "%s.tmp", HCSECD_KEYSFILE); 358121054Semax if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) { 359121054Semax syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n", 360121054Semax tmp, strerror(errno), errno); 361121054Semax return (-1); 362121054Semax } 363121054Semax 364121054Semax LIST_FOREACH(key, &link_keys, next) { 365121054Semax if (key->key == NULL) 366121054Semax continue; 367121054Semax 368121054Semax snprintf(buf, sizeof(buf), 369121054Semax"%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", 370121054Semax bt_ntoa(&key->bdaddr, NULL), 371121054Semax key->key[0], key->key[1], key->key[2], key->key[3], 372121054Semax key->key[4], key->key[5], key->key[6], key->key[7], 373121054Semax key->key[8], key->key[9], key->key[10], key->key[11], 374121054Semax key->key[12], key->key[13], key->key[14], key->key[15]); 375121054Semax 376121054Semax if (write(f, buf, strlen(buf)) < 0) { 377121054Semax syslog(LOG_ERR, "Could not write temp keys file. " \ 378121054Semax "%s (%d)\n", strerror(errno), errno); 379121054Semax break; 380121054Semax } 381121054Semax } 382121054Semax 383121054Semax close(f); 384121054Semax 385121054Semax if (rename(tmp, HCSECD_KEYSFILE) < 0) { 386121054Semax syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n", 387121054Semax tmp, HCSECD_KEYSFILE, strerror(errno), errno); 388121054Semax unlink(tmp); 389121054Semax return (-1); 390121054Semax } 391121054Semax 392121054Semax return (0); 393121054Semax} 394121054Semax 395114879Sjulian/* Free key entry */ 396114879Sjulianstatic void 397114879Sjulianfree_key(link_key_p key) 398114879Sjulian{ 399114879Sjulian if (key->name != NULL) 400114879Sjulian free(key->name); 401114879Sjulian if (key->key != NULL) 402114879Sjulian free(key->key); 403114879Sjulian if (key->pin != NULL) 404114879Sjulian free(key->pin); 405114879Sjulian 406114879Sjulian memset(key, 0, sizeof(*key)); 407114879Sjulian free(key); 408114879Sjulian} 409114879Sjulian 410114879Sjulian/* Convert hex ASCII to int4 */ 411114879Sjulianstatic int 412114879Sjulianhexa2int4(char *a) 413114879Sjulian{ 414114879Sjulian if ('0' <= *a && *a <= '9') 415114879Sjulian return (*a - '0'); 416114879Sjulian 417114879Sjulian if ('A' <= *a && *a <= 'F') 418114879Sjulian return (*a - 'A' + 0xa); 419114879Sjulian 420114879Sjulian if ('a' <= *a && *a <= 'f') 421114879Sjulian return (*a - 'a' + 0xa); 422114879Sjulian 423114879Sjulian syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a); 424114879Sjulian exit(1); 425114879Sjulian} 426114879Sjulian 427114879Sjulian/* Convert hex ASCII to int8 */ 428114879Sjulianstatic int 429114879Sjulianhexa2int8(char *a) 430114879Sjulian{ 431114879Sjulian return ((hexa2int4(a) << 4) | hexa2int4(a + 1)); 432114879Sjulian} 433114879Sjulian 434