]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/bind9/lib/dns/master.c
Fix multiple Denial of Service vulnerabilities with named(8).
[FreeBSD/releng/9.0.git] / contrib / bind9 / lib / dns / master.c
1 /*
2  * Copyright (C) 2004-2009, 2011  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: master.c,v 1.178.346.2 2011-03-12 04:59:17 tbox Exp $ */
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         isc_region_t r;
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;
2088         unsigned char *target_mem = NULL;
2089
2090         REQUIRE(DNS_LCTX_VALID(lctx));
2091         callbacks = lctx->callbacks;
2092
2093         if (lctx->first) {
2094                 dns_masterrawheader_t header;
2095                 isc_uint32_t format, version, dumptime;
2096                 size_t hdrlen = sizeof(format) + sizeof(version) +
2097                         sizeof(dumptime);
2098
2099                 INSIST(hdrlen <= sizeof(header));
2100                 isc_buffer_init(&target, &header, sizeof(header));
2101
2102                 result = isc_stdio_read(&header, 1, hdrlen, lctx->f, NULL);
2103                 if (result != ISC_R_SUCCESS) {
2104                         UNEXPECTED_ERROR(__FILE__, __LINE__,
2105                                          "isc_stdio_read failed: %s",
2106                                          isc_result_totext(result));
2107                         return (result);
2108                 }
2109                 isc_buffer_add(&target, hdrlen);
2110                 format = isc_buffer_getuint32(&target);
2111                 if (format != dns_masterformat_raw) {
2112                         (*callbacks->error)(callbacks,
2113                                             "dns_master_load: "
2114                                             "file format mismatch");
2115                         return (ISC_R_NOTIMPLEMENTED);
2116                 }
2117
2118                 version = isc_buffer_getuint32(&target);
2119                 if (version > DNS_RAWFORMAT_VERSION) {
2120                         (*callbacks->error)(callbacks,
2121                                             "dns_master_load: "
2122                                             "unsupported file format version");
2123                         return (ISC_R_NOTIMPLEMENTED);
2124                 }
2125
2126                 /* Empty read: currently, we do not use dumptime */
2127                 dumptime = isc_buffer_getuint32(&target);
2128                 POST(dumptime);
2129
2130                 lctx->first = ISC_FALSE;
2131         }
2132
2133         ISC_LIST_INIT(head);
2134         ISC_LIST_INIT(dummy);
2135         dns_rdatalist_init(&rdatalist);
2136
2137         /*
2138          * Allocate target_size of buffer space.  This is greater than twice
2139          * the maximum individual RR data size.
2140          */
2141         target_mem = isc_mem_get(mctx, target_size);
2142         if (target_mem == NULL) {
2143                 result = ISC_R_NOMEMORY;
2144                 goto cleanup;
2145         }
2146         isc_buffer_init(&target, target_mem, target_size);
2147
2148         /*
2149          * In the following loop, we regard any error fatal regardless of
2150          * whether "MANYERRORS" is set in the context option.  This is because
2151          * normal errors should already have been checked at creation time.
2152          * Besides, it is very unlikely that we can recover from an error
2153          * in this format, and so trying to continue parsing erroneous data
2154          * does not really make sense.
2155          */
2156         for (loop_cnt = 0;
2157              (lctx->loop_cnt == 0 || loop_cnt < lctx->loop_cnt);
2158              loop_cnt++) {
2159                 unsigned int i, rdcount, consumed_name;
2160                 isc_uint16_t namelen;
2161                 isc_uint32_t totallen;
2162                 size_t minlen, readlen;
2163                 isc_boolean_t sequential_read = ISC_FALSE;
2164
2165                 /* Read the data length */
2166                 isc_buffer_clear(&target);
2167                 INSIST(isc_buffer_availablelength(&target) >=
2168                        sizeof(totallen));
2169                 result = isc_stdio_read(target.base, 1, sizeof(totallen),
2170                                         lctx->f, NULL);
2171                 if (result == ISC_R_EOF) {
2172                         result = ISC_R_SUCCESS;
2173                         done = ISC_TRUE;
2174                         break;
2175                 }
2176                 if (result != ISC_R_SUCCESS)
2177                         goto cleanup;
2178                 isc_buffer_add(&target, sizeof(totallen));
2179                 totallen = isc_buffer_getuint32(&target);
2180                 /*
2181                  * Validation: the input data must at least contain the common
2182                  * header.
2183                  */
2184                 minlen = sizeof(totallen) + sizeof(isc_uint16_t) +
2185                         sizeof(isc_uint16_t) + sizeof(isc_uint16_t) +
2186                         sizeof(isc_uint32_t) + sizeof(isc_uint32_t);
2187                 if (totallen < minlen) {
2188                         result = ISC_R_RANGE;
2189                         goto cleanup;
2190                 }
2191                 totallen -= sizeof(totallen);
2192
2193                 isc_buffer_clear(&target);
2194                 if (totallen > isc_buffer_availablelength(&target)) {
2195                         /*
2196                          * The default buffer size should typically be large
2197                          * enough to store the entire RRset.  We could try to
2198                          * allocate enough space if this is not the case, but
2199                          * it might cause a hazardous result when "totallen"
2200                          * is forged.  Thus, we'd rather take an inefficient
2201                          * but robust approach in this atypical case: read
2202                          * data step by step, and commit partial data when
2203                          * necessary.  Note that the buffer must be large
2204                          * enough to store the "header part", owner name, and
2205                          * at least one rdata (however large it is).
2206                          */
2207                         sequential_read = ISC_TRUE;
2208                         readlen = minlen - sizeof(totallen);
2209                 } else {
2210                         /*
2211                          * Typical case.  We can read the whole RRset at once
2212                          * with the default buffer.
2213                          */
2214                         readlen = totallen;
2215                 }
2216                 result = isc_stdio_read(target.base, 1, readlen,
2217                                         lctx->f, NULL);
2218                 if (result != ISC_R_SUCCESS)
2219                         goto cleanup;
2220                 isc_buffer_add(&target, readlen);
2221
2222                 /* Construct RRset headers */
2223                 rdatalist.rdclass = isc_buffer_getuint16(&target);
2224                 rdatalist.type = isc_buffer_getuint16(&target);
2225                 rdatalist.covers = isc_buffer_getuint16(&target);
2226                 rdatalist.ttl =  isc_buffer_getuint32(&target);
2227                 rdcount = isc_buffer_getuint32(&target);
2228                 if (rdcount == 0) {
2229                         result = ISC_R_RANGE;
2230                         goto cleanup;
2231                 }
2232                 INSIST(isc_buffer_consumedlength(&target) <= readlen);
2233
2234                 /* Owner name: length followed by name */
2235                 result = read_and_check(sequential_read, &target,
2236                                         sizeof(namelen), lctx->f);
2237                 if (result != ISC_R_SUCCESS)
2238                         goto cleanup;
2239                 namelen = isc_buffer_getuint16(&target);
2240                 if (namelen > sizeof(namebuf)) {
2241                         result = ISC_R_RANGE;
2242                         goto cleanup;
2243                 }
2244
2245                 result = read_and_check(sequential_read, &target, namelen,
2246                                         lctx->f);
2247                 if (result != ISC_R_SUCCESS)
2248                         goto cleanup;
2249                 isc_buffer_setactive(&target, (unsigned int)namelen);
2250                 isc_buffer_activeregion(&target, &r);
2251                 dns_name_init(&name, NULL);
2252                 dns_name_fromregion(&name, &r);
2253                 isc_buffer_forward(&target, (unsigned int)namelen);
2254                 consumed_name = isc_buffer_consumedlength(&target);
2255
2256                 /* Rdata contents. */
2257                 if (rdcount > rdata_size) {
2258                         dns_rdata_t *new_rdata = NULL;
2259
2260                         new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
2261                                                rdata_size, &head,
2262                                                &dummy, mctx);
2263                         if (new_rdata == NULL) {
2264                                 result = ISC_R_NOMEMORY;
2265                                 goto cleanup;
2266                         }
2267                         rdata_size += RDSZ;
2268                         rdata = new_rdata;
2269                 }
2270
2271         continue_read:
2272                 for (i = 0; i < rdcount; i++) {
2273                         isc_uint16_t rdlen;
2274
2275                         dns_rdata_init(&rdata[i]);
2276
2277                         if (sequential_read &&
2278                             isc_buffer_availablelength(&target) < MINTSIZ) {
2279                                 unsigned int j;
2280
2281                                 INSIST(i > 0); /* detect an infinite loop */
2282
2283                                 /* Partial Commit. */
2284                                 ISC_LIST_APPEND(head, &rdatalist, link);
2285                                 result = commit(callbacks, lctx, &head, &name,
2286                                                 NULL, 0);
2287                                 for (j = 0; j < i; j++) {
2288                                         ISC_LIST_UNLINK(rdatalist.rdata,
2289                                                         &rdata[j], link);
2290                                         dns_rdata_reset(&rdata[j]);
2291                                 }
2292                                 if (result != ISC_R_SUCCESS)
2293                                         goto cleanup;
2294
2295                                 /* Rewind the buffer and continue */
2296                                 isc_buffer_clear(&target);
2297                                 isc_buffer_add(&target, consumed_name);
2298                                 isc_buffer_forward(&target, consumed_name);
2299
2300                                 rdcount -= i;
2301
2302                                 goto continue_read;
2303                         }
2304
2305                         /* rdata length */
2306                         result = read_and_check(sequential_read, &target,
2307                                                 sizeof(rdlen), lctx->f);
2308                         if (result != ISC_R_SUCCESS)
2309                                 goto cleanup;
2310                         rdlen = isc_buffer_getuint16(&target);
2311
2312                         /* rdata */
2313                         result = read_and_check(sequential_read, &target,
2314                                                 rdlen, lctx->f);
2315                         if (result != ISC_R_SUCCESS)
2316                                 goto cleanup;
2317                         isc_buffer_setactive(&target, (unsigned int)rdlen);
2318                         isc_buffer_activeregion(&target, &r);
2319                         isc_buffer_forward(&target, (unsigned int)rdlen);
2320                         dns_rdata_fromregion(&rdata[i], rdatalist.rdclass,
2321                                              rdatalist.type, &r);
2322
2323                         ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link);
2324                 }
2325
2326                 /*
2327                  * Sanity check.  Still having remaining space is not
2328                  * necessarily critical, but it very likely indicates broken
2329                  * or malformed data.
2330                  */
2331                 if (isc_buffer_remaininglength(&target) != 0) {
2332                         result = ISC_R_RANGE;
2333                         goto cleanup;
2334                 }
2335
2336                 ISC_LIST_APPEND(head, &rdatalist, link);
2337
2338                 /* Commit this RRset.  rdatalist will be unlinked. */
2339                 result = commit(callbacks, lctx, &head, &name, NULL, 0);
2340
2341                 for (i = 0; i < rdcount; i++) {
2342                         ISC_LIST_UNLINK(rdatalist.rdata, &rdata[i], link);
2343                         dns_rdata_reset(&rdata[i]);
2344                 }
2345
2346                 if (result != ISC_R_SUCCESS)
2347                         goto cleanup;
2348         }
2349
2350         if (!done) {
2351                 INSIST(lctx->done != NULL && lctx->task != NULL);
2352                 result = DNS_R_CONTINUE;
2353         } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS)
2354                 result = lctx->result;
2355
2356  cleanup:
2357         if (rdata != NULL)
2358                 isc_mem_put(mctx, rdata, rdata_size * sizeof(*rdata));
2359         if (target_mem != NULL)
2360                 isc_mem_put(mctx, target_mem, target_size);
2361         if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE) {
2362                 (*callbacks->error)(callbacks, "dns_master_load: %s",
2363                                     dns_result_totext(result));
2364         }
2365
2366         return (result);
2367 }
2368
2369 isc_result_t
2370 dns_master_loadfile(const char *master_file, dns_name_t *top,
2371                     dns_name_t *origin,
2372                     dns_rdataclass_t zclass, unsigned int options,
2373                     dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2374 {
2375         return (dns_master_loadfile3(master_file, top, origin, zclass, options,
2376                                      0, callbacks, mctx, dns_masterformat_text));
2377 }
2378
2379 isc_result_t
2380 dns_master_loadfile2(const char *master_file, dns_name_t *top,
2381                      dns_name_t *origin,
2382                      dns_rdataclass_t zclass, unsigned int options,
2383                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
2384                      dns_masterformat_t format)
2385 {
2386         return (dns_master_loadfile3(master_file, top, origin, zclass, options,
2387                                      0, callbacks, mctx, format));
2388 }
2389
2390 isc_result_t
2391 dns_master_loadfile3(const char *master_file, dns_name_t *top,
2392                      dns_name_t *origin, dns_rdataclass_t zclass,
2393                      unsigned int options, isc_uint32_t resign,
2394                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx,
2395                      dns_masterformat_t format)
2396 {
2397         dns_loadctx_t *lctx = NULL;
2398         isc_result_t result;
2399
2400         result = loadctx_create(format, mctx, options, resign, top, zclass,
2401                                 origin, callbacks, NULL, NULL, NULL, NULL,
2402                                 &lctx);
2403         if (result != ISC_R_SUCCESS)
2404                 return (result);
2405
2406         result = (lctx->openfile)(lctx, master_file);
2407         if (result != ISC_R_SUCCESS)
2408                 goto cleanup;
2409
2410         result = (lctx->load)(lctx);
2411         INSIST(result != DNS_R_CONTINUE);
2412
2413  cleanup:
2414         dns_loadctx_detach(&lctx);
2415         return (result);
2416 }
2417
2418 isc_result_t
2419 dns_master_loadfileinc(const char *master_file, dns_name_t *top,
2420                        dns_name_t *origin, dns_rdataclass_t zclass,
2421                        unsigned int options, dns_rdatacallbacks_t *callbacks,
2422                        isc_task_t *task, dns_loaddonefunc_t done,
2423                        void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx)
2424 {
2425         return (dns_master_loadfileinc3(master_file, top, origin, zclass,
2426                                         options, 0, callbacks, task, done,
2427                                         done_arg, lctxp, mctx,
2428                                         dns_masterformat_text));
2429 }
2430
2431 isc_result_t
2432 dns_master_loadfileinc2(const char *master_file, dns_name_t *top,
2433                         dns_name_t *origin, dns_rdataclass_t zclass,
2434                         unsigned int options, dns_rdatacallbacks_t *callbacks,
2435                         isc_task_t *task, dns_loaddonefunc_t done,
2436                         void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx,
2437                         dns_masterformat_t format)
2438 {
2439         return (dns_master_loadfileinc3(master_file, top, origin, zclass,
2440                                         options, 0, callbacks, task, done,
2441                                         done_arg, lctxp, mctx, format));
2442 }
2443
2444 isc_result_t
2445 dns_master_loadfileinc3(const char *master_file, dns_name_t *top,
2446                         dns_name_t *origin, dns_rdataclass_t zclass,
2447                         unsigned int options, isc_uint32_t resign,
2448                         dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2449                         dns_loaddonefunc_t done, void *done_arg,
2450                         dns_loadctx_t **lctxp, isc_mem_t *mctx,
2451                         dns_masterformat_t format)
2452 {
2453         dns_loadctx_t *lctx = NULL;
2454         isc_result_t result;
2455
2456         REQUIRE(task != NULL);
2457         REQUIRE(done != NULL);
2458
2459         result = loadctx_create(format, mctx, options, resign, top, zclass,
2460                                 origin, callbacks, task, done, done_arg, NULL,
2461                                 &lctx);
2462         if (result != ISC_R_SUCCESS)
2463                 return (result);
2464
2465         result = (lctx->openfile)(lctx, master_file);
2466         if (result != ISC_R_SUCCESS)
2467                 goto cleanup;
2468
2469         result = task_send(lctx);
2470         if (result == ISC_R_SUCCESS) {
2471                 dns_loadctx_attach(lctx, lctxp);
2472                 return (DNS_R_CONTINUE);
2473         }
2474
2475  cleanup:
2476         dns_loadctx_detach(&lctx);
2477         return (result);
2478 }
2479
2480 isc_result_t
2481 dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
2482                       dns_rdataclass_t zclass, unsigned int options,
2483                       dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2484 {
2485         isc_result_t result;
2486         dns_loadctx_t *lctx = NULL;
2487
2488         REQUIRE(stream != NULL);
2489
2490         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2491                                 zclass, origin, callbacks, NULL, NULL, NULL,
2492                                 NULL, &lctx);
2493         if (result != ISC_R_SUCCESS)
2494                 goto cleanup;
2495
2496         result = isc_lex_openstream(lctx->lex, stream);
2497         if (result != ISC_R_SUCCESS)
2498                 goto cleanup;
2499
2500         result = (lctx->load)(lctx);
2501         INSIST(result != DNS_R_CONTINUE);
2502
2503  cleanup:
2504         if (lctx != NULL)
2505                 dns_loadctx_detach(&lctx);
2506         return (result);
2507 }
2508
2509 isc_result_t
2510 dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
2511                          dns_rdataclass_t zclass, unsigned int options,
2512                          dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2513                          dns_loaddonefunc_t done, void *done_arg,
2514                          dns_loadctx_t **lctxp, isc_mem_t *mctx)
2515 {
2516         isc_result_t result;
2517         dns_loadctx_t *lctx = NULL;
2518
2519         REQUIRE(stream != NULL);
2520         REQUIRE(task != NULL);
2521         REQUIRE(done != NULL);
2522
2523         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2524                                 zclass, origin, callbacks, task, done,
2525                                 done_arg, NULL, &lctx);
2526         if (result != ISC_R_SUCCESS)
2527                 goto cleanup;
2528
2529         result = isc_lex_openstream(lctx->lex, stream);
2530         if (result != ISC_R_SUCCESS)
2531                 goto cleanup;
2532
2533         result = task_send(lctx);
2534         if (result == ISC_R_SUCCESS) {
2535                 dns_loadctx_attach(lctx, lctxp);
2536                 return (DNS_R_CONTINUE);
2537         }
2538
2539  cleanup:
2540         if (lctx != NULL)
2541                 dns_loadctx_detach(&lctx);
2542         return (result);
2543 }
2544
2545 isc_result_t
2546 dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
2547                       dns_name_t *origin, dns_rdataclass_t zclass,
2548                       unsigned int options,
2549                       dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2550 {
2551         isc_result_t result;
2552         dns_loadctx_t *lctx = NULL;
2553
2554         REQUIRE(buffer != NULL);
2555
2556         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2557                                 zclass, origin, callbacks, NULL, NULL, NULL,
2558                                 NULL, &lctx);
2559         if (result != ISC_R_SUCCESS)
2560                 return (result);
2561
2562         result = isc_lex_openbuffer(lctx->lex, buffer);
2563         if (result != ISC_R_SUCCESS)
2564                 goto cleanup;
2565
2566         result = (lctx->load)(lctx);
2567         INSIST(result != DNS_R_CONTINUE);
2568
2569  cleanup:
2570         dns_loadctx_detach(&lctx);
2571         return (result);
2572 }
2573
2574 isc_result_t
2575 dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
2576                          dns_name_t *origin, dns_rdataclass_t zclass,
2577                          unsigned int options,
2578                          dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2579                          dns_loaddonefunc_t done, void *done_arg,
2580                          dns_loadctx_t **lctxp, isc_mem_t *mctx)
2581 {
2582         isc_result_t result;
2583         dns_loadctx_t *lctx = NULL;
2584
2585         REQUIRE(buffer != NULL);
2586         REQUIRE(task != NULL);
2587         REQUIRE(done != NULL);
2588
2589         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2590                                 zclass, origin, callbacks, task, done,
2591                                 done_arg, NULL, &lctx);
2592         if (result != ISC_R_SUCCESS)
2593                 return (result);
2594
2595         result = isc_lex_openbuffer(lctx->lex, buffer);
2596         if (result != ISC_R_SUCCESS)
2597                 goto cleanup;
2598
2599         result = task_send(lctx);
2600         if (result == ISC_R_SUCCESS) {
2601                 dns_loadctx_attach(lctx, lctxp);
2602                 return (DNS_R_CONTINUE);
2603         }
2604
2605  cleanup:
2606         dns_loadctx_detach(&lctx);
2607         return (result);
2608 }
2609
2610 isc_result_t
2611 dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top,
2612                      dns_name_t *origin, dns_rdataclass_t zclass,
2613                      unsigned int options,
2614                      dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
2615 {
2616         isc_result_t result;
2617         dns_loadctx_t *lctx = NULL;
2618
2619         REQUIRE(lex != NULL);
2620
2621         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2622                                 zclass, origin, callbacks, NULL, NULL, NULL,
2623                                 lex, &lctx);
2624         if (result != ISC_R_SUCCESS)
2625                 return (result);
2626
2627         result = (lctx->load)(lctx);
2628         INSIST(result != DNS_R_CONTINUE);
2629
2630         dns_loadctx_detach(&lctx);
2631         return (result);
2632 }
2633
2634 isc_result_t
2635 dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top,
2636                         dns_name_t *origin, dns_rdataclass_t zclass,
2637                         unsigned int options,
2638                         dns_rdatacallbacks_t *callbacks, isc_task_t *task,
2639                         dns_loaddonefunc_t done, void *done_arg,
2640                         dns_loadctx_t **lctxp, isc_mem_t *mctx)
2641 {
2642         isc_result_t result;
2643         dns_loadctx_t *lctx = NULL;
2644
2645         REQUIRE(lex != NULL);
2646         REQUIRE(task != NULL);
2647         REQUIRE(done != NULL);
2648
2649         result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
2650                                 zclass, origin, callbacks, task, done,
2651                                 done_arg, lex, &lctx);
2652         if (result != ISC_R_SUCCESS)
2653                 return (result);
2654
2655         result = task_send(lctx);
2656         if (result == ISC_R_SUCCESS) {
2657                 dns_loadctx_attach(lctx, lctxp);
2658                 return (DNS_R_CONTINUE);
2659         }
2660
2661         dns_loadctx_detach(&lctx);
2662         return (result);
2663 }
2664
2665 /*
2666  * Grow the slab of dns_rdatalist_t structures.
2667  * Re-link glue and current list.
2668  */
2669 static dns_rdatalist_t *
2670 grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
2671                rdatalist_head_t *current, rdatalist_head_t *glue,
2672                isc_mem_t *mctx)
2673 {
2674         dns_rdatalist_t *new;
2675         int rdlcount = 0;
2676         ISC_LIST(dns_rdatalist_t) save;
2677         dns_rdatalist_t *this;
2678
2679         new = isc_mem_get(mctx, new_len * sizeof(*new));
2680         if (new == NULL)
2681                 return (NULL);
2682
2683         ISC_LIST_INIT(save);
2684         while ((this = ISC_LIST_HEAD(*current)) != NULL) {
2685                 ISC_LIST_UNLINK(*current, this, link);
2686                 ISC_LIST_APPEND(save, this, link);
2687         }
2688         while ((this = ISC_LIST_HEAD(save)) != NULL) {
2689                 ISC_LIST_UNLINK(save, this, link);
2690                 new[rdlcount] = *this;
2691                 ISC_LIST_APPEND(*current, &new[rdlcount], link);
2692                 rdlcount++;
2693         }
2694
2695         ISC_LIST_INIT(save);
2696         while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
2697                 ISC_LIST_UNLINK(*glue, this, link);
2698                 ISC_LIST_APPEND(save, this, link);
2699         }
2700         while ((this = ISC_LIST_HEAD(save)) != NULL) {
2701                 ISC_LIST_UNLINK(save, this, link);
2702                 new[rdlcount] = *this;
2703                 ISC_LIST_APPEND(*glue, &new[rdlcount], link);
2704                 rdlcount++;
2705         }
2706
2707         INSIST(rdlcount == old_len);
2708         if (old != NULL)
2709                 isc_mem_put(mctx, old, old_len * sizeof(*old));
2710         return (new);
2711 }
2712
2713 /*
2714  * Grow the slab of rdata structs.
2715  * Re-link the current and glue chains.
2716  */
2717 static dns_rdata_t *
2718 grow_rdata(int new_len, dns_rdata_t *old, int old_len,
2719            rdatalist_head_t *current, rdatalist_head_t *glue,
2720            isc_mem_t *mctx)
2721 {
2722         dns_rdata_t *new;
2723         int rdcount = 0;
2724         ISC_LIST(dns_rdata_t) save;
2725         dns_rdatalist_t *this;
2726         dns_rdata_t *rdata;
2727
2728         new = isc_mem_get(mctx, new_len * sizeof(*new));
2729         if (new == NULL)
2730                 return (NULL);
2731         memset(new, 0, new_len * sizeof(*new));
2732
2733         /*
2734          * Copy current relinking.
2735          */
2736         this = ISC_LIST_HEAD(*current);
2737         while (this != NULL) {
2738                 ISC_LIST_INIT(save);
2739                 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
2740                         ISC_LIST_UNLINK(this->rdata, rdata, link);
2741                         ISC_LIST_APPEND(save, rdata, link);
2742                 }
2743                 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
2744                         ISC_LIST_UNLINK(save, rdata, link);
2745                         new[rdcount] = *rdata;
2746                         ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
2747                         rdcount++;
2748                 }
2749                 this = ISC_LIST_NEXT(this, link);
2750         }
2751
2752         /*
2753          * Copy glue relinking.
2754          */
2755         this = ISC_LIST_HEAD(*glue);
2756         while (this != NULL) {
2757                 ISC_LIST_INIT(save);
2758                 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
2759                         ISC_LIST_UNLINK(this->rdata, rdata, link);
2760                         ISC_LIST_APPEND(save, rdata, link);
2761                 }
2762                 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
2763                         ISC_LIST_UNLINK(save, rdata, link);
2764                         new[rdcount] = *rdata;
2765                         ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
2766                         rdcount++;
2767                 }
2768                 this = ISC_LIST_NEXT(this, link);
2769         }
2770         INSIST(rdcount == old_len);
2771         if (old != NULL)
2772                 isc_mem_put(mctx, old, old_len * sizeof(*old));
2773         return (new);
2774 }
2775
2776 static isc_uint32_t
2777 resign_fromlist(dns_rdatalist_t *this, isc_uint32_t resign) {
2778         dns_rdata_t *rdata;
2779         dns_rdata_rrsig_t sig;
2780         isc_uint32_t when;
2781
2782         rdata = ISC_LIST_HEAD(this->rdata);
2783         INSIST(rdata != NULL);
2784         (void)dns_rdata_tostruct(rdata, &sig, NULL);
2785         when = sig.timeexpire - resign;
2786
2787         rdata = ISC_LIST_NEXT(rdata, link);
2788         while (rdata != NULL) {
2789                 (void)dns_rdata_tostruct(rdata, &sig, NULL);
2790                 if (sig.timeexpire - resign < when)
2791                         when = sig.timeexpire - resign;
2792                 rdata = ISC_LIST_NEXT(rdata, link);
2793         }
2794         return (when);
2795 }
2796
2797 /*
2798  * Convert each element from a rdatalist_t to rdataset then call commit.
2799  * Unlink each element as we go.
2800  */
2801
2802 static isc_result_t
2803 commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
2804        rdatalist_head_t *head, dns_name_t *owner,
2805        const char *source, unsigned int line)
2806 {
2807         dns_rdatalist_t *this;
2808         dns_rdataset_t dataset;
2809         isc_result_t result;
2810         char namebuf[DNS_NAME_FORMATSIZE];
2811         void    (*error)(struct dns_rdatacallbacks *, const char *, ...);
2812
2813         this = ISC_LIST_HEAD(*head);
2814         error = callbacks->error;
2815
2816         if (this == NULL)
2817                 return (ISC_R_SUCCESS);
2818         do {
2819                 dns_rdataset_init(&dataset);
2820                 RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset)
2821                               == ISC_R_SUCCESS);
2822                 dataset.trust = dns_trust_ultimate;
2823                 /*
2824                  * If this is a secure dynamic zone set the re-signing time.
2825                  */
2826                 if (dataset.type == dns_rdatatype_rrsig &&
2827                     (lctx->options & DNS_MASTER_RESIGN) != 0) {
2828                         dataset.attributes |= DNS_RDATASETATTR_RESIGN;
2829                         dns_name_format(owner, namebuf, sizeof(namebuf));
2830                         dataset.resign = resign_fromlist(this, lctx->resign);
2831                 }
2832                 result = ((*callbacks->add)(callbacks->add_private, owner,
2833                                             &dataset));
2834                 if (result == ISC_R_NOMEMORY) {
2835                         (*error)(callbacks, "dns_master_load: %s",
2836                                  dns_result_totext(result));
2837                 } else if (result != ISC_R_SUCCESS) {
2838                         dns_name_format(owner, namebuf, sizeof(namebuf));
2839                         if (source != NULL) {
2840                                 (*error)(callbacks, "%s: %s:%lu: %s: %s",
2841                                          "dns_master_load", source, line,
2842                                          namebuf, dns_result_totext(result));
2843                         } else {
2844                                 (*error)(callbacks, "%s: %s: %s",
2845                                          "dns_master_load", namebuf,
2846                                          dns_result_totext(result));
2847                         }
2848                 }
2849                 if (MANYERRS(lctx, result))
2850                         SETRESULT(lctx, result);
2851                 else if (result != ISC_R_SUCCESS)
2852                         return (result);
2853                 ISC_LIST_UNLINK(*head, this, link);
2854                 this = ISC_LIST_HEAD(*head);
2855         } while (this != NULL);
2856         return (ISC_R_SUCCESS);
2857 }
2858
2859 /*
2860  * Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
2861  */
2862
2863 static isc_boolean_t
2864 is_glue(rdatalist_head_t *head, dns_name_t *owner) {
2865         dns_rdatalist_t *this;
2866         dns_rdata_t *rdata;
2867         isc_region_t region;
2868         dns_name_t name;
2869
2870         /*
2871          * Find NS rrset.
2872          */
2873         this = ISC_LIST_HEAD(*head);
2874         while (this != NULL) {
2875                 if (this->type == dns_rdatatype_ns)
2876                         break;
2877                 this = ISC_LIST_NEXT(this, link);
2878         }
2879         if (this == NULL)
2880                 return (ISC_FALSE);
2881
2882         rdata = ISC_LIST_HEAD(this->rdata);
2883         while (rdata != NULL) {
2884                 dns_name_init(&name, NULL);
2885                 dns_rdata_toregion(rdata, &region);
2886                 dns_name_fromregion(&name, &region);
2887                 if (dns_name_compare(&name, owner) == 0)
2888                         return (ISC_TRUE);
2889                 rdata = ISC_LIST_NEXT(rdata, link);
2890         }
2891         return (ISC_FALSE);
2892 }
2893
2894 static void
2895 load_quantum(isc_task_t *task, isc_event_t *event) {
2896         isc_result_t result;
2897         dns_loadctx_t *lctx;
2898
2899         REQUIRE(event != NULL);
2900         lctx = event->ev_arg;
2901         REQUIRE(DNS_LCTX_VALID(lctx));
2902
2903         if (lctx->canceled)
2904                 result = ISC_R_CANCELED;
2905         else
2906                 result = (lctx->load)(lctx);
2907         if (result == DNS_R_CONTINUE) {
2908                 event->ev_arg = lctx;
2909                 isc_task_send(task, &event);
2910         } else {
2911                 (lctx->done)(lctx->done_arg, result);
2912                 isc_event_free(&event);
2913                 dns_loadctx_detach(&lctx);
2914         }
2915 }
2916
2917 static isc_result_t
2918 task_send(dns_loadctx_t *lctx) {
2919         isc_event_t *event;
2920
2921         event = isc_event_allocate(lctx->mctx, NULL,
2922                                    DNS_EVENT_MASTERQUANTUM,
2923                                    load_quantum, lctx, sizeof(*event));
2924         if (event == NULL)
2925                 return (ISC_R_NOMEMORY);
2926         isc_task_send(lctx->task, &event);
2927         return (ISC_R_SUCCESS);
2928 }
2929
2930 void
2931 dns_loadctx_cancel(dns_loadctx_t *lctx) {
2932         REQUIRE(DNS_LCTX_VALID(lctx));
2933
2934         LOCK(&lctx->lock);
2935         lctx->canceled = ISC_TRUE;
2936         UNLOCK(&lctx->lock);
2937 }