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