xref: /minix/external/bsd/bind/dist/bin/named/update.c (revision bb9622b5)
1 /*	$NetBSD: update.c,v 1.11 2015/07/08 17:28:55 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id: update.c,v 1.199 2011/12/22 07:32:40 each Exp  */
21 
22 #include <config.h>
23 
24 #include <isc/netaddr.h>
25 #include <isc/print.h>
26 #include <isc/serial.h>
27 #include <isc/stats.h>
28 #include <isc/string.h>
29 #include <isc/taskpool.h>
30 #include <isc/util.h>
31 
32 #include <dns/db.h>
33 #include <dns/dbiterator.h>
34 #include <dns/diff.h>
35 #include <dns/dnssec.h>
36 #include <dns/events.h>
37 #include <dns/fixedname.h>
38 #include <dns/journal.h>
39 #include <dns/keyvalues.h>
40 #include <dns/message.h>
41 #include <dns/nsec.h>
42 #include <dns/nsec3.h>
43 #include <dns/private.h>
44 #include <dns/rdataclass.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatasetiter.h>
47 #include <dns/rdatastruct.h>
48 #include <dns/rdatatype.h>
49 #include <dns/soa.h>
50 #include <dns/ssu.h>
51 #include <dns/tsig.h>
52 #include <dns/update.h>
53 #include <dns/view.h>
54 #include <dns/zone.h>
55 #include <dns/zt.h>
56 
57 #include <named/client.h>
58 #include <named/log.h>
59 #include <named/server.h>
60 #include <named/update.h>
61 
62 #include "pfilter.h"
63 
64 /*! \file
65  * \brief
66  * This module implements dynamic update as in RFC2136.
67  */
68 
69 /*
70  *  XXX TODO:
71  * - document strict minimality
72  */
73 
74 /**************************************************************************/
75 
76 /*%
77  * Log level for tracing dynamic update protocol requests.
78  */
79 #define LOGLEVEL_PROTOCOL	ISC_LOG_INFO
80 
81 /*%
82  * Log level for low-level debug tracing.
83  */
84 #define LOGLEVEL_DEBUG		ISC_LOG_DEBUG(8)
85 
86 /*%
87  * Check an operation for failure.  These macros all assume that
88  * the function using them has a 'result' variable and a 'failure'
89  * label.
90  */
91 #define CHECK(op) \
92 	do { result = (op); \
93 		if (result != ISC_R_SUCCESS) goto failure; \
94 	} while (/*CONSTCOND*/0)
95 
96 /*%
97  * Fail unconditionally with result 'code', which must not
98  * be ISC_R_SUCCESS.  The reason for failure presumably has
99  * been logged already.
100  *
101  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
102  * from complaining about "end-of-loop code not reached".
103  */
104 
105 #define FAIL(code) \
106 	do {							\
107 		result = (code);				\
108 		if (result != ISC_R_SUCCESS) goto failure;	\
109 	} while (/*CONSTCOND*/0)
110 
111 /*%
112  * Fail unconditionally and log as a client error.
113  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
114  * from complaining about "end-of-loop code not reached".
115  */
116 #define FAILC(code, msg) \
117 	do {							\
118 		const char *_what = "failed";			\
119 		result = (code);				\
120 		switch (result) {				\
121 		case DNS_R_NXDOMAIN:				\
122 		case DNS_R_YXDOMAIN:				\
123 		case DNS_R_YXRRSET:				\
124 		case DNS_R_NXRRSET:				\
125 			_what = "unsuccessful";			\
126 		}						\
127 		update_log(client, zone, LOGLEVEL_PROTOCOL,	\
128 			   "update %s: %s (%s)", _what,		\
129 			   msg, isc_result_totext(result));	\
130 		if (result != ISC_R_SUCCESS) goto failure;	\
131 	} while (/*CONSTCOND*/0)
132 #define PREREQFAILC(code, msg) \
133 	do {							\
134 		inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
135 		FAILC(code, msg);				\
136 	} while (/*CONSTCOND*/0)
137 
138 #define FAILN(code, name, msg) \
139 	do {								\
140 		const char *_what = "failed";				\
141 		result = (code);					\
142 		switch (result) {					\
143 		case DNS_R_NXDOMAIN:					\
144 		case DNS_R_YXDOMAIN:					\
145 		case DNS_R_YXRRSET:					\
146 		case DNS_R_NXRRSET:					\
147 			_what = "unsuccessful";				\
148 		}							\
149 		if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {	\
150 			char _nbuf[DNS_NAME_FORMATSIZE];		\
151 			dns_name_format(name, _nbuf, sizeof(_nbuf));	\
152 			update_log(client, zone, LOGLEVEL_PROTOCOL,	\
153 				   "update %s: %s: %s (%s)", _what, _nbuf, \
154 				   msg, isc_result_totext(result));	\
155 		}							\
156 		if (result != ISC_R_SUCCESS) goto failure;		\
157 	} while (/*CONSTCOND*/0)
158 #define PREREQFAILN(code, name, msg) \
159 	do {								\
160 		inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
161 		FAILN(code, name, msg);					\
162 	} while (/*CONSTCOND*/0)
163 
164 #define FAILNT(code, name, type, msg) \
165 	do {								\
166 		const char *_what = "failed";				\
167 		result = (code);					\
168 		switch (result) {					\
169 		case DNS_R_NXDOMAIN:					\
170 		case DNS_R_YXDOMAIN:					\
171 		case DNS_R_YXRRSET:					\
172 		case DNS_R_NXRRSET:					\
173 			_what = "unsuccessful";				\
174 		}							\
175 		if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {	\
176 			char _nbuf[DNS_NAME_FORMATSIZE];		\
177 			char _tbuf[DNS_RDATATYPE_FORMATSIZE];		\
178 			dns_name_format(name, _nbuf, sizeof(_nbuf));	\
179 			dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
180 			update_log(client, zone, LOGLEVEL_PROTOCOL,	\
181 				   "update %s: %s/%s: %s (%s)",		\
182 				   _what, _nbuf, _tbuf, msg,		\
183 				   isc_result_totext(result));		\
184 		}							\
185 		if (result != ISC_R_SUCCESS) goto failure;		\
186 	} while (/*CONSTCOND*/0)
187 #define PREREQFAILNT(code, name, type, msg)				\
188 	do {								\
189 		inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
190 		FAILNT(code, name, type, msg);				\
191 	} while (/*CONSTCOND*/0)
192 
193 /*%
194  * Fail unconditionally and log as a server error.
195  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
196  * from complaining about "end-of-loop code not reached".
197  */
198 #define FAILS(code, msg) \
199 	do {							\
200 		result = (code);				\
201 		update_log(client, zone, LOGLEVEL_PROTOCOL,	\
202 			   "error: %s: %s",			\
203 			   msg, isc_result_totext(result));	\
204 		if (result != ISC_R_SUCCESS) goto failure;	\
205 	} while (/*CONSTCOND*/0)
206 
207 /*
208  * Return TRUE if NS_CLIENTATTR_TCP is set in the attributes other FALSE.
209  */
210 #define TCPCLIENT(client) (((client)->attributes & NS_CLIENTATTR_TCP) != 0)
211 
212 /**************************************************************************/
213 
214 typedef struct rr rr_t;
215 
216 struct rr {
217 	/* dns_name_t name; */
218 	isc_uint32_t		ttl;
219 	dns_rdata_t		rdata;
220 };
221 
222 typedef struct update_event update_event_t;
223 
224 struct update_event {
225 	ISC_EVENT_COMMON(update_event_t);
226 	dns_zone_t		*zone;
227 	isc_result_t		result;
228 	dns_message_t		*answer;
229 };
230 
231 /**************************************************************************/
232 /*
233  * Forward declarations.
234  */
235 
236 static void update_action(isc_task_t *task, isc_event_t *event);
237 static void updatedone_action(isc_task_t *task, isc_event_t *event);
238 static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone);
239 static void forward_done(isc_task_t *task, isc_event_t *event);
240 
241 /**************************************************************************/
242 
243 static void
244 update_log(ns_client_t *client, dns_zone_t *zone,
245 	   int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
246 
247 static void
248 update_log(ns_client_t *client, dns_zone_t *zone,
249 	   int level, const char *fmt, ...)
250 {
251 	va_list ap;
252 	char message[4096];
253 	char namebuf[DNS_NAME_FORMATSIZE];
254 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
255 
256 	if (client == NULL || zone == NULL)
257 		return;
258 
259 	if (isc_log_wouldlog(ns_g_lctx, level) == ISC_FALSE)
260 		return;
261 
262 	dns_name_format(dns_zone_getorigin(zone), namebuf,
263 			sizeof(namebuf));
264 	dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
265 			      sizeof(classbuf));
266 
267 	va_start(ap, fmt);
268 	vsnprintf(message, sizeof(message), fmt, ap);
269 	va_end(ap);
270 
271 	ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
272 		      level, "updating zone '%s/%s': %s",
273 		      namebuf, classbuf, message);
274 }
275 
276 static void
277 update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) {
278 	update_log(arg, zone, level, "%s", message);
279 }
280 
281 /*%
282  * Increment updated-related statistics counters.
283  */
284 static inline void
285 inc_stats(dns_zone_t *zone, isc_statscounter_t counter) {
286 	isc_stats_increment(ns_g_server->nsstats, counter);
287 
288 	if (zone != NULL) {
289 		isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
290 		if (zonestats != NULL)
291 			isc_stats_increment(zonestats, counter);
292 	}
293 }
294 
295 /*%
296  * Check if we could have queried for the contents of this zone or
297  * if the zone is potentially updateable.
298  * If the zone can potentially be updated and the check failed then
299  * log a error otherwise we log a informational message.
300  */
301 static isc_result_t
302 checkqueryacl(ns_client_t *client, dns_acl_t *queryacl, dns_name_t *zonename,
303 	      dns_acl_t *updateacl, dns_ssutable_t *ssutable)
304 {
305 	char namebuf[DNS_NAME_FORMATSIZE];
306 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
307 	int level;
308 	isc_result_t result;
309 
310 	result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE);
311 	if (result != ISC_R_SUCCESS) {
312 		pfilter_notify(result, client, "queryacl");
313 		dns_name_format(zonename, namebuf, sizeof(namebuf));
314 		dns_rdataclass_format(client->view->rdclass, classbuf,
315 				      sizeof(classbuf));
316 
317 		level = (updateacl == NULL && ssutable == NULL) ?
318 				ISC_LOG_INFO : ISC_LOG_ERROR;
319 
320 		ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
321 			      NS_LOGMODULE_UPDATE, level,
322 			      "update '%s/%s' denied due to allow-query",
323 			      namebuf, classbuf);
324 	} else if (updateacl == NULL && ssutable == NULL) {
325 		dns_name_format(zonename, namebuf, sizeof(namebuf));
326 		dns_rdataclass_format(client->view->rdclass, classbuf,
327 				      sizeof(classbuf));
328 
329 		result = DNS_R_REFUSED;
330 		pfilter_notify(result, client, "updateacl");
331 		ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
332 			      NS_LOGMODULE_UPDATE, ISC_LOG_INFO,
333 			      "update '%s/%s' denied", namebuf, classbuf);
334 	}
335 	return (result);
336 }
337 
338 /*%
339  * Override the default acl logging when checking whether a client
340  * can update the zone or whether we can forward the request to the
341  * master based on IP address.
342  *
343  * 'message' contains the type of operation that is being attempted.
344  * 'slave' indicates if this is a slave zone.  If 'acl' is NULL then
345  * log at debug=3.
346  * If the zone has no access controls configured ('acl' == NULL &&
347  * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise
348  * at error.
349  *
350  * If the request was signed log that we received it.
351  */
352 static isc_result_t
353 checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message,
354 	       dns_name_t *zonename, isc_boolean_t slave,
355 	       isc_boolean_t has_ssutable)
356 {
357 	char namebuf[DNS_NAME_FORMATSIZE];
358 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
359 	int level = ISC_LOG_ERROR;
360 	const char *msg = "denied";
361 	isc_result_t result;
362 
363 	if (slave && acl == NULL) {
364 		result = DNS_R_NOTIMP;
365 		level = ISC_LOG_DEBUG(3);
366 		msg = "disabled";
367 	} else {
368 		result = ns_client_checkaclsilent(client, NULL, acl, ISC_FALSE);
369 		pfilter_notify(result, client, "updateacl");
370 		if (result == ISC_R_SUCCESS) {
371 			level = ISC_LOG_DEBUG(3);
372 			msg = "approved";
373 		} else if (acl == NULL && !has_ssutable) {
374 			level = ISC_LOG_INFO;
375 		}
376 	}
377 
378 	if (client->signer != NULL) {
379 		dns_name_format(client->signer, namebuf, sizeof(namebuf));
380 		ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
381 			      NS_LOGMODULE_UPDATE, ISC_LOG_INFO,
382 			      "signer \"%s\" %s", namebuf, msg);
383 	}
384 
385 	dns_name_format(zonename, namebuf, sizeof(namebuf));
386 	dns_rdataclass_format(client->view->rdclass, classbuf,
387 			      sizeof(classbuf));
388 
389 	ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
390 		      NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s",
391 		      message, namebuf, classbuf, msg);
392 	return (result);
393 }
394 
395 /*%
396  * Update a single RR in version 'ver' of 'db' and log the
397  * update in 'diff'.
398  *
399  * Ensures:
400  * \li	'*tuple' == NULL.  Either the tuple is freed, or its
401  *	ownership has been transferred to the diff.
402  */
403 static isc_result_t
404 do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
405 	     dns_diff_t *diff)
406 {
407 	dns_diff_t temp_diff;
408 	isc_result_t result;
409 
410 	/*
411 	 * Create a singleton diff.
412 	 */
413 	dns_diff_init(diff->mctx, &temp_diff);
414 	ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
415 
416 	/*
417 	 * Apply it to the database.
418 	 */
419 	result = dns_diff_apply(&temp_diff, db, ver);
420 	ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
421 	if (result != ISC_R_SUCCESS) {
422 		dns_difftuple_free(tuple);
423 		return (result);
424 	}
425 
426 	/*
427 	 * Merge it into the current pending journal entry.
428 	 */
429 	dns_diff_appendminimal(diff, tuple);
430 
431 	/*
432 	 * Do not clear temp_diff.
433 	 */
434 	return (ISC_R_SUCCESS);
435 }
436 
437 /*%
438  * Perform the updates in 'updates' in version 'ver' of 'db' and log the
439  * update in 'diff'.
440  *
441  * Ensures:
442  * \li	'updates' is empty.
443  */
444 static isc_result_t
445 do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver,
446 	dns_diff_t *diff)
447 {
448 	isc_result_t result;
449 	while (! ISC_LIST_EMPTY(updates->tuples)) {
450 		dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples);
451 		ISC_LIST_UNLINK(updates->tuples, t, link);
452 		CHECK(do_one_tuple(&t, db, ver, diff));
453 	}
454 	return (ISC_R_SUCCESS);
455 
456  failure:
457 	dns_diff_clear(diff);
458 	return (result);
459 }
460 
461 static isc_result_t
462 update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
463 	      dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
464 	      dns_rdata_t *rdata)
465 {
466 	dns_difftuple_t *tuple = NULL;
467 	isc_result_t result;
468 	result = dns_difftuple_create(diff->mctx, op,
469 				      name, ttl, rdata, &tuple);
470 	if (result != ISC_R_SUCCESS)
471 		return (result);
472 	return (do_one_tuple(&tuple, db, ver, diff));
473 }
474 
475 /**************************************************************************/
476 /*
477  * Callback-style iteration over rdatasets and rdatas.
478  *
479  * foreach_rrset() can be used to iterate over the RRsets
480  * of a name and call a callback function with each
481  * one.  Similarly, foreach_rr() can be used to iterate
482  * over the individual RRs at name, optionally restricted
483  * to RRs of a given type.
484  *
485  * The callback functions are called "actions" and take
486  * two arguments: a void pointer for passing arbitrary
487  * context information, and a pointer to the current RRset
488  * or RR.  By convention, their names end in "_action".
489  */
490 
491 /*
492  * XXXRTH  We might want to make this public somewhere in libdns.
493  */
494 
495 /*%
496  * Function type for foreach_rrset() iterator actions.
497  */
498 typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
499 
500 /*%
501  * Function type for foreach_rr() iterator actions.
502  */
503 typedef isc_result_t rr_func(void *data, rr_t *rr);
504 
505 /*%
506  * Internal context struct for foreach_node_rr().
507  */
508 typedef struct {
509 	rr_func *	rr_action;
510 	void *		rr_action_data;
511 } foreach_node_rr_ctx_t;
512 
513 /*%
514  * Internal helper function for foreach_node_rr().
515  */
516 static isc_result_t
517 foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
518 	isc_result_t result;
519 	foreach_node_rr_ctx_t *ctx = data;
520 	for (result = dns_rdataset_first(rdataset);
521 	     result == ISC_R_SUCCESS;
522 	     result = dns_rdataset_next(rdataset))
523 	{
524 		rr_t rr = { 0, DNS_RDATA_INIT };
525 
526 		dns_rdataset_current(rdataset, &rr.rdata);
527 		rr.ttl = rdataset->ttl;
528 		result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
529 		if (result != ISC_R_SUCCESS)
530 			return (result);
531 	}
532 	if (result != ISC_R_NOMORE)
533 		return (result);
534 	return (ISC_R_SUCCESS);
535 }
536 
537 /*%
538  * For each rdataset of 'name' in 'ver' of 'db', call 'action'
539  * with the rdataset and 'action_data' as arguments.  If the name
540  * does not exist, do nothing.
541  *
542  * If 'action' returns an error, abort iteration and return the error.
543  */
544 static isc_result_t
545 foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
546 	      rrset_func *action, void *action_data)
547 {
548 	isc_result_t result;
549 	dns_dbnode_t *node;
550 	dns_rdatasetiter_t *iter;
551 
552 	node = NULL;
553 	result = dns_db_findnode(db, name, ISC_FALSE, &node);
554 	if (result == ISC_R_NOTFOUND)
555 		return (ISC_R_SUCCESS);
556 	if (result != ISC_R_SUCCESS)
557 		return (result);
558 
559 	iter = NULL;
560 	result = dns_db_allrdatasets(db, node, ver,
561 				     (isc_stdtime_t) 0, &iter);
562 	if (result != ISC_R_SUCCESS)
563 		goto cleanup_node;
564 
565 	for (result = dns_rdatasetiter_first(iter);
566 	     result == ISC_R_SUCCESS;
567 	     result = dns_rdatasetiter_next(iter))
568 	{
569 		dns_rdataset_t rdataset;
570 
571 		dns_rdataset_init(&rdataset);
572 		dns_rdatasetiter_current(iter, &rdataset);
573 
574 		result = (*action)(action_data, &rdataset);
575 
576 		dns_rdataset_disassociate(&rdataset);
577 		if (result != ISC_R_SUCCESS)
578 			goto cleanup_iterator;
579 	}
580 	if (result == ISC_R_NOMORE)
581 		result = ISC_R_SUCCESS;
582 
583  cleanup_iterator:
584 	dns_rdatasetiter_destroy(&iter);
585 
586  cleanup_node:
587 	dns_db_detachnode(db, &node);
588 
589 	return (result);
590 }
591 
592 /*%
593  * For each RR of 'name' in 'ver' of 'db', call 'action'
594  * with the RR and 'action_data' as arguments.  If the name
595  * does not exist, do nothing.
596  *
597  * If 'action' returns an error, abort iteration
598  * and return the error.
599  */
600 static isc_result_t
601 foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
602 		rr_func *rr_action, void *rr_action_data)
603 {
604 	foreach_node_rr_ctx_t ctx;
605 	ctx.rr_action = rr_action;
606 	ctx.rr_action_data = rr_action_data;
607 	return (foreach_rrset(db, ver, name,
608 			      foreach_node_rr_action, &ctx));
609 }
610 
611 
612 /*%
613  * For each of the RRs specified by 'db', 'ver', 'name', 'type',
614  * (which can be dns_rdatatype_any to match any type), and 'covers', call
615  * 'action' with the RR and 'action_data' as arguments. If the name
616  * does not exist, or if no RRset of the given type exists at the name,
617  * do nothing.
618  *
619  * If 'action' returns an error, abort iteration and return the error.
620  */
621 static isc_result_t
622 foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
623 	   dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
624 	   void *rr_action_data)
625 {
626 
627 	isc_result_t result;
628 	dns_dbnode_t *node;
629 	dns_rdataset_t rdataset;
630 
631 	if (type == dns_rdatatype_any)
632 		return (foreach_node_rr(db, ver, name,
633 					rr_action, rr_action_data));
634 
635 	node = NULL;
636 	if (type == dns_rdatatype_nsec3 ||
637 	    (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
638 		result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
639 	else
640 		result = dns_db_findnode(db, name, ISC_FALSE, &node);
641 	if (result == ISC_R_NOTFOUND)
642 		return (ISC_R_SUCCESS);
643 	if (result != ISC_R_SUCCESS)
644 		return (result);
645 
646 	dns_rdataset_init(&rdataset);
647 	result = dns_db_findrdataset(db, node, ver, type, covers,
648 				     (isc_stdtime_t) 0, &rdataset, NULL);
649 	if (result == ISC_R_NOTFOUND) {
650 		result = ISC_R_SUCCESS;
651 		goto cleanup_node;
652 	}
653 	if (result != ISC_R_SUCCESS)
654 		goto cleanup_node;
655 
656 	for (result = dns_rdataset_first(&rdataset);
657 	     result == ISC_R_SUCCESS;
658 	     result = dns_rdataset_next(&rdataset))
659 	{
660 		rr_t rr = { 0, DNS_RDATA_INIT };
661 		dns_rdataset_current(&rdataset, &rr.rdata);
662 		rr.ttl = rdataset.ttl;
663 		result = (*rr_action)(rr_action_data, &rr);
664 		if (result != ISC_R_SUCCESS)
665 			goto cleanup_rdataset;
666 	}
667 	if (result != ISC_R_NOMORE)
668 		goto cleanup_rdataset;
669 	result = ISC_R_SUCCESS;
670 
671  cleanup_rdataset:
672 	dns_rdataset_disassociate(&rdataset);
673  cleanup_node:
674 	dns_db_detachnode(db, &node);
675 
676 	return (result);
677 }
678 
679 /**************************************************************************/
680 /*
681  * Various tests on the database contents (for prerequisites, etc).
682  */
683 
684 /*%
685  * Function type for predicate functions that compare a database RR 'db_rr'
686  * against an update RR 'update_rr'.
687  */
688 typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
689 
690 /*%
691  * Helper function for rrset_exists().
692  */
693 static isc_result_t
694 rrset_exists_action(void *data, rr_t *rr) {
695 	UNUSED(data);
696 	UNUSED(rr);
697 	return (ISC_R_EXISTS);
698 }
699 
700 /*%
701  * Utility macro for RR existence checking functions.
702  *
703  * If the variable 'result' has the value ISC_R_EXISTS or
704  * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
705  * respectively, and return success.
706  *
707  * If 'result' has any other value, there was a failure.
708  * Return the failure result code and do not set *exists.
709  *
710  * This would be more readable as "do { if ... } while(0)",
711  * but that form generates tons of warnings on Solaris 2.6.
712  */
713 #define RETURN_EXISTENCE_FLAG				\
714 	return ((result == ISC_R_EXISTS) ?		\
715 		(*exists = ISC_TRUE, ISC_R_SUCCESS) :	\
716 		((result == ISC_R_SUCCESS) ?		\
717 		 (*exists = ISC_FALSE, ISC_R_SUCCESS) :	\
718 		 result))
719 
720 /*%
721  * Set '*exists' to true iff an rrset of the given type exists,
722  * to false otherwise.
723  */
724 static isc_result_t
725 rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
726 	     dns_rdatatype_t type, dns_rdatatype_t covers,
727 	     isc_boolean_t *exists)
728 {
729 	isc_result_t result;
730 	result = foreach_rr(db, ver, name, type, covers,
731 			    rrset_exists_action, NULL);
732 	RETURN_EXISTENCE_FLAG;
733 }
734 
735 /*%
736  * Helper function for cname_incompatible_rrset_exists.
737  */
738 static isc_result_t
739 cname_compatibility_action(void *data, dns_rdataset_t *rrset) {
740 	UNUSED(data);
741 	if (rrset->type != dns_rdatatype_cname &&
742 	    ! dns_rdatatype_isdnssec(rrset->type))
743 		return (ISC_R_EXISTS);
744 	return (ISC_R_SUCCESS);
745 }
746 
747 /*%
748  * Check whether there is an rrset incompatible with adding a CNAME RR,
749  * i.e., anything but another CNAME (which can be replaced) or a
750  * DNSSEC RR (which can coexist).
751  *
752  * If such an incompatible rrset exists, set '*exists' to ISC_TRUE.
753  * Otherwise, set it to ISC_FALSE.
754  */
755 static isc_result_t
756 cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
757 				dns_name_t *name, isc_boolean_t *exists) {
758 	isc_result_t result;
759 	result = foreach_rrset(db, ver, name,
760 			       cname_compatibility_action, NULL);
761 	RETURN_EXISTENCE_FLAG;
762 }
763 
764 /*%
765  * Helper function for rr_count().
766  */
767 static isc_result_t
768 count_rr_action(void *data, rr_t *rr) {
769 	int *countp = data;
770 	UNUSED(rr);
771 	(*countp)++;
772 	return (ISC_R_SUCCESS);
773 }
774 
775 /*%
776  * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'.
777  */
778 static isc_result_t
779 rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
780 	 dns_rdatatype_t type, dns_rdatatype_t covers, int *countp)
781 {
782 	*countp = 0;
783 	return (foreach_rr(db, ver, name, type, covers,
784 			   count_rr_action, countp));
785 }
786 
787 /*%
788  * Context struct and helper function for name_exists().
789  */
790 
791 static isc_result_t
792 name_exists_action(void *data, dns_rdataset_t *rrset) {
793 	UNUSED(data);
794 	UNUSED(rrset);
795 	return (ISC_R_EXISTS);
796 }
797 
798 /*%
799  * Set '*exists' to true iff the given name exists, to false otherwise.
800  */
801 static isc_result_t
802 name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
803 	    isc_boolean_t *exists)
804 {
805 	isc_result_t result;
806 	result = foreach_rrset(db, ver, name,
807 			       name_exists_action, NULL);
808 	RETURN_EXISTENCE_FLAG;
809 }
810 
811 /*
812  *	'ssu_check_t' is used to pass the arguments to
813  *	dns_ssutable_checkrules() to the callback function
814  *	ssu_checkrule().
815  */
816 typedef struct {
817 	/* The ownername of the record to be updated. */
818 	dns_name_t *name;
819 
820 	/* The signature's name if the request was signed. */
821 	dns_name_t *signer;
822 
823 	/* The address of the client if the request was received via TCP. */
824 	isc_netaddr_t *tcpaddr;
825 
826 	/* The ssu table to check against. */
827 	dns_ssutable_t *table;
828 
829 	/* the key used for TKEY requests */
830 	dst_key_t *key;
831 } ssu_check_t;
832 
833 static isc_result_t
834 ssu_checkrule(void *data, dns_rdataset_t *rrset) {
835 	ssu_check_t *ssuinfo = data;
836 	isc_boolean_t result;
837 
838 	/*
839 	 * If we're deleting all records, it's ok to delete RRSIG and NSEC even
840 	 * if we're normally not allowed to.
841 	 */
842 	if (rrset->type == dns_rdatatype_rrsig ||
843 	    rrset->type == dns_rdatatype_nsec)
844 		return (ISC_R_SUCCESS);
845 	result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer,
846 					 ssuinfo->name, ssuinfo->tcpaddr,
847 					 rrset->type, ssuinfo->key);
848 	return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE);
849 }
850 
851 static isc_boolean_t
852 ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
853 	     dns_ssutable_t *ssutable, dns_name_t *signer,
854 	     isc_netaddr_t *tcpaddr, dst_key_t *key)
855 {
856 	isc_result_t result;
857 	ssu_check_t ssuinfo;
858 
859 	ssuinfo.name = name;
860 	ssuinfo.table = ssutable;
861 	ssuinfo.signer = signer;
862 	ssuinfo.tcpaddr = tcpaddr;
863 	ssuinfo.key = key;
864 	result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
865 	return (ISC_TF(result == ISC_R_SUCCESS));
866 }
867 
868 /**************************************************************************/
869 /*
870  * Checking of "RRset exists (value dependent)" prerequisites.
871  *
872  * In the RFC2136 section 3.2.5, this is the pseudocode involving
873  * a variable called "temp", a mapping of <name, type> tuples to rrsets.
874  *
875  * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
876  * where each tuple has op==DNS_DIFFOP_EXISTS.
877  */
878 
879 
880 /*%
881  * Append a tuple asserting the existence of the RR with
882  * 'name' and 'rdata' to 'diff'.
883  */
884 static isc_result_t
885 temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) {
886 	isc_result_t result;
887 	dns_difftuple_t *tuple = NULL;
888 
889 	REQUIRE(DNS_DIFF_VALID(diff));
890 	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS,
891 				   name, 0, rdata, &tuple));
892 	ISC_LIST_APPEND(diff->tuples, tuple, link);
893  failure:
894 	return (result);
895 }
896 
897 /*%
898  * Compare two rdatasets represented as sorted lists of tuples.
899  * All list elements must have the same owner name and type.
900  * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset)
901  * if not.
902  */
903 static isc_result_t
904 temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) {
905 	for (;;) {
906 		if (a == NULL || b == NULL)
907 			break;
908 		INSIST(a->op == DNS_DIFFOP_EXISTS &&
909 		       b->op == DNS_DIFFOP_EXISTS);
910 		INSIST(a->rdata.type == b->rdata.type);
911 		INSIST(dns_name_equal(&a->name, &b->name));
912 		if (dns_rdata_casecompare(&a->rdata, &b->rdata) != 0)
913 			return (DNS_R_NXRRSET);
914 		a = ISC_LIST_NEXT(a, link);
915 		b = ISC_LIST_NEXT(b, link);
916 	}
917 	if (a != NULL || b != NULL)
918 		return (DNS_R_NXRRSET);
919 	return (ISC_R_SUCCESS);
920 }
921 
922 /*%
923  * A comparison function defining the sorting order for the entries
924  * in the "temp" data structure.  The major sort key is the owner name,
925  * followed by the type and rdata.
926  */
927 static int
928 temp_order(const void *av, const void *bv) {
929 	dns_difftuple_t const * const *ap = av;
930 	dns_difftuple_t const * const *bp = bv;
931 	dns_difftuple_t const *a = *ap;
932 	dns_difftuple_t const *b = *bp;
933 	int r;
934 	r = dns_name_compare(&a->name, &b->name);
935 	if (r != 0)
936 		return (r);
937 	r = (b->rdata.type - a->rdata.type);
938 	if (r != 0)
939 		return (r);
940 	r = dns_rdata_casecompare(&a->rdata, &b->rdata);
941 	return (r);
942 }
943 
944 /*%
945  * Check the "RRset exists (value dependent)" prerequisite information
946  * in 'temp' against the contents of the database 'db'.
947  *
948  * Return ISC_R_SUCCESS if the prerequisites are satisfied,
949  * rcode(dns_rcode_nxrrset) if not.
950  *
951  * 'temp' must be pre-sorted.
952  */
953 
954 static isc_result_t
955 temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db,
956 	   dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep)
957 {
958 	isc_result_t result;
959 	dns_name_t *name;
960 	dns_dbnode_t *node;
961 	dns_difftuple_t *t;
962 	dns_diff_t trash;
963 
964 	dns_diff_init(mctx, &trash);
965 
966 	/*
967 	 * For each name and type in the prerequisites,
968 	 * construct a sorted rdata list of the corresponding
969 	 * database contents, and compare the lists.
970 	 */
971 	t = ISC_LIST_HEAD(temp->tuples);
972 	while (t != NULL) {
973 		name = &t->name;
974 		(void)dns_name_copy(name, tmpname, NULL);
975 		*typep = t->rdata.type;
976 
977 		/* A new unique name begins here. */
978 		node = NULL;
979 		result = dns_db_findnode(db, name, ISC_FALSE, &node);
980 		if (result == ISC_R_NOTFOUND) {
981 			dns_diff_clear(&trash);
982 			return (DNS_R_NXRRSET);
983 		}
984 		if (result != ISC_R_SUCCESS) {
985 			dns_diff_clear(&trash);
986 			return (result);
987 		}
988 
989 		/* A new unique type begins here. */
990 		while (t != NULL && dns_name_equal(&t->name, name)) {
991 			dns_rdatatype_t type, covers;
992 			dns_rdataset_t rdataset;
993 			dns_diff_t d_rrs; /* Database RRs with
994 						this name and type */
995 			dns_diff_t u_rrs; /* Update RRs with
996 						this name and type */
997 
998 			*typep = type = t->rdata.type;
999 			if (type == dns_rdatatype_rrsig ||
1000 			    type == dns_rdatatype_sig)
1001 				covers = dns_rdata_covers(&t->rdata);
1002 			else if (type == dns_rdatatype_any) {
1003 				dns_db_detachnode(db, &node);
1004 				dns_diff_clear(&trash);
1005 				return (DNS_R_NXRRSET);
1006 			} else
1007 				covers = 0;
1008 
1009 			/*
1010 			 * Collect all database RRs for this name and type
1011 			 * onto d_rrs and sort them.
1012 			 */
1013 			dns_rdataset_init(&rdataset);
1014 			result = dns_db_findrdataset(db, node, ver, type,
1015 						     covers, (isc_stdtime_t) 0,
1016 						     &rdataset, NULL);
1017 			if (result != ISC_R_SUCCESS) {
1018 				dns_db_detachnode(db, &node);
1019 				dns_diff_clear(&trash);
1020 				return (DNS_R_NXRRSET);
1021 			}
1022 
1023 			dns_diff_init(mctx, &d_rrs);
1024 			dns_diff_init(mctx, &u_rrs);
1025 
1026 			for (result = dns_rdataset_first(&rdataset);
1027 			     result == ISC_R_SUCCESS;
1028 			     result = dns_rdataset_next(&rdataset))
1029 			{
1030 				dns_rdata_t rdata = DNS_RDATA_INIT;
1031 				dns_rdataset_current(&rdataset, &rdata);
1032 				result = temp_append(&d_rrs, name, &rdata);
1033 				if (result != ISC_R_SUCCESS)
1034 					goto failure;
1035 			}
1036 			if (result != ISC_R_NOMORE)
1037 				goto failure;
1038 			result = dns_diff_sort(&d_rrs, temp_order);
1039 			if (result != ISC_R_SUCCESS)
1040 				goto failure;
1041 
1042 			/*
1043 			 * Collect all update RRs for this name and type
1044 			 * onto u_rrs.  No need to sort them here -
1045 			 * they are already sorted.
1046 			 */
1047 			while (t != NULL &&
1048 			       dns_name_equal(&t->name, name) &&
1049 			       t->rdata.type == type)
1050 			{
1051 				dns_difftuple_t *next =
1052 					ISC_LIST_NEXT(t, link);
1053 				ISC_LIST_UNLINK(temp->tuples, t, link);
1054 				ISC_LIST_APPEND(u_rrs.tuples, t, link);
1055 				t = next;
1056 			}
1057 
1058 			/* Compare the two sorted lists. */
1059 			result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples),
1060 						  ISC_LIST_HEAD(d_rrs.tuples));
1061 			if (result != ISC_R_SUCCESS)
1062 				goto failure;
1063 
1064 			/*
1065 			 * We are done with the tuples, but we can't free
1066 			 * them yet because "name" still points into one
1067 			 * of them.  Move them on a temporary list.
1068 			 */
1069 			ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link);
1070 			ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link);
1071 			dns_rdataset_disassociate(&rdataset);
1072 
1073 			continue;
1074 
1075 		    failure:
1076 			dns_diff_clear(&d_rrs);
1077 			dns_diff_clear(&u_rrs);
1078 			dns_diff_clear(&trash);
1079 			dns_rdataset_disassociate(&rdataset);
1080 			dns_db_detachnode(db, &node);
1081 			return (result);
1082 		}
1083 
1084 		dns_db_detachnode(db, &node);
1085 	}
1086 
1087 	dns_diff_clear(&trash);
1088 	return (ISC_R_SUCCESS);
1089 }
1090 
1091 /**************************************************************************/
1092 /*
1093  * Conditional deletion of RRs.
1094  */
1095 
1096 /*%
1097  * Context structure for delete_if().
1098  */
1099 
1100 typedef struct {
1101 	rr_predicate *predicate;
1102 	dns_db_t *db;
1103 	dns_dbversion_t *ver;
1104 	dns_diff_t *diff;
1105 	dns_name_t *name;
1106 	dns_rdata_t *update_rr;
1107 } conditional_delete_ctx_t;
1108 
1109 /*%
1110  * Predicate functions for delete_if().
1111  */
1112 
1113 /*%
1114  * Return true iff 'db_rr' is neither a SOA nor an NS RR nor
1115  * an RRSIG nor an NSEC3PARAM nor a NSEC.
1116  */
1117 static isc_boolean_t
1118 type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1119 	UNUSED(update_rr);
1120 	return ((db_rr->type != dns_rdatatype_soa &&
1121 		 db_rr->type != dns_rdatatype_ns &&
1122 		 db_rr->type != dns_rdatatype_nsec3param &&
1123 		 db_rr->type != dns_rdatatype_rrsig &&
1124 		 db_rr->type != dns_rdatatype_nsec) ?
1125 		ISC_TRUE : ISC_FALSE);
1126 }
1127 
1128 /*%
1129  * Return true iff 'db_rr' is neither a RRSIG nor a NSEC.
1130  */
1131 static isc_boolean_t
1132 type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1133 	UNUSED(update_rr);
1134 	return ((db_rr->type != dns_rdatatype_rrsig &&
1135 		 db_rr->type != dns_rdatatype_nsec) ?
1136 		ISC_TRUE : ISC_FALSE);
1137 }
1138 
1139 /*%
1140  * Return true always.
1141  */
1142 static isc_boolean_t
1143 true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1144 	UNUSED(update_rr);
1145 	UNUSED(db_rr);
1146 	return (ISC_TRUE);
1147 }
1148 
1149 /*%
1150  * Return true iff the two RRs have identical rdata.
1151  */
1152 static isc_boolean_t
1153 rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1154 	/*
1155 	 * XXXRTH  This is not a problem, but we should consider creating
1156 	 *         dns_rdata_equal() (that used dns_name_equal()), since it
1157 	 *         would be faster.  Not a priority.
1158 	 */
1159 	return (dns_rdata_casecompare(update_rr, db_rr) == 0 ?
1160 		ISC_TRUE : ISC_FALSE);
1161 }
1162 
1163 /*%
1164  * Return true iff 'update_rr' should replace 'db_rr' according
1165  * to the special RFC2136 rules for CNAME, SOA, and WKS records.
1166  *
1167  * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs
1168  * make little sense, so we replace those, too.
1169  *
1170  * Additionally replace RRSIG that have been generated by the same key
1171  * for the same type.  This simplifies refreshing a offline KSK by not
1172  * requiring that the old RRSIG be deleted.  It also simplifies key
1173  * rollover by only requiring that the new RRSIG be added.
1174  */
1175 static isc_boolean_t
1176 replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1177 	dns_rdata_rrsig_t updatesig, dbsig;
1178 	isc_result_t result;
1179 
1180 	if (db_rr->type != update_rr->type)
1181 		return (ISC_FALSE);
1182 	if (db_rr->type == dns_rdatatype_cname)
1183 		return (ISC_TRUE);
1184 	if (db_rr->type == dns_rdatatype_dname)
1185 		return (ISC_TRUE);
1186 	if (db_rr->type == dns_rdatatype_soa)
1187 		return (ISC_TRUE);
1188 	if (db_rr->type == dns_rdatatype_nsec)
1189 		return (ISC_TRUE);
1190 	if (db_rr->type == dns_rdatatype_rrsig) {
1191 		/*
1192 		 * Replace existing RRSIG with the same keyid,
1193 		 * covered and algorithm.
1194 		 */
1195 		result = dns_rdata_tostruct(db_rr, &dbsig, NULL);
1196 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1197 		result = dns_rdata_tostruct(update_rr, &updatesig, NULL);
1198 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1199 		if (dbsig.keyid == updatesig.keyid &&
1200 		    dbsig.covered == updatesig.covered &&
1201 		    dbsig.algorithm == updatesig.algorithm)
1202 			return (ISC_TRUE);
1203 	}
1204 	if (db_rr->type == dns_rdatatype_wks) {
1205 		/*
1206 		 * Compare the address and protocol fields only.  These
1207 		 * form the first five bytes of the RR data.  Do a
1208 		 * raw binary comparison; unpacking the WKS RRs using
1209 		 * dns_rdata_tostruct() might be cleaner in some ways.
1210 		 */
1211 		INSIST(db_rr->length >= 5 && update_rr->length >= 5);
1212 		return (memcmp(db_rr->data, update_rr->data, 5) == 0 ?
1213 			ISC_TRUE : ISC_FALSE);
1214 	}
1215 
1216 	if (db_rr->type == dns_rdatatype_nsec3param) {
1217 		if (db_rr->length != update_rr->length)
1218 			return (ISC_FALSE);
1219 		INSIST(db_rr->length >= 4 && update_rr->length >= 4);
1220 		/*
1221 		 * Replace NSEC3PARAM records that only differ by the
1222 		 * flags field.
1223 		 */
1224 		if (db_rr->data[0] == update_rr->data[0] &&
1225 		    memcmp(db_rr->data+2, update_rr->data+2,
1226 			   update_rr->length - 2) == 0)
1227 			return (ISC_TRUE);
1228 	}
1229 	return (ISC_FALSE);
1230 }
1231 
1232 /*%
1233  * Internal helper function for delete_if().
1234  */
1235 static isc_result_t
1236 delete_if_action(void *data, rr_t *rr) {
1237 	conditional_delete_ctx_t *ctx = data;
1238 	if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
1239 		isc_result_t result;
1240 		result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
1241 				       DNS_DIFFOP_DEL, ctx->name,
1242 				       rr->ttl, &rr->rdata);
1243 		return (result);
1244 	} else {
1245 		return (ISC_R_SUCCESS);
1246 	}
1247 }
1248 
1249 /*%
1250  * Conditionally delete RRs.  Apply 'predicate' to the RRs
1251  * specified by 'db', 'ver', 'name', and 'type' (which can
1252  * be dns_rdatatype_any to match any type).  Delete those
1253  * RRs for which the predicate returns true, and log the
1254  * deletions in 'diff'.
1255  */
1256 static isc_result_t
1257 delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
1258 	  dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
1259 	  dns_rdata_t *update_rr, dns_diff_t *diff)
1260 {
1261 	conditional_delete_ctx_t ctx;
1262 	ctx.predicate = predicate;
1263 	ctx.db = db;
1264 	ctx.ver = ver;
1265 	ctx.diff = diff;
1266 	ctx.name = name;
1267 	ctx.update_rr = update_rr;
1268 	return (foreach_rr(db, ver, name, type, covers,
1269 			   delete_if_action, &ctx));
1270 }
1271 
1272 /**************************************************************************/
1273 /*%
1274  * Prepare an RR for the addition of the new RR 'ctx->update_rr',
1275  * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting
1276  * the RRs if it is replaced by the new RR or has a conflicting TTL.
1277  * The necessary changes are appended to ctx->del_diff and ctx->add_diff;
1278  * we need to do all deletions before any additions so that we don't run
1279  * into transient states with conflicting TTLs.
1280  */
1281 
1282 typedef struct {
1283 	dns_db_t *db;
1284 	dns_dbversion_t *ver;
1285 	dns_diff_t *diff;
1286 	dns_name_t *name;
1287 	dns_rdata_t *update_rr;
1288 	dns_ttl_t update_rr_ttl;
1289 	isc_boolean_t ignore_add;
1290 	dns_diff_t del_diff;
1291 	dns_diff_t add_diff;
1292 } add_rr_prepare_ctx_t;
1293 
1294 static isc_result_t
1295 add_rr_prepare_action(void *data, rr_t *rr) {
1296 	isc_result_t result = ISC_R_SUCCESS;
1297 	add_rr_prepare_ctx_t *ctx = data;
1298 	dns_difftuple_t *tuple = NULL;
1299 	isc_boolean_t equal;
1300 
1301 	/*
1302 	 * If the update RR is a "duplicate" of the update RR,
1303 	 * the update should be silently ignored.
1304 	 */
1305 	equal = ISC_TF(dns_rdata_casecompare(&rr->rdata, ctx->update_rr) == 0);
1306 	if (equal && rr->ttl == ctx->update_rr_ttl) {
1307 		ctx->ignore_add = ISC_TRUE;
1308 		return (ISC_R_SUCCESS);
1309 	}
1310 
1311 	/*
1312 	 * If this RR is "equal" to the update RR, it should
1313 	 * be deleted before the update RR is added.
1314 	 */
1315 	if (replaces_p(ctx->update_rr, &rr->rdata)) {
1316 		CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
1317 					   ctx->name, rr->ttl, &rr->rdata,
1318 					   &tuple));
1319 		dns_diff_append(&ctx->del_diff, &tuple);
1320 		return (ISC_R_SUCCESS);
1321 	}
1322 
1323 	/*
1324 	 * If this RR differs in TTL from the update RR,
1325 	 * its TTL must be adjusted.
1326 	 */
1327 	if (rr->ttl != ctx->update_rr_ttl) {
1328 		CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
1329 					   ctx->name, rr->ttl, &rr->rdata,
1330 					   &tuple));
1331 		dns_diff_append(&ctx->del_diff, &tuple);
1332 		if (!equal) {
1333 			CHECK(dns_difftuple_create(ctx->add_diff.mctx,
1334 						   DNS_DIFFOP_ADD, ctx->name,
1335 						   ctx->update_rr_ttl,
1336 						   &rr->rdata, &tuple));
1337 			dns_diff_append(&ctx->add_diff, &tuple);
1338 		}
1339 	}
1340  failure:
1341 	return (result);
1342 }
1343 
1344 /**************************************************************************/
1345 /*
1346  * Miscellaneous subroutines.
1347  */
1348 
1349 /*%
1350  * Extract a single update RR from 'section' of dynamic update message
1351  * 'msg', with consistency checking.
1352  *
1353  * Stores the owner name, rdata, and TTL of the update RR at 'name',
1354  * 'rdata', and 'ttl', respectively.
1355  */
1356 static void
1357 get_current_rr(dns_message_t *msg, dns_section_t section,
1358 	       dns_rdataclass_t zoneclass, dns_name_t **name,
1359 	       dns_rdata_t *rdata, dns_rdatatype_t *covers,
1360 	       dns_ttl_t *ttl, dns_rdataclass_t *update_class)
1361 {
1362 	dns_rdataset_t *rdataset;
1363 	isc_result_t result;
1364 	dns_message_currentname(msg, section, name);
1365 	rdataset = ISC_LIST_HEAD((*name)->list);
1366 	INSIST(rdataset != NULL);
1367 	INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
1368 	*covers = rdataset->covers;
1369 	*ttl = rdataset->ttl;
1370 	result = dns_rdataset_first(rdataset);
1371 	INSIST(result == ISC_R_SUCCESS);
1372 	dns_rdataset_current(rdataset, rdata);
1373 	INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
1374 	*update_class = rdata->rdclass;
1375 	rdata->rdclass = zoneclass;
1376 }
1377 
1378 /*%
1379  * Increment the SOA serial number of database 'db', version 'ver'.
1380  * Replace the SOA record in the database, and log the
1381  * change in 'diff'.
1382  */
1383 
1384 	/*
1385 	 * XXXRTH  Failures in this routine will be worth logging, when
1386 	 *         we have a logging system.  Failure to find the zonename
1387 	 *	   or the SOA rdataset warrant at least an UNEXPECTED_ERROR().
1388 	 */
1389 
1390 static isc_result_t
1391 update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
1392 		  isc_mem_t *mctx, dns_updatemethod_t method)
1393 {
1394 	dns_difftuple_t *deltuple = NULL;
1395 	dns_difftuple_t *addtuple = NULL;
1396 	isc_uint32_t serial;
1397 	isc_result_t result;
1398 
1399 	CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple));
1400 	CHECK(dns_difftuple_copy(deltuple, &addtuple));
1401 	addtuple->op = DNS_DIFFOP_ADD;
1402 
1403 	serial = dns_soa_getserial(&addtuple->rdata);
1404 	serial = dns_update_soaserial(serial, method);
1405 	dns_soa_setserial(serial, &addtuple->rdata);
1406 	CHECK(do_one_tuple(&deltuple, db, ver, diff));
1407 	CHECK(do_one_tuple(&addtuple, db, ver, diff));
1408 	result = ISC_R_SUCCESS;
1409 
1410  failure:
1411 	if (addtuple != NULL)
1412 		dns_difftuple_free(&addtuple);
1413 	if (deltuple != NULL)
1414 		dns_difftuple_free(&deltuple);
1415 	return (result);
1416 }
1417 
1418 /*%
1419  * Check that the new SOA record at 'update_rdata' does not
1420  * illegally cause the SOA serial number to decrease or stay
1421  * unchanged relative to the existing SOA in 'db'.
1422  *
1423  * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not.
1424  *
1425  * William King points out that RFC2136 is inconsistent about
1426  * the case where the serial number stays unchanged:
1427  *
1428  *   section 3.4.2.2 requires a server to ignore a SOA update request
1429  *   if the serial number on the update SOA is less_than_or_equal to
1430  *   the zone SOA serial.
1431  *
1432  *   section 3.6 requires a server to ignore a SOA update request if
1433  *   the serial is less_than the zone SOA serial.
1434  *
1435  * Paul says 3.4.2.2 is correct.
1436  *
1437  */
1438 static isc_result_t
1439 check_soa_increment(dns_db_t *db, dns_dbversion_t *ver,
1440 		    dns_rdata_t *update_rdata, isc_boolean_t *ok)
1441 {
1442 	isc_uint32_t db_serial;
1443 	isc_uint32_t update_serial;
1444 	isc_result_t result;
1445 
1446 	update_serial = dns_soa_getserial(update_rdata);
1447 
1448 	result = dns_db_getsoaserial(db, ver, &db_serial);
1449 	if (result != ISC_R_SUCCESS)
1450 		return (result);
1451 
1452 	if (DNS_SERIAL_GE(db_serial, update_serial)) {
1453 		*ok = ISC_FALSE;
1454 	} else {
1455 		*ok = ISC_TRUE;
1456 	}
1457 
1458 	return (ISC_R_SUCCESS);
1459 
1460 }
1461 
1462 /**************************************************************************/
1463 /*%
1464  * The actual update code in all its glory.  We try to follow
1465  * the RFC2136 pseudocode as closely as possible.
1466  */
1467 
1468 static isc_result_t
1469 send_update_event(ns_client_t *client, dns_zone_t *zone) {
1470 	isc_result_t result = ISC_R_SUCCESS;
1471 	update_event_t *event = NULL;
1472 	isc_task_t *zonetask = NULL;
1473 	ns_client_t *evclient;
1474 
1475 	event = (update_event_t *)
1476 		isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
1477 				   update_action, NULL, sizeof(*event));
1478 	if (event == NULL)
1479 		FAIL(ISC_R_NOMEMORY);
1480 	event->zone = zone;
1481 	event->result = ISC_R_SUCCESS;
1482 
1483 	evclient = NULL;
1484 	ns_client_attach(client, &evclient);
1485 	INSIST(client->nupdates == 0);
1486 	client->nupdates++;
1487 	event->ev_arg = evclient;
1488 
1489 	dns_zone_gettask(zone, &zonetask);
1490 	isc_task_send(zonetask, ISC_EVENT_PTR(&event));
1491 
1492  failure:
1493 	if (event != NULL)
1494 		isc_event_free(ISC_EVENT_PTR(&event));
1495 	return (result);
1496 }
1497 
1498 static void
1499 respond(ns_client_t *client, isc_result_t result) {
1500 	isc_result_t msg_result;
1501 
1502 	msg_result = dns_message_reply(client->message, ISC_TRUE);
1503 	if (msg_result != ISC_R_SUCCESS)
1504 		goto msg_failure;
1505 	client->message->rcode = dns_result_torcode(result);
1506 
1507 	ns_client_send(client);
1508 	return;
1509 
1510  msg_failure:
1511 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
1512 		      ISC_LOG_ERROR,
1513 		      "could not create update response message: %s",
1514 		      isc_result_totext(msg_result));
1515 	ns_client_next(client, msg_result);
1516 }
1517 
1518 void
1519 ns_update_start(ns_client_t *client, isc_result_t sigresult) {
1520 	dns_message_t *request = client->message;
1521 	isc_result_t result;
1522 	dns_name_t *zonename;
1523 	dns_rdataset_t *zone_rdataset;
1524 	dns_zone_t *zone = NULL, *raw = NULL;
1525 
1526 	/*
1527 	 * Interpret the zone section.
1528 	 */
1529 	result = dns_message_firstname(request, DNS_SECTION_ZONE);
1530 	if (result != ISC_R_SUCCESS)
1531 		FAILC(DNS_R_FORMERR, "update zone section empty");
1532 
1533 	/*
1534 	 * The zone section must contain exactly one "question", and
1535 	 * it must be of type SOA.
1536 	 */
1537 	zonename = NULL;
1538 	dns_message_currentname(request, DNS_SECTION_ZONE, &zonename);
1539 	zone_rdataset = ISC_LIST_HEAD(zonename->list);
1540 	if (zone_rdataset->type != dns_rdatatype_soa)
1541 		FAILC(DNS_R_FORMERR,
1542 		      "update zone section contains non-SOA");
1543 	if (ISC_LIST_NEXT(zone_rdataset, link) != NULL)
1544 		FAILC(DNS_R_FORMERR,
1545 		      "update zone section contains multiple RRs");
1546 
1547 	/* The zone section must have exactly one name. */
1548 	result = dns_message_nextname(request, DNS_SECTION_ZONE);
1549 	if (result != ISC_R_NOMORE)
1550 		FAILC(DNS_R_FORMERR,
1551 		      "update zone section contains multiple RRs");
1552 
1553 	result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
1554 			     &zone);
1555 	if (result != ISC_R_SUCCESS)
1556 		FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
1557 
1558 	/*
1559 	 * If there is a raw (unsigned) zone associated with this
1560 	 * zone then it processes the UPDATE request.
1561 	 */
1562 	dns_zone_getraw(zone, &raw);
1563 	if (raw != NULL) {
1564 		dns_zone_detach(&zone);
1565 		dns_zone_attach(raw, &zone);
1566 		dns_zone_detach(&raw);
1567 	}
1568 
1569 	switch(dns_zone_gettype(zone)) {
1570 	case dns_zone_master:
1571 	case dns_zone_dlz:
1572 		/*
1573 		 * We can now fail due to a bad signature as we now know
1574 		 * that we are the master.
1575 		 */
1576 		if (sigresult != ISC_R_SUCCESS)
1577 			FAIL(sigresult);
1578 		CHECK(send_update_event(client, zone));
1579 		break;
1580 	case dns_zone_slave:
1581 		CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone),
1582 				     "update forwarding", zonename, ISC_TRUE,
1583 				     ISC_FALSE));
1584 		CHECK(send_forward_event(client, zone));
1585 		break;
1586 	default:
1587 		FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
1588 	}
1589 	return;
1590 
1591  failure:
1592 	if (result == DNS_R_REFUSED) {
1593 		INSIST(dns_zone_gettype(zone) == dns_zone_slave);
1594 		inc_stats(zone, dns_nsstatscounter_updaterej);
1595 	}
1596 	/*
1597 	 * We failed without having sent an update event to the zone.
1598 	 * We are still in the client task context, so we can
1599 	 * simply give an error response without switching tasks.
1600 	 */
1601 	respond(client, result);
1602 	if (zone != NULL)
1603 		dns_zone_detach(&zone);
1604 }
1605 
1606 /*%
1607  * DS records are not allowed to exist without corresponding NS records,
1608  * RFC 3658, 2.2 Protocol Change,
1609  * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex".
1610  */
1611 
1612 static isc_result_t
1613 remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) {
1614 	isc_result_t result;
1615 	isc_boolean_t ns_exists;
1616 	dns_difftuple_t *tupple;
1617 	dns_diff_t temp_diff;
1618 
1619 	dns_diff_init(diff->mctx, &temp_diff);
1620 
1621 	for (tupple = ISC_LIST_HEAD(diff->tuples);
1622 	     tupple != NULL;
1623 	     tupple = ISC_LIST_NEXT(tupple, link)) {
1624 		if (!((tupple->op == DNS_DIFFOP_DEL &&
1625 		       tupple->rdata.type == dns_rdatatype_ns) ||
1626 		      (tupple->op == DNS_DIFFOP_ADD &&
1627 		       tupple->rdata.type == dns_rdatatype_ds)))
1628 			continue;
1629 		CHECK(rrset_exists(db, newver, &tupple->name,
1630 				   dns_rdatatype_ns, 0, &ns_exists));
1631 		if (ns_exists &&
1632 		    !dns_name_equal(&tupple->name, dns_db_origin(db)))
1633 			continue;
1634 		CHECK(delete_if(true_p, db, newver, &tupple->name,
1635 				dns_rdatatype_ds, 0, NULL, &temp_diff));
1636 	}
1637 	result = ISC_R_SUCCESS;
1638 
1639  failure:
1640 	for (tupple = ISC_LIST_HEAD(temp_diff.tuples);
1641 	     tupple != NULL;
1642 	     tupple = ISC_LIST_HEAD(temp_diff.tuples)) {
1643 		ISC_LIST_UNLINK(temp_diff.tuples, tupple, link);
1644 		dns_diff_appendminimal(diff, &tupple);
1645 	}
1646 	return (result);
1647 }
1648 
1649 /*
1650  * This implements the post load integrity checks for mx records.
1651  */
1652 static isc_result_t
1653 check_mx(ns_client_t *client, dns_zone_t *zone,
1654 	 dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff)
1655 {
1656 	char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
1657 	char ownerbuf[DNS_NAME_FORMATSIZE];
1658 	char namebuf[DNS_NAME_FORMATSIZE];
1659 	char altbuf[DNS_NAME_FORMATSIZE];
1660 	dns_difftuple_t *t;
1661 	dns_fixedname_t fixed;
1662 	dns_name_t *foundname;
1663 	dns_rdata_mx_t mx;
1664 	dns_rdata_t rdata;
1665 	isc_boolean_t ok = ISC_TRUE;
1666 	isc_boolean_t isaddress;
1667 	isc_result_t result;
1668 	struct in6_addr addr6;
1669 	struct in_addr addr;
1670 	unsigned int options;
1671 
1672 	dns_fixedname_init(&fixed);
1673 	foundname = dns_fixedname_name(&fixed);
1674 	dns_rdata_init(&rdata);
1675 	options = dns_zone_getoptions(zone);
1676 
1677 	for (t = ISC_LIST_HEAD(diff->tuples);
1678 	     t != NULL;
1679 	     t = ISC_LIST_NEXT(t, link)) {
1680 		if (t->op != DNS_DIFFOP_ADD ||
1681 		    t->rdata.type != dns_rdatatype_mx)
1682 			continue;
1683 
1684 		result = dns_rdata_tostruct(&t->rdata, &mx, NULL);
1685 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1686 		/*
1687 		 * Check if we will error out if we attempt to reload the
1688 		 * zone.
1689 		 */
1690 		dns_name_format(&mx.mx, namebuf, sizeof(namebuf));
1691 		dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf));
1692 		isaddress = ISC_FALSE;
1693 		if ((options & DNS_RDATA_CHECKMX) != 0 &&
1694 		    strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) {
1695 			if (tmp[strlen(tmp) - 1] == '.')
1696 				tmp[strlen(tmp) - 1] = '\0';
1697 			if (inet_aton(tmp, &addr) == 1 ||
1698 			    inet_pton(AF_INET6, tmp, &addr6) == 1)
1699 				isaddress = ISC_TRUE;
1700 		}
1701 
1702 		if (isaddress && (options & DNS_RDATA_CHECKMXFAIL) != 0) {
1703 			update_log(client, zone, ISC_LOG_ERROR,
1704 				   "%s/MX: '%s': %s",
1705 				   ownerbuf, namebuf,
1706 				   dns_result_totext(DNS_R_MXISADDRESS));
1707 			ok = ISC_FALSE;
1708 		} else if (isaddress) {
1709 			update_log(client, zone, ISC_LOG_WARNING,
1710 				   "%s/MX: warning: '%s': %s",
1711 				   ownerbuf, namebuf,
1712 				   dns_result_totext(DNS_R_MXISADDRESS));
1713 		}
1714 
1715 		/*
1716 		 * Check zone integrity checks.
1717 		 */
1718 		if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0)
1719 			continue;
1720 		result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a,
1721 				     0, 0, NULL, foundname, NULL, NULL);
1722 		if (result == ISC_R_SUCCESS)
1723 			continue;
1724 
1725 		if (result == DNS_R_NXRRSET) {
1726 			result = dns_db_find(db, &mx.mx, newver,
1727 					     dns_rdatatype_aaaa,
1728 					     0, 0, NULL, foundname,
1729 					     NULL, NULL);
1730 			if (result == ISC_R_SUCCESS)
1731 				continue;
1732 		}
1733 
1734 		if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) {
1735 			update_log(client, zone, ISC_LOG_ERROR,
1736 				   "%s/MX '%s' has no address records "
1737 				   "(A or AAAA)", ownerbuf, namebuf);
1738 			ok = ISC_FALSE;
1739 		} else if (result == DNS_R_CNAME) {
1740 			update_log(client, zone, ISC_LOG_ERROR,
1741 				   "%s/MX '%s' is a CNAME (illegal)",
1742 				   ownerbuf, namebuf);
1743 			ok = ISC_FALSE;
1744 		} else if (result == DNS_R_DNAME) {
1745 			dns_name_format(foundname, altbuf, sizeof altbuf);
1746 			update_log(client, zone, ISC_LOG_ERROR,
1747 				   "%s/MX '%s' is below a DNAME '%s' (illegal)",
1748 				   ownerbuf, namebuf, altbuf);
1749 			ok = ISC_FALSE;
1750 		}
1751 	}
1752 	return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
1753 }
1754 
1755 static isc_result_t
1756 rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1757 	  const dns_rdata_t *rdata, isc_boolean_t *flag)
1758 {
1759 	dns_rdataset_t rdataset;
1760 	dns_dbnode_t *node = NULL;
1761 	isc_result_t result;
1762 
1763 	dns_rdataset_init(&rdataset);
1764 	if (rdata->type == dns_rdatatype_nsec3)
1765 		CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
1766 	else
1767 		CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1768 	result = dns_db_findrdataset(db, node, ver, rdata->type, 0,
1769 				     (isc_stdtime_t) 0, &rdataset, NULL);
1770 	if (result == ISC_R_NOTFOUND) {
1771 		*flag = ISC_FALSE;
1772 		result = ISC_R_SUCCESS;
1773 		goto failure;
1774 	}
1775 
1776 	for (result = dns_rdataset_first(&rdataset);
1777 	     result == ISC_R_SUCCESS;
1778 	     result = dns_rdataset_next(&rdataset)) {
1779 		dns_rdata_t myrdata = DNS_RDATA_INIT;
1780 		dns_rdataset_current(&rdataset, &myrdata);
1781 		if (!dns_rdata_casecompare(&myrdata, rdata))
1782 			break;
1783 	}
1784 	dns_rdataset_disassociate(&rdataset);
1785 	if (result == ISC_R_SUCCESS) {
1786 		*flag = ISC_TRUE;
1787 	} else if (result == ISC_R_NOMORE) {
1788 		*flag = ISC_FALSE;
1789 		result = ISC_R_SUCCESS;
1790 	}
1791 
1792  failure:
1793 	if (node != NULL)
1794 		dns_db_detachnode(db, &node);
1795 	return (result);
1796 }
1797 
1798 static isc_result_t
1799 get_iterations(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype,
1800 	       unsigned int *iterationsp)
1801 {
1802 	dns_dbnode_t *node = NULL;
1803 	dns_rdata_nsec3param_t nsec3param;
1804 	dns_rdataset_t rdataset;
1805 	isc_result_t result;
1806 	unsigned int iterations = 0;
1807 
1808 	dns_rdataset_init(&rdataset);
1809 
1810 	result = dns_db_getoriginnode(db, &node);
1811 	if (result != ISC_R_SUCCESS)
1812 		return (result);
1813 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
1814 				     0, (isc_stdtime_t) 0, &rdataset, NULL);
1815 	if (result == ISC_R_NOTFOUND)
1816 		goto try_private;
1817 	if (result != ISC_R_SUCCESS)
1818 		goto failure;
1819 
1820 	for (result = dns_rdataset_first(&rdataset);
1821 	     result == ISC_R_SUCCESS;
1822 	     result = dns_rdataset_next(&rdataset)) {
1823 		dns_rdata_t rdata = DNS_RDATA_INIT;
1824 		dns_rdataset_current(&rdataset, &rdata);
1825 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
1826 		if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
1827 			continue;
1828 		if (nsec3param.iterations > iterations)
1829 			iterations = nsec3param.iterations;
1830 	}
1831 	if (result != ISC_R_NOMORE)
1832 		goto failure;
1833 
1834 	dns_rdataset_disassociate(&rdataset);
1835 
1836  try_private:
1837 	if (privatetype == 0)
1838 		goto success;
1839 
1840 	result = dns_db_findrdataset(db, node, ver, privatetype,
1841 				     0, (isc_stdtime_t) 0, &rdataset, NULL);
1842 	if (result == ISC_R_NOTFOUND)
1843 		goto success;
1844 	if (result != ISC_R_SUCCESS)
1845 		goto failure;
1846 
1847 	for (result = dns_rdataset_first(&rdataset);
1848 	     result == ISC_R_SUCCESS;
1849 	     result = dns_rdataset_next(&rdataset)) {
1850 		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
1851 		dns_rdata_t private = DNS_RDATA_INIT;
1852 		dns_rdata_t rdata = DNS_RDATA_INIT;
1853 
1854 		dns_rdataset_current(&rdataset, &rdata);
1855 		if (!dns_nsec3param_fromprivate(&private, &rdata,
1856 						buf, sizeof(buf)))
1857 			continue;
1858 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
1859 		if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
1860 			continue;
1861 		if (nsec3param.iterations > iterations)
1862 			iterations = nsec3param.iterations;
1863 	}
1864 	if (result != ISC_R_NOMORE)
1865 		goto failure;
1866 
1867  success:
1868 	*iterationsp = iterations;
1869 	result = ISC_R_SUCCESS;
1870 
1871  failure:
1872 	if (node != NULL)
1873 		dns_db_detachnode(db, &node);
1874 	if (dns_rdataset_isassociated(&rdataset))
1875 		dns_rdataset_disassociate(&rdataset);
1876 	return (result);
1877 }
1878 
1879 /*
1880  * Prevent the zone entering a inconsistent state where
1881  * NSEC only DNSKEYs are present with NSEC3 chains.
1882  */
1883 static isc_result_t
1884 check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
1885 	     dns_dbversion_t *ver, dns_diff_t *diff)
1886 {
1887 	dns_difftuple_t *tuple;
1888 	isc_boolean_t nseconly = ISC_FALSE, nsec3 = ISC_FALSE;
1889 	isc_result_t result;
1890 	unsigned int iterations = 0, max;
1891 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
1892 
1893 	/* Scan the tuples for an NSEC-only DNSKEY or an NSEC3PARAM */
1894 	for (tuple = ISC_LIST_HEAD(diff->tuples);
1895 	     tuple != NULL;
1896 	     tuple = ISC_LIST_NEXT(tuple, link)) {
1897 		if (tuple->op != DNS_DIFFOP_ADD)
1898 			continue;
1899 
1900 		if (tuple->rdata.type == dns_rdatatype_dnskey) {
1901 			isc_uint8_t alg;
1902 			alg = tuple->rdata.data[3];
1903 			if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
1904 			    alg == DST_ALG_DSA || alg == DST_ALG_ECC) {
1905 				nseconly = ISC_TRUE;
1906 				break;
1907 			}
1908 		} else if (tuple->rdata.type == dns_rdatatype_nsec3param) {
1909 			nsec3 = ISC_TRUE;
1910 			break;
1911 		}
1912 	}
1913 
1914 	/* Check existing DB for NSEC-only DNSKEY */
1915 	if (!nseconly) {
1916 		result = dns_nsec_nseconly(db, ver, &nseconly);
1917 
1918 		/*
1919 		 * An NSEC3PARAM update can proceed without a DNSKEY (it
1920 		 * will trigger a delayed change), so we can ignore
1921 		 * ISC_R_NOTFOUND here.
1922 		 */
1923 		if (result == ISC_R_NOTFOUND)
1924 			result = ISC_R_SUCCESS;
1925 
1926 		CHECK(result);
1927 	}
1928 
1929 	/* Check existing DB for NSEC3 */
1930 	if (!nsec3)
1931 		CHECK(dns_nsec3_activex(db, ver, ISC_FALSE,
1932 					privatetype, &nsec3));
1933 
1934 	/* Refuse to allow NSEC3 with NSEC-only keys */
1935 	if (nseconly && nsec3) {
1936 		update_log(client, zone, ISC_LOG_ERROR,
1937 			   "NSEC only DNSKEYs and NSEC3 chains not allowed");
1938 		result = DNS_R_REFUSED;
1939 		goto failure;
1940 	}
1941 
1942 	/* Verify NSEC3 params */
1943 	CHECK(get_iterations(db, ver, privatetype, &iterations));
1944 	CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max));
1945 	if (max != 0 && iterations > max) {
1946 		update_log(client, zone, ISC_LOG_ERROR,
1947 			   "too many NSEC3 iterations (%u) for "
1948 			   "weakest DNSKEY (%u)", iterations, max);
1949 		result = DNS_R_REFUSED;
1950 		goto failure;
1951 	}
1952 
1953  failure:
1954 	return (result);
1955 }
1956 
1957 /*
1958  * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
1959  */
1960 static isc_result_t
1961 add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
1962 		       dns_dbversion_t *ver, dns_diff_t *diff)
1963 {
1964 	isc_result_t result = ISC_R_SUCCESS;
1965 	dns_difftuple_t *tuple, *newtuple = NULL, *next;
1966 	dns_rdata_t rdata = DNS_RDATA_INIT;
1967 	unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1];
1968 	dns_diff_t temp_diff;
1969 	dns_diffop_t op;
1970 	isc_boolean_t flag;
1971 	dns_name_t *name = dns_zone_getorigin(zone);
1972 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
1973 	isc_uint32_t ttl = 0;
1974 	isc_boolean_t ttl_good = ISC_FALSE;
1975 
1976 	update_log(client, zone, ISC_LOG_DEBUG(3),
1977 		    "checking for NSEC3PARAM changes");
1978 
1979 	dns_diff_init(diff->mctx, &temp_diff);
1980 
1981 	/*
1982 	 * Extract NSEC3PARAM tuples from list.
1983 	 */
1984 	for (tuple = ISC_LIST_HEAD(diff->tuples);
1985 	     tuple != NULL;
1986 	     tuple = next) {
1987 
1988 		next = ISC_LIST_NEXT(tuple, link);
1989 
1990 		if (tuple->rdata.type != dns_rdatatype_nsec3param ||
1991 		    !dns_name_equal(name, &tuple->name))
1992 			continue;
1993 		ISC_LIST_UNLINK(diff->tuples, tuple, link);
1994 		ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
1995 	}
1996 
1997 	/*
1998 	 * Extract TTL changes pairs, we don't need to convert these to
1999 	 * delayed changes.
2000 	 */
2001 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
2002 	     tuple != NULL; tuple = next) {
2003 		if (tuple->op == DNS_DIFFOP_ADD) {
2004 			if (!ttl_good) {
2005 				/*
2006 				 * Any adds here will contain the final
2007 				 * NSEC3PARAM RRset TTL.
2008 				 */
2009 				ttl = tuple->ttl;
2010 				ttl_good = ISC_TRUE;
2011 			}
2012 			/*
2013 			 * Walk the temp_diff list looking for the
2014 			 * corresponding delete.
2015 			 */
2016 			next = ISC_LIST_HEAD(temp_diff.tuples);
2017 			while (next != NULL) {
2018 				unsigned char *next_data = next->rdata.data;
2019 				unsigned char *tuple_data = tuple->rdata.data;
2020 				if (next->op == DNS_DIFFOP_DEL &&
2021 				    next->rdata.length == tuple->rdata.length &&
2022 				    !memcmp(next_data, tuple_data,
2023 					    next->rdata.length)) {
2024 					ISC_LIST_UNLINK(temp_diff.tuples, next,
2025 							link);
2026 					ISC_LIST_APPEND(diff->tuples, next,
2027 							link);
2028 					break;
2029 				}
2030 				next = ISC_LIST_NEXT(next, link);
2031 			}
2032 			/*
2033 			 * If we have not found a pair move onto the next
2034 			 * tuple.
2035 			 */
2036 			if (next == NULL) {
2037 				next = ISC_LIST_NEXT(tuple, link);
2038 				continue;
2039 			}
2040 			/*
2041 			 * Find the next tuple to be processed before
2042 			 * unlinking then complete moving the pair to 'diff'.
2043 			 */
2044 			next = ISC_LIST_NEXT(tuple, link);
2045 			ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2046 			ISC_LIST_APPEND(diff->tuples, tuple, link);
2047 		} else
2048 			next = ISC_LIST_NEXT(tuple, link);
2049 	}
2050 
2051 	/*
2052 	 * Preserve any ongoing changes from a BIND 9.6.x upgrade.
2053 	 *
2054 	 * Any NSEC3PARAM records with flags other than OPTOUT named
2055 	 * in managing and should not be touched so revert such changes
2056 	 * taking into account any TTL change of the NSEC3PARAM RRset.
2057 	 */
2058 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
2059 	     tuple != NULL; tuple = next) {
2060 		next = ISC_LIST_NEXT(tuple, link);
2061 		if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
2062 			/*
2063 			 * If we havn't had any adds then the tuple->ttl must
2064 			 * be the original ttl and should be used for any
2065 			 * future changes.
2066 			 */
2067 			if (!ttl_good) {
2068 				ttl = tuple->ttl;
2069 				ttl_good = ISC_TRUE;
2070 			}
2071 			op = (tuple->op == DNS_DIFFOP_DEL) ?
2072 			     DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
2073 			CHECK(dns_difftuple_create(diff->mctx, op, name,
2074 						   ttl, &tuple->rdata,
2075 						   &newtuple));
2076 			CHECK(do_one_tuple(&newtuple, db, ver, diff));
2077 			ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2078 			dns_diff_appendminimal(diff, &tuple);
2079 		}
2080 	}
2081 
2082 	/*
2083 	 * We now have just the actual changes to the NSEC3PARAM RRset.
2084 	 * Convert the adds to delayed adds and the deletions into delayed
2085 	 * deletions.
2086 	 */
2087 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
2088 	     tuple != NULL; tuple = next) {
2089 		/*
2090 		 * If we havn't had any adds then the tuple->ttl must be the
2091 		 * original ttl and should be used for any future changes.
2092 		 */
2093 		if (!ttl_good) {
2094 			ttl = tuple->ttl;
2095 			ttl_good = ISC_TRUE;
2096 		}
2097 		if (tuple->op == DNS_DIFFOP_ADD) {
2098 			isc_boolean_t nseconly = ISC_FALSE;
2099 
2100 			/*
2101 			 * Look for any deletes which match this ADD ignoring
2102 			 * flags.  We don't need to explictly remove them as
2103 			 * they will be removed a side effect of processing
2104 			 * the add.
2105 			 */
2106 			next = ISC_LIST_HEAD(temp_diff.tuples);
2107 			while (next != NULL) {
2108 				unsigned char *next_data = next->rdata.data;
2109 				unsigned char *tuple_data = tuple->rdata.data;
2110 				if (next->op != DNS_DIFFOP_DEL ||
2111 				    next->rdata.length != tuple->rdata.length ||
2112 				    next_data[0] != tuple_data[0] ||
2113 				    next_data[2] != tuple_data[2] ||
2114 				    next_data[3] != tuple_data[3] ||
2115 				    memcmp(next_data + 4, tuple_data + 4,
2116 					   tuple->rdata.length - 4)) {
2117 					next = ISC_LIST_NEXT(next, link);
2118 					continue;
2119 				}
2120 				ISC_LIST_UNLINK(temp_diff.tuples, next, link);
2121 				ISC_LIST_APPEND(diff->tuples, next, link);
2122 				next = ISC_LIST_HEAD(temp_diff.tuples);
2123 			}
2124 
2125 			/*
2126 			 * Create a private-type record to signal that
2127 			 * we want a delayed NSEC3 chain add/delete
2128 			 */
2129 			dns_nsec3param_toprivate(&tuple->rdata, &rdata,
2130 						 privatetype, buf, sizeof(buf));
2131 			buf[2] |= DNS_NSEC3FLAG_CREATE;
2132 
2133 			/*
2134 			 * If the zone is not currently capable of
2135 			 * supporting an NSEC3 chain, then we set the
2136 			 * INITIAL flag to indicate that these parameters
2137 			 * are to be used later.
2138 			 */
2139 			result = dns_nsec_nseconly(db, ver, &nseconly);
2140 			if (result == ISC_R_NOTFOUND || nseconly)
2141 				buf[2] |= DNS_NSEC3FLAG_INITIAL;
2142 
2143 			/*
2144 			 * See if this CREATE request already exists.
2145 			 */
2146 			CHECK(rr_exists(db, ver, name, &rdata, &flag));
2147 
2148 			if (!flag) {
2149 				CHECK(dns_difftuple_create(diff->mctx,
2150 							   DNS_DIFFOP_ADD,
2151 							   name, 0, &rdata,
2152 							   &newtuple));
2153 				CHECK(do_one_tuple(&newtuple, db, ver, diff));
2154 			}
2155 
2156 			/*
2157 			 * Remove any existing CREATE request to add an
2158 			 * otherwise indentical chain with a reversed
2159 			 * OPTOUT state.
2160 			 */
2161 			buf[2] ^= DNS_NSEC3FLAG_OPTOUT;
2162 			CHECK(rr_exists(db, ver, name, &rdata, &flag));
2163 
2164 			if (flag) {
2165 				CHECK(dns_difftuple_create(diff->mctx,
2166 							   DNS_DIFFOP_DEL,
2167 							   name, 0, &rdata,
2168 							   &newtuple));
2169 				CHECK(do_one_tuple(&newtuple, db, ver, diff));
2170 			}
2171 
2172 			/*
2173 			 * Find the next tuple to be processed and remove the
2174 			 * temporary add record.
2175 			 */
2176 			next = ISC_LIST_NEXT(tuple, link);
2177 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
2178 						   name, ttl, &tuple->rdata,
2179 						   &newtuple));
2180 			CHECK(do_one_tuple(&newtuple, db, ver, diff));
2181 			ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2182 			dns_diff_appendminimal(diff, &tuple);
2183 			dns_rdata_reset(&rdata);
2184 		} else
2185 			next = ISC_LIST_NEXT(tuple, link);
2186 	}
2187 
2188 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
2189 	     tuple != NULL; tuple = next) {
2190 
2191 		INSIST(ttl_good);
2192 
2193 		next = ISC_LIST_NEXT(tuple, link);
2194 		/*
2195 		 * See if we already have a REMOVE request in progress.
2196 		 */
2197 		dns_nsec3param_toprivate(&tuple->rdata, &rdata, privatetype,
2198 					 buf, sizeof(buf));
2199 
2200 		buf[2] |= DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
2201 
2202 		CHECK(rr_exists(db, ver, name, &rdata, &flag));
2203 		if (!flag) {
2204 			buf[2] &= ~DNS_NSEC3FLAG_NONSEC;
2205 			CHECK(rr_exists(db, ver, name, &rdata, &flag));
2206 		}
2207 
2208 		if (!flag) {
2209 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
2210 						   name, 0, &rdata, &newtuple));
2211 			CHECK(do_one_tuple(&newtuple, db, ver, diff));
2212 		}
2213 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
2214 					   ttl, &tuple->rdata, &newtuple));
2215 		CHECK(do_one_tuple(&newtuple, db, ver, diff));
2216 		ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2217 		dns_diff_appendminimal(diff, &tuple);
2218 		dns_rdata_reset(&rdata);
2219 	}
2220 
2221 	result = ISC_R_SUCCESS;
2222  failure:
2223 	dns_diff_clear(&temp_diff);
2224 	return (result);
2225 }
2226 
2227 static isc_result_t
2228 rollback_private(dns_db_t *db, dns_rdatatype_t privatetype,
2229 		 dns_dbversion_t *ver, dns_diff_t *diff)
2230 {
2231 	dns_diff_t temp_diff;
2232 	dns_diffop_t op;
2233 	dns_difftuple_t *tuple, *newtuple = NULL, *next;
2234 	dns_name_t *name = dns_db_origin(db);
2235 	isc_mem_t *mctx = diff->mctx;
2236 	isc_result_t result;
2237 
2238 	if (privatetype == 0)
2239 		return (ISC_R_SUCCESS);
2240 
2241 	dns_diff_init(mctx, &temp_diff);
2242 
2243 	/*
2244 	 * Extract the changes to be rolled back.
2245 	 */
2246 	for (tuple = ISC_LIST_HEAD(diff->tuples);
2247 	     tuple != NULL; tuple = next) {
2248 
2249 		next = ISC_LIST_NEXT(tuple, link);
2250 
2251 		if (tuple->rdata.type != privatetype ||
2252 		    !dns_name_equal(name, &tuple->name))
2253 			continue;
2254 
2255 		/*
2256 		 * Allow records which indicate that a zone has been
2257 		 * signed with a DNSKEY to be removed.
2258 		 */
2259 		if (tuple->op == DNS_DIFFOP_DEL &&
2260 		    tuple->rdata.length == 5 &&
2261 		    tuple->rdata.data[0] != 0 &&
2262 		    tuple->rdata.data[4] != 0)
2263 			continue;
2264 
2265 		ISC_LIST_UNLINK(diff->tuples, tuple, link);
2266 		ISC_LIST_PREPEND(temp_diff.tuples, tuple, link);
2267 	}
2268 
2269 	/*
2270 	 * Rollback the changes.
2271 	 */
2272 	while ((tuple = ISC_LIST_HEAD(temp_diff.tuples)) != NULL) {
2273 		op = (tuple->op == DNS_DIFFOP_DEL) ?
2274 		      DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
2275 		CHECK(dns_difftuple_create(mctx, op, name, tuple->ttl,
2276 					   &tuple->rdata, &newtuple));
2277 		CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff));
2278 	}
2279 	result = ISC_R_SUCCESS;
2280 
2281  failure:
2282 	dns_diff_clear(&temp_diff);
2283 	return (result);
2284 }
2285 
2286 /*
2287  * Add records to cause the delayed signing of the zone by added DNSKEY
2288  * to remove the RRSIG records generated by a deleted DNSKEY.
2289  */
2290 static isc_result_t
2291 add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
2292 		    dns_dbversion_t *ver, dns_diff_t *diff)
2293 {
2294 	dns_difftuple_t *tuple, *newtuple = NULL, *next;
2295 	dns_rdata_dnskey_t dnskey;
2296 	dns_rdata_t rdata = DNS_RDATA_INIT;
2297 	isc_boolean_t flag;
2298 	isc_region_t r;
2299 	isc_result_t result = ISC_R_SUCCESS;
2300 	isc_uint16_t keyid;
2301 	unsigned char buf[5];
2302 	dns_name_t *name = dns_db_origin(db);
2303 	dns_diff_t temp_diff;
2304 
2305 	dns_diff_init(diff->mctx, &temp_diff);
2306 
2307 	/*
2308 	 * Extract the DNSKEY tuples from the list.
2309 	 */
2310 	for (tuple = ISC_LIST_HEAD(diff->tuples);
2311 	     tuple != NULL; tuple = next) {
2312 
2313 		next = ISC_LIST_NEXT(tuple, link);
2314 
2315 		if (tuple->rdata.type != dns_rdatatype_dnskey)
2316 			continue;
2317 
2318 		ISC_LIST_UNLINK(diff->tuples, tuple, link);
2319 		ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
2320 	}
2321 
2322 	/*
2323 	 * Extract TTL changes pairs, we don't need signing records for these.
2324 	 */
2325 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
2326 	     tuple != NULL; tuple = next) {
2327 		if (tuple->op == DNS_DIFFOP_ADD) {
2328 			/*
2329 			 * Walk the temp_diff list looking for the
2330 			 * corresponding delete.
2331 			 */
2332 			next = ISC_LIST_HEAD(temp_diff.tuples);
2333 			while (next != NULL) {
2334 				unsigned char *next_data = next->rdata.data;
2335 				unsigned char *tuple_data = tuple->rdata.data;
2336 				if (next->op == DNS_DIFFOP_DEL &&
2337 				    dns_name_equal(&tuple->name, &next->name) &&
2338 				    next->rdata.length == tuple->rdata.length &&
2339 				    !memcmp(next_data, tuple_data,
2340 					    next->rdata.length)) {
2341 					ISC_LIST_UNLINK(temp_diff.tuples, next,
2342 							link);
2343 					ISC_LIST_APPEND(diff->tuples, next,
2344 							link);
2345 					break;
2346 				}
2347 				next = ISC_LIST_NEXT(next, link);
2348 			}
2349 			/*
2350 			 * If we have not found a pair move onto the next
2351 			 * tuple.
2352 			 */
2353 			if (next == NULL) {
2354 				next = ISC_LIST_NEXT(tuple, link);
2355 				continue;
2356 			}
2357 			/*
2358 			 * Find the next tuple to be processed before
2359 			 * unlinking then complete moving the pair to 'diff'.
2360 			 */
2361 			next = ISC_LIST_NEXT(tuple, link);
2362 			ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2363 			ISC_LIST_APPEND(diff->tuples, tuple, link);
2364 		} else
2365 			next = ISC_LIST_NEXT(tuple, link);
2366 	}
2367 
2368 	/*
2369 	 * Process the remaining DNSKEY entries.
2370 	 */
2371 	for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
2372 	     tuple != NULL;
2373 	     tuple = ISC_LIST_HEAD(temp_diff.tuples)) {
2374 
2375 		ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
2376 		ISC_LIST_APPEND(diff->tuples, tuple, link);
2377 
2378 		result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
2379 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
2380 		if ((dnskey.flags &
2381 		     (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
2382 			 != DNS_KEYOWNER_ZONE)
2383 			continue;
2384 
2385 		dns_rdata_toregion(&tuple->rdata, &r);
2386 
2387 		keyid = dst_region_computeid(&r, dnskey.algorithm);
2388 
2389 		buf[0] = dnskey.algorithm;
2390 		buf[1] = (keyid & 0xff00) >> 8;
2391 		buf[2] = (keyid & 0xff);
2392 		buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
2393 		buf[4] = 0;
2394 		rdata.data = buf;
2395 		rdata.length = sizeof(buf);
2396 		rdata.type = privatetype;
2397 		rdata.rdclass = tuple->rdata.rdclass;
2398 
2399 		CHECK(rr_exists(db, ver, name, &rdata, &flag));
2400 		if (flag)
2401 			continue;
2402 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
2403 					   name, 0, &rdata, &newtuple));
2404 		CHECK(do_one_tuple(&newtuple, db, ver, diff));
2405 		INSIST(newtuple == NULL);
2406 		/*
2407 		 * Remove any record which says this operation has already
2408 		 * completed.
2409 		 */
2410 		buf[4] = 1;
2411 		CHECK(rr_exists(db, ver, name, &rdata, &flag));
2412 		if (flag) {
2413 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
2414 						   name, 0, &rdata, &newtuple));
2415 			CHECK(do_one_tuple(&newtuple, db, ver, diff));
2416 			INSIST(newtuple == NULL);
2417 		}
2418 	}
2419 
2420  failure:
2421 	dns_diff_clear(&temp_diff);
2422 	return (result);
2423 }
2424 
2425 static isc_boolean_t
2426 isdnssec(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype) {
2427 	isc_result_t result;
2428 	isc_boolean_t build_nsec, build_nsec3;
2429 
2430 	if (dns_db_issecure(db))
2431 		return (ISC_TRUE);
2432 
2433 	result = dns_private_chains(db, ver, privatetype,
2434 				    &build_nsec, &build_nsec3);
2435 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2436 	return (build_nsec || build_nsec3);
2437 }
2438 
2439 static void
2440 update_action(isc_task_t *task, isc_event_t *event) {
2441 	update_event_t *uev = (update_event_t *) event;
2442 	dns_zone_t *zone = uev->zone;
2443 	ns_client_t *client = (ns_client_t *)event->ev_arg;
2444 	isc_result_t result;
2445 	dns_db_t *db = NULL;
2446 	dns_dbversion_t *oldver = NULL;
2447 	dns_dbversion_t *ver = NULL;
2448 	dns_diff_t diff;	/* Pending updates. */
2449 	dns_diff_t temp;	/* Pending RR existence assertions. */
2450 	isc_boolean_t soa_serial_changed = ISC_FALSE;
2451 	isc_mem_t *mctx = client->mctx;
2452 	dns_rdatatype_t covers;
2453 	dns_message_t *request = client->message;
2454 	dns_rdataclass_t zoneclass;
2455 	dns_name_t *zonename;
2456 	dns_ssutable_t *ssutable = NULL;
2457 	dns_fixedname_t tmpnamefixed;
2458 	dns_name_t *tmpname = NULL;
2459 	unsigned int options, options2;
2460 	dns_difftuple_t *tuple;
2461 	dns_rdata_dnskey_t dnskey;
2462 	isc_boolean_t had_dnskey;
2463 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
2464 	dns_ttl_t maxttl = 0;
2465 
2466 	INSIST(event->ev_type == DNS_EVENT_UPDATE);
2467 
2468 	dns_diff_init(mctx, &diff);
2469 	dns_diff_init(mctx, &temp);
2470 
2471 	CHECK(dns_zone_getdb(zone, &db));
2472 	zonename = dns_db_origin(db);
2473 	zoneclass = dns_db_class(db);
2474 	dns_zone_getssutable(zone, &ssutable);
2475 
2476 	/*
2477 	 * Update message processing can leak record existance information
2478 	 * so check that we are allowed to query this zone.  Additionally
2479 	 * if we would refuse all updates for this zone we bail out here.
2480 	 */
2481 	CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename,
2482 			    dns_zone_getupdateacl(zone), ssutable));
2483 
2484 	/*
2485 	 * Get old and new versions now that queryacl has been checked.
2486 	 */
2487 	dns_db_currentversion(db, &oldver);
2488 	CHECK(dns_db_newversion(db, &ver));
2489 
2490 	/*
2491 	 * Check prerequisites.
2492 	 */
2493 
2494 	for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE);
2495 	     result == ISC_R_SUCCESS;
2496 	     result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE))
2497 	{
2498 		dns_name_t *name = NULL;
2499 		dns_rdata_t rdata = DNS_RDATA_INIT;
2500 		dns_ttl_t ttl;
2501 		dns_rdataclass_t update_class;
2502 		isc_boolean_t flag;
2503 
2504 		get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
2505 			       &name, &rdata, &covers, &ttl, &update_class);
2506 
2507 		if (ttl != 0)
2508 			PREREQFAILC(DNS_R_FORMERR,
2509 				    "prerequisite TTL is not zero");
2510 
2511 		if (! dns_name_issubdomain(name, zonename))
2512 			PREREQFAILN(DNS_R_NOTZONE, name,
2513 				    "prerequisite name is out of zone");
2514 
2515 		if (update_class == dns_rdataclass_any) {
2516 			if (rdata.length != 0)
2517 				PREREQFAILC(DNS_R_FORMERR,
2518 				      "class ANY prerequisite "
2519 				      "RDATA is not empty");
2520 			if (rdata.type == dns_rdatatype_any) {
2521 				CHECK(name_exists(db, ver, name, &flag));
2522 				if (! flag) {
2523 					PREREQFAILN(DNS_R_NXDOMAIN, name,
2524 						    "'name in use' "
2525 						    "prerequisite not "
2526 						    "satisfied");
2527 				}
2528 			} else {
2529 				CHECK(rrset_exists(db, ver, name,
2530 						   rdata.type, covers, &flag));
2531 				if (! flag) {
2532 					/* RRset does not exist. */
2533 					PREREQFAILNT(DNS_R_NXRRSET, name, rdata.type,
2534 					"'rrset exists (value independent)' "
2535 					"prerequisite not satisfied");
2536 				}
2537 			}
2538 		} else if (update_class == dns_rdataclass_none) {
2539 			if (rdata.length != 0)
2540 				PREREQFAILC(DNS_R_FORMERR,
2541 					    "class NONE prerequisite "
2542 					    "RDATA is not empty");
2543 			if (rdata.type == dns_rdatatype_any) {
2544 				CHECK(name_exists(db, ver, name, &flag));
2545 				if (flag) {
2546 					PREREQFAILN(DNS_R_YXDOMAIN, name,
2547 						    "'name not in use' "
2548 						    "prerequisite not "
2549 						    "satisfied");
2550 				}
2551 			} else {
2552 				CHECK(rrset_exists(db, ver, name,
2553 						   rdata.type, covers, &flag));
2554 				if (flag) {
2555 					/* RRset exists. */
2556 					PREREQFAILNT(DNS_R_YXRRSET, name,
2557 						     rdata.type,
2558 						     "'rrset does not exist' "
2559 						     "prerequisite not "
2560 						     "satisfied");
2561 				}
2562 			}
2563 		} else if (update_class == zoneclass) {
2564 			/* "temp<rr.name, rr.type> += rr;" */
2565 			result = temp_append(&temp, name, &rdata);
2566 			if (result != ISC_R_SUCCESS) {
2567 				UNEXPECTED_ERROR(__FILE__, __LINE__,
2568 					 "temp entry creation failed: %s",
2569 						 dns_result_totext(result));
2570 				FAIL(ISC_R_UNEXPECTED);
2571 			}
2572 		} else {
2573 			PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite");
2574 		}
2575 	}
2576 	if (result != ISC_R_NOMORE)
2577 		FAIL(result);
2578 
2579 	/*
2580 	 * Perform the final check of the "rrset exists (value dependent)"
2581 	 * prerequisites.
2582 	 */
2583 	if (ISC_LIST_HEAD(temp.tuples) != NULL) {
2584 		dns_rdatatype_t type;
2585 
2586 		/*
2587 		 * Sort the prerequisite records by owner name,
2588 		 * type, and rdata.
2589 		 */
2590 		result = dns_diff_sort(&temp, temp_order);
2591 		if (result != ISC_R_SUCCESS)
2592 			FAILC(result, "'RRset exists (value dependent)' "
2593 			      "prerequisite not satisfied");
2594 
2595 		dns_fixedname_init(&tmpnamefixed);
2596 		tmpname = dns_fixedname_name(&tmpnamefixed);
2597 		result = temp_check(mctx, &temp, db, ver, tmpname, &type);
2598 		if (result != ISC_R_SUCCESS)
2599 			FAILNT(result, tmpname, type,
2600 			       "'RRset exists (value dependent)' "
2601 			       "prerequisite not satisfied");
2602 	}
2603 
2604 	update_log(client, zone, LOGLEVEL_DEBUG,
2605 		   "prerequisites are OK");
2606 
2607 	/*
2608 	 * Check Requestor's Permissions.  It seems a bit silly to do this
2609 	 * only after prerequisite testing, but that is what RFC2136 says.
2610 	 */
2611 	if (ssutable == NULL)
2612 		CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
2613 				     "update", zonename, ISC_FALSE, ISC_FALSE));
2614 	else if (client->signer == NULL && !TCPCLIENT(client))
2615 		CHECK(checkupdateacl(client, NULL, "update", zonename,
2616 				     ISC_FALSE, ISC_TRUE));
2617 
2618 	if (dns_zone_getupdatedisabled(zone))
2619 		FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled "
2620 				     "because the zone is frozen.  Use "
2621 				     "'rndc thaw' to re-enable updates.");
2622 
2623 	/*
2624 	 * Perform the Update Section Prescan.
2625 	 */
2626 
2627 	for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
2628 	     result == ISC_R_SUCCESS;
2629 	     result = dns_message_nextname(request, DNS_SECTION_UPDATE))
2630 	{
2631 		dns_name_t *name = NULL;
2632 		dns_rdata_t rdata = DNS_RDATA_INIT;
2633 		dns_ttl_t ttl;
2634 		dns_rdataclass_t update_class;
2635 		get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
2636 			       &name, &rdata, &covers, &ttl, &update_class);
2637 
2638 		if (! dns_name_issubdomain(name, zonename))
2639 			FAILC(DNS_R_NOTZONE,
2640 			      "update RR is outside zone");
2641 		if (update_class == zoneclass) {
2642 			/*
2643 			 * Check for meta-RRs.  The RFC2136 pseudocode says
2644 			 * check for ANY|AXFR|MAILA|MAILB, but the text adds
2645 			 * "or any other QUERY metatype"
2646 			 */
2647 			if (dns_rdatatype_ismeta(rdata.type)) {
2648 				FAILC(DNS_R_FORMERR,
2649 				      "meta-RR in update");
2650 			}
2651 			result = dns_zone_checknames(zone, name, &rdata);
2652 			if (result != ISC_R_SUCCESS)
2653 				FAIL(DNS_R_REFUSED);
2654 		} else if (update_class == dns_rdataclass_any) {
2655 			if (ttl != 0 || rdata.length != 0 ||
2656 			    (dns_rdatatype_ismeta(rdata.type) &&
2657 			     rdata.type != dns_rdatatype_any))
2658 				FAILC(DNS_R_FORMERR,
2659 				      "meta-RR in update");
2660 		} else if (update_class == dns_rdataclass_none) {
2661 			if (ttl != 0 ||
2662 			    dns_rdatatype_ismeta(rdata.type))
2663 				FAILC(DNS_R_FORMERR,
2664 				      "meta-RR in update");
2665 		} else {
2666 			update_log(client, zone, ISC_LOG_WARNING,
2667 				   "update RR has incorrect class %d",
2668 				   update_class);
2669 			FAIL(DNS_R_FORMERR);
2670 		}
2671 
2672 		/*
2673 		 * draft-ietf-dnsind-simple-secure-update-01 says
2674 		 * "Unlike traditional dynamic update, the client
2675 		 * is forbidden from updating NSEC records."
2676 		 */
2677 		if (rdata.type == dns_rdatatype_nsec3) {
2678 			FAILC(DNS_R_REFUSED,
2679 			      "explicit NSEC3 updates are not allowed "
2680 			      "in secure zones");
2681 		} else if (rdata.type == dns_rdatatype_nsec) {
2682 			FAILC(DNS_R_REFUSED,
2683 			      "explicit NSEC updates are not allowed "
2684 			      "in secure zones");
2685 		} else if (rdata.type == dns_rdatatype_rrsig &&
2686 			   !dns_name_equal(name, zonename)) {
2687 			FAILC(DNS_R_REFUSED,
2688 			      "explicit RRSIG updates are currently "
2689 			      "not supported in secure zones except "
2690 			      "at the apex");
2691 		}
2692 
2693 		if (ssutable != NULL) {
2694 			isc_netaddr_t *tcpaddr, netaddr;
2695 			dst_key_t *tsigkey = NULL;
2696 			/*
2697 			 * If this is a TCP connection then pass the
2698 			 * address of the client through for tcp-self
2699 			 * and 6to4-self otherwise pass NULL.  This
2700 			 * provides weak address based authentication.
2701 			 */
2702 			if (TCPCLIENT(client)) {
2703 				isc_netaddr_fromsockaddr(&netaddr,
2704 							 &client->peeraddr);
2705 				tcpaddr = &netaddr;
2706 			} else
2707 				tcpaddr = NULL;
2708 
2709 			if (client->message->tsigkey != NULL)
2710 				tsigkey = client->message->tsigkey->key;
2711 
2712 			if (rdata.type != dns_rdatatype_any) {
2713 				if (!dns_ssutable_checkrules(ssutable,
2714 							     client->signer,
2715 							     name, tcpaddr,
2716 							     rdata.type,
2717 							     tsigkey))
2718 					FAILC(DNS_R_REFUSED,
2719 					      "rejected by secure update");
2720 			} else {
2721 				if (!ssu_checkall(db, ver, name, ssutable,
2722 						  client->signer, tcpaddr,
2723 						  tsigkey))
2724 					FAILC(DNS_R_REFUSED,
2725 					      "rejected by secure update");
2726 			}
2727 		}
2728 	}
2729 	if (result != ISC_R_NOMORE)
2730 		FAIL(result);
2731 
2732 	update_log(client, zone, LOGLEVEL_DEBUG,
2733 		   "update section prescan OK");
2734 
2735 	/*
2736 	 * Process the Update Section.
2737 	 */
2738 
2739 	options = dns_zone_getoptions(zone);
2740 	options2 = dns_zone_getoptions2(zone);
2741 	for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
2742 	     result == ISC_R_SUCCESS;
2743 	     result = dns_message_nextname(request, DNS_SECTION_UPDATE))
2744 	{
2745 		dns_name_t *name = NULL;
2746 		dns_rdata_t rdata = DNS_RDATA_INIT;
2747 		dns_ttl_t ttl;
2748 		dns_rdataclass_t update_class;
2749 		isc_boolean_t flag;
2750 
2751 		get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
2752 			       &name, &rdata, &covers, &ttl, &update_class);
2753 
2754 		if (update_class == zoneclass) {
2755 
2756 			/*
2757 			 * RFC1123 doesn't allow MF and MD in master zones.				 */
2758 			if (rdata.type == dns_rdatatype_md ||
2759 			    rdata.type == dns_rdatatype_mf) {
2760 				char typebuf[DNS_RDATATYPE_FORMATSIZE];
2761 
2762 				dns_rdatatype_format(rdata.type, typebuf,
2763 						     sizeof(typebuf));
2764 				update_log(client, zone, LOGLEVEL_PROTOCOL,
2765 					   "attempt to add %s ignored",
2766 					   typebuf);
2767 				continue;
2768 			}
2769 			if ((rdata.type == dns_rdatatype_ns ||
2770 			     rdata.type == dns_rdatatype_dname) &&
2771 			    dns_name_iswildcard(name)) {
2772 				char typebuf[DNS_RDATATYPE_FORMATSIZE];
2773 
2774 				dns_rdatatype_format(rdata.type, typebuf,
2775 						     sizeof(typebuf));
2776 				update_log(client, zone,
2777 					   LOGLEVEL_PROTOCOL,
2778 					   "attempt to add wildcard %s record "
2779 					   "ignored", typebuf);
2780 				continue;
2781 			}
2782 			if (rdata.type == dns_rdatatype_cname) {
2783 				CHECK(cname_incompatible_rrset_exists(db, ver,
2784 								      name,
2785 								      &flag));
2786 				if (flag) {
2787 					update_log(client, zone,
2788 						   LOGLEVEL_PROTOCOL,
2789 						   "attempt to add CNAME "
2790 						   "alongside non-CNAME "
2791 						   "ignored");
2792 					continue;
2793 				}
2794 			} else {
2795 				CHECK(rrset_exists(db, ver, name,
2796 						   dns_rdatatype_cname, 0,
2797 						   &flag));
2798 				if (flag &&
2799 				    ! dns_rdatatype_isdnssec(rdata.type))
2800 				{
2801 					update_log(client, zone,
2802 						   LOGLEVEL_PROTOCOL,
2803 						   "attempt to add non-CNAME "
2804 						   "alongside CNAME ignored");
2805 					continue;
2806 				}
2807 			}
2808 			if (rdata.type == dns_rdatatype_soa) {
2809 				isc_boolean_t ok;
2810 				CHECK(rrset_exists(db, ver, name,
2811 						   dns_rdatatype_soa, 0,
2812 						   &flag));
2813 				if (! flag) {
2814 					update_log(client, zone,
2815 						   LOGLEVEL_PROTOCOL,
2816 						   "attempt to create 2nd "
2817 						   "SOA ignored");
2818 					continue;
2819 				}
2820 				CHECK(check_soa_increment(db, ver, &rdata,
2821 							  &ok));
2822 				if (! ok) {
2823 					update_log(client, zone,
2824 						   LOGLEVEL_PROTOCOL,
2825 						   "SOA update failed to "
2826 						   "increment serial, "
2827 						   "ignoring it");
2828 					continue;
2829 				}
2830 				soa_serial_changed = ISC_TRUE;
2831 			}
2832 
2833 			if (rdata.type == privatetype) {
2834 				update_log(client, zone, LOGLEVEL_PROTOCOL,
2835 					   "attempt to add a private type "
2836 					   "(%u) record rejected internal "
2837 					   "use only", privatetype);
2838 				continue;
2839 			}
2840 
2841 			if (rdata.type == dns_rdatatype_nsec3param) {
2842 				/*
2843 				 * Ignore attempts to add NSEC3PARAM records
2844 				 * with any flags other than OPTOUT.
2845 				 */
2846 				if ((rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
2847 					update_log(client, zone,
2848 						   LOGLEVEL_PROTOCOL,
2849 						   "attempt to add NSEC3PARAM "
2850 						   "record with non OPTOUT "
2851 						   "flag");
2852 					continue;
2853 				}
2854 			}
2855 
2856 			if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
2857 			    dns_name_internalwildcard(name)) {
2858 				char namestr[DNS_NAME_FORMATSIZE];
2859 				dns_name_format(name, namestr,
2860 						sizeof(namestr));
2861 				update_log(client, zone, LOGLEVEL_PROTOCOL,
2862 					   "warning: ownername '%s' contains "
2863 					   "a non-terminal wildcard", namestr);
2864 			}
2865 
2866 			if ((options2 & DNS_ZONEOPT2_CHECKTTL) != 0) {
2867 				maxttl = dns_zone_getmaxttl(zone);
2868 				if (ttl > maxttl) {
2869 					ttl = maxttl;
2870 					update_log(client, zone,
2871 						   LOGLEVEL_PROTOCOL,
2872 						   "reducing TTL to the "
2873 						   "configured max-zone-ttl %d",
2874 						   maxttl);
2875 				}
2876 			}
2877 
2878 			if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {
2879 				char namestr[DNS_NAME_FORMATSIZE];
2880 				char typestr[DNS_RDATATYPE_FORMATSIZE];
2881 				char rdstr[2048];
2882 				isc_buffer_t buf;
2883 				int len = 0;
2884 				const char *truncated = "";
2885 
2886 				dns_name_format(name, namestr, sizeof(namestr));
2887 				dns_rdatatype_format(rdata.type, typestr,
2888 						     sizeof(typestr));
2889 				isc_buffer_init(&buf, rdstr, sizeof(rdstr));
2890 				result = dns_rdata_totext(&rdata, NULL, &buf);
2891 				if (result == ISC_R_NOSPACE) {
2892 					len = (int)isc_buffer_usedlength(&buf);
2893 					truncated = " [TRUNCATED]";
2894 				} else if (result != ISC_R_SUCCESS) {
2895 					snprintf(rdstr, sizeof(rdstr), "[dns_"
2896 						 "rdata_totext failed: %s]",
2897 						 dns_result_totext(result));
2898 					len = strlen(rdstr);
2899 				} else
2900 					len = (int)isc_buffer_usedlength(&buf);
2901 				update_log(client, zone, LOGLEVEL_PROTOCOL,
2902 					   "adding an RR at '%s' %s %.*s%s",
2903 					   namestr, typestr, len, rdstr,
2904 					   truncated);
2905 			}
2906 
2907 			/* Prepare the affected RRset for the addition. */
2908 			{
2909 				add_rr_prepare_ctx_t ctx;
2910 				ctx.db = db;
2911 				ctx.ver = ver;
2912 				ctx.diff = &diff;
2913 				ctx.name = name;
2914 				ctx.update_rr = &rdata;
2915 				ctx.update_rr_ttl = ttl;
2916 				ctx.ignore_add = ISC_FALSE;
2917 				dns_diff_init(mctx, &ctx.del_diff);
2918 				dns_diff_init(mctx, &ctx.add_diff);
2919 				CHECK(foreach_rr(db, ver, name, rdata.type,
2920 						 covers, add_rr_prepare_action,
2921 						 &ctx));
2922 
2923 				if (ctx.ignore_add) {
2924 					dns_diff_clear(&ctx.del_diff);
2925 					dns_diff_clear(&ctx.add_diff);
2926 				} else {
2927 					result = do_diff(&ctx.del_diff, db, ver,
2928 							 &diff);
2929 					if (result == ISC_R_SUCCESS) {
2930 						result = do_diff(&ctx.add_diff,
2931 								 db, ver,
2932 								 &diff);
2933 					}
2934 					if (result != ISC_R_SUCCESS) {
2935 						dns_diff_clear(&ctx.del_diff);
2936 						dns_diff_clear(&ctx.add_diff);
2937 						goto failure;
2938 					}
2939 					CHECK(update_one_rr(db, ver, &diff,
2940 							    DNS_DIFFOP_ADD,
2941 							    name, ttl, &rdata));
2942 				}
2943 			}
2944 		} else if (update_class == dns_rdataclass_any) {
2945 			if (rdata.type == dns_rdatatype_any) {
2946 				if (isc_log_wouldlog(ns_g_lctx,
2947 						     LOGLEVEL_PROTOCOL))
2948 				{
2949 					char namestr[DNS_NAME_FORMATSIZE];
2950 					dns_name_format(name, namestr,
2951 							sizeof(namestr));
2952 					update_log(client, zone,
2953 						   LOGLEVEL_PROTOCOL,
2954 						   "delete all rrsets from "
2955 						   "name '%s'", namestr);
2956 				}
2957 				if (dns_name_equal(name, zonename)) {
2958 					CHECK(delete_if(type_not_soa_nor_ns_p,
2959 							db, ver, name,
2960 							dns_rdatatype_any, 0,
2961 							&rdata, &diff));
2962 				} else {
2963 					CHECK(delete_if(type_not_dnssec,
2964 							db, ver, name,
2965 							dns_rdatatype_any, 0,
2966 							&rdata, &diff));
2967 				}
2968 			} else if (dns_name_equal(name, zonename) &&
2969 				   (rdata.type == dns_rdatatype_soa ||
2970 				    rdata.type == dns_rdatatype_ns)) {
2971 				update_log(client, zone, LOGLEVEL_PROTOCOL,
2972 					   "attempt to delete all SOA "
2973 					   "or NS records ignored");
2974 				continue;
2975 			} else {
2976 				if (isc_log_wouldlog(ns_g_lctx,
2977 						     LOGLEVEL_PROTOCOL))
2978 				{
2979 					char namestr[DNS_NAME_FORMATSIZE];
2980 					char typestr[DNS_RDATATYPE_FORMATSIZE];
2981 					dns_name_format(name, namestr,
2982 							sizeof(namestr));
2983 					dns_rdatatype_format(rdata.type,
2984 							     typestr,
2985 							     sizeof(typestr));
2986 					update_log(client, zone,
2987 						   LOGLEVEL_PROTOCOL,
2988 						   "deleting rrset at '%s' %s",
2989 						   namestr, typestr);
2990 				}
2991 				CHECK(delete_if(true_p, db, ver, name,
2992 						rdata.type, covers, &rdata,
2993 						&diff));
2994 			}
2995 		} else if (update_class == dns_rdataclass_none) {
2996 			char namestr[DNS_NAME_FORMATSIZE];
2997 			char typestr[DNS_RDATATYPE_FORMATSIZE];
2998 
2999 			/*
3000 			 * The (name == zonename) condition appears in
3001 			 * RFC2136 3.4.2.4 but is missing from the pseudocode.
3002 			 */
3003 			if (dns_name_equal(name, zonename)) {
3004 				if (rdata.type == dns_rdatatype_soa) {
3005 					update_log(client, zone,
3006 						   LOGLEVEL_PROTOCOL,
3007 						   "attempt to delete SOA "
3008 						   "ignored");
3009 					continue;
3010 				}
3011 				if (rdata.type == dns_rdatatype_ns) {
3012 					int count;
3013 					CHECK(rr_count(db, ver, name,
3014 						       dns_rdatatype_ns,
3015 						       0, &count));
3016 					if (count == 1) {
3017 						update_log(client, zone,
3018 							   LOGLEVEL_PROTOCOL,
3019 							   "attempt to "
3020 							   "delete last "
3021 							   "NS ignored");
3022 						continue;
3023 					}
3024 				}
3025 			}
3026 			dns_name_format(name, namestr, sizeof(namestr));
3027 			dns_rdatatype_format(rdata.type, typestr,
3028 					     sizeof(typestr));
3029 			update_log(client, zone, LOGLEVEL_PROTOCOL,
3030 				   "deleting an RR at %s %s", namestr, typestr);
3031 			CHECK(delete_if(rr_equal_p, db, ver, name, rdata.type,
3032 					covers, &rdata, &diff));
3033 		}
3034 	}
3035 	if (result != ISC_R_NOMORE)
3036 		FAIL(result);
3037 
3038 	/*
3039 	 * Check that any changes to DNSKEY/NSEC3PARAM records make sense.
3040 	 * If they don't then back out all changes to DNSKEY/NSEC3PARAM
3041 	 * records.
3042 	 */
3043 	if (! ISC_LIST_EMPTY(diff.tuples))
3044 		CHECK(check_dnssec(client, zone, db, ver, &diff));
3045 
3046 	if (! ISC_LIST_EMPTY(diff.tuples)) {
3047 		unsigned int errors = 0;
3048 		CHECK(dns_zone_nscheck(zone, db, ver, &errors));
3049 		if (errors != 0) {
3050 			update_log(client, zone, LOGLEVEL_PROTOCOL,
3051 				   "update rejected: post update name server "
3052 				   "sanity check failed");
3053 			result = DNS_R_REFUSED;
3054 			goto failure;
3055 		}
3056 	}
3057 
3058 	/*
3059 	 * If any changes were made, increment the SOA serial number,
3060 	 * update RRSIGs and NSECs (if zone is secure), and write the update
3061 	 * to the journal.
3062 	 */
3063 	if (! ISC_LIST_EMPTY(diff.tuples)) {
3064 		char *journalfile;
3065 		dns_journal_t *journal;
3066 		isc_boolean_t has_dnskey;
3067 
3068 		/*
3069 		 * Increment the SOA serial, but only if it was not
3070 		 * changed as a result of an update operation.
3071 		 */
3072 		if (! soa_serial_changed) {
3073 			CHECK(update_soa_serial(db, ver, &diff, mctx,
3074 				       dns_zone_getserialupdatemethod(zone)));
3075 		}
3076 
3077 		CHECK(check_mx(client, zone, db, ver, &diff));
3078 
3079 		CHECK(remove_orphaned_ds(db, ver, &diff));
3080 
3081 		CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
3082 				   0, &has_dnskey));
3083 
3084 #define ALLOW_SECURE_TO_INSECURE(zone) \
3085 	((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0)
3086 
3087 		CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey,
3088 				   0, &had_dnskey));
3089 		if (!ALLOW_SECURE_TO_INSECURE(zone)) {
3090 			if (had_dnskey && !has_dnskey) {
3091 				update_log(client, zone, LOGLEVEL_PROTOCOL,
3092 					   "update rejected: all DNSKEY "
3093 					   "records removed and "
3094 					   "'dnssec-secure-to-insecure' "
3095 					   "not set");
3096 				result = DNS_R_REFUSED;
3097 				goto failure;
3098 			}
3099 		}
3100 
3101 		CHECK(rollback_private(db, privatetype, ver, &diff));
3102 
3103 		CHECK(add_signing_records(db, privatetype, ver, &diff));
3104 
3105 		CHECK(add_nsec3param_records(client, zone, db, ver, &diff));
3106 
3107 		if (had_dnskey && !has_dnskey) {
3108 			/*
3109 			 * We are transitioning from secure to insecure.
3110 			 * Cause all NSEC3 chains to be deleted.  When the
3111 			 * the last signature for the DNSKEY records are
3112 			 * remove any NSEC chain present will also be removed.
3113 			 */
3114 			 CHECK(dns_nsec3param_deletechains(db, ver, zone,
3115 							   ISC_TRUE, &diff));
3116 		} else if (has_dnskey && isdnssec(db, ver, privatetype)) {
3117 			isc_uint32_t interval;
3118 			dns_update_log_t log;
3119 
3120 			interval = dns_zone_getsigvalidityinterval(zone);
3121 			log.func = update_log_cb;
3122 			log.arg = client;
3123 			result = dns_update_signatures(&log, zone, db, oldver,
3124 						       ver, &diff, interval);
3125 
3126 			if (result != ISC_R_SUCCESS) {
3127 				update_log(client, zone,
3128 					   ISC_LOG_ERROR,
3129 					   "RRSIG/NSEC/NSEC3 update failed: %s",
3130 					   isc_result_totext(result));
3131 				goto failure;
3132 			}
3133 		}
3134 
3135 		journalfile = dns_zone_getjournal(zone);
3136 		if (journalfile != NULL) {
3137 			update_log(client, zone, LOGLEVEL_DEBUG,
3138 				   "writing journal %s", journalfile);
3139 
3140 			journal = NULL;
3141 			result = dns_journal_open(mctx, journalfile,
3142 						  DNS_JOURNAL_CREATE, &journal);
3143 			if (result != ISC_R_SUCCESS)
3144 				FAILS(result, "journal open failed");
3145 
3146 			result = dns_journal_write_transaction(journal, &diff);
3147 			if (result != ISC_R_SUCCESS) {
3148 				dns_journal_destroy(&journal);
3149 				FAILS(result, "journal write failed");
3150 			}
3151 
3152 			dns_journal_destroy(&journal);
3153 		}
3154 
3155 		/*
3156 		 * XXXRTH  Just a note that this committing code will have
3157 		 *	   to change to handle databases that need two-phase
3158 		 *	   commit, but this isn't a priority.
3159 		 */
3160 		update_log(client, zone, LOGLEVEL_DEBUG,
3161 			   "committing update transaction");
3162 
3163 		dns_db_closeversion(db, &ver, ISC_TRUE);
3164 
3165 		/*
3166 		 * Mark the zone as dirty so that it will be written to disk.
3167 		 */
3168 		dns_zone_markdirty(zone);
3169 
3170 		/*
3171 		 * Notify slaves of the change we just made.
3172 		 */
3173 		dns_zone_notify(zone);
3174 
3175 		/*
3176 		 * Cause the zone to be signed with the key that we
3177 		 * have just added or have the corresponding signatures
3178 		 * deleted.
3179 		 *
3180 		 * Note: we are already committed to this course of action.
3181 		 */
3182 		for (tuple = ISC_LIST_HEAD(diff.tuples);
3183 		     tuple != NULL;
3184 		     tuple = ISC_LIST_NEXT(tuple, link)) {
3185 			isc_region_t r;
3186 			dns_secalg_t algorithm;
3187 			isc_uint16_t keyid;
3188 
3189 			if (tuple->rdata.type != dns_rdatatype_dnskey)
3190 				continue;
3191 
3192 			dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
3193 			if ((dnskey.flags &
3194 			     (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
3195 				 != DNS_KEYOWNER_ZONE)
3196 				continue;
3197 
3198 			dns_rdata_toregion(&tuple->rdata, &r);
3199 			algorithm = dnskey.algorithm;
3200 			keyid = dst_region_computeid(&r, algorithm);
3201 
3202 			result = dns_zone_signwithkey(zone, algorithm, keyid,
3203 					ISC_TF(tuple->op == DNS_DIFFOP_DEL));
3204 			if (result != ISC_R_SUCCESS) {
3205 				update_log(client, zone, ISC_LOG_ERROR,
3206 					   "dns_zone_signwithkey failed: %s",
3207 					   dns_result_totext(result));
3208 			}
3209 		}
3210 
3211 		/*
3212 		 * Cause the zone to add/delete NSEC3 chains for the
3213 		 * deferred NSEC3PARAM changes.
3214 		 *
3215 		 * Note: we are already committed to this course of action.
3216 		 */
3217 		for (tuple = ISC_LIST_HEAD(diff.tuples);
3218 		     tuple != NULL;
3219 		     tuple = ISC_LIST_NEXT(tuple, link)) {
3220 			unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
3221 			dns_rdata_t rdata = DNS_RDATA_INIT;
3222 			dns_rdata_nsec3param_t nsec3param;
3223 
3224 			if (tuple->rdata.type != privatetype ||
3225 			    tuple->op != DNS_DIFFOP_ADD)
3226 				continue;
3227 
3228 			if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata,
3229 						   buf, sizeof(buf)))
3230 				continue;
3231 			dns_rdata_tostruct(&rdata, &nsec3param, NULL);
3232 			if (nsec3param.flags == 0)
3233 				continue;
3234 
3235 			result = dns_zone_addnsec3chain(zone, &nsec3param);
3236 			if (result != ISC_R_SUCCESS) {
3237 				update_log(client, zone, ISC_LOG_ERROR,
3238 					   "dns_zone_addnsec3chain failed: %s",
3239 					   dns_result_totext(result));
3240 			}
3241 		}
3242 	} else {
3243 		update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
3244 		dns_db_closeversion(db, &ver, ISC_TRUE);
3245 	}
3246 	result = ISC_R_SUCCESS;
3247 	goto common;
3248 
3249  failure:
3250 	/*
3251 	 * The reason for failure should have been logged at this point.
3252 	 */
3253 	if (ver != NULL) {
3254 		update_log(client, zone, LOGLEVEL_DEBUG,
3255 			   "rolling back");
3256 		dns_db_closeversion(db, &ver, ISC_FALSE);
3257 	}
3258 
3259  common:
3260 	dns_diff_clear(&temp);
3261 	dns_diff_clear(&diff);
3262 
3263 	if (oldver != NULL)
3264 		dns_db_closeversion(db, &oldver, ISC_FALSE);
3265 
3266 	if (db != NULL)
3267 		dns_db_detach(&db);
3268 
3269 	if (ssutable != NULL)
3270 		dns_ssutable_detach(&ssutable);
3271 
3272 	isc_task_detach(&task);
3273 	uev->result = result;
3274 	if (zone != NULL)
3275 		INSIST(uev->zone == zone); /* we use this later */
3276 	uev->ev_type = DNS_EVENT_UPDATEDONE;
3277 	uev->ev_action = updatedone_action;
3278 	isc_task_send(client->task, &event);
3279 
3280 	INSIST(ver == NULL);
3281 	INSIST(event == NULL);
3282 }
3283 
3284 static void
3285 updatedone_action(isc_task_t *task, isc_event_t *event) {
3286 	update_event_t *uev = (update_event_t *) event;
3287 	ns_client_t *client = (ns_client_t *) event->ev_arg;
3288 
3289 	UNUSED(task);
3290 
3291 	INSIST(event->ev_type == DNS_EVENT_UPDATEDONE);
3292 	INSIST(task == client->task);
3293 
3294 	INSIST(client->nupdates > 0);
3295 	switch (uev->result) {
3296 	case ISC_R_SUCCESS:
3297 		inc_stats(uev->zone, dns_nsstatscounter_updatedone);
3298 		break;
3299 	case DNS_R_REFUSED:
3300 		inc_stats(uev->zone, dns_nsstatscounter_updaterej);
3301 		break;
3302 	default:
3303 		inc_stats(uev->zone, dns_nsstatscounter_updatefail);
3304 		break;
3305 	}
3306 	if (uev->zone != NULL)
3307 		dns_zone_detach(&uev->zone);
3308 	client->nupdates--;
3309 	respond(client, uev->result);
3310 	isc_event_free(&event);
3311 	ns_client_detach(&client);
3312 }
3313 
3314 /*%
3315  * Update forwarding support.
3316  */
3317 
3318 static void
3319 forward_fail(isc_task_t *task, isc_event_t *event) {
3320 	ns_client_t *client = (ns_client_t *)event->ev_arg;
3321 
3322 	UNUSED(task);
3323 
3324 	INSIST(client->nupdates > 0);
3325 	client->nupdates--;
3326 	respond(client, DNS_R_SERVFAIL);
3327 	isc_event_free(&event);
3328 	ns_client_detach(&client);
3329 }
3330 
3331 
3332 static void
3333 forward_callback(void *arg, isc_result_t result, dns_message_t *answer) {
3334 	update_event_t *uev = arg;
3335 	ns_client_t *client = uev->ev_arg;
3336 	dns_zone_t *zone = uev->zone;
3337 
3338 	if (result != ISC_R_SUCCESS) {
3339 		INSIST(answer == NULL);
3340 		uev->ev_type = DNS_EVENT_UPDATEDONE;
3341 		uev->ev_action = forward_fail;
3342 		inc_stats(zone, dns_nsstatscounter_updatefwdfail);
3343 	} else {
3344 		uev->ev_type = DNS_EVENT_UPDATEDONE;
3345 		uev->ev_action = forward_done;
3346 		uev->answer = answer;
3347 		inc_stats(zone, dns_nsstatscounter_updaterespfwd);
3348 	}
3349 	isc_task_send(client->task, ISC_EVENT_PTR(&uev));
3350 	dns_zone_detach(&zone);
3351 }
3352 
3353 static void
3354 forward_done(isc_task_t *task, isc_event_t *event) {
3355 	update_event_t *uev = (update_event_t *) event;
3356 	ns_client_t *client = (ns_client_t *)event->ev_arg;
3357 
3358 	UNUSED(task);
3359 
3360 	INSIST(client->nupdates > 0);
3361 	client->nupdates--;
3362 	ns_client_sendraw(client, uev->answer);
3363 	dns_message_destroy(&uev->answer);
3364 	isc_event_free(&event);
3365 	ns_client_detach(&client);
3366 }
3367 
3368 static void
3369 forward_action(isc_task_t *task, isc_event_t *event) {
3370 	update_event_t *uev = (update_event_t *) event;
3371 	dns_zone_t *zone = uev->zone;
3372 	ns_client_t *client = (ns_client_t *)event->ev_arg;
3373 	isc_result_t result;
3374 
3375 	result = dns_zone_forwardupdate(zone, client->message,
3376 					forward_callback, event);
3377 	if (result != ISC_R_SUCCESS) {
3378 		uev->ev_type = DNS_EVENT_UPDATEDONE;
3379 		uev->ev_action = forward_fail;
3380 		isc_task_send(client->task, &event);
3381 		inc_stats(zone, dns_nsstatscounter_updatefwdfail);
3382 		dns_zone_detach(&zone);
3383 	} else
3384 		inc_stats(zone, dns_nsstatscounter_updatereqfwd);
3385 	isc_task_detach(&task);
3386 }
3387 
3388 static isc_result_t
3389 send_forward_event(ns_client_t *client, dns_zone_t *zone) {
3390 	char namebuf[DNS_NAME_FORMATSIZE];
3391 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
3392 	isc_result_t result = ISC_R_SUCCESS;
3393 	update_event_t *event = NULL;
3394 	isc_task_t *zonetask = NULL;
3395 	ns_client_t *evclient;
3396 
3397 	/*
3398 	 * This may take some time so replace this client.
3399 	 */
3400 	if (!client->mortal && (client->attributes & NS_CLIENTATTR_TCP) == 0)
3401 		CHECK(ns_client_replace(client));
3402 
3403 	event = (update_event_t *)
3404 		isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
3405 				   forward_action, NULL, sizeof(*event));
3406 	if (event == NULL)
3407 		FAIL(ISC_R_NOMEMORY);
3408 	event->zone = zone;
3409 	event->result = ISC_R_SUCCESS;
3410 
3411 	evclient = NULL;
3412 	ns_client_attach(client, &evclient);
3413 	INSIST(client->nupdates == 0);
3414 	client->nupdates++;
3415 	event->ev_arg = evclient;
3416 
3417 	dns_name_format(dns_zone_getorigin(zone), namebuf,
3418 			sizeof(namebuf));
3419 	dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
3420 			      sizeof(classbuf));
3421 
3422 	ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
3423 		      LOGLEVEL_PROTOCOL, "forwarding update for zone '%s/%s'",
3424 		      namebuf, classbuf);
3425 
3426 	dns_zone_gettask(zone, &zonetask);
3427 	isc_task_send(zonetask, ISC_EVENT_PTR(&event));
3428 
3429  failure:
3430 	if (event != NULL)
3431 		isc_event_free(ISC_EVENT_PTR(&event));
3432 	return (result);
3433 }
3434