parser.y revision 302408
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: stable/11/usr.sbin/bluetooth/hcsecd/parser.y 281210 2015-04-07 16:48:23Z takawata $
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
50static	void	free_key (link_key_p key);
51static	int	hexa2int4(char *a);
52static	int	hexa2int8(char *a);
53
54extern	int			 yylineno;
55static	LIST_HEAD(, link_key)	 link_keys;
56	char			*config_file = "/etc/bluetooth/hcsecd.conf";
57
58static	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
70config:		line
71		| config line
72		;
73
74line:		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
99options:	option ';'
100		| options option ';'
101		;
102
103option:		bdaddr
104		| name
105		| key
106		| pin
107		;
108
109bdaddr:		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
119name:		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
133key:		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
165pin:		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 */
189void
190yyerror(char const *message)
191{
192	syslog(LOG_ERR, "%s in line %d", message, yylineno);
193}
194
195/* Re-read config file */
196void
197read_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 */
227void
228clean_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 */
239link_key_p
240get_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 */
259void
260dump_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 */
290int
291read_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 */
352int
353dump_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 */
398static void
399free_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 */
413static int
414hexa2int4(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 */
430static int
431hexa2int8(char *a)
432{
433	return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
434}
435
436