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