]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/bluetooth/hcsecd/parser.y
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.sbin / bluetooth / hcsecd / parser.y
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