xref: /dragonfly/usr.sbin/bthcid/parser.y (revision e6d22e9b)
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: src/usr.sbin/bluetooth/hcsecd/parser.y,v 1.4 2004/09/14 20:04:33 emax Exp $
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 <stdlib.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <unistd.h>
44 #include "bthcid.h"
45 
46 #if YYPATCH < 20180510
47 	int	yylex    (void);
48 #endif
49 
50 static	void	free_key (link_key_p key);
51 static	int	hexa2int4(char *a);
52 static	int	hexa2int8(char *a);
53 
54 extern	void			 yyerror(const char *);
55 extern	int			 yylineno;
56 extern	FILE			*yyin;
57 
58 static	LIST_HEAD(, link_key)	 link_keys;
59 
60 const	char			*config_file = "/etc/bluetooth/bthcid.conf";
61 static	link_key_p		 key = NULL;
62 %}
63 
64 %union {
65 	char	*string;
66 }
67 
68 %token <string> T_BDADDRSTRING T_HEXSTRING T_STRING
69 %token T_DEVICE T_BDADDR T_NAME T_KEY T_PIN T_NOKEY T_NOPIN T_JUNK
70 
71 %%
72 
73 config:		line
74 		| config line
75 		;
76 
77 line:		T_DEVICE
78 			{
79 			key = (link_key_p) malloc(sizeof(*key));
80 			if (key == NULL) {
81 				syslog(LOG_ERR, "Could not allocate new " \
82 						"config entry");
83 				exit(1);
84 			}
85 
86 			memset(key, 0, sizeof(*key));
87 			}
88 		'{' options '}'
89 			{
90 			if (get_key(&key->bdaddr, 1) != NULL) {
91 				syslog(LOG_ERR, "Ignoring duplicated entry " \
92 						"for bdaddr %s",
93 						bt_ntoa(&key->bdaddr, NULL));
94 				free_key(key);
95 			} else
96 				LIST_INSERT_HEAD(&link_keys, key, next);
97 
98 			key = NULL;
99 			}
100 		;
101 
102 options:	option ';'
103 		| options option ';'
104 		;
105 
106 option:		bdaddr
107 		| name
108 		| key
109 		| pin
110 		;
111 
112 bdaddr:		T_BDADDR T_BDADDRSTRING
113 			{
114 			if (!bt_aton($2, &key->bdaddr)) {
115 				syslog(LOG_ERR, "Could not parse BD_ADDR " \
116 						"'%s'", $2);
117 				exit(1);
118 			}
119 			}
120 		;
121 
122 name:		T_NAME T_STRING
123 			{
124 			if (key->name != NULL)
125 				free(key->name);
126 
127 			key->name = strdup($2);
128 			if (key->name == NULL) {
129 				syslog(LOG_ERR, "Could not allocate new " \
130 						"device name");
131 				exit(1);
132 			}
133 			}
134 		;
135 
136 key:		T_KEY T_HEXSTRING
137 			{
138 			int	i, len;
139 
140 			if (key->key != NULL)
141 				free(key->key);
142 
143 			key->key = (uint8_t *) malloc(HCI_KEY_SIZE);
144 			if (key->key == NULL) {
145 				syslog(LOG_ERR, "Could not allocate new " \
146 						"link key");
147 				exit(1);
148 			}
149 
150 			memset(key->key, 0, HCI_KEY_SIZE);
151 
152 			len = strlen($2) / 2;
153 			if (len > HCI_KEY_SIZE)
154 				len = HCI_KEY_SIZE;
155 
156 			for (i = 0; i < len; i ++)
157 				key->key[i] = hexa2int8((char *)($2) + 2*i);
158 			}
159 		| T_KEY T_NOKEY
160 			{
161 			if (key->key != NULL)
162 				free(key->key);
163 
164 			key->key = NULL;
165 			}
166 		;
167 
168 pin:		T_PIN T_STRING
169 			{
170 			if (key->pin != NULL)
171 				free(key->pin);
172 
173 			key->pin = strdup($2);
174 			if (key->pin == NULL) {
175 				syslog(LOG_ERR, "Could not allocate new " \
176 						"PIN code");
177 				exit(1);
178 			}
179 			}
180 		| T_PIN T_NOPIN
181 			{
182 			if (key->pin != NULL)
183 				free(key->pin);
184 
185 			key->pin = NULL;
186 			}
187 		;
188 
189 %%
190 
191 /* Display parser error message */
192 void
193 yyerror(char const *message)
194 {
195 	syslog(LOG_ERR, "%s in line %d", message, yylineno);
196 }
197 
198 /* Re-read config file */
199 void
200 read_config_file(void)
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 #ifdef __config_debug__
223 	dump_config();
224 #endif
225 }
226 
227 /* Clean config */
228 void
229 clean_config(void)
230 {
231 	link_key_p	lkey = NULL;
232 
233 	while ((lkey = LIST_FIRST(&link_keys)) != NULL) {
234 		LIST_REMOVE(lkey, next);
235 		free_key(lkey);
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	lkey = NULL, defkey = NULL;
244 
245 	LIST_FOREACH(lkey, &link_keys, next) {
246 		if (memcmp(bdaddr, &lkey->bdaddr, sizeof(lkey->bdaddr)) == 0)
247 			break;
248 
249 		if (!exact_match)
250 			if (memcmp(BDADDR_ANY, &lkey->bdaddr,
251 					sizeof(lkey->bdaddr)) == 0)
252 				defkey = lkey;
253 	}
254 
255 	return ((lkey != NULL)? lkey : defkey);
256 }
257 
258 #ifdef __config_debug__
259 /* Dump config */
260 void
261 dump_config(void)
262 {
263 	link_key_p	lkey = NULL;
264 	char		buffer[64];
265 
266 	LIST_FOREACH(lkey, &link_keys, next) {
267 		if (lkey->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 				lkey->key[0], lkey->key[1], lkey->key[2],
271 				lkey->key[3], lkey->key[4], lkey->key[5],
272 				lkey->key[6], lkey->key[7], lkey->key[8],
273 				lkey->key[9], lkey->key[10], lkey->key[11],
274 				lkey->key[12], lkey->key[13], lkey->key[14],
275 				lkey->key[15]);
276 
277 		syslog(LOG_DEBUG,
278 "device %s " \
279 "bdaddr %s " \
280 "pin %s " \
281 "key %s",
282 			(lkey->name != NULL)? lkey->name : "noname",
283 			bt_ntoa(&lkey->bdaddr, NULL),
284 			(lkey->pin != NULL)? lkey->pin : "nopin",
285 			(lkey->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	*lkey = NULL;
296 	char		 buf[BTHCID_BUFFER_SIZE], *p = NULL, *cp = NULL;
297 	bdaddr_t	 bdaddr;
298 	int		 i, len;
299 
300 	if ((f = fopen(BTHCID_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 				BTHCID_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 ((lkey = get_key(&bdaddr, 1)) == NULL)
322 			continue;
323 
324 		if (lkey->key == NULL) {
325 			lkey->key = (uint8_t *) malloc(HCI_KEY_SIZE);
326 			if (lkey->key == NULL) {
327 				syslog(LOG_ERR, "Could not allocate link key");
328 				exit(1);
329 			}
330 		}
331 
332 		memset(lkey->key, 0, HCI_KEY_SIZE);
333 
334 		len = strlen(cp) / 2;
335 		if (len > HCI_KEY_SIZE)
336 			len = HCI_KEY_SIZE;
337 
338 		for (i = 0; i < len; i ++)
339 			lkey->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(&lkey->bdaddr, NULL),
344 				(lkey->name != NULL)? lkey->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	lkey = NULL;
357 	char		tmp[PATH_MAX], buf[BTHCID_BUFFER_SIZE];
358 	int		f;
359 
360 	snprintf(tmp, sizeof(tmp), "%s.tmp", BTHCID_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(lkey, &link_keys, next) {
368 		if (lkey->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(&lkey->bdaddr, NULL),
374 			lkey->key[0],  lkey->key[1],  lkey->key[2],  lkey->key[3],
375 			lkey->key[4],  lkey->key[5],  lkey->key[6],  lkey->key[7],
376 			lkey->key[8],  lkey->key[9],  lkey->key[10], lkey->key[11],
377 			lkey->key[12], lkey->key[13], lkey->key[14], lkey->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, BTHCID_KEYSFILE) < 0) {
389 		syslog(LOG_ERR, "Could not rename(%s, %s). %s (%d)\n",
390 				tmp, BTHCID_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 lkey)
401 {
402 	if (lkey->name != NULL)
403 		free(lkey->name);
404 	if (lkey->key != NULL)
405 		free(lkey->key);
406 	if (lkey->pin != NULL)
407 		free(lkey->pin);
408 
409 	memset(lkey, 0, sizeof(*lkey));
410 	free(lkey);
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