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