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: src/usr.sbin/bluetooth/hcsecd/parser.y,v 1.4 2004/09/14 20:04:33 emax Exp $
31 */
32
33 #include <sys/fcntl.h>
34 #include <sys/queue.h>
35 #include <bluetooth.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <unistd.h>
44 #include "bthcid.h"
45
46 #if YYPATCH < 20180510
47 int yylex (void);
48 #endif
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 void yyerror(const char *);
55 extern int yylineno;
56 extern FILE *yyin;
57
58 static LIST_HEAD(, link_key) link_keys;
59
60 const char *config_file = "/etc/bluetooth/bthcid.conf";
61 static link_key_p key = NULL;
62 %}
63
64 %union {
65 char *string;
66 }
67
68 %token <string> T_BDADDRSTRING T_HEXSTRING T_STRING
69 %token T_DEVICE T_BDADDR T_NAME T_KEY T_PIN T_NOKEY T_NOPIN T_JUNK
70
71 %%
72
73 config: line
74 | config line
75 ;
76
77 line: T_DEVICE
78 {
79 key = (link_key_p) malloc(sizeof(*key));
80 if (key == NULL) {
81 syslog(LOG_ERR, "Could not allocate new " \
82 "config entry");
83 exit(1);
84 }
85
86 memset(key, 0, sizeof(*key));
87 }
88 '{' options '}'
89 {
90 if (get_key(&key->bdaddr, 1) != NULL) {
91 syslog(LOG_ERR, "Ignoring duplicated entry " \
92 "for bdaddr %s",
93 bt_ntoa(&key->bdaddr, NULL));
94 free_key(key);
95 } else
96 LIST_INSERT_HEAD(&link_keys, key, next);
97
98 key = NULL;
99 }
100 ;
101
102 options: option ';'
103 | options option ';'
104 ;
105
106 option: bdaddr
107 | name
108 | key
109 | pin
110 ;
111
112 bdaddr: T_BDADDR T_BDADDRSTRING
113 {
114 if (!bt_aton($2, &key->bdaddr)) {
115 syslog(LOG_ERR, "Could not parse BD_ADDR " \
116 "'%s'", $2);
117 exit(1);
118 }
119 }
120 ;
121
122 name: T_NAME T_STRING
123 {
124 if (key->name != NULL)
125 free(key->name);
126
127 key->name = strdup($2);
128 if (key->name == NULL) {
129 syslog(LOG_ERR, "Could not allocate new " \
130 "device name");
131 exit(1);
132 }
133 }
134 ;
135
136 key: T_KEY T_HEXSTRING
137 {
138 int i, len;
139
140 if (key->key != NULL)
141 free(key->key);
142
143 key->key = (uint8_t *) malloc(HCI_KEY_SIZE);
144 if (key->key == NULL) {
145 syslog(LOG_ERR, "Could not allocate new " \
146 "link key");
147 exit(1);
148 }
149
150 memset(key->key, 0, HCI_KEY_SIZE);
151
152 len = strlen($2) / 2;
153 if (len > HCI_KEY_SIZE)
154 len = HCI_KEY_SIZE;
155
156 for (i = 0; i < len; i ++)
157 key->key[i] = hexa2int8((char *)($2) + 2*i);
158 }
159 | T_KEY T_NOKEY
160 {
161 if (key->key != NULL)
162 free(key->key);
163
164 key->key = NULL;
165 }
166 ;
167
168 pin: T_PIN T_STRING
169 {
170 if (key->pin != NULL)
171 free(key->pin);
172
173 key->pin = strdup($2);
174 if (key->pin == NULL) {
175 syslog(LOG_ERR, "Could not allocate new " \
176 "PIN code");
177 exit(1);
178 }
179 }
180 | T_PIN T_NOPIN
181 {
182 if (key->pin != NULL)
183 free(key->pin);
184
185 key->pin = NULL;
186 }
187 ;
188
189 %%
190
191 /* Display parser error message */
192 void
193 yyerror(char const *message)
194 {
195 syslog(LOG_ERR, "%s in line %d", message, yylineno);
196 }
197
198 /* Re-read config file */
199 void
read_config_file(void)200 read_config_file(void)
201 {
202 if (config_file == NULL) {
203 syslog(LOG_ERR, "Unknown config file name!");
204 exit(1);
205 }
206
207 if ((yyin = fopen(config_file, "r")) == NULL) {
208 syslog(LOG_ERR, "Could not open config file '%s'. %s (%d)",
209 config_file, strerror(errno), errno);
210 exit(1);
211 }
212
213 clean_config();
214 if (yyparse() < 0) {
215 syslog(LOG_ERR, "Could not parse config file '%s'",config_file);
216 exit(1);
217 }
218
219 fclose(yyin);
220 yyin = NULL;
221
222 #ifdef __config_debug__
223 dump_config();
224 #endif
225 }
226
227 /* Clean config */
228 void
clean_config(void)229 clean_config(void)
230 {
231 link_key_p lkey = NULL;
232
233 while ((lkey = LIST_FIRST(&link_keys)) != NULL) {
234 LIST_REMOVE(lkey, next);
235 free_key(lkey);
236 }
237 }
238
239 /* Find link key entry in the list. Return exact or default match */
240 link_key_p
get_key(bdaddr_p bdaddr,int exact_match)241 get_key(bdaddr_p bdaddr, int exact_match)
242 {
243 link_key_p lkey = NULL, defkey = NULL;
244
245 LIST_FOREACH(lkey, &link_keys, next) {
246 if (memcmp(bdaddr, &lkey->bdaddr, sizeof(lkey->bdaddr)) == 0)
247 break;
248
249 if (!exact_match)
250 if (memcmp(BDADDR_ANY, &lkey->bdaddr,
251 sizeof(lkey->bdaddr)) == 0)
252 defkey = lkey;
253 }
254
255 return ((lkey != NULL)? lkey : defkey);
256 }
257
258 #ifdef __config_debug__
259 /* Dump config */
260 void
dump_config(void)261 dump_config(void)
262 {
263 link_key_p lkey = NULL;
264 char buffer[64];
265
266 LIST_FOREACH(lkey, &link_keys, next) {
267 if (lkey->key != NULL)
268 snprintf(buffer, sizeof(buffer),
269 "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
270 lkey->key[0], lkey->key[1], lkey->key[2],
271 lkey->key[3], lkey->key[4], lkey->key[5],
272 lkey->key[6], lkey->key[7], lkey->key[8],
273 lkey->key[9], lkey->key[10], lkey->key[11],
274 lkey->key[12], lkey->key[13], lkey->key[14],
275 lkey->key[15]);
276
277 syslog(LOG_DEBUG,
278 "device %s " \
279 "bdaddr %s " \
280 "pin %s " \
281 "key %s",
282 (lkey->name != NULL)? lkey->name : "noname",
283 bt_ntoa(&lkey->bdaddr, NULL),
284 (lkey->pin != NULL)? lkey->pin : "nopin",
285 (lkey->key != NULL)? buffer : "nokey");
286 }
287 }
288 #endif
289
290 /* Read keys file */
291 int
read_keys_file(void)292 read_keys_file(void)
293 {
294 FILE *f = NULL;
295 link_key_t *lkey = NULL;
296 char buf[BTHCID_BUFFER_SIZE], *p = NULL, *cp = NULL;
297 bdaddr_t bdaddr;
298 int i, len;
299
300 if ((f = fopen(BTHCID_KEYSFILE, "r")) == NULL) {
301 if (errno == ENOENT)
302 return (0);
303
304 syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n",
305 BTHCID_KEYSFILE, strerror(errno), errno);
306
307 return (-1);
308 }
309
310 while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
311 if (*p == '#')
312 continue;
313 if ((cp = strpbrk(p, " ")) == NULL)
314 continue;
315
316 *cp++ = '\0';
317
318 if (!bt_aton(p, &bdaddr))
319 continue;
320
321 if ((lkey = get_key(&bdaddr, 1)) == NULL)
322 continue;
323
324 if (lkey->key == NULL) {
325 lkey->key = (uint8_t *) malloc(HCI_KEY_SIZE);
326 if (lkey->key == NULL) {
327 syslog(LOG_ERR, "Could not allocate link key");
328 exit(1);
329 }
330 }
331
332 memset(lkey->key, 0, HCI_KEY_SIZE);
333
334 len = strlen(cp) / 2;
335 if (len > HCI_KEY_SIZE)
336 len = HCI_KEY_SIZE;
337
338 for (i = 0; i < len; i ++)
339 lkey->key[i] = hexa2int8(cp + 2*i);
340
341 syslog(LOG_DEBUG, "Restored link key for the entry, " \
342 "remote bdaddr %s, name '%s'",
343 bt_ntoa(&lkey->bdaddr, NULL),
344 (lkey->name != NULL)? lkey->name : "No name");
345 }
346
347 fclose(f);
348
349 return (0);
350 }
351
352 /* Dump keys file */
353 int
dump_keys_file(void)354 dump_keys_file(void)
355 {
356 link_key_p lkey = NULL;
357 char tmp[PATH_MAX], buf[BTHCID_BUFFER_SIZE];
358 int f;
359
360 snprintf(tmp, sizeof(tmp), "%s.tmp", BTHCID_KEYSFILE);
361 if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) {
362 syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n",
363 tmp, strerror(errno), errno);
364 return (-1);
365 }
366
367 LIST_FOREACH(lkey, &link_keys, next) {
368 if (lkey->key == NULL)
369 continue;
370
371 snprintf(buf, sizeof(buf),
372 "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
373 bt_ntoa(&lkey->bdaddr, NULL),
374 lkey->key[0], lkey->key[1], lkey->key[2], lkey->key[3],
375 lkey->key[4], lkey->key[5], lkey->key[6], lkey->key[7],
376 lkey->key[8], lkey->key[9], lkey->key[10], lkey->key[11],
377 lkey->key[12], lkey->key[13], lkey->key[14], lkey->key[15]);
378
379 if (write(f, buf, strlen(buf)) < 0) {
380 syslog(LOG_ERR, "Could not write temp keys file. " \
381 "%s (%d)\n", strerror(errno), errno);
382 break;
383 }
384 }
385
386 close(f);
387
388 if (rename(tmp, BTHCID_KEYSFILE) < 0) {
389 syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n",
390 tmp, BTHCID_KEYSFILE, strerror(errno), errno);
391 unlink(tmp);
392 return (-1);
393 }
394
395 return (0);
396 }
397
398 /* Free key entry */
399 static void
free_key(link_key_p lkey)400 free_key(link_key_p lkey)
401 {
402 if (lkey->name != NULL)
403 free(lkey->name);
404 if (lkey->key != NULL)
405 free(lkey->key);
406 if (lkey->pin != NULL)
407 free(lkey->pin);
408
409 memset(lkey, 0, sizeof(*lkey));
410 free(lkey);
411 }
412
413 /* Convert hex ASCII to int4 */
414 static int
hexa2int4(char * a)415 hexa2int4(char *a)
416 {
417 if ('0' <= *a && *a <= '9')
418 return (*a - '0');
419
420 if ('A' <= *a && *a <= 'F')
421 return (*a - 'A' + 0xa);
422
423 if ('a' <= *a && *a <= 'f')
424 return (*a - 'a' + 0xa);
425
426 syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a);
427 exit(1);
428 }
429
430 /* Convert hex ASCII to int8 */
431 static int
hexa2int8(char * a)432 hexa2int8(char *a)
433 {
434 return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
435 }
436
437