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