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