xref: /freebsd/contrib/ntp/ntpd/ntp_scanner.c (revision d356ca0c3ffa363d5bfbc237b44f53b3f88fd415)
1 
2 /* ntp_scanner.c
3  *
4  * The source code for a simple lexical analyzer.
5  *
6  * Written By:	Sachin Kamboj
7  *		University of Delaware
8  *		Newark, DE 19711
9  * Copyright (c) 2006
10  */
11 
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15 
16 #include <stdio.h>
17 #include <ctype.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <string.h>
21 
22 #include "ntpd.h"
23 #include "ntp_config.h"
24 #include "ntpsim.h"
25 #include "ntp_scanner.h"
26 #include "ntp_parser.h"
27 
28 /* ntp_keyword.h declares finite state machine and token text */
29 #include "ntp_keyword.h"
30 
31 
32 
33 /* SCANNER GLOBAL VARIABLES
34  * ------------------------
35  */
36 
37 #define MAX_LEXEME (1024 + 1)	/* The maximum size of a lexeme */
38 char yytext[MAX_LEXEME];	/* Buffer for storing the input text/lexeme */
39 u_int32 conf_file_sum;		/* Simple sum of characters read */
40 
41 static struct FILE_INFO * lex_stack = NULL;
42 
43 
44 
45 /* CONSTANTS
46  * ---------
47  */
48 
49 
50 /* SCANNER GLOBAL VARIABLES
51  * ------------------------
52  */
53 const char special_chars[] = "{}(),;|=";
54 
55 
56 /* FUNCTIONS
57  * ---------
58  */
59 
60 static int is_keyword(char *lexeme, follby *pfollowedby);
61 
62 
63 /*
64  * keyword() - Return the keyword associated with token T_ identifier.
65  *	       See also token_name() for the string-ized T_ identifier.
66  *	       Example: keyword(T_Server) returns "server"
67  *			token_name(T_Server) returns "T_Server"
68  */
69 const char *
70 keyword(
71 	int token
72 	)
73 {
74 	size_t i;
75 	const char *text;
76 
77 	i = token - LOWEST_KEYWORD_ID;
78 
79 	if (i < COUNTOF(keyword_text))
80 		text = keyword_text[i];
81 	else
82 		text = NULL;
83 
84 	return (text != NULL)
85 		   ? text
86 		   : "(keyword not found)";
87 }
88 
89 
90 /* FILE & STRING BUFFER INTERFACE
91  * ------------------------------
92  *
93  * This set out as a couple of wrapper functions around the standard C
94  * fgetc and ungetc functions in order to include positional
95  * bookkeeping. Alas, this is no longer a good solution with nested
96  * input files and the possibility to send configuration commands via
97  * 'ntpdc' and 'ntpq'.
98  *
99  * Now there are a few functions to maintain a stack of nested input
100  * sources (though nesting is only allowd for disk files) and from the
101  * scanner / parser point of view there's no difference between both
102  * types of sources.
103  *
104  * The 'fgetc()' / 'ungetc()' replacements now operate on a FILE_INFO
105  * structure. Instead of trying different 'ungetc()' strategies for file
106  * and buffer based parsing, we keep the backup char in our own
107  * FILE_INFO structure. This is sufficient, as the parser does *not*
108  * jump around via 'seek' or the like, and there's no need to
109  * check/clear the backup store in other places than 'lex_getch()'.
110  */
111 
112 /*
113  * Allocate an info structure and attach it to a file.
114  *
115  * Note: When 'mode' is NULL, then the INFO block will be set up to
116  * contain a NULL file pointer, as suited for remote config command
117  * parsing. Otherwise having a NULL file pointer is considered an error,
118  * and a NULL info block pointer is returned to indicate failure!
119  *
120  * Note: We use a variable-sized structure to hold a copy of the file
121  * name (or, more proper, the input source description). This is more
122  * secure than keeping a reference to some other storage that might go
123  * out of scope.
124  */
125 static struct FILE_INFO *
126 lex_open(
127 	const char *path,
128 	const char *mode
129 	)
130 {
131 	struct FILE_INFO *stream;
132 	size_t            nnambuf;
133 
134 	nnambuf = strlen(path);
135 	stream = emalloc_zero(sizeof(*stream) + nnambuf);
136 	stream->curpos.nline = 1;
137 	stream->backch = EOF;
138 	/* copy name with memcpy -- trailing NUL already there! */
139 	memcpy(stream->fname, path, nnambuf);
140 
141 	if (NULL != mode) {
142 		stream->fpi = fopen(path, mode);
143 		if (NULL == stream->fpi) {
144 			free(stream);
145 			stream = NULL;
146 		}
147 	}
148 	return stream;
149 }
150 
151 /* get next character from buffer or file. This will return any putback
152  * character first; it will also make sure the last line is at least
153  * virtually terminated with a '\n'.
154  */
155 static int
156 lex_getch(
157 	struct FILE_INFO *stream
158 	)
159 {
160 	int ch;
161 
162 	if (NULL == stream || stream->force_eof)
163 		return EOF;
164 
165 	if (EOF != stream->backch) {
166 		ch = stream->backch;
167 		stream->backch = EOF;
168 		if (stream->fpi)
169 			conf_file_sum += ch;
170 	} else if (stream->fpi) {
171 		/* fetch next 7-bit ASCII char (or EOF) from file */
172 		while ((ch = fgetc(stream->fpi)) != EOF && ch > SCHAR_MAX)
173 			stream->curpos.ncol++;
174 		if (EOF != ch) {
175 			conf_file_sum += ch;
176 			stream->curpos.ncol++;
177 		}
178 	} else {
179 		/* fetch next 7-bit ASCII char from buffer */
180 		const char * scan;
181 		scan = &remote_config.buffer[remote_config.pos];
182 		while ((ch = (u_char)*scan) > SCHAR_MAX) {
183 			scan++;
184 			stream->curpos.ncol++;
185 		}
186 		if ('\0' != ch) {
187 			scan++;
188 			stream->curpos.ncol++;
189 		} else {
190 			ch = EOF;
191 		}
192 		remote_config.pos = (int)(scan - remote_config.buffer);
193 	}
194 
195 	/* If the last line ends without '\n', generate one. This
196 	 * happens most likely on Windows, where editors often have a
197 	 * sloppy concept of a line.
198 	 */
199 	if (EOF == ch && stream->curpos.ncol != 0)
200 		ch = '\n';
201 
202 	/* update scan position tallies */
203 	if (ch == '\n') {
204 		stream->bakpos = stream->curpos;
205 		stream->curpos.nline++;
206 		stream->curpos.ncol = 0;
207 	}
208 
209 	return ch;
210 }
211 
212 /* Note: lex_ungetch will fail to track more than one line of push
213  * back. But since it guarantees only one char of back storage anyway,
214  * this should not be a problem.
215  */
216 static int
217 lex_ungetch(
218 	int ch,
219 	struct FILE_INFO *stream
220 	)
221 {
222 	/* check preconditions */
223 	if (NULL == stream || stream->force_eof)
224 		return EOF;
225 	if (EOF != stream->backch || EOF == ch)
226 		return EOF;
227 
228 	/* keep for later reference and update checksum */
229 	stream->backch = (u_char)ch;
230 	if (stream->fpi)
231 		conf_file_sum -= stream->backch;
232 
233 	/* update position */
234 	if (stream->backch == '\n') {
235 	    stream->curpos = stream->bakpos;
236 	    stream->bakpos.ncol = -1;
237 	}
238 	stream->curpos.ncol--;
239 	return stream->backch;
240 }
241 
242 /* dispose of an input structure. If the file pointer is not NULL, close
243  * the file. This function does not check the result of 'fclose()'.
244  */
245 static void
246 lex_close(
247 	struct FILE_INFO *stream
248 	)
249 {
250 	if (NULL != stream) {
251 		if (NULL != stream->fpi)
252 			fclose(stream->fpi);
253 		free(stream);
254 	}
255 }
256 
257 /* INPUT STACK
258  * -----------
259  *
260  * Nested input sources are a bit tricky at first glance. We deal with
261  * this problem using a stack of input sources, that is, a forward
262  * linked list of FILE_INFO structs.
263  *
264  * This stack is never empty during parsing; while an encounter with EOF
265  * can and will remove nested input sources, removing the last element
266  * in the stack will not work during parsing, and the EOF condition of
267  * the outermost input file remains until the parser folds up.
268  */
269 
270 static struct FILE_INFO *
271 _drop_stack_do(
272 	struct FILE_INFO * head
273 	)
274 {
275 	struct FILE_INFO * tail;
276 	while (NULL != head) {
277 		tail = head->st_next;
278 		lex_close(head);
279 		head = tail;
280 	}
281 	return head;
282 }
283 
284 
285 
286 /* Create a singleton input source on an empty lexer stack. This will
287  * fail if there is already an input source, or if the underlying disk
288  * file cannot be opened.
289  *
290  * Returns TRUE if a new input object was successfully created.
291  */
292 int/*BOOL*/
293 lex_init_stack(
294 	const char * path,
295 	const char * mode
296 	)
297 {
298 	if (NULL != lex_stack || NULL == path)
299 		return FALSE;
300 
301 	lex_stack = lex_open(path, mode);
302 	return (NULL != lex_stack);
303 }
304 
305 /* This removes *all* input sources from the stack, leaving the head
306  * pointer as NULL. Any attempt to parse in that state is likely to bomb
307  * with segmentation faults or the like.
308  *
309  * In other words: Use this to clean up after parsing, and do not parse
310  * anything until the next 'lex_init_stack()' succeeded.
311  */
312 void
313 lex_drop_stack()
314 {
315 	lex_stack = _drop_stack_do(lex_stack);
316 }
317 
318 /* Flush the lexer input stack: This will nip all input objects on the
319  * stack (but keeps the current top-of-stack) and marks the top-of-stack
320  * as inactive. Any further calls to lex_getch yield only EOF, and it's
321  * no longer possible to push something back.
322  *
323  * Returns TRUE if there is a head element (top-of-stack) that was not
324  * in the force-eof mode before this call.
325  */
326 int/*BOOL*/
327 lex_flush_stack()
328 {
329 	int retv = FALSE;
330 
331 	if (NULL != lex_stack) {
332 		retv = !lex_stack->force_eof;
333 		lex_stack->force_eof = TRUE;
334 		lex_stack->st_next = _drop_stack_do(
335 					lex_stack->st_next);
336 	}
337 	return retv;
338 }
339 
340 /* Push another file on the parsing stack. If the mode is NULL, create a
341  * FILE_INFO suitable for in-memory parsing; otherwise, create a
342  * FILE_INFO that is bound to a local/disc file. Note that 'path' must
343  * not be NULL, or the function will fail.
344  *
345  * Returns TRUE if a new info record was pushed onto the stack.
346  */
347 int/*BOOL*/ lex_push_file(
348 	const char * path,
349 	const char * mode
350 	)
351 {
352 	struct FILE_INFO * next = NULL;
353 
354 	if (NULL != path) {
355 		next = lex_open(path, mode);
356 		if (NULL != next) {
357 			next->st_next = lex_stack;
358 			lex_stack = next;
359 		}
360 	}
361 	return (NULL != next);
362 }
363 
364 /* Pop, close & free the top of the include stack, unless the stack
365  * contains only a singleton input object. In that case the function
366  * fails, because the parser does not expect the input stack to be
367  * empty.
368  *
369  * Returns TRUE if an object was successfuly popped from the stack.
370  */
371 int/*BOOL*/
372 lex_pop_file(void)
373 {
374 	struct FILE_INFO * head = lex_stack;
375 	struct FILE_INFO * tail = NULL;
376 
377 	if (NULL != head) {
378 		tail = head->st_next;
379 		if (NULL != tail) {
380 			lex_stack = tail;
381 			lex_close(head);
382 		}
383 	}
384 	return (NULL != tail);
385 }
386 
387 /* Get include nesting level. This currently loops over the stack and
388  * counts elements; but since this is of concern only with an include
389  * statement and the nesting depth has a small limit, there's no
390  * bottleneck expected here.
391  *
392  * Returns the nesting level of includes, that is, the current depth of
393  * the lexer input stack.
394  *
395  * Note:
396  */
397 size_t
398 lex_level(void)
399 {
400 	size_t            cnt = 0;
401 	struct FILE_INFO *ipf = lex_stack;
402 
403 	while (NULL != ipf) {
404 		cnt++;
405 		ipf = ipf->st_next;
406 	}
407 	return cnt;
408 }
409 
410 /* check if the current input is from a file */
411 int/*BOOL*/
412 lex_from_file(void)
413 {
414 	return (NULL != lex_stack) && (NULL != lex_stack->fpi);
415 }
416 
417 struct FILE_INFO *
418 lex_current()
419 {
420 	/* this became so simple, it could be a macro. But then,
421 	 * lex_stack needed to be global...
422 	 */
423 	return lex_stack;
424 }
425 
426 
427 /* STATE MACHINES
428  * --------------
429  */
430 
431 /* Keywords */
432 static int
433 is_keyword(
434 	char *lexeme,
435 	follby *pfollowedby
436 	)
437 {
438 	follby fb;
439 	int curr_s;		/* current state index */
440 	int token;
441 	int i;
442 
443 	curr_s = SCANNER_INIT_S;
444 	token = 0;
445 
446 	for (i = 0; lexeme[i]; i++) {
447 		while (curr_s && (lexeme[i] != SS_CH(sst[curr_s])))
448 			curr_s = SS_OTHER_N(sst[curr_s]);
449 
450 		if (curr_s && (lexeme[i] == SS_CH(sst[curr_s]))) {
451 			if ('\0' == lexeme[i + 1]
452 			    && FOLLBY_NON_ACCEPTING
453 			       != SS_FB(sst[curr_s])) {
454 				fb = SS_FB(sst[curr_s]);
455 				*pfollowedby = fb;
456 				token = curr_s;
457 				break;
458 			}
459 			curr_s = SS_MATCH_N(sst[curr_s]);
460 		} else
461 			break;
462 	}
463 
464 	return token;
465 }
466 
467 
468 /* Integer */
469 static int
470 is_integer(
471 	char *lexeme
472 	)
473 {
474 	int	i;
475 	int	is_neg;
476 	u_int	u_val;
477 
478 	i = 0;
479 
480 	/* Allow a leading minus sign */
481 	if (lexeme[i] == '-') {
482 		i++;
483 		is_neg = TRUE;
484 	} else {
485 		is_neg = FALSE;
486 	}
487 
488 	/* Check that all the remaining characters are digits */
489 	for (; lexeme[i] != '\0'; i++) {
490 		if (!isdigit((u_char)lexeme[i]))
491 			return FALSE;
492 	}
493 
494 	if (is_neg)
495 		return TRUE;
496 
497 	/* Reject numbers that fit in unsigned but not in signed int */
498 	if (1 == sscanf(lexeme, "%u", &u_val))
499 		return (u_val <= INT_MAX);
500 	else
501 		return FALSE;
502 }
503 
504 
505 /* U_int -- assumes is_integer() has returned FALSE */
506 static int
507 is_u_int(
508 	char *lexeme
509 	)
510 {
511 	int	i;
512 	int	is_hex;
513 
514 	i = 0;
515 	if ('0' == lexeme[i] && 'x' == tolower((u_char)lexeme[i + 1])) {
516 		i += 2;
517 		is_hex = TRUE;
518 	} else {
519 		is_hex = FALSE;
520 	}
521 
522 	/* Check that all the remaining characters are digits */
523 	for (; lexeme[i] != '\0'; i++) {
524 		if (is_hex && !isxdigit((u_char)lexeme[i]))
525 			return FALSE;
526 		if (!is_hex && !isdigit((u_char)lexeme[i]))
527 			return FALSE;
528 	}
529 
530 	return TRUE;
531 }
532 
533 
534 /* Double */
535 static int
536 is_double(
537 	char *lexeme
538 	)
539 {
540 	u_int num_digits = 0;  /* Number of digits read */
541 	u_int i;
542 
543 	i = 0;
544 
545 	/* Check for an optional '+' or '-' */
546 	if ('+' == lexeme[i] || '-' == lexeme[i])
547 		i++;
548 
549 	/* Read the integer part */
550 	for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
551 		num_digits++;
552 
553 	/* Check for the optional decimal point */
554 	if ('.' == lexeme[i]) {
555 		i++;
556 		/* Check for any digits after the decimal point */
557 		for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
558 			num_digits++;
559 	}
560 
561 	/*
562 	 * The number of digits in both the decimal part and the
563 	 * fraction part must not be zero at this point
564 	 */
565 	if (!num_digits)
566 		return 0;
567 
568 	/* Check if we are done */
569 	if (!lexeme[i])
570 		return 1;
571 
572 	/* There is still more input, read the exponent */
573 	if ('e' == tolower((u_char)lexeme[i]))
574 		i++;
575 	else
576 		return 0;
577 
578 	/* Read an optional Sign */
579 	if ('+' == lexeme[i] || '-' == lexeme[i])
580 		i++;
581 
582 	/* Now read the exponent part */
583 	while (lexeme[i] && isdigit((u_char)lexeme[i]))
584 		i++;
585 
586 	/* Check if we are done */
587 	if (!lexeme[i])
588 		return 1;
589 	else
590 		return 0;
591 }
592 
593 
594 /* is_special() - Test whether a character is a token */
595 static inline int
596 is_special(
597 	int ch
598 	)
599 {
600 	return strchr(special_chars, ch) != NULL;
601 }
602 
603 
604 static int
605 is_EOC(
606 	int ch
607 	)
608 {
609 	if ((old_config_style && (ch == '\n')) ||
610 	    (!old_config_style && (ch == ';')))
611 		return 1;
612 	return 0;
613 }
614 
615 
616 char *
617 quote_if_needed(char *str)
618 {
619 	char *ret;
620 	size_t len;
621 	size_t octets;
622 
623 	len = strlen(str);
624 	octets = len + 2 + 1;
625 	ret = emalloc(octets);
626 	if ('"' != str[0]
627 	    && (strcspn(str, special_chars) < len
628 		|| strchr(str, ' ') != NULL)) {
629 		snprintf(ret, octets, "\"%s\"", str);
630 	} else
631 		strlcpy(ret, str, octets);
632 
633 	return ret;
634 }
635 
636 
637 static int
638 create_string_token(
639 	char *lexeme
640 	)
641 {
642 	char *pch;
643 
644 	/*
645 	 * ignore end of line whitespace
646 	 */
647 	pch = lexeme;
648 	while (*pch && isspace((u_char)*pch))
649 		pch++;
650 
651 	if (!*pch) {
652 		yylval.Integer = T_EOC;
653 		return yylval.Integer;
654 	}
655 
656 	yylval.String = estrdup(lexeme);
657 	return T_String;
658 }
659 
660 
661 /*
662  * yylex() - function that does the actual scanning.
663  * Bison expects this function to be called yylex and for it to take no
664  * input and return an int.
665  * Conceptually yylex "returns" yylval as well as the actual return
666  * value representing the token or type.
667  */
668 int
669 yylex(void)
670 {
671 	static follby	followedby = FOLLBY_TOKEN;
672 	size_t		i;
673 	int		instring;
674 	int		yylval_was_set;
675 	int		converted;
676 	int		token;		/* The return value */
677 	int		ch;
678 
679 	instring = FALSE;
680 	yylval_was_set = FALSE;
681 
682 	do {
683 		/* Ignore whitespace at the beginning */
684 		while (EOF != (ch = lex_getch(lex_stack)) &&
685 		       isspace(ch) &&
686 		       !is_EOC(ch))
687 
688 			; /* Null Statement */
689 
690 		if (EOF == ch) {
691 
692 			if ( ! lex_pop_file())
693 				return 0;
694 			token = T_EOC;
695 			goto normal_return;
696 
697 		} else if (is_EOC(ch)) {
698 
699 			/* end FOLLBY_STRINGS_TO_EOC effect */
700 			followedby = FOLLBY_TOKEN;
701 			token = T_EOC;
702 			goto normal_return;
703 
704 		} else if (is_special(ch) && FOLLBY_TOKEN == followedby) {
705 			/* special chars are their own token values */
706 			token = ch;
707 			/*
708 			 * '=' outside simulator configuration implies
709 			 * a single string following as in:
710 			 * setvar Owner = "The Boss" default
711 			 */
712 			if ('=' == ch && old_config_style)
713 				followedby = FOLLBY_STRING;
714 			yytext[0] = (char)ch;
715 			yytext[1] = '\0';
716 			goto normal_return;
717 		} else
718 			lex_ungetch(ch, lex_stack);
719 
720 		/* save the position of start of the token */
721 		lex_stack->tokpos = lex_stack->curpos;
722 
723 		/* Read in the lexeme */
724 		i = 0;
725 		while (EOF != (ch = lex_getch(lex_stack))) {
726 
727 			yytext[i] = (char)ch;
728 
729 			/* Break on whitespace or a special character */
730 			if (isspace(ch) || is_EOC(ch)
731 			    || '"' == ch
732 			    || (FOLLBY_TOKEN == followedby
733 				&& is_special(ch)))
734 				break;
735 
736 			/* Read the rest of the line on reading a start
737 			   of comment character */
738 			if ('#' == ch) {
739 				while (EOF != (ch = lex_getch(lex_stack))
740 				       && '\n' != ch)
741 					; /* Null Statement */
742 				break;
743 			}
744 
745 			i++;
746 			if (i >= COUNTOF(yytext))
747 				goto lex_too_long;
748 		}
749 		/* Pick up all of the string inside between " marks, to
750 		 * end of line.  If we make it to EOL without a
751 		 * terminating " assume it for them.
752 		 *
753 		 * XXX - HMS: I'm not sure we want to assume the closing "
754 		 */
755 		if ('"' == ch) {
756 			instring = TRUE;
757 			while (EOF != (ch = lex_getch(lex_stack)) &&
758 			       ch != '"' && ch != '\n') {
759 				yytext[i++] = (char)ch;
760 				if (i >= COUNTOF(yytext))
761 					goto lex_too_long;
762 			}
763 			/*
764 			 * yytext[i] will be pushed back as not part of
765 			 * this lexeme, but any closing quote should
766 			 * not be pushed back, so we read another char.
767 			 */
768 			if ('"' == ch)
769 				ch = lex_getch(lex_stack);
770 		}
771 		/* Pushback the last character read that is not a part
772 		 * of this lexeme. This fails silently if ch is EOF,
773 		 * but then the EOF condition persists and is handled on
774 		 * the next turn by the include stack mechanism.
775 		 */
776 		lex_ungetch(ch, lex_stack);
777 
778 		yytext[i] = '\0';
779 	} while (i == 0);
780 
781 	/* Now return the desired token */
782 
783 	/* First make sure that the parser is *not* expecting a string
784 	 * as the next token (based on the previous token that was
785 	 * returned) and that we haven't read a string.
786 	 */
787 
788 	if (followedby == FOLLBY_TOKEN && !instring) {
789 		token = is_keyword(yytext, &followedby);
790 		if (token) {
791 			/*
792 			 * T_Server is exceptional as it forces the
793 			 * following token to be a string in the
794 			 * non-simulator parts of the configuration,
795 			 * but in the simulator configuration section,
796 			 * "server" is followed by "=" which must be
797 			 * recognized as a token not a string.
798 			 */
799 			if (T_Server == token && !old_config_style)
800 				followedby = FOLLBY_TOKEN;
801 			goto normal_return;
802 		} else if (is_integer(yytext)) {
803 			yylval_was_set = TRUE;
804 			errno = 0;
805 			if ((yylval.Integer = strtol(yytext, NULL, 10)) == 0
806 			    && ((errno == EINVAL) || (errno == ERANGE))) {
807 				msyslog(LOG_ERR,
808 					"Integer cannot be represented: %s",
809 					yytext);
810 				if (lex_from_file()) {
811 					exit(1);
812 				} else {
813 					/* force end of parsing */
814 					yylval.Integer = 0;
815 					return 0;
816 				}
817 			}
818 			token = T_Integer;
819 			goto normal_return;
820 		} else if (is_u_int(yytext)) {
821 			yylval_was_set = TRUE;
822 			if ('0' == yytext[0] &&
823 			    'x' == tolower((unsigned long)yytext[1]))
824 				converted = sscanf(&yytext[2], "%x",
825 						   &yylval.U_int);
826 			else
827 				converted = sscanf(yytext, "%u",
828 						   &yylval.U_int);
829 			if (1 != converted) {
830 				msyslog(LOG_ERR,
831 					"U_int cannot be represented: %s",
832 					yytext);
833 				if (lex_from_file()) {
834 					exit(1);
835 				} else {
836 					/* force end of parsing */
837 					yylval.Integer = 0;
838 					return 0;
839 				}
840 			}
841 			token = T_U_int;
842 			goto normal_return;
843 		} else if (is_double(yytext)) {
844 			yylval_was_set = TRUE;
845 			errno = 0;
846 			if ((yylval.Double = atof(yytext)) == 0 && errno == ERANGE) {
847 				msyslog(LOG_ERR,
848 					"Double too large to represent: %s",
849 					yytext);
850 				exit(1);
851 			} else {
852 				token = T_Double;
853 				goto normal_return;
854 			}
855 		} else {
856 			/* Default: Everything is a string */
857 			yylval_was_set = TRUE;
858 			token = create_string_token(yytext);
859 			goto normal_return;
860 		}
861 	}
862 
863 	/*
864 	 * Either followedby is not FOLLBY_TOKEN or this lexeme is part
865 	 * of a string.  Hence, we need to return T_String.
866 	 *
867 	 * _Except_ we might have a -4 or -6 flag on a an association
868 	 * configuration line (server, peer, pool, etc.).
869 	 *
870 	 * This is a terrible hack, but the grammar is ambiguous so we
871 	 * don't have a choice.  [SK]
872 	 *
873 	 * The ambiguity is in the keyword scanner, not ntp_parser.y.
874 	 * We do not require server addresses be quoted in ntp.conf,
875 	 * complicating the scanner's job.  To avoid trying (and
876 	 * failing) to match an IP address or DNS name to a keyword,
877 	 * the association keywords use FOLLBY_STRING in the keyword
878 	 * table, which tells the scanner to force the next token to be
879 	 * a T_String, so it does not try to match a keyword but rather
880 	 * expects a string when -4/-6 modifiers to server, peer, etc.
881 	 * are encountered.
882 	 * restrict -4 and restrict -6 parsing works correctly without
883 	 * this hack, as restrict uses FOLLBY_TOKEN.  [DH]
884 	 */
885 	if ('-' == yytext[0]) {
886 		if ('4' == yytext[1]) {
887 			token = T_Ipv4_flag;
888 			goto normal_return;
889 		} else if ('6' == yytext[1]) {
890 			token = T_Ipv6_flag;
891 			goto normal_return;
892 		}
893 	}
894 
895 	instring = FALSE;
896 	if (FOLLBY_STRING == followedby)
897 		followedby = FOLLBY_TOKEN;
898 
899 	yylval_was_set = TRUE;
900 	token = create_string_token(yytext);
901 
902 normal_return:
903 	if (T_EOC == token)
904 		DPRINTF(4,("\t<end of command>\n"));
905 	else
906 		DPRINTF(4, ("yylex: lexeme '%s' -> %s\n", yytext,
907 			    token_name(token)));
908 
909 	if (!yylval_was_set)
910 		yylval.Integer = token;
911 
912 	return token;
913 
914 lex_too_long:
915 	yytext[min(sizeof(yytext) - 1, 50)] = 0;
916 	msyslog(LOG_ERR,
917 		"configuration item on line %d longer than limit of %lu, began with '%s'",
918 		lex_stack->curpos.nline, (u_long)min(sizeof(yytext) - 1, 50),
919 		yytext);
920 
921 	/*
922 	 * If we hit the length limit reading the startup configuration
923 	 * file, abort.
924 	 */
925 	if (lex_from_file())
926 		exit(sizeof(yytext) - 1);
927 
928 	/*
929 	 * If it's runtime configuration via ntpq :config treat it as
930 	 * if the configuration text ended before the too-long lexeme,
931 	 * hostname, or string.
932 	 */
933 	yylval.Integer = 0;
934 	return 0;
935 }
936