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