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