]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/isccfg/parser.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / isccfg / parser.c
1 /*
2  * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id$ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <isc/buffer.h>
25 #include <isc/dir.h>
26 #include <isc/formatcheck.h>
27 #include <isc/lex.h>
28 #include <isc/log.h>
29 #include <isc/mem.h>
30 #include <isc/net.h>
31 #include <isc/netaddr.h>
32 #include <isc/netscope.h>
33 #include <isc/print.h>
34 #include <isc/string.h>
35 #include <isc/sockaddr.h>
36 #include <isc/symtab.h>
37 #include <isc/util.h>
38
39 #include <isccfg/cfg.h>
40 #include <isccfg/grammar.h>
41 #include <isccfg/log.h>
42
43 /* Shorthand */
44 #define CAT CFG_LOGCATEGORY_CONFIG
45 #define MOD CFG_LOGMODULE_PARSER
46
47 #define MAP_SYM 1       /* Unique type for isc_symtab */
48
49 #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
50
51 /* Check a return value. */
52 #define CHECK(op)                                               \
53         do { result = (op);                                     \
54                 if (result != ISC_R_SUCCESS) goto cleanup;      \
55         } while (0)
56
57 /* Clean up a configuration object if non-NULL. */
58 #define CLEANUP_OBJ(obj) \
59         do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
60
61
62 /*
63  * Forward declarations of static functions.
64  */
65
66 static void
67 free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
68
69 static isc_result_t
70 parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
71
72 static void
73 print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
74
75 static void
76 free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
77
78 static isc_result_t
79 create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
80
81 static isc_result_t
82 create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
83               cfg_obj_t **ret);
84
85 static void
86 free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
87
88 static isc_result_t
89 create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
90
91 static void
92 free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
93
94 static isc_result_t
95 parse_symtab_elt(cfg_parser_t *pctx, const char *name,
96                  cfg_type_t *elttype, isc_symtab_t *symtab,
97                  isc_boolean_t callback);
98
99 static void
100 free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
101
102 static isc_result_t
103 cfg_getstringtoken(cfg_parser_t *pctx);
104
105 static void
106 parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
107                 unsigned int flags, const char *format, va_list args);
108
109 /*
110  * Data representations.  These correspond to members of the
111  * "value" union in struct cfg_obj (except "void", which does
112  * not need a union member).
113  */
114
115 cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop };
116 cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop };
117 cfg_rep_t cfg_rep_string = { "string", free_string };
118 cfg_rep_t cfg_rep_boolean = { "boolean", free_noop };
119 cfg_rep_t cfg_rep_map = { "map", free_map };
120 cfg_rep_t cfg_rep_list = { "list", free_list };
121 cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple };
122 cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
123 cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop };
124 cfg_rep_t cfg_rep_void = { "void", free_noop };
125
126 /*
127  * Configuration type definitions.
128  */
129
130 /*%
131  * An implicit list.  These are formed by clauses that occur multiple times.
132  */
133 static cfg_type_t cfg_type_implicitlist = {
134         "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL };
135
136 /* Functions. */
137
138 void
139 cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
140         obj->type->print(pctx, obj);
141 }
142
143 void
144 cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
145         pctx->f(pctx->closure, text, len);
146 }
147
148 static void
149 print_open(cfg_printer_t *pctx) {
150         cfg_print_chars(pctx, "{\n", 2);
151         pctx->indent++;
152 }
153
154 static void
155 print_indent(cfg_printer_t *pctx) {
156         int indent = pctx->indent;
157         while (indent > 0) {
158                 cfg_print_chars(pctx, "\t", 1);
159                 indent--;
160         }
161 }
162
163 static void
164 print_close(cfg_printer_t *pctx) {
165         pctx->indent--;
166         print_indent(pctx);
167         cfg_print_chars(pctx, "}", 1);
168 }
169
170 isc_result_t
171 cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
172         isc_result_t result;
173         INSIST(ret != NULL && *ret == NULL);
174         result = type->parse(pctx, type, ret);
175         if (result != ISC_R_SUCCESS)
176                 return (result);
177         INSIST(*ret != NULL);
178         return (ISC_R_SUCCESS);
179 }
180
181 void
182 cfg_print(const cfg_obj_t *obj,
183           void (*f)(void *closure, const char *text, int textlen),
184           void *closure)
185 {
186         cfg_printer_t pctx;
187         pctx.f = f;
188         pctx.closure = closure;
189         pctx.indent = 0;
190         obj->type->print(&pctx, obj);
191 }
192
193
194 /* Tuples. */
195
196 isc_result_t
197 cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
198         isc_result_t result;
199         const cfg_tuplefielddef_t *fields = type->of;
200         const cfg_tuplefielddef_t *f;
201         cfg_obj_t *obj = NULL;
202         unsigned int nfields = 0;
203         int i;
204
205         for (f = fields; f->name != NULL; f++)
206                 nfields++;
207
208         CHECK(cfg_create_obj(pctx, type, &obj));
209         obj->value.tuple = isc_mem_get(pctx->mctx,
210                                        nfields * sizeof(cfg_obj_t *));
211         if (obj->value.tuple == NULL) {
212                 result = ISC_R_NOMEMORY;
213                 goto cleanup;
214         }
215         for (f = fields, i = 0; f->name != NULL; f++, i++)
216                 obj->value.tuple[i] = NULL;
217         *ret = obj;
218         return (ISC_R_SUCCESS);
219
220  cleanup:
221         if (obj != NULL)
222                 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
223         return (result);
224 }
225
226 isc_result_t
227 cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
228 {
229         isc_result_t result;
230         const cfg_tuplefielddef_t *fields = type->of;
231         const cfg_tuplefielddef_t *f;
232         cfg_obj_t *obj = NULL;
233         unsigned int i;
234
235         CHECK(cfg_create_tuple(pctx, type, &obj));
236         for (f = fields, i = 0; f->name != NULL; f++, i++)
237                 CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
238
239         *ret = obj;
240         return (ISC_R_SUCCESS);
241
242  cleanup:
243         CLEANUP_OBJ(obj);
244         return (result);
245 }
246
247 void
248 cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
249         unsigned int i;
250         const cfg_tuplefielddef_t *fields = obj->type->of;
251         const cfg_tuplefielddef_t *f;
252         isc_boolean_t need_space = ISC_FALSE;
253
254         for (f = fields, i = 0; f->name != NULL; f++, i++) {
255                 const cfg_obj_t *fieldobj = obj->value.tuple[i];
256                 if (need_space)
257                         cfg_print_chars(pctx, " ", 1);
258                 cfg_print_obj(pctx, fieldobj);
259                 need_space = ISC_TF(fieldobj->type->print != cfg_print_void);
260         }
261 }
262
263 void
264 cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
265         const cfg_tuplefielddef_t *fields = type->of;
266         const cfg_tuplefielddef_t *f;
267         isc_boolean_t need_space = ISC_FALSE;
268
269         for (f = fields; f->name != NULL; f++) {
270                 if (need_space)
271                         cfg_print_chars(pctx, " ", 1);
272                 cfg_doc_obj(pctx, f->type);
273                 need_space = ISC_TF(f->type->print != cfg_print_void);
274         }
275 }
276
277 static void
278 free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
279         unsigned int i;
280         const cfg_tuplefielddef_t *fields = obj->type->of;
281         const cfg_tuplefielddef_t *f;
282         unsigned int nfields = 0;
283
284         if (obj->value.tuple == NULL)
285                 return;
286
287         for (f = fields, i = 0; f->name != NULL; f++, i++) {
288                 CLEANUP_OBJ(obj->value.tuple[i]);
289                 nfields++;
290         }
291         isc_mem_put(pctx->mctx, obj->value.tuple,
292                     nfields * sizeof(cfg_obj_t *));
293 }
294
295 isc_boolean_t
296 cfg_obj_istuple(const cfg_obj_t *obj) {
297         REQUIRE(obj != NULL);
298         return (ISC_TF(obj->type->rep == &cfg_rep_tuple));
299 }
300
301 const cfg_obj_t *
302 cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) {
303         unsigned int i;
304         const cfg_tuplefielddef_t *fields;
305         const cfg_tuplefielddef_t *f;
306
307         REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
308
309         fields = tupleobj->type->of;
310         for (f = fields, i = 0; f->name != NULL; f++, i++) {
311                 if (strcmp(f->name, name) == 0)
312                         return (tupleobj->value.tuple[i]);
313         }
314         INSIST(0);
315         return (NULL);
316 }
317
318 isc_result_t
319 cfg_parse_special(cfg_parser_t *pctx, int special) {
320         isc_result_t result;
321         CHECK(cfg_gettoken(pctx, 0));
322         if (pctx->token.type == isc_tokentype_special &&
323             pctx->token.value.as_char == special)
324                 return (ISC_R_SUCCESS);
325
326         cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
327         return (ISC_R_UNEXPECTEDTOKEN);
328  cleanup:
329         return (result);
330 }
331
332 /*
333  * Parse a required semicolon.  If it is not there, log
334  * an error and increment the error count but continue
335  * parsing.  Since the next token is pushed back,
336  * care must be taken to make sure it is eventually
337  * consumed or an infinite loop may result.
338  */
339 static isc_result_t
340 parse_semicolon(cfg_parser_t *pctx) {
341         isc_result_t result;
342         CHECK(cfg_gettoken(pctx, 0));
343         if (pctx->token.type == isc_tokentype_special &&
344             pctx->token.value.as_char == ';')
345                 return (ISC_R_SUCCESS);
346
347         cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
348         cfg_ungettoken(pctx);
349  cleanup:
350         return (result);
351 }
352
353 /*
354  * Parse EOF, logging and returning an error if not there.
355  */
356 static isc_result_t
357 parse_eof(cfg_parser_t *pctx) {
358         isc_result_t result;
359         CHECK(cfg_gettoken(pctx, 0));
360
361         if (pctx->token.type == isc_tokentype_eof)
362                 return (ISC_R_SUCCESS);
363
364         cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
365         return (ISC_R_UNEXPECTEDTOKEN);
366  cleanup:
367         return (result);
368 }
369
370 /* A list of files, used internally for pctx->files. */
371
372 static cfg_type_t cfg_type_filelist = {
373         "filelist", NULL, print_list, NULL, &cfg_rep_list,
374         &cfg_type_qstring
375 };
376
377 isc_result_t
378 cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
379         isc_result_t result;
380         cfg_parser_t *pctx;
381         isc_lexspecials_t specials;
382
383         REQUIRE(mctx != NULL);
384         REQUIRE(ret != NULL && *ret == NULL);
385
386         pctx = isc_mem_get(mctx, sizeof(*pctx));
387         if (pctx == NULL)
388                 return (ISC_R_NOMEMORY);
389
390         result = isc_refcount_init(&pctx->references, 1);
391         if (result != ISC_R_SUCCESS) {
392                 isc_mem_put(mctx, pctx, sizeof(*pctx));
393                 return (result);
394         }
395
396         pctx->mctx = mctx;
397         pctx->lctx = lctx;
398         pctx->lexer = NULL;
399         pctx->seen_eof = ISC_FALSE;
400         pctx->ungotten = ISC_FALSE;
401         pctx->errors = 0;
402         pctx->warnings = 0;
403         pctx->open_files = NULL;
404         pctx->closed_files = NULL;
405         pctx->line = 0;
406         pctx->callback = NULL;
407         pctx->callbackarg = NULL;
408         pctx->token.type = isc_tokentype_unknown;
409         pctx->flags = 0;
410
411         memset(specials, 0, sizeof(specials));
412         specials['{'] = 1;
413         specials['}'] = 1;
414         specials[';'] = 1;
415         specials['/'] = 1;
416         specials['"'] = 1;
417         specials['!'] = 1;
418
419         CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer));
420
421         isc_lex_setspecials(pctx->lexer, specials);
422         isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C |
423                                          ISC_LEXCOMMENT_CPLUSPLUS |
424                                          ISC_LEXCOMMENT_SHELL));
425
426         CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
427         CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
428
429         *ret = pctx;
430         return (ISC_R_SUCCESS);
431
432  cleanup:
433         if (pctx->lexer != NULL)
434                 isc_lex_destroy(&pctx->lexer);
435         CLEANUP_OBJ(pctx->open_files);
436         CLEANUP_OBJ(pctx->closed_files);
437         isc_mem_put(mctx, pctx, sizeof(*pctx));
438         return (result);
439 }
440
441 static isc_result_t
442 parser_openfile(cfg_parser_t *pctx, const char *filename) {
443         isc_result_t result;
444         cfg_listelt_t *elt = NULL;
445         cfg_obj_t *stringobj = NULL;
446
447         result = isc_lex_openfile(pctx->lexer, filename);
448         if (result != ISC_R_SUCCESS) {
449                 cfg_parser_error(pctx, 0, "open: %s: %s",
450                              filename, isc_result_totext(result));
451                 goto cleanup;
452         }
453
454         CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
455         CHECK(create_listelt(pctx, &elt));
456         elt->obj = stringobj;
457         ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
458
459         return (ISC_R_SUCCESS);
460  cleanup:
461         CLEANUP_OBJ(stringobj);
462         return (result);
463 }
464
465 void
466 cfg_parser_setcallback(cfg_parser_t *pctx,
467                        cfg_parsecallback_t callback,
468                        void *arg)
469 {
470         pctx->callback = callback;
471         pctx->callbackarg = arg;
472 }
473
474 /*
475  * Parse a configuration using a pctx where a lexer has already
476  * been set up with a source.
477  */
478 static isc_result_t
479 parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
480         isc_result_t result;
481         cfg_obj_t *obj = NULL;
482
483         result = cfg_parse_obj(pctx, type, &obj);
484
485         if (pctx->errors != 0) {
486                 /* Errors have been logged. */
487                 if (result == ISC_R_SUCCESS)
488                         result = ISC_R_FAILURE;
489                 goto cleanup;
490         }
491
492         if (result != ISC_R_SUCCESS) {
493                 /* Parsing failed but no errors have been logged. */
494                 cfg_parser_error(pctx, 0, "parsing failed");
495                 goto cleanup;
496         }
497
498         CHECK(parse_eof(pctx));
499
500         *ret = obj;
501         return (ISC_R_SUCCESS);
502
503  cleanup:
504         CLEANUP_OBJ(obj);
505         return (result);
506 }
507
508 isc_result_t
509 cfg_parse_file(cfg_parser_t *pctx, const char *filename,
510                const cfg_type_t *type, cfg_obj_t **ret)
511 {
512         isc_result_t result;
513
514         REQUIRE(filename != NULL);
515
516         CHECK(parser_openfile(pctx, filename));
517         CHECK(parse2(pctx, type, ret));
518  cleanup:
519         return (result);
520 }
521
522
523 isc_result_t
524 cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
525         const cfg_type_t *type, cfg_obj_t **ret)
526 {
527         isc_result_t result;
528         REQUIRE(buffer != NULL);
529         CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
530         CHECK(parse2(pctx, type, ret));
531  cleanup:
532         return (result);
533 }
534
535 void
536 cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) {
537         REQUIRE(src != NULL);
538         REQUIRE(dest != NULL && *dest == NULL);
539         isc_refcount_increment(&src->references, NULL);
540         *dest = src;
541 }
542
543 void
544 cfg_parser_destroy(cfg_parser_t **pctxp) {
545         cfg_parser_t *pctx = *pctxp;
546         unsigned int refs;
547
548         isc_refcount_decrement(&pctx->references, &refs);
549         if (refs == 0) {
550                 isc_lex_destroy(&pctx->lexer);
551                 /*
552                  * Cleaning up open_files does not
553                  * close the files; that was already done
554                  * by closing the lexer.
555                  */
556                 CLEANUP_OBJ(pctx->open_files);
557                 CLEANUP_OBJ(pctx->closed_files);
558                 isc_mem_put(pctx->mctx, pctx, sizeof(*pctx));
559         }
560         *pctxp = NULL;
561 }
562
563 /*
564  * void
565  */
566 isc_result_t
567 cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
568         UNUSED(type);
569         return (cfg_create_obj(pctx, &cfg_type_void, ret));
570 }
571
572 void
573 cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
574         UNUSED(pctx);
575         UNUSED(obj);
576 }
577
578 void
579 cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
580         UNUSED(pctx);
581         UNUSED(type);
582 }
583
584 isc_boolean_t
585 cfg_obj_isvoid(const cfg_obj_t *obj) {
586         REQUIRE(obj != NULL);
587         return (ISC_TF(obj->type->rep == &cfg_rep_void));
588 }
589
590 cfg_type_t cfg_type_void = {
591         "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
592         NULL };
593
594
595 /*
596  * uint32
597  */
598 isc_result_t
599 cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
600         isc_result_t result;
601         cfg_obj_t *obj = NULL;
602         UNUSED(type);
603
604         CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
605         if (pctx->token.type != isc_tokentype_number) {
606                 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
607                 return (ISC_R_UNEXPECTEDTOKEN);
608         }
609
610         CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
611
612         obj->value.uint32 = pctx->token.value.as_ulong;
613         *ret = obj;
614  cleanup:
615         return (result);
616 }
617
618 void
619 cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
620         cfg_print_chars(pctx, s, strlen(s));
621 }
622
623 void
624 cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
625         char buf[32];
626         snprintf(buf, sizeof(buf), "%u", u);
627         cfg_print_cstr(pctx, buf);
628 }
629
630 void
631 cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
632         cfg_print_rawuint(pctx, obj->value.uint32);
633 }
634
635 isc_boolean_t
636 cfg_obj_isuint32(const cfg_obj_t *obj) {
637         REQUIRE(obj != NULL);
638         return (ISC_TF(obj->type->rep == &cfg_rep_uint32));
639 }
640
641 isc_uint32_t
642 cfg_obj_asuint32(const cfg_obj_t *obj) {
643         REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
644         return (obj->value.uint32);
645 }
646
647 cfg_type_t cfg_type_uint32 = {
648         "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal,
649         &cfg_rep_uint32, NULL
650 };
651
652
653 /*
654  * uint64
655  */
656 isc_boolean_t
657 cfg_obj_isuint64(const cfg_obj_t *obj) {
658         REQUIRE(obj != NULL);
659         return (ISC_TF(obj->type->rep == &cfg_rep_uint64));
660 }
661
662 isc_uint64_t
663 cfg_obj_asuint64(const cfg_obj_t *obj) {
664         REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
665         return (obj->value.uint64);
666 }
667
668 void
669 cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
670         char buf[32];
671         snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u",
672                  obj->value.uint64);
673         cfg_print_cstr(pctx, buf);
674 }
675
676 cfg_type_t cfg_type_uint64 = {
677         "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal,
678         &cfg_rep_uint64, NULL
679 };
680
681 /*
682  * qstring (quoted string), ustring (unquoted string), astring
683  * (any string)
684  */
685
686 /* Create a string object from a null-terminated C string. */
687 static isc_result_t
688 create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
689               cfg_obj_t **ret)
690 {
691         isc_result_t result;
692         cfg_obj_t *obj = NULL;
693         int len;
694
695         CHECK(cfg_create_obj(pctx, type, &obj));
696         len = strlen(contents);
697         obj->value.string.length = len;
698         obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
699         if (obj->value.string.base == 0) {
700                 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
701                 return (ISC_R_NOMEMORY);
702         }
703         memcpy(obj->value.string.base, contents, len);
704         obj->value.string.base[len] = '\0';
705
706         *ret = obj;
707  cleanup:
708         return (result);
709 }
710
711 isc_result_t
712 cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
713         isc_result_t result;
714         UNUSED(type);
715
716         CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
717         if (pctx->token.type != isc_tokentype_qstring) {
718                 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
719                 return (ISC_R_UNEXPECTEDTOKEN);
720         }
721         return (create_string(pctx,
722                               TOKEN_STRING(pctx),
723                               &cfg_type_qstring,
724                               ret));
725  cleanup:
726         return (result);
727 }
728
729 static isc_result_t
730 parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
731         isc_result_t result;
732         UNUSED(type);
733
734         CHECK(cfg_gettoken(pctx, 0));
735         if (pctx->token.type != isc_tokentype_string) {
736                 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string");
737                 return (ISC_R_UNEXPECTEDTOKEN);
738         }
739         return (create_string(pctx,
740                               TOKEN_STRING(pctx),
741                               &cfg_type_ustring,
742                               ret));
743  cleanup:
744         return (result);
745 }
746
747 isc_result_t
748 cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type,
749                   cfg_obj_t **ret)
750 {
751         isc_result_t result;
752         UNUSED(type);
753
754         CHECK(cfg_getstringtoken(pctx));
755         return (create_string(pctx,
756                               TOKEN_STRING(pctx),
757                               &cfg_type_qstring,
758                               ret));
759  cleanup:
760         return (result);
761 }
762
763 isc_boolean_t
764 cfg_is_enum(const char *s, const char *const *enums) {
765         const char * const *p;
766         for (p = enums; *p != NULL; p++) {
767                 if (strcasecmp(*p, s) == 0)
768                         return (ISC_TRUE);
769         }
770         return (ISC_FALSE);
771 }
772
773 static isc_result_t
774 check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
775         const char *s = obj->value.string.base;
776         if (cfg_is_enum(s, enums))
777                 return (ISC_R_SUCCESS);
778         cfg_parser_error(pctx, 0, "'%s' unexpected", s);
779         return (ISC_R_UNEXPECTEDTOKEN);
780 }
781
782 isc_result_t
783 cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
784         isc_result_t result;
785         cfg_obj_t *obj = NULL;
786         CHECK(parse_ustring(pctx, NULL, &obj));
787         CHECK(check_enum(pctx, obj, type->of));
788         *ret = obj;
789         return (ISC_R_SUCCESS);
790  cleanup:
791         CLEANUP_OBJ(obj);
792         return (result);
793 }
794
795 void
796 cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
797         const char * const *p;
798         cfg_print_chars(pctx, "( ", 2);
799         for (p = type->of; *p != NULL; p++) {
800                 cfg_print_cstr(pctx, *p);
801                 if (p[1] != NULL)
802                         cfg_print_chars(pctx, " | ", 3);
803         }
804         cfg_print_chars(pctx, " )", 2);
805 }
806
807 void
808 cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
809         cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
810 }
811
812 static void
813 print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
814         cfg_print_chars(pctx, "\"", 1);
815         cfg_print_ustring(pctx, obj);
816         cfg_print_chars(pctx, "\"", 1);
817 }
818
819 static void
820 free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
821         isc_mem_put(pctx->mctx, obj->value.string.base,
822                     obj->value.string.length + 1);
823 }
824
825 isc_boolean_t
826 cfg_obj_isstring(const cfg_obj_t *obj) {
827         REQUIRE(obj != NULL);
828         return (ISC_TF(obj->type->rep == &cfg_rep_string));
829 }
830
831 const char *
832 cfg_obj_asstring(const cfg_obj_t *obj) {
833         REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
834         return (obj->value.string.base);
835 }
836
837 /* Quoted string only */
838 cfg_type_t cfg_type_qstring = {
839         "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal,
840         &cfg_rep_string, NULL
841 };
842
843 /* Unquoted string only */
844 cfg_type_t cfg_type_ustring = {
845         "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal,
846         &cfg_rep_string, NULL
847 };
848
849 /* Any string (quoted or unquoted); printed with quotes */
850 cfg_type_t cfg_type_astring = {
851         "string", cfg_parse_astring, print_qstring, cfg_doc_terminal,
852         &cfg_rep_string, NULL
853 };
854
855 /*
856  * Booleans
857  */
858
859 isc_boolean_t
860 cfg_obj_isboolean(const cfg_obj_t *obj) {
861         REQUIRE(obj != NULL);
862         return (ISC_TF(obj->type->rep == &cfg_rep_boolean));
863 }
864
865 isc_boolean_t
866 cfg_obj_asboolean(const cfg_obj_t *obj) {
867         REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
868         return (obj->value.boolean);
869 }
870
871 isc_result_t
872 cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
873 {
874         isc_result_t result;
875         isc_boolean_t value;
876         cfg_obj_t *obj = NULL;
877         UNUSED(type);
878
879         result = cfg_gettoken(pctx, 0);
880         if (result != ISC_R_SUCCESS)
881                 return (result);
882
883         if (pctx->token.type != isc_tokentype_string)
884                 goto bad_boolean;
885
886         if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
887             (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
888             (strcmp(TOKEN_STRING(pctx), "1") == 0)) {
889                 value = ISC_TRUE;
890         } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
891                    (strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
892                    (strcmp(TOKEN_STRING(pctx), "0") == 0)) {
893                 value = ISC_FALSE;
894         } else {
895                 goto bad_boolean;
896         }
897
898         CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
899         obj->value.boolean = value;
900         *ret = obj;
901         return (result);
902
903  bad_boolean:
904         cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
905         return (ISC_R_UNEXPECTEDTOKEN);
906
907  cleanup:
908         return (result);
909 }
910
911 void
912 cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
913         if (obj->value.boolean)
914                 cfg_print_chars(pctx, "yes", 3);
915         else
916                 cfg_print_chars(pctx, "no", 2);
917 }
918
919 cfg_type_t cfg_type_boolean = {
920         "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal,
921         &cfg_rep_boolean, NULL
922 };
923
924 /*
925  * Lists.
926  */
927
928 isc_result_t
929 cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
930         isc_result_t result;
931         CHECK(cfg_create_obj(pctx, type, obj));
932         ISC_LIST_INIT((*obj)->value.list);
933  cleanup:
934         return (result);
935 }
936
937 static isc_result_t
938 create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
939         cfg_listelt_t *elt;
940         elt = isc_mem_get(pctx->mctx, sizeof(*elt));
941         if (elt == NULL)
942                 return (ISC_R_NOMEMORY);
943         elt->obj = NULL;
944         ISC_LINK_INIT(elt, link);
945         *eltp = elt;
946         return (ISC_R_SUCCESS);
947 }
948
949 static void
950 free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
951         cfg_obj_destroy(pctx, &elt->obj);
952         isc_mem_put(pctx->mctx, elt, sizeof(*elt));
953 }
954
955 static void
956 free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
957         cfg_listelt_t *elt, *next;
958         for (elt = ISC_LIST_HEAD(obj->value.list);
959              elt != NULL;
960              elt = next)
961         {
962                 next = ISC_LIST_NEXT(elt, link);
963                 free_list_elt(pctx, elt);
964         }
965 }
966
967 isc_result_t
968 cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
969                   cfg_listelt_t **ret)
970 {
971         isc_result_t result;
972         cfg_listelt_t *elt = NULL;
973         cfg_obj_t *value = NULL;
974
975         CHECK(create_listelt(pctx, &elt));
976
977         result = cfg_parse_obj(pctx, elttype, &value);
978         if (result != ISC_R_SUCCESS)
979                 goto cleanup;
980
981         elt->obj = value;
982
983         *ret = elt;
984         return (ISC_R_SUCCESS);
985
986  cleanup:
987         isc_mem_put(pctx->mctx, elt, sizeof(*elt));
988         return (result);
989 }
990
991 /*
992  * Parse a homogeneous list whose elements are of type 'elttype'
993  * and where each element is terminated by a semicolon.
994  */
995 static isc_result_t
996 parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret)
997 {
998         cfg_obj_t *listobj = NULL;
999         const cfg_type_t *listof = listtype->of;
1000         isc_result_t result;
1001         cfg_listelt_t *elt = NULL;
1002
1003         CHECK(cfg_create_list(pctx, listtype, &listobj));
1004
1005         for (;;) {
1006                 CHECK(cfg_peektoken(pctx, 0));
1007                 if (pctx->token.type == isc_tokentype_special &&
1008                     pctx->token.value.as_char == /*{*/ '}')
1009                         break;
1010                 CHECK(cfg_parse_listelt(pctx, listof, &elt));
1011                 CHECK(parse_semicolon(pctx));
1012                 ISC_LIST_APPEND(listobj->value.list, elt, link);
1013                 elt = NULL;
1014         }
1015         *ret = listobj;
1016         return (ISC_R_SUCCESS);
1017
1018  cleanup:
1019         if (elt != NULL)
1020                 free_list_elt(pctx, elt);
1021         CLEANUP_OBJ(listobj);
1022         return (result);
1023 }
1024
1025 static void
1026 print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1027         const cfg_list_t *list = &obj->value.list;
1028         const cfg_listelt_t *elt;
1029
1030         for (elt = ISC_LIST_HEAD(*list);
1031              elt != NULL;
1032              elt = ISC_LIST_NEXT(elt, link)) {
1033                 print_indent(pctx);
1034                 cfg_print_obj(pctx, elt->obj);
1035                 cfg_print_chars(pctx, ";\n", 2);
1036         }
1037 }
1038
1039 isc_result_t
1040 cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
1041                      cfg_obj_t **ret)
1042 {
1043         isc_result_t result;
1044         CHECK(cfg_parse_special(pctx, '{'));
1045         CHECK(parse_list(pctx, type, ret));
1046         CHECK(cfg_parse_special(pctx, '}'));
1047  cleanup:
1048         return (result);
1049 }
1050
1051 void
1052 cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1053         print_open(pctx);
1054         print_list(pctx, obj);
1055         print_close(pctx);
1056 }
1057
1058 void
1059 cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
1060         cfg_print_chars(pctx, "{ ", 2);
1061         cfg_doc_obj(pctx, type->of);
1062         cfg_print_chars(pctx, "; ... }", 7);
1063 }
1064
1065 /*
1066  * Parse a homogeneous list whose elements are of type 'elttype'
1067  * and where elements are separated by space.  The list ends
1068  * before the first semicolon.
1069  */
1070 isc_result_t
1071 cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
1072                     cfg_obj_t **ret)
1073 {
1074         cfg_obj_t *listobj = NULL;
1075         const cfg_type_t *listof = listtype->of;
1076         isc_result_t result;
1077
1078         CHECK(cfg_create_list(pctx, listtype, &listobj));
1079
1080         for (;;) {
1081                 cfg_listelt_t *elt = NULL;
1082
1083                 CHECK(cfg_peektoken(pctx, 0));
1084                 if (pctx->token.type == isc_tokentype_special &&
1085                     pctx->token.value.as_char == ';')
1086                         break;
1087                 CHECK(cfg_parse_listelt(pctx, listof, &elt));
1088                 ISC_LIST_APPEND(listobj->value.list, elt, link);
1089         }
1090         *ret = listobj;
1091         return (ISC_R_SUCCESS);
1092
1093  cleanup:
1094         CLEANUP_OBJ(listobj);
1095         return (result);
1096 }
1097
1098 void
1099 cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1100         const cfg_list_t *list = &obj->value.list;
1101         const cfg_listelt_t *elt;
1102
1103         for (elt = ISC_LIST_HEAD(*list);
1104              elt != NULL;
1105              elt = ISC_LIST_NEXT(elt, link)) {
1106                 cfg_print_obj(pctx, elt->obj);
1107                 if (ISC_LIST_NEXT(elt, link) != NULL)
1108                         cfg_print_chars(pctx, " ", 1);
1109         }
1110 }
1111
1112 isc_boolean_t
1113 cfg_obj_islist(const cfg_obj_t *obj) {
1114         REQUIRE(obj != NULL);
1115         return (ISC_TF(obj->type->rep == &cfg_rep_list));
1116 }
1117
1118 const cfg_listelt_t *
1119 cfg_list_first(const cfg_obj_t *obj) {
1120         REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
1121         if (obj == NULL)
1122                 return (NULL);
1123         return (ISC_LIST_HEAD(obj->value.list));
1124 }
1125
1126 const cfg_listelt_t *
1127 cfg_list_next(const cfg_listelt_t *elt) {
1128         REQUIRE(elt != NULL);
1129         return (ISC_LIST_NEXT(elt, link));
1130 }
1131
1132 /*
1133  * Return the length of a list object.  If obj is NULL or is not
1134  * a list, return 0.
1135  */
1136 unsigned int
1137 cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) {
1138         const cfg_listelt_t *elt;
1139         unsigned int count = 0;
1140
1141         if (obj == NULL || !cfg_obj_islist(obj))
1142                 return (0U);
1143         for (elt = cfg_list_first(obj);
1144              elt != NULL;
1145              elt = cfg_list_next(elt)) {
1146                 if (recurse && cfg_obj_islist(elt->obj)) {
1147                         count += cfg_list_length(elt->obj, recurse);
1148                 } else {
1149                         count++;
1150                 }
1151         }
1152         return (count);
1153 }
1154
1155 cfg_obj_t *
1156 cfg_listelt_value(const cfg_listelt_t *elt) {
1157         REQUIRE(elt != NULL);
1158         return (elt->obj);
1159 }
1160
1161 /*
1162  * Maps.
1163  */
1164
1165 /*
1166  * Parse a map body.  That's something like
1167  *
1168  *   "foo 1; bar { glub; }; zap true; zap false;"
1169  *
1170  * i.e., a sequence of option names followed by values and
1171  * terminated by semicolons.  Used for the top level of
1172  * the named.conf syntax, as well as for the body of the
1173  * options, view, zone, and other statements.
1174  */
1175 isc_result_t
1176 cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
1177 {
1178         const cfg_clausedef_t * const *clausesets = type->of;
1179         isc_result_t result;
1180         const cfg_clausedef_t * const *clauseset;
1181         const cfg_clausedef_t *clause;
1182         cfg_obj_t *value = NULL;
1183         cfg_obj_t *obj = NULL;
1184         cfg_obj_t *eltobj = NULL;
1185         cfg_obj_t *includename = NULL;
1186         isc_symvalue_t symval;
1187         cfg_list_t *list = NULL;
1188
1189         CHECK(create_map(pctx, type, &obj));
1190
1191         obj->value.map.clausesets = clausesets;
1192
1193         for (;;) {
1194                 cfg_listelt_t *elt;
1195
1196         redo:
1197                 /*
1198                  * Parse the option name and see if it is known.
1199                  */
1200                 CHECK(cfg_gettoken(pctx, 0));
1201
1202                 if (pctx->token.type != isc_tokentype_string) {
1203                         cfg_ungettoken(pctx);
1204                         break;
1205                 }
1206
1207                 /*
1208                  * We accept "include" statements wherever a map body
1209                  * clause can occur.
1210                  */
1211                 if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
1212                         /*
1213                          * Turn the file name into a temporary configuration
1214                          * object just so that it is not overwritten by the
1215                          * semicolon token.
1216                          */
1217                         CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename));
1218                         CHECK(parse_semicolon(pctx));
1219                         CHECK(parser_openfile(pctx, includename->
1220                                               value.string.base));
1221                          cfg_obj_destroy(pctx, &includename);
1222                          goto redo;
1223                 }
1224
1225                 clause = NULL;
1226                 for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
1227                         for (clause = *clauseset;
1228                              clause->name != NULL;
1229                              clause++) {
1230                                 if (strcasecmp(TOKEN_STRING(pctx),
1231                                            clause->name) == 0)
1232                                         goto done;
1233                         }
1234                 }
1235         done:
1236                 if (clause == NULL || clause->name == NULL) {
1237                         cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option");
1238                         /*
1239                          * Try to recover by parsing this option as an unknown
1240                          * option and discarding it.
1241                          */
1242                         CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj));
1243                         cfg_obj_destroy(pctx, &eltobj);
1244                         CHECK(parse_semicolon(pctx));
1245                         continue;
1246                 }
1247
1248                 /* Clause is known. */
1249
1250                 /* Issue warnings if appropriate */
1251                 if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
1252                         cfg_parser_warning(pctx, 0, "option '%s' is obsolete",
1253                                        clause->name);
1254                 if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
1255                         cfg_parser_warning(pctx, 0, "option '%s' is "
1256                                        "not implemented", clause->name);
1257                 if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
1258                         cfg_parser_warning(pctx, 0, "option '%s' is "
1259                                        "not implemented", clause->name);
1260
1261                 if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) {
1262                         cfg_parser_warning(pctx, 0, "option '%s' is not "
1263                                            "configured", clause->name);
1264                         result = ISC_R_FAILURE;
1265                         goto cleanup;
1266                 }
1267
1268                 /*
1269                  * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
1270                  * set here - we need to log the *lack* of such an option,
1271                  * not its presence.
1272                  */
1273
1274                 /* See if the clause already has a value; if not create one. */
1275                 result = isc_symtab_lookup(obj->value.map.symtab,
1276                                            clause->name, 0, &symval);
1277
1278                 if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
1279                         /* Multivalued clause */
1280                         cfg_obj_t *listobj = NULL;
1281                         if (result == ISC_R_NOTFOUND) {
1282                                 CHECK(cfg_create_list(pctx,
1283                                                   &cfg_type_implicitlist,
1284                                                   &listobj));
1285                                 symval.as_pointer = listobj;
1286                                 result = isc_symtab_define(obj->value.
1287                                                    map.symtab,
1288                                                    clause->name,
1289                                                    1, symval,
1290                                                    isc_symexists_reject);
1291                                 if (result != ISC_R_SUCCESS) {
1292                                         cfg_parser_error(pctx, CFG_LOG_NEAR,
1293                                                      "isc_symtab_define(%s) "
1294                                                      "failed", clause->name);
1295                                         isc_mem_put(pctx->mctx, list,
1296                                                     sizeof(cfg_list_t));
1297                                         goto cleanup;
1298                                 }
1299                         } else {
1300                                 INSIST(result == ISC_R_SUCCESS);
1301                                 listobj = symval.as_pointer;
1302                         }
1303
1304                         elt = NULL;
1305                         CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
1306                         CHECK(parse_semicolon(pctx));
1307
1308                         ISC_LIST_APPEND(listobj->value.list, elt, link);
1309                 } else {
1310                         /* Single-valued clause */
1311                         if (result == ISC_R_NOTFOUND) {
1312                                 isc_boolean_t callback =
1313                                         ISC_TF((clause->flags &
1314                                                 CFG_CLAUSEFLAG_CALLBACK) != 0);
1315                                 CHECK(parse_symtab_elt(pctx, clause->name,
1316                                                        clause->type,
1317                                                        obj->value.map.symtab,
1318                                                        callback));
1319                                 CHECK(parse_semicolon(pctx));
1320                         } else if (result == ISC_R_SUCCESS) {
1321                                 cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined",
1322                                              clause->name);
1323                                 result = ISC_R_EXISTS;
1324                                 goto cleanup;
1325                         } else {
1326                                 cfg_parser_error(pctx, CFG_LOG_NEAR,
1327                                              "isc_symtab_define() failed");
1328                                 goto cleanup;
1329                         }
1330                 }
1331         }
1332
1333
1334         *ret = obj;
1335         return (ISC_R_SUCCESS);
1336
1337  cleanup:
1338         CLEANUP_OBJ(value);
1339         CLEANUP_OBJ(obj);
1340         CLEANUP_OBJ(eltobj);
1341         CLEANUP_OBJ(includename);
1342         return (result);
1343 }
1344
1345 static isc_result_t
1346 parse_symtab_elt(cfg_parser_t *pctx, const char *name,
1347                  cfg_type_t *elttype, isc_symtab_t *symtab,
1348                  isc_boolean_t callback)
1349 {
1350         isc_result_t result;
1351         cfg_obj_t *obj = NULL;
1352         isc_symvalue_t symval;
1353
1354         CHECK(cfg_parse_obj(pctx, elttype, &obj));
1355
1356         if (callback && pctx->callback != NULL)
1357                 CHECK(pctx->callback(name, obj, pctx->callbackarg));
1358
1359         symval.as_pointer = obj;
1360         CHECK(isc_symtab_define(symtab, name,
1361                                 1, symval,
1362                                 isc_symexists_reject));
1363         return (ISC_R_SUCCESS);
1364
1365  cleanup:
1366         CLEANUP_OBJ(obj);
1367         return (result);
1368 }
1369
1370 /*
1371  * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
1372  */
1373 isc_result_t
1374 cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1375         isc_result_t result;
1376         CHECK(cfg_parse_special(pctx, '{'));
1377         CHECK(cfg_parse_mapbody(pctx, type, ret));
1378         CHECK(cfg_parse_special(pctx, '}'));
1379  cleanup:
1380         return (result);
1381 }
1382
1383 /*
1384  * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
1385  */
1386 static isc_result_t
1387 parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type,
1388                     cfg_obj_t **ret)
1389 {
1390         isc_result_t result;
1391         cfg_obj_t *idobj = NULL;
1392         cfg_obj_t *mapobj = NULL;
1393
1394         CHECK(cfg_parse_obj(pctx, nametype, &idobj));
1395         CHECK(cfg_parse_map(pctx, type, &mapobj));
1396         mapobj->value.map.id = idobj;
1397         idobj = NULL;
1398         *ret = mapobj;
1399  cleanup:
1400         CLEANUP_OBJ(idobj);
1401         return (result);
1402 }
1403
1404 /*
1405  * Parse a map identified by a string name.  E.g., "name { foo 1; }".
1406  * Used for the "key" and "channel" statements.
1407  */
1408 isc_result_t
1409 cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1410         return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
1411 }
1412
1413 /*
1414  * Parse a map identified by a network address.
1415  * Used to be used for the "server" statement.
1416  */
1417 isc_result_t
1418 cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1419         return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
1420 }
1421
1422 /*
1423  * Parse a map identified by a network prefix.
1424  * Used for the "server" statement.
1425  */
1426 isc_result_t
1427 cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1428         return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
1429 }
1430
1431 void
1432 cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1433         isc_result_t result = ISC_R_SUCCESS;
1434
1435         const cfg_clausedef_t * const *clauseset;
1436
1437         for (clauseset = obj->value.map.clausesets;
1438              *clauseset != NULL;
1439              clauseset++)
1440         {
1441                 isc_symvalue_t symval;
1442                 const cfg_clausedef_t *clause;
1443
1444                 for (clause = *clauseset;
1445                      clause->name != NULL;
1446                      clause++) {
1447                         result = isc_symtab_lookup(obj->value.map.symtab,
1448                                                    clause->name, 0, &symval);
1449                         if (result == ISC_R_SUCCESS) {
1450                                 cfg_obj_t *obj = symval.as_pointer;
1451                                 if (obj->type == &cfg_type_implicitlist) {
1452                                         /* Multivalued. */
1453                                         cfg_list_t *list = &obj->value.list;
1454                                         cfg_listelt_t *elt;
1455                                         for (elt = ISC_LIST_HEAD(*list);
1456                                              elt != NULL;
1457                                              elt = ISC_LIST_NEXT(elt, link)) {
1458                                                 print_indent(pctx);
1459                                                 cfg_print_cstr(pctx, clause->name);
1460                                                 cfg_print_chars(pctx, " ", 1);
1461                                                 cfg_print_obj(pctx, elt->obj);
1462                                                 cfg_print_chars(pctx, ";\n", 2);
1463                                         }
1464                                 } else {
1465                                         /* Single-valued. */
1466                                         print_indent(pctx);
1467                                         cfg_print_cstr(pctx, clause->name);
1468                                         cfg_print_chars(pctx, " ", 1);
1469                                         cfg_print_obj(pctx, obj);
1470                                         cfg_print_chars(pctx, ";\n", 2);
1471                                 }
1472                         } else if (result == ISC_R_NOTFOUND) {
1473                                 ; /* do nothing */
1474                         } else {
1475                                 INSIST(0);
1476                         }
1477                 }
1478         }
1479 }
1480
1481 void
1482 cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
1483         const cfg_clausedef_t * const *clauseset;
1484         const cfg_clausedef_t *clause;
1485
1486         for (clauseset = type->of; *clauseset != NULL; clauseset++) {
1487                 for (clause = *clauseset;
1488                      clause->name != NULL;
1489                      clause++) {
1490                         cfg_print_cstr(pctx, clause->name);
1491                         cfg_print_chars(pctx, " ", 1);
1492                         cfg_doc_obj(pctx, clause->type);
1493                         cfg_print_chars(pctx, ";", 1);
1494                         /* XXX print flags here? */
1495                         cfg_print_chars(pctx, "\n\n", 2);
1496                 }
1497         }
1498 }
1499
1500 static struct flagtext {
1501         unsigned int flag;
1502         const char *text;
1503 } flagtexts[] = {
1504         { CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
1505         { CFG_CLAUSEFLAG_NYI, "not yet implemented" },
1506         { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
1507         { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
1508         { CFG_CLAUSEFLAG_TESTONLY, "test only" },
1509         { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" },
1510         { 0, NULL }
1511 };
1512
1513 void
1514 cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1515         if (obj->value.map.id != NULL) {
1516                 cfg_print_obj(pctx, obj->value.map.id);
1517                 cfg_print_chars(pctx, " ", 1);
1518         }
1519         print_open(pctx);
1520         cfg_print_mapbody(pctx, obj);
1521         print_close(pctx);
1522 }
1523
1524 static void
1525 print_clause_flags(cfg_printer_t *pctx, unsigned int flags) {
1526         struct flagtext *p;
1527         isc_boolean_t first = ISC_TRUE;
1528         for (p = flagtexts; p->flag != 0; p++) {
1529                 if ((flags & p->flag) != 0) {
1530                         if (first)
1531                                 cfg_print_chars(pctx, " // ", 4);
1532                         else
1533                                 cfg_print_chars(pctx, ", ", 2);
1534                         cfg_print_cstr(pctx, p->text);
1535                         first = ISC_FALSE;
1536                 }
1537         }
1538 }
1539
1540 void
1541 cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
1542         const cfg_clausedef_t * const *clauseset;
1543         const cfg_clausedef_t *clause;
1544
1545         if (type->parse == cfg_parse_named_map) {
1546                 cfg_doc_obj(pctx, &cfg_type_astring);
1547                 cfg_print_chars(pctx, " ", 1);
1548         } else if (type->parse == cfg_parse_addressed_map) {
1549                 cfg_doc_obj(pctx, &cfg_type_netaddr);
1550                 cfg_print_chars(pctx, " ", 1);
1551         } else if (type->parse == cfg_parse_netprefix_map) {
1552                 cfg_doc_obj(pctx, &cfg_type_netprefix);
1553                 cfg_print_chars(pctx, " ", 1);
1554         }
1555
1556         print_open(pctx);
1557
1558         for (clauseset = type->of; *clauseset != NULL; clauseset++) {
1559                 for (clause = *clauseset;
1560                      clause->name != NULL;
1561                      clause++) {
1562                         print_indent(pctx);
1563                         cfg_print_cstr(pctx, clause->name);
1564                         if (clause->type->print != cfg_print_void)
1565                                 cfg_print_chars(pctx, " ", 1);
1566                         cfg_doc_obj(pctx, clause->type);
1567                         cfg_print_chars(pctx, ";", 1);
1568                         print_clause_flags(pctx, clause->flags);
1569                         cfg_print_chars(pctx, "\n", 1);
1570                 }
1571         }
1572         print_close(pctx);
1573 }
1574
1575 isc_boolean_t
1576 cfg_obj_ismap(const cfg_obj_t *obj) {
1577         REQUIRE(obj != NULL);
1578         return (ISC_TF(obj->type->rep == &cfg_rep_map));
1579 }
1580
1581 isc_result_t
1582 cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) {
1583         isc_result_t result;
1584         isc_symvalue_t val;
1585         const cfg_map_t *map;
1586
1587         REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
1588         REQUIRE(name != NULL);
1589         REQUIRE(obj != NULL && *obj == NULL);
1590
1591         map = &mapobj->value.map;
1592
1593         result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
1594         if (result != ISC_R_SUCCESS)
1595                 return (result);
1596         *obj = val.as_pointer;
1597         return (ISC_R_SUCCESS);
1598 }
1599
1600 const cfg_obj_t *
1601 cfg_map_getname(const cfg_obj_t *mapobj) {
1602         REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
1603         return (mapobj->value.map.id);
1604 }
1605
1606
1607 /* Parse an arbitrary token, storing its raw text representation. */
1608 static isc_result_t
1609 parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1610         cfg_obj_t *obj = NULL;
1611         isc_result_t result;
1612         isc_region_t r;
1613
1614         UNUSED(type);
1615
1616         CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
1617         CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
1618         if (pctx->token.type == isc_tokentype_eof) {
1619                 cfg_ungettoken(pctx);
1620                 result = ISC_R_EOF;
1621                 goto cleanup;
1622         }
1623
1624         isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
1625
1626         obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
1627         if (obj->value.string.base == NULL) {
1628                 result = ISC_R_NOMEMORY;
1629                 goto cleanup;
1630         }
1631         obj->value.string.length = r.length;
1632         memcpy(obj->value.string.base, r.base, r.length);
1633         obj->value.string.base[r.length] = '\0';
1634         *ret = obj;
1635         return (result);
1636
1637  cleanup:
1638         if (obj != NULL)
1639                 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
1640         return (result);
1641 }
1642
1643 cfg_type_t cfg_type_token = {
1644         "token", parse_token, cfg_print_ustring, cfg_doc_terminal,
1645         &cfg_rep_string, NULL
1646 };
1647
1648 /*
1649  * An unsupported option.  This is just a list of tokens with balanced braces
1650  * ending in a semicolon.
1651  */
1652
1653 static isc_result_t
1654 parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1655         cfg_obj_t *listobj = NULL;
1656         isc_result_t result;
1657         int braces = 0;
1658
1659         CHECK(cfg_create_list(pctx, type, &listobj));
1660
1661         for (;;) {
1662                 cfg_listelt_t *elt = NULL;
1663
1664                 CHECK(cfg_peektoken(pctx, 0));
1665                 if (pctx->token.type == isc_tokentype_special) {
1666                         if (pctx->token.value.as_char == '{')
1667                                 braces++;
1668                         else if (pctx->token.value.as_char == '}')
1669                                 braces--;
1670                         else if (pctx->token.value.as_char == ';')
1671                                 if (braces == 0)
1672                                         break;
1673                 }
1674                 if (pctx->token.type == isc_tokentype_eof || braces < 0) {
1675                         cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token");
1676                         result = ISC_R_UNEXPECTEDTOKEN;
1677                         goto cleanup;
1678                 }
1679
1680                 CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
1681                 ISC_LIST_APPEND(listobj->value.list, elt, link);
1682         }
1683         INSIST(braces == 0);
1684         *ret = listobj;
1685         return (ISC_R_SUCCESS);
1686
1687  cleanup:
1688         CLEANUP_OBJ(listobj);
1689         return (result);
1690 }
1691
1692 cfg_type_t cfg_type_unsupported = {
1693         "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal,
1694         &cfg_rep_list, NULL
1695 };
1696
1697 /*
1698  * Try interpreting the current token as a network address.
1699  *
1700  * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard
1701  * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set.  The
1702  * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
1703  * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
1704  * and the IPv6 wildcard address otherwise.
1705  */
1706 static isc_result_t
1707 token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
1708         char *s;
1709         struct in_addr in4a;
1710         struct in6_addr in6a;
1711
1712         if (pctx->token.type != isc_tokentype_string)
1713                 return (ISC_R_UNEXPECTEDTOKEN);
1714
1715         s = TOKEN_STRING(pctx);
1716         if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
1717                 if ((flags & CFG_ADDR_V4OK) != 0) {
1718                         isc_netaddr_any(na);
1719                         return (ISC_R_SUCCESS);
1720                 } else if ((flags & CFG_ADDR_V6OK) != 0) {
1721                         isc_netaddr_any6(na);
1722                         return (ISC_R_SUCCESS);
1723                 } else {
1724                         INSIST(0);
1725                 }
1726         } else {
1727                 if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
1728                         if (inet_pton(AF_INET, s, &in4a) == 1) {
1729                                 isc_netaddr_fromin(na, &in4a);
1730                                 return (ISC_R_SUCCESS);
1731                         }
1732                 }
1733                 if ((flags & CFG_ADDR_V4PREFIXOK) != 0 &&
1734                     strlen(s) <= 15U) {
1735                         char buf[64];
1736                         int i;
1737
1738                         strcpy(buf, s);
1739                         for (i = 0; i < 3; i++) {
1740                                 strcat(buf, ".0");
1741                                 if (inet_pton(AF_INET, buf, &in4a) == 1) {
1742                                         isc_netaddr_fromin(na, &in4a);
1743                                         return (ISC_R_SUCCESS);
1744                                 }
1745                         }
1746                 }
1747                 if ((flags & CFG_ADDR_V6OK) != 0 &&
1748                     strlen(s) <= 127U) {
1749                         char buf[128]; /* see lib/bind9/getaddresses.c */
1750                         char *d; /* zone delimiter */
1751                         isc_uint32_t zone = 0; /* scope zone ID */
1752
1753                         strcpy(buf, s);
1754                         d = strchr(buf, '%');
1755                         if (d != NULL)
1756                                 *d = '\0';
1757
1758                         if (inet_pton(AF_INET6, buf, &in6a) == 1) {
1759                                 if (d != NULL) {
1760 #ifdef ISC_PLATFORM_HAVESCOPEID
1761                                         isc_result_t result;
1762
1763                                         result = isc_netscope_pton(AF_INET6,
1764                                                                    d + 1,
1765                                                                    &in6a,
1766                                                                    &zone);
1767                                         if (result != ISC_R_SUCCESS)
1768                                                 return (result);
1769 #else
1770                                 return (ISC_R_BADADDRESSFORM);
1771 #endif
1772                                 }
1773
1774                                 isc_netaddr_fromin6(na, &in6a);
1775                                 isc_netaddr_setzone(na, zone);
1776                                 return (ISC_R_SUCCESS);
1777                         }
1778                 }
1779         }
1780         return (ISC_R_UNEXPECTEDTOKEN);
1781 }
1782
1783 isc_result_t
1784 cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
1785         isc_result_t result;
1786         const char *wild = "";
1787         const char *prefix = "";
1788
1789         CHECK(cfg_gettoken(pctx, 0));
1790         result = token_addr(pctx, flags, na);
1791         if (result == ISC_R_UNEXPECTEDTOKEN) {
1792                 if ((flags & CFG_ADDR_WILDOK) != 0)
1793                         wild = " or '*'";
1794                 if ((flags & CFG_ADDR_V4PREFIXOK) != 0)
1795                         wild = " or IPv4 prefix";
1796                 if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK)
1797                         cfg_parser_error(pctx, CFG_LOG_NEAR,
1798                                          "expected IPv4 address%s%s",
1799                                          prefix, wild);
1800                 else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK)
1801                         cfg_parser_error(pctx, CFG_LOG_NEAR,
1802                                          "expected IPv6 address%s%s",
1803                                          prefix, wild);
1804                 else
1805                         cfg_parser_error(pctx, CFG_LOG_NEAR,
1806                                          "expected IP address%s%s",
1807                                          prefix, wild);
1808         }
1809  cleanup:
1810         return (result);
1811 }
1812
1813 isc_boolean_t
1814 cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
1815         isc_result_t result;
1816         isc_netaddr_t na_dummy;
1817         result = token_addr(pctx, flags, &na_dummy);
1818         return (ISC_TF(result == ISC_R_SUCCESS));
1819 }
1820
1821 isc_result_t
1822 cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
1823         isc_result_t result;
1824
1825         CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
1826
1827         if ((flags & CFG_ADDR_WILDOK) != 0 &&
1828             pctx->token.type == isc_tokentype_string &&
1829             strcmp(TOKEN_STRING(pctx), "*") == 0) {
1830                 *port = 0;
1831                 return (ISC_R_SUCCESS);
1832         }
1833         if (pctx->token.type != isc_tokentype_number) {
1834                 cfg_parser_error(pctx, CFG_LOG_NEAR,
1835                              "expected port number or '*'");
1836                 return (ISC_R_UNEXPECTEDTOKEN);
1837         }
1838         if (pctx->token.value.as_ulong >= 65536U) {
1839                 cfg_parser_error(pctx, CFG_LOG_NEAR,
1840                              "port number out of range");
1841                 return (ISC_R_UNEXPECTEDTOKEN);
1842         }
1843         *port = (in_port_t)(pctx->token.value.as_ulong);
1844         return (ISC_R_SUCCESS);
1845  cleanup:
1846         return (result);
1847 }
1848
1849 void
1850 cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
1851         isc_result_t result;
1852         char text[128];
1853         isc_buffer_t buf;
1854
1855         isc_buffer_init(&buf, text, sizeof(text));
1856         result = isc_netaddr_totext(na, &buf);
1857         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1858         cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf));
1859 }
1860
1861 /* netaddr */
1862
1863 static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
1864 static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
1865 static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
1866 static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
1867 static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
1868
1869 static isc_result_t
1870 parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
1871         isc_result_t result;
1872         cfg_obj_t *obj = NULL;
1873         isc_netaddr_t netaddr;
1874         unsigned int flags = *(const unsigned int *)type->of;
1875
1876         CHECK(cfg_create_obj(pctx, type, &obj));
1877         CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
1878         isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
1879         *ret = obj;
1880         return (ISC_R_SUCCESS);
1881  cleanup:
1882         CLEANUP_OBJ(obj);
1883         return (result);
1884 }
1885
1886 static void
1887 cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
1888         const unsigned int *flagp = type->of;
1889         int n = 0;
1890         if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
1891                 cfg_print_chars(pctx, "( ", 2);
1892         if (*flagp & CFG_ADDR_V4OK) {
1893                 cfg_print_cstr(pctx, "<ipv4_address>");
1894                 n++;
1895         }
1896         if (*flagp & CFG_ADDR_V6OK) {
1897                 if (n != 0)
1898                         cfg_print_chars(pctx, " | ", 3);
1899                 cfg_print_cstr(pctx, "<ipv6_address>");
1900                 n++;
1901         }
1902         if (*flagp & CFG_ADDR_WILDOK) {
1903                 if (n != 0)
1904                         cfg_print_chars(pctx, " | ", 3);
1905                 cfg_print_chars(pctx, "*", 1);
1906                 n++;
1907                 POST(n);
1908         }
1909         if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
1910                 cfg_print_chars(pctx, " )", 2);
1911 }
1912
1913 cfg_type_t cfg_type_netaddr = {
1914         "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1915         &cfg_rep_sockaddr, &netaddr_flags
1916 };
1917
1918 cfg_type_t cfg_type_netaddr4 = {
1919         "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1920         &cfg_rep_sockaddr, &netaddr4_flags
1921 };
1922
1923 cfg_type_t cfg_type_netaddr4wild = {
1924         "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1925         &cfg_rep_sockaddr, &netaddr4wild_flags
1926 };
1927
1928 cfg_type_t cfg_type_netaddr6 = {
1929         "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1930         &cfg_rep_sockaddr, &netaddr6_flags
1931 };
1932
1933 cfg_type_t cfg_type_netaddr6wild = {
1934         "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
1935         &cfg_rep_sockaddr, &netaddr6wild_flags
1936 };
1937
1938 /* netprefix */
1939
1940 isc_result_t
1941 cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
1942                     cfg_obj_t **ret)
1943 {
1944         cfg_obj_t *obj = NULL;
1945         isc_result_t result;
1946         isc_netaddr_t netaddr;
1947         unsigned int addrlen = 0, prefixlen;
1948         UNUSED(type);
1949
1950         CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
1951                                 CFG_ADDR_V6OK, &netaddr));
1952         switch (netaddr.family) {
1953         case AF_INET:
1954                 addrlen = 32;
1955                 break;
1956         case AF_INET6:
1957                 addrlen = 128;
1958                 break;
1959         default:
1960                 INSIST(0);
1961                 break;
1962         }
1963         CHECK(cfg_peektoken(pctx, 0));
1964         if (pctx->token.type == isc_tokentype_special &&
1965             pctx->token.value.as_char == '/') {
1966                 CHECK(cfg_gettoken(pctx, 0)); /* read "/" */
1967                 CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
1968                 if (pctx->token.type != isc_tokentype_number) {
1969                         cfg_parser_error(pctx, CFG_LOG_NEAR,
1970                                      "expected prefix length");
1971                         return (ISC_R_UNEXPECTEDTOKEN);
1972                 }
1973                 prefixlen = pctx->token.value.as_ulong;
1974                 if (prefixlen > addrlen) {
1975                         cfg_parser_error(pctx, CFG_LOG_NOPREP,
1976                                      "invalid prefix length");
1977                         return (ISC_R_RANGE);
1978                 }
1979         } else {
1980                 prefixlen = addrlen;
1981         }
1982         CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
1983         obj->value.netprefix.address = netaddr;
1984         obj->value.netprefix.prefixlen = prefixlen;
1985         *ret = obj;
1986         return (ISC_R_SUCCESS);
1987  cleanup:
1988         cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
1989         return (result);
1990 }
1991
1992 static void
1993 print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
1994         const cfg_netprefix_t *p = &obj->value.netprefix;
1995
1996         cfg_print_rawaddr(pctx, &p->address);
1997         cfg_print_chars(pctx, "/", 1);
1998         cfg_print_rawuint(pctx, p->prefixlen);
1999 }
2000
2001 isc_boolean_t
2002 cfg_obj_isnetprefix(const cfg_obj_t *obj) {
2003         REQUIRE(obj != NULL);
2004         return (ISC_TF(obj->type->rep == &cfg_rep_netprefix));
2005 }
2006
2007 void
2008 cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
2009                     unsigned int *prefixlen)
2010 {
2011         REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
2012         REQUIRE(netaddr != NULL);
2013         REQUIRE(prefixlen != NULL);
2014
2015         *netaddr = obj->value.netprefix.address;
2016         *prefixlen = obj->value.netprefix.prefixlen;
2017 }
2018
2019 cfg_type_t cfg_type_netprefix = {
2020         "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal,
2021         &cfg_rep_netprefix, NULL
2022 };
2023
2024 static isc_result_t
2025 parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type,
2026                   int flags, cfg_obj_t **ret)
2027 {
2028         isc_result_t result;
2029         isc_netaddr_t netaddr;
2030         in_port_t port = 0;
2031         cfg_obj_t *obj = NULL;
2032
2033         CHECK(cfg_create_obj(pctx, type, &obj));
2034         CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
2035         CHECK(cfg_peektoken(pctx, 0));
2036         if (pctx->token.type == isc_tokentype_string &&
2037             strcasecmp(TOKEN_STRING(pctx), "port") == 0) {
2038                 CHECK(cfg_gettoken(pctx, 0)); /* read "port" */
2039                 CHECK(cfg_parse_rawport(pctx, flags, &port));
2040         }
2041         isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
2042         *ret = obj;
2043         return (ISC_R_SUCCESS);
2044
2045  cleanup:
2046         CLEANUP_OBJ(obj);
2047         return (result);
2048 }
2049
2050 static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
2051 cfg_type_t cfg_type_sockaddr = {
2052         "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
2053         &cfg_rep_sockaddr, &sockaddr_flags
2054 };
2055
2056 isc_result_t
2057 cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2058         const unsigned int *flagp = type->of;
2059         return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
2060 }
2061
2062 void
2063 cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
2064         isc_netaddr_t netaddr;
2065         in_port_t port;
2066         char buf[ISC_NETADDR_FORMATSIZE];
2067
2068         isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
2069         isc_netaddr_format(&netaddr, buf, sizeof(buf));
2070         cfg_print_cstr(pctx, buf);
2071         port = isc_sockaddr_getport(&obj->value.sockaddr);
2072         if (port != 0) {
2073                 cfg_print_chars(pctx, " port ", 6);
2074                 cfg_print_rawuint(pctx, port);
2075         }
2076 }
2077
2078 void
2079 cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
2080         const unsigned int *flagp = type->of;
2081         int n = 0;
2082         cfg_print_chars(pctx, "( ", 2);
2083         if (*flagp & CFG_ADDR_V4OK) {
2084                 cfg_print_cstr(pctx, "<ipv4_address>");
2085                 n++;
2086         }
2087         if (*flagp & CFG_ADDR_V6OK) {
2088                 if (n != 0)
2089                         cfg_print_chars(pctx, " | ", 3);
2090                 cfg_print_cstr(pctx, "<ipv6_address>");
2091                 n++;
2092         }
2093         if (*flagp & CFG_ADDR_WILDOK) {
2094                 if (n != 0)
2095                         cfg_print_chars(pctx, " | ", 3);
2096                 cfg_print_chars(pctx, "*", 1);
2097                 n++;
2098                 POST(n);
2099         }
2100         cfg_print_chars(pctx, " ) ", 3);
2101         if (*flagp & CFG_ADDR_WILDOK) {
2102                 cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
2103         } else {
2104                 cfg_print_cstr(pctx, "[ port <integer> ]");
2105         }
2106 }
2107
2108 isc_boolean_t
2109 cfg_obj_issockaddr(const cfg_obj_t *obj) {
2110         REQUIRE(obj != NULL);
2111         return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr));
2112 }
2113
2114 const isc_sockaddr_t *
2115 cfg_obj_assockaddr(const cfg_obj_t *obj) {
2116         REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
2117         return (&obj->value.sockaddr);
2118 }
2119
2120 isc_result_t
2121 cfg_gettoken(cfg_parser_t *pctx, int options) {
2122         isc_result_t result;
2123
2124         if (pctx->seen_eof)
2125                 return (ISC_R_SUCCESS);
2126
2127         options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
2128
2129  redo:
2130         pctx->token.type = isc_tokentype_unknown;
2131         result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
2132         pctx->ungotten = ISC_FALSE;
2133         pctx->line = isc_lex_getsourceline(pctx->lexer);
2134
2135         switch (result) {
2136         case ISC_R_SUCCESS:
2137                 if (pctx->token.type == isc_tokentype_eof) {
2138                         result = isc_lex_close(pctx->lexer);
2139                         INSIST(result == ISC_R_NOMORE ||
2140                                result == ISC_R_SUCCESS);
2141
2142                         if (isc_lex_getsourcename(pctx->lexer) != NULL) {
2143                                 /*
2144                                  * Closed an included file, not the main file.
2145                                  */
2146                                 cfg_listelt_t *elt;
2147                                 elt = ISC_LIST_TAIL(pctx->open_files->
2148                                                     value.list);
2149                                 INSIST(elt != NULL);
2150                                 ISC_LIST_UNLINK(pctx->open_files->
2151                                                 value.list, elt, link);
2152                                 ISC_LIST_APPEND(pctx->closed_files->
2153                                                 value.list, elt, link);
2154                                 goto redo;
2155                         }
2156                         pctx->seen_eof = ISC_TRUE;
2157                 }
2158                 break;
2159
2160         case ISC_R_NOSPACE:
2161                 /* More understandable than "ran out of space". */
2162                 cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
2163                 break;
2164
2165         case ISC_R_IOERROR:
2166                 cfg_parser_error(pctx, 0, "%s",
2167                                  isc_result_totext(result));
2168                 break;
2169
2170         default:
2171                 cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
2172                                  isc_result_totext(result));
2173                 break;
2174         }
2175         return (result);
2176 }
2177
2178 void
2179 cfg_ungettoken(cfg_parser_t *pctx) {
2180         if (pctx->seen_eof)
2181                 return;
2182         isc_lex_ungettoken(pctx->lexer, &pctx->token);
2183         pctx->ungotten = ISC_TRUE;
2184 }
2185
2186 isc_result_t
2187 cfg_peektoken(cfg_parser_t *pctx, int options) {
2188         isc_result_t result;
2189         CHECK(cfg_gettoken(pctx, options));
2190         cfg_ungettoken(pctx);
2191  cleanup:
2192         return (result);
2193 }
2194
2195 /*
2196  * Get a string token, accepting both the quoted and the unquoted form.
2197  * Log an error if the next token is not a string.
2198  */
2199 static isc_result_t
2200 cfg_getstringtoken(cfg_parser_t *pctx) {
2201         isc_result_t result;
2202
2203         result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
2204         if (result != ISC_R_SUCCESS)
2205                 return (result);
2206
2207         if (pctx->token.type != isc_tokentype_string &&
2208             pctx->token.type != isc_tokentype_qstring) {
2209                 cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
2210                 return (ISC_R_UNEXPECTEDTOKEN);
2211         }
2212         return (ISC_R_SUCCESS);
2213 }
2214
2215 void
2216 cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
2217         va_list args;
2218         va_start(args, fmt);
2219         parser_complain(pctx, ISC_FALSE, flags, fmt, args);
2220         va_end(args);
2221         pctx->errors++;
2222 }
2223
2224 void
2225 cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
2226         va_list args;
2227         va_start(args, fmt);
2228         parser_complain(pctx, ISC_TRUE, flags, fmt, args);
2229         va_end(args);
2230         pctx->warnings++;
2231 }
2232
2233 #define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
2234
2235 static isc_boolean_t
2236 have_current_file(cfg_parser_t *pctx) {
2237         cfg_listelt_t *elt;
2238         if (pctx->open_files == NULL)
2239                 return (ISC_FALSE);
2240
2241         elt = ISC_LIST_TAIL(pctx->open_files->value.list);
2242         if (elt == NULL)
2243               return (ISC_FALSE);
2244
2245         return (ISC_TRUE);
2246 }
2247
2248 static char *
2249 current_file(cfg_parser_t *pctx) {
2250         static char none[] = "none";
2251         cfg_listelt_t *elt;
2252         cfg_obj_t *fileobj;
2253
2254         if (!have_current_file(pctx))
2255                 return (none);
2256
2257         elt = ISC_LIST_TAIL(pctx->open_files->value.list);
2258         if (elt == NULL)        /* shouldn't be possible, but... */
2259               return (none);
2260
2261         fileobj = elt->obj;
2262         INSIST(fileobj->type == &cfg_type_qstring);
2263         return (fileobj->value.string.base);
2264 }
2265
2266 static void
2267 parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
2268                 unsigned int flags, const char *format,
2269                 va_list args)
2270 {
2271         char tokenbuf[MAX_LOG_TOKEN + 10];
2272         static char where[ISC_DIR_PATHMAX + 100];
2273         static char message[2048];
2274         int level = ISC_LOG_ERROR;
2275         const char *prep = "";
2276         size_t len;
2277
2278         if (is_warning)
2279                 level = ISC_LOG_WARNING;
2280
2281         where[0] = '\0';
2282         if (have_current_file(pctx))
2283                 snprintf(where, sizeof(where), "%s:%u: ",
2284                          current_file(pctx), pctx->line);
2285
2286         len = vsnprintf(message, sizeof(message), format, args);
2287         if (len >= sizeof(message))
2288                 FATAL_ERROR(__FILE__, __LINE__,
2289                             "error message would overflow");
2290
2291         if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) {
2292                 isc_region_t r;
2293
2294                 if (pctx->ungotten)
2295                         (void)cfg_gettoken(pctx, 0);
2296
2297                 if (pctx->token.type == isc_tokentype_eof) {
2298                         snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
2299                 } else if (pctx->token.type == isc_tokentype_unknown) {
2300                         flags = 0;
2301                         tokenbuf[0] = '\0';
2302                 } else {
2303                         isc_lex_getlasttokentext(pctx->lexer,
2304                                                  &pctx->token, &r);
2305                         if (r.length > MAX_LOG_TOKEN)
2306                                 snprintf(tokenbuf, sizeof(tokenbuf),
2307                                          "'%.*s...'", MAX_LOG_TOKEN, r.base);
2308                         else
2309                                 snprintf(tokenbuf, sizeof(tokenbuf),
2310                                          "'%.*s'", (int)r.length, r.base);
2311                 }
2312
2313                 /* Choose a preposition. */
2314                 if (flags & CFG_LOG_NEAR)
2315                         prep = " near ";
2316                 else if (flags & CFG_LOG_BEFORE)
2317                         prep = " before ";
2318                 else
2319                         prep = " ";
2320         } else {
2321                 tokenbuf[0] = '\0';
2322         }
2323         isc_log_write(pctx->lctx, CAT, MOD, level,
2324                       "%s%s%s%s", where, message, prep, tokenbuf);
2325 }
2326
2327 void
2328 cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
2329             const char *fmt, ...) {
2330         va_list ap;
2331         char msgbuf[2048];
2332
2333         if (! isc_log_wouldlog(lctx, level))
2334                 return;
2335
2336         va_start(ap, fmt);
2337
2338         vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
2339         isc_log_write(lctx, CAT, MOD, level,
2340                       "%s:%u: %s",
2341                       obj->file == NULL ? "<unknown file>" : obj->file,
2342                       obj->line, msgbuf);
2343         va_end(ap);
2344 }
2345
2346 const char *
2347 cfg_obj_file(const cfg_obj_t *obj) {
2348         return (obj->file);
2349 }
2350
2351 unsigned int
2352 cfg_obj_line(const cfg_obj_t *obj) {
2353         return (obj->line);
2354 }
2355
2356 isc_result_t
2357 cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2358         isc_result_t result;
2359         cfg_obj_t *obj;
2360
2361         obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
2362         if (obj == NULL)
2363                 return (ISC_R_NOMEMORY);
2364         obj->type = type;
2365         obj->file = current_file(pctx);
2366         obj->line = pctx->line;
2367         result = isc_refcount_init(&obj->references, 1);
2368         if (result != ISC_R_SUCCESS) {
2369                 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
2370                 return (result);
2371         }
2372         *ret = obj;
2373         return (ISC_R_SUCCESS);
2374 }
2375
2376
2377 static void
2378 map_symtabitem_destroy(char *key, unsigned int type,
2379                        isc_symvalue_t symval, void *userarg)
2380 {
2381         cfg_obj_t *obj = symval.as_pointer;
2382         cfg_parser_t *pctx = (cfg_parser_t *)userarg;
2383
2384         UNUSED(key);
2385         UNUSED(type);
2386
2387         cfg_obj_destroy(pctx, &obj);
2388 }
2389
2390
2391 static isc_result_t
2392 create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
2393         isc_result_t result;
2394         isc_symtab_t *symtab = NULL;
2395         cfg_obj_t *obj = NULL;
2396
2397         CHECK(cfg_create_obj(pctx, type, &obj));
2398         CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */
2399                                 map_symtabitem_destroy,
2400                                 pctx, ISC_FALSE, &symtab));
2401         obj->value.map.symtab = symtab;
2402         obj->value.map.id = NULL;
2403
2404         *ret = obj;
2405         return (ISC_R_SUCCESS);
2406
2407  cleanup:
2408         if (obj != NULL)
2409                 isc_mem_put(pctx->mctx, obj, sizeof(*obj));
2410         return (result);
2411 }
2412
2413 static void
2414 free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
2415         CLEANUP_OBJ(obj->value.map.id);
2416         isc_symtab_destroy(&obj->value.map.symtab);
2417 }
2418
2419 isc_boolean_t
2420 cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
2421         return (ISC_TF(obj->type == type));
2422 }
2423
2424 /*
2425  * Destroy 'obj', a configuration object created in 'pctx'.
2426  */
2427 void
2428 cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
2429         cfg_obj_t *obj = *objp;
2430         unsigned int refs;
2431
2432         isc_refcount_decrement(&obj->references, &refs);
2433         if (refs == 0) {
2434                 obj->type->rep->free(pctx, obj);
2435                 isc_refcount_destroy(&obj->references);
2436                 isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
2437         }
2438         *objp = NULL;
2439 }
2440
2441 void
2442 cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) {
2443     REQUIRE(src != NULL);
2444     REQUIRE(dest != NULL && *dest == NULL);
2445     isc_refcount_increment(&src->references, NULL);
2446     *dest = src;
2447 }
2448
2449 static void
2450 free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
2451         UNUSED(pctx);
2452         UNUSED(obj);
2453 }
2454
2455 void
2456 cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
2457         type->doc(pctx, type);
2458 }
2459
2460 void
2461 cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
2462         cfg_print_chars(pctx, "<", 1);
2463         cfg_print_cstr(pctx, type->name);
2464         cfg_print_chars(pctx, ">", 1);
2465 }
2466
2467 void
2468 cfg_print_grammar(const cfg_type_t *type,
2469         void (*f)(void *closure, const char *text, int textlen),
2470         void *closure)
2471 {
2472         cfg_printer_t pctx;
2473         pctx.f = f;
2474         pctx.closure = closure;
2475         pctx.indent = 0;
2476         cfg_doc_obj(&pctx, type);
2477 }