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