Merge from vendor branch WPA_SUPPLICANT:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / master.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: master.c,v 1.122.2.9 2004/03/09 06:11:03 marka Exp $ */
19
20 #include <config.h>
21
22 #include <isc/event.h>
23 #include <isc/lex.h>
24 #include <isc/magic.h>
25 #include <isc/mem.h>
26 #include <isc/print.h>
27 #include <isc/serial.h>
28 #include <isc/stdtime.h>
29 #include <isc/string.h>
30 #include <isc/task.h>
31 #include <isc/util.h>
32
33 #include <dns/callbacks.h>
34 #include <dns/events.h>
35 #include <dns/fixedname.h>
36 #include <dns/master.h>
37 #include <dns/name.h>
38 #include <dns/rdata.h>
39 #include <dns/rdataclass.h>
40 #include <dns/rdatalist.h>
41 #include <dns/rdataset.h>
42 #include <dns/rdatastruct.h>
43 #include <dns/rdatatype.h>
44 #include <dns/result.h>
45 #include <dns/soa.h>
46 #include <dns/time.h>
47 #include <dns/ttl.h>
48
49 /*
50  * Grow the number of dns_rdatalist_t (RDLSZ) and dns_rdata_t (RDSZ) structures
51  * by these sizes when we need to.
52  *
53  * RDLSZ reflects the number of different types with the same name expected.
54  * RDSZ reflects the number of rdata expected at a give name that can fit into
55  * 64k.
56  */
57
58 #define RDLSZ 32
59 #define RDSZ 512
60
61 #define NBUFS 4
62 #define MAXWIRESZ 255
63
64 /*
65  * Target buffer size and minimum target size.
66  * MINTSIZ must be big enough to hold the largest rdata record.
67  *
68  * TSIZ >= MINTSIZ
69  */
70 #define TSIZ (128*1024)
71 /*
72  * max message size - header - root - type - class - ttl - rdlen
73  */
74 #define MINTSIZ (65535 - 12 - 1 - 2 - 2 - 4 - 2)
75 /*
76  * Size for tokens in the presentation format,
77  * The largest tokens are the base64 blocks in KEY and CERT records,
78  * Largest key allowed is about 1372 bytes but
79  * there is no fixed upper bound on CERT records.
80  * 2K is too small for some X.509s, 8K is overkill.
81  */
82 #define TOKENSIZ (8*1024)
83
84 #define DNS_MASTER_BUFSZ 2048
85
86 typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
87
88 typedef struct dns_incctx dns_incctx_t;
89
90 /*
91  * Master file load state.
92  */
93
94 struct dns_loadctx {
95         unsigned int            magic;
96         isc_mem_t               *mctx;
97         isc_lex_t               *lex;
98         dns_rdatacallbacks_t    *callbacks;
99         isc_task_t              *task;
100         dns_loaddonefunc_t      done;
101         void                    *done_arg;
102         unsigned int            options;
103         isc_boolean_t           ttl_known;
104         isc_boolean_t           default_ttl_known;
105         isc_boolean_t           warn_1035;
106         isc_boolean_t           warn_sigexpired;
107         isc_boolean_t           seen_include;
108         isc_uint32_t            ttl;
109         isc_uint32_t            default_ttl;
110         dns_rdataclass_t        zclass;
111         dns_fixedname_t         fixed_top;
112         dns_name_t              *top;                   /* top of zone */
113         /* Which fixed buffers we are using? */
114         unsigned int            loop_cnt;               /* records per quantum,
115                                                          * 0 => all. */
116         isc_boolean_t           canceled;
117         isc_mutex_t             lock;
118         isc_result_t            result;
119         /* locked by lock */
120         isc_uint32_t            references;
121         dns_incctx_t            *inc;
122 };
123
124 struct dns_incctx {
125         dns_incctx_t            *parent;
126         dns_name_t              *origin;
127         dns_name_t              *current;
128         dns_name_t              *glue;
129         dns_fixedname_t         fixed[NBUFS];           /* working buffers */
130         unsigned int            in_use[NBUFS];          /* covert to bitmap? */
131         int                     glue_in_use;
132         int                     current_in_use;
133         int                     origin_in_use;
134         isc_boolean_t           drop;
135         unsigned int            glue_line;
136         unsigned int            current_line;
137 };
138
139 #define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x')
140 #define DNS_LCTX_VALID(lctx) ISC_MAGIC_VALID(lctx, DNS_LCTX_MAGIC)
141
142 static isc_result_t
143 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx);
144
145 static isc_result_t
146 commit(dns_rdatacallbacks_t *, dns_loadctx_t *, rdatalist_head_t *,
147        dns_name_t *, const char *, unsigned int);
148
149 static isc_boolean_t
150 is_glue(rdatalist_head_t *, dns_name_t *);
151
152 static dns_rdatalist_t *
153 grow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *,
154                 rdatalist_head_t *, isc_mem_t *mctx);
155
156 static dns_rdata_t *
157 grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
158            isc_mem_t *);
159
160 static void
161 load_quantum(isc_task_t *task, isc_event_t *event);
162
163 static isc_result_t
164 task_send(dns_loadctx_t *lctx);
165
166 static void
167 loadctx_destroy(dns_loadctx_t *lctx);
168
169 #define GETTOKEN(lexer, options, token, eol) \
170         do { \
171                 result = gettoken(lexer, options, token, eol, callbacks); \
172                 switch (result) { \
173                 case ISC_R_SUCCESS: \
174                         break; \
175                 case ISC_R_UNEXPECTED: \
176                         goto insist_and_cleanup; \
177                 default: \
178                         if (MANYERRS(lctx, result)) { \
179                                 SETRESULT(lctx, result); \
180                                 LOGIT(result); \
181                                 read_till_eol = ISC_TRUE; \
182                                 goto next_line; \
183                         } else \
184                                 goto log_and_cleanup; \
185                 } \
186                 if ((token)->type == isc_tokentype_special) { \
187                         result = DNS_R_SYNTAX; \
188                         if (MANYERRS(lctx, result)) { \
189                                 SETRESULT(lctx, result); \
190                                 LOGIT(result); \
191                                 read_till_eol = ISC_TRUE; \
192                                 goto next_line; \
193                         } else \
194                                 goto log_and_cleanup; \
195                 } \
196         } while (0)
197
198 #define COMMITALL \
199         do { \
200                 result = commit(callbacks, lctx, &current_list, \
201                                 ictx->current, source, ictx->current_line); \
202                 if (MANYERRS(lctx, result)) { \
203                         SETRESULT(lctx, result); \
204                 } else if (result != ISC_R_SUCCESS) \
205                         goto insist_and_cleanup; \
206                 result = commit(callbacks, lctx, &glue_list, \
207                                 ictx->glue, source, ictx->glue_line); \
208                 if (MANYERRS(lctx, result)) { \
209                         SETRESULT(lctx, result); \
210                 } else if (result != ISC_R_SUCCESS) \
211                         goto insist_and_cleanup; \
212                 rdcount = 0; \
213                 rdlcount = 0; \
214                 isc_buffer_init(&target, target_mem, target_size); \
215                 rdcount_save = rdcount; \
216                 rdlcount_save = rdlcount; \
217         } while (0)
218
219 #define WARNUNEXPECTEDEOF(lexer) \
220         do { \
221                 if (isc_lex_isfile(lexer)) \
222                         (*callbacks->warn)(callbacks, \
223                                 "%s: file does not end with newline", \
224                                 source); \
225         } while (0)
226
227 #define EXPECTEOL \
228         do { \
229                 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE); \
230                 if (token.type != isc_tokentype_eol) { \
231                         isc_lex_ungettoken(lctx->lex, &token); \
232                         result = DNS_R_EXTRATOKEN; \
233                         if (MANYERRS(lctx, result)) { \
234                                 SETRESULT(lctx, result); \
235                                 LOGIT(result); \
236                                 read_till_eol = ISC_TRUE; \
237                                 continue; \
238                         } else if (result != ISC_R_SUCCESS) \
239                                 goto log_and_cleanup; \
240                 } \
241         } while (0)
242
243 #define MANYERRS(lctx, result) \
244                 ((result != ISC_R_SUCCESS) && \
245                 ((lctx)->options & DNS_MASTER_MANYERRORS) != 0)
246
247 #define SETRESULT(lctx, r) \
248                 do { \
249                         if ((lctx)->result == ISC_R_SUCCESS) \
250                                 (lctx)->result = r; \
251                 } while (0)
252
253 #define LOGITFILE(result, filename) \
254         if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \
255             result == ISC_R_IOERROR || result == ISC_R_TOOMANYOPENFILES || \
256             result == ISC_R_NOPERM) \
257                 (*callbacks->error)(callbacks, "%s: %s:%lu: %s: %s", \
258                                     "dns_master_load", source, line, \
259                                     filename, dns_result_totext(result)); \
260         else LOGIT(result)
261
262 #define LOGIT(result) \
263         if (result == ISC_R_NOMEMORY) \
264                 (*callbacks->error)(callbacks, "dns_master_load: %s", \
265                                     dns_result_totext(result)); \
266         else \
267                 (*callbacks->error)(callbacks, "%s: %s:%lu: %s", \
268                                     "dns_master_load", \
269                                     source, line, dns_result_totext(result))
270
271 static inline isc_result_t
272 gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token,
273          isc_boolean_t eol, dns_rdatacallbacks_t *callbacks)
274 {
275         isc_result_t result;
276
277         options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE |
278                 ISC_LEXOPT_ESCAPE;
279         result = isc_lex_gettoken(lex, options, token);
280         if (result != ISC_R_SUCCESS) {
281                 switch (result) {
282                 case ISC_R_NOMEMORY:
283                         return (ISC_R_NOMEMORY);
284                 default:
285                         (*callbacks->error)(callbacks,
286                                             "dns_master_load: %s:%lu:"
287                                             " isc_lex_gettoken() failed: %s",
288                                             isc_lex_getsourcename(lex),
289                                             isc_lex_getsourceline(lex),
290                                             isc_result_totext(result));
291                         return (result);
292                 }
293                 /*NOTREACHED*/
294         }
295         if (eol != ISC_TRUE)
296                 if (token->type == isc_tokentype_eol ||
297                     token->type == isc_tokentype_eof) {
298                         (*callbacks->error)(callbacks,
299                             "dns_master_load: %s:%lu: unexpected end of %s",
300                                             isc_lex_getsourcename(lex),
301                                             isc_lex_getsourceline(lex),
302                                             (token->type ==
303                                              isc_tokentype_eol) ?
304                                             "line" : "file");
305                         return (ISC_R_UNEXPECTEDEND);
306                 }
307         return (ISC_R_SUCCESS);
308 }
309
310
311 void
312 dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
313
314         REQUIRE(target != NULL && *target == NULL);
315         REQUIRE(DNS_LCTX_VALID(source));
316
317         LOCK(&source->lock);
318         INSIST(source->references > 0);
319         source->references++;
320         INSIST(source->references != 0);        /* Overflow? */
321         UNLOCK(&source->lock);
322
323         *target = source;
324 }
325
326 void
327 dns_loadctx_detach(dns_loadctx_t **lctxp) {
328         dns_loadctx_t *lctx;
329         isc_boolean_t need_destroy = ISC_FALSE;
330
331         REQUIRE(lctxp != NULL);
332         lctx = *lctxp;
333         REQUIRE(DNS_LCTX_VALID(lctx));
334
335         LOCK(&lctx->lock);
336         INSIST(lctx->references > 0);
337         lctx->references--;
338         if (lctx->references == 0)
339                 need_destroy = ISC_TRUE;
340         UNLOCK(&lctx->lock);
341
342         if (need_destroy)
343                 loadctx_destroy(lctx);
344         *lctxp = NULL;
345 }
346
347 static void
348 incctx_destroy(isc_mem_t *mctx, dns_incctx_t *ictx) {
349         dns_incctx_t *parent;
350
351  again:
352         parent = ictx->parent;
353         ictx->parent = NULL;
354
355         isc_mem_put(mctx, ictx, sizeof *ictx);
356
357         if (parent != NULL) {
358                 ictx = parent;
359                 goto again;
360         }
361 }
362
363 static void
364 loadctx_destroy(dns_loadctx_t *lctx) {
365         isc_mem_t *mctx;
366
367         REQUIRE(DNS_LCTX_VALID(lctx));
368
369         lctx->magic = 0;
370         if (lctx->inc != NULL)
371                 incctx_destroy(lctx->mctx, lctx->inc);
372
373         if (lctx->lex != NULL) {
374                 /* isc_lex_destroy() will close all open streams */
375                 isc_lex_destroy(&lctx->lex);
376         }
377         if (lctx->task != NULL)
378                 isc_task_detach(&lctx->task);
379         DESTROYLOCK(&lctx->lock);
380         mctx = NULL;
381         isc_mem_attach(lctx->mctx, &mctx);
382         isc_mem_detach(&lctx->mctx);
383         isc_mem_put(mctx, lctx, sizeof(*lctx));
384         isc_mem_detach(&mctx);
385 }
386
387 static isc_result_t
388 incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
389         dns_incctx_t *ictx;
390         isc_region_t r;
391         int i;
392
393         ictx = isc_mem_get(mctx, sizeof *ictx);
394         if (ictx == NULL)
395                 return (ISC_R_NOMEMORY);
396
397         for (i = 0; i < NBUFS; i++) {
398                 dns_fixedname_init(&ictx->fixed[i]);
399                 ictx->in_use[i] = ISC_FALSE;
400         }
401
402         ictx->origin_in_use = 0;
403         ictx->origin = dns_fixedname_name(&ictx->fixed[ictx->origin_in_use]);
404         ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
405         dns_name_toregion(origin, &r);
406         dns_name_fromregion(ictx->origin, &r);
407
408         ictx->glue = NULL;
409         ictx->current = NULL;
410         ictx->glue_in_use = -1;
411         ictx->current_in_use = -1;
412         ictx->parent = NULL;
413         ictx->drop = ISC_FALSE;
414         ictx->glue_line = 0;
415         ictx->current_line = 0;
416
417         *ictxp = ictx;
418         return (ISC_R_SUCCESS);
419 }
420
421 static isc_result_t
422 loadctx_create(isc_mem_t *mctx, unsigned int options, dns_name_t *top,
423                dns_rdataclass_t zclass, dns_name_t *origin,
424                dns_rdatacallbacks_t *callbacks, isc_task_t *task,
425                dns_loaddonefunc_t done, void *done_arg,
426                dns_loadctx_t **lctxp)
427 {
428         dns_loadctx_t *lctx;
429         isc_result_t result;
430         isc_region_t r;
431         isc_lexspecials_t specials;
432
433         REQUIRE(lctxp != NULL && *lctxp == NULL);
434         REQUIRE(callbacks != NULL);
435         REQUIRE(callbacks->add != NULL);
436         REQUIRE(callbacks->error != NULL);
437         REQUIRE(callbacks->warn != NULL);
438         REQUIRE(mctx != NULL);
439         REQUIRE(dns_name_isabsolute(top));
440         REQUIRE(dns_name_isabsolute(origin));
441         REQUIRE((task == NULL && done == NULL) ||
442                 (task != NULL && done != NULL));
443
444         lctx = isc_mem_get(mctx, sizeof(*lctx));
445         if (lctx == NULL)
446                 return (ISC_R_NOMEMORY);
447         result = isc_mutex_init(&lctx->lock);
448         if (result != ISC_R_SUCCESS) {
449                 isc_mem_put(mctx, lctx, sizeof *lctx);
450                 UNEXPECTED_ERROR(__FILE__, __LINE__,
451                                  "isc_mutex_init() failed: %s",
452                                  isc_result_totext(result));
453                 return (ISC_R_UNEXPECTED);
454         }
455
456         lctx->inc = NULL;
457         result = incctx_create(mctx, origin, &lctx->inc);
458         if (result != ISC_R_SUCCESS) 
459                 goto cleanup_ctx;
460
461         lctx->lex = NULL;
462         result = isc_lex_create(mctx, TOKENSIZ, &lctx->lex);
463         if (result != ISC_R_SUCCESS)
464                 goto cleanup_inc;
465         memset(specials, 0, sizeof specials);
466         specials['('] = 1;
467         specials[')'] = 1;
468         specials['"'] = 1;
469         isc_lex_setspecials(lctx->lex, specials);
470         isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
471
472         lctx->ttl_known = ISC_FALSE;
473         lctx->ttl = 0;
474         lctx->default_ttl_known = ISC_FALSE;
475         lctx->default_ttl = 0;
476         lctx->warn_1035 = ISC_TRUE;     /* XXX Argument? */
477         lctx->warn_sigexpired = ISC_TRUE;       /* XXX Argument? */
478         lctx->options = options;
479         lctx->seen_include = ISC_FALSE;
480         lctx->zclass = zclass;
481         lctx->result = ISC_R_SUCCESS;
482
483         dns_fixedname_init(&lctx->fixed_top);
484         lctx->top = dns_fixedname_name(&lctx->fixed_top);
485         dns_name_toregion(top, &r);
486         dns_name_fromregion(lctx->top, &r);
487
488         lctx->loop_cnt = (done != NULL) ? 100 : 0;
489         lctx->callbacks = callbacks;
490         lctx->task = NULL;
491         if (task != NULL)
492                 isc_task_attach(task, &lctx->task);
493         lctx->done = done;
494         lctx->done_arg = done_arg;
495         lctx->canceled = ISC_FALSE;
496         lctx->mctx = NULL;
497         isc_mem_attach(mctx, &lctx->mctx);
498         lctx->references = 1;                   /* Implicit attach. */
499         lctx->magic = DNS_LCTX_MAGIC;
500         *lctxp = lctx;
501         return (ISC_R_SUCCESS);
502
503  cleanup_inc:
504         incctx_destroy(mctx, lctx->inc);
505  cleanup_ctx:
506         isc_mem_put(mctx, lctx, sizeof(*lctx));
507         return (result);
508 }
509
510 static isc_result_t
511 genname(char *name, int it, char *buffer, size_t length) {
512         char fmt[sizeof("%04000000000d")];
513         char numbuf[128];
514         char *cp;
515         char mode[2];
516         int delta = 0;
517         isc_textregion_t r;
518         unsigned int n;
519         unsigned int width;
520
521         r.base = buffer;
522         r.length = length;
523
524         while (*name != '\0') {
525                 if (*name == '$') {
526                         name++;
527                         if (*name == '$') {
528                                 if (r.length == 0)
529                                         return (ISC_R_NOSPACE);
530                                 r.base[0] = *name++;
531                                 isc_textregion_consume(&r, 1);
532                                 continue;
533                         }
534                         strcpy(fmt, "%d");
535                         /* Get format specifier. */
536                         if (*name == '{' ) {
537                                 n = sscanf(name, "{%d,%u,%1[doxX]}",
538                                            &delta, &width, mode);
539                                 switch (n) {
540                                 case 1:
541                                         break;
542                                 case 2:
543                                         n = snprintf(fmt, sizeof(fmt),
544                                                      "%%0%ud", width);
545                                         break;
546                                 case 3:
547                                         n = snprintf(fmt, sizeof(fmt),
548                                                      "%%0%u%c", width, mode[0]);
549                                         break;
550                                 default:
551                                         return (DNS_R_SYNTAX);
552                                 }
553                                 if (n >= sizeof(fmt))
554                                         return (ISC_R_NOSPACE);
555                                 /* Skip past closing brace. */
556                                 while (*name != '\0' && *name++ != '}')
557                                         continue;
558                         }
559                         n = snprintf(numbuf, sizeof(numbuf), fmt, it + delta);
560                         if (n >= sizeof(numbuf))
561                                 return (ISC_R_NOSPACE);
562                         cp = numbuf;
563                         while (*cp != '\0') {
564                                 if (r.length == 0)
565                                         return (ISC_R_NOSPACE);
566                                 r.base[0] = *cp++;
567                                 isc_textregion_consume(&r, 1);
568                         }
569                 } else if (*name == '\\') {
570                         if (r.length == 0)
571                                 return (ISC_R_NOSPACE);
572                         r.base[0] = *name++;
573                         isc_textregion_consume(&r, 1);
574                         if (*name == '\0')
575                                 continue;
576                         if (r.length == 0)
577                                 return (ISC_R_NOSPACE);
578                         r.base[0] = *name++;
579                         isc_textregion_consume(&r, 1);
580                 } else {
581                         if (r.length == 0)
582                                 return (ISC_R_NOSPACE);
583                         r.base[0] = *name++;
584                         isc_textregion_consume(&r, 1);
585                 }
586         }
587         if (r.length == 0)
588                 return (ISC_R_NOSPACE);
589         r.base[0] = '\0';
590         return (ISC_R_SUCCESS);
591 }
592
593 static isc_result_t
594 generate(dns_loadctx_t *lctx, char *range, char *lhs, char *gtype, char *rhs,
595          const char *source, unsigned int line)
596 {
597         char *target_mem = NULL;
598         char *lhsbuf = NULL;
599         char *rhsbuf = NULL;
600         dns_fixedname_t ownerfixed;
601         dns_name_t *owner;
602         dns_rdata_t rdata = DNS_RDATA_INIT;
603         dns_rdatacallbacks_t *callbacks;
604         dns_rdatalist_t rdatalist;
605         dns_rdatatype_t type;
606         rdatalist_head_t head;
607         int n;
608         int target_size = MINTSIZ;      /* only one rdata at a time */
609         isc_buffer_t buffer;
610         isc_buffer_t target;
611         isc_result_t result;
612         isc_textregion_t r;
613         unsigned int start, stop, step, i;
614         dns_incctx_t *ictx;
615
616         ictx = lctx->inc;
617         callbacks = lctx->callbacks;
618         dns_fixedname_init(&ownerfixed);
619         owner = dns_fixedname_name(&ownerfixed);
620         ISC_LIST_INIT(head);
621
622         target_mem = isc_mem_get(lctx->mctx, target_size);
623         rhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_BUFSZ);
624         lhsbuf = isc_mem_get(lctx->mctx, DNS_MASTER_BUFSZ);
625         if (target_mem == NULL || rhsbuf == NULL || lhsbuf == NULL) {
626                 result = ISC_R_NOMEMORY;
627                 goto error_cleanup;
628         }
629         isc_buffer_init(&target, target_mem, target_size);
630
631         n = sscanf(range, "%u-%u/%u", &start, &stop, &step);
632         if (n < 2 || stop < start) {
633                (*callbacks->error)(callbacks,
634                                   "%s: %s:%lu: invalid range '%s'",
635                                   "$GENERATE", source, line, range);
636                 result = DNS_R_SYNTAX;
637                 goto insist_cleanup;
638         }
639         if (n == 2)
640                 step = 1;
641
642         /*
643          * Get type.
644          */
645         r.base = gtype;
646         r.length = strlen(gtype);
647         result = dns_rdatatype_fromtext(&type, &r);
648         if (result != ISC_R_SUCCESS) {
649                 (*callbacks->error)(callbacks,
650                                    "%s: %s:%lu: unknown RR type '%s'",
651                                    "$GENERATE", source, line, gtype);
652                 goto insist_cleanup;
653         }
654
655         switch (type) {
656         case dns_rdatatype_ns:
657         case dns_rdatatype_ptr:
658         case dns_rdatatype_cname:
659         case dns_rdatatype_dname:
660                 break;
661
662         case dns_rdatatype_a:
663         case dns_rdatatype_aaaa:
664                 if (lctx->zclass == dns_rdataclass_in ||
665                     lctx->zclass == dns_rdataclass_hs)
666                         break;
667                 /* FALLTHROUGH */
668         default:
669                (*callbacks->error)(callbacks,
670                                   "%s: %s:%lu: unsupported type '%s'",
671                                   "$GENERATE", source, line, gtype);
672                 result = ISC_R_NOTIMPLEMENTED;
673                 goto error_cleanup;
674         }
675
676         ISC_LIST_INIT(rdatalist.rdata);
677         ISC_LINK_INIT(&rdatalist, link);
678         for (i = start; i <= stop; i += step) {
679                 result = genname(lhs, i, lhsbuf, DNS_MASTER_BUFSZ);
680                 if (result != ISC_R_SUCCESS)
681                         goto error_cleanup;
682                 result = genname(rhs, i, rhsbuf, DNS_MASTER_BUFSZ);
683                 if (result != ISC_R_SUCCESS)
684                         goto error_cleanup;
685
686                 isc_buffer_init(&buffer, lhsbuf, strlen(lhsbuf));
687                 isc_buffer_add(&buffer, strlen(lhsbuf));
688                 isc_buffer_setactive(&buffer, strlen(lhsbuf));
689                 result = dns_name_fromtext(owner, &buffer, ictx->origin,
690                                            ISC_FALSE, NULL);
691                 if (result != ISC_R_SUCCESS)
692                         goto error_cleanup;
693
694                 if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
695                     (lctx->options & DNS_MASTER_SLAVE) == 0 &&
696                     !dns_name_issubdomain(owner, lctx->top))
697                 {
698                         char namebuf[DNS_NAME_FORMATSIZE];
699                         dns_name_format(owner, namebuf, sizeof(namebuf));
700                         /*
701                          * Ignore out-of-zone data.
702                          */
703                         (*callbacks->warn)(callbacks,
704                                            "dns_master_load: %s:%lu: "
705                                            "ignoring out-of-zone data (%s)",
706                                            source, line, namebuf);
707                         continue;
708                 }
709
710                 isc_buffer_init(&buffer, rhsbuf, strlen(rhsbuf));
711                 isc_buffer_add(&buffer, strlen(rhsbuf));
712                 isc_buffer_setactive(&buffer, strlen(rhsbuf));
713
714                 result = isc_lex_openbuffer(lctx->lex, &buffer);
715                 if (result != ISC_R_SUCCESS)
716                         goto error_cleanup;
717
718                 isc_buffer_init(&target, target_mem, target_size);
719                 result = dns_rdata_fromtext(&rdata, lctx->zclass, type,
720                                             lctx->lex, ictx->origin, ISC_FALSE,
721                                             lctx->mctx, &target, callbacks);
722                 isc_lex_close(lctx->lex);
723                 if (result != ISC_R_SUCCESS)
724                         goto error_cleanup;
725
726                 rdatalist.type = type;
727                 rdatalist.covers = 0;
728                 rdatalist.rdclass = lctx->zclass;
729                 rdatalist.ttl = lctx->ttl;
730                 ISC_LIST_PREPEND(head, &rdatalist, link);
731                 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
732                 result = commit(callbacks, lctx, &head, owner, source, line);
733                 ISC_LIST_UNLINK(rdatalist.rdata, &rdata, link);
734                 if (result != ISC_R_SUCCESS)
735                         goto error_cleanup;
736                 dns_rdata_reset(&rdata);
737         }
738         result = ISC_R_SUCCESS;
739         goto cleanup;
740
741  error_cleanup:
742         if (result == ISC_R_NOMEMORY)
743                 (*callbacks->error)(callbacks, "$GENERATE: %s",
744                                     dns_result_totext(result));
745         else
746                 (*callbacks->error)(callbacks, "$GENERATE: %s:%lu: %s",
747                                     source, line, dns_result_totext(result));
748
749  insist_cleanup:
750         INSIST(result != ISC_R_SUCCESS);
751
752  cleanup:
753         if (target_mem != NULL)
754                 isc_mem_put(lctx->mctx, target_mem, target_size);
755         if (lhsbuf != NULL)
756                 isc_mem_put(lctx->mctx, lhsbuf, DNS_MASTER_BUFSZ);
757         if (rhsbuf != NULL)
758                 isc_mem_put(lctx->mctx, rhsbuf, DNS_MASTER_BUFSZ);
759         return (result);
760 }
761
762 static void
763 limit_ttl(dns_rdatacallbacks_t *callbacks, const char *source, unsigned int line,
764           isc_uint32_t *ttlp)
765 {
766         if (*ttlp > 0x7fffffffUL) {
767                 (callbacks->warn)(callbacks,
768                                   "%s: %s:%lu: "
769                                   "$TTL %lu > MAXTTL, "
770                                   "setting $TTL to 0",
771                                   "dns_master_load",
772                                   source, line,
773                                   *ttlp);
774                 *ttlp = 0;
775         }
776 }
777
778 static isc_result_t
779 load(dns_loadctx_t *lctx) {
780         dns_rdataclass_t rdclass;
781         dns_rdatatype_t type, covers;
782         isc_uint32_t ttl_offset = 0;
783         dns_name_t *new_name;
784         isc_boolean_t current_has_delegation = ISC_FALSE;
785         isc_boolean_t done = ISC_FALSE;
786         isc_boolean_t finish_origin = ISC_FALSE;
787         isc_boolean_t finish_include = ISC_FALSE;
788         isc_boolean_t read_till_eol = ISC_FALSE;
789         isc_boolean_t initialws;
790         char *include_file = NULL;
791         isc_token_t token;
792         isc_result_t result = ISC_R_UNEXPECTED;
793         rdatalist_head_t glue_list;
794         rdatalist_head_t current_list;
795         dns_rdatalist_t *this;
796         dns_rdatalist_t *rdatalist = NULL;
797         dns_rdatalist_t *new_rdatalist;
798         int rdlcount = 0;
799         int rdlcount_save = 0;
800         int rdatalist_size = 0;
801         isc_buffer_t buffer;
802         isc_buffer_t target;
803         isc_buffer_t target_ft;
804         isc_buffer_t target_save;
805         dns_rdata_t *rdata = NULL;
806         dns_rdata_t *new_rdata;
807         int rdcount = 0;
808         int rdcount_save = 0;
809         int rdata_size = 0;
810         unsigned char *target_mem = NULL;
811         int target_size = TSIZ;
812         int new_in_use;
813         unsigned int loop_cnt = 0;
814         isc_mem_t *mctx;
815         dns_rdatacallbacks_t *callbacks;
816         dns_incctx_t *ictx;
817         char *range = NULL;
818         char *lhs = NULL;
819         char *gtype = NULL;
820         char *rhs = NULL;
821         const char *source = "";
822         unsigned long line = 0;
823         isc_boolean_t explicit_ttl;
824         isc_stdtime_t now;
825
826         REQUIRE(DNS_LCTX_VALID(lctx));
827         callbacks = lctx->callbacks;
828         mctx = lctx->mctx;
829         ictx = lctx->inc;
830
831         ISC_LIST_INIT(glue_list);
832         ISC_LIST_INIT(current_list);
833
834         isc_stdtime_get(&now);
835
836         /*
837          * Allocate target_size of buffer space.  This is greater than twice
838          * the maximum individual RR data size.
839          */
840         target_mem = isc_mem_get(mctx, target_size);
841         if (target_mem == NULL) {
842                 result = ISC_R_NOMEMORY;
843                 goto log_and_cleanup;
844         }
845         isc_buffer_init(&target, target_mem, target_size);
846         target_save = target;
847
848         source = isc_lex_getsourcename(lctx->lex);
849         do {
850                 initialws = ISC_FALSE;
851                 line = isc_lex_getsourceline(lctx->lex);
852                 GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS, &token, ISC_TRUE);
853                 line = isc_lex_getsourceline(lctx->lex);
854
855                 if (token.type == isc_tokentype_eof) {
856                         if (read_till_eol)
857                                 WARNUNEXPECTEDEOF(lctx->lex);
858                         /* Pop the include stack? */
859                         if (ictx->parent != NULL) {
860                                 COMMITALL;
861                                 lctx->inc = ictx->parent;
862                                 ictx->parent = NULL;
863                                 incctx_destroy(lctx->mctx, ictx);
864                                 isc_lex_close(lctx->lex);
865                                 line = isc_lex_getsourceline(lctx->lex);
866                                 source = isc_lex_getsourcename(lctx->lex);
867                                 ictx = lctx->inc;
868                                 EXPECTEOL;
869                                 continue;
870                         }
871                         done = ISC_TRUE;
872                         continue;
873                 }
874
875                 if (token.type == isc_tokentype_eol) {
876                         read_till_eol = ISC_FALSE;
877                         continue;               /* blank line */
878                 }
879
880                 if (read_till_eol)
881                         continue;
882
883                 if (token.type == isc_tokentype_initialws) {
884                         /*
885                          * Still working on the same name.
886                          */
887                         initialws = ISC_TRUE;
888                 } else if (token.type == isc_tokentype_string) {
889
890                         /*
891                          * "$" Support.
892                          *
893                          * "$ORIGIN" and "$INCLUDE" can both take domain names.
894                          * The processing of "$ORIGIN" and "$INCLUDE" extends
895                          * across the normal domain name processing.
896                          */
897
898                         if (strcasecmp(token.value.as_pointer,
899                                        "$ORIGIN") == 0) {
900                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
901                                 finish_origin = ISC_TRUE;
902                         } else if (strcasecmp(token.value.as_pointer,
903                                               "$TTL") == 0) {
904                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
905                                 result =
906                                    dns_ttl_fromtext(&token.value.as_textregion,
907                                                     &lctx->ttl);
908                                 if (MANYERRS(lctx, result)) {
909                                         SETRESULT(lctx, result);
910                                         lctx->ttl = 0;
911                                 } else if (result != ISC_R_SUCCESS)
912                                         goto insist_and_cleanup;
913                                 limit_ttl(callbacks, source, line, &lctx->ttl);
914                                 lctx->default_ttl = lctx->ttl;
915                                 lctx->default_ttl_known = ISC_TRUE;
916                                 EXPECTEOL;
917                                 continue;
918                         } else if (strcasecmp(token.value.as_pointer,
919                                               "$INCLUDE") == 0) {
920                                 COMMITALL;
921                                 if ((lctx->options & DNS_MASTER_NOINCLUDE) != 0) {
922                                         (callbacks->error)(callbacks,
923                                            "%s: %s:%lu: $INCLUDE not allowed",
924                                            "dns_master_load",
925                                            source, line);
926                                         result = DNS_R_REFUSED;
927                                         goto insist_and_cleanup;
928                                 }
929                                 if (ttl_offset != 0) {
930                                         (callbacks->error)(callbacks,
931                                            "%s: %s:%lu: $INCLUDE "
932                                            "may not be used with $DATE",
933                                            "dns_master_load",
934                                            source, line);
935                                         result = DNS_R_SYNTAX;
936                                         goto insist_and_cleanup;
937                                 }
938                                 GETTOKEN(lctx->lex, ISC_LEXOPT_QSTRING, &token,
939                                          ISC_FALSE);
940                                 if (include_file != NULL)
941                                         isc_mem_free(mctx, include_file);
942                                 include_file = isc_mem_strdup(mctx,
943                                                 token.value.as_pointer);
944                                 if (include_file == NULL) {
945                                         result = ISC_R_NOMEMORY;
946                                         goto log_and_cleanup;
947                                 }
948                                 GETTOKEN(lctx->lex, 0, &token, ISC_TRUE);
949
950                                 if (token.type == isc_tokentype_eol ||
951                                     token.type == isc_tokentype_eof) {
952                                         if (token.type == isc_tokentype_eof)
953                                                 WARNUNEXPECTEDEOF(lctx->lex);
954                                         isc_lex_ungettoken(lctx->lex, &token);
955                                         /*
956                                          * No origin field.
957                                          */
958                                         result = pushfile(include_file,
959                                                           ictx->origin, lctx);
960                                         if (MANYERRS(lctx, result)) {
961                                                 SETRESULT(lctx, result);
962                                                 LOGITFILE(result, include_file);
963                                                 continue;
964                                         } else if (result != ISC_R_SUCCESS) {
965                                                 LOGITFILE(result, include_file);
966                                                 goto insist_and_cleanup;
967                                         }
968                                         ictx = lctx->inc;
969                                         line = isc_lex_getsourceline(lctx->lex);
970                                         source =
971                                                isc_lex_getsourcename(lctx->lex);
972                                         continue;
973                                 }
974                                 /*
975                                  * There is an origin field.  Fall through
976                                  * to domain name processing code and do
977                                  * the actual inclusion later.
978                                  */
979                                 finish_include = ISC_TRUE;
980                         } else if (strcasecmp(token.value.as_pointer,
981                                               "$DATE") == 0) {
982                                 isc_int64_t dump_time64;
983                                 isc_stdtime_t dump_time, current_time;
984                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
985                                 isc_stdtime_get(&current_time);
986                                 result = dns_time64_fromtext(token.value.
987                                              as_pointer, &dump_time64);
988                                 if (MANYERRS(lctx, result)) {
989                                         SETRESULT(lctx, result);
990                                         LOGIT(result);
991                                         dump_time64 = 0;
992                                 } else if (result != ISC_R_SUCCESS)
993                                         goto log_and_cleanup;
994                                 dump_time = (isc_stdtime_t)dump_time64;
995                                 if (dump_time != dump_time64) {
996                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
997                                          "%s: %s:%lu: $DATE outside epoch",
998                                          "dns_master_load", source, line);
999                                         result = ISC_R_UNEXPECTED;
1000                                         goto insist_and_cleanup;
1001                                 }
1002                                 if (dump_time > current_time) {
1003                                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1004                                         "%s: %s:%lu: "
1005                                         "$DATE in future, using current date",
1006                                         "dns_master_load", source, line);
1007                                         dump_time = current_time;
1008                                 }
1009                                 ttl_offset = current_time - dump_time;
1010                                 EXPECTEOL;
1011                                 continue;
1012                         } else if (strcasecmp(token.value.as_pointer,
1013                                               "$GENERATE") == 0) {
1014                                 /*
1015                                  * Use default ttl if known otherwise
1016                                  * inherit or error.
1017                                  */
1018                                 if (!lctx->ttl_known &&
1019                                     !lctx->default_ttl_known) {
1020                                         (*callbacks->error)(callbacks,
1021                                             "%s: %s:%lu: no TTL specified",
1022                                             "dns_master_load", source, line);
1023                                         result = DNS_R_NOTTL;
1024                                         if (MANYERRS(lctx, result)) {
1025                                                 SETRESULT(lctx, result);
1026                                                 lctx->ttl = 0;
1027                                         } else if (result != ISC_R_SUCCESS)
1028                                                 goto insist_and_cleanup;
1029                                 } else if (lctx->default_ttl_known) {
1030                                         lctx->ttl = lctx->default_ttl;
1031                                 }
1032                                 /*
1033                                  * Lazy cleanup.
1034                                  */
1035                                 if (range != NULL)
1036                                         isc_mem_free(mctx, range);
1037                                 if (lhs != NULL)
1038                                         isc_mem_free(mctx, lhs);
1039                                 if (gtype != NULL)
1040                                         isc_mem_free(mctx, gtype);
1041                                 if (rhs != NULL)
1042                                         isc_mem_free(mctx, rhs);
1043                                 /* range */
1044                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1045                                 range = isc_mem_strdup(mctx,
1046                                                      token.value.as_pointer);
1047                                 if (range == NULL) {
1048                                         result = ISC_R_NOMEMORY;
1049                                         goto log_and_cleanup;
1050                                 }
1051                                 /* LHS */
1052                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1053                                 lhs = isc_mem_strdup(mctx,
1054                                                     token.value.as_pointer);
1055                                 if (lhs == NULL) {
1056                                         result = ISC_R_NOMEMORY;
1057                                         goto log_and_cleanup;
1058                                 }
1059                                 /* TYPE */
1060                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1061                                 gtype = isc_mem_strdup(mctx,
1062                                                        token.value.as_pointer);
1063                                 if (gtype == NULL) {
1064                                         result = ISC_R_NOMEMORY;
1065                                         goto log_and_cleanup;
1066                                 }
1067                                 /* RHS */
1068                                 GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1069                                 rhs = isc_mem_strdup(mctx,
1070                                                      token.value.as_pointer);
1071                                 if (rhs == NULL) {
1072                                         result = ISC_R_NOMEMORY;
1073                                         goto log_and_cleanup;
1074                                 }
1075                                 result = generate(lctx, range, lhs, gtype, rhs,
1076                                                   source, line);
1077                                 if (MANYERRS(lctx, result)) {
1078                                         SETRESULT(lctx, result);
1079                                 } else if (result != ISC_R_SUCCESS)
1080                                         goto insist_and_cleanup;
1081                                 EXPECTEOL;
1082                                 continue;
1083                         } else if (strncasecmp(token.value.as_pointer,
1084                                                "$", 1) == 0) {
1085                                 (callbacks->error)(callbacks,
1086                                            "%s: %s:%lu: "
1087                                            "unknown $ directive '%s'",
1088                                            "dns_master_load", source, line,
1089                                            token.value.as_pointer);
1090                                 result = DNS_R_SYNTAX;
1091                                 if (MANYERRS(lctx, result)) {
1092                                         SETRESULT(lctx, result);
1093                                 } else if (result != ISC_R_SUCCESS)
1094                                         goto insist_and_cleanup;
1095                         }
1096
1097                         /*
1098                          * Normal processing resumes.
1099                          *
1100                          * Find a free name buffer.
1101                          */
1102                         for (new_in_use = 0; new_in_use < NBUFS ; new_in_use++)
1103                                 if (!ictx->in_use[new_in_use])
1104                                         break;
1105                         INSIST(new_in_use < NBUFS);
1106                         dns_fixedname_init(&ictx->fixed[new_in_use]);
1107                         new_name = dns_fixedname_name(&ictx->fixed[new_in_use]);
1108                         isc_buffer_init(&buffer, token.value.as_region.base,
1109                                         token.value.as_region.length);
1110                         isc_buffer_add(&buffer, token.value.as_region.length);
1111                         isc_buffer_setactive(&buffer,
1112                                              token.value.as_region.length);
1113                         result = dns_name_fromtext(new_name, &buffer,
1114                                           ictx->origin, ISC_FALSE, NULL);
1115                         if (MANYERRS(lctx, result)) {
1116                                 SETRESULT(lctx, result);
1117                                 LOGITFILE(result, include_file);
1118                                 read_till_eol = ISC_TRUE;
1119                                 continue;
1120                         } else if (result != ISC_R_SUCCESS)
1121                                 goto log_and_cleanup;
1122
1123                         /*
1124                          * Finish $ORIGIN / $INCLUDE processing if required.
1125                          */
1126                         if (finish_origin) {
1127                                 if (ictx->origin_in_use != -1)
1128                                         ictx->in_use[ictx->origin_in_use] =
1129                                                 ISC_FALSE;
1130                                 ictx->origin_in_use = new_in_use;
1131                                 ictx->in_use[ictx->origin_in_use] = ISC_TRUE;
1132                                 ictx->origin = new_name;
1133                                 finish_origin = ISC_FALSE;
1134                                 EXPECTEOL;
1135                                 continue;
1136                         }
1137                         if (finish_include) {
1138                                 finish_include = ISC_FALSE;
1139                                 result = pushfile(include_file, new_name, lctx);
1140                                 if (MANYERRS(lctx, result)) {
1141                                         SETRESULT(lctx, result);
1142                                         LOGITFILE(result, include_file);
1143                                         continue;
1144                                 } else if (result != ISC_R_SUCCESS) {
1145                                         LOGITFILE(result, include_file);
1146                                         goto insist_and_cleanup;
1147                                 }
1148                                 ictx = lctx->inc;
1149                                 line = isc_lex_getsourceline(lctx->lex);
1150                                 source = isc_lex_getsourcename(lctx->lex);
1151                                 continue;
1152                         }
1153
1154                         /*
1155                          * "$" Processing Finished
1156                          */
1157
1158                         /*
1159                          * If we are processing glue and the new name does
1160                          * not match the current glue name, commit the glue
1161                          * and pop stacks leaving us in 'normal' processing
1162                          * state.  Linked lists are undone by commit().
1163                          */
1164                         if (ictx->glue != NULL &&
1165                             dns_name_compare(ictx->glue, new_name) != 0) {
1166                                 result = commit(callbacks, lctx, &glue_list,
1167                                                 ictx->glue, source,
1168                                                 ictx->glue_line);
1169                                 if (MANYERRS(lctx, result)) {
1170                                         SETRESULT(lctx, result);
1171                                 } else if (result != ISC_R_SUCCESS)
1172                                         goto insist_and_cleanup;
1173                                 if (ictx->glue_in_use != -1)
1174                                         ictx->in_use[ictx->glue_in_use] =
1175                                                 ISC_FALSE;
1176                                 ictx->glue_in_use = -1;
1177                                 ictx->glue = NULL;
1178                                 rdcount = rdcount_save;
1179                                 rdlcount = rdlcount_save;
1180                                 target = target_save;
1181                         }
1182
1183                         /*
1184                          * If we are in 'normal' processing state and the new
1185                          * name does not match the current name, see if the
1186                          * new name is for glue and treat it as such,
1187                          * otherwise we have a new name so commit what we
1188                          * have.
1189                          */
1190                         if ((ictx->glue == NULL) && (ictx->current == NULL ||
1191                             dns_name_compare(ictx->current, new_name) != 0)) {
1192                                 if (current_has_delegation &&
1193                                         is_glue(&current_list, new_name)) {
1194                                         rdcount_save = rdcount;
1195                                         rdlcount_save = rdlcount;
1196                                         target_save = target;
1197                                         ictx->glue = new_name;
1198                                         ictx->glue_in_use = new_in_use;
1199                                         ictx->in_use[ictx->glue_in_use] = 
1200                                                 ISC_TRUE;
1201                                 } else {
1202                                         result = commit(callbacks, lctx,
1203                                                         &current_list,
1204                                                         ictx->current,
1205                                                         source,
1206                                                         ictx->current_line);
1207                                         if (MANYERRS(lctx, result)) {
1208                                                 SETRESULT(lctx, result);
1209                                         } else if (result != ISC_R_SUCCESS)
1210                                                 goto insist_and_cleanup;
1211                                         rdcount = 0;
1212                                         rdlcount = 0;
1213                                         if (ictx->current_in_use != -1)
1214                                             ictx->in_use[ictx->current_in_use] =
1215                                                 ISC_FALSE;
1216                                         ictx->current_in_use = new_in_use;
1217                                         ictx->in_use[ictx->current_in_use] =
1218                                                 ISC_TRUE;
1219                                         ictx->current = new_name;
1220                                         current_has_delegation = ISC_FALSE;
1221                                         isc_buffer_init(&target, target_mem,
1222                                                         target_size);
1223                                 }
1224                         }
1225                         if ((lctx->options & DNS_MASTER_ZONE) != 0 &&
1226                             (lctx->options & DNS_MASTER_SLAVE) == 0 &&
1227                             !dns_name_issubdomain(new_name, lctx->top))
1228                         {
1229                                 char namebuf[DNS_NAME_FORMATSIZE];
1230                                 dns_name_format(new_name, namebuf,
1231                                                 sizeof(namebuf));
1232                                 /*
1233                                  * Ignore out-of-zone data.
1234                                  */
1235                                 (*callbacks->warn)(callbacks,
1236                                        "dns_master_load: %s:%lu: "
1237                                        "ignoring out-of-zone data (%s)",
1238                                        source, line, namebuf);
1239                                 ictx->drop = ISC_TRUE;
1240                         } else
1241                                 ictx->drop = ISC_FALSE;
1242                 } else {
1243                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1244                                          "%s:%lu: isc_lex_gettoken() returned "
1245                                          "unexpeced token type (%d)",
1246                                          source, line, token.type);
1247                         result = ISC_R_UNEXPECTED;
1248                         if (MANYERRS(lctx, result)) {
1249                                 SETRESULT(lctx, result);
1250                                 LOGIT(result);
1251                                 continue;
1252                         } else if (result != ISC_R_SUCCESS)
1253                                 goto insist_and_cleanup;
1254                 }
1255
1256                 /*
1257                  * Find TTL, class and type.  Both TTL and class are optional
1258                  * and may occur in any order if they exist. TTL and class
1259                  * come before type which must exist.
1260                  *
1261                  * [<TTL>] [<class>] <type> <RDATA>
1262                  * [<class>] [<TTL>] <type> <RDATA>
1263                  */
1264
1265                 type = 0;
1266                 rdclass = 0;
1267
1268                 GETTOKEN(lctx->lex, 0, &token, initialws);
1269
1270                 if (initialws) {
1271                         if (token.type == isc_tokentype_eol) {
1272                                 read_till_eol = ISC_FALSE;
1273                                 continue;               /* blank line */
1274                         }
1275
1276                         if (token.type == isc_tokentype_eof) {
1277                                 WARNUNEXPECTEDEOF(lctx->lex);
1278                                 read_till_eol = ISC_FALSE;
1279                                 isc_lex_ungettoken(lctx->lex, &token);
1280                                 continue;
1281                         }
1282
1283                         if (ictx->current == NULL) {
1284                                 (*callbacks->error)(callbacks,
1285                                         "%s: %s:%lu: no current owner name",
1286                                         "dns_master_load",
1287                                         source, line);
1288                                 result = DNS_R_NOOWNER;
1289                                 if (MANYERRS(lctx, result)) {
1290                                         SETRESULT(lctx, result);
1291                                         read_till_eol = ISC_TRUE;
1292                                         continue;
1293                                 } else if (result != ISC_R_SUCCESS)
1294                                         goto insist_and_cleanup;
1295                         }
1296                 }
1297
1298                 if (dns_rdataclass_fromtext(&rdclass,
1299                                             &token.value.as_textregion)
1300                                 == ISC_R_SUCCESS)
1301                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1302
1303                 explicit_ttl = ISC_FALSE;
1304                 if (dns_ttl_fromtext(&token.value.as_textregion, &lctx->ttl)
1305                                 == ISC_R_SUCCESS) {
1306                         limit_ttl(callbacks, source, line, &lctx->ttl);
1307                         explicit_ttl = ISC_TRUE;
1308                         lctx->ttl_known = ISC_TRUE;
1309                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1310                 }
1311
1312                 if (token.type != isc_tokentype_string) {
1313                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1314                         "isc_lex_gettoken() returned unexpected token type");
1315                         result = ISC_R_UNEXPECTED;
1316                         if (MANYERRS(lctx, result)) {
1317                                 SETRESULT(lctx, result);
1318                                 read_till_eol = ISC_TRUE;
1319                                 continue;
1320                         } else if (result != ISC_R_SUCCESS)
1321                                 goto insist_and_cleanup;
1322                 }
1323
1324                 if (rdclass == 0 &&
1325                     dns_rdataclass_fromtext(&rdclass,
1326                                             &token.value.as_textregion)
1327                                 == ISC_R_SUCCESS)
1328                         GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
1329
1330                 if (token.type != isc_tokentype_string) {
1331                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1332                         "isc_lex_gettoken() returned unexpected token type");
1333                         result = ISC_R_UNEXPECTED;
1334                         if (MANYERRS(lctx, result)) {
1335                                 SETRESULT(lctx, result);
1336                                 read_till_eol = ISC_TRUE;
1337                                 continue;
1338                         } else if (result != ISC_R_SUCCESS)
1339                                 goto insist_and_cleanup;
1340                 }
1341
1342                 result = dns_rdatatype_fromtext(&type,
1343                                                 &token.value.as_textregion);
1344                 if (result != ISC_R_SUCCESS) {
1345                         (*callbacks->warn)(callbacks,
1346                                    "%s: %s:%lu: unknown RR type '%.*s'",
1347                                    "dns_master_load", source, line,
1348                                    token.value.as_textregion.length,
1349                                    token.value.as_textregion.base);
1350                         if (MANYERRS(lctx, result)) {
1351                                 SETRESULT(lctx, result);
1352                                 read_till_eol = ISC_TRUE;
1353                                 continue;
1354                         } else if (result != ISC_R_SUCCESS)
1355                                 goto insist_and_cleanup;
1356                 }
1357
1358                 /*
1359                  * If the class specified does not match the zone's class
1360                  * print out a error message and exit.
1361                  */
1362                 if (rdclass != 0 && rdclass != lctx->zclass) {
1363                         char classname1[DNS_RDATACLASS_FORMATSIZE];
1364                         char classname2[DNS_RDATACLASS_FORMATSIZE];
1365
1366                         dns_rdataclass_format(rdclass, classname1,
1367                                               sizeof(classname1));
1368                         dns_rdataclass_format(lctx->zclass, classname2,
1369                                               sizeof(classname2));
1370                         (*callbacks->error)(callbacks,
1371                                             "%s: %s:%lu: class '%s' != "
1372                                             "zone class '%s'",
1373                                             "dns_master_load", source, line,
1374                                             classname1, classname2);
1375                         result = DNS_R_BADCLASS;
1376                         if (MANYERRS(lctx, result)) {
1377                                 SETRESULT(lctx, result);
1378                                 read_till_eol = ISC_TRUE;
1379                                 continue;
1380                         } else if (result != ISC_R_SUCCESS)
1381                                 goto insist_and_cleanup;
1382                 }
1383
1384                 if (type == dns_rdatatype_ns && ictx->glue == NULL)
1385                         current_has_delegation = ISC_TRUE;
1386
1387                 /*
1388                  * Find a rdata structure.
1389                  */
1390                 if (rdcount == rdata_size) {
1391                         new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
1392                                                rdata_size, &current_list,
1393                                                &glue_list, mctx);
1394                         if (new_rdata == NULL) {
1395                                 result = ISC_R_NOMEMORY;
1396                                 goto log_and_cleanup;
1397                         }
1398                         rdata_size += RDSZ;
1399                         rdata = new_rdata;
1400                 }
1401
1402                 /*
1403                  * Read rdata contents.
1404                  */
1405                 dns_rdata_init(&rdata[rdcount]);
1406                 target_ft = target;
1407                 result = dns_rdata_fromtext(&rdata[rdcount], lctx->zclass,
1408                                             type, lctx->lex, ictx->origin,
1409                                             ISC_FALSE, lctx->mctx, &target,
1410                                             callbacks);
1411                 if (MANYERRS(lctx, result)) {
1412                         SETRESULT(lctx, result);
1413                         continue;
1414                 } else if (result != ISC_R_SUCCESS)
1415                         goto insist_and_cleanup;
1416
1417                 if (ictx->drop) {
1418                         target = target_ft;
1419                         continue;
1420                 }
1421
1422                 if (type == dns_rdatatype_soa &&
1423                     (lctx->options & DNS_MASTER_ZONE) != 0 &&
1424                     dns_name_compare(ictx->current, lctx->top) != 0) {
1425                         char namebuf[DNS_NAME_FORMATSIZE];
1426                         dns_name_format(ictx->current, namebuf,
1427                                         sizeof(namebuf));
1428                         (*callbacks->error)(callbacks,
1429                                             "dns_master_load: %s:%lu: SOA "
1430                                             "record not at top of zone (%s)",
1431                                             source, line, namebuf);
1432                         result = DNS_R_NOTZONETOP;
1433                         if (MANYERRS(lctx, result)) {
1434                                 SETRESULT(lctx, result);
1435                                 read_till_eol = ISC_TRUE;
1436                                 target = target_ft;
1437                                 continue;
1438                         } else if (result != ISC_R_SUCCESS)
1439                                 goto insist_and_cleanup;
1440                 }
1441
1442
1443                 if (type == dns_rdatatype_sig)
1444                         covers = dns_rdata_covers(&rdata[rdcount]);
1445                 else
1446                         covers = 0;
1447
1448                 if (!lctx->ttl_known && !lctx->default_ttl_known) {
1449                         if (type == dns_rdatatype_soa) {
1450                                 (*callbacks->warn)(callbacks,
1451                                                    "%s:%lu: no TTL specified; "
1452                                                    "using SOA MINTTL instead",
1453                                                    source, line);
1454                                 lctx->ttl = dns_soa_getminimum(&rdata[rdcount]);
1455                                 limit_ttl(callbacks, source, line, &lctx->ttl);
1456                                 lctx->default_ttl = lctx->ttl;
1457                                 lctx->default_ttl_known = ISC_TRUE;
1458                         } else {
1459                                 (*callbacks->warn)(callbacks,
1460                                                    "%s:%lu: no TTL specified; "
1461                                                    "zone rejected",
1462                                                    source, line);
1463                                 result = DNS_R_NOTTL;
1464                                 if (MANYERRS(lctx, result)) {
1465                                         SETRESULT(lctx, result);
1466                                         lctx->ttl = 0;
1467                                 } else {
1468                                         goto insist_and_cleanup;
1469                                 }
1470                         }
1471                 } else if (!explicit_ttl && lctx->default_ttl_known) {
1472                         lctx->ttl = lctx->default_ttl;
1473                 } else if (!explicit_ttl && lctx->warn_1035) {
1474                         (*callbacks->warn)(callbacks,
1475                                            "%s: %s:%lu: "
1476                                            "using RFC 1035 TTL semantics",
1477                                            "dns_master_load", source, line);
1478                         lctx->warn_1035 = ISC_FALSE;
1479                 }
1480
1481                 if (type == dns_rdatatype_sig && lctx->warn_sigexpired) {
1482                         dns_rdata_sig_t sig;
1483                         (void)dns_rdata_tostruct(&rdata[rdcount], &sig, NULL);
1484                         if (isc_serial_lt(sig.timeexpire, now)) {
1485                                 (*callbacks->warn)(callbacks,
1486                                                    "%s: %s:%lu: "
1487                                                    "signature has expired",
1488                                                    "dns_master_load",
1489                                                    source, line);
1490                                 lctx->warn_sigexpired = ISC_FALSE;
1491                         }
1492                 }
1493
1494                 if ((lctx->options & DNS_MASTER_AGETTL) != 0) {
1495                         /*
1496                          * Adjust the TTL for $DATE.  If the RR has already
1497                          * expired, ignore it.
1498                          */
1499                         if (lctx->ttl < ttl_offset)
1500                                 continue;
1501                         lctx->ttl -= ttl_offset;
1502                 }
1503
1504                 /*
1505                  * Find type in rdatalist.
1506                  * If it does not exist create new one and prepend to list
1507                  * as this will mimimise list traversal.
1508                  */
1509                 if (ictx->glue != NULL)
1510                         this = ISC_LIST_HEAD(glue_list);
1511                 else
1512                         this = ISC_LIST_HEAD(current_list);
1513
1514                 while (this != NULL) {
1515                         if (this->type == type && this->covers == covers)
1516                                 break;
1517                         this = ISC_LIST_NEXT(this, link);
1518                 }
1519
1520                 if (this == NULL) {
1521                         if (rdlcount == rdatalist_size) {
1522                                 new_rdatalist =
1523                                         grow_rdatalist(rdatalist_size + RDLSZ,
1524                                                        rdatalist,
1525                                                        rdatalist_size,
1526                                                        &current_list,
1527                                                        &glue_list,
1528                                                        mctx);
1529                                 if (new_rdatalist == NULL) {
1530                                         result = ISC_R_NOMEMORY;
1531                                         goto log_and_cleanup;
1532                                 }
1533                                 rdatalist = new_rdatalist;
1534                                 rdatalist_size += RDLSZ;
1535                         }
1536                         this = &rdatalist[rdlcount++];
1537                         this->type = type;
1538                         this->covers = covers;
1539                         this->rdclass = lctx->zclass;
1540                         this->ttl = lctx->ttl;
1541                         ISC_LIST_INIT(this->rdata);
1542                         if (ictx->glue != NULL)
1543                                 ISC_LIST_INITANDPREPEND(glue_list, this, link);
1544                         else
1545                                 ISC_LIST_INITANDPREPEND(current_list, this,
1546                                                         link);
1547                 } else if (this->ttl != lctx->ttl) {
1548                         (*callbacks->warn)(callbacks,
1549                                            "%s: %s:%lu: "
1550                                            "TTL set to prior TTL (%lu)",
1551                                            "dns_master_load",
1552                                            source, line, this->ttl);
1553                         lctx->ttl = this->ttl;
1554                 }
1555
1556                 ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
1557                 if (ictx->glue != NULL) 
1558                         ictx->glue_line = line;
1559                 else
1560                         ictx->current_line = line;
1561                 rdcount++;
1562
1563                 /*
1564                  * We must have at least 64k as rdlen is 16 bits.
1565                  * If we don't commit everything we have so far.
1566                  */
1567                 if ((target.length - target.used) < MINTSIZ)
1568                         COMMITALL;
1569  next_line:
1570                 ;
1571         } while (!done && (lctx->loop_cnt == 0 || loop_cnt++ < lctx->loop_cnt));
1572
1573         /*
1574          * Commit what has not yet been committed.
1575          */
1576         result = commit(callbacks, lctx, &current_list, ictx->current,
1577                         source, ictx->current_line);
1578         if (MANYERRS(lctx, result)) {
1579                 SETRESULT(lctx, result);
1580         } else if (result != ISC_R_SUCCESS)
1581                 goto insist_and_cleanup;
1582         result = commit(callbacks, lctx, &glue_list, ictx->glue,
1583                         source, ictx->glue_line);
1584         if (MANYERRS(lctx, result)) {
1585                 SETRESULT(lctx, result);
1586         } else if (result != ISC_R_SUCCESS)
1587                 goto insist_and_cleanup;
1588
1589         if (!done) {
1590                 INSIST(lctx->done != NULL && lctx->task != NULL);
1591                 result = DNS_R_CONTINUE;
1592         } else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
1593                 result = lctx->result;
1594         } else if (result == ISC_R_SUCCESS && lctx->seen_include)
1595                 result = DNS_R_SEENINCLUDE;
1596         goto cleanup;
1597
1598  log_and_cleanup:
1599         LOGIT(result);
1600
1601  insist_and_cleanup:
1602         INSIST(result != ISC_R_SUCCESS);
1603
1604  cleanup:
1605         while ((this = ISC_LIST_HEAD(current_list)) != NULL)
1606                 ISC_LIST_UNLINK(current_list, this, link);
1607         while ((this = ISC_LIST_HEAD(glue_list)) != NULL)
1608                 ISC_LIST_UNLINK(glue_list, this, link);
1609         if (rdatalist != NULL)
1610                 isc_mem_put(mctx, rdatalist,
1611                             rdatalist_size * sizeof *rdatalist);
1612         if (rdata != NULL)
1613                 isc_mem_put(mctx, rdata, rdata_size * sizeof *rdata);
1614         if (target_mem != NULL)
1615                 isc_mem_put(mctx, target_mem, target_size);
1616         if (include_file != NULL)
1617                 isc_mem_free(mctx, include_file);
1618         if (range != NULL)
1619                 isc_mem_free(mctx, range);
1620         if (lhs != NULL)
1621                 isc_mem_free(mctx, lhs);
1622         if (gtype != NULL)
1623                 isc_mem_free(mctx, gtype);
1624         if (rhs != NULL)
1625                 isc_mem_free(mctx, rhs);
1626         return (result);
1627 }
1628
1629 static isc_result_t
1630 pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) {
1631         isc_result_t result;
1632         dns_incctx_t *ictx;
1633         dns_incctx_t *new = NULL;
1634         isc_region_t r;
1635         int new_in_use;
1636
1637         REQUIRE(master_file != NULL);
1638         REQUIRE(DNS_LCTX_VALID(lctx));
1639
1640         ictx = lctx->inc;
1641         lctx->seen_include = ISC_TRUE;
1642
1643         result = incctx_create(lctx->mctx, origin, &new);
1644         if (result != ISC_R_SUCCESS)
1645                 return (result);
1646
1647         /* Set current domain. */
1648         if (ictx->glue != NULL || ictx->current != NULL) {
1649                 for (new_in_use = 0; new_in_use < NBUFS ; new_in_use++)
1650                         if (!new->in_use[new_in_use])
1651                                 break;
1652                 INSIST(new_in_use < NBUFS);
1653                 new->current_in_use = new_in_use;
1654                 new->current =
1655                         dns_fixedname_name(&new->fixed[new->current_in_use]);
1656                 new->in_use[new->current_in_use] = ISC_TRUE;
1657                 dns_name_toregion((ictx->glue != NULL) ?
1658                                    ictx->glue : ictx->current, &r);
1659                 dns_name_fromregion(new->current, &r);
1660                 new->drop = ictx->drop;
1661         }
1662
1663         result = isc_lex_openfile(lctx->lex, master_file);
1664         if (result != ISC_R_SUCCESS)
1665                 goto cleanup;
1666         new->parent = ictx;
1667         lctx->inc = new;
1668         return (ISC_R_SUCCESS);
1669
1670  cleanup:
1671         if (new != NULL)
1672                 incctx_destroy(lctx->mctx, new);
1673         return (result);
1674 }
1675
1676 isc_result_t
1677 dns_master_loadfile(const char *master_file, dns_name_t *top,
1678                     dns_name_t *origin,
1679                     dns_rdataclass_t zclass, unsigned int options,
1680                     dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
1681 {
1682         dns_loadctx_t *lctx = NULL;
1683         isc_result_t result;
1684
1685         result = loadctx_create(mctx, options, top, zclass, origin,
1686                                 callbacks, NULL, NULL, NULL, &lctx);
1687         if (result != ISC_R_SUCCESS)
1688                 return (result);
1689
1690         result = isc_lex_openfile(lctx->lex, master_file);
1691         if (result != ISC_R_SUCCESS)
1692                 goto cleanup;
1693
1694         result = load(lctx);
1695         INSIST(result != DNS_R_CONTINUE);
1696
1697  cleanup:
1698         if (lctx != NULL)
1699                 dns_loadctx_detach(&lctx);
1700         return (result);
1701 }
1702
1703 isc_result_t
1704 dns_master_loadfileinc(const char *master_file, dns_name_t *top,
1705                        dns_name_t *origin, dns_rdataclass_t zclass,
1706                        unsigned int options, dns_rdatacallbacks_t *callbacks,
1707                        isc_task_t *task, dns_loaddonefunc_t done,
1708                        void *done_arg, dns_loadctx_t **lctxp, isc_mem_t *mctx)
1709 {
1710         dns_loadctx_t *lctx = NULL;
1711         isc_result_t result;
1712         
1713         REQUIRE(task != NULL);
1714         REQUIRE(done != NULL);
1715
1716         result = loadctx_create(mctx, options, top, zclass, origin,
1717                                 callbacks, task, done, done_arg, &lctx);
1718         if (result != ISC_R_SUCCESS)
1719                 return (result);
1720
1721         result = isc_lex_openfile(lctx->lex, master_file);
1722         if (result != ISC_R_SUCCESS)
1723                 goto cleanup;
1724
1725         result = task_send(lctx);
1726         if (result == ISC_R_SUCCESS) {
1727                 dns_loadctx_attach(lctx, lctxp);
1728                 return (DNS_R_CONTINUE);
1729         }
1730
1731  cleanup:
1732         if (lctx != NULL)
1733                 dns_loadctx_detach(&lctx);
1734         return (result);
1735 }
1736
1737 isc_result_t
1738 dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
1739                       dns_rdataclass_t zclass, unsigned int options,
1740                       dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
1741 {
1742         isc_result_t result;
1743         dns_loadctx_t *lctx = NULL;
1744
1745         REQUIRE(stream != NULL);
1746
1747         result = loadctx_create(mctx, options, top, zclass, origin,
1748                                 callbacks, NULL, NULL, NULL, &lctx);
1749         if (result != ISC_R_SUCCESS)
1750                 goto cleanup;
1751
1752         result = isc_lex_openstream(lctx->lex, stream);
1753         if (result != ISC_R_SUCCESS)
1754                 goto cleanup;
1755
1756         result = load(lctx);
1757         INSIST(result != DNS_R_CONTINUE);
1758
1759  cleanup:
1760         if (lctx != NULL)
1761                 dns_loadctx_detach(&lctx);
1762         return (result);
1763 }
1764
1765 isc_result_t
1766 dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
1767                          dns_rdataclass_t zclass, unsigned int options,
1768                          dns_rdatacallbacks_t *callbacks, isc_task_t *task,
1769                          dns_loaddonefunc_t done, void *done_arg,
1770                          dns_loadctx_t **lctxp, isc_mem_t *mctx)
1771 {
1772         isc_result_t result;
1773         dns_loadctx_t *lctx = NULL;
1774
1775         REQUIRE(stream != NULL);
1776         REQUIRE(task != NULL);
1777         REQUIRE(done != NULL);
1778
1779         result = loadctx_create(mctx, options, top, zclass, origin,
1780                                 callbacks, task, done, done_arg, &lctx);
1781         if (result != ISC_R_SUCCESS)
1782                 goto cleanup;
1783
1784         result = isc_lex_openstream(lctx->lex, stream);
1785         if (result != ISC_R_SUCCESS)
1786                 goto cleanup;
1787
1788         result = task_send(lctx);
1789         if (result == ISC_R_SUCCESS) {
1790                 dns_loadctx_attach(lctx, lctxp);
1791                 return (DNS_R_CONTINUE);
1792         }
1793
1794  cleanup:
1795         if (lctx != NULL)
1796                 dns_loadctx_detach(&lctx);
1797         return (result);
1798 }
1799
1800 isc_result_t
1801 dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
1802                       dns_name_t *origin, dns_rdataclass_t zclass,
1803                       unsigned int options,
1804                       dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
1805 {
1806         isc_result_t result;
1807         dns_loadctx_t *lctx = NULL;
1808
1809         REQUIRE(buffer != NULL);
1810
1811         result = loadctx_create(mctx, options, top, zclass, origin,
1812                                 callbacks, NULL, NULL, NULL, &lctx);
1813         if (result != ISC_R_SUCCESS)
1814                 return (result);
1815
1816         result = isc_lex_openbuffer(lctx->lex, buffer);
1817         if (result != ISC_R_SUCCESS)
1818                 goto cleanup;
1819
1820         result = load(lctx);
1821         INSIST(result != DNS_R_CONTINUE);
1822
1823  cleanup:
1824         if (lctx != NULL)
1825                 dns_loadctx_detach(&lctx);
1826         return (result);
1827 }
1828
1829 isc_result_t
1830 dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
1831                          dns_name_t *origin, dns_rdataclass_t zclass,
1832                          unsigned int options,
1833                          dns_rdatacallbacks_t *callbacks, isc_task_t *task,
1834                          dns_loaddonefunc_t done, void *done_arg,
1835                          dns_loadctx_t **lctxp, isc_mem_t *mctx)
1836 {
1837         isc_result_t result;
1838         dns_loadctx_t *lctx = NULL;
1839
1840         REQUIRE(buffer != NULL);
1841         REQUIRE(task != NULL);
1842         REQUIRE(done != NULL);
1843
1844         result = loadctx_create(mctx, options, top, zclass, origin,
1845                                 callbacks, task, done, done_arg, &lctx);
1846         if (result != ISC_R_SUCCESS)
1847                 return (result);
1848
1849         result = isc_lex_openbuffer(lctx->lex, buffer);
1850         if (result != ISC_R_SUCCESS)
1851                 goto cleanup;
1852
1853         result = task_send(lctx);
1854         if (result == ISC_R_SUCCESS) {
1855                 dns_loadctx_attach(lctx, lctxp);
1856                 return (DNS_R_CONTINUE);
1857         }
1858
1859  cleanup:
1860         if (lctx != NULL)
1861                 dns_loadctx_detach(&lctx);
1862         return (result);
1863 }
1864
1865 /*
1866  * Grow the slab of dns_rdatalist_t structures.
1867  * Re-link glue and current list.
1868  */
1869 static dns_rdatalist_t *
1870 grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
1871                rdatalist_head_t *current, rdatalist_head_t *glue,
1872                isc_mem_t *mctx)
1873 {
1874         dns_rdatalist_t *new;
1875         int rdlcount = 0;
1876         ISC_LIST(dns_rdatalist_t) save;
1877         dns_rdatalist_t *this;
1878
1879         new = isc_mem_get(mctx, new_len * sizeof *new);
1880         if (new == NULL)
1881                 return (NULL);
1882
1883         ISC_LIST_INIT(save);
1884         this = ISC_LIST_HEAD(*current);
1885         while ((this = ISC_LIST_HEAD(*current)) != NULL) {
1886                 ISC_LIST_UNLINK(*current, this, link);
1887                 ISC_LIST_APPEND(save, this, link);
1888         }
1889         while ((this = ISC_LIST_HEAD(save)) != NULL) {
1890                 ISC_LIST_UNLINK(save, this, link);
1891                 new[rdlcount] = *this;
1892                 ISC_LIST_APPEND(*current, &new[rdlcount], link);
1893                 rdlcount++;
1894         }
1895
1896         ISC_LIST_INIT(save);
1897         this = ISC_LIST_HEAD(*glue);
1898         while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
1899                 ISC_LIST_UNLINK(*glue, this, link);
1900                 ISC_LIST_APPEND(save, this, link);
1901         }
1902         while ((this = ISC_LIST_HEAD(save)) != NULL) {
1903                 ISC_LIST_UNLINK(save, this, link);
1904                 new[rdlcount] = *this;
1905                 ISC_LIST_APPEND(*glue, &new[rdlcount], link);
1906                 rdlcount++;
1907         }
1908
1909         INSIST(rdlcount == old_len);
1910         if (old != NULL)
1911                 isc_mem_put(mctx, old, old_len * sizeof *old);
1912         return (new);
1913 }
1914
1915 /*
1916  * Grow the slab of rdata structs.
1917  * Re-link the current and glue chains.
1918  */
1919 static dns_rdata_t *
1920 grow_rdata(int new_len, dns_rdata_t *old, int old_len,
1921            rdatalist_head_t *current, rdatalist_head_t *glue,
1922            isc_mem_t *mctx)
1923 {
1924         dns_rdata_t *new;
1925         int rdcount = 0;
1926         ISC_LIST(dns_rdata_t) save;
1927         dns_rdatalist_t *this;
1928         dns_rdata_t *rdata;
1929
1930         new = isc_mem_get(mctx, new_len * sizeof *new);
1931         if (new == NULL)
1932                 return (NULL);
1933         memset(new, 0, new_len * sizeof *new);
1934
1935         /*
1936          * Copy current relinking.
1937          */
1938         this = ISC_LIST_HEAD(*current);
1939         while (this != NULL) {
1940                 ISC_LIST_INIT(save);
1941                 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
1942                         ISC_LIST_UNLINK(this->rdata, rdata, link);
1943                         ISC_LIST_APPEND(save, rdata, link);
1944                 }
1945                 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
1946                         ISC_LIST_UNLINK(save, rdata, link);
1947                         new[rdcount] = *rdata;
1948                         ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
1949                         rdcount++;
1950                 }
1951                 this = ISC_LIST_NEXT(this, link);
1952         }
1953
1954         /*
1955          * Copy glue relinking.
1956          */
1957         this = ISC_LIST_HEAD(*glue);
1958         while (this != NULL) {
1959                 ISC_LIST_INIT(save);
1960                 while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
1961                         ISC_LIST_UNLINK(this->rdata, rdata, link);
1962                         ISC_LIST_APPEND(save, rdata, link);
1963                 }
1964                 while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
1965                         ISC_LIST_UNLINK(save, rdata, link);
1966                         new[rdcount] = *rdata;
1967                         ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
1968                         rdcount++;
1969                 }
1970                 this = ISC_LIST_NEXT(this, link);
1971         }
1972         INSIST(rdcount == old_len);
1973         if (old != NULL)
1974                 isc_mem_put(mctx, old, old_len * sizeof *old);
1975         return (new);
1976 }
1977
1978 /*
1979  * Convert each element from a rdatalist_t to rdataset then call commit.
1980  * Unlink each element as we go.
1981  */
1982
1983 static isc_result_t
1984 commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
1985        rdatalist_head_t *head, dns_name_t *owner,
1986        const char *source, unsigned int line)
1987 {
1988         dns_rdatalist_t *this;
1989         dns_rdataset_t dataset;
1990         isc_result_t result;
1991         char namebuf[DNS_NAME_FORMATSIZE];
1992         void    (*error)(struct dns_rdatacallbacks *, const char *, ...);
1993         void    (*warn)(struct dns_rdatacallbacks *, const char *, ...);
1994
1995         this = ISC_LIST_HEAD(*head);
1996         error = callbacks->error;
1997         warn = callbacks->warn;
1998
1999         if (this == NULL)
2000                 return (ISC_R_SUCCESS);
2001         do {
2002                 dns_rdataset_init(&dataset);
2003                 dns_rdatalist_tordataset(this, &dataset);
2004                 dataset.trust = dns_trust_ultimate;
2005                 result = ((*callbacks->add)(callbacks->add_private, owner,
2006                                             &dataset));
2007                 if (result == ISC_R_NOMEMORY) {
2008                         (*error)(callbacks, "dns_master_load: %s",
2009                                  dns_result_totext(result));
2010                 } else if (result != ISC_R_SUCCESS) {
2011                         dns_name_format(owner, namebuf,
2012                                         sizeof(namebuf));
2013                         (*error)(callbacks, "%s: %s:%lu: %s: %s",
2014                                  "dns_master_load", source, line,
2015                                  namebuf, dns_result_totext(result));
2016                 }
2017                 if (MANYERRS(lctx, result))
2018                         SETRESULT(lctx, result);
2019                 else if (result != ISC_R_SUCCESS)
2020                         return (result);
2021                 ISC_LIST_UNLINK(*head, this, link);
2022                 this = ISC_LIST_HEAD(*head);
2023         } while (this != NULL);
2024         return (ISC_R_SUCCESS);
2025 }
2026
2027 /*
2028  * Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
2029  */
2030
2031 static isc_boolean_t
2032 is_glue(rdatalist_head_t *head, dns_name_t *owner) {
2033         dns_rdatalist_t *this;
2034         dns_rdata_t *rdata;
2035         isc_region_t region;
2036         dns_name_t name;
2037
2038         /*
2039          * Find NS rrset.
2040          */
2041         this = ISC_LIST_HEAD(*head);
2042         while (this != NULL) {
2043                 if (this->type == dns_rdatatype_ns)
2044                         break;
2045                 this = ISC_LIST_NEXT(this, link);
2046         }
2047         if (this == NULL)
2048                 return (ISC_FALSE);
2049
2050         rdata = ISC_LIST_HEAD(this->rdata);
2051         while (rdata != NULL) {
2052                 dns_name_init(&name, NULL);
2053                 dns_rdata_toregion(rdata, &region);
2054                 dns_name_fromregion(&name, &region);
2055                 if (dns_name_compare(&name, owner) == 0)
2056                         return (ISC_TRUE);
2057                 rdata = ISC_LIST_NEXT(rdata, link);
2058         }
2059         return (ISC_FALSE);
2060 }
2061
2062 static void
2063 load_quantum(isc_task_t *task, isc_event_t *event) {
2064         isc_result_t result;
2065         dns_loadctx_t *lctx;
2066
2067         REQUIRE(event != NULL);
2068         lctx = event->ev_arg;
2069         REQUIRE(DNS_LCTX_VALID(lctx));
2070
2071         if (lctx->canceled)
2072                 result = ISC_R_CANCELED;
2073         else
2074                 result = load(lctx);
2075         if (result == DNS_R_CONTINUE) {
2076                 event->ev_arg = lctx;
2077                 isc_task_send(task, &event);
2078         } else {
2079                 (lctx->done)(lctx->done_arg, result);
2080                 isc_event_free(&event);
2081                 dns_loadctx_detach(&lctx);
2082         }
2083 }
2084
2085 static isc_result_t
2086 task_send(dns_loadctx_t *lctx) {
2087         isc_event_t *event;
2088
2089         event = isc_event_allocate(lctx->mctx, NULL,
2090                                    DNS_EVENT_MASTERQUANTUM,
2091                                    load_quantum, lctx, sizeof(*event));
2092         if (event == NULL)
2093                 return (ISC_R_NOMEMORY);
2094         isc_task_send(lctx->task, &event);
2095         return (ISC_R_SUCCESS);
2096 }
2097
2098 void
2099 dns_loadctx_cancel(dns_loadctx_t *lctx) {
2100         REQUIRE(DNS_LCTX_VALID(lctx));
2101
2102         LOCK(&lctx->lock);
2103         lctx->canceled = ISC_TRUE;
2104         UNLOCK(&lctx->lock);
2105 }