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