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