]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/dns/master.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / dns / master.c
1 /*
2  * Copyright (C) 2004-2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-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/event.h>
25 #include <isc/lex.h>
26 #include <isc/magic.h>
27 #include <isc/mem.h>
28 #include <isc/print.h>
29 #include <isc/serial.h>
30 #include <isc/stdio.h>
31 #include <isc/stdtime.h>
32 #include <isc/string.h>
33 #include <isc/task.h>
34 #include <isc/util.h>
35
36 #include <dns/callbacks.h>
37 #include <dns/events.h>
38 #include <dns/fixedname.h>
39 #include <dns/master.h>
40 #include <dns/name.h>
41 #include <dns/rdata.h>
42 #include <dns/rdataclass.h>
43 #include <dns/rdatalist.h>
44 #include <dns/rdataset.h>
45 #include <dns/rdatastruct.h>
46 #include <dns/rdatatype.h>
47 #include <dns/result.h>
48 #include <dns/soa.h>
49 #include <dns/time.h>
50 #include <dns/ttl.h>
51
52 /*!
53  * Grow the number of dns_rdatalist_t (#RDLSZ) and dns_rdata_t (#RDSZ) structures
54  * by these sizes when we need to.
55  *
56  */
57 /*% RDLSZ reflects the number of different types with the same name expected. */
58 #define RDLSZ 32
59 /*%
60  * RDSZ reflects the number of rdata expected at a give name that can fit into
61  * 64k.
62  */
63 #define RDSZ 512
64
65 #define NBUFS 4
66 #define MAXWIRESZ 255
67
68 /*%
69  * Target buffer size and minimum target size.
70  * MINTSIZ must be big enough to hold the largest rdata record.
71  * \brief
72  * TSIZ >= MINTSIZ
73  */
74 #define TSIZ (128*1024)
75 /*%
76  * max message size - header - root - type - class - ttl - rdlen
77  */
78 #define MINTSIZ DNS_RDATA_MAXLENGTH
79 /*%
80  * Size for tokens in the presentation format,
81  * The largest tokens are the base64 blocks in KEY and CERT records,
82  * Largest key allowed is about 1372 bytes but
83  * there is no fixed upper bound on CERT records.
84  * 2K is too small for some X.509s, 8K is overkill.
85  */
86 #define TOKENSIZ (8*1024)
87
88 /*%
89  * Buffers sizes for $GENERATE.
90  */
91 #define DNS_MASTER_LHS 2048
92 #define DNS_MASTER_RHS MINTSIZ
93
94 typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
95
96 typedef struct dns_incctx dns_incctx_t;
97
98 /*%
99  * Master file load state.
100  */
101
102 struct dns_loadctx {
103         unsigned int            magic;
104         isc_mem_t               *mctx;
105         dns_masterformat_t      format;
106
107         dns_rdatacallbacks_t    *callbacks;
108         isc_task_t              *task;
109         dns_loaddonefunc_t      done;
110         void                    *done_arg;
111
112         /* Common methods */
113         isc_result_t            (*openfile)(dns_loadctx_t *lctx,
114                                             const char *filename);
115         isc_result_t            (*load)(dns_loadctx_t *lctx);
116
117         /* Members specific to the text format: */
118         isc_lex_t               *lex;
119         isc_boolean_t           keep_lex;
120         unsigned int            options;
121         isc_boolean_t           ttl_known;
122         isc_boolean_t           default_ttl_known;
123         isc_boolean_t           warn_1035;
124         isc_boolean_t           warn_tcr;
125         isc_boolean_t           warn_sigexpired;
126         isc_boolean_t           seen_include;
127         isc_uint32_t            ttl;
128         isc_uint32_t            default_ttl;
129         dns_rdataclass_t        zclass;
130         dns_fixedname_t         fixed_top;
131         dns_name_t              *top;                   /*%< top of zone */
132
133         /* Members specific to the raw format: */
134         FILE                    *f;
135         isc_boolean_t           first;
136
137         /* Which fixed buffers we are using? */
138         unsigned int            loop_cnt;               /*% records per quantum,
139                                                          * 0 => all. */
140         isc_boolean_t           canceled;
141         isc_mutex_t             lock;
142         isc_result_t            result;
143         /* locked by lock */
144         isc_uint32_t            references;
145         dns_incctx_t            *inc;
146         isc_uint32_t            resign;
147 };
148
149 struct dns_incctx {
150         dns_incctx_t            *parent;
151         dns_name_t              *origin;
152         dns_name_t              *current;
153         dns_name_t              *glue;
154         dns_fixedname_t         fixed[NBUFS];           /* working buffers */
155         unsigned int            in_use[NBUFS];          /* covert to bitmap? */
156         int                     glue_in_use;
157         int                     current_in_use;
158         int                     origin_in_use;
159         isc_boolean_t           drop;
160         unsigned int            glue_line;
161         unsigned int            current_line;
162 };
163
164 #define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x')
165 #define DNS_LCTX_VALID(lctx) ISC_MAGIC_VALID(lctx, DNS_LCTX_MAGIC)
166
167 #define DNS_AS_STR(t) ((t).value.as_textregion.base)
168
169 static isc_result_t
170 openfile_text(dns_loadctx_t *lctx, const char *master_file);
171
172 static isc_result_t
173 openfile_raw(dns_loadctx_t *lctx, const char *master_file);
174
175 static isc_result_t
176 load_text(dns_loadctx_t *lctx);
177
178 static isc_result_t
179 load_raw(dns_loadctx_t *lctx);
180
181 static isc_result_t
182 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx);
183
184 static isc_result_t
185 commit(dns_rdatacallbacks_t *, dns_loadctx_t *, rdatalist_head_t *,
186        dns_name_t *, const char *, unsigned int);
187
188 static isc_boolean_t
189 is_glue(rdatalist_head_t *, dns_name_t *);
190
191 static dns_rdatalist_t *
192 grow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *,
193                 rdatalist_head_t *, isc_mem_t *mctx);
194
195 static dns_rdata_t *
196 grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
197            isc_mem_t *);
198
199 static void
200 load_quantum(isc_task_t *task, isc_event_t *event);
201
202 static isc_result_t
203 task_send(dns_loadctx_t *lctx);
204
205 static void
206 loadctx_destroy(dns_loadctx_t *lctx);
207
208 #define GETTOKEN(lexer, options, token, eol) \
209         do { \
210                 result = gettoken(lexer, options, token, eol, callbacks); \
211                 switch (result) { \
212                 case ISC_R_SUCCESS: \
213                         break; \
214                 case ISC_R_UNEXPECTED: \
215                         goto insist_and_cleanup; \
216                 default: \
217                         if (MANYERRS(lctx, result)) { \
218                                 SETRESULT(lctx, result); \
219                                 LOGIT(result); \
220                                 read_till_eol = ISC_TRUE; \
221                                 goto next_line; \
222                         } else \
223                                 goto log_and_cleanup; \
224                 } \
225                 if ((token)->type == isc_tokentype_special) { \
226                         result = DNS_R_SYNTAX; \
227                         if (MANYERRS(lctx, result)) { \
228                                 SETRESULT(lctx, result); \
229                                 LOGIT(result); \
230                                 read_till_eol = ISC_TRUE; \
231                                 goto next_line; \
232                         } else \
233                                 goto log_and_cleanup; \
234                 } \
235         } while (0)
236
237 #define COMMITALL \
238         do { \
239                 result = commit(callbacks, lctx, &current_list, \
240                                 ictx->current, source, ictx->current_line); \
241                 if (MANYERRS(lctx, result)) { \
242                         SETRESULT(lctx, result); \
243                 } else if (result != ISC_R_SUCCESS) \
244                         goto insist_and_cleanup; \
245                 result = commit(callbacks, lctx, &glue_list, \
246                                 ictx->glue, source, ictx->glue_line); \
247                 if (MANYERRS(lctx, result)) { \
248                         SETRESULT(lctx, result); \
249                 } else if (result != ISC_R_SUCCESS) \
250                         goto insist_and_cleanup; \
251                 rdcount = 0; \
252                 rdlcount = 0; \
253                 isc_buffer_init(&target, target_mem, target_size); \
254                 rdcount_save = rdcount; \
255                 rdlcount_save = rdlcount; \
256         } while (0)
257
258 #define WARNUNEXPECTEDEOF(lexer) \
259         do { \
260                 if (isc_lex_isfile(lexer)) \
261                         (*callbacks->warn)(callbacks, \
262                                 "%s: file does not end with newline", \
263                                 source); \
264         } while (0)
265
266 #define EXPECTEOL \
267         do { \
268                 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE); \
269                 if (token.type != isc_tokentype_eol) { \
270                         isc_lex_ungettoken(lctx->lex, &token); \
271                         result = DNS_R_EXTRATOKEN; \
272                         if (MANYERRS(lctx, result)) { \
273                                 SETRESULT(lctx, result); \
274                                 LOGIT(result); \
275                                 read_till_eol = ISC_TRUE; \
276                                 continue; \
277                         } else if (result != ISC_R_SUCCESS) \
278                                 goto log_and_cleanup; \
279                 } \
280         } while (0)
281
282 #define MANYERRS(lctx, result) \
283                 ((result != ISC_R_SUCCESS) && \
284                  (result != ISC_R_IOERROR) && \
285                  ((lctx)->options & DNS_MASTER_MANYERRORS) != 0)
286
287 #define SETRESULT(lctx, r) \
288                 do { \
289                         if ((lctx)->result == ISC_R_SUCCESS) \
290                                 (lctx)->result = r; \
291                 } while (0)
292
293 #define LOGITFILE(result, filename) \
294         if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \
295             result == ISC_R_IOERROR || result == ISC_R_TOOMANYOPENFILES || \
296             result == ISC_R_NOPERM) \
297                 (*callbacks->error)(callbacks, "%s: %s:%lu: %s: %s", \
298                                     "dns_master_load", source, line, \
299                                     filename, dns_result_totext(result)); \
300         else LOGIT(result)
301
302 #define LOGIT(result) \
303         if (result == ISC_R_NOMEMORY) \
304                 (*callbacks->error)(callbacks, "dns_master_load: %s", \
305                                     dns_result_totext(result)); \
306         else \
307                 (*callbacks->error)(callbacks, "%s: %s:%lu: %s", \
308                                     "dns_master_load", \
309                                     source, line, dns_result_totext(result))
310
311
312 static unsigned char in_addr_arpa_data[]  = "\007IN-ADDR\004ARPA";
313 static unsigned char in_addr_arpa_offsets[] = { 0, 8, 13 };
314 static const dns_name_t in_addr_arpa =
315 {
316         DNS_NAME_MAGIC,
317         in_addr_arpa_data, 14, 3,
318         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
319         in_addr_arpa_offsets, NULL,
320         {(void *)-1, (void *)-1},
321         {NULL, NULL}
322 };
323
324 static unsigned char ip6_int_data[]  = "\003IP6\003INT";
325 static unsigned char ip6_int_offsets[] = { 0, 4, 8 };
326 static const dns_name_t ip6_int =
327 {
328         DNS_NAME_MAGIC,
329         ip6_int_data, 9, 3,
330         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
331         ip6_int_offsets, NULL,
332         {(void *)-1, (void *)-1},
333         {NULL, NULL}
334 };
335
336 static unsigned char ip6_arpa_data[]  = "\003IP6\004ARPA";
337 static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 };
338 static const dns_name_t ip6_arpa =
339 {
340         DNS_NAME_MAGIC,
341         ip6_arpa_data, 10, 3,
342         DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
343         ip6_arpa_offsets, NULL,
344         {(void *)-1, (void *)-1},
345         {NULL, NULL}
346 };
347
348
349 static inline isc_result_t
350 gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token,
351          isc_boolean_t eol, dns_rdatacallbacks_t *callbacks)
352 {
353         isc_result_t result;
354
355         options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE |
356                 ISC_LEXOPT_ESCAPE;
357         result = isc_lex_gettoken(lex, options, token);
358         if (result != ISC_R_SUCCESS) {
359                 switch (result) {
360                 case ISC_R_NOMEMORY:
361                         return (ISC_R_NOMEMORY);
362                 default:
363                         (*callbacks->error)(callbacks,
364                                             "dns_master_load: %s:%lu:"
365                                             " isc_lex_gettoken() failed: %s",
366                                             isc_lex_getsourcename(lex),
367                                             isc_lex_getsourceline(lex),
368                                             isc_result_totext(result));
369                         return (result);
370                 }
371                 /*NOTREACHED*/
372         }
373         if (eol != ISC_TRUE)
374                 if (token->type == isc_tokentype_eol ||
375                     token->type == isc_tokentype_eof) {
376                         (*callbacks->error)(callbacks,
377                             "dns_master_load: %s:%lu: unexpected end of %s",
378                                             isc_lex_getsourcename(lex),
379                                             isc_lex_getsourceline(lex),
380                                             (token->type ==
381                                              isc_tokentype_eol) ?
382                                             "line" : "file");
383                         return (ISC_R_UNEXPECTEDEND);
384                 }
385         return (ISC_R_SUCCESS);
386 }
387
388
389 void
390 dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
391
392         REQUIRE(target != NULL && *target == NULL);
393         REQUIRE(DNS_LCTX_VALID(source));
394
395         LOCK(&source->lock);
396         INSIST(source->references > 0);
397         source->references++;
398         INSIST(source->references != 0);        /* Overflow? */
399         UNLOCK(&source->lock);
400
401         *target = source;
402 }
403
404 void
405 dns_loadctx_detach(dns_loadctx_t **lctxp) {
406         dns_loadctx_t *lctx;
407         isc_boolean_t need_destroy = ISC_FALSE;
408
409         REQUIRE(lctxp != NULL);
410         lctx = *lctxp;
411         REQUIRE(DNS_LCTX_VALID(lctx));
412
413         LOCK(&lctx->lock);
414         INSIST(lctx->references > 0);
415         lctx->references--;
416         if (lctx->references == 0)
417                 need_destroy = ISC_TRUE;
418         UNLOCK(&lctx->lock);
419
420         if (need_destroy)
421                 loadctx_destroy(lctx);
422         *lctxp = NULL;
423 }
424
425 static void
426 incctx_destroy(isc_mem_t *mctx, dns_incctx_t *ictx) {
427         dns_incctx_t *parent;
428
429  again:
430         parent = ictx->parent;
431         ictx->parent = NULL;
432
433         isc_mem_put(mctx, ictx, sizeof(*ictx));
434
435         if (parent != NULL) {
436                 ictx = parent;
437                 goto again;
438         }
439 }
440
441 static void
442 loadctx_destroy(dns_loadctx_t *lctx) {
443         isc_mem_t *mctx;
444         isc_result_t result;
445
446         REQUIRE(DNS_LCTX_VALID(lctx));
447
448         lctx->magic = 0;
449         if (lctx->inc != NULL)
450                 incctx_destroy(lctx->mctx, lctx->inc);
451
452         if (lctx->f != NULL) {
453                 result = isc_stdio_close(lctx->f);
454                 if (result != ISC_R_SUCCESS) {
455                         UNEXPECTED_ERROR(__FILE__, __LINE__,
456                                          "isc_stdio_close() failed: %s",
457                                          isc_result_totext(result));
458                 }
459         }
460
461         /* isc_lex_destroy() will close all open streams */
462         if (lctx->lex != NULL && !lctx->keep_lex)
463                 isc_lex_destroy(&lctx->lex);
464
465         if (lctx->task != NULL)
466                 isc_task_detach(&lctx->task);
467         DESTROYLOCK(&lctx->lock);
468         mctx = NULL;
469         isc_mem_attach(lctx->mctx, &mctx);
470         isc_mem_detach(&lctx->mctx);
471         isc_mem_put(mctx, lctx, sizeof(*lctx));
472         isc_mem_detach(&mctx);
473 }
474
475 static isc_result_t
476 incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
477         dns_incctx_t *ictx;
478         isc_region_t r;
479         int i;
480
481         ictx = isc_mem_get(mctx, sizeof(*ictx));
482         if (ictx == NULL)
483                 return (ISC_R_NOMEMORY);
484
485         for (i = 0; i < NBUFS; i++) {
486                 dns_fixedname_init(&ictx->fixed[i]);
487                 ictx->in_use[i] = ISC_FALSE;
488         }
489
490         ictx->origin_in_use = 0;
491         ictx->origin = dns_fixedname_name(&ictx->fixed[ictx->origin_in_use]);
492         ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
493         dns_name_toregion(origin, &r);
494         dns_name_fromregion(ictx->origin, &r);
495
496         ictx->glue = NULL;
497         ictx->current = NULL;
498         ictx->glue_in_use = -1;
499         ictx->current_in_use = -1;
500         ictx->parent = NULL;
501         ictx->drop = ISC_FALSE;
502         ictx->glue_line = 0;
503         ictx->current_line = 0;
504
505         *ictxp = ictx;
506         return (ISC_R_SUCCESS);
507 }
508
509 static isc_result_t
510 loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
511                unsigned int options, isc_uint32_t resign, dns_name_t *top,
512                dns_rdataclass_t zclass, dns_name_t *origin,
513                dns_rdatacallbacks_t *callbacks, isc_task_t *task,
514                dns_loaddonefunc_t done, void *done_arg, isc_lex_t *lex,
515                dns_loadctx_t **lctxp)
516 {
517         dns_loadctx_t *lctx;
518         isc_result_t result;
519         isc_region_t r;
520         isc_lexspecials_t specials;
521
522         REQUIRE(lctxp != NULL && *lctxp == NULL);
523         REQUIRE(callbacks != NULL);
524         REQUIRE(callbacks->add != NULL);
525         REQUIRE(callbacks->error != NULL);
526         REQUIRE(callbacks->warn != NULL);
527         REQUIRE(mctx != NULL);
528         REQUIRE(dns_name_isabsolute(top));
529         REQUIRE(dns_name_isabsolute(origin));
530         REQUIRE((task == NULL && done == NULL) ||
531                 (task != NULL && done != NULL));
532
533         lctx = isc_mem_get(mctx, sizeof(*lctx));
534         if (lctx == NULL)
535                 return (ISC_R_NOMEMORY);
536         result = isc_mutex_init(&lctx->lock);
537         if (result != ISC_R_SUCCESS) {
538                 isc_mem_put(mctx, lctx, sizeof(*lctx));
539                 return (result);
540         }
541
542         lctx->inc = NULL;
543         result = incctx_create(mctx, origin, &lctx->inc);
544         if (result != ISC_R_SUCCESS)
545                 goto cleanup_ctx;
546
547         lctx->format = format;
548         switch (format) {
549         default:
550                 INSIST(0);
551         case dns_masterformat_text:
552                 lctx->openfile = openfile_text;
553                 lctx->load = load_text;
554                 break;
555         case dns_masterformat_raw:
556                 lctx->openfile = openfile_raw;
557                 lctx->load = load_raw;
558                 break;
559         }
560
561         if (lex != NULL) {
562                 lctx->lex = lex;
563                 lctx->keep_lex = ISC_TRUE;
564         } else {
565                 lctx->lex = NULL;
566                 result = isc_lex_create(mctx, TOKENSIZ, &lctx->lex);
567                 if (result != ISC_R_SUCCESS)
568                         goto cleanup_inc;
569                 lctx->keep_lex = ISC_FALSE;
570                 memset(specials, 0, sizeof(specials));
571                 specials['('] = 1;
572                 specials[')'] = 1;
573                 specials['"'] = 1;
574                 isc_lex_setspecials(lctx->lex, specials);
575                 isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
576         }
577
578         lctx->ttl_known = ISC_FALSE;
579         lctx->ttl = 0;
580         lctx->default_ttl_known = ISC_FALSE;
581         lctx->default_ttl = 0;
582         lctx->warn_1035 = ISC_TRUE;     /* XXX Argument? */
583         lctx->warn_tcr = ISC_TRUE;      /* XXX Argument? */
584         lctx->warn_sigexpired = ISC_TRUE;       /* XXX Argument? */
585         lctx->options = options;
586         lctx->seen_include = ISC_FALSE;
587         lctx->zclass = zclass;
588         lctx->resign = resign;
589         lctx->result = ISC_R_SUCCESS;
590
591         dns_fixedname_init(&lctx->fixed_top);
592         lctx->top = dns_fixedname_name(&lctx->fixed_top);
593         dns_name_toregion(top, &r);
594         dns_name_fromregion(lctx->top, &r);
595
596         lctx->f = NULL;
597         lctx->first = ISC_TRUE;
598
599         lctx->loop_cnt = (done != NULL) ? 100 : 0;
600         lctx->callbacks = callbacks;
601         lctx->task = NULL;
602         if (task != NULL)
603                 isc_task_attach(task, &lctx->task);
604         lctx->done = done;
605         lctx->done_arg = done_arg;
606         lctx->canceled = ISC_FALSE;
607         lctx->mctx = NULL;
608         isc_mem_attach(mctx, &lctx->mctx);
609         lctx->references = 1;                   /* Implicit attach. */
610         lctx->magic = DNS_LCTX_MAGIC;
611         *lctxp = lctx;
612         return (ISC_R_SUCCESS);
613
614  cleanup_inc:
615         incctx_destroy(mctx, lctx->inc);
616  cleanup_ctx:
617         isc_mem_put(mctx, lctx, sizeof(*lctx));
618         return (result);
619 }
620
621 static const char *hex = "0123456789abcdef0123456789ABCDEF";
622
623 /*%
624  * Convert value into a nibble sequence from least significant to most
625  * significant nibble.  Zero fill upper most significant nibbles if
626  * required to make the width.
627  *
628  * Returns the number of characters that should have been written without
629  * counting the terminating NUL.
630  */
631 static unsigned int
632 nibbles(char *numbuf, size_t length, unsigned int width, char mode, int value) {
633         unsigned int count = 0;
634
635         /*
636          * This reserve space for the NUL string terminator.
637          */
638         if (length > 0U) {
639                 *numbuf = '\0';
640                 length--;
641         }
642         do {
643                 char val = hex[(value & 0x0f) + ((mode == 'n') ? 0 : 16)];
644                 value >>= 4;
645                 if (length > 0U) {
646                         *numbuf++ = val;
647                         *numbuf = '\0';
648                         length--;
649                 }
650                 if (width > 0)
651                         width--;
652                 count++;
653                 /*
654                  * If width is non zero then we need to add a label seperator.
655                  * If value is non zero then we need to add another label and
656                  * that requires a label seperator.
657                  */
658                 if (width > 0 || value != 0) {
659                         if (length > 0U) {
660                                 *numbuf++ = '.';
661                                 *numbuf = '\0';
662                                 length--;
663                         }
664                         if (width > 0)
665                                 width--;
666                         count++;
667                 }
668         } while (value != 0 || width > 0);
669         return (count);
670 }
671
672 static isc_result_t
673 genname(char *name, int it, char *buffer, size_t length) {
674         char fmt[sizeof("%04000000000d")];
675         char numbuf[128];
676         char *cp;
677         char mode[2];
678         int delta = 0;
679         isc_textregion_t r;
680         unsigned int n;
681         unsigned int width;
682         isc_boolean_t nibblemode;
683
684         r.base = buffer;
685         r.length = length;
686
687         while (*name != '\0') {
688                 if (*name == '$') {
689                         name++;
690                         if (*name == '$') {
691                                 if (r.length == 0)
692                                         return (ISC_R_NOSPACE);
693                                 r.base[0] = *name++;
694                                 isc_textregion_consume(&r, 1);
695                                 continue;
696                         }
697                         nibblemode = ISC_FALSE;
698                         strcpy(fmt, "%d");
699                         /* Get format specifier. */
700                         if (*name == '{' ) {
701                                 n = sscanf(name, "{%d,%u,%1[doxXnN]}",
702                                            &delta, &width, mode);
703                                 switch (n) {
704                                 case 1:
705                                         break;
706                                 case 2:
707                                         n = snprintf(fmt, sizeof(fmt),
708                                                      "%%0%ud", width);
709                                         break;
710                                 case 3:
711                                         if (mode[0] == 'n' || mode[0] == 'N')
712                                                 nibblemode = ISC_TRUE;
713                                         n = snprintf(fmt, sizeof(fmt),
714                                                      "%%0%u%c", width, mode[0]);
715                                         break;
716                                 default:
717                                         return (DNS_R_SYNTAX);
718                                 }
719                                 if (n >= sizeof(fmt))
720                                         return (ISC_R_NOSPACE);
721                                 /* Skip past closing brace. */
722                                 while (*name != '\0' && *name++ != '}')
723                                         continue;
724                         }
725                         if (nibblemode)
726                                 n = nibbles(numbuf, sizeof(numbuf), width,
727                                             mode[0], it + delta);
728                         else
729                                 n = snprintf(numbuf, sizeof(numbuf), fmt,
730                                              it + delta);
731                         if (n >= sizeof(numbuf))
732                                 return (ISC_R_NOSPACE);
733                         cp = numbuf;
734                         while (*cp != '\0') {
735                                 if (r.length == 0)
736                                         return (ISC_R_NOSPACE);
737                                 r.base[0] = *cp++;
738                                 isc_textregion_consume(&r, 1);
739                         }
740                 } else if (*name == '\\') {
741                         if (r.length == 0)
742                                 return (ISC_R_NOSPACE);
743                         r.base[0] = *name++;
744                         isc_textregion_consume(&r, 1);
745                         if (*name == '\0')
746                                 continue;
747                         if (r.length == 0)
748                                 return (ISC_R_NOSPACE);
749                         r.base[0] = *name++;
750                         isc_textregion_consume(&r, 1);
751                 } else {
752                         if (r.length == 0)
753                                 return (ISC_R_NOSPACE);
754                         r.base[0] = *name++;
755                         isc_textregion_consume(&r, 1);
756                 }
757         }
758         if (r.length == 0)
759                 return (ISC_R_NOSPACE);
760         r.base[0] = '\0';
761         return (ISC_R_SUCCESS);
762 }
763
764 static isc_result_t
765 openfile_text(dns_loadctx_t *lctx, const char *master_file) {
766         return (isc_lex_openfile(lctx->lex, master_file));
767 }
768
769 static isc_result_t
770 openfile_raw(dns_loadctx_t *lctx, const char *master_file) {
771         isc_result_t result;
772
773         result = isc_stdio_open(master_file, "r", &lctx->f);
774         if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
775                 UNEXPECTED_ERROR(__FILE__, __LINE__,
776                                  "isc_stdio_open() failed: %s",
777                                  isc_result_totext(result));
778         }
779
780         return (result);
781 }
782
783 static isc_result_t
784 generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs,
785          const char *source, unsigned int line)
786 {
787         char *target_mem = NULL;
788         char *lhsbuf = NULL;
789         char *rhsbuf = NULL;
790         dns_fixedname_t ownerfixed;
791         dns_name_t *owner;
792         dns_rdata_t rdata = DNS_RDATA_INIT;
793         dns_rdatacallbacks_t *callbacks;
794         dns_rdatalist_t rdatalist;
795         dns_rdatatype_t type;
796         rdatalist_head_t head;
797         int n;
798         int target_size = MINTSIZ;      /* only one rdata at a time */
799         isc_buffer_t buffer;
800         isc_buffer_t target;
801         isc_result_t result;
802         isc_textregion_t r;
803         unsigned int start, stop, step, i;
804         dns_incctx_t *ictx;
805
806         ictx = lctx->inc;
807         callbacks = lctx->callbacks;
808         dns_fixedname_init(&ownerfixed);
809         owner = dns_fixedname_name(&ownerfixed);
810         ISC_LIST_INIT(head);
811
812         target_mem = isc_mem_get(lctx->mctx, target_size);
813         rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_RHS);
814         lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_LHS);
815         if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) {
816                 result = ISC_R_NOMEMORY;
817                 goto error_cleanup;
818         }
819         isc_buffer_init(&target, target_mem, target_size);
820
821         n = sscanf(range, "%u-%u/%u", &start, &stop, &step);
822         if (n < 2 || stop < start) {
823                (*callbacks->error)(callbacks,
824                                   "%s: %s:%lu: invalid range '%s'",
825                                   "$GENERATE", source, line, range);
826                 result = DNS_R_SYNTAX;
827                 goto insist_cleanup;
828         }
829         if (n == 2)
830                 step = 1;
831
832         /*
833          * Get type.
834          */
835         r.base = gtype;
836         r.length = strlen(gtype);
837         result = dns_rdatatype_fromtext(&type, &r);
838         if (result != ISC_R_SUCCESS) {
839                 (*callbacks->error)(callbacks,
840                                    "%s: %s:%lu: unknown RR type '%s'",
841                                    "$GENERATE", source, line, gtype);
842                 goto insist_cleanup;
843         }
844
845         ISC_LIST_INIT(rdatalist.rdata);
846         ISC_LINK_INIT(&rdatalist, link);
847         for (i = start; i <= stop; i += step) {
848                 result = genname(lhs, i, lhsbuf, DNS_MASTER_LHS);
849                 if (result != ISC_R_SUCCESS)
850                         goto error_cleanup;
851                 result = genname(rhs, i, rhsbuf, DNS_MASTER_RHS);
852                 if (result != ISC_R_SUCCESS)
853                         goto error_cleanup;
854
855                 isc_buffer_init(&buffer, lhsbuf, strlen(lhsbuf));
856                 isc_buffer_add(&buffer, strlen(lhsbuf));
857                 isc_buffer_setactive(&buffer, strlen(lhsbuf));
858                 result = dns_name_fromtext(owner, &buffer, ictx->origin,
859                                            0, NULL);
860                 if (result != ISC_R_SUCCESS)
861                         goto error_cleanup;
862
863                 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
864                     (lctx->options & DNS_MASTER_SLAVE) == 0 &&
865                     (lctx->options & DNS_MASTER_KEY) == 0 &&
866                     !dns_name_issubdomain(owner, lctx->top))
867                 {
868                         char namebuf[DNS_NAME_FORMATSIZE];
869                         dns_name_format(owner, namebuf, sizeof(namebuf));
870                         /*
871                          * Ignore out-of-zone data.
872                          */
873                         (*callbacks->warn)(callbacks,
874                                            "%s:%lu: "
875                                            "ignoring out-of-zone data (%s)",
876                                            source, line, namebuf);
877                         continue;
878                 }
879
880                 isc_buffer_init(&buffer, rhsbuf, strlen(rhsbuf));
881                 isc_buffer_add(&buffer, strlen(rhsbuf));
882                 isc_buffer_setactive(&buffer, strlen(rhsbuf));
883
884                 result = isc_lex_openbuffer(lctx->lex, &buffer);
885                 if (result != ISC_R_SUCCESS)
886                         goto error_cleanup;
887
888                 isc_buffer_init(&target, target_mem, target_size);
889                 result = dns_rdata_fromtext(&rdata, lctx->zclass, type,
890                                             lctx->lex, ictx->origin, 0,
891                                             lctx->mctx, &target, callbacks);
892                 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
893                 if (result != ISC_R_SUCCESS)
894                         goto error_cleanup;
895
896                 rdatalist.type = type;
897                 rdatalist.covers = 0;
898                 rdatalist.rdclass = lctx->zclass;
899                 rdatalist.ttl = lctx->ttl;
900                 ISC_LIST_PREPEND(head, &rdatalist, link);
901                 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
902                 result = commit(callbacks, lctx, &head, owner, source, line);
903                 ISC_LIST_UNLINK(rdatalist.rdata, &rdata, link);
904                 if (result != ISC_R_SUCCESS)
905                         goto error_cleanup;
906                 dns_rdata_reset(&rdata);
907         }
908         result = ISC_R_SUCCESS;
909         goto cleanup;
910
911  error_cleanup:
912         if (result == ISC_R_NOMEMORY)
913                 (*callbacks->error)(callbacks, "$GENERATE: %s",
914                                     dns_result_totext(result));
915         else
916                 (*callbacks->error)(callbacks, "$GENERATE: %s:%lu: %s",
917                                     source, line, dns_result_totext(result));
918
919  insist_cleanup:
920         INSIST(result != ISC_R_SUCCESS);
921
922  cleanup:
923         if (target_mem != NULL)
924                 isc_mem_put(lctx->mctx, target_mem, target_size);
925         if (lhsbuf != NULL)
926                 isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_LHS);
927         if (rhsbuf != NULL)
928                 isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_RHS);
929         return (result);
930 }
931
932 static void
933 limit_ttl(dns_rdatacallbacks_t *callbacks, const char *source, unsigned int line,
934           isc_uint32_t *ttlp)
935 {
936         if (*ttlp > 0x7fffffffUL) {
937                 (callbacks->warn)(callbacks,
938                                   "%s: %s:%lu: "
939                                   "$TTL %lu > MAXTTL, "
940                                   "setting $TTL to 0",
941                                   "dns_master_load",
942                                   source, line,
943                                   *ttlp);
944                 *ttlp = 0;
945         }
946 }
947
948 static isc_result_t
949 check_ns(dns_loadctx_t *lctx, isc_token_t *token, const char *source,
950          unsigned long line)
951 {
952         char *tmp = NULL;
953         isc_result_t result = ISC_R_SUCCESS;
954         void (*callback)(struct dns_rdatacallbacks *, const char *, ...);
955
956         if ((lctx->options & DNS_MASTER_FATALNS) != 0)
957                 callback = lctx->callbacks->error;
958         else
959                 callback = lctx->callbacks->warn;
960
961         if (token->type == isc_tokentype_string) {
962                 struct in_addr addr;
963                 struct in6_addr addr6;
964
965                 tmp = isc_mem_strdup(lctx->mctx, DNS_AS_STR(*token));
966                 if (tmp == NULL)
967                         return (ISC_R_NOMEMORY);
968                 /*
969                  * Catch both "1.2.3.4" and "1.2.3.4."
970                  */
971                 if (tmp[strlen(tmp) - 1] == '.')
972                         tmp[strlen(tmp) - 1] = '\0';
973                 if (inet_aton(tmp, &addr) == 1 ||
974                     inet_pton(AF_INET6, tmp, &addr6) == 1)
975                         result = DNS_R_NSISADDRESS;
976         }
977         if (result != ISC_R_SUCCESS)
978                 (*callback)(lctx->callbacks, "%s:%lu: NS record '%s' "
979                             "appears to be an address",
980                             source, line, DNS_AS_STR(*token));
981         if (tmp != NULL)
982                 isc_mem_free(lctx->mctx, tmp);
983         return (result);
984 }
985
986 static void
987 check_wildcard(dns_incctx_t *ictx, const char *source, unsigned long line,
988                dns_rdatacallbacks_t *callbacks)
989 {
990         dns_name_t *name;
991
992         name = (ictx->glue != NULL) ? ictx->glue : ictx->current;
993         if (dns_name_internalwildcard(name)) {
994                 char namebuf[DNS_NAME_FORMATSIZE];
995
996                 dns_name_format(name, namebuf, sizeof(namebuf));
997                 (*callbacks->warn)(callbacks, "%s:%lu: warning: ownername "
998                                    "'%s' contains an non-terminal wildcard",
999                                    source, line, namebuf);
1000         }
1001 }
1002
1003 static isc_result_t
1004 load_text(dns_loadctx_t *lctx) {
1005         dns_rdataclass_t rdclass;
1006         dns_rdatatype_t type, covers;
1007         isc_uint32_t ttl_offset = 0;
1008         dns_name_t *new_name;
1009         isc_boolean_t current_has_delegation = ISC_FALSE;
1010         isc_boolean_t done = ISC_FALSE;
1011         isc_boolean_t finish_origin = ISC_FALSE;
1012         isc_boolean_t finish_include = ISC_FALSE;
1013         isc_boolean_t read_till_eol = ISC_FALSE;
1014         isc_boolean_t initialws;
1015         char *include_file = NULL;
1016         isc_token_t token;
1017         isc_result_t result = ISC_R_UNEXPECTED;
1018         rdatalist_head_t glue_list;
1019         rdatalist_head_t current_list;
1020         dns_rdatalist_t *this;
1021         dns_rdatalist_t *rdatalist = NULL;
1022         dns_rdatalist_t *new_rdatalist;
1023         int rdlcount = 0;
1024         int rdlcount_save = 0;
1025         int rdatalist_size = 0;
1026         isc_buffer_t buffer;
1027         isc_buffer_t target;
1028         isc_buffer_t target_ft;
1029         isc_buffer_t target_save;
1030         dns_rdata_t *rdata = NULL;
1031         dns_rdata_t *new_rdata;
1032         int rdcount = 0;
1033         int rdcount_save = 0;
1034         int rdata_size = 0;
1035         unsigned char *target_mem = NULL;
1036         int target_size = TSIZ;
1037         int new_in_use;
1038         unsigned int loop_cnt = 0;
1039         isc_mem_t *mctx;
1040         dns_rdatacallbacks_t *callbacks;
1041         dns_incctx_t *ictx;
1042         char *range = NULL;
1043         char *lhs = NULL;
1044         char *gtype = NULL;
1045         char *rhs = NULL;
1046         const char *source = "";
1047         unsigned long line = 0;
1048         isc_boolean_t explicit_ttl;
1049         isc_stdtime_t now;
1050         char classname1[DNS_RDATACLASS_FORMATSIZE];
1051         char classname2[DNS_RDATACLASS_FORMATSIZE];
1052         unsigned int options = 0;
1053
1054         REQUIRE(DNS_LCTX_VALID(lctx));
1055         callbacks = lctx->callbacks;
1056         mctx = lctx->mctx;
1057         ictx = lctx->inc;
1058
1059         ISC_LIST_INIT(glue_list);
1060         ISC_LIST_INIT(current_list);
1061
1062         isc_stdtime_get(&now);
1063
1064         /*
1065          * Allocate target_size of buffer space.  This is greater than twice
1066          * the maximum individual RR data size.
1067          */
1068         target_mem = isc_mem_get(mctx, target_size);
1069         if (target_mem == NULL) {
1070                 result = ISC_R_NOMEMORY;
1071                 goto log_and_cleanup;
1072         }
1073         isc_buffer_init(&target, target_mem, target_size);
1074         target_save = target;
1075
1076         if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0)
1077                 options |= DNS_RDATA_CHECKNAMES;
1078         if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0)
1079                 options |= DNS_RDATA_CHECKNAMESFAIL;
1080         if ((lctx->options & DNS_MASTER_CHECKMX) != 0)
1081                 options |= DNS_RDATA_CHECKMX;
1082         if ((lctx->options & DNS_MASTER_CHECKMXFAIL) != 0)
1083                 options |= DNS_RDATA_CHECKMXFAIL;
1084         source = isc_lex_getsourcename(lctx->lex);
1085         do {
1086                 initialws = ISC_FALSE;
1087                 line = isc_lex_getsourceline(lctx->lex);
1088                 GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING,
1089                          &token, ISC_TRUE);
1090                 line = isc_lex_getsourceline(lctx->lex);
1091
1092                 if (token.type == isc_tokentype_eof) {
1093                         if (read_till_eol)
1094                                 WARNUNEXPECTEDEOF(lctx->lex);
1095                         /* Pop the include stack? */
1096                         if (ictx->parent != NULL) {
1097                                 COMMITALL;
1098                                 lctx->inc = ictx->parent;
1099                                 ictx->parent = NULL;
1100                                 incctx_destroy(lctx->mctx, ictx);
1101                                 RUNTIME_CHECK(isc_lex_close(lctx->lex) == ISC_R_SUCCESS);
1102                                 line = isc_lex_getsourceline(lctx->lex);
1103                                 source = isc_lex_getsourcename(lctx->lex);
1104                                 ictx = lctx->inc;
1105                                 EXPECTEOL;
1106                                 continue;
1107                         }
1108                         done = ISC_TRUE;
1109                         continue;
1110                 }
1111
1112                 if (token.type == isc_tokentype_eol) {
1113                         read_till_eol = ISC_FALSE;
1114                         continue;               /* blank line */
1115                 }
1116
1117                 if (read_till_eol)
1118                         continue;
1119
1120                 if (token.type == isc_tokentype_initialws) {
1121                         /*
1122                          * Still working on the same name.
1123                          */
1124                         initialws = ISC_TRUE;
1125                 } else if (token.type == isc_tokentype_string ||
1126                            token.type == isc_tokentype_qstring) {
1127
1128                         /*
1129                          * "$" Support.
1130                          *
1131                          * "$ORIGIN" and "$INCLUDE" can both take domain names.
1132                          * The processing of "$ORIGIN" and "$INCLUDE" extends
1133                          * across the normal domain name processing.
1134                          */
1135
1136                         if (strcasecmp(DNS_AS_STR(token), "$ORIGIN") == 0) {
1137                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1138                                 finish_origin = ISC_TRUE;
1139                         } else if (strcasecmp(DNS_AS_STR(token),
1140                                               "$TTL") == 0) {
1141                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1142                                 result =
1143                                    dns_ttl_fromtext(&token.value.as_textregion,
1144                                                     &lctx->ttl);
1145                                 if (MANYERRS(lctx, result)) {
1146                                         SETRESULT(lctx, result);
1147                                         lctx->ttl = 0;
1148                                 } else if (result != ISC_R_SUCCESS)
1149                                         goto insist_and_cleanup;
1150                                 limit_ttl(callbacks, source, line, &lctx->ttl);
1151                                 lctx->default_ttl = lctx->ttl;
1152                                 lctx->default_ttl_known = ISC_TRUE;
1153                                 EXPECTEOL;
1154                                 continue;
1155                         } else if (strcasecmp(DNS_AS_STR(token),
1156                                               "$INCLUDE") == 0) {
1157                                 COMMITALL;
1158                                 if ((lctx->options & DNS_MASTER_NOINCLUDE)
1159                                     != 0)
1160                                 {
1161                                         (callbacks->error)(callbacks,
1162                                            "%s: %s:%lu: $INCLUDE not allowed",
1163                                            "dns_master_load",
1164                                            source, line);
1165                                         result = DNS_R_REFUSED;
1166                                         goto insist_and_cleanup;
1167                                 }
1168                                 if (ttl_offset != 0) {
1169                                         (callbacks->error)(callbacks,
1170                                            "%s: %s:%lu: $INCLUDE "
1171                                            "may not be used with $DATE",
1172                                            "dns_master_load",
1173                                            source, line);
1174                                         result = DNS_R_SYNTAX;
1175                                         goto insist_and_cleanup;
1176                                 }
1177                                 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token,
1178                                          ISC_FALSE);
1179                                 if (include_file != NULL)
1180                                         isc_mem_free(mctx, include_file);
1181                                 include_file = isc_mem_strdup(mctx,
1182                                                            DNS_AS_STR(token));
1183                                 if (include_file == NULL) {
1184                                         result = ISC_R_NOMEMORY;
1185                                         goto log_and_cleanup;
1186                                 }
1187                                 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE);
1188
1189                                 if (token.type == isc_tokentype_eol ||
1190                                     token.type == isc_tokentype_eof) {
1191                                         if (token.type == isc_tokentype_eof)
1192                                                 WARNUNEXPECTEDEOF(lctx->lex);
1193                                         isc_lex_ungettoken(lctx->lex, &token);
1194                                         /*
1195                                          * No origin field.
1196                                          */
1197                                         result = pushfile(include_file,
1198                                                           ictx->origin, lctx);
1199                                         if (MANYERRS(lctx, result)) {
1200                                                 SETRESULT(lctx, result);
1201                                                 LOGITFILE(result, include_file);
1202                                                 continue;
1203                                         } else if (result != ISC_R_SUCCESS) {
1204                                                 LOGITFILE(result, include_file);
1205                                                 goto insist_and_cleanup;
1206                                         }
1207                                         ictx = lctx->inc;
1208                                         source =
1209                                                isc_lex_getsourcename(lctx->lex);
1210                                         line = isc_lex_getsourceline(lctx->lex);
1211                                         POST(line);
1212                                         continue;
1213                                 }
1214                                 /*
1215                                  * There is an origin field.  Fall through
1216                                  * to domain name processing code and do
1217                                  * the actual inclusion later.
1218                                  */
1219                                 finish_include = ISC_TRUE;
1220                         } else if (strcasecmp(DNS_AS_STR(token),
1221                                               "$DATE") == 0) {
1222                                 isc_int64_t dump_time64;
1223                                 isc_stdtime_t dump_time, current_time;
1224                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1225                                 isc_stdtime_get(&current_time);
1226                                 result = dns_time64_fromtext(DNS_AS_STR(token),
1227                                                              &dump_time64);
1228                                 if (MANYERRS(lctx, result)) {
1229                                         SETRESULT(lctx, result);
1230                                         LOGIT(result);
1231                                         dump_time64 = 0;
1232                                 } else if (result != ISC_R_SUCCESS)
1233                                         goto log_and_cleanup;
1234                                 dump_time = (isc_stdtime_t)dump_time64;
1235                                 if (dump_time != dump_time64) {
1236                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1237                                          "%s: %s:%lu: $DATE outside epoch",
1238                                          "dns_master_load", source, line);
1239                                         result = ISC_R_UNEXPECTED;
1240                                         goto insist_and_cleanup;
1241                                 }
1242                                 if (dump_time > current_time) {
1243                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1244                                         "%s: %s:%lu: "
1245                                         "$DATE in future, using current date",
1246                                         "dns_master_load", source, line);
1247                                         dump_time = current_time;
1248                                 }
1249                                 ttl_offset = current_time - dump_time;
1250                                 EXPECTEOL;
1251                                 continue;
1252                         } else if (strcasecmp(DNS_AS_STR(token),
1253                                               "$GENERATE") == 0) {
1254                                 /*
1255                                  * Lazy cleanup.
1256                                  */
1257                                 if (range != NULL)
1258                                         isc_mem_free(mctx, range);
1259                                 if (lhs != NULL)
1260                                         isc_mem_free(mctx, lhs);
1261                                 if (gtype != NULL)
1262                                         isc_mem_free(mctx, gtype);
1263                                 if (rhs != NULL)
1264                                         isc_mem_free(mctx, rhs);
1265                                 range = lhs = gtype = rhs = NULL;
1266                                 /* RANGE */
1267                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1268                                 range = isc_mem_strdup(mctx,
1269                                                      DNS_AS_STR(token));
1270                                 if (range == NULL) {
1271                                         result = ISC_R_NOMEMORY;
1272                                         goto log_and_cleanup;
1273                                 }
1274                                 /* LHS */
1275                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1276                                 lhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
1277                                 if (lhs == NULL) {
1278                                         result = ISC_R_NOMEMORY;
1279                                         goto log_and_cleanup;
1280                                 }
1281                                 rdclass = 0;
1282                                 explicit_ttl = ISC_FALSE;
1283                                 /* CLASS? */
1284                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1285                                 if (dns_rdataclass_fromtext(&rdclass,
1286                                             &token.value.as_textregion)
1287                                                 == ISC_R_SUCCESS) {
1288                                         GETTOKEN(lctx->lex, 0, &token,
1289                                                  ISC_FALSE);
1290                                 }
1291                                 /* TTL? */
1292                                 if (dns_ttl_fromtext(&token.value.as_textregion,
1293                                                      &lctx->ttl)
1294                                                 == ISC_R_SUCCESS) {
1295                                         limit_ttl(callbacks, source, line,
1296                                                   &lctx->ttl);
1297                                         lctx->ttl_known = ISC_TRUE;
1298                                         explicit_ttl = ISC_TRUE;
1299                                         GETTOKEN(lctx->lex, 0, &token,
1300                                                  ISC_FALSE);
1301                                 }
1302                                 /* CLASS? */
1303                                 if (rdclass == 0 &&
1304                                     dns_rdataclass_fromtext(&rdclass,
1305                                                     &token.value.as_textregion)
1306                                                 == ISC_R_SUCCESS)
1307                                         GETTOKEN(lctx->lex, 0, &token,
1308                                                  ISC_FALSE);
1309                                 /* TYPE */
1310                                 gtype = isc_mem_strdup(mctx,
1311                                                        DNS_AS_STR(token));
1312                                 if (gtype == NULL) {
1313                                         result = ISC_R_NOMEMORY;
1314                                         goto log_and_cleanup;
1315                                 }
1316                                 /* RHS */
1317                                 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING,
1318                                          &token, ISC_FALSE);
1319                                 rhs = isc_mem_strdup(mctx, DNS_AS_STR(token));
1320                                 if (rhs == NULL) {
1321                                         result = ISC_R_NOMEMORY;
1322                                         goto log_and_cleanup;
1323                                 }
1324                                 if (!lctx->ttl_known &&
1325                                     !lctx->default_ttl_known) {
1326                                         (*callbacks->error)(callbacks,
1327                                             "%s: %s:%lu: no TTL specified",
1328                                             "dns_master_load", source, line);
1329                                         result = DNS_R_NOTTL;
1330                                         if (MANYERRS(lctx, result)) {
1331                                                 SETRESULT(lctx, result);
1332                                                 lctx->ttl = 0;
1333                                         } else if (result != ISC_R_SUCCESS)
1334                                                 goto insist_and_cleanup;
1335                                 } else if (!explicit_ttl &&
1336                                            lctx->default_ttl_known) {
1337                                         lctx->ttl = lctx->default_ttl;
1338                                 }
1339                                 /*
1340                                  * If the class specified does not match the
1341                                  * zone's class print out a error message and
1342                                  * exit.
1343                                  */
1344                                 if (rdclass != 0 && rdclass != lctx->zclass) {
1345                                         goto bad_class;
1346                                 }
1347                                 result = generate(lctx, range, lhs, gtype, rhs,
1348                                                   source, line);
1349                                 if (MANYERRS(lctx, result)) {
1350                                         SETRESULT(lctx, result);
1351                                 } else if (result != ISC_R_SUCCESS)
1352                                         goto insist_and_cleanup;
1353                                 EXPECTEOL;
1354                                 continue;
1355                         } else if (strncasecmp(DNS_AS_STR(token),
1356                                                "$", 1) == 0) {
1357                                 (callbacks->error)(callbacks,
1358                                            "%s: %s:%lu: "
1359                                            "unknown $ directive '%s'",
1360                                            "dns_master_load", source, line,
1361                                            DNS_AS_STR(token));
1362                                 result = DNS_R_SYNTAX;
1363                                 if (MANYERRS(lctx, result)) {
1364                                         SETRESULT(lctx, result);
1365                                 } else if (result != ISC_R_SUCCESS)
1366                                         goto insist_and_cleanup;
1367                         }
1368
1369                         /*
1370                          * Normal processing resumes.
1371                          *
1372                          * Find a free name buffer.
1373                          */
1374                         for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
1375                                 if (!ictx->in_use[new_in_use])
1376                                         break;
1377                         INSIST(new_in_use < NBUFS);
1378                         dns_fixedname_init(&ictx->fixed[new_in_use]);
1379                         new_name = dns_fixedname_name(&ictx->fixed[new_in_use]);
1380                         isc_buffer_init(&buffer, token.value.as_region.base,
1381                                         token.value.as_region.length);
1382                         isc_buffer_add(&buffer, token.value.as_region.length);
1383                         isc_buffer_setactive(&buffer,
1384                                              token.value.as_region.length);
1385                         result = dns_name_fromtext(new_name, &buffer,
1386                                           ictx->origin, 0, NULL);
1387                         if (MANYERRS(lctx, result)) {
1388                                 SETRESULT(lctx, result);
1389                                 LOGIT(result);
1390                                 read_till_eol = ISC_TRUE;
1391                                 continue;
1392                         } else if (result != ISC_R_SUCCESS)
1393                                 goto log_and_cleanup;
1394
1395                         /*
1396                          * Finish $ORIGIN / $INCLUDE processing if required.
1397                          */
1398                         if (finish_origin) {
1399                                 if (ictx->origin_in_use != -1)
1400                                         ictx->in_use[ictx->origin_in_use] =
1401                                                 ISC_FALSE;
1402                                 ictx->origin_in_use = new_in_use;
1403                                 ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
1404                                 ictx->origin = new_name;
1405                                 finish_origin = ISC_FALSE;
1406                                 EXPECTEOL;
1407                                 continue;
1408                         }
1409                         if (finish_include) {
1410                                 finish_include = ISC_FALSE;
1411                                 result = pushfile(include_file, new_name, lctx);
1412                                 if (MANYERRS(lctx, result)) {
1413                                         SETRESULT(lctx, result);
1414                                         LOGITFILE(result, include_file);
1415                                         continue;
1416                                 } else if (result != ISC_R_SUCCESS) {
1417                                         LOGITFILE(result, include_file);
1418                                         goto insist_and_cleanup;
1419                                 }
1420                                 ictx = lctx->inc;
1421                                 source = isc_lex_getsourcename(lctx->lex);
1422                                 line = isc_lex_getsourceline(lctx->lex);
1423                                 POST(line);
1424                                 continue;
1425                         }
1426
1427                         /*
1428                          * "$" Processing Finished
1429                          */
1430
1431                         /*
1432                          * If we are processing glue and the new name does
1433                          * not match the current glue name, commit the glue
1434                          * and pop stacks leaving us in 'normal' processing
1435                          * state.  Linked lists are undone by commit().
1436                          */
1437                         if (ictx->glue != NULL &&
1438                             dns_name_compare(ictx->glue, new_name) != 0) {
1439                                 result = commit(callbacks, lctx, &glue_list,
1440                                                 ictx->glue, source,
1441                                                 ictx->glue_line);
1442                                 if (MANYERRS(lctx, result)) {
1443                                         SETRESULT(lctx, result);
1444                                 } else if (result != ISC_R_SUCCESS)
1445                                         goto insist_and_cleanup;
1446                                 if (ictx->glue_in_use != -1)
1447                                         ictx->in_use[ictx->glue_in_use] =
1448                                                 ISC_FALSE;
1449                                 ictx->glue_in_use = -1;
1450                                 ictx->glue = NULL;
1451                                 rdcount = rdcount_save;
1452                                 rdlcount = rdlcount_save;
1453                                 target = target_save;
1454                         }
1455
1456                         /*
1457                          * If we are in 'normal' processing state and the new
1458                          * name does not match the current name, see if the
1459                          * new name is for glue and treat it as such,
1460                          * otherwise we have a new name so commit what we
1461                          * have.
1462                          */
1463                         if ((ictx->glue == NULL) && (ictx->current == NULL ||
1464                             dns_name_compare(ictx->current, new_name) != 0)) {
1465                                 if (current_has_delegation &&
1466                                         is_glue(&current_list, new_name)) {
1467                                         rdcount_save = rdcount;
1468                                         rdlcount_save = rdlcount;
1469                                         target_save = target;
1470                                         ictx->glue = new_name;
1471                                         ictx->glue_in_use = new_in_use;
1472                                         ictx->in_use[ictx->glue_in_use] =
1473                                                 ISC_TRUE;
1474                                 } else {
1475                                         result = commit(callbacks, lctx,
1476                                                         &current_list,
1477                                                         ictx->current,
1478                                                         source,
1479                                                         ictx->current_line);
1480                                         if (MANYERRS(lctx, result)) {
1481                                                 SETRESULT(lctx, result);
1482                                         } else if (result != ISC_R_SUCCESS)
1483                                                 goto insist_and_cleanup;
1484                                         rdcount = 0;
1485                                         rdlcount = 0;
1486                                         if (ictx->current_in_use != -1)
1487                                             ictx->in_use[ictx->current_in_use] =
1488                                                 ISC_FALSE;
1489                                         ictx->current_in_use = new_in_use;
1490                                         ictx->in_use[ictx->current_in_use] =
1491                                                 ISC_TRUE;
1492                                         ictx->current = new_name;
1493                                         current_has_delegation = ISC_FALSE;
1494                                         isc_buffer_init(&target, target_mem,
1495                                                         target_size);
1496                                 }
1497                                 /*
1498                                  * Check for internal wildcards.
1499                                  */
1500                                 if ((lctx->options & DNS_MASTER_CHECKWILDCARD)
1501                                                  != 0)
1502                                         check_wildcard(ictx, source, line,
1503                                                        callbacks);
1504
1505                         }
1506                         if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
1507                             (lctx->options & DNS_MASTER_SLAVE) == 0 &&
1508                             (lctx->options & DNS_MASTER_KEY) == 0 &&
1509                             !dns_name_issubdomain(new_name, lctx->top))
1510                         {
1511                                 char namebuf[DNS_NAME_FORMATSIZE];
1512                                 dns_name_format(new_name, namebuf,
1513                                                 sizeof(namebuf));
1514                                 /*
1515                                  * Ignore out-of-zone data.
1516                                  */
1517                                 (*callbacks->warn)(callbacks,
1518                                        "%s:%lu: "
1519                                        "ignoring out-of-zone data (%s)",
1520                                        source, line, namebuf);
1521                                 ictx->drop = ISC_TRUE;
1522                         } else
1523                                 ictx->drop = ISC_FALSE;
1524                 } else {
1525                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1526                                          "%s:%lu: isc_lex_gettoken() returned "
1527                                          "unexpected token type (%d)",
1528                                          source, line, token.type);
1529                         result = ISC_R_UNEXPECTED;
1530                         if (MANYERRS(lctx, result)) {
1531                                 SETRESULT(lctx, result);
1532                                 LOGIT(result);
1533                                 continue;
1534                         } else if (result != ISC_R_SUCCESS)
1535                                 goto insist_and_cleanup;
1536                 }
1537
1538                 /*
1539                  * Find TTL, class and type.  Both TTL and class are optional
1540                  * and may occur in any order if they exist. TTL and class
1541                  * come before type which must exist.
1542                  *
1543                  * [<TTL>] [<class>] <type> <RDATA>
1544                  * [<class>] [<TTL>] <type> <RDATA>
1545                  */
1546
1547                 type = 0;
1548                 rdclass = 0;
1549
1550                 GETTOKEN(lctx->lex, 0, &token, initialws);
1551
1552                 if (initialws) {
1553                         if (token.type == isc_tokentype_eol) {
1554                                 read_till_eol = ISC_FALSE;
1555                                 continue;               /* blank line */
1556                         }
1557
1558                         if (token.type == isc_tokentype_eof) {
1559                                 WARNUNEXPECTEDEOF(lctx->lex);
1560                                 read_till_eol = ISC_FALSE;
1561                                 isc_lex_ungettoken(lctx->lex, &token);
1562                                 continue;
1563                         }
1564
1565                         if (ictx->current == NULL) {
1566                                 (*callbacks->error)(callbacks,
1567                                         "%s:%lu: no current owner name",
1568                                         source, line);
1569                                 result = DNS_R_NOOWNER;
1570                                 if (MANYERRS(lctx, result)) {
1571                                         SETRESULT(lctx, result);
1572                                         read_till_eol = ISC_TRUE;
1573                                         continue;
1574                                 } else if (result != ISC_R_SUCCESS)
1575                                         goto insist_and_cleanup;
1576                         }
1577                 }
1578
1579                 if (dns_rdataclass_fromtext(&rdclass,
1580                                             &token.value.as_textregion)
1581                                 == ISC_R_SUCCESS)
1582                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1583
1584                 explicit_ttl = ISC_FALSE;
1585                 if (dns_ttl_fromtext(&token.value.as_textregion, &lctx->ttl)
1586                                 == ISC_R_SUCCESS) {
1587                         limit_ttl(callbacks, source, line, &lctx->ttl);
1588                         explicit_ttl = ISC_TRUE;
1589                         lctx->ttl_known = ISC_TRUE;
1590                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1591                 }
1592
1593                 if (token.type != isc_tokentype_string) {
1594                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1595                         "isc_lex_gettoken() returned unexpected token type");
1596                         result = ISC_R_UNEXPECTED;
1597                         if (MANYERRS(lctx, result)) {
1598                                 SETRESULT(lctx, result);
1599                                 read_till_eol = ISC_TRUE;
1600                                 continue;
1601                         } else if (result != ISC_R_SUCCESS)
1602                                 goto insist_and_cleanup;
1603                 }
1604
1605                 if (rdclass == 0 &&
1606                     dns_rdataclass_fromtext(&rdclass,
1607                                             &token.value.as_textregion)
1608                                 == ISC_R_SUCCESS)
1609                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1610
1611                 if (token.type != isc_tokentype_string) {
1612                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1613                         "isc_lex_gettoken() returned unexpected token type");
1614                         result = ISC_R_UNEXPECTED;
1615                         if (MANYERRS(lctx, result)) {
1616                                 SETRESULT(lctx, result);
1617                                 read_till_eol = ISC_TRUE;
1618                                 continue;
1619                         } else if (result != ISC_R_SUCCESS)
1620                                 goto insist_and_cleanup;
1621                 }
1622
1623                 result = dns_rdatatype_fromtext(&type,
1624                                                 &token.value.as_textregion);
1625                 if (result != ISC_R_SUCCESS) {
1626                         (*callbacks->warn)(callbacks,
1627                                    "%s:%lu: unknown RR type '%.*s'",
1628                                    source, line,
1629                                    token.value.as_textregion.length,
1630                                    token.value.as_textregion.base);
1631                         if (MANYERRS(lctx, result)) {
1632                                 SETRESULT(lctx, result);
1633                                 read_till_eol = ISC_TRUE;
1634                                 continue;
1635                         } else if (result != ISC_R_SUCCESS)
1636                                 goto insist_and_cleanup;
1637                 }
1638
1639                 /*
1640                  * If the class specified does not match the zone's class
1641                  * print out a error message and exit.
1642                  */
1643                 if (rdclass != 0 && rdclass != lctx->zclass) {
1644   bad_class:
1645
1646                         dns_rdataclass_format(rdclass, classname1,
1647                                               sizeof(classname1));
1648                         dns_rdataclass_format(lctx->zclass, classname2,
1649                                               sizeof(classname2));
1650                         (*callbacks->error)(callbacks,
1651                                             "%s:%lu: class '%s' != "
1652                                             "zone class '%s'",
1653                                             source, line,
1654                                             classname1, classname2);
1655                         result = DNS_R_BADCLASS;
1656                         if (MANYERRS(lctx, result)) {
1657                                 SETRESULT(lctx, result);
1658                                 read_till_eol = ISC_TRUE;
1659                                 continue;
1660                         } else if (result != ISC_R_SUCCESS)
1661                                 goto insist_and_cleanup;
1662                 }
1663
1664                 if (type == dns_rdatatype_ns && ictx->glue == NULL)
1665                         current_has_delegation = ISC_TRUE;
1666
1667                 /*
1668                  * RFC1123: MD and MF are not allowed to be loaded from
1669                  * master files.
1670                  */
1671                 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
1672                     (lctx->options & DNS_MASTER_SLAVE) == 0 &&
1673                     (type == dns_rdatatype_md || type == dns_rdatatype_mf)) {
1674                         char typename[DNS_RDATATYPE_FORMATSIZE];
1675
1676                         result = DNS_R_OBSOLETE;
1677
1678                         dns_rdatatype_format(type, typename, sizeof(typename));
1679                         (*callbacks->error)(callbacks,
1680                                             "%s:%lu: %s '%s': %s",
1681                                             source, line,
1682                                             "type", typename,
1683                                             dns_result_totext(result));
1684                         if (MANYERRS(lctx, result)) {
1685                                 SETRESULT(lctx, result);
1686                         } else
1687                                 goto insist_and_cleanup;
1688                 }
1689
1690                 /*
1691                  * Find a rdata structure.
1692                  */
1693                 if (rdcount == rdata_size) {
1694                         new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
1695                                                rdata_size, &current_list,
1696                                                &glue_list, mctx);
1697                         if (new_rdata == NULL) {
1698                                 result = ISC_R_NOMEMORY;
1699                                 goto log_and_cleanup;
1700                         }
1701                         rdata_size += RDSZ;
1702                         rdata = new_rdata;
1703                 }
1704
1705                 /*
1706                  * Peek at the NS record.
1707                  */
1708                 if (type == dns_rdatatype_ns &&
1709                     lctx->zclass == dns_rdataclass_in &&
1710                     (lctx->options & DNS_MASTER_CHECKNS) != 0) {
1711
1712                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1713                         result = check_ns(lctx, &token, source, line);
1714                         isc_lex_ungettoken(lctx->lex, &token);
1715                         if ((lctx->options & DNS_MASTER_FATALNS) != 0) {
1716                                 if (MANYERRS(lctx, result)) {
1717                                         SETRESULT(lctx, result);
1718                                 } else if (result != ISC_R_SUCCESS)
1719                                         goto insist_and_cleanup;
1720                         }
1721                 }
1722
1723                 /*
1724                  * Check owner name.
1725                  */
1726                 options &= ~DNS_RDATA_CHECKREVERSE;
1727                 if ((lctx->options & DNS_MASTER_CHECKNAMES) != 0) {
1728                         isc_boolean_t ok;
1729                         dns_name_t *name;
1730
1731                         name = (ictx->glue != NULL) ? ictx->glue :
1732                                                       ictx->current;
1733                         ok = dns_rdata_checkowner(name, lctx->zclass, type,
1734                                                   ISC_TRUE);
1735                         if (!ok) {
1736                                 char namebuf[DNS_NAME_FORMATSIZE];
1737                                 const char *desc;
1738                                 dns_name_format(name, namebuf, sizeof(namebuf));
1739                                 result = DNS_R_BADOWNERNAME;
1740                                 desc = dns_result_totext(result);
1741                                 if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) {
1742                                         (*callbacks->error)(callbacks,
1743                                                             "%s:%lu: %s: %s",
1744                                                             source, line,
1745                                                             namebuf, desc);
1746                                         if (MANYERRS(lctx, result)) {
1747                                                 SETRESULT(lctx, result);
1748                                         } else if (result != ISC_R_SUCCESS)
1749                                                 goto cleanup;
1750                                 } else {
1751                                         (*callbacks->warn)(callbacks,
1752                                                            "%s:%lu: %s: %s",
1753                                                            source, line,
1754                                                            namebuf, desc);
1755                                 }
1756                         }
1757                         if (type == dns_rdatatype_ptr &&
1758                             (dns_name_issubdomain(name, &in_addr_arpa) ||
1759                              dns_name_issubdomain(name, &ip6_arpa) ||
1760                              dns_name_issubdomain(name, &ip6_int)))
1761                                 options |= DNS_RDATA_CHECKREVERSE;
1762                 }
1763
1764                 /*
1765                  * Read rdata contents.
1766                  */
1767                 dns_rdata_init(&rdata[rdcount]);
1768                 target_ft = target;
1769                 result = dns_rdata_fromtext(&rdata[rdcount], lctx->zclass,
1770                                             type, lctx->lex, ictx->origin,
1771                                             options, lctx->mctx, &target,
1772                                             callbacks);
1773                 if (MANYERRS(lctx, result)) {
1774                         SETRESULT(lctx, result);
1775                         continue;
1776                 } else if (result != ISC_R_SUCCESS)
1777                         goto insist_and_cleanup;
1778
1779                 if (ictx->drop) {
1780                         target = target_ft;
1781                         continue;
1782                 }
1783
1784                 if (type == dns_rdatatype_soa &&
1785                     (lctx->options & DNS_MASTER_ZONE) != 0 &&
1786                     dns_name_compare(ictx->current, lctx->top) != 0) {
1787                         char namebuf[DNS_NAME_FORMATSIZE];
1788                         dns_name_format(ictx->current, namebuf,
1789                                         sizeof(namebuf));
1790                         (*callbacks->error)(callbacks, "%s:%lu: SOA "
1791                                             "record not at top of zone (%s)",
1792                                             source, line, namebuf);
1793                         result = DNS_R_NOTZONETOP;
1794                         if (MANYERRS(lctx, result)) {
1795                                 SETRESULT(lctx, result);
1796                                 read_till_eol = ISC_TRUE;
1797                                 target = target_ft;
1798                                 continue;
1799                         } else if (result != ISC_R_SUCCESS)
1800                                 goto insist_and_cleanup;
1801                 }
1802
1803
1804                 if (type == dns_rdatatype_rrsig ||
1805                     type == dns_rdatatype_sig)
1806                         covers = dns_rdata_covers(&rdata[rdcount]);
1807                 else
1808                         covers = 0;
1809
1810                 if (!lctx->ttl_known && !lctx->default_ttl_known) {
1811                         if (type == dns_rdatatype_soa) {
1812                                 (*callbacks->warn)(callbacks,
1813                                                    "%s:%lu: no TTL specified; "
1814                                                    "using SOA MINTTL instead",
1815                                                    source, line);
1816                                 lctx->ttl = dns_soa_getminimum(&rdata[rdcount]);
1817                                 limit_ttl(callbacks, source, line, &lctx->ttl);
1818                                 lctx->default_ttl = lctx->ttl;
1819                                 lctx->default_ttl_known = ISC_TRUE;
1820                         } else if ((lctx->options & DNS_MASTER_HINT) != 0) {
1821                                 /*
1822                                  * Zero TTL's are fine for hints.
1823                                  */
1824                                 lctx->ttl = 0;
1825                                 lctx->default_ttl = lctx->ttl;
1826                                 lctx->default_ttl_known = ISC_TRUE;
1827                         } else {
1828                                 (*callbacks->warn)(callbacks,
1829                                                    "%s:%lu: no TTL specified; "
1830                                                    "zone rejected",
1831                                                    source, line);
1832                                 result = DNS_R_NOTTL;
1833                                 if (MANYERRS(lctx, result)) {
1834                                         SETRESULT(lctx, result);
1835                                         lctx->ttl = 0;
1836                                 } else {
1837                                         goto insist_and_cleanup;
1838                                 }
1839                         }
1840                 } else if (!explicit_ttl && lctx->default_ttl_known) {
1841                         lctx->ttl = lctx->default_ttl;
1842                 } else if (!explicit_ttl && lctx->warn_1035) {
1843                         (*callbacks->warn)(callbacks,
1844                                            "%s:%lu: "
1845                                            "using RFC1035 TTL semantics",
1846                                            source, line);
1847                         lctx->warn_1035 = ISC_FALSE;
1848                 }
1849
1850                 if (type == dns_rdatatype_rrsig && lctx->warn_sigexpired) {
1851                         dns_rdata_rrsig_t sig;
1852                         result = dns_rdata_tostruct(&rdata[rdcount], &sig,
1853                                                     NULL);
1854                         RUNTIME_CHECK(result == ISC_R_SUCCESS);
1855                         if (isc_serial_lt(sig.timeexpire, now)) {
1856                                 (*callbacks->warn)(callbacks,
1857                                                    "%s:%lu: "
1858                                                    "signature has expired",
1859                                                    source, line);
1860                                 lctx->warn_sigexpired = ISC_FALSE;
1861                         }
1862                 }
1863
1864                 if ((type == dns_rdatatype_sig || type == dns_rdatatype_nxt) &&
1865                     lctx->warn_tcr && (lctx->options & DNS_MASTER_ZONE) != 0 &&
1866                     (lctx->options & DNS_MASTER_SLAVE) == 0) {
1867                         (*callbacks->warn)(callbacks, "%s:%lu: old style DNSSEC "
1868                                            " zone detected", source, line);
1869                         lctx->warn_tcr = ISC_FALSE;
1870                 }
1871
1872                 if ((lctx->options & DNS_MASTER_AGETTL) != 0) {
1873                         /*
1874                          * Adjust the TTL for $DATE.  If the RR has already
1875                          * expired, ignore it.
1876                          */
1877                         if (lctx->ttl < ttl_offset)
1878                                 continue;
1879                         lctx->ttl -= ttl_offset;
1880                 }
1881
1882                 /*
1883                  * Find type in rdatalist.
1884                  * If it does not exist create new one and prepend to list
1885                  * as this will minimise list traversal.
1886                  */
1887                 if (ictx->glue != NULL)
1888                         this = ISC_LIST_HEAD(glue_list);
1889                 else
1890                         this = ISC_LIST_HEAD(current_list);
1891
1892                 while (this != NULL) {
1893                         if (this->type == type && this->covers == covers)
1894                                 break;
1895                         this = ISC_LIST_NEXT(this, link);
1896                 }
1897
1898                 if (this == NULL) {
1899                         if (rdlcount == rdatalist_size) {
1900                                 new_rdatalist =
1901                                         grow_rdatalist(rdatalist_size + RDLSZ,
1902                                                        rdatalist,
1903                                                        rdatalist_size,
1904                                                        &current_list,
1905                                                        &glue_list,
1906                                                        mctx);
1907                                 if (new_rdatalist == NULL) {
1908                                         result = ISC_R_NOMEMORY;
1909                                         goto log_and_cleanup;
1910                                 }
1911                                 rdatalist = new_rdatalist;
1912                                 rdatalist_size += RDLSZ;
1913                         }
1914                         this = &rdatalist[rdlcount++];
1915                         this->type = type;
1916                         this->covers = covers;
1917                         this->rdclass = lctx->zclass;
1918                         this->ttl = lctx->ttl;
1919                         ISC_LIST_INIT(this->rdata);
1920                         if (ictx->glue != NULL)
1921                                 ISC_LIST_INITANDPREPEND(glue_list, this, link);
1922                         else
1923                                 ISC_LIST_INITANDPREPEND(current_list, this,
1924                                                         link);
1925                 } else if (this->ttl != lctx->ttl) {
1926                         (*callbacks->warn)(callbacks,
1927                                            "%s:%lu: "
1928                                            "TTL set to prior TTL (%lu)",
1929                                            source, line, this->ttl);
1930                         lctx->ttl = this->ttl;
1931                 }
1932
1933                 ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
1934                 if (ictx->glue != NULL)
1935                         ictx->glue_line = line;
1936                 else
1937                         ictx->current_line = line;
1938                 rdcount++;
1939
1940                 /*
1941                  * We must have at least 64k as rdlen is 16 bits.
1942                  * If we don't commit everything we have so far.
1943                  */
1944                 if ((target.length - target.used) < MINTSIZ)
1945                         COMMITALL;
1946  next_line:
1947                 ;
1948         } while (!done && (lctx->loop_cnt == 0 || loop_cnt++ < lctx->loop_cnt));
1949
1950         /*
1951          * Commit what has not yet been committed.
1952          */
1953         result = commit(callbacks, lctx, &current_list, ictx->current,
1954                         source, ictx->current_line);
1955         if (MANYERRS(lctx, result)) {
1956                 SETRESULT(lctx, result);
1957         } else if (result != ISC_R_SUCCESS)
1958                 goto insist_and_cleanup;
1959         result = commit(callbacks, lctx, &glue_list, ictx->glue,
1960                         source, ictx->glue_line);
1961         if (MANYERRS(lctx, result)) {
1962                 SETRESULT(lctx, result);
1963         } else if (result != ISC_R_SUCCESS)
1964                 goto insist_and_cleanup;
1965
1966         if (!done) {
1967                 INSIST(lctx->done != NULL && lctx->task != NULL);
1968                 result = DNS_R_CONTINUE;
1969         } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
1970                 result = lctx->result;
1971         } else if (result == ISC_R_SUCCESS && lctx->seen_include)
1972                 result = DNS_R_SEENINCLUDE;
1973         goto cleanup;
1974
1975  log_and_cleanup:
1976         LOGIT(result);
1977
1978  insist_and_cleanup:
1979         INSIST(result != ISC_R_SUCCESS);
1980
1981  cleanup:
1982         while ((this = ISC_LIST_HEAD(current_list)) != NULL)
1983                 ISC_LIST_UNLINK(current_list, this, link);
1984         while ((this = ISC_LIST_HEAD(glue_list)) != NULL)
1985                 ISC_LIST_UNLINK(glue_list, this, link);
1986         if (rdatalist != NULL)
1987                 isc_mem_put(mctx, rdatalist,
1988                             rdatalist_size * sizeof(*rdatalist));
1989         if (rdata != NULL)
1990                 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
1991         if (target_mem != NULL)
1992                 isc_mem_put(mctx, target_mem, target_size);
1993         if (include_file != NULL)
1994                 isc_mem_free(mctx, include_file);
1995         if (range != NULL)
1996                 isc_mem_free(mctx, range);
1997         if (lhs != NULL)
1998                 isc_mem_free(mctx, lhs);
1999         if (gtype != NULL)
2000                 isc_mem_free(mctx, gtype);
2001         if (rhs != NULL)
2002                 isc_mem_free(mctx, rhs);
2003         return (result);
2004 }
2005
2006 static isc_result_t
2007 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) {
2008         isc_result_t result;
2009         dns_incctx_t *ictx;
2010         dns_incctx_t *new = NULL;
2011         isc_region_t r;
2012         int new_in_use;
2013
2014         REQUIRE(master_file != NULL);
2015         REQUIRE(DNS_LCTX_VALID(lctx));
2016
2017         ictx = lctx->inc;
2018         lctx->seen_include = ISC_TRUE;
2019
2020         result = incctx_create(lctx->mctx, origin, &new);
2021         if (result != ISC_R_SUCCESS)
2022                 return (result);
2023
2024         /* Set current domain. */
2025         if (ictx->glue != NULL || ictx->current != NULL) {
2026                 for (new_in_use = 0; new_in_use < NBUFS; new_in_use++)
2027                         if (!new->in_use[new_in_use])
2028                                 break;
2029                 INSIST(new_in_use < NBUFS);
2030                 new->current_in_use = new_in_use;
2031                 new->current =
2032                         dns_fixedname_name(&new->fixed[new->current_in_use]);
2033                 new->in_use[new->current_in_use] = ISC_TRUE;
2034                 dns_name_toregion((ictx->glue != NULL) ?
2035                                    ictx->glue : ictx->current, &r);
2036                 dns_name_fromregion(new->current, &r);
2037                 new->drop = ictx->drop;
2038         }
2039
2040         result = (lctx->openfile)(lctx, master_file);
2041         if (result != ISC_R_SUCCESS)
2042                 goto cleanup;
2043         new->parent = ictx;
2044         lctx->inc = new;
2045         return (ISC_R_SUCCESS);
2046
2047  cleanup:
2048         if (new != NULL)
2049                 incctx_destroy(lctx->mctx, new);
2050         return (result);
2051 }
2052
2053 static inline isc_result_t
2054 read_and_check(isc_boolean_t do_read, isc_buffer_t *buffer,
2055                size_t len, FILE *f)
2056 {
2057         isc_result_t result;
2058
2059         if (do_read) {
2060                 INSIST(isc_buffer_availablelength(buffer) >= len);
2061                 result = isc_stdio_read(isc_buffer_used(buffer), 1, len,
2062                                         f, NULL);
2063                 if (result != ISC_R_SUCCESS)
2064                         return (result);
2065                 isc_buffer_add(buffer, len);
2066         } else if (isc_buffer_remaininglength(buffer) < len)
2067                 return (ISC_R_RANGE);
2068
2069         return (ISC_R_SUCCESS);
2070 }
2071
2072 static isc_result_t
2073 load_raw(dns_loadctx_t *lctx) {
2074         isc_result_t result = ISC_R_SUCCESS;
2075         isc_boolean_t done = ISC_FALSE;
2076         unsigned int loop_cnt = 0;
2077         dns_rdatacallbacks_t *callbacks;
2078         unsigned char namebuf[DNS_NAME_MAXWIRE];
2079         dns_fixedname_t fixed;
2080         dns_name_t *name;
2081         rdatalist_head_t head, dummy;
2082         dns_rdatalist_t rdatalist;
2083         isc_mem_t *mctx = lctx->mctx;
2084         dns_rdata_t *rdata = NULL;
2085         unsigned int rdata_size = 0;
2086         int target_size = TSIZ;
2087         isc_buffer_t target, buf;
2088         unsigned char *target_mem = NULL;
2089         dns_decompress_t dctx;
2090
2091         REQUIRE(DNS_LCTX_VALID(lctx));
2092         callbacks = lctx->callbacks;
2093         dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
2094
2095         if (lctx->first) {
2096                 dns_masterrawheader_t header;
2097                 isc_uint32_t format, version, dumptime;
2098                 size_t hdrlen = sizeof(format) + sizeof(version) +
2099                         sizeof(dumptime);
2100
2101                 INSIST(hdrlen <= sizeof(header));
2102                 isc_buffer_init(&target, &header, sizeof(header));
2103
2104                 result = isc_stdio_read(&header, 1, hdrlen, lctx->f, NULL);
2105                 if (result != ISC_R_SUCCESS) {
2106                         UNEXPECTED_ERROR(__FILE__, __LINE__,
2107                                          "isc_stdio_read failed: %s",
2108                                          isc_result_totext(result));
2109                         return (result);
2110                 }
2111                 isc_buffer_add(&target, hdrlen);
2112                 format = isc_buffer_getuint32(&target);
2113                 if (format != dns_masterformat_raw) {
2114                         (*callbacks->error)(callbacks,
2115                                             "dns_master_load: "
2116                                             "file format mismatch");
2117                         return (ISC_R_NOTIMPLEMENTED);
2118                 }
2119
2120                 version = isc_buffer_getuint32(&target);
2121                 if (version > DNS_RAWFORMAT_VERSION) {
2122                         (*callbacks->error)(callbacks,
2123                                             "dns_master_load: "
2124                                             "unsupported file format version");
2125                         return (ISC_R_NOTIMPLEMENTED);
2126                 }
2127
2128                 /* Empty read: currently, we do not use dumptime */
2129                 dumptime = isc_buffer_getuint32(&target);
2130                 POST(dumptime);
2131
2132                 lctx->first = ISC_FALSE;
2133         }
2134
2135         ISC_LIST_INIT(head);
2136         ISC_LIST_INIT(dummy);
2137         dns_rdatalist_init(&rdatalist);
2138
2139         /*
2140          * Allocate target_size of buffer space.  This is greater than twice
2141          * the maximum individual RR data size.
2142          */
2143         target_mem = isc_mem_get(mctx, target_size);
2144         if (target_mem == NULL) {
2145                 result = ISC_R_NOMEMORY;
2146                 goto cleanup;
2147         }
2148         isc_buffer_init(&target, target_mem, target_size);
2149
2150         dns_fixedname_init(&fixed);
2151         name = dns_fixedname_name(&fixed);
2152
2153         /*
2154          * In the following loop, we regard any error fatal regardless of
2155          * whether "MANYERRORS" is set in the context option.  This is because
2156          * normal errors should already have been checked at creation time.
2157          * Besides, it is very unlikely that we can recover from an error
2158          * in this format, and so trying to continue parsing erroneous data
2159          * does not really make sense.
2160          */
2161         for (loop_cnt = 0;
2162              (lctx->loop_cnt == 0 || loop_cnt < lctx->loop_cnt);
2163              loop_cnt++) {
2164                 unsigned int i, rdcount;
2165                 isc_uint16_t namelen;
2166                 isc_uint32_t totallen;
2167                 size_t minlen, readlen;
2168                 isc_boolean_t sequential_read = ISC_FALSE;
2169
2170                 /* Read the data length */
2171                 isc_buffer_clear(&target);
2172                 INSIST(isc_buffer_availablelength(&target) >=
2173                        sizeof(totallen));
2174                 result = isc_stdio_read(target.base, 1, sizeof(totallen),
2175                                         lctx->f, NULL);
2176                 if (result == ISC_R_EOF) {
2177                         result = ISC_R_SUCCESS;
2178                         done = ISC_TRUE;
2179                         break;
2180                 }
2181                 if (result != ISC_R_SUCCESS)
2182                         goto cleanup;
2183                 isc_buffer_add(&target, sizeof(totallen));
2184                 totallen = isc_buffer_getuint32(&target);
2185                 /*
2186                  * Validation: the input data must at least contain the common
2187                  * header.
2188                  */
2189                 minlen = sizeof(totallen) + sizeof(isc_uint16_t) +
2190                         sizeof(isc_uint16_t) + sizeof(isc_uint16_t) +
2191                         sizeof(isc_uint32_t) + sizeof(isc_uint32_t);
2192                 if (totallen < minlen) {
2193                         result = ISC_R_RANGE;
2194                         goto cleanup;
2195                 }
2196                 totallen -= sizeof(totallen);
2197
2198                 isc_buffer_clear(&target);
2199                 if (totallen > isc_buffer_availablelength(&target)) {
2200                         /*
2201                          * The default buffer size should typically be large
2202                          * enough to store the entire RRset.  We could try to
2203                          * allocate enough space if this is not the case, but
2204                          * it might cause a hazardous result when "totallen"
2205                          * is forged.  Thus, we'd rather take an inefficient
2206                          * but robust approach in this atypical case: read
2207                          * data step by step, and commit partial data when
2208                          * necessary.  Note that the buffer must be large
2209                          * enough to store the "header part", owner name, and
2210                          * at least one rdata (however large it is).
2211                          */
2212                         sequential_read = ISC_TRUE;
2213                         readlen = minlen - sizeof(totallen);
2214                 } else {
2215                         /*
2216                          * Typical case.  We can read the whole RRset at once
2217                          * with the default buffer.
2218                          */
2219                         readlen = totallen;
2220                 }
2221                 result = isc_stdio_read(target.base, 1, readlen,
2222                                         lctx->f, NULL);
2223                 if (result != ISC_R_SUCCESS)
2224                         goto cleanup;
2225                 isc_buffer_add(&target, readlen);
2226
2227                 /* Construct RRset headers */
2228                 rdatalist.rdclass = isc_buffer_getuint16(&target);
2229                 rdatalist.type = isc_buffer_getuint16(&target);
2230                 rdatalist.covers = isc_buffer_getuint16(&target);
2231                 rdatalist.ttl =  isc_buffer_getuint32(&target);
2232                 rdcount = isc_buffer_getuint32(&target);
2233                 if (rdcount == 0) {
2234                         result = ISC_R_RANGE;
2235                         goto cleanup;
2236                 }
2237                 INSIST(isc_buffer_consumedlength(&target) <= readlen);
2238
2239                 /* Owner name: length followed by name */
2240                 result = read_and_check(sequential_read, &target,
2241                                         sizeof(namelen), lctx->f);
2242                 if (result != ISC_R_SUCCESS)
2243                         goto cleanup;
2244                 namelen = isc_buffer_getuint16(&target);
2245                 if (namelen > sizeof(namebuf)) {
2246                         result = ISC_R_RANGE;
2247                         goto cleanup;
2248                 }
2249
2250                 result = read_and_check(sequential_read, &target, namelen,
2251                                         lctx->f);
2252                 if (result != ISC_R_SUCCESS)
2253                         goto cleanup;
2254
2255                 isc_buffer_setactive(&target, (unsigned int)namelen);
2256                 result = dns_name_fromwire(name, &target, &dctx, 0, NULL);
2257                 if (result != ISC_R_SUCCESS)
2258                         goto cleanup;
2259
2260                 /* Rdata contents. */
2261                 if (rdcount > rdata_size) {
2262                         dns_rdata_t *new_rdata = NULL;
2263
2264                         new_rdata = grow_rdata(rdcount + RDSZ, rdata,
2265                                                rdata_size, &head,
2266                                                &dummy, mctx);
2267                         if (new_rdata == NULL) {
2268                                 result = ISC_R_NOMEMORY;
2269                                 goto cleanup;
2270                         }
2271                         rdata_size = rdcount + RDSZ;
2272                         rdata = new_rdata;
2273                 }
2274
2275         continue_read:
2276                 for (i = 0; i < rdcount; i++) {
2277                         isc_uint16_t rdlen;
2278
2279                         dns_rdata_init(&rdata[i]);
2280
2281                         if (sequential_read &&
2282                             isc_buffer_availablelength(&target) < MINTSIZ) {
2283                                 unsigned int j;
2284
2285                                 INSIST(i > 0); /* detect an infinite loop */
2286
2287                                 /* Partial Commit. */
2288                                 ISC_LIST_APPEND(head, &rdatalist, link);
2289                                 result = commit(callbacks, lctx, &head, name,
2290                                                 NULL, 0);
2291                                 for (j = 0; j < i; j++) {
2292                                         ISC_LIST_UNLINK(rdatalist.rdata,
2293                                                         &rdata[j], link);
2294                                         dns_rdata_reset(&rdata[j]);
2295                                 }
2296                                 if (result != ISC_R_SUCCESS)
2297                                         goto cleanup;
2298
2299                                 /* Rewind the buffer and continue */
2300                                 isc_buffer_clear(&target);
2301
2302                                 rdcount -= i;
2303
2304                                 goto continue_read;
2305                         }
2306
2307                         /* rdata length */
2308                         result = read_and_check(sequential_read, &target,
2309                                                 sizeof(rdlen), lctx->f);
2310                         if (result != ISC_R_SUCCESS)
2311                                 goto cleanup;
2312                         rdlen = isc_buffer_getuint16(&target);
2313
2314                         /* rdata */
2315                         result = read_and_check(sequential_read, &target,
2316                                                 rdlen, lctx->f);
2317                         if (result != ISC_R_SUCCESS)
2318                                 goto cleanup;
2319                         isc_buffer_setactive(&target, (unsigned int)rdlen);
2320                         /*
2321                          * It is safe to have the source active region and
2322                          * the target available region be the same if
2323                          * decompression is disabled (see dctx above) and we
2324                          * are not downcasing names (options == 0).
2325                          */
2326                         isc_buffer_init(&buf, isc_buffer_current(&target),
2327                                         (unsigned int)rdlen);
2328                         result = dns_rdata_fromwire(&rdata[i],
2329                                                     rdatalist.rdclass,
2330                                                     rdatalist.type, &target,
2331                                                     &dctx, 0, &buf);
2332                         if (result != ISC_R_SUCCESS)
2333                                 goto cleanup;
2334                         ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link);
2335                 }
2336
2337                 /*
2338                  * Sanity check.  Still having remaining space is not
2339                  * necessarily critical, but it very likely indicates broken
2340                  * or malformed data.
2341                  */
2342                 if (isc_buffer_remaininglength(&target) != 0) {
2343                         result = ISC_R_RANGE;
2344                         goto cleanup;
2345                 }
2346
2347                 ISC_LIST_APPEND(head, &rdatalist, link);
2348
2349                 /* Commit this RRset.  rdatalist will be unlinked. */
2350                 result = commit(callbacks, lctx, &head, name, NULL, 0);
2351
2352                 for (i = 0; i < rdcount; i++) {
2353                         ISC_LIST_UNLINK(rdatalist.rdata, &rdata[i], link);
2354                         dns_rdata_reset(&rdata[i]);
2355                 }
2356
2357                 if (result != ISC_R_SUCCESS)
2358                         goto cleanup;
2359         }
2360
2361         if (!done) {
2362                 INSIST(lctx->done != NULL && lctx->task != NULL);
2363                 result = DNS_R_CONTINUE;
2364         } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS)
2365                 result = lctx->result;
2366
2367  cleanup:
2368         if (rdata != NULL)
2369                 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
2370         if (target_mem != NULL)
2371                 isc_mem_put(mctx, target_mem, target_size);
2372         if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE) {
2373                 (*callbacks->error)(callbacks, "dns_master_load: %s",
2374                                     dns_result_totext(result));
2375         }
2376
2377         return (result);
2378 }
2379
2380 isc_result_t
2381 dns_master_loadfile(const char *master_file, dns_name_t *top,
2382                     dns_name_t *origin,
2383                     dns_rdataclass_t zclass, unsigned int options,
2384                     dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2385 {
2386         return (dns_master_loadfile3(master_file, top, origin, zclass, options,
2387                                      0, callbacks, mctx, dns_masterformat_text));
2388 }
2389
2390 isc_result_t
2391 dns_master_loadfile2(const char *master_file, dns_name_t *top,
2392                      dns_name_t *origin,
2393                      dns_rdataclass_t zclass, unsigned int options,
2394                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
2395                      dns_masterformat_t format)
2396 {
2397         return (dns_master_loadfile3(master_file, top, origin, zclass, options,
2398                                      0, callbacks, mctx, format));
2399 }
2400
2401 isc_result_t
2402 dns_master_loadfile3(const char *master_file, dns_name_t *top,
2403                      dns_name_t *origin, dns_rdataclass_t zclass,
2404                      unsigned int options, isc_uint32_t resign,
2405                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
2406                      dns_masterformat_t format)
2407 {
2408         dns_loadctx_t *lctx = NULL;
2409         isc_result_t result;
2410
2411         result = loadctx_create(format, mctx, options, resign, top, zclass,
2412                                 origin, callbacks, NULL, NULL, NULL, NULL,
2413                                 &lctx);
2414         if (result != ISC_R_SUCCESS)
2415                 return (result);
2416
2417         result = (lctx->openfile)(lctx, master_file);
2418         if (result != ISC_R_SUCCESS)
2419                 goto cleanup;
2420
2421         result = (lctx->load)(lctx);
2422         INSIST(result != DNS_R_CONTINUE);
2423
2424  cleanup:
2425         dns_loadctx_detach(&lctx);
2426         return (result);
2427 }
2428
2429 isc_result_t
2430 dns_master_loadfileinc(const char *master_file, dns_name_t *top,
2431                        dns_name_t *origin, dns_rdataclass_t zclass,
2432                        unsigned int options, dns_rdatacallbacks_t *callbacks,
2433                        isc_task_t *task, dns_loaddonefunc_t done,
2434                        void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx)
2435 {
2436         return (dns_master_loadfileinc3(master_file, top, origin, zclass,
2437                                         options, 0, callbacks, task, done,
2438                                         done_arg, lctxp, mctx,
2439                                         dns_masterformat_text));
2440 }
2441
2442 isc_result_t
2443 dns_master_loadfileinc2(const char *master_file, dns_name_t *top,
2444                         dns_name_t *origin, dns_rdataclass_t zclass,
2445                         unsigned int options, dns_rdatacallbacks_t *callbacks,
2446                         isc_task_t *task, dns_loaddonefunc_t done,
2447                         void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx,
2448                         dns_masterformat_t format)
2449 {
2450         return (dns_master_loadfileinc3(master_file, top, origin, zclass,
2451                                         options, 0, callbacks, task, done,
2452                                         done_arg, lctxp, mctx, format));
2453 }
2454
2455 isc_result_t
2456 dns_master_loadfileinc3(const char *master_file, dns_name_t *top,
2457                         dns_name_t *origin, dns_rdataclass_t zclass,
2458                         unsigned int options, isc_uint32_t resign,
2459                         dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2460                         dns_loaddonefunc_t done, void *done_arg,
2461                         dns_loadctx_t **lctxp, isc_mem_t *mctx,
2462                         dns_masterformat_t format)
2463 {
2464         dns_loadctx_t *lctx = NULL;
2465         isc_result_t result;
2466
2467         REQUIRE(task != NULL);
2468         REQUIRE(done != NULL);
2469
2470         result = loadctx_create(format, mctx, options, resign, top, zclass,
2471                                 origin, callbacks, task, done, done_arg, NULL,
2472                                 &lctx);
2473         if (result != ISC_R_SUCCESS)
2474                 return (result);
2475
2476         result = (lctx->openfile)(lctx, master_file);
2477         if (result != ISC_R_SUCCESS)
2478                 goto cleanup;
2479
2480         result = task_send(lctx);
2481         if (result == ISC_R_SUCCESS) {
2482                 dns_loadctx_attach(lctx, lctxp);
2483                 return (DNS_R_CONTINUE);
2484         }
2485
2486  cleanup:
2487         dns_loadctx_detach(&lctx);
2488         return (result);
2489 }
2490
2491 isc_result_t
2492 dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
2493                       dns_rdataclass_t zclass, unsigned int options,
2494                       dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2495 {
2496         isc_result_t result;
2497         dns_loadctx_t *lctx = NULL;
2498
2499         REQUIRE(stream != NULL);
2500
2501         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2502                                 zclass, origin, callbacks, NULL, NULL, NULL,
2503                                 NULL, &lctx);
2504         if (result != ISC_R_SUCCESS)
2505                 goto cleanup;
2506
2507         result = isc_lex_openstream(lctx->lex, stream);
2508         if (result != ISC_R_SUCCESS)
2509                 goto cleanup;
2510
2511         result = (lctx->load)(lctx);
2512         INSIST(result != DNS_R_CONTINUE);
2513
2514  cleanup:
2515         if (lctx != NULL)
2516                 dns_loadctx_detach(&lctx);
2517         return (result);
2518 }
2519
2520 isc_result_t
2521 dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
2522                          dns_rdataclass_t zclass, unsigned int options,
2523                          dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2524                          dns_loaddonefunc_t done, void *done_arg,
2525                          dns_loadctx_t **lctxp, isc_mem_t *mctx)
2526 {
2527         isc_result_t result;
2528         dns_loadctx_t *lctx = NULL;
2529
2530         REQUIRE(stream != NULL);
2531         REQUIRE(task != NULL);
2532         REQUIRE(done != NULL);
2533
2534         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2535                                 zclass, origin, callbacks, task, done,
2536                                 done_arg, NULL, &lctx);
2537         if (result != ISC_R_SUCCESS)
2538                 goto cleanup;
2539
2540         result = isc_lex_openstream(lctx->lex, stream);
2541         if (result != ISC_R_SUCCESS)
2542                 goto cleanup;
2543
2544         result = task_send(lctx);
2545         if (result == ISC_R_SUCCESS) {
2546                 dns_loadctx_attach(lctx, lctxp);
2547                 return (DNS_R_CONTINUE);
2548         }
2549
2550  cleanup:
2551         if (lctx != NULL)
2552                 dns_loadctx_detach(&lctx);
2553         return (result);
2554 }
2555
2556 isc_result_t
2557 dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
2558                       dns_name_t *origin, dns_rdataclass_t zclass,
2559                       unsigned int options,
2560                       dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2561 {
2562         isc_result_t result;
2563         dns_loadctx_t *lctx = NULL;
2564
2565         REQUIRE(buffer != NULL);
2566
2567         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2568                                 zclass, origin, callbacks, NULL, NULL, NULL,
2569                                 NULL, &lctx);
2570         if (result != ISC_R_SUCCESS)
2571                 return (result);
2572
2573         result = isc_lex_openbuffer(lctx->lex, buffer);
2574         if (result != ISC_R_SUCCESS)
2575                 goto cleanup;
2576
2577         result = (lctx->load)(lctx);
2578         INSIST(result != DNS_R_CONTINUE);
2579
2580  cleanup:
2581         dns_loadctx_detach(&lctx);
2582         return (result);
2583 }
2584
2585 isc_result_t
2586 dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
2587                          dns_name_t *origin, dns_rdataclass_t zclass,
2588                          unsigned int options,
2589                          dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2590                          dns_loaddonefunc_t done, void *done_arg,
2591                          dns_loadctx_t **lctxp, isc_mem_t *mctx)
2592 {
2593         isc_result_t result;
2594         dns_loadctx_t *lctx = NULL;
2595
2596         REQUIRE(buffer != NULL);
2597         REQUIRE(task != NULL);
2598         REQUIRE(done != NULL);
2599
2600         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2601                                 zclass, origin, callbacks, task, done,
2602                                 done_arg, NULL, &lctx);
2603         if (result != ISC_R_SUCCESS)
2604                 return (result);
2605
2606         result = isc_lex_openbuffer(lctx->lex, buffer);
2607         if (result != ISC_R_SUCCESS)
2608                 goto cleanup;
2609
2610         result = task_send(lctx);
2611         if (result == ISC_R_SUCCESS) {
2612                 dns_loadctx_attach(lctx, lctxp);
2613                 return (DNS_R_CONTINUE);
2614         }
2615
2616  cleanup:
2617         dns_loadctx_detach(&lctx);
2618         return (result);
2619 }
2620
2621 isc_result_t
2622 dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top,
2623                      dns_name_t *origin, dns_rdataclass_t zclass,
2624                      unsigned int options,
2625                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2626 {
2627         isc_result_t result;
2628         dns_loadctx_t *lctx = NULL;
2629
2630         REQUIRE(lex != NULL);
2631
2632         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2633                                 zclass, origin, callbacks, NULL, NULL, NULL,
2634                                 lex, &lctx);
2635         if (result != ISC_R_SUCCESS)
2636                 return (result);
2637
2638         result = (lctx->load)(lctx);
2639         INSIST(result != DNS_R_CONTINUE);
2640
2641         dns_loadctx_detach(&lctx);
2642         return (result);
2643 }
2644
2645 isc_result_t
2646 dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top,
2647                         dns_name_t *origin, dns_rdataclass_t zclass,
2648                         unsigned int options,
2649                         dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2650                         dns_loaddonefunc_t done, void *done_arg,
2651                         dns_loadctx_t **lctxp, isc_mem_t *mctx)
2652 {
2653         isc_result_t result;
2654         dns_loadctx_t *lctx = NULL;
2655
2656         REQUIRE(lex != NULL);
2657         REQUIRE(task != NULL);
2658         REQUIRE(done != NULL);
2659
2660         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2661                                 zclass, origin, callbacks, task, done,
2662                                 done_arg, lex, &lctx);
2663         if (result != ISC_R_SUCCESS)
2664                 return (result);
2665
2666         result = task_send(lctx);
2667         if (result == ISC_R_SUCCESS) {
2668                 dns_loadctx_attach(lctx, lctxp);
2669                 return (DNS_R_CONTINUE);
2670         }
2671
2672         dns_loadctx_detach(&lctx);
2673         return (result);
2674 }
2675
2676 /*
2677  * Grow the slab of dns_rdatalist_t structures.
2678  * Re-link glue and current list.
2679  */
2680 static dns_rdatalist_t *
2681 grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
2682                rdatalist_head_t *current, rdatalist_head_t *glue,
2683                isc_mem_t *mctx)
2684 {
2685         dns_rdatalist_t *new;
2686         int rdlcount = 0;
2687         ISC_LIST(dns_rdatalist_t) save;
2688         dns_rdatalist_t *this;
2689
2690         new = isc_mem_get(mctx, new_len * sizeof(*new));
2691         if (new == NULL)
2692                 return (NULL);
2693
2694         ISC_LIST_INIT(save);
2695         while ((this = ISC_LIST_HEAD(*current)) != NULL) {
2696                 ISC_LIST_UNLINK(*current, this, link);
2697                 ISC_LIST_APPEND(save, this, link);
2698         }
2699         while ((this = ISC_LIST_HEAD(save)) != NULL) {
2700                 ISC_LIST_UNLINK(save, this, link);
2701                 INSIST(rdlcount < new_len);
2702                 new[rdlcount] = *this;
2703                 ISC_LIST_APPEND(*current, &new[rdlcount], link);
2704                 rdlcount++;
2705         }
2706
2707         ISC_LIST_INIT(save);
2708         while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
2709                 ISC_LIST_UNLINK(*glue, this, link);
2710                 ISC_LIST_APPEND(save, this, link);
2711         }
2712         while ((this = ISC_LIST_HEAD(save)) != NULL) {
2713                 ISC_LIST_UNLINK(save, this, link);
2714                 INSIST(rdlcount < new_len);
2715                 new[rdlcount] = *this;
2716                 ISC_LIST_APPEND(*glue, &new[rdlcount], link);
2717                 rdlcount++;
2718         }
2719
2720         INSIST(rdlcount == old_len);
2721         if (old != NULL)
2722                 isc_mem_put(mctx, old, old_len * sizeof(*old));
2723         return (new);
2724 }
2725
2726 /*
2727  * Grow the slab of rdata structs.
2728  * Re-link the current and glue chains.
2729  */
2730 static dns_rdata_t *
2731 grow_rdata(int new_len, dns_rdata_t *old, int old_len,
2732            rdatalist_head_t *current, rdatalist_head_t *glue,
2733            isc_mem_t *mctx)
2734 {
2735         dns_rdata_t *new;
2736         int rdcount = 0;
2737         ISC_LIST(dns_rdata_t) save;
2738         dns_rdatalist_t *this;
2739         dns_rdata_t *rdata;
2740
2741         new = isc_mem_get(mctx, new_len * sizeof(*new));
2742         if (new == NULL)
2743                 return (NULL);
2744         memset(new, 0, new_len * sizeof(*new));
2745
2746         /*
2747          * Copy current relinking.
2748          */
2749         this = ISC_LIST_HEAD(*current);
2750         while (this != NULL) {
2751                 ISC_LIST_INIT(save);
2752                 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
2753                         ISC_LIST_UNLINK(this->rdata, rdata, link);
2754                         ISC_LIST_APPEND(save, rdata, link);
2755                 }
2756                 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
2757                         ISC_LIST_UNLINK(save, rdata, link);
2758                         INSIST(rdcount < new_len);
2759                         new[rdcount] = *rdata;
2760                         ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
2761                         rdcount++;
2762                 }
2763                 this = ISC_LIST_NEXT(this, link);
2764         }
2765
2766         /*
2767          * Copy glue relinking.
2768          */
2769         this = ISC_LIST_HEAD(*glue);
2770         while (this != NULL) {
2771                 ISC_LIST_INIT(save);
2772                 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
2773                         ISC_LIST_UNLINK(this->rdata, rdata, link);
2774                         ISC_LIST_APPEND(save, rdata, link);
2775                 }
2776                 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
2777                         ISC_LIST_UNLINK(save, rdata, link);
2778                         INSIST(rdcount < new_len);
2779                         new[rdcount] = *rdata;
2780                         ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
2781                         rdcount++;
2782                 }
2783                 this = ISC_LIST_NEXT(this, link);
2784         }
2785         INSIST(rdcount == old_len || rdcount == 0);
2786         if (old != NULL)
2787                 isc_mem_put(mctx, old, old_len * sizeof(*old));
2788         return (new);
2789 }
2790
2791 static isc_uint32_t
2792 resign_fromlist(dns_rdatalist_t *this, isc_uint32_t resign) {
2793         dns_rdata_t *rdata;
2794         dns_rdata_rrsig_t sig;
2795         isc_uint32_t when;
2796
2797         rdata = ISC_LIST_HEAD(this->rdata);
2798         INSIST(rdata != NULL);
2799         (void)dns_rdata_tostruct(rdata, &sig, NULL);
2800         when = sig.timeexpire - resign;
2801
2802         rdata = ISC_LIST_NEXT(rdata, link);
2803         while (rdata != NULL) {
2804                 (void)dns_rdata_tostruct(rdata, &sig, NULL);
2805                 if (sig.timeexpire - resign < when)
2806                         when = sig.timeexpire - resign;
2807                 rdata = ISC_LIST_NEXT(rdata, link);
2808         }
2809         return (when);
2810 }
2811
2812 /*
2813  * Convert each element from a rdatalist_t to rdataset then call commit.
2814  * Unlink each element as we go.
2815  */
2816
2817 static isc_result_t
2818 commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
2819        rdatalist_head_t *head, dns_name_t *owner,
2820        const char *source, unsigned int line)
2821 {
2822         dns_rdatalist_t *this;
2823         dns_rdataset_t dataset;
2824         isc_result_t result;
2825         char namebuf[DNS_NAME_FORMATSIZE];
2826         void    (*error)(struct dns_rdatacallbacks *, const char *, ...);
2827
2828         this = ISC_LIST_HEAD(*head);
2829         error = callbacks->error;
2830
2831         if (this == NULL)
2832                 return (ISC_R_SUCCESS);
2833         do {
2834                 dns_rdataset_init(&dataset);
2835                 RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset)
2836                               == ISC_R_SUCCESS);
2837                 dataset.trust = dns_trust_ultimate;
2838                 /*
2839                  * If this is a secure dynamic zone set the re-signing time.
2840                  */
2841                 if (dataset.type == dns_rdatatype_rrsig &&
2842                     (lctx->options & DNS_MASTER_RESIGN) != 0) {
2843                         dataset.attributes |= DNS_RDATASETATTR_RESIGN;
2844                         dns_name_format(owner, namebuf, sizeof(namebuf));
2845                         dataset.resign = resign_fromlist(this, lctx->resign);
2846                 }
2847                 result = ((*callbacks->add)(callbacks->add_private, owner,
2848                                             &dataset));
2849                 if (result == ISC_R_NOMEMORY) {
2850                         (*error)(callbacks, "dns_master_load: %s",
2851                                  dns_result_totext(result));
2852                 } else if (result != ISC_R_SUCCESS) {
2853                         dns_name_format(owner, namebuf, sizeof(namebuf));
2854                         if (source != NULL) {
2855                                 (*error)(callbacks, "%s: %s:%lu: %s: %s",
2856                                          "dns_master_load", source, line,
2857                                          namebuf, dns_result_totext(result));
2858                         } else {
2859                                 (*error)(callbacks, "%s: %s: %s",
2860                                          "dns_master_load", namebuf,
2861                                          dns_result_totext(result));
2862                         }
2863                 }
2864                 if (MANYERRS(lctx, result))
2865                         SETRESULT(lctx, result);
2866                 else if (result != ISC_R_SUCCESS)
2867                         return (result);
2868                 ISC_LIST_UNLINK(*head, this, link);
2869                 this = ISC_LIST_HEAD(*head);
2870         } while (this != NULL);
2871         return (ISC_R_SUCCESS);
2872 }
2873
2874 /*
2875  * Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
2876  */
2877
2878 static isc_boolean_t
2879 is_glue(rdatalist_head_t *head, dns_name_t *owner) {
2880         dns_rdatalist_t *this;
2881         dns_rdata_t *rdata;
2882         isc_region_t region;
2883         dns_name_t name;
2884
2885         /*
2886          * Find NS rrset.
2887          */
2888         this = ISC_LIST_HEAD(*head);
2889         while (this != NULL) {
2890                 if (this->type == dns_rdatatype_ns)
2891                         break;
2892                 this = ISC_LIST_NEXT(this, link);
2893         }
2894         if (this == NULL)
2895                 return (ISC_FALSE);
2896
2897         rdata = ISC_LIST_HEAD(this->rdata);
2898         while (rdata != NULL) {
2899                 dns_name_init(&name, NULL);
2900                 dns_rdata_toregion(rdata, &region);
2901                 dns_name_fromregion(&name, &region);
2902                 if (dns_name_compare(&name, owner) == 0)
2903                         return (ISC_TRUE);
2904                 rdata = ISC_LIST_NEXT(rdata, link);
2905         }
2906         return (ISC_FALSE);
2907 }
2908
2909 static void
2910 load_quantum(isc_task_t *task, isc_event_t *event) {
2911         isc_result_t result;
2912         dns_loadctx_t *lctx;
2913
2914         REQUIRE(event != NULL);
2915         lctx = event->ev_arg;
2916         REQUIRE(DNS_LCTX_VALID(lctx));
2917
2918         if (lctx->canceled)
2919                 result = ISC_R_CANCELED;
2920         else
2921                 result = (lctx->load)(lctx);
2922         if (result == DNS_R_CONTINUE) {
2923                 event->ev_arg = lctx;
2924                 isc_task_send(task, &event);
2925         } else {
2926                 (lctx->done)(lctx->done_arg, result);
2927                 isc_event_free(&event);
2928                 dns_loadctx_detach(&lctx);
2929         }
2930 }
2931
2932 static isc_result_t
2933 task_send(dns_loadctx_t *lctx) {
2934         isc_event_t *event;
2935
2936         event = isc_event_allocate(lctx->mctx, NULL,
2937                                    DNS_EVENT_MASTERQUANTUM,
2938                                    load_quantum, lctx, sizeof(*event));
2939         if (event == NULL)
2940                 return (ISC_R_NOMEMORY);
2941         isc_task_send(lctx->task, &event);
2942         return (ISC_R_SUCCESS);
2943 }
2944
2945 void
2946 dns_loadctx_cancel(dns_loadctx_t *lctx) {
2947         REQUIRE(DNS_LCTX_VALID(lctx));
2948
2949         LOCK(&lctx->lock);
2950         lctx->canceled = ISC_TRUE;
2951         UNLOCK(&lctx->lock);
2952 }