xref: /freebsd/usr.sbin/bluetooth/hcsecd/parser.y (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
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$
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 
47 static	void	free_key (link_key_p key);
48 static	int	hexa2int4(char *a);
49 static	int	hexa2int8(char *a);
50 
51 extern	int			 yylineno;
52 static	LIST_HEAD(, link_key)	 link_keys;
53 	char			*config_file = "/etc/bluetooth/hcsecd.conf";
54 
55 static	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 
67 config:		line
68 		| config line
69 		;
70 
71 line:		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 
96 options:	option ';'
97 		| options option ';'
98 		;
99 
100 option:		bdaddr
101 		| name
102 		| key
103 		| pin
104 		;
105 
106 bdaddr:		T_BDADDR T_BDADDRSTRING
107 			{
108 			if (!bt_aton($2, &key->bdaddr)) {
109 				syslog(LOG_ERR, "Cound not parse BDADDR " \
110 						"'%s'", $2);
111 				exit(1);
112 			}
113 			}
114 		;
115 
116 name:		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 
130 key:		T_KEY T_HEXSTRING
131 			{
132 			int	i, len;
133 
134 			if (key->key != NULL)
135 				free(key->key);
136 
137 			key->key = (u_int8_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 
162 pin:		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 */
186 void
187 yyerror(char const *message)
188 {
189 	syslog(LOG_ERR, "%s in line %d", message, yylineno);
190 }
191 
192 /* Re-read config file */
193 void
194 read_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 */
224 void
225 clean_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 */
236 link_key_p
237 get_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 */
256 void
257 dump_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 */
287 int
288 read_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 = (u_int8_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 */
349 int
350 dump_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 */
395 static void
396 free_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 */
410 static int
411 hexa2int4(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 */
427 static int
428 hexa2int8(char *a)
429 {
430 	return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
431 }
432 
433