xref: /freebsd/usr.sbin/bluetooth/hcsecd/parser.y (revision 7bd6fde3)
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 <unistd.h>
43 #include "hcsecd.h"
44 
45 	int	yyparse  (void);
46 	int	yylex    (void);
47 
48 static	void	free_key (link_key_p key);
49 static	int	hexa2int4(char *a);
50 static	int	hexa2int8(char *a);
51 
52 extern	int			 yylineno;
53 static	LIST_HEAD(, link_key)	 link_keys;
54 	char			*config_file = "/etc/bluetooth/hcsecd.conf";
55 
56 static	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 
68 config:		line
69 		| config line
70 		;
71 
72 line:		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 
97 options:	option ';'
98 		| options option ';'
99 		;
100 
101 option:		bdaddr
102 		| name
103 		| key
104 		| pin
105 		;
106 
107 bdaddr:		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 
117 name:		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 
131 key:		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 
163 pin:		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 */
187 void
188 yyerror(char const *message)
189 {
190 	syslog(LOG_ERR, "%s in line %d", message, yylineno);
191 }
192 
193 /* Re-read config file */
194 void
195 read_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 */
225 void
226 clean_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 */
237 link_key_p
238 get_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 */
257 void
258 dump_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 */
288 int
289 read_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 */
350 int
351 dump_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 */
396 static void
397 free_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 */
411 static int
412 hexa2int4(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 */
428 static int
429 hexa2int8(char *a)
430 {
431 	return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
432 }
433 
434