]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind/bin/named/ns_parser.y
This commit was generated by cvs2svn to compensate for changes in r53796,
[FreeBSD/FreeBSD.git] / contrib / bind / bin / named / ns_parser.y
1 %{
2 #if !defined(lint) && !defined(SABER)
3 static char rcsid[] = "$Id: ns_parser.y,v 8.11 1997/12/04 07:03:05 halley Exp $";
4 #endif /* not lint */
5
6 /*
7  * Copyright (c) 1996, 1997 by Internet Software Consortium.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
14  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
16  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
17  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20  * SOFTWARE.
21  */
22
23 /* Global C stuff goes here. */
24
25 #include "port_before.h"
26
27 #include <sys/types.h>
28
29 #include <netinet/in.h>
30 #include <arpa/nameser.h>
31 #include <arpa/inet.h>
32
33 #include <ctype.h>
34 #include <limits.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <syslog.h>
39 #include <time.h>
40
41 #include <isc/eventlib.h>
42 #include <isc/logging.h>
43
44 #include "port_after.h"
45
46 #include "named.h"
47 #include "ns_parseutil.h"
48 #include "ns_lexer.h"
49
50 #define SYM_ZONE        0x010000
51 #define SYM_SERVER      0x020000
52 #define SYM_KEY         0x030000
53 #define SYM_ACL         0x040000
54 #define SYM_CHANNEL     0x050000
55 #define SYM_PORT        0x060000
56
57 #define SYMBOL_TABLE_SIZE 29989         /* should always be prime */
58 static symbol_table symtab;
59
60 #define AUTH_TABLE_SIZE 397             /* should always be prime */
61 static symbol_table authtab = NULL;
62
63 static zone_config current_zone;
64 static int seen_zone;
65
66 static options current_options;
67 static int seen_options;
68
69 static topology_config current_topology;
70 static int seen_topology;
71
72 static server_config current_server;
73 static int seen_server;
74
75 static char *current_algorithm;
76 static char *current_secret;
77
78 static log_config current_logging;
79 static int current_category;
80 static int chan_type;
81 static int chan_level;
82 static u_int chan_flags;
83 static int chan_facility;
84 static char *chan_name;
85 static int chan_versions;
86 static u_long chan_max_size;
87
88 static log_channel lookup_channel(char *);
89 static void define_channel(char *, log_channel);
90 static char *canonical_name(char *);
91
92 int yyparse();
93
94 %}
95
96 %union {
97         char *                  cp;
98         int                     s_int;
99         long                    num;
100         u_long                  ul_int;
101         u_int16_t               us_int;
102         struct in_addr          ip_addr;
103         ip_match_element        ime;
104         ip_match_list           iml;
105         key_info                keyi;
106         enum axfr_format        axfr_fmt;
107 }
108
109 /* Lexical analyzer return values. */
110 %token                  L_EOS
111 %token  <ip_addr>       L_IPADDR
112 %token  <num>           L_NUMBER
113 %token  <cp>            L_STRING
114 %token  <cp>            L_QSTRING
115 %token                  L_END_INCLUDE
116
117 /* Include support */
118 %token                  T_INCLUDE
119
120 /* Items related to the "options" statement: */
121 %token                  T_OPTIONS
122 %token                  T_DIRECTORY T_PIDFILE T_NAMED_XFER
123 %token                  T_DUMP_FILE T_STATS_FILE T_MEMSTATS_FILE
124 %token                  T_FAKE_IQUERY T_RECURSION T_FETCH_GLUE
125 %token                  T_QUERY_SOURCE T_LISTEN_ON T_PORT T_ADDRESS
126 %type   <us_int>        in_port
127 %type   <us_int>        maybe_port
128 %type   <us_int>        maybe_wild_port
129 %type   <ip_addr>       maybe_wild_addr
130 %token                  T_DATASIZE T_STACKSIZE T_CORESIZE
131 %token                  T_DEFAULT T_UNLIMITED
132 %token                  T_FILES
133 %token                  T_HOSTSTATS T_DEALLOC_ON_EXIT
134 %token                  T_TRANSFERS_IN T_TRANSFERS_OUT T_TRANSFERS_PER_NS
135 %token                  T_TRANSFER_FORMAT T_MAX_TRANSFER_TIME_IN
136 %token                  T_ONE_ANSWER T_MANY_ANSWERS
137 %type   <axfr_fmt>      transfer_format
138 %token                  T_NOTIFY T_AUTH_NXDOMAIN T_MULTIPLE_CNAMES
139 %token                  T_CLEAN_INTERVAL T_INTERFACE_INTERVAL T_STATS_INTERVAL
140
141 /* Items used for the "logging" statement: */
142 %token                  T_LOGGING T_CATEGORY T_CHANNEL T_SEVERITY T_DYNAMIC
143 %token                  T_FILE T_VERSIONS T_SIZE
144 %token                  T_SYSLOG T_DEBUG T_NULL_OUTPUT
145 %token                  T_PRINT_TIME T_PRINT_CATEGORY T_PRINT_SEVERITY
146 %type   <s_int>         category
147 %type   <cp>            category_name channel_name facility_name
148 %type   <s_int>         maybe_syslog_facility
149
150 /* Items used for the "topology" statement: */
151 %token                  T_TOPOLOGY
152
153 /* ip_match_list */
154 %type   <ime>           address_match_simple address_match_element address_name
155 %type   <iml>           address_match_list
156
157 /* Items used for "server" statements: */
158 %token                  T_SERVER 
159 %token                  T_LONG_AXFR 
160 %token                  T_BOGUS 
161 %token                  T_TRANSFERS 
162 %token                  T_KEYS
163
164 /* Items used for "zone" statements: */
165 %token                  T_ZONE
166 %type   <num>           optional_class
167 %type   <s_int>         zone_type
168 %token                  T_IN T_CHAOS T_HESIOD
169 %token                  T_TYPE
170 %token                  T_MASTER T_SLAVE T_STUB T_RESPONSE
171 %token                  T_HINT
172 %token                  T_MASTERS T_TRANSFER_SOURCE
173 %token                  T_ALSO_NOTIFY
174
175 /* Items used for access control lists and "allow" clauses: */
176 %token                  T_ACL 
177 %token                  T_ALLOW_UPDATE T_ALLOW_QUERY T_ALLOW_TRANSFER
178
179 /* Items related to the "key" statement: */
180 %token                  T_SEC_KEY T_ALGID T_SECRET
181 %type   <keyi>          key_ref
182 %type   <cp>            algorithm_id secret
183
184 /* Items used for "size_spec" clauses: */
185 %type   <ul_int>        size_spec
186
187 /* Items used for a "check-names" clause: */
188 %token                  T_CHECK_NAMES
189 %type   <s_int>         check_names_type
190 %type   <s_int>         check_names_opt
191 %token                  T_WARN T_FAIL T_IGNORE
192
193 /* Items used for "forward" clauses: */
194 %token                  T_FORWARD T_FORWARDERS
195 %token                  T_ONLY T_FIRST T_IF_NO_ANSWER T_IF_NO_DOMAIN
196
197 /* Items used for yes/no responses: */
198 %type   <num>           yea_or_nay
199 %token                  T_YES T_TRUE T_NO T_FALSE
200
201 /* Miscellaneous items (used in several places): */
202 %type   <cp>            any_string
203
204 %%
205 config_file: statement_list
206         {
207                 /* nothing */
208         }
209         ;
210
211 statement_list: statement
212         | statement_list statement
213         ;
214
215 statement: include_stmt
216         | options_stmt L_EOS
217         | logging_stmt L_EOS
218         | server_stmt L_EOS
219         | zone_stmt L_EOS
220         | acl_stmt L_EOS
221         | key_stmt L_EOS
222         | L_END_INCLUDE
223         | error L_EOS
224         | error L_END_INCLUDE
225         ;
226
227 include_stmt: T_INCLUDE L_QSTRING L_EOS { lexer_begin_file($2, NULL); }
228         ;
229
230 /*
231  * Options
232  */
233
234 options_stmt: T_OPTIONS 
235         {
236                 if (seen_options)
237                         parser_error(0, "cannot redefine options");
238                 current_options = new_options();
239         }
240         '{' options '}'
241         {
242                 if (!seen_options)
243                         set_options(current_options, 0);
244                 else
245                         free_options(current_options);
246                 current_options = NULL;
247                 seen_options = 1;
248         }
249         ;
250
251 options: option L_EOS
252         | options option L_EOS
253         ;
254
255 option: /* Empty */
256         | T_DIRECTORY L_QSTRING
257         {
258                 if (current_options->directory != NULL)
259                         freestr(current_options->directory);
260                 current_options->directory = $2;
261         }
262         | T_NAMED_XFER L_QSTRING
263         {
264                 if (current_options->named_xfer != NULL)
265                         freestr(current_options->named_xfer);
266                 current_options->named_xfer = $2;
267         }
268         | T_PIDFILE L_QSTRING
269         {
270                 if (current_options->pid_filename != NULL)
271                         freestr(current_options->pid_filename);
272                 current_options->pid_filename = $2;
273         }
274         | T_STATS_FILE L_QSTRING
275         {
276                 if (current_options->stats_filename != NULL)
277                         freestr(current_options->stats_filename);
278                 current_options->stats_filename = $2;
279         }
280         | T_MEMSTATS_FILE L_QSTRING
281         {
282                 if (current_options->memstats_filename != NULL)
283                         freestr(current_options->memstats_filename);
284                 current_options->memstats_filename = $2;
285         }
286         | T_DUMP_FILE L_QSTRING
287         {
288                 if (current_options->dump_filename != NULL)
289                         freestr(current_options->dump_filename);
290                 current_options->dump_filename = $2;
291         }
292         | T_FAKE_IQUERY yea_or_nay
293         {
294                 set_boolean_option(current_options, OPTION_FAKE_IQUERY, $2);
295         }
296         | T_RECURSION yea_or_nay
297         {
298                 set_boolean_option(current_options, OPTION_NORECURSE, !$2);
299         }
300         | T_FETCH_GLUE yea_or_nay
301         {
302                 set_boolean_option(current_options, OPTION_NOFETCHGLUE, !$2);
303         }
304         | T_NOTIFY yea_or_nay
305         {
306                 set_boolean_option(current_options, OPTION_NONOTIFY, !$2);
307         }
308         | T_HOSTSTATS yea_or_nay
309         {
310                 set_boolean_option(current_options, OPTION_HOSTSTATS, $2);
311         }
312         | T_DEALLOC_ON_EXIT yea_or_nay
313         {
314                 set_boolean_option(current_options, OPTION_DEALLOC_ON_EXIT,
315                                    $2);
316         }
317         | T_AUTH_NXDOMAIN yea_or_nay
318         {
319                 set_boolean_option(current_options, OPTION_NONAUTH_NXDOMAIN,
320                                    !$2);
321         }
322         | T_MULTIPLE_CNAMES yea_or_nay
323         {
324                 set_boolean_option(current_options, OPTION_MULTIPLE_CNAMES,
325                                    $2);
326         }
327         | T_CHECK_NAMES check_names_type check_names_opt
328         {
329                 current_options->check_names[$2] = $3;
330         }
331         | T_LISTEN_ON maybe_port '{' address_match_list '}'
332         {
333                 char port_string[10];
334                 symbol_value value;
335
336                 (void)sprintf(port_string, "%u", $2);
337                 if (lookup_symbol(symtab, port_string, SYM_PORT, NULL))
338                         parser_error(0,
339                                      "cannot redefine listen-on for port %u",
340                                      ntohs($2));
341                 else {
342                         add_listen_on(current_options, $2, $4);
343                         value.pointer = NULL;
344                         define_symbol(symtab, savestr(port_string, 1),
345                                       SYM_PORT, value, SYMBOL_FREE_KEY);
346                 }
347
348         }
349         | T_FORWARD forward_opt
350         | T_FORWARDERS 
351         {
352                 if (current_options->fwdtab) {
353                         free_forwarders(current_options->fwdtab);
354                         current_options->fwdtab = NULL;
355                 }
356         }
357         '{' opt_forwarders_list '}'
358         | T_QUERY_SOURCE query_source
359         | T_ALLOW_QUERY '{' address_match_list '}'
360         {
361                 if (current_options->query_acl)
362                         free_ip_match_list(current_options->query_acl);
363                 current_options->query_acl = $3;
364         }
365         | T_ALLOW_TRANSFER '{' address_match_list '}'
366         {
367                 if (current_options->transfer_acl)
368                         free_ip_match_list(current_options->transfer_acl);
369                 current_options->transfer_acl = $3;
370         }
371         | T_TOPOLOGY '{' address_match_list '}'
372         {
373                 if (current_options->topology)
374                         free_ip_match_list(current_options->topology);
375                 current_options->topology = $3;
376         }
377         | size_clause
378         {
379                 /* To get around the $$ = $1 default rule. */
380         }
381         | transfer_clause
382         | T_TRANSFER_FORMAT transfer_format
383         {
384                 current_options->transfer_format = $2;
385         }
386         | T_MAX_TRANSFER_TIME_IN L_NUMBER
387         {
388                 current_options->max_transfer_time_in = $2 * 60;
389         }
390         | T_CLEAN_INTERVAL L_NUMBER
391         {
392                 current_options->clean_interval = $2 * 60;
393         }
394         | T_INTERFACE_INTERVAL L_NUMBER
395         {
396                 current_options->interface_interval = $2 * 60;
397         }
398         | T_STATS_INTERVAL L_NUMBER
399         {
400                 current_options->stats_interval = $2 * 60;
401         }
402         | error
403         ;
404
405 transfer_format: T_ONE_ANSWER
406         {
407                 $$ = axfr_one_answer;
408         }
409         | T_MANY_ANSWERS
410         {
411                 $$ = axfr_many_answers;
412         }
413         ;
414         
415 maybe_wild_addr: L_IPADDR { $$ = $1; }
416         | '*' { $$.s_addr = htonl(INADDR_ANY); }
417         ;
418
419 maybe_wild_port: in_port { $$ = $1; }
420         | '*' { $$ = htons(0); }
421         ;
422
423 query_source_address: T_ADDRESS maybe_wild_addr
424         {
425                 current_options->query_source.sin_addr = $2;
426         }
427         ;
428
429 query_source_port: T_PORT maybe_wild_port
430         {
431                 current_options->query_source.sin_port = $2;
432         }
433         ;
434
435 query_source: query_source_address
436         | query_source_port
437         | query_source_address query_source_port
438         | query_source_port query_source_address
439         ;
440
441 maybe_port: /* nothing */ { $$ = htons(NS_DEFAULTPORT); }
442         | T_PORT in_port { $$ = $2; }
443         ;
444
445 yea_or_nay: T_YES
446         { 
447                 $$ = 1; 
448         }
449         | T_TRUE
450         { 
451                 $$ = 1; 
452         }
453         | T_NO
454         { 
455                 $$ = 0; 
456         }
457         | T_FALSE 
458         { 
459                 $$ = 0; 
460         }
461         | L_NUMBER
462         { 
463                 if ($1 == 1 || $1 == 0) {
464                         $$ = $1;
465                 } else {
466                         parser_warning(0,
467                                        "number should be 0 or 1; assuming 1");
468                         $$ = 1;
469                 }
470         }
471         ;
472
473 check_names_type: T_MASTER
474         {
475                 $$ = primary_trans;
476         }
477         | T_SLAVE
478         {
479                 $$ = secondary_trans;
480         }
481         | T_RESPONSE
482         {
483                 $$ = response_trans;
484         }
485         ;
486
487 check_names_opt: T_WARN
488         {
489                 $$ = warn;
490         }
491         | T_FAIL
492         {
493                 $$ = fail;
494         }
495         | T_IGNORE
496         {
497                 $$ = ignore;
498         }
499         ;
500
501 forward_opt: T_ONLY
502         {
503                 set_boolean_option(current_options, OPTION_FORWARD_ONLY, 1);
504         }
505         | T_FIRST
506         {
507                 set_boolean_option(current_options, OPTION_FORWARD_ONLY, 0);
508         }
509         | T_IF_NO_ANSWER
510         {
511                 parser_warning(0, "forward if-no-answer is unimplemented");
512         }
513         | T_IF_NO_DOMAIN
514         {
515                 parser_warning(0, "forward if-no-domain is unimplemented");
516         }
517         ;
518
519 size_clause: T_DATASIZE size_spec
520         {
521                 current_options->data_size = $2;
522         }
523         | T_STACKSIZE size_spec
524         {
525                 current_options->stack_size = $2;
526         }
527         | T_CORESIZE size_spec
528         {
529                 current_options->core_size = $2;
530         }
531         | T_FILES size_spec
532         {
533                 current_options->files = $2;
534         }
535         ;
536
537 size_spec: any_string
538         {
539                 u_long result;
540
541                 if (unit_to_ulong($1, &result))
542                         $$ = result;
543                 else {
544                         parser_error(0, "invalid unit string '%s'", $1);
545                         /* 0 means "use default" */
546                         $$ = 0;
547                 }
548                 freestr($1);
549         }
550         | L_NUMBER
551         {       
552                 $$ = (u_long)$1;
553         }
554         | T_DEFAULT
555         {
556                 $$ = 0;
557         }
558         | T_UNLIMITED
559         {
560                 $$ = ULONG_MAX;
561         }
562         ;
563
564 transfer_clause: T_TRANSFERS_IN L_NUMBER
565         {
566                 current_options->transfers_in = (u_long) $2;
567         }
568         | T_TRANSFERS_OUT L_NUMBER
569         {
570                 current_options->transfers_out = (u_long) $2;
571         }
572         | T_TRANSFERS_PER_NS L_NUMBER
573         {
574                 current_options->transfers_per_ns = (u_long) $2;
575         }
576         ;
577
578 opt_forwarders_list: /* nothing */
579         | forwarders_in_addr_list
580         ;
581
582 forwarders_in_addr_list: forwarders_in_addr L_EOS
583         {
584                 /* nothing */
585         }
586         | forwarders_in_addr_list forwarders_in_addr L_EOS
587         {
588                 /* nothing */
589         }
590         ;
591
592 forwarders_in_addr: L_IPADDR
593         {
594                 add_forwarder(current_options, $1);
595         }
596         ;
597
598 /*
599  * Logging
600  */
601
602 logging_stmt: T_LOGGING
603         {
604                 current_logging = begin_logging();
605         }
606         '{' logging_opts_list '}'
607         {
608                 end_logging(current_logging, 1);
609                 current_logging = NULL;
610         }
611         ;
612
613 logging_opts_list: logging_opt L_EOS
614         | logging_opts_list logging_opt L_EOS
615         | error
616         ;
617
618 logging_opt: T_CATEGORY category 
619         {
620                 current_category = $2;
621         }
622         '{' channel_list '}'
623         | T_CHANNEL channel_name
624         {
625                 chan_type = log_null;
626                 chan_flags = 0;
627                 chan_level = log_info;
628         }
629         '{' channel_opt_list '}'
630         {
631                 log_channel current_channel = NULL;
632
633                 if (lookup_channel($2) != NULL) {
634                         parser_error(0, "can't redefine channel '%s'", $2);
635                         freestr($2);
636                 } else {
637                         switch (chan_type) {
638                         case log_file:
639                                 current_channel =
640                                         log_new_file_channel(chan_flags,
641                                                              chan_level,
642                                                              chan_name, NULL,
643                                                              chan_versions,
644                                                              chan_max_size);
645                                 freestr(chan_name);
646                                 chan_name = NULL;
647                                 break;
648                         case log_syslog:
649                                 current_channel =
650                                         log_new_syslog_channel(chan_flags,
651                                                                chan_level,
652                                                                chan_facility);
653                                 break;
654                         case log_null:
655                                 current_channel = log_new_null_channel();
656                                 break;
657                         default:
658                                 ns_panic(ns_log_parser, 1,
659                                          "unknown channel type: %d",
660                                          chan_type);
661                         }
662                         if (current_channel == NULL)
663                                 ns_panic(ns_log_parser, 0,
664                                          "couldn't create channel");
665                         define_channel($2, current_channel);
666                 }
667         }
668         ;
669
670 channel_severity: any_string
671         {
672                 symbol_value value;
673
674                 if (lookup_symbol(constants, $1, SYM_LOGGING, &value)) {
675                         chan_level = value.integer;
676                 } else {
677                         parser_error(0, "unknown severity '%s'", $1);
678                         chan_level = log_debug(99);
679                 }
680                 freestr($1);
681         }
682         | T_DEBUG
683         {
684                 chan_level = log_debug(1);
685         }
686         | T_DEBUG L_NUMBER
687         {
688                 chan_level = $2;
689         }
690         | T_DYNAMIC
691         {
692                 chan_level = 0;
693                 chan_flags |= LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG;
694         }
695         ;
696
697 version_modifier: T_VERSIONS L_NUMBER
698         {
699                 chan_versions = $2;
700                 chan_flags |= LOG_TRUNCATE;
701         }
702         | T_VERSIONS T_UNLIMITED
703         {
704                 chan_versions = LOG_MAX_VERSIONS;
705                 chan_flags |= LOG_TRUNCATE;
706         }
707         ;
708
709 size_modifier: T_SIZE size_spec
710         {
711                 chan_max_size = $2;
712         }
713         ;
714
715 maybe_file_modifiers: /* nothing */
716         {
717                 chan_versions = 0;
718                 chan_max_size = ULONG_MAX;
719         }
720         | version_modifier
721         {
722                 chan_max_size = ULONG_MAX;
723         }
724         | size_modifier
725         {
726                 chan_versions = 0;
727         }
728         | version_modifier size_modifier
729         | size_modifier version_modifier
730         ;
731
732 channel_file: T_FILE L_QSTRING maybe_file_modifiers
733         {
734                 chan_flags |= LOG_CLOSE_STREAM;
735                 chan_type = log_file;
736                 chan_name = $2;
737         }
738         ;
739
740
741 facility_name: any_string { $$ = $1; }
742         | T_SYSLOG { $$ = savestr("syslog", 1); }
743         ;
744
745 maybe_syslog_facility: /* nothing */ { $$ = LOG_DAEMON; }
746         | facility_name
747         {
748                 symbol_value value;
749
750                 if (lookup_symbol(constants, $1, SYM_SYSLOG, &value)) {
751                         $$ = value.integer;
752                 } else {
753                         parser_error(0, "unknown facility '%s'", $1);
754                         $$ = LOG_DAEMON;
755                 }
756                 freestr($1);
757         }
758         ;
759
760 channel_syslog: T_SYSLOG maybe_syslog_facility
761         {
762                 chan_type = log_syslog;
763                 chan_facility = $2;
764         }
765         ;
766
767 channel_opt: channel_file { /* nothing to do */ }
768         | channel_syslog { /* nothing to do */ }
769         | T_NULL_OUTPUT
770         {
771                 chan_type = log_null;
772         }
773         | T_SEVERITY channel_severity { /* nothing to do */ }
774         | T_PRINT_TIME yea_or_nay
775         {
776                 if ($2)
777                         chan_flags |= LOG_TIMESTAMP;
778                 else
779                         chan_flags &= ~LOG_TIMESTAMP;
780         }
781         | T_PRINT_CATEGORY yea_or_nay
782         {
783                 if ($2)
784                         chan_flags |= LOG_PRINT_CATEGORY;
785                 else
786                         chan_flags &= ~LOG_PRINT_CATEGORY;
787         }
788         | T_PRINT_SEVERITY yea_or_nay
789         {
790                 if ($2)
791                         chan_flags |= LOG_PRINT_LEVEL;
792                 else
793                         chan_flags &= ~LOG_PRINT_LEVEL;
794         }
795         ;
796
797 channel_opt_list: channel_opt L_EOS
798         | channel_opt_list channel_opt L_EOS
799         | error
800         ;
801
802 channel_name: any_string
803         | T_NULL_OUTPUT { $$ = savestr("null", 1); }
804         ;
805
806 channel: channel_name
807         {
808                 log_channel channel;
809                 symbol_value value;
810
811                 if (current_category >= 0) {
812                         channel = lookup_channel($1);
813                         if (channel != NULL) {
814                                 add_log_channel(current_logging,
815                                                 current_category, channel);
816                         } else
817                                 parser_error(0, "unknown channel '%s'", $1);
818                 }
819                 freestr($1);
820         }
821         ;
822
823 channel_list: channel L_EOS
824         | channel_list channel L_EOS
825         | error
826         ;
827
828 category_name: any_string
829         | T_DEFAULT { $$ = savestr("default", 1); }
830         | T_NOTIFY { $$ = savestr("notify", 1); }
831         ;
832
833 category: category_name
834         {
835                 symbol_value value;
836
837                 if (lookup_symbol(constants, $1, SYM_CATEGORY, &value))
838                         $$ = value.integer;
839                 else {
840                         parser_error(0, "invalid logging category '%s'",
841                                      $1);
842                         $$ = -1;
843                 }
844                 freestr($1);
845         }
846         ;
847
848 /*
849  * Server Information
850  */
851
852 server_stmt: T_SERVER L_IPADDR
853         {
854                 char *ip_printable;
855                 symbol_value value;
856                 
857                 ip_printable = inet_ntoa($2);
858                 value.pointer = NULL;
859                 if (lookup_symbol(symtab, ip_printable, SYM_SERVER, NULL))
860                         seen_server = 1;
861                 else
862                         seen_server = 0;
863                 if (seen_server)
864                         parser_error(0, "cannot redefine server '%s'", 
865                                      ip_printable);
866                 else
867                         define_symbol(symtab, savestr(ip_printable, 1),
868                                       SYM_SERVER, value,
869                                       SYMBOL_FREE_KEY);
870                 current_server = begin_server($2);
871         }
872         '{' server_info_list '}'
873         {
874                 end_server(current_server, !seen_server);
875         }
876         ;
877
878 server_info_list: server_info L_EOS
879         | server_info_list server_info L_EOS
880         ;
881
882 server_info: T_BOGUS yea_or_nay
883         {
884                 set_server_option(current_server, SERVER_INFO_BOGUS, $2);
885         }
886         | T_TRANSFERS L_NUMBER
887         {
888                 set_server_transfers(current_server, (int)$2);
889         }
890         | T_TRANSFER_FORMAT transfer_format
891         {
892                 set_server_transfer_format(current_server, $2);
893         }
894         | T_KEYS '{' key_list '}'
895         | error
896         ;
897
898 /*
899  * Address Matching
900  */
901
902 address_match_list: address_match_element L_EOS
903         {
904                 ip_match_list iml;
905                 
906                 iml = new_ip_match_list();
907                 if ($1 != NULL)
908                         add_to_ip_match_list(iml, $1);
909                 $$ = iml;
910         }
911         | address_match_list address_match_element L_EOS
912         {
913                 if ($2 != NULL)
914                         add_to_ip_match_list($1, $2);
915                 $$ = $1;
916         }
917         ;
918
919 address_match_element: address_match_simple
920         | '!' address_match_simple
921         {
922                 if ($2 != NULL)
923                         ip_match_negate($2);
924                 $$ = $2;
925         }
926         ;
927
928 address_match_simple: L_IPADDR
929         {
930                 $$ = new_ip_match_pattern($1, 32);
931         }
932         | L_IPADDR '/' L_NUMBER
933         {
934                 if ($3 < 0 || $3 > 32) {
935                         parser_error(0, "mask bits out of range; skipping");
936                         $$ = NULL;
937                 } else {
938                         $$ = new_ip_match_pattern($1, $3);
939                         if ($$ == NULL)
940                                 parser_error(0, 
941                                            "address/mask mismatch; skipping");
942                 }
943         }
944         | L_NUMBER '/' L_NUMBER
945         {
946                 struct in_addr ia;
947
948                 if ($1 > 255) {
949                         parser_error(0, "address out of range; skipping");
950                         $$ = NULL;
951                 } else {
952                         if ($3 < 0 || $3 > 32) {
953                                 parser_error(0,
954                                         "mask bits out of range; skipping");
955                                         $$ = NULL;
956                         } else {
957                                 ia.s_addr = htonl(($1 & 0xff) << 24);
958                                 $$ = new_ip_match_pattern(ia, $3);
959                                 if ($$ == NULL)
960                                         parser_error(0, 
961                                            "address/mask mismatch; skipping");
962                         }
963                 }
964         }
965         | address_name
966         | '{' address_match_list '}'
967         {
968                 char name[256];
969
970                 /*
971                  * We want to be able to clean up this iml later so
972                  * we give it a name and treat it like any other acl.
973                  */
974                 sprintf(name, "__internal_%p", $2);
975                 define_acl(savestr(name, 1), $2);
976                 $$ = new_ip_match_indirect($2);
977         }
978         ;
979
980 address_name: any_string
981         {
982                 ip_match_list iml;
983
984                 iml = lookup_acl($1);
985                 if (iml == NULL) {
986                         parser_error(0, "unknown ACL '%s'", $1);
987                         $$ = NULL;
988                 } else
989                         $$ = new_ip_match_indirect(iml);
990                 freestr($1);
991         }
992         ;
993
994 /*
995  * Keys
996  */
997
998 key_ref: any_string
999         {
1000                 key_info ki;
1001
1002                 ki = lookup_key($1);
1003                 if (ki == NULL) {
1004                         parser_error(0, "unknown key '%s'", $1);
1005                         $$ = NULL;
1006                 } else
1007                         $$ = ki;
1008                 freestr($1);
1009         }
1010         ;
1011
1012 key_list_element: key_ref
1013         {
1014                 if ($1 == NULL)
1015                         parser_error(0, "empty key not added to server list ");
1016                 else
1017                         add_server_key_info(current_server, $1);
1018         }
1019         ;
1020
1021 key_list: key_list_element L_EOS
1022         | key_list key_list_element L_EOS
1023         | error
1024         ;
1025
1026 key_stmt: T_SEC_KEY
1027         {
1028                 current_algorithm = NULL;
1029                 current_secret = NULL;
1030         }
1031         any_string '{' key_definition '}'
1032         {
1033                 key_info ki;
1034
1035                 if (lookup_key($3) != NULL) {
1036                         parser_error(0, "can't redefine key '%s'", $3);
1037                         freestr($3);
1038                 } else {
1039                         if (current_algorithm == NULL ||
1040                             current_secret == NULL)
1041                                 parser_error(0, "skipping bad key '%s'", $3);
1042                         else {
1043                                 ki = new_key_info($3, current_algorithm,
1044                                                   current_secret);
1045                                 define_key($3, ki);
1046                         }
1047                 }
1048         }
1049         ;
1050         
1051 key_definition: algorithm_id secret
1052         {
1053                 current_algorithm = $1;
1054                 current_secret = $2;
1055         }
1056         | secret algorithm_id
1057         {
1058                 current_algorithm = $2;
1059                 current_secret = $1;
1060         }
1061         | error
1062         {
1063                 current_algorithm = NULL;
1064                 current_secret = NULL;
1065         }
1066         ;
1067
1068 algorithm_id: T_ALGID any_string L_EOS { $$ = $2; }
1069         ;
1070
1071 secret: T_SECRET any_string L_EOS { $$ = $2; }
1072         ;
1073
1074 /*
1075  * ACLs
1076  */
1077
1078 acl_stmt: T_ACL any_string '{' address_match_list '}'
1079         {
1080                 if (lookup_acl($2) != NULL) {
1081                         parser_error(0, "can't redefine ACL '%s'", $2);
1082                         freestr($2);
1083                 } else
1084                         define_acl($2, $4);
1085         }
1086         ;
1087
1088 /*
1089  * Zones
1090  */
1091         
1092 zone_stmt: T_ZONE L_QSTRING optional_class
1093         {
1094                 int sym_type;
1095                 symbol_value value;
1096                 char *zone_name;
1097
1098                 if (!seen_options)
1099                         parser_error(0,
1100              "no options statement before first zone; using previous/default");
1101                 sym_type = SYM_ZONE | ($3 & 0xffff);
1102                 value.pointer = NULL;
1103                 zone_name = canonical_name($2);
1104                 if (zone_name == NULL) {
1105                         parser_error(0, "can't make zone name '%s' canonical",
1106                                      $2);
1107                         seen_zone = 1;
1108                         zone_name = savestr("__bad_zone__", 1);
1109                 } else {
1110                         seen_zone = lookup_symbol(symtab, zone_name, sym_type,
1111                                                   NULL);
1112                         if (seen_zone) {
1113                                 parser_error(0,
1114                                         "cannot redefine zone '%s' class %d",
1115                                              zone_name, $3);
1116                         } else
1117                                 define_symbol(symtab, zone_name, sym_type,
1118                                               value, 0);
1119                 }
1120                 freestr($2);
1121                 current_zone = begin_zone(zone_name, $3); 
1122         }
1123         optional_zone_options_list
1124         { end_zone(current_zone, !seen_zone); }
1125         ;
1126
1127 optional_zone_options_list: /* Empty */
1128         | '{' zone_option_list '}'
1129         ;
1130
1131 optional_class: /* Empty */
1132         {
1133                 $$ = C_IN;
1134         }
1135         | any_string
1136         {
1137                 symbol_value value;
1138
1139                 if (lookup_symbol(constants, $1, SYM_CLASS, &value))
1140                         $$ = value.integer;
1141                 else {
1142                         /* the zone validator will give the error */
1143                         $$ = C_NONE;
1144                 }
1145                 freestr($1);
1146         }
1147         ;
1148
1149 zone_type: T_MASTER
1150         {
1151                 $$ = Z_MASTER;
1152         }
1153         | T_SLAVE
1154         {
1155                 $$ = Z_SLAVE;
1156         }
1157         | T_HINT
1158         {
1159                 $$ = Z_HINT;
1160         }
1161         | T_STUB
1162         {
1163                 $$ = Z_STUB;
1164         }
1165         ;
1166
1167 zone_option_list: zone_option L_EOS
1168         | zone_option_list zone_option L_EOS
1169         ;
1170
1171 zone_option: T_TYPE zone_type
1172         {
1173                 if (!set_zone_type(current_zone, $2))
1174                         parser_warning(0, "zone type already set; skipping");
1175         }
1176         | T_FILE L_QSTRING
1177         {
1178                 if (!set_zone_filename(current_zone, $2))
1179                         parser_warning(0,
1180                                        "zone filename already set; skipping");
1181         }
1182         | T_MASTERS '{' master_in_addr_list '}'
1183         | T_TRANSFER_SOURCE maybe_wild_addr
1184         {
1185                 set_zone_transfer_source(current_zone, $2);
1186         }
1187         | T_CHECK_NAMES check_names_opt
1188         {
1189                 if (!set_zone_checknames(current_zone, $2))
1190                         parser_warning(0,
1191                                       "zone checknames already set; skipping");
1192         }
1193         | T_ALLOW_UPDATE '{' address_match_list '}'
1194         {
1195                 if (!set_zone_update_acl(current_zone, $3))
1196                         parser_warning(0,
1197                                       "zone update acl already set; skipping");
1198         }
1199         | T_ALLOW_QUERY '{' address_match_list '}'
1200         {
1201                 if (!set_zone_query_acl(current_zone, $3))
1202                         parser_warning(0,
1203                                       "zone query acl already set; skipping");
1204         }
1205         | T_ALLOW_TRANSFER '{' address_match_list '}'
1206         {
1207                 if (!set_zone_transfer_acl(current_zone, $3))
1208                         parser_warning(0,
1209                                     "zone transfer acl already set; skipping");
1210         }
1211         | T_MAX_TRANSFER_TIME_IN L_NUMBER
1212         {
1213                 if (!set_zone_transfer_time_in(current_zone, $2*60))
1214                         parser_warning(0,
1215                        "zone max transfer time (in) already set; skipping");
1216         }
1217         | T_NOTIFY yea_or_nay
1218         {
1219                 set_zone_notify(current_zone, $2);
1220         }
1221         | T_ALSO_NOTIFY '{' opt_notify_in_addr_list '}'
1222         | error
1223         ;
1224
1225 master_in_addr_list: master_in_addr L_EOS
1226         {
1227                 /* nothing */
1228         }
1229         | master_in_addr_list master_in_addr L_EOS
1230         {
1231                 /* nothing */
1232         }
1233         ;
1234
1235 master_in_addr: L_IPADDR
1236         {
1237                 add_zone_master(current_zone, $1);
1238         }
1239         ;
1240
1241 opt_notify_in_addr_list: /* nothing */
1242         | notify_in_addr_list
1243         ;
1244
1245 notify_in_addr_list: notify_in_addr L_EOS
1246         {
1247                 /* nothing */
1248         }
1249         | notify_in_addr_list notify_in_addr L_EOS
1250         {
1251                 /* nothing */
1252         }
1253         ;
1254
1255 notify_in_addr: L_IPADDR
1256         {
1257                 add_zone_notify(current_zone, $1);
1258         }
1259         ;
1260
1261 /*
1262  * Misc.
1263  */
1264
1265 in_port: L_NUMBER
1266         {
1267                 if ($1 < 0 || $1 > 65535) {
1268                         parser_warning(0, 
1269                           "invalid IP port number '%d'; setting port to 0",
1270                                        $1);
1271                         $1 = 0;
1272                 } else
1273                         $$ = htons($1);
1274         }
1275         ;
1276
1277 any_string: L_STRING
1278         | L_QSTRING
1279         ;
1280         
1281 %%
1282
1283 static char *
1284 canonical_name(char *name) {
1285         char canonical[MAXDNAME];
1286         
1287         if (strlen(name) >= MAXDNAME)
1288                 return (NULL);
1289         strcpy(canonical, name);
1290         if (makename(canonical, ".", sizeof canonical) < 0)
1291                 return (NULL);
1292         return (savestr(canonical, 0));
1293 }
1294
1295 static void
1296 init_acls() {
1297         ip_match_element ime;
1298         ip_match_list iml;
1299         struct in_addr address;
1300
1301         /* Create the predefined ACLs */
1302
1303         address.s_addr = 0U;
1304
1305         /* ACL "any" */
1306         ime = new_ip_match_pattern(address, 0);
1307         iml = new_ip_match_list();
1308         add_to_ip_match_list(iml, ime);
1309         define_acl(savestr("any", 1), iml);
1310
1311         /* ACL "none" */
1312         ime = new_ip_match_pattern(address, 0);
1313         ip_match_negate(ime);
1314         iml = new_ip_match_list();
1315         add_to_ip_match_list(iml, ime);
1316         define_acl(savestr("none", 1), iml);
1317
1318         /* ACL "localhost" */
1319         ime = new_ip_match_localhost();
1320         iml = new_ip_match_list();
1321         add_to_ip_match_list(iml, ime);
1322         define_acl(savestr("localhost", 1), iml);
1323
1324         /* ACL "localnets" */
1325         ime = new_ip_match_localnets();
1326         iml = new_ip_match_list();
1327         add_to_ip_match_list(iml, ime);
1328         define_acl(savestr("localnets", 1), iml);
1329 }
1330
1331 static void
1332 free_sym_value(int type, void *value) {
1333         ns_debug(ns_log_parser, 99, "free_sym_value: type %06x value %p",
1334                  type, value);
1335         type &= ~0xffff;
1336         switch (type) {
1337         case SYM_ACL:
1338                 free_ip_match_list(value);
1339                 break;
1340         case SYM_KEY:
1341                 free_key_info(value);
1342                 break;
1343         default:
1344                 ns_panic(ns_log_parser, 1,
1345                          "unhandled case in free_sym_value()");
1346                 /* NOTREACHED */
1347                 break;
1348         }
1349 }
1350
1351 static log_channel
1352 lookup_channel(char *name) {
1353         symbol_value value;
1354
1355         if (lookup_symbol(symtab, name, SYM_CHANNEL, &value))
1356                 return ((log_channel)(value.pointer));
1357         return (NULL);
1358 }
1359
1360 static void
1361 define_channel(char *name, log_channel channel) {
1362         symbol_value value;
1363
1364         value.pointer = channel;  
1365         define_symbol(symtab, name, SYM_CHANNEL, value, SYMBOL_FREE_KEY);
1366 }
1367
1368 static void
1369 define_builtin_channels() {
1370         define_channel(savestr("default_syslog", 1), syslog_channel);
1371         define_channel(savestr("default_debug", 1), debug_channel);
1372         define_channel(savestr("default_stderr", 1), stderr_channel);
1373         define_channel(savestr("null", 1), null_channel);
1374 }
1375
1376 static void
1377 parser_setup() {
1378         seen_options = 0;
1379         seen_topology = 0;
1380         symtab = new_symbol_table(SYMBOL_TABLE_SIZE, NULL);
1381         if (authtab != NULL)
1382                 free_symbol_table(authtab);
1383         authtab = new_symbol_table(AUTH_TABLE_SIZE, free_sym_value);
1384         init_acls();
1385         define_builtin_channels();
1386 }
1387
1388 static void
1389 parser_cleanup() {
1390         if (symtab != NULL)
1391                 free_symbol_table(symtab);
1392         symtab = NULL;
1393         /*
1394          * We don't clean up authtab here because the ip_match_lists are in
1395          * use.
1396          */
1397 }
1398
1399 /*
1400  * Public Interface
1401  */
1402
1403 ip_match_list
1404 lookup_acl(char *name) {
1405         symbol_value value;
1406
1407         if (lookup_symbol(authtab, name, SYM_ACL, &value))
1408                 return ((ip_match_list)(value.pointer));
1409         return (NULL);
1410 }
1411
1412 void
1413 define_acl(char *name, ip_match_list iml) {
1414         symbol_value value;
1415
1416         INSIST(name != NULL);
1417         INSIST(iml != NULL);
1418
1419         value.pointer = iml;
1420         define_symbol(authtab, name, SYM_ACL, value,
1421                       SYMBOL_FREE_KEY|SYMBOL_FREE_VALUE);
1422         ns_debug(ns_log_parser, 7, "acl %s", name);
1423         dprint_ip_match_list(ns_log_parser, iml, 2, "allow ", "deny ");
1424 }
1425
1426 key_info
1427 lookup_key(char *name) {
1428         symbol_value value;
1429
1430         if (lookup_symbol(authtab, name, SYM_KEY, &value))
1431                 return ((key_info)(value.pointer));
1432         return (NULL);
1433 }
1434
1435 void
1436 define_key(char *name, key_info ki) {
1437         symbol_value value;
1438
1439         INSIST(name != NULL);
1440         INSIST(ki != NULL);
1441
1442         value.pointer = ki;
1443         define_symbol(authtab, name, SYM_KEY, value, SYMBOL_FREE_VALUE);
1444         dprint_key_info(ki);
1445 }
1446
1447 void
1448 parse_configuration(const char *filename) {
1449         FILE *config_stream;
1450
1451         config_stream = fopen(filename, "r");
1452         if (config_stream == NULL)
1453                 ns_panic(ns_log_parser, 0, "can't open '%s'", filename);
1454
1455         lexer_setup();
1456         parser_setup();
1457         lexer_begin_file(filename, config_stream);
1458         (void)yyparse();
1459         lexer_end_file();
1460         parser_cleanup();
1461 }
1462
1463 void
1464 parser_initialize(void) {
1465         lexer_initialize();
1466 }
1467
1468 void
1469 parser_shutdown(void) {
1470         if (authtab != NULL)
1471                 free_symbol_table(authtab);
1472         lexer_shutdown();
1473 }