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