]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/bin/named/update.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bind9 / bin / named / update.c
1 /*
2  * Copyright (C) 2004-2009  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.9 2009/12/30 04:02:56 marka 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                 added_sig = ISC_TRUE;
1949         }
1950         if (!added_sig) {
1951                 update_log(client, zone, ISC_LOG_ERROR,
1952                            "found no private keys, "
1953                            "unable to generate any signatures");
1954                 result = ISC_R_NOTFOUND;
1955         }
1956
1957  failure:
1958         if (dns_rdataset_isassociated(&rdataset))
1959                 dns_rdataset_disassociate(&rdataset);
1960         if (node != NULL)
1961                 dns_db_detachnode(db, &node);
1962         return (result);
1963 }
1964
1965 /*
1966  * Delete expired RRsigs and any RRsigs we are about to re-sign.
1967  * See also zone.c:del_sigs().
1968  */
1969 static isc_result_t
1970 del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1971             dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys)
1972 {
1973         isc_result_t result;
1974         dns_dbnode_t *node = NULL;
1975         dns_rdataset_t rdataset;
1976         dns_rdata_t rdata = DNS_RDATA_INIT;
1977         unsigned int i;
1978         dns_rdata_rrsig_t rrsig;
1979         isc_boolean_t found;
1980
1981         dns_rdataset_init(&rdataset);
1982
1983         result = dns_db_findnode(db, name, ISC_FALSE, &node);
1984         if (result == ISC_R_NOTFOUND)
1985                 return (ISC_R_SUCCESS);
1986         if (result != ISC_R_SUCCESS)
1987                 goto failure;
1988         result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig,
1989                                      dns_rdatatype_dnskey, (isc_stdtime_t) 0,
1990                                      &rdataset, NULL);
1991         dns_db_detachnode(db, &node);
1992
1993         if (result == ISC_R_NOTFOUND)
1994                 return (ISC_R_SUCCESS);
1995         if (result != ISC_R_SUCCESS)
1996                 goto failure;
1997
1998         for (result = dns_rdataset_first(&rdataset);
1999              result == ISC_R_SUCCESS;
2000              result = dns_rdataset_next(&rdataset)) {
2001                 dns_rdataset_current(&rdataset, &rdata);
2002                 result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
2003                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2004                 found = ISC_FALSE;
2005                 for (i = 0; i < nkeys; i++) {
2006                         if (rrsig.keyid == dst_key_id(keys[i])) {
2007                                 found = ISC_TRUE;
2008                                 if (!dst_key_isprivate(keys[i])) {
2009                                         /*
2010                                          * The re-signing code in zone.c
2011                                          * will mark this as offline.
2012                                          * Just skip the record for now.
2013                                          */
2014                                         break;
2015                                 }
2016                                 result = update_one_rr(db, ver, diff,
2017                                                        DNS_DIFFOP_DEL, name,
2018                                                        rdataset.ttl, &rdata);
2019                                 break;
2020                         }
2021                 }
2022                 /*
2023                  * If there is not a matching DNSKEY then delete the RRSIG.
2024                  */
2025                 if (!found)
2026                         result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
2027                                                name, rdataset.ttl, &rdata);
2028                 dns_rdata_reset(&rdata);
2029                 if (result != ISC_R_SUCCESS)
2030                         break;
2031         }
2032         dns_rdataset_disassociate(&rdataset);
2033         if (result == ISC_R_NOMORE)
2034                 result = ISC_R_SUCCESS;
2035 failure:
2036         if (node != NULL)
2037                 dns_db_detachnode(db, &node);
2038         return (result);
2039 }
2040
2041 static isc_result_t
2042 add_exposed_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
2043                  dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut,
2044                  dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
2045                  isc_stdtime_t inception, isc_stdtime_t expire,
2046                  isc_boolean_t check_ksk)
2047 {
2048         isc_result_t result;
2049         dns_dbnode_t *node;
2050         dns_rdatasetiter_t *iter;
2051
2052         node = NULL;
2053         result = dns_db_findnode(db, name, ISC_FALSE, &node);
2054         if (result == ISC_R_NOTFOUND)
2055                 return (ISC_R_SUCCESS);
2056         if (result != ISC_R_SUCCESS)
2057                 return (result);
2058
2059         iter = NULL;
2060         result = dns_db_allrdatasets(db, node, ver,
2061                                      (isc_stdtime_t) 0, &iter);
2062         if (result != ISC_R_SUCCESS)
2063                 goto cleanup_node;
2064
2065         for (result = dns_rdatasetiter_first(iter);
2066              result == ISC_R_SUCCESS;
2067              result = dns_rdatasetiter_next(iter))
2068         {
2069                 dns_rdataset_t rdataset;
2070                 dns_rdatatype_t type;
2071                 isc_boolean_t flag;
2072
2073                 dns_rdataset_init(&rdataset);
2074                 dns_rdatasetiter_current(iter, &rdataset);
2075                 type = rdataset.type;
2076                 dns_rdataset_disassociate(&rdataset);
2077
2078                 /*
2079                  * We don't need to sign unsigned NSEC records at the cut
2080                  * as they are handled elsewhere.
2081                  */
2082                 if ((type == dns_rdatatype_rrsig) ||
2083                     (cut && type != dns_rdatatype_ds))
2084                         continue;
2085                 result = rrset_exists(db, ver, name, dns_rdatatype_rrsig,
2086                                       type, &flag);
2087                 if (result != ISC_R_SUCCESS)
2088                         goto cleanup_iterator;
2089                 if (flag)
2090                         continue;;
2091                 result = add_sigs(client, zone, db, ver, name, type, diff,
2092                                   keys, nkeys, inception, expire, check_ksk);
2093                 if (result != ISC_R_SUCCESS)
2094                         goto cleanup_iterator;
2095         }
2096         if (result == ISC_R_NOMORE)
2097                 result = ISC_R_SUCCESS;
2098
2099  cleanup_iterator:
2100         dns_rdatasetiter_destroy(&iter);
2101
2102  cleanup_node:
2103         dns_db_detachnode(db, &node);
2104
2105         return (result);
2106 }
2107
2108 /*%
2109  * Update RRSIG, NSEC and NSEC3 records affected by an update.  The original
2110  * update, including the SOA serial update but excluding the RRSIG & NSEC
2111  * changes, is in "diff" and has already been applied to "newver" of "db".
2112  * The database version prior to the update is "oldver".
2113  *
2114  * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
2115  * and added (as a minimal diff) to "diff".
2116  *
2117  * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
2118  */
2119 static isc_result_t
2120 update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
2121                   dns_dbversion_t *oldver, dns_dbversion_t *newver,
2122                   dns_diff_t *diff, isc_uint32_t sigvalidityinterval,
2123                   isc_boolean_t *deleted_zsk)
2124 {
2125         isc_result_t result;
2126         dns_difftuple_t *t;
2127         dns_diff_t diffnames;
2128         dns_diff_t affected;
2129         dns_diff_t sig_diff;
2130         dns_diff_t nsec_diff;
2131         dns_diff_t nsec_mindiff;
2132         isc_boolean_t flag;
2133         dst_key_t *zone_keys[MAXZONEKEYS];
2134         unsigned int nkeys = 0;
2135         unsigned int i;
2136         isc_stdtime_t now, inception, expire;
2137         dns_ttl_t nsecttl;
2138         dns_rdata_soa_t soa;
2139         dns_rdata_t rdata = DNS_RDATA_INIT;
2140         dns_rdataset_t rdataset;
2141         dns_dbnode_t *node = NULL;
2142         isc_boolean_t check_ksk;
2143         isc_boolean_t unsecure;
2144         isc_boolean_t cut;
2145
2146         dns_diff_init(client->mctx, &diffnames);
2147         dns_diff_init(client->mctx, &affected);
2148
2149         dns_diff_init(client->mctx, &sig_diff);
2150         sig_diff.resign = dns_zone_getsigresigninginterval(zone);
2151         dns_diff_init(client->mctx, &nsec_diff);
2152         dns_diff_init(client->mctx, &nsec_mindiff);
2153
2154         result = find_zone_keys(zone, db, newver, client->mctx,
2155                                 MAXZONEKEYS, zone_keys, &nkeys);
2156         if (result != ISC_R_SUCCESS) {
2157                 update_log(client, zone, ISC_LOG_ERROR,
2158                            "could not get zone keys for secure dynamic update");
2159                 goto failure;
2160         }
2161
2162         isc_stdtime_get(&now);
2163         inception = now - 3600; /* Allow for some clock skew. */
2164         expire = now + sigvalidityinterval;
2165
2166         /*
2167          * Do we look at the KSK flag on the DNSKEY to determining which
2168          * keys sign which RRsets?  First check the zone option then
2169          * check the keys flags to make sure at least one has a ksk set
2170          * and one doesn't.
2171          */
2172         check_ksk = ISC_TF((dns_zone_getoptions(zone) &
2173                             DNS_ZONEOPT_UPDATECHECKKSK) != 0);
2174         /*
2175          * If we are not checking the ZSK flag then all DNSKEY's are
2176          * already signing all RRsets so we don't need to trigger special
2177          * changes.
2178          */
2179         if (*deleted_zsk && (!check_ksk || !ksk_sanity(db, oldver)))
2180                 *deleted_zsk = ISC_FALSE;
2181
2182         if (check_ksk) {
2183                 check_ksk = ksk_sanity(db, newver);
2184                 if (!check_ksk && ksk_sanity(db, oldver))
2185                         update_log(client, zone, ISC_LOG_WARNING,
2186                                    "disabling update-check-ksk");
2187         }
2188
2189         /*
2190          * If we have deleted a ZSK and we we still have some ZSK's
2191          * we don't need to convert the KSK's to a ZSK's.
2192          */
2193         if (*deleted_zsk && check_ksk)
2194                 *deleted_zsk = ISC_FALSE;
2195
2196         /*
2197          * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field.
2198          */
2199         CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
2200         dns_rdataset_init(&rdataset);
2201         CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0,
2202                                   (isc_stdtime_t) 0, &rdataset, NULL));
2203         CHECK(dns_rdataset_first(&rdataset));
2204         dns_rdataset_current(&rdataset, &rdata);
2205         CHECK(dns_rdata_tostruct(&rdata, &soa, NULL));
2206         nsecttl = soa.minimum;
2207         dns_rdataset_disassociate(&rdataset);
2208         dns_db_detachnode(db, &node);
2209
2210         /*
2211          * Find all RRsets directly affected by the update, and
2212          * update their RRSIGs.  Also build a list of names affected
2213          * by the update in "diffnames".
2214          */
2215         CHECK(dns_diff_sort(diff, temp_order));
2216
2217         t = ISC_LIST_HEAD(diff->tuples);
2218         while (t != NULL) {
2219                 dns_name_t *name = &t->name;
2220                 /* Now "name" is a new, unique name affected by the update. */
2221
2222                 CHECK(namelist_append_name(&diffnames, name));
2223
2224                 while (t != NULL && dns_name_equal(&t->name, name)) {
2225                         dns_rdatatype_t type;
2226                         type = t->rdata.type;
2227
2228                         /*
2229                          * Now "name" and "type" denote a new unique RRset
2230                          * affected by the update.
2231                          */
2232
2233                         /* Don't sign RRSIGs. */
2234                         if (type == dns_rdatatype_rrsig)
2235                                 goto skip;
2236
2237                         /*
2238                          * Delete all old RRSIGs covering this type, since they
2239                          * are all invalid when the signed RRset has changed.
2240                          * We may not be able to recreate all of them - tough.
2241                          * Special case changes to the zone's DNSKEY records
2242                          * to support offline KSKs.
2243                          */
2244                         if (type == dns_rdatatype_dnskey)
2245                                 del_keysigs(db, newver, name, &sig_diff,
2246                                             zone_keys, nkeys);
2247                         else
2248                                 CHECK(delete_if(true_p, db, newver, name,
2249                                                 dns_rdatatype_rrsig, type,
2250                                                 NULL, &sig_diff));
2251
2252                         /*
2253                          * If this RRset is still visible after the update,
2254                          * add a new signature for it.
2255                          */
2256                         CHECK(rrset_visible(db, newver, name, type, &flag));
2257                         if (flag) {
2258                                 CHECK(add_sigs(client, zone, db, newver, name,
2259                                                type, &sig_diff, zone_keys,
2260                                                nkeys, inception, expire,
2261                                                check_ksk));
2262                         }
2263                 skip:
2264                         /* Skip any other updates to the same RRset. */
2265                         while (t != NULL &&
2266                                dns_name_equal(&t->name, name) &&
2267                                t->rdata.type == type)
2268                         {
2269                                 t = ISC_LIST_NEXT(t, link);
2270                         }
2271                 }
2272         }
2273         update_log(client, zone, ISC_LOG_DEBUG(3), "updated data signatures");
2274
2275         /* Remove orphaned NSECs and RRSIG NSECs. */
2276         for (t = ISC_LIST_HEAD(diffnames.tuples);
2277              t != NULL;
2278              t = ISC_LIST_NEXT(t, link))
2279         {
2280                 CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag));
2281                 if (! flag) {
2282                         CHECK(delete_if(true_p, db, newver, &t->name,
2283                                         dns_rdatatype_any, 0,
2284                                         NULL, &sig_diff));
2285                 }
2286         }
2287         update_log(client, zone, ISC_LOG_DEBUG(3),
2288                    "removed any orphaned NSEC records");
2289
2290         /*
2291          * If we don't have a NSEC record at the origin then we need to
2292          * update the NSEC3 records.
2293          */
2294         CHECK(rrset_exists(db, newver, dns_db_origin(db), dns_rdatatype_nsec,
2295                            0, &flag));
2296         if (!flag)
2297                 goto update_nsec3;
2298
2299         update_log(client, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC chain");
2300
2301         /*
2302          * When a name is created or deleted, its predecessor needs to
2303          * have its NSEC updated.
2304          */
2305         for (t = ISC_LIST_HEAD(diffnames.tuples);
2306              t != NULL;
2307              t = ISC_LIST_NEXT(t, link))
2308         {
2309                 isc_boolean_t existed, exists;
2310                 dns_fixedname_t fixedname;
2311                 dns_name_t *prevname;
2312
2313                 dns_fixedname_init(&fixedname);
2314                 prevname = dns_fixedname_name(&fixedname);
2315
2316                 CHECK(name_exists(db, oldver, &t->name, &existed));
2317                 CHECK(name_exists(db, newver, &t->name, &exists));
2318                 if (exists == existed)
2319                         continue;
2320
2321                 /*
2322                  * Find the predecessor.
2323                  * When names become obscured or unobscured in this update
2324                  * transaction, we may find the wrong predecessor because
2325                  * the NSECs have not yet been updated to reflect the delegation
2326                  * change.  This should not matter because in this case,
2327                  * the correct predecessor is either the delegation node or
2328                  * a newly unobscured node, and those nodes are on the
2329                  * "affected" list in any case.
2330                  */
2331                 CHECK(next_active(client, zone, db, newver,
2332                                   &t->name, prevname, ISC_FALSE));
2333                 CHECK(namelist_append_name(&affected, prevname));
2334         }
2335
2336         /*
2337          * Find names potentially affected by delegation changes
2338          * (obscured by adding an NS or DNAME, or unobscured by
2339          * removing one).
2340          */
2341         for (t = ISC_LIST_HEAD(diffnames.tuples);
2342              t != NULL;
2343              t = ISC_LIST_NEXT(t, link))
2344         {
2345                 isc_boolean_t ns_existed, dname_existed;
2346                 isc_boolean_t ns_exists, dname_exists;
2347
2348                 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_ns, 0,
2349                                    &ns_existed));
2350                 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_dname, 0,
2351                                    &dname_existed));
2352                 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0,
2353                                    &ns_exists));
2354                 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0,
2355                                    &dname_exists));
2356                 if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
2357                         continue;
2358                 /*
2359                  * There was a delegation change.  Mark all subdomains
2360                  * of t->name as potentially needing a NSEC update.
2361                  */
2362                 CHECK(namelist_append_subdomain(db, &t->name, &affected));
2363         }
2364
2365         ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link);
2366         INSIST(ISC_LIST_EMPTY(diffnames.tuples));
2367
2368         CHECK(uniqify_name_list(&affected));
2369
2370         /*
2371          * Determine which names should have NSECs, and delete/create
2372          * NSECs to make it so.  We don't know the final NSEC targets yet,
2373          * so we just create placeholder NSECs with arbitrary contents
2374          * to indicate that their respective owner names should be part of
2375          * the NSEC chain.
2376          */
2377         for (t = ISC_LIST_HEAD(affected.tuples);
2378              t != NULL;
2379              t = ISC_LIST_NEXT(t, link))
2380         {
2381                 isc_boolean_t exists;
2382                 dns_name_t *name = &t->name;
2383
2384                 CHECK(name_exists(db, newver, name, &exists));
2385                 if (! exists)
2386                         continue;
2387                 CHECK(is_active(db, newver, name, &flag, &cut, NULL));
2388                 if (!flag) {
2389                         /*
2390                          * This name is obscured.  Delete any
2391                          * existing NSEC record.
2392                          */
2393                         CHECK(delete_if(true_p, db, newver, name,
2394                                         dns_rdatatype_nsec, 0,
2395                                         NULL, &nsec_diff));
2396                         CHECK(delete_if(rrsig_p, db, newver, name,
2397                                         dns_rdatatype_any, 0, NULL, diff));
2398                 } else {
2399                         /*
2400                          * This name is not obscured.  It should have a NSEC.
2401                          */
2402                         CHECK(rrset_exists(db, newver, name,
2403                                            dns_rdatatype_nsec, 0, &flag));
2404                         if (! flag)
2405                                 CHECK(add_placeholder_nsec(db, newver, name,
2406                                                            diff));
2407                         CHECK(add_exposed_sigs(client, zone, db, newver, name,
2408                                                cut, diff, zone_keys, nkeys,
2409                                                inception, expire, check_ksk));
2410                 }
2411         }
2412
2413         /*
2414          * Now we know which names are part of the NSEC chain.
2415          * Make them all point at their correct targets.
2416          */
2417         for (t = ISC_LIST_HEAD(affected.tuples);
2418              t != NULL;
2419              t = ISC_LIST_NEXT(t, link))
2420         {
2421                 CHECK(rrset_exists(db, newver, &t->name,
2422                                    dns_rdatatype_nsec, 0, &flag));
2423                 if (flag) {
2424                         /*
2425                          * There is a NSEC, but we don't know if it is correct.
2426                          * Delete it and create a correct one to be sure.
2427                          * If the update was unnecessary, the diff minimization
2428                          * will take care of eliminating it from the journal,
2429                          * IXFRs, etc.
2430                          *
2431                          * The RRSIG bit should always be set in the NSECs
2432                          * we generate, because they will all get RRSIG NSECs.
2433                          * (XXX what if the zone keys are missing?).
2434                          * Because the RRSIG NSECs have not necessarily been
2435                          * created yet, the correctness of the bit mask relies
2436                          * on the assumption that NSECs are only created if
2437                          * there is other data, and if there is other data,
2438                          * there are other RRSIGs.
2439                          */
2440                         CHECK(add_nsec(client, zone, db, newver, &t->name,
2441                                        nsecttl, &nsec_diff));
2442                 }
2443         }
2444
2445         /*
2446          * Minimize the set of NSEC updates so that we don't
2447          * have to regenerate the RRSIG NSECs for NSECs that were
2448          * replaced with identical ones.
2449          */
2450         while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
2451                 ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
2452                 dns_diff_appendminimal(&nsec_mindiff, &t);
2453         }
2454
2455         update_log(client, zone, ISC_LOG_DEBUG(3),
2456                    "signing rebuilt NSEC chain");
2457
2458         /* Update RRSIG NSECs. */
2459         for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
2460              t != NULL;
2461              t = ISC_LIST_NEXT(t, link))
2462         {
2463                 if (t->op == DNS_DIFFOP_DEL) {
2464                         CHECK(delete_if(true_p, db, newver, &t->name,
2465                                         dns_rdatatype_rrsig, dns_rdatatype_nsec,
2466                                         NULL, &sig_diff));
2467                 } else if (t->op == DNS_DIFFOP_ADD) {
2468                         CHECK(add_sigs(client, zone, db, newver, &t->name,
2469                                        dns_rdatatype_nsec, &sig_diff,
2470                                        zone_keys, nkeys, inception, expire,
2471                                        check_ksk));
2472                 } else {
2473                         INSIST(0);
2474                 }
2475         }
2476
2477  update_nsec3:
2478
2479         /* Record our changes for the journal. */
2480         while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
2481                 ISC_LIST_UNLINK(sig_diff.tuples, t, link);
2482                 dns_diff_appendminimal(diff, &t);
2483         }
2484         while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
2485                 ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
2486                 dns_diff_appendminimal(diff, &t);
2487         }
2488
2489         INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
2490         INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
2491         INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
2492
2493         /*
2494          * Check if we have any active NSEC3 chains by looking for a
2495          * NSEC3PARAM RRset.
2496          */
2497         CHECK(rrset_exists(db, newver, dns_db_origin(db),
2498                            dns_rdatatype_nsec3param, 0, &flag));
2499         if (!flag) {
2500                 update_log(client, zone, ISC_LOG_DEBUG(3),
2501                            "no NSEC3 chains to rebuild");
2502                 goto failure;
2503         }
2504
2505         update_log(client, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC3 chains");
2506
2507         dns_diff_clear(&diffnames);
2508         dns_diff_clear(&affected);
2509
2510         CHECK(dns_diff_sort(diff, temp_order));
2511
2512         /*
2513          * Find names potentially affected by delegation changes
2514          * (obscured by adding an NS or DNAME, or unobscured by
2515          * removing one).
2516          */
2517         t = ISC_LIST_HEAD(diff->tuples);
2518         while (t != NULL) {
2519                 dns_name_t *name = &t->name;
2520
2521                 isc_boolean_t ns_existed, dname_existed;
2522                 isc_boolean_t ns_exists, dname_exists;
2523
2524                 if (t->rdata.type == dns_rdatatype_nsec ||
2525                     t->rdata.type == dns_rdatatype_rrsig) {
2526                         t = ISC_LIST_NEXT(t, link);
2527                         continue;
2528                 }
2529
2530                 CHECK(namelist_append_name(&affected, name));
2531
2532                 CHECK(rrset_exists(db, oldver, name, dns_rdatatype_ns, 0,
2533                                    &ns_existed));
2534                 CHECK(rrset_exists(db, oldver, name, dns_rdatatype_dname, 0,
2535                                    &dname_existed));
2536                 CHECK(rrset_exists(db, newver, name, dns_rdatatype_ns, 0,
2537                                    &ns_exists));
2538                 CHECK(rrset_exists(db, newver, name, dns_rdatatype_dname, 0,
2539                                    &dname_exists));
2540
2541                 if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
2542                         goto nextname;
2543                 /*
2544                  * There was a delegation change.  Mark all subdomains
2545                  * of t->name as potentially needing a NSEC3 update.
2546                  */
2547                 CHECK(namelist_append_subdomain(db, name, &affected));
2548
2549         nextname:
2550                 while (t != NULL && dns_name_equal(&t->name, name))
2551                         t = ISC_LIST_NEXT(t, link);
2552         }
2553
2554         for (t = ISC_LIST_HEAD(affected.tuples);
2555              t != NULL;
2556              t = ISC_LIST_NEXT(t, link)) {
2557                 dns_name_t *name = &t->name;
2558
2559                 unsecure = ISC_FALSE;   /* Silence compiler warning. */
2560                 CHECK(is_active(db, newver, name, &flag, &cut, &unsecure));
2561
2562                 if (!flag) {
2563                         CHECK(delete_if(rrsig_p, db, newver, name,
2564                                         dns_rdatatype_any, 0, NULL, diff));
2565                         CHECK(dns_nsec3_delnsec3s(db, newver, name,
2566                                                   &nsec_diff));
2567                 } else {
2568                         CHECK(add_exposed_sigs(client, zone, db, newver, name,
2569                                                cut, diff, zone_keys, nkeys,
2570                                                inception, expire, check_ksk));
2571                         CHECK(dns_nsec3_addnsec3s(db, newver, name, nsecttl,
2572                                                   unsecure, &nsec_diff));
2573                 }
2574         }
2575
2576         /*
2577          * Minimize the set of NSEC3 updates so that we don't
2578          * have to regenerate the RRSIG NSEC3s for NSEC3s that were
2579          * replaced with identical ones.
2580          */
2581         while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
2582                 ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
2583                 dns_diff_appendminimal(&nsec_mindiff, &t);
2584         }
2585
2586         update_log(client, zone, ISC_LOG_DEBUG(3),
2587                    "signing rebuilt NSEC3 chain");
2588
2589         /* Update RRSIG NSEC3s. */
2590         for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
2591              t != NULL;
2592              t = ISC_LIST_NEXT(t, link))
2593         {
2594                 if (t->op == DNS_DIFFOP_DEL) {
2595                         CHECK(delete_if(true_p, db, newver, &t->name,
2596                                         dns_rdatatype_rrsig,
2597                                         dns_rdatatype_nsec3,
2598                                         NULL, &sig_diff));
2599                 } else if (t->op == DNS_DIFFOP_ADD) {
2600                         CHECK(add_sigs(client, zone, db, newver, &t->name,
2601                                        dns_rdatatype_nsec3,
2602                                        &sig_diff, zone_keys, nkeys,
2603                                        inception, expire, check_ksk));
2604                 } else {
2605                         INSIST(0);
2606                 }
2607         }
2608
2609         /* Record our changes for the journal. */
2610         while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
2611                 ISC_LIST_UNLINK(sig_diff.tuples, t, link);
2612                 dns_diff_appendminimal(diff, &t);
2613         }
2614         while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
2615                 ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
2616                 dns_diff_appendminimal(diff, &t);
2617         }
2618
2619         INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
2620         INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
2621         INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
2622
2623  failure:
2624         dns_diff_clear(&sig_diff);
2625         dns_diff_clear(&nsec_diff);
2626         dns_diff_clear(&nsec_mindiff);
2627
2628         dns_diff_clear(&affected);
2629         dns_diff_clear(&diffnames);
2630
2631         for (i = 0; i < nkeys; i++)
2632                 dst_key_free(&zone_keys[i]);
2633
2634         return (result);
2635 }
2636
2637
2638 /**************************************************************************/
2639 /*%
2640  * The actual update code in all its glory.  We try to follow
2641  * the RFC2136 pseudocode as closely as possible.
2642  */
2643
2644 static isc_result_t
2645 send_update_event(ns_client_t *client, dns_zone_t *zone) {
2646         isc_result_t result = ISC_R_SUCCESS;
2647         update_event_t *event = NULL;
2648         isc_task_t *zonetask = NULL;
2649         ns_client_t *evclient;
2650
2651         event = (update_event_t *)
2652                 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
2653                                    update_action, NULL, sizeof(*event));
2654         if (event == NULL)
2655                 FAIL(ISC_R_NOMEMORY);
2656         event->zone = zone;
2657         event->result = ISC_R_SUCCESS;
2658
2659         evclient = NULL;
2660         ns_client_attach(client, &evclient);
2661         INSIST(client->nupdates == 0);
2662         client->nupdates++;
2663         event->ev_arg = evclient;
2664
2665         dns_zone_gettask(zone, &zonetask);
2666         isc_task_send(zonetask, ISC_EVENT_PTR(&event));
2667
2668  failure:
2669         if (event != NULL)
2670                 isc_event_free(ISC_EVENT_PTR(&event));
2671         return (result);
2672 }
2673
2674 static void
2675 respond(ns_client_t *client, isc_result_t result) {
2676         isc_result_t msg_result;
2677
2678         msg_result = dns_message_reply(client->message, ISC_TRUE);
2679         if (msg_result != ISC_R_SUCCESS)
2680                 goto msg_failure;
2681         client->message->rcode = dns_result_torcode(result);
2682
2683         ns_client_send(client);
2684         return;
2685
2686  msg_failure:
2687         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
2688                       ISC_LOG_ERROR,
2689                       "could not create update response message: %s",
2690                       isc_result_totext(msg_result));
2691         ns_client_next(client, msg_result);
2692 }
2693
2694 void
2695 ns_update_start(ns_client_t *client, isc_result_t sigresult) {
2696         dns_message_t *request = client->message;
2697         isc_result_t result;
2698         dns_name_t *zonename;
2699         dns_rdataset_t *zone_rdataset;
2700         dns_zone_t *zone = NULL;
2701
2702         /*
2703          * Interpret the zone section.
2704          */
2705         result = dns_message_firstname(request, DNS_SECTION_ZONE);
2706         if (result != ISC_R_SUCCESS)
2707                 FAILC(DNS_R_FORMERR, "update zone section empty");
2708
2709         /*
2710          * The zone section must contain exactly one "question", and
2711          * it must be of type SOA.
2712          */
2713         zonename = NULL;
2714         dns_message_currentname(request, DNS_SECTION_ZONE, &zonename);
2715         zone_rdataset = ISC_LIST_HEAD(zonename->list);
2716         if (zone_rdataset->type != dns_rdatatype_soa)
2717                 FAILC(DNS_R_FORMERR,
2718                       "update zone section contains non-SOA");
2719         if (ISC_LIST_NEXT(zone_rdataset, link) != NULL)
2720                 FAILC(DNS_R_FORMERR,
2721                       "update zone section contains multiple RRs");
2722
2723         /* The zone section must have exactly one name. */
2724         result = dns_message_nextname(request, DNS_SECTION_ZONE);
2725         if (result != ISC_R_NOMORE)
2726                 FAILC(DNS_R_FORMERR,
2727                       "update zone section contains multiple RRs");
2728
2729         result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
2730                              &zone);
2731         if (result != ISC_R_SUCCESS)
2732                 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
2733
2734         switch(dns_zone_gettype(zone)) {
2735         case dns_zone_master:
2736                 /*
2737                  * We can now fail due to a bad signature as we now know
2738                  * that we are the master.
2739                  */
2740                 if (sigresult != ISC_R_SUCCESS)
2741                         FAIL(sigresult);
2742                 CHECK(send_update_event(client, zone));
2743                 break;
2744         case dns_zone_slave:
2745                 CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone),
2746                                      "update forwarding", zonename, ISC_TRUE,
2747                                      ISC_FALSE));
2748                 CHECK(send_forward_event(client, zone));
2749                 break;
2750         default:
2751                 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
2752         }
2753         return;
2754
2755  failure:
2756         if (result == DNS_R_REFUSED) {
2757                 INSIST(dns_zone_gettype(zone) == dns_zone_slave);
2758                 inc_stats(zone, dns_nsstatscounter_updaterej);
2759         }
2760         /*
2761          * We failed without having sent an update event to the zone.
2762          * We are still in the client task context, so we can
2763          * simply give an error response without switching tasks.
2764          */
2765         respond(client, result);
2766         if (zone != NULL)
2767                 dns_zone_detach(&zone);
2768 }
2769
2770 /*%
2771  * DS records are not allowed to exist without corresponding NS records,
2772  * RFC 3658, 2.2 Protocol Change,
2773  * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex".
2774  */
2775
2776 static isc_result_t
2777 remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) {
2778         isc_result_t result;
2779         isc_boolean_t ns_exists;
2780         dns_difftuple_t *tupple;
2781         dns_diff_t temp_diff;
2782
2783         dns_diff_init(diff->mctx, &temp_diff);
2784
2785         for (tupple = ISC_LIST_HEAD(diff->tuples);
2786              tupple != NULL;
2787              tupple = ISC_LIST_NEXT(tupple, link)) {
2788                 if (!((tupple->op == DNS_DIFFOP_DEL &&
2789                        tupple->rdata.type == dns_rdatatype_ns) ||
2790                       (tupple->op == DNS_DIFFOP_ADD &&
2791                        tupple->rdata.type == dns_rdatatype_ds)))
2792                         continue;
2793                 CHECK(rrset_exists(db, newver, &tupple->name,
2794                                    dns_rdatatype_ns, 0, &ns_exists));
2795                 if (ns_exists &&
2796                     !dns_name_equal(&tupple->name, dns_db_origin(db)))
2797                         continue;
2798                 CHECK(delete_if(true_p, db, newver, &tupple->name,
2799                                 dns_rdatatype_ds, 0, NULL, &temp_diff));
2800         }
2801         result = ISC_R_SUCCESS;
2802
2803  failure:
2804         for (tupple = ISC_LIST_HEAD(temp_diff.tuples);
2805              tupple != NULL;
2806              tupple = ISC_LIST_HEAD(temp_diff.tuples)) {
2807                 ISC_LIST_UNLINK(temp_diff.tuples, tupple, link);
2808                 dns_diff_appendminimal(diff, &tupple);
2809         }
2810         return (result);
2811 }
2812
2813 /*
2814  * This implements the post load integrity checks for mx records.
2815  */
2816 static isc_result_t
2817 check_mx(ns_client_t *client, dns_zone_t *zone,
2818          dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff)
2819 {
2820         char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
2821         char ownerbuf[DNS_NAME_FORMATSIZE];
2822         char namebuf[DNS_NAME_FORMATSIZE];
2823         char altbuf[DNS_NAME_FORMATSIZE];
2824         dns_difftuple_t *t;
2825         dns_fixedname_t fixed;
2826         dns_name_t *foundname;
2827         dns_rdata_mx_t mx;
2828         dns_rdata_t rdata;
2829         isc_boolean_t ok = ISC_TRUE;
2830         isc_boolean_t isaddress;
2831         isc_result_t result;
2832         struct in6_addr addr6;
2833         struct in_addr addr;
2834         unsigned int options;
2835
2836         dns_fixedname_init(&fixed);
2837         foundname = dns_fixedname_name(&fixed);
2838         dns_rdata_init(&rdata);
2839         options = dns_zone_getoptions(zone);
2840
2841         for (t = ISC_LIST_HEAD(diff->tuples);
2842              t != NULL;
2843              t = ISC_LIST_NEXT(t, link)) {
2844                 if (t->op != DNS_DIFFOP_ADD ||
2845                     t->rdata.type != dns_rdatatype_mx)
2846                         continue;
2847
2848                 result = dns_rdata_tostruct(&t->rdata, &mx, NULL);
2849                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2850                 /*
2851                  * Check if we will error out if we attempt to reload the
2852                  * zone.
2853                  */
2854                 dns_name_format(&mx.mx, namebuf, sizeof(namebuf));
2855                 dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf));
2856                 isaddress = ISC_FALSE;
2857                 if ((options & DNS_RDATA_CHECKMX) != 0 &&
2858                     strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) {
2859                         if (tmp[strlen(tmp) - 1] == '.')
2860                                 tmp[strlen(tmp) - 1] = '\0';
2861                         if (inet_aton(tmp, &addr) == 1 ||
2862                             inet_pton(AF_INET6, tmp, &addr6) == 1)
2863                                 isaddress = ISC_TRUE;
2864                 }
2865
2866                 if (isaddress && (options & DNS_RDATA_CHECKMXFAIL) != 0) {
2867                         update_log(client, zone, ISC_LOG_ERROR,
2868                                    "%s/MX: '%s': %s",
2869                                    ownerbuf, namebuf,
2870                                    dns_result_totext(DNS_R_MXISADDRESS));
2871                         ok = ISC_FALSE;
2872                 } else if (isaddress) {
2873                         update_log(client, zone, ISC_LOG_WARNING,
2874                                    "%s/MX: warning: '%s': %s",
2875                                    ownerbuf, namebuf,
2876                                    dns_result_totext(DNS_R_MXISADDRESS));
2877                 }
2878
2879                 /*
2880                  * Check zone integrity checks.
2881                  */
2882                 if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0)
2883                         continue;
2884                 result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a,
2885                                      0, 0, NULL, foundname, NULL, NULL);
2886                 if (result == ISC_R_SUCCESS)
2887                         continue;
2888
2889                 if (result == DNS_R_NXRRSET) {
2890                         result = dns_db_find(db, &mx.mx, newver,
2891                                              dns_rdatatype_aaaa,
2892                                              0, 0, NULL, foundname,
2893                                              NULL, NULL);
2894                         if (result == ISC_R_SUCCESS)
2895                                 continue;
2896                 }
2897
2898                 if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) {
2899                         update_log(client, zone, ISC_LOG_ERROR,
2900                                    "%s/MX '%s' has no address records "
2901                                    "(A or AAAA)", ownerbuf, namebuf);
2902                         ok = ISC_FALSE;
2903                 } else if (result == DNS_R_CNAME) {
2904                         update_log(client, zone, ISC_LOG_ERROR,
2905                                    "%s/MX '%s' is a CNAME (illegal)",
2906                                    ownerbuf, namebuf);
2907                         ok = ISC_FALSE;
2908                 } else if (result == DNS_R_DNAME) {
2909                         dns_name_format(foundname, altbuf, sizeof altbuf);
2910                         update_log(client, zone, ISC_LOG_ERROR,
2911                                    "%s/MX '%s' is below a DNAME '%s' (illegal)",
2912                                    ownerbuf, namebuf, altbuf);
2913                         ok = ISC_FALSE;
2914                 }
2915         }
2916         return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
2917 }
2918
2919 static isc_result_t
2920 rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
2921           const dns_rdata_t *rdata, isc_boolean_t *flag)
2922 {
2923         dns_rdataset_t rdataset;
2924         dns_dbnode_t *node = NULL;
2925         isc_result_t result;
2926
2927         dns_rdataset_init(&rdataset);
2928         if (rdata->type == dns_rdatatype_nsec3)
2929                 CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
2930         else
2931                 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
2932         result = dns_db_findrdataset(db, node, ver, rdata->type, 0,
2933                                      (isc_stdtime_t) 0, &rdataset, NULL);
2934         if (result == ISC_R_NOTFOUND) {
2935                 *flag = ISC_FALSE;
2936                 result = ISC_R_SUCCESS;
2937                 goto failure;
2938         }
2939
2940         for (result = dns_rdataset_first(&rdataset);
2941              result == ISC_R_SUCCESS;
2942              result = dns_rdataset_next(&rdataset)) {
2943                 dns_rdata_t myrdata = DNS_RDATA_INIT;
2944                 dns_rdataset_current(&rdataset, &myrdata);
2945                 if (!dns_rdata_compare(&myrdata, rdata))
2946                         break;
2947         }
2948         dns_rdataset_disassociate(&rdataset);
2949         if (result == ISC_R_SUCCESS) {
2950                 *flag = ISC_TRUE;
2951         } else if (result == ISC_R_NOMORE) {
2952                 *flag = ISC_FALSE;
2953                 result = ISC_R_SUCCESS;
2954         }
2955
2956  failure:
2957         if (node != NULL)
2958                 dns_db_detachnode(db, &node);
2959         return (result);
2960 }
2961
2962 static isc_result_t
2963 get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) {
2964         dns_dbnode_t *node = NULL;
2965         dns_rdata_nsec3param_t nsec3param;
2966         dns_rdataset_t rdataset;
2967         isc_result_t result;
2968         unsigned int iterations = 0;
2969
2970         dns_rdataset_init(&rdataset);
2971
2972         result = dns_db_getoriginnode(db, &node);
2973         if (result != ISC_R_SUCCESS)
2974                 return (result);
2975         result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
2976                                      0, (isc_stdtime_t) 0, &rdataset, NULL);
2977         dns_db_detachnode(db, &node);
2978         if (result == ISC_R_NOTFOUND)
2979                 goto success;
2980         if (result != ISC_R_SUCCESS)
2981                 goto failure;
2982
2983         for (result = dns_rdataset_first(&rdataset);
2984              result == ISC_R_SUCCESS;
2985              result = dns_rdataset_next(&rdataset)) {
2986                 dns_rdata_t rdata = DNS_RDATA_INIT;
2987                 dns_rdataset_current(&rdataset, &rdata);
2988                 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
2989                 if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
2990                         continue;
2991                 if (nsec3param.iterations > iterations)
2992                         iterations = nsec3param.iterations;
2993         }
2994         if (result != ISC_R_NOMORE)
2995                 goto failure;
2996
2997  success:
2998         *iterationsp = iterations;
2999         result = ISC_R_SUCCESS;
3000
3001  failure:
3002         if (dns_rdataset_isassociated(&rdataset))
3003                 dns_rdataset_disassociate(&rdataset);
3004         return (result);
3005 }
3006
3007 /*
3008  * Prevent the zone entering a inconsistent state where
3009  * NSEC only DNSKEYs are present with NSEC3 chains.
3010  */
3011 static isc_result_t
3012 check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
3013              dns_dbversion_t *ver, dns_diff_t *diff)
3014 {
3015         dns_diff_t temp_diff;
3016         dns_diffop_t op;
3017         dns_difftuple_t *tuple, *newtuple = NULL, *next;
3018         isc_boolean_t flag;
3019         isc_result_t result;
3020         unsigned int iterations = 0, max;
3021
3022         dns_diff_init(diff->mctx, &temp_diff);
3023
3024         CHECK(dns_nsec_nseconly(db, ver, &flag));
3025
3026         if (flag)
3027                 CHECK(dns_nsec3_active(db, ver, ISC_FALSE, &flag));
3028         if (flag) {
3029                 update_log(client, zone, ISC_LOG_WARNING,
3030                            "NSEC only DNSKEYs and NSEC3 chains not allowed");
3031         } else {
3032                 CHECK(get_iterations(db, ver, &iterations));
3033                 CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max));
3034                 if (max != 0 && iterations > max) {
3035                         flag = ISC_TRUE;
3036                         update_log(client, zone, ISC_LOG_WARNING,
3037                                    "too many NSEC3 iterations (%u) for "
3038                                    "weakest DNSKEY (%u)", iterations, max);
3039                 }
3040         }
3041         if (flag) {
3042                 for (tuple = ISC_LIST_HEAD(diff->tuples);
3043                      tuple != NULL;
3044                      tuple = next) {
3045                         next = ISC_LIST_NEXT(tuple, link);
3046                         if (tuple->rdata.type != dns_rdatatype_dnskey &&
3047                             tuple->rdata.type != dns_rdatatype_nsec3param)
3048                                 continue;
3049                         op = (tuple->op == DNS_DIFFOP_DEL) ?
3050                              DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
3051                         CHECK(dns_difftuple_create(temp_diff.mctx, op,
3052                                                    &tuple->name, tuple->ttl,
3053                                                    &tuple->rdata, &newtuple));
3054                         CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff));
3055                         INSIST(newtuple == NULL);
3056                 }
3057                 for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
3058                      tuple != NULL;
3059                      tuple = ISC_LIST_HEAD(temp_diff.tuples)) {
3060                         ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
3061                         dns_diff_appendminimal(diff, &tuple);
3062                 }
3063         }
3064
3065
3066  failure:
3067         dns_diff_clear(&temp_diff);
3068         return (result);
3069 }
3070
3071 #ifdef ALLOW_NSEC3PARAM_UPDATE
3072 /*
3073  * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
3074  */
3075 static isc_result_t
3076 add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
3077                        dns_name_t *name, dns_dbversion_t *ver, dns_diff_t *diff)
3078 {
3079         isc_result_t result = ISC_R_SUCCESS;
3080         dns_difftuple_t *tuple, *newtuple = NULL, *next;
3081         dns_rdata_t rdata = DNS_RDATA_INIT;
3082         unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
3083         dns_diff_t temp_diff;
3084         dns_diffop_t op;
3085         isc_boolean_t flag;
3086
3087         update_log(client, zone, ISC_LOG_DEBUG(3),
3088                     "checking for NSEC3PARAM changes");
3089
3090         dns_diff_init(diff->mctx, &temp_diff);
3091
3092         /*
3093          * Extract NSEC3PARAM tuples from list.
3094          */
3095         for (tuple = ISC_LIST_HEAD(diff->tuples);
3096              tuple != NULL;
3097              tuple = next) {
3098
3099                 next = ISC_LIST_NEXT(tuple, link);
3100
3101                 if (tuple->rdata.type != dns_rdatatype_nsec3param ||
3102                     !dns_name_equal(name, &tuple->name))
3103                         continue;
3104                 ISC_LIST_UNLINK(diff->tuples, tuple, link);
3105                 ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
3106         }
3107
3108         for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
3109              tuple != NULL; tuple = next) {
3110
3111                 if (tuple->op == DNS_DIFFOP_ADD) {
3112                         next = ISC_LIST_NEXT(tuple, link);
3113                         while (next != NULL) {
3114                                 unsigned char *next_data = next->rdata.data;
3115                                 unsigned char *tuple_data = tuple->rdata.data;
3116                                 if (next_data[0] != tuple_data[0] ||
3117                                         /* Ignore flags. */
3118                                     next_data[2] != tuple_data[2] ||
3119                                     next_data[3] != tuple_data[3] ||
3120                                     next_data[4] != tuple_data[4] ||
3121                                     !memcmp(&next_data[5], &tuple_data[5],
3122                                             tuple_data[4])) {
3123                                         next = ISC_LIST_NEXT(next, link);
3124                                         continue;
3125                                 }
3126                                 op = (next->op == DNS_DIFFOP_DEL) ?
3127                                      DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
3128                                 CHECK(dns_difftuple_create(diff->mctx, op,
3129                                                            name, next->ttl,
3130                                                            &next->rdata,
3131                                                            &newtuple));
3132                                 CHECK(do_one_tuple(&newtuple, db, ver, diff));
3133                                 ISC_LIST_UNLINK(temp_diff.tuples, next, link);
3134                                 dns_diff_appendminimal(diff, &next);
3135                                 next = ISC_LIST_NEXT(tuple, link);
3136                         }
3137
3138                         INSIST(tuple->rdata.data[1] & DNS_NSEC3FLAG_UPDATE);
3139
3140                         /*
3141                          * See if we already have a CREATE request in progress.
3142                          */
3143                         dns_rdata_clone(&tuple->rdata, &rdata);
3144                         INSIST(rdata.length <= sizeof(buf));
3145                         memcpy(buf, rdata.data, rdata.length);
3146                         buf[1] |= DNS_NSEC3FLAG_CREATE;
3147                         buf[1] &= ~DNS_NSEC3FLAG_UPDATE;
3148                         rdata.data = buf;
3149
3150                         CHECK(rr_exists(db, ver, name, &rdata, &flag));
3151
3152                         if (!flag) {
3153                                 CHECK(dns_difftuple_create(diff->mctx,
3154                                                            DNS_DIFFOP_ADD,
3155                                                            name, tuple->ttl,
3156                                                            &rdata,
3157                                                            &newtuple));
3158                                 CHECK(do_one_tuple(&newtuple, db, ver, diff));
3159                         }
3160
3161                         /*
3162                          * Remove any existing CREATE request to add an
3163                          * otherwise indentical chain with a reversed
3164                          * OPTOUT state.
3165                          */
3166                         buf[1] ^= DNS_NSEC3FLAG_OPTOUT;
3167                         CHECK(rr_exists(db, ver, name, &rdata, &flag));
3168
3169                         if (flag) {
3170                                 CHECK(dns_difftuple_create(diff->mctx,
3171                                                            DNS_DIFFOP_DEL,
3172                                                            name, tuple->ttl,
3173                                                            &rdata,
3174                                                            &newtuple));
3175                                 CHECK(do_one_tuple(&newtuple, db, ver, diff));
3176                         }
3177
3178                         /*
3179                          * Remove the temporary add record.
3180                          */
3181                         CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
3182                                                    name, tuple->ttl,
3183                                                    &tuple->rdata, &newtuple));
3184                         CHECK(do_one_tuple(&newtuple, db, ver, diff));
3185                         next = ISC_LIST_NEXT(tuple, link);
3186                         ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
3187                         dns_diff_appendminimal(diff, &tuple);
3188                         dns_rdata_reset(&rdata);
3189                 } else
3190                         next = ISC_LIST_NEXT(tuple, link);
3191         }
3192
3193         /*
3194          * Reverse any pending changes.
3195          */
3196         for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
3197              tuple != NULL; tuple = next) {
3198                 next = ISC_LIST_NEXT(tuple, link);
3199                 if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
3200                         op = (tuple->op == DNS_DIFFOP_DEL) ?
3201                              DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
3202                         CHECK(dns_difftuple_create(diff->mctx, op, name,
3203                                                    tuple->ttl, &tuple->rdata,
3204                                                    &newtuple));
3205                         CHECK(do_one_tuple(&newtuple, db, ver, diff));
3206                         ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
3207                         dns_diff_appendminimal(diff, &tuple);
3208                 }
3209         }
3210
3211         /*
3212          * Convert deletions into delayed deletions.
3213          */
3214         for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
3215              tuple != NULL; tuple = next) {
3216                 next = ISC_LIST_NEXT(tuple, link);
3217                 /*
3218                  * See if we already have a REMOVE request in progress.
3219                  */
3220                 dns_rdata_clone(&tuple->rdata, &rdata);
3221                 INSIST(rdata.length <= sizeof(buf));
3222                 memcpy(buf, rdata.data, rdata.length);
3223                 buf[1] |= DNS_NSEC3FLAG_REMOVE;
3224                 rdata.data = buf;
3225
3226                 CHECK(rr_exists(db, ver, name, &rdata, &flag));
3227
3228                 if (!flag) {
3229                         CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
3230                                                    name, tuple->ttl, &rdata,
3231                                                    &newtuple));
3232                         CHECK(do_one_tuple(&newtuple, db, ver, diff));
3233                 }
3234                 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
3235                                            tuple->ttl, &tuple->rdata,
3236                                            &newtuple));
3237                 CHECK(do_one_tuple(&newtuple, db, ver, diff));
3238                 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
3239                 dns_diff_appendminimal(diff, &tuple);
3240                 dns_rdata_reset(&rdata);
3241         }
3242
3243         result = ISC_R_SUCCESS;
3244  failure:
3245         dns_diff_clear(&temp_diff);
3246         return (result);
3247 }
3248 #endif
3249
3250 /*
3251  * Add records to cause the delayed signing of the zone by added DNSKEY
3252  * to remove the RRSIG records generated by a deleted DNSKEY.
3253  */
3254 static isc_result_t
3255 add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver,
3256                     dns_rdatatype_t privatetype, dns_diff_t *diff)
3257 {
3258         dns_difftuple_t *tuple, *newtuple = NULL;
3259         dns_rdata_dnskey_t dnskey;
3260         dns_rdata_t rdata = DNS_RDATA_INIT;
3261         isc_boolean_t flag;
3262         isc_region_t r;
3263         isc_result_t result = ISC_R_SUCCESS;
3264         isc_uint16_t keyid;
3265         unsigned char buf[5];
3266
3267         for (tuple = ISC_LIST_HEAD(diff->tuples);
3268              tuple != NULL;
3269              tuple = ISC_LIST_NEXT(tuple, link)) {
3270                 if (tuple->rdata.type != dns_rdatatype_dnskey)
3271                         continue;
3272
3273                 dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
3274                 if ((dnskey.flags &
3275                      (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
3276                          != DNS_KEYOWNER_ZONE)
3277                         continue;
3278
3279                 dns_rdata_toregion(&tuple->rdata, &r);
3280                 keyid = dst_region_computeid(&r, dnskey.algorithm);
3281
3282                 buf[0] = dnskey.algorithm;
3283                 buf[1] = (keyid & 0xff00) >> 8;
3284                 buf[2] = (keyid & 0xff);
3285                 buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
3286                 buf[4] = 0;
3287                 rdata.data = buf;
3288                 rdata.length = sizeof(buf);
3289                 rdata.type = privatetype;
3290                 rdata.rdclass = tuple->rdata.rdclass;
3291
3292                 CHECK(rr_exists(db, ver, name, &rdata, &flag));
3293                 if (flag)
3294                         continue;
3295                 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
3296                                            name, 0, &rdata, &newtuple));
3297                 CHECK(do_one_tuple(&newtuple, db, ver, diff));
3298                 INSIST(newtuple == NULL);
3299                 /*
3300                  * Remove any record which says this operation has already
3301                  * completed.
3302                  */
3303                 buf[4] = 1;
3304                 CHECK(rr_exists(db, ver, name, &rdata, &flag));
3305                 if (flag) {
3306                         CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
3307                                                    name, 0, &rdata, &newtuple));
3308                         CHECK(do_one_tuple(&newtuple, db, ver, diff));
3309                         INSIST(newtuple == NULL);
3310                 }
3311         }
3312  failure:
3313         return (result);
3314 }
3315
3316 #ifdef ALLOW_NSEC3PARAM_UPDATE
3317 /*
3318  * Mark all NSEC3 chains for deletion without creating a NSEC chain as
3319  * a side effect of deleting the last chain.
3320  */
3321 static isc_result_t
3322 delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
3323               dns_diff_t *diff)
3324 {
3325         dns_dbnode_t *node = NULL;
3326         dns_difftuple_t *tuple = NULL;
3327         dns_name_t next;
3328         dns_rdata_t rdata = DNS_RDATA_INIT;
3329         dns_rdataset_t rdataset;
3330         isc_boolean_t flag;
3331         isc_result_t result = ISC_R_SUCCESS;
3332         unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
3333
3334         dns_name_init(&next, NULL);
3335         dns_rdataset_init(&rdataset);
3336
3337         result = dns_db_getoriginnode(db, &node);
3338         if (result != ISC_R_SUCCESS)
3339                 return (result);
3340
3341         /*
3342          * Cause all NSEC3 chains to be deleted.
3343          */
3344         result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
3345                                      0, (isc_stdtime_t) 0, &rdataset, NULL);
3346         if (result == ISC_R_NOTFOUND)
3347                 goto success;
3348         if (result != ISC_R_SUCCESS)
3349                 goto failure;
3350
3351         for (result = dns_rdataset_first(&rdataset);
3352              result == ISC_R_SUCCESS;
3353              result = dns_rdataset_next(&rdataset)) {
3354                 dns_rdataset_current(&rdataset, &rdata);
3355                 INSIST(rdata.length <= sizeof(buf));
3356                 memcpy(buf, rdata.data, rdata.length);
3357
3358                 if (buf[1] == (DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC)) {
3359                         dns_rdata_reset(&rdata);
3360                         continue;
3361                 }
3362
3363                 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
3364                                            origin, 0, &rdata, &tuple));
3365                 CHECK(do_one_tuple(&tuple, db, ver, diff));
3366                 INSIST(tuple == NULL);
3367
3368                 buf[1] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
3369                 rdata.data = buf;
3370
3371                 CHECK(rr_exists(db, ver, origin, &rdata, &flag));
3372
3373                 if (!flag) {
3374                         CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
3375                                                    origin, 0, &rdata, &tuple));
3376                         CHECK(do_one_tuple(&tuple, db, ver, diff));
3377                         INSIST(tuple == NULL);
3378                 }
3379                 dns_rdata_reset(&rdata);
3380         }
3381         if (result != ISC_R_NOMORE)
3382                 goto failure;
3383  success:
3384         result = ISC_R_SUCCESS;
3385
3386  failure:
3387         if (dns_rdataset_isassociated(&rdataset))
3388                 dns_rdataset_disassociate(&rdataset);
3389         dns_db_detachnode(db, &node);
3390         return (result);
3391 }
3392 #endif
3393
3394 static void
3395 update_action(isc_task_t *task, isc_event_t *event) {
3396         update_event_t *uev = (update_event_t *) event;
3397         dns_zone_t *zone = uev->zone;
3398         ns_client_t *client = (ns_client_t *)event->ev_arg;
3399
3400         isc_result_t result;
3401         dns_db_t *db = NULL;
3402         dns_dbversion_t *oldver = NULL;
3403         dns_dbversion_t *ver = NULL;
3404         dns_diff_t diff;        /* Pending updates. */
3405         dns_diff_t temp;        /* Pending RR existence assertions. */
3406         isc_boolean_t soa_serial_changed = ISC_FALSE;
3407         isc_mem_t *mctx = client->mctx;
3408         dns_rdatatype_t covers;
3409         dns_message_t *request = client->message;
3410         dns_rdataclass_t zoneclass;
3411         dns_name_t *zonename;
3412         dns_ssutable_t *ssutable = NULL;
3413         dns_fixedname_t tmpnamefixed;
3414         dns_name_t *tmpname = NULL;
3415         unsigned int options;
3416         isc_boolean_t deleted_zsk;
3417         dns_difftuple_t *tuple;
3418         dns_rdata_dnskey_t dnskey;
3419 #ifdef ALLOW_NSEC3PARAM_UPDATE
3420         unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
3421 #endif
3422 #if !defined(ALLOW_SECURE_TO_INSECURE) || !defined(ALLOW_INSECURE_TO_SECURE)
3423         isc_boolean_t had_dnskey;
3424 #endif
3425
3426         INSIST(event->ev_type == DNS_EVENT_UPDATE);
3427
3428         dns_diff_init(mctx, &diff);
3429         dns_diff_init(mctx, &temp);
3430
3431         CHECK(dns_zone_getdb(zone, &db));
3432         zonename = dns_db_origin(db);
3433         zoneclass = dns_db_class(db);
3434         dns_zone_getssutable(zone, &ssutable);
3435         dns_db_currentversion(db, &oldver);
3436         CHECK(dns_db_newversion(db, &ver));
3437
3438         /*
3439          * Check prerequisites.
3440          */
3441
3442         for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE);
3443              result == ISC_R_SUCCESS;
3444              result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE))
3445         {
3446                 dns_name_t *name = NULL;
3447                 dns_rdata_t rdata = DNS_RDATA_INIT;
3448                 dns_ttl_t ttl;
3449                 dns_rdataclass_t update_class;
3450                 isc_boolean_t flag;
3451
3452                 get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
3453                                &name, &rdata, &covers, &ttl, &update_class);
3454
3455                 if (ttl != 0)
3456                         PREREQFAILC(DNS_R_FORMERR,
3457                                     "prerequisite TTL is not zero");
3458
3459                 if (! dns_name_issubdomain(name, zonename))
3460                         PREREQFAILN(DNS_R_NOTZONE, name,
3461                                     "prerequisite name is out of zone");
3462
3463                 if (update_class == dns_rdataclass_any) {
3464                         if (rdata.length != 0)
3465                                 PREREQFAILC(DNS_R_FORMERR,
3466                                       "class ANY prerequisite "
3467                                       "RDATA is not empty");
3468                         if (rdata.type == dns_rdatatype_any) {
3469                                 CHECK(name_exists(db, ver, name, &flag));
3470                                 if (! flag) {
3471                                         PREREQFAILN(DNS_R_NXDOMAIN, name,
3472                                                     "'name in use' "
3473                                                     "prerequisite not "
3474                                                     "satisfied");
3475                                 }
3476                         } else {
3477                                 CHECK(rrset_exists(db, ver, name,
3478                                                    rdata.type, covers, &flag));
3479                                 if (! flag) {
3480                                         /* RRset does not exist. */
3481                                         PREREQFAILNT(DNS_R_NXRRSET, name, rdata.type,
3482                                         "'rrset exists (value independent)' "
3483                                         "prerequisite not satisfied");
3484                                 }
3485                         }
3486                 } else if (update_class == dns_rdataclass_none) {
3487                         if (rdata.length != 0)
3488                                 PREREQFAILC(DNS_R_FORMERR,
3489                                             "class NONE prerequisite "
3490                                             "RDATA is not empty");
3491                         if (rdata.type == dns_rdatatype_any) {
3492                                 CHECK(name_exists(db, ver, name, &flag));
3493                                 if (flag) {
3494                                         PREREQFAILN(DNS_R_YXDOMAIN, name,
3495                                                     "'name not in use' "
3496                                                     "prerequisite not "
3497                                                     "satisfied");
3498                                 }
3499                         } else {
3500                                 CHECK(rrset_exists(db, ver, name,
3501                                                    rdata.type, covers, &flag));
3502                                 if (flag) {
3503                                         /* RRset exists. */
3504                                         PREREQFAILNT(DNS_R_YXRRSET, name,
3505                                                      rdata.type,
3506                                                      "'rrset does not exist' "
3507                                                      "prerequisite not "
3508                                                      "satisfied");
3509                                 }
3510                         }
3511                 } else if (update_class == zoneclass) {
3512                         /* "temp<rr.name, rr.type> += rr;" */
3513                         result = temp_append(&temp, name, &rdata);
3514                         if (result != ISC_R_SUCCESS) {
3515                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
3516                                          "temp entry creation failed: %s",
3517                                                  dns_result_totext(result));
3518                                 FAIL(ISC_R_UNEXPECTED);
3519                         }
3520                 } else {
3521                         PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite");
3522                 }
3523         }
3524         if (result != ISC_R_NOMORE)
3525                 FAIL(result);
3526
3527
3528         /*
3529          * Perform the final check of the "rrset exists (value dependent)"
3530          * prerequisites.
3531          */
3532         if (ISC_LIST_HEAD(temp.tuples) != NULL) {
3533                 dns_rdatatype_t type;
3534
3535                 /*
3536                  * Sort the prerequisite records by owner name,
3537                  * type, and rdata.
3538                  */
3539                 result = dns_diff_sort(&temp, temp_order);
3540                 if (result != ISC_R_SUCCESS)
3541                         FAILC(result, "'RRset exists (value dependent)' "
3542                               "prerequisite not satisfied");
3543
3544                 dns_fixedname_init(&tmpnamefixed);
3545                 tmpname = dns_fixedname_name(&tmpnamefixed);
3546                 result = temp_check(mctx, &temp, db, ver, tmpname, &type);
3547                 if (result != ISC_R_SUCCESS)
3548                         FAILNT(result, tmpname, type,
3549                                "'RRset exists (value dependent)' "
3550                                "prerequisite not satisfied");
3551         }
3552
3553         update_log(client, zone, LOGLEVEL_DEBUG,
3554                    "prerequisites are OK");
3555
3556         /*
3557          * Check Requestor's Permissions.  It seems a bit silly to do this
3558          * only after prerequisite testing, but that is what RFC2136 says.
3559          */
3560         result = ISC_R_SUCCESS;
3561         if (ssutable == NULL)
3562                 CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
3563                                      "update", zonename, ISC_FALSE, ISC_FALSE));
3564         else if (client->signer == NULL && !TCPCLIENT(client))
3565                 CHECK(checkupdateacl(client, NULL, "update", zonename,
3566                                      ISC_FALSE, ISC_TRUE));
3567
3568         if (dns_zone_getupdatedisabled(zone))
3569                 FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled "
3570                                      "because the zone is frozen.  Use "
3571                                      "'rndc thaw' to re-enable updates.");
3572
3573         /*
3574          * Perform the Update Section Prescan.
3575          */
3576
3577         for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
3578              result == ISC_R_SUCCESS;
3579              result = dns_message_nextname(request, DNS_SECTION_UPDATE))
3580         {
3581                 dns_name_t *name = NULL;
3582                 dns_rdata_t rdata = DNS_RDATA_INIT;
3583                 dns_ttl_t ttl;
3584                 dns_rdataclass_t update_class;
3585                 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
3586                                &name, &rdata, &covers, &ttl, &update_class);
3587
3588                 if (! dns_name_issubdomain(name, zonename))
3589                         FAILC(DNS_R_NOTZONE,
3590                               "update RR is outside zone");
3591                 if (update_class == zoneclass) {
3592                         /*
3593                          * Check for meta-RRs.  The RFC2136 pseudocode says
3594                          * check for ANY|AXFR|MAILA|MAILB, but the text adds
3595                          * "or any other QUERY metatype"
3596                          */
3597                         if (dns_rdatatype_ismeta(rdata.type)) {
3598                                 FAILC(DNS_R_FORMERR,
3599                                       "meta-RR in update");
3600                         }
3601                         result = dns_zone_checknames(zone, name, &rdata);
3602                         if (result != ISC_R_SUCCESS)
3603                                 FAIL(DNS_R_REFUSED);
3604                 } else if (update_class == dns_rdataclass_any) {
3605                         if (ttl != 0 || rdata.length != 0 ||
3606                             (dns_rdatatype_ismeta(rdata.type) &&
3607                              rdata.type != dns_rdatatype_any))
3608                                 FAILC(DNS_R_FORMERR,
3609                                       "meta-RR in update");
3610                 } else if (update_class == dns_rdataclass_none) {
3611                         if (ttl != 0 ||
3612                             dns_rdatatype_ismeta(rdata.type))
3613                                 FAILC(DNS_R_FORMERR,
3614                                       "meta-RR in update");
3615                 } else {
3616                         update_log(client, zone, ISC_LOG_WARNING,
3617                                    "update RR has incorrect class %d",
3618                                    update_class);
3619                         FAIL(DNS_R_FORMERR);
3620                 }
3621                 /*
3622                  * draft-ietf-dnsind-simple-secure-update-01 says
3623                  * "Unlike traditional dynamic update, the client
3624                  * is forbidden from updating NSEC records."
3625                  */
3626                 if (dns_db_issecure(db)) {
3627                         if (rdata.type == dns_rdatatype_nsec3) {
3628                                 FAILC(DNS_R_REFUSED,
3629                                       "explicit NSEC3 updates are not allowed "
3630                                       "in secure zones");
3631                         } else if (rdata.type == dns_rdatatype_nsec) {
3632                                 FAILC(DNS_R_REFUSED,
3633                                       "explicit NSEC updates are not allowed "
3634                                       "in secure zones");
3635                         } else if (rdata.type == dns_rdatatype_rrsig &&
3636                                    !dns_name_equal(name, zonename)) {
3637                                 FAILC(DNS_R_REFUSED,
3638                                       "explicit RRSIG updates are currently "
3639                                       "not supported in secure zones except "
3640                                       "at the apex");
3641                         }
3642                 }
3643
3644                 if (ssutable != NULL) {
3645                         isc_netaddr_t *tcpaddr, netaddr;
3646                         /*
3647                          * If this is a TCP connection then pass the
3648                          * address of the client through for tcp-self
3649                          * and 6to4-self otherwise pass NULL.  This
3650                          * provides weak address based authentication.
3651                          */
3652                         if (TCPCLIENT(client)) {
3653                                 isc_netaddr_fromsockaddr(&netaddr,
3654                                                          &client->peeraddr);
3655                                 tcpaddr = &netaddr;
3656                         } else
3657                                 tcpaddr = NULL;
3658                         if (rdata.type != dns_rdatatype_any) {
3659                                 if (!dns_ssutable_checkrules(ssutable,
3660                                                              client->signer,
3661                                                              name, tcpaddr,
3662                                                              rdata.type))
3663                                         FAILC(DNS_R_REFUSED,
3664                                               "rejected by secure update");
3665                         } else {
3666                                 if (!ssu_checkall(db, ver, name, ssutable,
3667                                                   client->signer, tcpaddr))
3668                                         FAILC(DNS_R_REFUSED,
3669                                               "rejected by secure update");
3670                         }
3671                 }
3672         }
3673         if (result != ISC_R_NOMORE)
3674                 FAIL(result);
3675
3676         update_log(client, zone, LOGLEVEL_DEBUG,
3677                    "update section prescan OK");
3678
3679         /*
3680          * Process the Update Section.
3681          */
3682
3683         options = dns_zone_getoptions(zone);
3684         for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
3685              result == ISC_R_SUCCESS;
3686              result = dns_message_nextname(request, DNS_SECTION_UPDATE))
3687         {
3688                 dns_name_t *name = NULL;
3689                 dns_rdata_t rdata = DNS_RDATA_INIT;
3690                 dns_ttl_t ttl;
3691                 dns_rdataclass_t update_class;
3692                 isc_boolean_t flag;
3693
3694                 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
3695                                &name, &rdata, &covers, &ttl, &update_class);
3696
3697                 if (update_class == zoneclass) {
3698
3699                         /*
3700                          * RFC1123 doesn't allow MF and MD in master zones.                              */
3701                         if (rdata.type == dns_rdatatype_md ||
3702                             rdata.type == dns_rdatatype_mf) {
3703                                 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3704
3705                                 dns_rdatatype_format(rdata.type, typebuf,
3706                                                      sizeof(typebuf));
3707                                 update_log(client, zone, LOGLEVEL_PROTOCOL,
3708                                            "attempt to add %s ignored",
3709                                            typebuf);
3710                                 continue;
3711                         }
3712                         if ((rdata.type == dns_rdatatype_ns ||
3713                              rdata.type == dns_rdatatype_dname) &&
3714                             dns_name_iswildcard(name)) {
3715                                 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3716
3717                                 dns_rdatatype_format(rdata.type, typebuf,
3718                                                      sizeof(typebuf));
3719                                 update_log(client, zone,
3720                                            LOGLEVEL_PROTOCOL,
3721                                            "attempt to add wildcard %s record "
3722                                            "ignored", typebuf);
3723                                 continue;
3724                         }
3725                         if (rdata.type == dns_rdatatype_cname) {
3726                                 CHECK(cname_incompatible_rrset_exists(db, ver,
3727                                                                       name,
3728                                                                       &flag));
3729                                 if (flag) {
3730                                         update_log(client, zone,
3731                                                    LOGLEVEL_PROTOCOL,
3732                                                    "attempt to add CNAME "
3733                                                    "alongside non-CNAME "
3734                                                    "ignored");
3735                                         continue;
3736                                 }
3737                         } else {
3738                                 CHECK(rrset_exists(db, ver, name,
3739                                                    dns_rdatatype_cname, 0,
3740                                                    &flag));
3741                                 if (flag &&
3742                                     ! dns_rdatatype_isdnssec(rdata.type))
3743                                 {
3744                                         update_log(client, zone,
3745                                                    LOGLEVEL_PROTOCOL,
3746                                                    "attempt to add non-CNAME "
3747                                                    "alongside CNAME ignored");
3748                                         continue;
3749                                 }
3750                         }
3751                         if (rdata.type == dns_rdatatype_soa) {
3752                                 isc_boolean_t ok;
3753                                 CHECK(rrset_exists(db, ver, name,
3754                                                    dns_rdatatype_soa, 0,
3755                                                    &flag));
3756                                 if (! flag) {
3757                                         update_log(client, zone,
3758                                                    LOGLEVEL_PROTOCOL,
3759                                                    "attempt to create 2nd "
3760                                                    "SOA ignored");
3761                                         continue;
3762                                 }
3763                                 CHECK(check_soa_increment(db, ver, &rdata,
3764                                                           &ok));
3765                                 if (! ok) {
3766                                         update_log(client, zone,
3767                                                    LOGLEVEL_PROTOCOL,
3768                                                    "SOA update failed to "
3769                                                    "increment serial, "
3770                                                    "ignoring it");
3771                                         continue;
3772                                 }
3773                                 soa_serial_changed = ISC_TRUE;
3774                         }
3775
3776 #ifdef ALLOW_NSEC3PARAM_UPDATE
3777                         if (rdata.type == dns_rdatatype_nsec3param) {
3778                                 /*
3779                                  * Ignore attempts to add NSEC3PARAM records
3780                                  * with any flags other than OPTOUT.
3781                                  */
3782                                 if ((rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
3783                                         update_log(client, zone,
3784                                                    LOGLEVEL_PROTOCOL,
3785                                                    "attempt to add NSEC3PARAM "
3786                                                    "record with non OPTOUT "
3787                                                    "flag");
3788                                         continue;
3789                                 }
3790
3791                                 /*
3792                                  * Set the NSEC3CHAIN creation flag.
3793                                  */
3794                                 INSIST(rdata.length <= sizeof(buf));
3795                                 memcpy(buf, rdata.data, rdata.length);
3796                                 buf[1] |= DNS_NSEC3FLAG_UPDATE;
3797                                 rdata.data = buf;
3798                                 /*
3799                                  * Force the TTL to zero for NSEC3PARAM records.
3800                                  */
3801                                 ttl = 0;
3802                         }
3803 #else
3804                         if (rdata.type == dns_rdatatype_nsec3param) {
3805                                 update_log(client, zone, LOGLEVEL_PROTOCOL,
3806                                            "attempt to add NSEC3PARAM "
3807                                            "record ignored");
3808                                 continue;
3809                         };
3810 #endif
3811
3812                         if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
3813                             dns_name_internalwildcard(name)) {
3814                                 char namestr[DNS_NAME_FORMATSIZE];
3815                                 dns_name_format(name, namestr,
3816                                                 sizeof(namestr));
3817                                 update_log(client, zone, LOGLEVEL_PROTOCOL,
3818                                            "warning: ownername '%s' contains "
3819                                            "a non-terminal wildcard", namestr);
3820                         }
3821
3822                         if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {
3823                                 char namestr[DNS_NAME_FORMATSIZE];
3824                                 char typestr[DNS_RDATATYPE_FORMATSIZE];
3825                                 dns_name_format(name, namestr,
3826                                                 sizeof(namestr));
3827                                 dns_rdatatype_format(rdata.type, typestr,
3828                                                      sizeof(typestr));
3829                                 update_log(client, zone, LOGLEVEL_PROTOCOL,
3830                                            "adding an RR at '%s' %s",
3831                                            namestr, typestr);
3832                         }
3833
3834                         /* Prepare the affected RRset for the addition. */
3835                         {
3836                                 add_rr_prepare_ctx_t ctx;
3837                                 ctx.db = db;
3838                                 ctx.ver = ver;
3839                                 ctx.diff = &diff;
3840                                 ctx.name = name;
3841                                 ctx.update_rr = &rdata;
3842                                 ctx.update_rr_ttl = ttl;
3843                                 ctx.ignore_add = ISC_FALSE;
3844                                 dns_diff_init(mctx, &ctx.del_diff);
3845                                 dns_diff_init(mctx, &ctx.add_diff);
3846                                 CHECK(foreach_rr(db, ver, name, rdata.type,
3847                                                  covers, add_rr_prepare_action,
3848                                                  &ctx));
3849
3850                                 if (ctx.ignore_add) {
3851                                         dns_diff_clear(&ctx.del_diff);
3852                                         dns_diff_clear(&ctx.add_diff);
3853                                 } else {
3854                                         CHECK(do_diff(&ctx.del_diff, db, ver,
3855                                                       &diff));
3856                                         CHECK(do_diff(&ctx.add_diff, db, ver,
3857                                                       &diff));
3858                                         CHECK(update_one_rr(db, ver, &diff,
3859                                                             DNS_DIFFOP_ADD,
3860                                                             name, ttl, &rdata));
3861                                 }
3862                         }
3863                 } else if (update_class == dns_rdataclass_any) {
3864                         if (rdata.type == dns_rdatatype_any) {
3865                                 if (isc_log_wouldlog(ns_g_lctx,
3866                                                      LOGLEVEL_PROTOCOL))
3867                                 {
3868                                         char namestr[DNS_NAME_FORMATSIZE];
3869                                         dns_name_format(name, namestr,
3870                                                         sizeof(namestr));
3871                                         update_log(client, zone,
3872                                                    LOGLEVEL_PROTOCOL,
3873                                                    "delete all rrsets from "
3874                                                    "name '%s'", namestr);
3875                                 }
3876                                 if (dns_name_equal(name, zonename)) {
3877                                         CHECK(delete_if(type_not_soa_nor_ns_p,
3878                                                         db, ver, name,
3879                                                         dns_rdatatype_any, 0,
3880                                                         &rdata, &diff));
3881                                 } else {
3882                                         CHECK(delete_if(type_not_dnssec,
3883                                                         db, ver, name,
3884                                                         dns_rdatatype_any, 0,
3885                                                         &rdata, &diff));
3886                                 }
3887 #ifndef ALLOW_NSEC3PARAM_UPDATE
3888                         } else if (rdata.type == dns_rdatatype_nsec3param) {
3889                                 update_log(client, zone, LOGLEVEL_PROTOCOL,
3890                                            "attempt to delete a NSEC3PARAM "
3891                                            "records ignored");
3892                                 continue;
3893 #endif
3894                         } else if (dns_name_equal(name, zonename) &&
3895                                    (rdata.type == dns_rdatatype_soa ||
3896                                     rdata.type == dns_rdatatype_ns)) {
3897                                 update_log(client, zone, LOGLEVEL_PROTOCOL,
3898                                            "attempt to delete all SOA "
3899                                            "or NS records ignored");
3900                                 continue;
3901                         } else {
3902                                 if (isc_log_wouldlog(ns_g_lctx,
3903                                                      LOGLEVEL_PROTOCOL))
3904                                 {
3905                                         char namestr[DNS_NAME_FORMATSIZE];
3906                                         char typestr[DNS_RDATATYPE_FORMATSIZE];
3907                                         dns_name_format(name, namestr,
3908                                                         sizeof(namestr));
3909                                         dns_rdatatype_format(rdata.type,
3910                                                              typestr,
3911                                                              sizeof(typestr));
3912                                         update_log(client, zone,
3913                                                    LOGLEVEL_PROTOCOL,
3914                                                    "deleting rrset at '%s' %s",
3915                                                    namestr, typestr);
3916                                 }
3917                                 CHECK(delete_if(true_p, db, ver, name,
3918                                                 rdata.type, covers, &rdata,
3919                                                 &diff));
3920                         }
3921                 } else if (update_class == dns_rdataclass_none) {
3922                         /*
3923                          * The (name == zonename) condition appears in
3924                          * RFC2136 3.4.2.4 but is missing from the pseudocode.
3925                          */
3926                         if (dns_name_equal(name, zonename)) {
3927                                 if (rdata.type == dns_rdatatype_soa) {
3928                                         update_log(client, zone,
3929                                                    LOGLEVEL_PROTOCOL,
3930                                                    "attempt to delete SOA "
3931                                                    "ignored");
3932                                         continue;
3933                                 }
3934                                 if (rdata.type == dns_rdatatype_ns) {
3935                                         int count;
3936                                         CHECK(rr_count(db, ver, name,
3937                                                        dns_rdatatype_ns,
3938                                                        0, &count));
3939                                         if (count == 1) {
3940                                                 update_log(client, zone,
3941                                                            LOGLEVEL_PROTOCOL,
3942                                                            "attempt to "
3943                                                            "delete last "
3944                                                            "NS ignored");
3945                                                 continue;
3946                                         }
3947                                 }
3948                         }
3949                         update_log(client, zone,
3950                                    LOGLEVEL_PROTOCOL,
3951                                    "deleting an RR");
3952                         CHECK(delete_if(rr_equal_p, db, ver, name,
3953                                         rdata.type, covers, &rdata, &diff));
3954                 }
3955         }
3956         if (result != ISC_R_NOMORE)
3957                 FAIL(result);
3958
3959         /*
3960          * Check that any changes to DNSKEY/NSEC3PARAM records make sense.
3961          * If they don't then back out all changes to DNSKEY/NSEC3PARAM
3962          * records.
3963          */
3964         if (! ISC_LIST_EMPTY(diff.tuples))
3965                 CHECK(check_dnssec(client, zone, db, ver, &diff));
3966
3967         /*
3968          * If any changes were made, increment the SOA serial number,
3969          * update RRSIGs and NSECs (if zone is secure), and write the update
3970          * to the journal.
3971          */
3972         if (! ISC_LIST_EMPTY(diff.tuples)) {
3973                 char *journalfile;
3974                 dns_journal_t *journal;
3975                 isc_boolean_t has_dnskey;
3976
3977                 /*
3978                  * Increment the SOA serial, but only if it was not
3979                  * changed as a result of an update operation.
3980                  */
3981                 if (! soa_serial_changed) {
3982                         CHECK(increment_soa_serial(db, ver, &diff, mctx));
3983                 }
3984
3985                 CHECK(check_mx(client, zone, db, ver, &diff));
3986
3987                 CHECK(remove_orphaned_ds(db, ver, &diff));
3988
3989                 CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
3990                                    0, &has_dnskey));
3991
3992 #if !defined(ALLOW_SECURE_TO_INSECURE) || !defined(ALLOW_INSECURE_TO_SECURE)
3993                 CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey,
3994                                    0, &had_dnskey));
3995
3996 #ifndef ALLOW_SECURE_TO_INSECURE
3997                 if (had_dnskey && !has_dnskey) {
3998                         update_log(client, zone, LOGLEVEL_PROTOCOL,
3999                                    "update rejected: all DNSKEY records "
4000                                    "removed");
4001                         result = DNS_R_REFUSED;
4002                         goto failure;
4003                 }
4004 #endif
4005 #ifndef ALLOW_INSECURE_TO_SECURE
4006                 if (!had_dnskey && has_dnskey) {
4007                         update_log(client, zone, LOGLEVEL_PROTOCOL,
4008                                    "update rejected: DNSKEY record added");
4009                         result = DNS_R_REFUSED;
4010                         goto failure;
4011                 }
4012 #endif
4013 #endif
4014
4015                 CHECK(add_signing_records(db, zonename, ver,
4016                                           dns_zone_getprivatetype(zone),
4017                                           &diff));
4018
4019 #ifdef ALLOW_NSEC3PARAM_UPDATE
4020                 CHECK(add_nsec3param_records(client, zone, db, zonename,
4021                                              ver, &diff));
4022 #endif
4023
4024                 if (!has_dnskey) {
4025                         /*
4026                          * We are transitioning from secure to insecure.
4027                          * Cause all NSEC3 chains to be deleted.  When the
4028                          * the last signature for the DNSKEY records are
4029                          * remove any NSEC chain present will also be removed.
4030                          */
4031 #ifdef ALLOW_NSEC3PARAM_UPDATE
4032                          CHECK(delete_chains(db, ver, zonename, &diff));
4033 #endif
4034                 } else if (has_dnskey && dns_db_isdnssec(db)) {
4035                         isc_uint32_t interval;
4036                         interval = dns_zone_getsigvalidityinterval(zone);
4037                         result = update_signatures(client, zone, db, oldver,
4038                                                    ver, &diff, interval,
4039                                                    &deleted_zsk);
4040                         if (result != ISC_R_SUCCESS) {
4041                                 update_log(client, zone,
4042                                            ISC_LOG_ERROR,
4043                                            "RRSIG/NSEC/NSEC3 update failed: %s",
4044                                            isc_result_totext(result));
4045                                 goto failure;
4046                         }
4047                 }
4048
4049                 journalfile = dns_zone_getjournal(zone);
4050                 if (journalfile != NULL) {
4051                         update_log(client, zone, LOGLEVEL_DEBUG,
4052                                    "writing journal %s", journalfile);
4053
4054                         journal = NULL;
4055                         result = dns_journal_open(mctx, journalfile,
4056                                                   ISC_TRUE, &journal);
4057                         if (result != ISC_R_SUCCESS)
4058                                 FAILS(result, "journal open failed");
4059
4060                         result = dns_journal_write_transaction(journal, &diff);
4061                         if (result != ISC_R_SUCCESS) {
4062                                 dns_journal_destroy(&journal);
4063                                 FAILS(result, "journal write failed");
4064                         }
4065
4066                         dns_journal_destroy(&journal);
4067                 }
4068
4069                 /*
4070                  * XXXRTH  Just a note that this committing code will have
4071                  *         to change to handle databases that need two-phase
4072                  *         commit, but this isn't a priority.
4073                  */
4074                 update_log(client, zone, LOGLEVEL_DEBUG,
4075                            "committing update transaction");
4076
4077                 dns_db_closeversion(db, &ver, ISC_TRUE);
4078
4079                 /*
4080                  * Mark the zone as dirty so that it will be written to disk.
4081                  */
4082                 dns_zone_markdirty(zone);
4083
4084                 /*
4085                  * Notify slaves of the change we just made.
4086                  */
4087                 dns_zone_notify(zone);
4088
4089                 /*
4090                  * Cause the zone to be signed with the key that we
4091                  * have just added or have the corresponding signatures
4092                  * deleted.
4093                  *
4094                  * Note: we are already committed to this course of action.
4095                  */
4096                 for (tuple = ISC_LIST_HEAD(diff.tuples);
4097                      tuple != NULL;
4098                      tuple = ISC_LIST_NEXT(tuple, link)) {
4099                         isc_region_t r;
4100                         dns_secalg_t algorithm;
4101                         isc_uint16_t keyid;
4102
4103                         if (tuple->rdata.type != dns_rdatatype_dnskey)
4104                                 continue;
4105
4106                         dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
4107                         if ((dnskey.flags &
4108                              (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
4109                                  != DNS_KEYOWNER_ZONE)
4110                                 continue;
4111
4112                         dns_rdata_toregion(&tuple->rdata, &r);
4113                         algorithm = dnskey.algorithm;
4114                         keyid = dst_region_computeid(&r, algorithm);
4115
4116                         result = dns_zone_signwithkey(zone, algorithm, keyid,
4117                                         ISC_TF(tuple->op == DNS_DIFFOP_DEL));
4118                         if (result != ISC_R_SUCCESS) {
4119                                 update_log(client, zone, ISC_LOG_ERROR,
4120                                            "dns_zone_signwithkey failed: %s",
4121                                            dns_result_totext(result));
4122                         }
4123                 }
4124
4125 #ifdef ALLOW_NSEC3PARAM_UPDATE
4126                 /*
4127                  * Cause the zone to add/delete NSEC3 chains for the
4128                  * deferred NSEC3PARAM changes.
4129                  *
4130                  * Note: we are already committed to this course of action.
4131                  */
4132                 for (tuple = ISC_LIST_HEAD(diff.tuples);
4133                      tuple != NULL;
4134                      tuple = ISC_LIST_NEXT(tuple, link)) {
4135                         dns_rdata_nsec3param_t nsec3param;
4136
4137                         if (tuple->rdata.type != dns_rdatatype_nsec3param ||
4138                             tuple->op != DNS_DIFFOP_ADD)
4139                                 continue;
4140
4141                         dns_rdata_tostruct(&tuple->rdata, &nsec3param, NULL);
4142                         if (nsec3param.flags == 0)
4143                                 continue;
4144
4145                         result = dns_zone_addnsec3chain(zone, &nsec3param);
4146                         if (result != ISC_R_SUCCESS) {
4147                                 update_log(client, zone, ISC_LOG_ERROR,
4148                                            "dns_zone_addnsec3chain failed: %s",
4149                                            dns_result_totext(result));
4150                         }
4151                 }
4152 #endif
4153         } else {
4154                 update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
4155                 dns_db_closeversion(db, &ver, ISC_TRUE);
4156         }
4157         result = ISC_R_SUCCESS;
4158         goto common;
4159
4160  failure:
4161         /*
4162          * The reason for failure should have been logged at this point.
4163          */
4164         if (ver != NULL) {
4165                 update_log(client, zone, LOGLEVEL_DEBUG,
4166                            "rolling back");
4167                 dns_db_closeversion(db, &ver, ISC_FALSE);
4168         }
4169
4170  common:
4171         dns_diff_clear(&temp);
4172         dns_diff_clear(&diff);
4173
4174         if (oldver != NULL)
4175                 dns_db_closeversion(db, &oldver, ISC_FALSE);
4176
4177         if (db != NULL)
4178                 dns_db_detach(&db);
4179
4180         if (ssutable != NULL)
4181                 dns_ssutable_detach(&ssutable);
4182
4183         isc_task_detach(&task);
4184         uev->result = result;
4185         if (zone != NULL)
4186                 INSIST(uev->zone == zone); /* we use this later */
4187         uev->ev_type = DNS_EVENT_UPDATEDONE;
4188         uev->ev_action = updatedone_action;
4189         isc_task_send(client->task, &event);
4190         INSIST(event == NULL);
4191 }
4192
4193 static void
4194 updatedone_action(isc_task_t *task, isc_event_t *event) {
4195         update_event_t *uev = (update_event_t *) event;
4196         ns_client_t *client = (ns_client_t *) event->ev_arg;
4197
4198         UNUSED(task);
4199
4200         INSIST(event->ev_type == DNS_EVENT_UPDATEDONE);
4201         INSIST(task == client->task);
4202
4203         INSIST(client->nupdates > 0);
4204         switch (uev->result) {
4205         case ISC_R_SUCCESS:
4206                 inc_stats(uev->zone, dns_nsstatscounter_updatedone);
4207                 break;
4208         case DNS_R_REFUSED:
4209                 inc_stats(uev->zone, dns_nsstatscounter_updaterej);
4210                 break;
4211         default:
4212                 inc_stats(uev->zone, dns_nsstatscounter_updatefail);
4213                 break;
4214         }
4215         if (uev->zone != NULL)
4216                 dns_zone_detach(&uev->zone);
4217         client->nupdates--;
4218         respond(client, uev->result);
4219         isc_event_free(&event);
4220         ns_client_detach(&client);
4221 }
4222
4223 /*%
4224  * Update forwarding support.
4225  */
4226
4227 static void
4228 forward_fail(isc_task_t *task, isc_event_t *event) {
4229         ns_client_t *client = (ns_client_t *)event->ev_arg;
4230
4231         UNUSED(task);
4232
4233         INSIST(client->nupdates > 0);
4234         client->nupdates--;
4235         respond(client, DNS_R_SERVFAIL);
4236         isc_event_free(&event);
4237         ns_client_detach(&client);
4238 }
4239
4240
4241 static void
4242 forward_callback(void *arg, isc_result_t result, dns_message_t *answer) {
4243         update_event_t *uev = arg;
4244         ns_client_t *client = uev->ev_arg;
4245         dns_zone_t *zone = uev->zone;
4246
4247         if (result != ISC_R_SUCCESS) {
4248                 INSIST(answer == NULL);
4249                 uev->ev_type = DNS_EVENT_UPDATEDONE;
4250                 uev->ev_action = forward_fail;
4251                 inc_stats(zone, dns_nsstatscounter_updatefwdfail);
4252         } else {
4253                 uev->ev_type = DNS_EVENT_UPDATEDONE;
4254                 uev->ev_action = forward_done;
4255                 uev->answer = answer;
4256                 inc_stats(zone, dns_nsstatscounter_updaterespfwd);
4257         }
4258         isc_task_send(client->task, ISC_EVENT_PTR(&uev));
4259         dns_zone_detach(&zone);
4260 }
4261
4262 static void
4263 forward_done(isc_task_t *task, isc_event_t *event) {
4264         update_event_t *uev = (update_event_t *) event;
4265         ns_client_t *client = (ns_client_t *)event->ev_arg;
4266
4267         UNUSED(task);
4268
4269         INSIST(client->nupdates > 0);
4270         client->nupdates--;
4271         ns_client_sendraw(client, uev->answer);
4272         dns_message_destroy(&uev->answer);
4273         isc_event_free(&event);
4274         ns_client_detach(&client);
4275 }
4276
4277 static void
4278 forward_action(isc_task_t *task, isc_event_t *event) {
4279         update_event_t *uev = (update_event_t *) event;
4280         dns_zone_t *zone = uev->zone;
4281         ns_client_t *client = (ns_client_t *)event->ev_arg;
4282         isc_result_t result;
4283
4284         result = dns_zone_forwardupdate(zone, client->message,
4285                                         forward_callback, event);
4286         if (result != ISC_R_SUCCESS) {
4287                 uev->ev_type = DNS_EVENT_UPDATEDONE;
4288                 uev->ev_action = forward_fail;
4289                 isc_task_send(client->task, &event);
4290                 inc_stats(zone, dns_nsstatscounter_updatefwdfail);
4291                 dns_zone_detach(&zone);
4292         } else
4293                 inc_stats(zone, dns_nsstatscounter_updatereqfwd);
4294         isc_task_detach(&task);
4295 }
4296
4297 static isc_result_t
4298 send_forward_event(ns_client_t *client, dns_zone_t *zone) {
4299         isc_result_t result = ISC_R_SUCCESS;
4300         update_event_t *event = NULL;
4301         isc_task_t *zonetask = NULL;
4302         ns_client_t *evclient;
4303
4304         event = (update_event_t *)
4305                 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
4306                                    forward_action, NULL, sizeof(*event));
4307         if (event == NULL)
4308                 FAIL(ISC_R_NOMEMORY);
4309         event->zone = zone;
4310         event->result = ISC_R_SUCCESS;
4311
4312         evclient = NULL;
4313         ns_client_attach(client, &evclient);
4314         INSIST(client->nupdates == 0);
4315         client->nupdates++;
4316         event->ev_arg = evclient;
4317
4318         dns_zone_gettask(zone, &zonetask);
4319         isc_task_send(zonetask, ISC_EVENT_PTR(&event));
4320
4321  failure:
4322         if (event != NULL)
4323                 isc_event_free(ISC_EVENT_PTR(&event));
4324         return (result);
4325 }