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