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> 39235789Sbapt#include <stdlib.h> 40114879Sjulian#include <stdarg.h> 41114879Sjulian#include <string.h> 42114879Sjulian#include <syslog.h> 43135245Semax#include <unistd.h> 44114879Sjulian#include "hcsecd.h" 45114879Sjulian 46114879Sjulian int yyparse (void); 47114879Sjulian int yylex (void); 48114879Sjulian 49114879Sjulianstatic void free_key (link_key_p key); 50114879Sjulianstatic int hexa2int4(char *a); 51114879Sjulianstatic int hexa2int8(char *a); 52114879Sjulian 53114879Sjulianextern int yylineno; 54114879Sjulianstatic LIST_HEAD(, link_key) link_keys; 55121054Semax char *config_file = "/etc/bluetooth/hcsecd.conf"; 56114879Sjulian 57114879Sjulianstatic link_key_p key = NULL; 58114879Sjulian%} 59114879Sjulian 60114879Sjulian%union { 61114879Sjulian char *string; 62114879Sjulian} 63114879Sjulian 64114879Sjulian%token <string> T_BDADDRSTRING T_HEXSTRING T_STRING 65114879Sjulian%token T_DEVICE T_BDADDR T_NAME T_KEY T_PIN T_NOKEY T_NOPIN T_JUNK 66114879Sjulian 67114879Sjulian%% 68114879Sjulian 69114879Sjulianconfig: line 70114879Sjulian | config line 71114879Sjulian ; 72114879Sjulian 73114879Sjulianline: T_DEVICE 74114879Sjulian { 75114879Sjulian key = (link_key_p) malloc(sizeof(*key)); 76114879Sjulian if (key == NULL) { 77114879Sjulian syslog(LOG_ERR, "Could not allocate new " \ 78114879Sjulian "config entry"); 79114879Sjulian exit(1); 80114879Sjulian } 81114879Sjulian 82114879Sjulian memset(key, 0, sizeof(*key)); 83114879Sjulian } 84114879Sjulian '{' options '}' 85114879Sjulian { 86114879Sjulian if (get_key(&key->bdaddr, 1) != NULL) { 87114879Sjulian syslog(LOG_ERR, "Ignoring duplicated entry " \ 88121054Semax "for bdaddr %s", 89121054Semax bt_ntoa(&key->bdaddr, NULL)); 90114879Sjulian free_key(key); 91114879Sjulian } else 92114879Sjulian LIST_INSERT_HEAD(&link_keys, key, next); 93114879Sjulian 94114879Sjulian key = NULL; 95114879Sjulian } 96114879Sjulian ; 97114879Sjulian 98114879Sjulianoptions: option ';' 99114879Sjulian | options option ';' 100114879Sjulian ; 101114879Sjulian 102114879Sjulianoption: bdaddr 103114879Sjulian | name 104114879Sjulian | key 105114879Sjulian | pin 106114879Sjulian ; 107114879Sjulian 108114879Sjulianbdaddr: T_BDADDR T_BDADDRSTRING 109114879Sjulian { 110121054Semax if (!bt_aton($2, &key->bdaddr)) { 111133178Semax syslog(LOG_ERR, "Cound not parse BD_ADDR " \ 112114879Sjulian "'%s'", $2); 113114879Sjulian exit(1); 114114879Sjulian } 115114879Sjulian } 116114879Sjulian ; 117114879Sjulian 118114879Sjulianname: T_NAME T_STRING 119114879Sjulian { 120114879Sjulian if (key->name != NULL) 121114879Sjulian free(key->name); 122114879Sjulian 123114879Sjulian key->name = strdup($2); 124114879Sjulian if (key->name == NULL) { 125114879Sjulian syslog(LOG_ERR, "Could not allocate new " \ 126114879Sjulian "device name"); 127114879Sjulian exit(1); 128114879Sjulian } 129114879Sjulian } 130114879Sjulian ; 131114879Sjulian 132114879Sjuliankey: T_KEY T_HEXSTRING 133114879Sjulian { 134114879Sjulian int i, len; 135114879Sjulian 136114879Sjulian if (key->key != NULL) 137114879Sjulian free(key->key); 138114879Sjulian 139133178Semax key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE); 140114879Sjulian if (key->key == NULL) { 141114879Sjulian syslog(LOG_ERR, "Could not allocate new " \ 142114879Sjulian "link key"); 143114879Sjulian exit(1); 144114879Sjulian } 145114879Sjulian 146114879Sjulian memset(key->key, 0, NG_HCI_KEY_SIZE); 147114879Sjulian 148114879Sjulian len = strlen($2) / 2; 149114879Sjulian if (len > NG_HCI_KEY_SIZE) 150114879Sjulian len = NG_HCI_KEY_SIZE; 151114879Sjulian 152114879Sjulian for (i = 0; i < len; i ++) 153114879Sjulian key->key[i] = hexa2int8((char *)($2) + 2*i); 154114879Sjulian } 155114879Sjulian | T_KEY T_NOKEY 156114879Sjulian { 157114879Sjulian if (key->key != NULL) 158114879Sjulian free(key->key); 159114879Sjulian 160114879Sjulian key->key = NULL; 161114879Sjulian } 162114879Sjulian ; 163114879Sjulian 164114879Sjulianpin: T_PIN T_STRING 165114879Sjulian { 166114879Sjulian if (key->pin != NULL) 167114879Sjulian free(key->pin); 168114879Sjulian 169114879Sjulian key->pin = strdup($2); 170114879Sjulian if (key->pin == NULL) { 171114879Sjulian syslog(LOG_ERR, "Could not allocate new " \ 172114879Sjulian "PIN code"); 173114879Sjulian exit(1); 174114879Sjulian } 175114879Sjulian } 176114879Sjulian | T_PIN T_NOPIN 177114879Sjulian { 178114879Sjulian if (key->pin != NULL) 179114879Sjulian free(key->pin); 180114879Sjulian 181114879Sjulian key->pin = NULL; 182114879Sjulian } 183114879Sjulian ; 184114879Sjulian 185114879Sjulian%% 186114879Sjulian 187114879Sjulian/* Display parser error message */ 188114879Sjulianvoid 189114879Sjulianyyerror(char const *message) 190114879Sjulian{ 191114879Sjulian syslog(LOG_ERR, "%s in line %d", message, yylineno); 192114879Sjulian} 193114879Sjulian 194114879Sjulian/* Re-read config file */ 195114879Sjulianvoid 196121054Semaxread_config_file(void) 197114879Sjulian{ 198114879Sjulian extern FILE *yyin; 199114879Sjulian 200114879Sjulian if (config_file == NULL) { 201114879Sjulian syslog(LOG_ERR, "Unknown config file name!"); 202114879Sjulian exit(1); 203114879Sjulian } 204114879Sjulian 205114879Sjulian if ((yyin = fopen(config_file, "r")) == NULL) { 206114879Sjulian syslog(LOG_ERR, "Could not open config file '%s'. %s (%d)", 207114879Sjulian config_file, strerror(errno), errno); 208114879Sjulian exit(1); 209114879Sjulian } 210114879Sjulian 211114879Sjulian clean_config(); 212114879Sjulian if (yyparse() < 0) { 213114879Sjulian syslog(LOG_ERR, "Could not parse config file '%s'",config_file); 214114879Sjulian exit(1); 215114879Sjulian } 216114879Sjulian 217114879Sjulian fclose(yyin); 218114879Sjulian yyin = NULL; 219114879Sjulian 220114879Sjulian#if __config_debug__ 221114879Sjulian dump_config(); 222114879Sjulian#endif 223114879Sjulian} 224114879Sjulian 225114879Sjulian/* Clean config */ 226114879Sjulianvoid 227114879Sjulianclean_config(void) 228114879Sjulian{ 229114879Sjulian link_key_p key = NULL; 230114879Sjulian 231114879Sjulian while ((key = LIST_FIRST(&link_keys)) != NULL) { 232114879Sjulian LIST_REMOVE(key, next); 233114879Sjulian free_key(key); 234114879Sjulian } 235114879Sjulian} 236114879Sjulian 237114879Sjulian/* Find link key entry in the list. Return exact or default match */ 238114879Sjulianlink_key_p 239114879Sjulianget_key(bdaddr_p bdaddr, int exact_match) 240114879Sjulian{ 241114879Sjulian link_key_p key = NULL, defkey = NULL; 242114879Sjulian 243114879Sjulian LIST_FOREACH(key, &link_keys, next) { 244114879Sjulian if (memcmp(bdaddr, &key->bdaddr, sizeof(key->bdaddr)) == 0) 245114879Sjulian break; 246114879Sjulian 247114879Sjulian if (!exact_match) 248114879Sjulian if (memcmp(NG_HCI_BDADDR_ANY, &key->bdaddr, 249114879Sjulian sizeof(key->bdaddr)) == 0) 250114879Sjulian defkey = key; 251114879Sjulian } 252114879Sjulian 253114879Sjulian return ((key != NULL)? key : defkey); 254114879Sjulian} 255114879Sjulian 256114879Sjulian#if __config_debug__ 257114879Sjulian/* Dump config */ 258114879Sjulianvoid 259114879Sjuliandump_config(void) 260114879Sjulian{ 261114879Sjulian link_key_p key = NULL; 262114879Sjulian char buffer[64]; 263114879Sjulian 264114879Sjulian LIST_FOREACH(key, &link_keys, next) { 265114879Sjulian if (key->key != NULL) 266114879Sjulian snprintf(buffer, sizeof(buffer), 267114879Sjulian"0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 268114879Sjulian key->key[0], key->key[1], key->key[2], 269114879Sjulian key->key[3], key->key[4], key->key[5], 270114879Sjulian key->key[6], key->key[7], key->key[8], 271114879Sjulian key->key[9], key->key[10], key->key[11], 272114879Sjulian key->key[12], key->key[13], key->key[14], 273114879Sjulian key->key[15]); 274114879Sjulian 275114879Sjulian syslog(LOG_DEBUG, 276114879Sjulian"device %s " \ 277121054Semax"bdaddr %s " \ 278114879Sjulian"pin %s " \ 279114879Sjulian"key %s", 280114879Sjulian (key->name != NULL)? key->name : "noname", 281121054Semax bt_ntoa(&key->bdaddr, NULL), 282114879Sjulian (key->pin != NULL)? key->pin : "nopin", 283114879Sjulian (key->key != NULL)? buffer : "nokey"); 284114879Sjulian } 285114879Sjulian} 286114879Sjulian#endif 287114879Sjulian 288121054Semax/* Read keys file */ 289121054Semaxint 290121054Semaxread_keys_file(void) 291121054Semax{ 292121054Semax FILE *f = NULL; 293121054Semax link_key_t *key = NULL; 294121054Semax char buf[HCSECD_BUFFER_SIZE], *p = NULL, *cp = NULL; 295121054Semax bdaddr_t bdaddr; 296121054Semax int i, len; 297121054Semax 298121054Semax if ((f = fopen(HCSECD_KEYSFILE, "r")) == NULL) { 299121054Semax if (errno == ENOENT) 300121054Semax return (0); 301121054Semax 302121054Semax syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n", 303121054Semax HCSECD_KEYSFILE, strerror(errno), errno); 304121054Semax 305121054Semax return (-1); 306121054Semax } 307121054Semax 308121054Semax while ((p = fgets(buf, sizeof(buf), f)) != NULL) { 309121054Semax if (*p == '#') 310121054Semax continue; 311121054Semax if ((cp = strpbrk(p, " ")) == NULL) 312121054Semax continue; 313121054Semax 314121054Semax *cp++ = '\0'; 315121054Semax 316121054Semax if (!bt_aton(p, &bdaddr)) 317121054Semax continue; 318121054Semax 319121054Semax if ((key = get_key(&bdaddr, 1)) == NULL) 320121054Semax continue; 321121054Semax 322121054Semax if (key->key == NULL) { 323133178Semax key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE); 324121054Semax if (key->key == NULL) { 325121054Semax syslog(LOG_ERR, "Could not allocate link key"); 326121054Semax exit(1); 327121054Semax } 328121054Semax } 329121054Semax 330121054Semax memset(key->key, 0, NG_HCI_KEY_SIZE); 331121054Semax 332121054Semax len = strlen(cp) / 2; 333121054Semax if (len > NG_HCI_KEY_SIZE) 334121054Semax len = NG_HCI_KEY_SIZE; 335121054Semax 336121054Semax for (i = 0; i < len; i ++) 337121054Semax key->key[i] = hexa2int8(cp + 2*i); 338121054Semax 339121054Semax syslog(LOG_DEBUG, "Restored link key for the entry, " \ 340121054Semax "remote bdaddr %s, name '%s'", 341121054Semax bt_ntoa(&key->bdaddr, NULL), 342121054Semax (key->name != NULL)? key->name : "No name"); 343121054Semax } 344121054Semax 345121054Semax fclose(f); 346121054Semax 347121054Semax return (0); 348121054Semax} 349121054Semax 350121054Semax/* Dump keys file */ 351121054Semaxint 352121054Semaxdump_keys_file(void) 353121054Semax{ 354121054Semax link_key_p key = NULL; 355121054Semax char tmp[PATH_MAX], buf[HCSECD_BUFFER_SIZE]; 356121054Semax int f; 357121054Semax 358121054Semax snprintf(tmp, sizeof(tmp), "%s.tmp", HCSECD_KEYSFILE); 359121054Semax if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) { 360121054Semax syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n", 361121054Semax tmp, strerror(errno), errno); 362121054Semax return (-1); 363121054Semax } 364121054Semax 365121054Semax LIST_FOREACH(key, &link_keys, next) { 366121054Semax if (key->key == NULL) 367121054Semax continue; 368121054Semax 369121054Semax snprintf(buf, sizeof(buf), 370121054Semax"%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", 371121054Semax bt_ntoa(&key->bdaddr, NULL), 372121054Semax key->key[0], key->key[1], key->key[2], key->key[3], 373121054Semax key->key[4], key->key[5], key->key[6], key->key[7], 374121054Semax key->key[8], key->key[9], key->key[10], key->key[11], 375121054Semax key->key[12], key->key[13], key->key[14], key->key[15]); 376121054Semax 377121054Semax if (write(f, buf, strlen(buf)) < 0) { 378121054Semax syslog(LOG_ERR, "Could not write temp keys file. " \ 379121054Semax "%s (%d)\n", strerror(errno), errno); 380121054Semax break; 381121054Semax } 382121054Semax } 383121054Semax 384121054Semax close(f); 385121054Semax 386121054Semax if (rename(tmp, HCSECD_KEYSFILE) < 0) { 387121054Semax syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n", 388121054Semax tmp, HCSECD_KEYSFILE, strerror(errno), errno); 389121054Semax unlink(tmp); 390121054Semax return (-1); 391121054Semax } 392121054Semax 393121054Semax return (0); 394121054Semax} 395121054Semax 396114879Sjulian/* Free key entry */ 397114879Sjulianstatic void 398114879Sjulianfree_key(link_key_p key) 399114879Sjulian{ 400114879Sjulian if (key->name != NULL) 401114879Sjulian free(key->name); 402114879Sjulian if (key->key != NULL) 403114879Sjulian free(key->key); 404114879Sjulian if (key->pin != NULL) 405114879Sjulian free(key->pin); 406114879Sjulian 407114879Sjulian memset(key, 0, sizeof(*key)); 408114879Sjulian free(key); 409114879Sjulian} 410114879Sjulian 411114879Sjulian/* Convert hex ASCII to int4 */ 412114879Sjulianstatic int 413114879Sjulianhexa2int4(char *a) 414114879Sjulian{ 415114879Sjulian if ('0' <= *a && *a <= '9') 416114879Sjulian return (*a - '0'); 417114879Sjulian 418114879Sjulian if ('A' <= *a && *a <= 'F') 419114879Sjulian return (*a - 'A' + 0xa); 420114879Sjulian 421114879Sjulian if ('a' <= *a && *a <= 'f') 422114879Sjulian return (*a - 'a' + 0xa); 423114879Sjulian 424114879Sjulian syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a); 425114879Sjulian exit(1); 426114879Sjulian} 427114879Sjulian 428114879Sjulian/* Convert hex ASCII to int8 */ 429114879Sjulianstatic int 430114879Sjulianhexa2int8(char *a) 431114879Sjulian{ 432114879Sjulian return ((hexa2int4(a) << 4) | hexa2int4(a + 1)); 433114879Sjulian} 434114879Sjulian 435