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