1 /*
2 * Copyright (C) 2002-2008 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7 * Use is subject to license terms.
8 * Copyright 2019 Joyent, Inc.
9 */
10
11 #include <ctype.h>
12 #include "ipf.h"
13 #ifdef IPFILTER_SCAN
14 # include "netinet/ip_scan.h"
15 #endif
16 #include <sys/ioctl.h>
17 #include <syslog.h>
18 #include <uuid/uuid.h>
19 #ifdef TEST_LEXER
20 # define NO_YACC
21 union {
22 int num;
23 char *str;
24 struct in_addr ipa;
25 i6addr_t ip6;
26 uuid_t uuid;
27 } yylval;
28 #endif
29 #include "lexer.h"
30 #include "y.tab.h"
31
32 FILE *yyin;
33
34 #define ishex(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \
35 ((c) >= 'A' && (c) <= 'F'))
36 #define TOOLONG -3
37
38 extern int string_start;
39 extern int string_end;
40 extern char *string_val;
41 extern int pos;
42 extern int yydebug;
43
44 char *yystr = NULL;
45 int yytext[YYBUFSIZ+1];
46 char yychars[YYBUFSIZ+1];
47 int yylineNum = 1;
48 int yypos = 0;
49 int yylast = -1;
50 int yyexpectaddr = 0;
51 int yybreakondot = 0;
52 int yyvarnext = 0;
53 int yytokentype = 0;
54 wordtab_t *yywordtab = NULL;
55 int yysavedepth = 0;
56 wordtab_t *yysavewords[30];
57
58
59 static wordtab_t *yyfindkey __P((char *));
60 static int yygetc __P((int));
61 static void yyunputc __P((int));
62 static int yyswallow __P((int));
63 static char *yytexttostr __P((int, int));
64 static void yystrtotext __P((char *));
65 static char *yytexttochar __P((void));
66
67 static int yygetc(docont)
68 int docont;
69 {
70 int c;
71
72 if (yypos < yylast) {
73 c = yytext[yypos++];
74 if (c == '\n')
75 yylineNum++;
76 return c;
77 }
78
79 if (yypos == YYBUFSIZ)
80 return TOOLONG;
81
82 if (pos >= string_start && pos <= string_end) {
83 c = string_val[pos - string_start];
84 yypos++;
85 } else {
86 c = fgetc(yyin);
87 if (docont && (c == '\\')) {
88 c = fgetc(yyin);
89 if (c == '\n') {
90 yylineNum++;
91 c = fgetc(yyin);
92 }
93 }
94 }
95 if (c == '\n')
96 yylineNum++;
97 yytext[yypos++] = c;
98 yylast = yypos;
99 yytext[yypos] = '\0';
100
101 return c;
102 }
103
104
105 static void yyunputc(c)
106 int c;
107 {
108 if (c == '\n')
109 yylineNum--;
110 yytext[--yypos] = c;
111 }
112
113
114 static int yyswallow(last)
115 int last;
116 {
117 int c;
118
119 while (((c = yygetc(0)) > '\0') && (c != last))
120 ;
121
122 if (c != EOF)
123 yyunputc(c);
124 if (c == last)
125 return 0;
126 return -1;
127 }
128
129
130 static char *yytexttochar()
131 {
132 int i;
133
134 for (i = 0; i < yypos; i++)
135 yychars[i] = (char)(yytext[i] & 0xff);
136 yychars[i] = '\0';
137 return yychars;
138 }
139
140
141 static void yystrtotext(str)
142 char *str;
143 {
144 int len;
145 char *s;
146
147 len = strlen(str);
148 if (len > YYBUFSIZ)
149 len = YYBUFSIZ;
150
151 for (s = str; *s != '\0' && len > 0; s++, len--)
152 yytext[yylast++] = *s;
153 yytext[yylast] = '\0';
154 }
155
156
157 static char *yytexttostr(offset, max)
158 int offset, max;
159 {
160 char *str;
161 int i;
162
163 if ((yytext[offset] == '\'' || yytext[offset] == '"') &&
164 (yytext[offset] == yytext[offset + max - 1])) {
165 offset++;
166 max--;
167 }
168
169 if (max > yylast)
170 max = yylast;
171 str = malloc(max + 1);
172 if (str != NULL) {
173 for (i = offset; i < max; i++)
174 str[i - offset] = (char)(yytext[i] & 0xff);
175 str[i - offset] = '\0';
176 }
177 return str;
178 }
179
180
181 int yylex()
182 {
183 int c, n, isbuilding, rval, lnext, nokey = 0;
184 char *name;
185
186 isbuilding = 0;
187 lnext = 0;
188 rval = 0;
189
190 if (yystr != NULL) {
191 free(yystr);
192 yystr = NULL;
193 }
194
195 nextchar:
196 c = yygetc(0);
197 if (yydebug > 1)
198 printf("yygetc = (%x) %c [%*.*s]\n", c, c, yypos, yypos,
199 yytexttochar());
200
201 switch (c)
202 {
203 case '\n' :
204 lnext = 0;
205 nokey = 0;
206 /* FALLTHROUGH */
207 case '\t' :
208 case '\r' :
209 case ' ' :
210 if (isbuilding == 1) {
211 yyunputc(c);
212 goto done;
213 }
214 if (yylast > yypos) {
215 bcopy(yytext + yypos, yytext,
216 sizeof(yytext[0]) * (yylast - yypos + 1));
217 }
218 yylast -= yypos;
219 yypos = 0;
220 lnext = 0;
221 nokey = 0;
222 goto nextchar;
223
224 case '\\' :
225 if (lnext == 0) {
226 lnext = 1;
227 if (yylast == yypos) {
228 yylast--;
229 yypos--;
230 } else
231 yypos--;
232 if (yypos == 0)
233 nokey = 1;
234 goto nextchar;
235 }
236 break;
237 }
238
239 if (lnext == 1) {
240 lnext = 0;
241 if ((isbuilding == 0) && !ISALNUM(c)) {
242 return c;
243 }
244 goto nextchar;
245 }
246
247 switch (c)
248 {
249 case '#' :
250 if (isbuilding == 1) {
251 yyunputc(c);
252 goto done;
253 }
254 yyswallow('\n');
255 rval = YY_COMMENT;
256 goto done;
257
258 case '$' :
259 if (isbuilding == 1) {
260 yyunputc(c);
261 goto done;
262 }
263 n = yygetc(0);
264 if (n == '{') {
265 if (yyswallow('}') == -1) {
266 rval = -2;
267 goto done;
268 }
269 (void) yygetc(0);
270 } else {
271 if (!ISALPHA(n)) {
272 yyunputc(n);
273 break;
274 }
275 do {
276 n = yygetc(1);
277 } while (ISALPHA(n) || ISDIGIT(n) || n == '_');
278 yyunputc(n);
279 }
280
281 name = yytexttostr(1, yypos); /* skip $ */
282
283 if (name != NULL) {
284 string_val = get_variable(name, NULL, yylineNum);
285 free(name);
286 if (string_val != NULL) {
287 name = yytexttostr(yypos, yylast);
288 if (name != NULL) {
289 yypos = 0;
290 yylast = 0;
291 yystrtotext(string_val);
292 yystrtotext(name);
293 free(string_val);
294 free(name);
295 goto nextchar;
296 }
297 free(string_val);
298 }
299 }
300 break;
301
302 case '\'':
303 case '"' :
304 if (isbuilding == 1) {
305 goto done;
306 }
307 do {
308 n = yygetc(1);
309 if (n == EOF || n == TOOLONG) {
310 rval = -2;
311 goto done;
312 }
313 if (n == '\n') {
314 yyunputc(' ');
315 yypos++;
316 }
317 } while (n != c);
318 rval = YY_STR;
319 goto done;
320 /* NOTREACHED */
321
322 case EOF :
323 yylineNum = 1;
324 yypos = 0;
325 yylast = -1;
326 yyexpectaddr = 0;
327 yybreakondot = 0;
328 yyvarnext = 0;
329 yytokentype = 0;
330 return 0;
331 }
332
333 if (strchr("=,/;{}()@", c) != NULL) {
334 if (isbuilding == 1) {
335 yyunputc(c);
336 goto done;
337 }
338 rval = c;
339 goto done;
340 } else if (c == '.') {
341 if (isbuilding == 0) {
342 rval = c;
343 goto done;
344 }
345 if (yybreakondot != 0) {
346 yyunputc(c);
347 goto done;
348 }
349 }
350
351 switch (c)
352 {
353 case '-' :
354 if (yyexpectaddr)
355 break;
356 if (isbuilding == 1)
357 break;
358 n = yygetc(0);
359 if (n == '>') {
360 isbuilding = 1;
361 goto done;
362 }
363 yyunputc(n);
364 rval = '-';
365 goto done;
366
367 case '!' :
368 if (isbuilding == 1) {
369 yyunputc(c);
370 goto done;
371 }
372 n = yygetc(0);
373 if (n == '=') {
374 rval = YY_CMP_NE;
375 goto done;
376 }
377 yyunputc(n);
378 rval = '!';
379 goto done;
380
381 case '<' :
382 if (yyexpectaddr)
383 break;
384 if (isbuilding == 1) {
385 yyunputc(c);
386 goto done;
387 }
388 n = yygetc(0);
389 if (n == '=') {
390 rval = YY_CMP_LE;
391 goto done;
392 }
393 if (n == '>') {
394 rval = YY_RANGE_OUT;
395 goto done;
396 }
397 yyunputc(n);
398 rval = YY_CMP_LT;
399 goto done;
400
401 case '>' :
402 if (yyexpectaddr)
403 break;
404 if (isbuilding == 1) {
405 yyunputc(c);
406 goto done;
407 }
408 n = yygetc(0);
409 if (n == '=') {
410 rval = YY_CMP_GE;
411 goto done;
412 }
413 if (n == '<') {
414 rval = YY_RANGE_IN;
415 goto done;
416 }
417 yyunputc(n);
418 rval = YY_CMP_GT;
419 goto done;
420 }
421
422 /*
423 * Now for the reason this is here...IPv6 address parsing.
424 * The longest string we can expect is of this form:
425 * 0000:0000:0000:0000:0000:0000:000.000.000.000
426 * not:
427 * 0000:0000:0000:0000:0000:0000:0000:0000
428 */
429 #ifdef USE_INET6
430 if (isbuilding == 0 && (ishex(c) || c == ':')) {
431 char ipv6buf[45 + 1], *s, oc;
432 int start;
433
434 start = yypos;
435 s = ipv6buf;
436 oc = c;
437
438 /*
439 * Perhaps we should implement stricter controls on what we
440 * swallow up here, but surely it would just be duplicating
441 * the code in inet_pton() anyway.
442 */
443 do {
444 *s++ = c;
445 c = yygetc(1);
446 } while ((ishex(c) || c == ':' || c == '.') &&
447 (s - ipv6buf < 46));
448 yyunputc(c);
449 *s = '\0';
450
451 if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) {
452 rval = YY_IPV6;
453 yyexpectaddr = 0;
454 goto done;
455 }
456 yypos = start;
457 c = oc;
458 }
459 #endif
460
461 /*
462 * UUID: 2426e38c-9f63-c0b8-cfd5-9aaeaf992d42 or uppercase
463 */
464 if (isbuilding == 0 && (ishex(c) || c == '-')) {
465 char uuidbuf[UUID_PRINTABLE_STRING_LENGTH], *s, oc;
466 int start;
467
468 start = yypos;
469 s = uuidbuf;
470 oc = c;
471
472 /*
473 * Don't worry about exact position of hexdigits and hyphens
474 * because uuid_parse() will provide the sanity check.
475 */
476 do {
477 *s++ = c;
478 c = yygetc(1);
479 } while ((ishex(c) || c == '-') &&
480 (s - uuidbuf < sizeof (uuidbuf)));
481 yyunputc(c);
482 *s = '\0';
483
484 if (uuid_parse(uuidbuf, yylval.uuid) == 0) {
485 rval = YY_UUID;
486 yyexpectaddr = 0;
487 goto done;
488 }
489 yypos = start;
490 c = oc;
491 }
492
493
494 if (c == ':') {
495 if (isbuilding == 1) {
496 yyunputc(c);
497 goto done;
498 }
499 rval = ':';
500 goto done;
501 }
502
503 if (isbuilding == 0 && c == '0') {
504 n = yygetc(0);
505 if (n == 'x') {
506 do {
507 n = yygetc(1);
508 } while (ishex(n));
509 yyunputc(n);
510 rval = YY_HEX;
511 goto done;
512 }
513 yyunputc(n);
514 }
515
516 /*
517 * No negative numbers with leading - sign..
518 */
519 if (isbuilding == 0 && ISDIGIT(c)) {
520 do {
521 n = yygetc(1);
522 } while (ISDIGIT(n));
523 yyunputc(n);
524 rval = YY_NUMBER;
525 goto done;
526 }
527
528 isbuilding = 1;
529 goto nextchar;
530
531 done:
532 yystr = yytexttostr(0, yypos);
533
534 if (yydebug)
535 printf("isbuilding %d yyvarnext %d nokey %d\n",
536 isbuilding, yyvarnext, nokey);
537 if (isbuilding == 1) {
538 wordtab_t *w;
539
540 w = NULL;
541 isbuilding = 0;
542
543 if ((yyvarnext == 0) && (nokey == 0)) {
544 w = yyfindkey(yystr);
545 if (w == NULL && yywordtab != NULL) {
546 yyresetdict();
547 w = yyfindkey(yystr);
548 }
549 } else
550 yyvarnext = 0;
551 if (w != NULL)
552 rval = w->w_value;
553 else
554 rval = YY_STR;
555 }
556
557 if (rval == YY_STR && yysavedepth > 0)
558 yyresetdict();
559
560 yytokentype = rval;
561
562 if (yydebug)
563 printf("lexed(%s) [%d,%d,%d] => %d @%d\n", yystr, string_start,
564 string_end, pos, rval, yysavedepth);
565
566 switch (rval)
567 {
568 case YY_NUMBER :
569 sscanf(yystr, "%u", &yylval.num);
570 break;
571
572 case YY_HEX :
573 sscanf(yystr, "0x%x", (u_int *)&yylval.num);
574 break;
575
576 case YY_STR :
577 yylval.str = strdup(yystr);
578 break;
579
580 default :
581 break;
582 }
583
584 if (yylast > 0) {
585 bcopy(yytext + yypos, yytext,
586 sizeof(yytext[0]) * (yylast - yypos + 1));
587 yylast -= yypos;
588 yypos = 0;
589 }
590
591 return rval;
592 }
593
594
595 static wordtab_t *yyfindkey(key)
596 char *key;
597 {
598 wordtab_t *w;
599
600 if (yywordtab == NULL)
601 return NULL;
602
603 for (w = yywordtab; w->w_word != 0; w++)
604 if (strcasecmp(key, w->w_word) == 0)
605 return w;
606 return NULL;
607 }
608
609
610 char *yykeytostr(num)
611 int num;
612 {
613 wordtab_t *w;
614
615 if (yywordtab == NULL)
616 return "<unknown>";
617
618 for (w = yywordtab; w->w_word; w++)
619 if (w->w_value == num)
620 return w->w_word;
621 return "<unknown>";
622 }
623
624
625 wordtab_t *yysettab(words)
626 wordtab_t *words;
627 {
628 wordtab_t *save;
629
630 save = yywordtab;
631 yywordtab = words;
632 return save;
633 }
634
635
636 void yyerror(msg)
637 char *msg;
638 {
639 char *txt, letter[2];
640 int freetxt = 0;
641
642 if (yytokentype < 256) {
643 letter[0] = yytokentype;
644 letter[1] = '\0';
645 txt = letter;
646 } else if (yytokentype == YY_STR || yytokentype == YY_HEX ||
647 yytokentype == YY_NUMBER) {
648 if (yystr == NULL) {
649 txt = yytexttostr(yypos, YYBUFSIZ);
650 if (txt == NULL) {
651 fprintf(stderr, "sorry, out of memory,"
652 " bailing out\n");
653 exit(1);
654 }
655 freetxt = 1;
656 } else
657 txt = yystr;
658 } else {
659 txt = yykeytostr(yytokentype);
660 if (txt == NULL) {
661 fprintf(stderr, "sorry, out of memory,"
662 " bailing out\n");
663 exit(1);
664 }
665 }
666 fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum);
667 if (freetxt == 1)
668 free(txt);
669 exit(1);
670 }
671
672
673 void yysetdict(newdict)
674 wordtab_t *newdict;
675 {
676 if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) {
677 fprintf(stderr, "%d: at maximum dictionary depth\n",
678 yylineNum);
679 return;
680 }
681
682 yysavewords[yysavedepth++] = yysettab(newdict);
683 if (yydebug)
684 printf("yysavedepth++ => %d\n", yysavedepth);
685 }
686
687 void yyresetdict()
688 {
689 if (yydebug)
690 printf("yyresetdict(%d)\n", yysavedepth);
691 if (yysavedepth > 0) {
692 yysettab(yysavewords[--yysavedepth]);
693 if (yydebug)
694 printf("yysavedepth-- => %d\n", yysavedepth);
695 }
696 }
697
698
699
700 #ifdef TEST_LEXER
701 int main(argc, argv)
702 int argc;
703 char *argv[];
704 {
705 int n;
706
707 yyin = stdin;
708
709 while ((n = yylex()) != 0)
710 printf("%d.n = %d [%s] %d %d\n",
711 yylineNum, n, yystr, yypos, yylast);
712 }
713 #endif