xref: /freebsd/usr.sbin/bluetooth/hcsecd/parser.y (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 %{
2 /*-
3  * parser.y
4  *
5  * SPDX-License-Identifier: BSD-2-Clause
6  *
7  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $Id: parser.y,v 1.5 2003/06/07 21:22:30 max Exp $
32  */
33 
34 #include <sys/fcntl.h>
35 #include <sys/queue.h>
36 #define L2CAP_SOCKET_CHECKED
37 #include <bluetooth.h>
38 #include <errno.h>
39 #include <limits.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <string.h>
44 #include <syslog.h>
45 #include <unistd.h>
46 #include "hcsecd.h"
47 
48 	int	yyparse  (void);
49 	int	yylex    (void);
50 
51 static	void	free_key (link_key_p key);
52 static	int	hexa2int4(char *a);
53 static	int	hexa2int8(char *a);
54 
55 extern	int			 yylineno;
56 static	LIST_HEAD(, link_key)	 link_keys;
57 	char			*config_file = "/etc/bluetooth/hcsecd.conf";
58 
59 static	link_key_p		 key = NULL;
60 %}
61 
62 %union {
63 	char	*string;
64 }
65 
66 %token <string> T_BDADDRSTRING T_HEXSTRING T_STRING
67 %token T_DEVICE T_BDADDR T_NAME T_KEY T_PIN T_NOKEY T_NOPIN T_JUNK
68 
69 %%
70 
71 config:		line
72 		| config line
73 		;
74 
75 line:		T_DEVICE
76 			{
77 			key = (link_key_p) malloc(sizeof(*key));
78 			if (key == NULL) {
79 				syslog(LOG_ERR, "Could not allocate new " \
80 						"config entry");
81 				exit(1);
82 			}
83 
84 			memset(key, 0, sizeof(*key));
85 			}
86 		'{' options '}'
87 			{
88 			if (get_key(&key->bdaddr, 1) != NULL) {
89 				syslog(LOG_ERR, "Ignoring duplicated entry " \
90 						"for bdaddr %s",
91 						bt_ntoa(&key->bdaddr, NULL));
92 				free_key(key);
93 			} else
94 				LIST_INSERT_HEAD(&link_keys, key, next);
95 
96 			key = NULL;
97 			}
98 		;
99 
100 options:	option ';'
101 		| options option ';'
102 		;
103 
104 option:		bdaddr
105 		| name
106 		| key
107 		| pin
108 		;
109 
110 bdaddr:		T_BDADDR T_BDADDRSTRING
111 			{
112 			if (!bt_aton($2, &key->bdaddr)) {
113 				syslog(LOG_ERR, "Cound not parse BD_ADDR " \
114 						"'%s'", $2);
115 				exit(1);
116 			}
117 			}
118 		;
119 
120 name:		T_NAME T_STRING
121 			{
122 			if (key->name != NULL)
123 				free(key->name);
124 
125 			key->name = strdup($2);
126 			if (key->name == NULL) {
127 				syslog(LOG_ERR, "Could not allocate new " \
128 						"device name");
129 				exit(1);
130 			}
131 			}
132 		;
133 
134 key:		T_KEY T_HEXSTRING
135 			{
136 			int	i, len;
137 
138 			if (key->key != NULL)
139 				free(key->key);
140 
141 			key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);
142 			if (key->key == NULL) {
143 				syslog(LOG_ERR, "Could not allocate new " \
144 						"link key");
145 				exit(1);
146 			}
147 
148 			memset(key->key, 0, NG_HCI_KEY_SIZE);
149 
150 			len = strlen($2) / 2;
151 			if (len > NG_HCI_KEY_SIZE)
152 				len = NG_HCI_KEY_SIZE;
153 
154 			for (i = 0; i < len; i ++)
155 				key->key[i] = hexa2int8((char *)($2) + 2*i);
156 			}
157 		| T_KEY T_NOKEY
158 			{
159 			if (key->key != NULL)
160 				free(key->key);
161 
162 			key->key = NULL;
163 			}
164 		;
165 
166 pin:		T_PIN T_STRING
167 			{
168 			if (key->pin != NULL)
169 				free(key->pin);
170 
171 			key->pin = strdup($2);
172 			if (key->pin == NULL) {
173 				syslog(LOG_ERR, "Could not allocate new " \
174 						"PIN code");
175 				exit(1);
176 			}
177 			}
178 		| T_PIN T_NOPIN
179 			{
180 			if (key->pin != NULL)
181 				free(key->pin);
182 
183 			key->pin = NULL;
184 			}
185 		;
186 
187 %%
188 
189 /* Display parser error message */
190 void
191 yyerror(char const *message)
192 {
193 	syslog(LOG_ERR, "%s in line %d", message, yylineno);
194 }
195 
196 /* Re-read config file */
197 void
198 read_config_file(void)
199 {
200 	extern FILE	*yyin;
201 
202 	if (config_file == NULL) {
203 		syslog(LOG_ERR, "Unknown config file name!");
204 		exit(1);
205 	}
206 
207 	if ((yyin = fopen(config_file, "r")) == NULL) {
208 		syslog(LOG_ERR, "Could not open config file '%s'. %s (%d)",
209 				config_file, strerror(errno), errno);
210 		exit(1);
211 	}
212 
213 	clean_config();
214 	if (yyparse() < 0) {
215 		syslog(LOG_ERR, "Could not parse config file '%s'",config_file);
216 		exit(1);
217 	}
218 
219 	fclose(yyin);
220 	yyin = NULL;
221 
222 #if __config_debug__
223 	dump_config();
224 #endif
225 }
226 
227 /* Clean config */
228 void
229 clean_config(void)
230 {
231 	link_key_p	key = NULL;
232 
233 	while ((key = LIST_FIRST(&link_keys)) != NULL) {
234 		LIST_REMOVE(key, next);
235 		free_key(key);
236 	}
237 }
238 
239 /* Find link key entry in the list. Return exact or default match */
240 link_key_p
241 get_key(bdaddr_p bdaddr, int exact_match)
242 {
243 	link_key_p	key = NULL, defkey = NULL;
244 
245 	LIST_FOREACH(key, &link_keys, next) {
246 		if (memcmp(bdaddr, &key->bdaddr, sizeof(key->bdaddr)) == 0)
247 			break;
248 
249 		if (!exact_match)
250 			if (memcmp(NG_HCI_BDADDR_ANY, &key->bdaddr,
251 					sizeof(key->bdaddr)) == 0)
252 				defkey = key;
253 	}
254 
255 	return ((key != NULL)? key : defkey);
256 }
257 
258 #if __config_debug__
259 /* Dump config */
260 void
261 dump_config(void)
262 {
263 	link_key_p	key = NULL;
264 	char		buffer[64];
265 
266 	LIST_FOREACH(key, &link_keys, next) {
267 		if (key->key != NULL)
268 			snprintf(buffer, sizeof(buffer),
269 "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
270 				key->key[0], key->key[1], key->key[2],
271 				key->key[3], key->key[4], key->key[5],
272 				key->key[6], key->key[7], key->key[8],
273 				key->key[9], key->key[10], key->key[11],
274 				key->key[12], key->key[13], key->key[14],
275 				key->key[15]);
276 
277 		syslog(LOG_DEBUG,
278 "device %s " \
279 "bdaddr %s " \
280 "pin %s " \
281 "key %s",
282 			(key->name != NULL)? key->name : "noname",
283 			bt_ntoa(&key->bdaddr, NULL),
284 			(key->pin != NULL)? key->pin : "nopin",
285 			(key->key != NULL)? buffer : "nokey");
286 	}
287 }
288 #endif
289 
290 /* Read keys file */
291 int
292 read_keys_file(void)
293 {
294 	FILE		*f = NULL;
295 	link_key_t	*key = NULL;
296 	char		 buf[HCSECD_BUFFER_SIZE], *p = NULL, *cp = NULL;
297 	bdaddr_t	 bdaddr;
298 	int		 i, len;
299 
300 	if ((f = fopen(HCSECD_KEYSFILE, "r")) == NULL) {
301 		if (errno == ENOENT)
302 			return (0);
303 
304 		syslog(LOG_ERR, "Could not open keys file %s. %s (%d)\n",
305 				HCSECD_KEYSFILE, strerror(errno), errno);
306 
307 		return (-1);
308 	}
309 
310 	while ((p = fgets(buf, sizeof(buf), f)) != NULL) {
311 		if (*p == '#')
312 			continue;
313 		if ((cp = strpbrk(p, " ")) == NULL)
314 			continue;
315 
316 		*cp++ = '\0';
317 
318 		if (!bt_aton(p, &bdaddr))
319 			continue;
320 
321 		if ((key = get_key(&bdaddr, 1)) == NULL)
322 			continue;
323 
324 		if (key->key == NULL) {
325 			key->key = (uint8_t *) malloc(NG_HCI_KEY_SIZE);
326 			if (key->key == NULL) {
327 				syslog(LOG_ERR, "Could not allocate link key");
328 				exit(1);
329 			}
330 		}
331 
332 		memset(key->key, 0, NG_HCI_KEY_SIZE);
333 
334 		len = strlen(cp) / 2;
335 		if (len > NG_HCI_KEY_SIZE)
336 			len = NG_HCI_KEY_SIZE;
337 
338 		for (i = 0; i < len; i ++)
339 			key->key[i] = hexa2int8(cp + 2*i);
340 
341 		syslog(LOG_DEBUG, "Restored link key for the entry, " \
342 				"remote bdaddr %s, name '%s'",
343 				bt_ntoa(&key->bdaddr, NULL),
344 				(key->name != NULL)? key->name : "No name");
345 	}
346 
347 	fclose(f);
348 
349 	return (0);
350 }
351 
352 /* Dump keys file */
353 int
354 dump_keys_file(void)
355 {
356 	link_key_p	key = NULL;
357 	char		tmp[PATH_MAX], buf[HCSECD_BUFFER_SIZE];
358 	int		f;
359 
360 	snprintf(tmp, sizeof(tmp), "%s.tmp", HCSECD_KEYSFILE);
361 	if ((f = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0600)) < 0) {
362 		syslog(LOG_ERR, "Could not create temp keys file %s. %s (%d)\n",
363 				tmp, strerror(errno), errno);
364 		return (-1);
365 	}
366 
367 	LIST_FOREACH(key, &link_keys, next) {
368 		if (key->key == NULL)
369 			continue;
370 
371 		snprintf(buf, sizeof(buf),
372 "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
373 			bt_ntoa(&key->bdaddr, NULL),
374 			key->key[0],  key->key[1],  key->key[2],  key->key[3],
375 			key->key[4],  key->key[5],  key->key[6],  key->key[7],
376 			key->key[8],  key->key[9],  key->key[10], key->key[11],
377 			key->key[12], key->key[13], key->key[14], key->key[15]);
378 
379 		if (write(f, buf, strlen(buf)) < 0) {
380 			syslog(LOG_ERR, "Could not write temp keys file. " \
381 					"%s (%d)\n", strerror(errno), errno);
382 			break;
383 		}
384 	}
385 
386 	close(f);
387 
388 	if (rename(tmp, HCSECD_KEYSFILE) < 0) {
389 		syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n",
390 				tmp, HCSECD_KEYSFILE, strerror(errno), errno);
391 		unlink(tmp);
392 		return (-1);
393 	}
394 
395 	return (0);
396 }
397 
398 /* Free key entry */
399 static void
400 free_key(link_key_p key)
401 {
402 	if (key->name != NULL)
403 		free(key->name);
404 	if (key->key != NULL)
405 		free(key->key);
406 	if (key->pin != NULL)
407 		free(key->pin);
408 
409 	memset(key, 0, sizeof(*key));
410 	free(key);
411 }
412 
413 /* Convert hex ASCII to int4 */
414 static int
415 hexa2int4(char *a)
416 {
417 	if ('0' <= *a && *a <= '9')
418 		return (*a - '0');
419 
420 	if ('A' <= *a && *a <= 'F')
421 		return (*a - 'A' + 0xa);
422 
423 	if ('a' <= *a && *a <= 'f')
424 		return (*a - 'a' + 0xa);
425 
426 	syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a);
427 	exit(1);
428 }
429 
430 /* Convert hex ASCII to int8 */
431 static int
432 hexa2int8(char *a)
433 {
434 	return ((hexa2int4(a) << 4) | hexa2int4(a + 1));
435 }
436 
437