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