1 /*
2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /**
28  * Zone.
29  *
30  */
31 
32 #include "adapter/adapter.h"
33 #include "file.h"
34 #include "hsm.h"
35 #include "locks.h"
36 #include "log.h"
37 #include "status.h"
38 #include "util.h"
39 #include "signer/backup.h"
40 #include "signer/zone.h"
41 #include "wire/netio.h"
42 #include "compat.h"
43 #include "daemon/signertasks.h"
44 
45 #include <ldns/ldns.h>
46 
47 static const char* zone_str = "zone";
48 
49 
50 /**
51  * Create a new zone.
52  *
53  */
54 zone_type*
zone_create(char * name,ldns_rr_class klass)55 zone_create(char* name, ldns_rr_class klass)
56 {
57     zone_type* zone = NULL;
58     int err;
59 
60     if (!name || !klass) {
61         return NULL;
62     }
63     CHECKALLOC(zone = (zone_type*) calloc(1, sizeof(zone_type)));
64     /* [start] PS 9218653: Drop trailing dot in domain name */
65     if (strlen(name) > 1 && name[strlen(name)-1] == '.') {
66         name[strlen(name)-1] = '\0';
67     }
68     /* [end] PS 9218653 */
69 
70     if (pthread_mutex_init(&zone->zone_lock, NULL)) {
71         free(zone);
72         return NULL;
73     }
74     if (pthread_mutex_init(&zone->xfr_lock, NULL)) {
75         (void)pthread_mutex_destroy(&zone->zone_lock);
76         free(zone);
77         return NULL;
78     }
79 
80     zone->name = strdup(name);
81     if (!zone->name) {
82         ods_log_error("[%s] unable to create zone %s: allocator_strdup() "
83             "failed", zone_str, name);
84         zone_cleanup(zone);
85         return NULL;
86     }
87     zone->klass = klass;
88     zone->default_ttl = 3600; /* TODO: configure --default-ttl option? */
89     zone->apex = ldns_dname_new_frm_str(name);
90     /* check zone->apex? */
91     zone->notify_command = NULL;
92     zone->notify_ns = NULL;
93     zone->notify_args = NULL;
94     zone->policy_name = NULL;
95     zone->signconf_filename = NULL;
96     zone->adinbound = NULL;
97     zone->adoutbound = NULL;
98     zone->zl_status = ZONE_ZL_OK;
99     zone->xfrd = NULL;
100     zone->notify = NULL;
101     zone->db = namedb_create((void*)zone);
102     if (!zone->db) {
103         ods_log_error("[%s] unable to create zone %s: namedb_create() "
104             "failed", zone_str, name);
105         zone_cleanup(zone);
106         return NULL;
107     }
108     zone->ixfr = ixfr_create();
109     if (!zone->ixfr) {
110         ods_log_error("[%s] unable to create zone %s: ixfr_create() "
111             "failed", zone_str, name);
112         zone_cleanup(zone);
113         return NULL;
114     }
115     zone->zoneconfigvalid = 0;
116     zone->signconf = signconf_create();
117     if (!zone->signconf) {
118         ods_log_error("[%s] unable to create zone %s: signconf_create() "
119             "failed", zone_str, name);
120         zone_cleanup(zone);
121         return NULL;
122     }
123     zone->stats = stats_create();
124     zone->rrstore = rrset_store_initialize();
125     return zone;
126 }
127 
128 /**
129  * Load signer configuration for zone.
130  *
131  */
132 ods_status
zone_load_signconf(zone_type * zone,signconf_type ** new_signconf)133 zone_load_signconf(zone_type* zone, signconf_type** new_signconf)
134 {
135     ods_status status = ODS_STATUS_OK;
136     signconf_type* signconf = NULL;
137     char* datestamp = NULL;
138 
139     if (!zone || !zone->name || !zone->signconf) {
140         return ODS_STATUS_ASSERT_ERR;
141     }
142     if (!zone->signconf_filename) {
143         ods_log_warning("[%s] zone %s has no signconf filename, treat as "
144             "insecure?", zone_str, zone->name);
145         return ODS_STATUS_INSECURE;
146     }
147     status = signconf_update(&signconf, zone->signconf_filename,
148         zone->signconf->last_modified);
149     if (status == ODS_STATUS_OK) {
150         if (!signconf) {
151             /* this is unexpected */
152             ods_log_alert("[%s] unable to load signconf for zone %s: signconf "
153                 "status ok but no signconf stored", zone_str, zone->name);
154             return ODS_STATUS_ASSERT_ERR;
155         }
156         (void)time_datestamp(signconf->last_modified, "%Y-%m-%d %T",
157             &datestamp);
158         ods_log_debug("[%s] zone %s signconf file %s is modified since %s",
159             zone_str, zone->name, zone->signconf_filename,
160             datestamp?datestamp:"Unknown");
161         free((void*)datestamp);
162         *new_signconf = signconf;
163     } else if (status == ODS_STATUS_UNCHANGED) {
164         /* OPENDNSSEC-686: changes happening within one second will not be
165          * seen
166          */
167         (void)time_datestamp(zone->signconf->last_modified,
168             "%Y-%m-%d %T", &datestamp);
169         ods_log_verbose("[%s] zone %s signconf file %s is unchanged since "
170             "%s", zone_str, zone->name, zone->signconf_filename,
171             datestamp?datestamp:"Unknown");
172         free((void*)datestamp);
173     } else {
174         ods_log_error("[%s] unable to load signconf for zone %s: signconf %s "
175             "%s", zone_str, zone->name, zone->signconf_filename,
176             ods_status2str(status));
177     }
178     return status;
179 }
180 
181 /**
182  * Publish the keys as indicated by the signer configuration.
183  *
184  */
185 ods_status
zone_publish_dnskeys(zone_type * zone,int skip_hsm_access)186 zone_publish_dnskeys(zone_type* zone, int skip_hsm_access)
187 {
188     hsm_ctx_t* ctx = NULL;
189     uint32_t ttl = 0;
190     unsigned int i;
191     ods_status status = ODS_STATUS_OK;
192     rrset_type* rrset = NULL;
193     rr_type* dnskey = NULL;
194 
195     if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
196         return ODS_STATUS_ASSERT_ERR;
197     }
198     ods_log_assert(zone->name);
199 
200     /* hsm access */
201     if (!skip_hsm_access) {
202         ctx = hsm_create_context();
203         if (ctx == NULL) {
204             ods_log_error("[%s] unable to publish keys for zone %s: "
205                 "error creating libhsm context", zone_str, zone->name);
206             return ODS_STATUS_HSM_ERR;
207         }
208     }
209     ttl = zone->default_ttl;
210     /* dnskey ttl */
211     if (zone->signconf->dnskey_ttl) {
212         ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
213     }
214     /* publish keys */
215     for (i=0; i < zone->signconf->keys->count; i++) {
216         if (!zone->signconf->keys->keys[i].publish) {
217             continue;
218         }
219         if (!zone->signconf->keys->keys[i].dnskey) {
220             /* get dnskey */
221             if  (zone->signconf->keys->keys[i].resourcerecord) {
222                 if ((status = rrset_getliteralrr(&zone->signconf->keys->keys[i].dnskey, zone->signconf->keys->keys[i].resourcerecord, ttl, zone->apex)) != ODS_STATUS_OK) {
223                     ods_log_error("[%s] unable to publish dnskeys for zone %s: "
224                             "error decoding literal dnskey", zone_str, zone->name);
225                     if (!skip_hsm_access) {
226                         hsm_destroy_context(ctx);
227                     }
228                     return status;
229                 }
230             } else {
231                 status = lhsm_get_key(ctx, zone->apex,
232                         &zone->signconf->keys->keys[i], skip_hsm_access);
233                 if (status != ODS_STATUS_OK) {
234                     ods_log_error("[%s] unable to publish dnskeys for zone %s: "
235                             "error creating dnskey", zone_str, zone->name);
236                     break;
237                 }
238             }
239         }
240         ods_log_debug("[%s] publish %s DNSKEY locator %s", zone_str,
241             zone->name, zone->signconf->keys->keys[i].locator);
242         if (!skip_hsm_access) {
243             ods_log_assert(zone->signconf->keys->keys[i].dnskey);
244             ldns_rr_set_ttl(zone->signconf->keys->keys[i].dnskey, ttl);
245             ldns_rr_set_class(zone->signconf->keys->keys[i].dnskey, zone->klass);
246             status = zone_add_rr(zone, zone->signconf->keys->keys[i].dnskey, 0);
247             if (status == ODS_STATUS_UNCHANGED) {
248                 /* rr already exists, adjust pointer */
249                 rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
250                 ods_log_assert(rrset);
251                 dnskey = rrset_lookup_rr(rrset,
252                     zone->signconf->keys->keys[i].dnskey);
253                 ods_log_assert(dnskey);
254                 if (dnskey->rr != zone->signconf->keys->keys[i].dnskey) {
255                     ldns_rr_free(zone->signconf->keys->keys[i].dnskey);
256                 }
257                 zone->signconf->keys->keys[i].dnskey = dnskey->rr;
258                 status = ODS_STATUS_OK;
259             } else if (status != ODS_STATUS_OK) {
260                 ods_log_error("[%s] unable to publish dnskeys for zone %s: "
261                     "error adding dnskey", zone_str, zone->name);
262                 break;
263             }
264         }
265     }
266     /* done */
267     if (!skip_hsm_access) {
268         hsm_destroy_context(ctx);
269     }
270     return status;
271 }
272 
273 
274 /**
275  * Unlink DNSKEY RRs.
276  *
277  */
278 void
zone_rollback_dnskeys(zone_type * zone)279 zone_rollback_dnskeys(zone_type* zone)
280 {
281     uint16_t i = 0;
282     rrset_type* rrset = NULL;
283     rr_type* dnskey = NULL;
284     if (!zone || !zone->signconf || !zone->signconf->keys) {
285         return;
286     }
287     rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
288     /* unlink dnskey rrs */
289     for (i=0; i < zone->signconf->keys->count; i++) {
290         if (rrset && zone->signconf->keys->keys[i].dnskey) {
291             dnskey = rrset_lookup_rr(rrset, zone->signconf->keys->keys[i].dnskey);
292             /* always remove the DNSKEY record when rollback is requested, as we don't know how to
293              * distinguish reading an empty file or reading a failed input set.
294              */
295             zone->signconf->keys->keys[i].dnskey = NULL;
296         }
297     }
298 }
299 
300 
301 /**
302  * Publish the NSEC3 parameters as indicated by the signer configuration.
303  *
304  */
305 ods_status
zone_publish_nsec3param(zone_type * zone)306 zone_publish_nsec3param(zone_type* zone)
307 {
308     rrset_type* rrset = NULL;
309     rr_type* n3prr = NULL;
310     ldns_rr* rr = NULL;
311     ods_status status = ODS_STATUS_OK;
312 
313     if (!zone || !zone->name || !zone->db || !zone->signconf) {
314         return ODS_STATUS_ASSERT_ERR;
315     }
316     if (!zone->signconf->nsec3params) {
317         /* NSEC */
318         ods_log_assert(zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC);
319         return ODS_STATUS_OK;
320     }
321 
322     if (!zone->signconf->nsec3params->rr) {
323         uint32_t paramttl =
324             (uint32_t) duration2time(zone->signconf->nsec3param_ttl);
325         rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
326         if (!rr) {
327             ods_log_error("[%s] unable to publish nsec3params for zone %s: "
328                 "error creating rr (%s)", zone_str, zone->name,
329                 ods_status2str(status));
330             return ODS_STATUS_MALLOC_ERR;
331         }
332         ldns_rr_set_class(rr, zone->klass);
333         ldns_rr_set_ttl(rr, paramttl);
334         ldns_rr_set_owner(rr, ldns_rdf_clone(zone->apex));
335         ldns_nsec3_add_param_rdfs(rr,
336             zone->signconf->nsec3params->algorithm, 0,
337             zone->signconf->nsec3params->iterations,
338             zone->signconf->nsec3params->salt_len,
339             zone->signconf->nsec3params->salt_data);
340         /**
341          * Always set bit 7 of the flags to zero,
342          * according to rfc5155 section 11
343          */
344         ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(rr, 1)), 7, 0);
345         zone->signconf->nsec3params->rr = rr;
346     }
347 
348     /* Delete all nsec3param rrs. */
349     (void) zone_del_nsec3params(zone);
350 
351     ods_log_assert(zone->signconf->nsec3params->rr);
352     status = zone_add_rr(zone, ldns_rr_clone(zone->signconf->nsec3params->rr), 0);
353     if (status == ODS_STATUS_UNCHANGED) {
354         status = ODS_STATUS_OK;
355     } else if (status != ODS_STATUS_OK) {
356         ods_log_error("[%s] unable to publish nsec3params for zone %s: "
357             "error adding nsec3params (%s)", zone_str,
358             zone->name, ods_status2str(status));
359     }
360     return status;
361 }
362 
363 
364 /**
365  * Unlink NSEC3PARAM RR.
366  *
367  */
368 void
zone_rollback_nsec3param(zone_type * zone)369 zone_rollback_nsec3param(zone_type* zone)
370 {
371     rrset_type* rrset = NULL;
372     rr_type* n3prr = NULL;
373 
374     if (!zone || !zone->signconf || !zone->signconf->nsec3params) {
375         return;
376     }
377     rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS);
378     if (rrset && zone->signconf->nsec3params->rr) {
379         n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr);
380         if (n3prr && !n3prr->exists &&
381             n3prr->rr == zone->signconf->nsec3params->rr) {
382             zone->signconf->nsec3params->rr = NULL;
383         }
384     }
385 }
386 
387 
388 /**
389  * Prepare keys for signing.
390  *
391  */
392 ods_status
zone_prepare_keys(zone_type * zone)393 zone_prepare_keys(zone_type* zone)
394 {
395     hsm_ctx_t* ctx = NULL;
396     int skip_hsm_access;
397     uint16_t i = 0;
398     ods_status status = ODS_STATUS_OK;
399 
400     if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
401         return ODS_STATUS_ASSERT_ERR;
402     }
403     ods_log_assert(zone->name);
404     /* hsm access */
405     ctx = hsm_create_context();
406     if (ctx == NULL) {
407         ods_log_error("[%s] unable to prepare signing keys for zone %s: error creating libhsm context", zone_str, zone->name);
408         return ODS_STATUS_HSM_ERR;
409     }
410     /* prepare keys */
411     for (i=0; i < zone->signconf->keys->count; i++) {
412         if(zone->signconf->dnskey_signature != NULL && zone->signconf->keys->keys[i].ksk)
413             continue;
414         /* get dnskey */
415         skip_hsm_access = (zone->signconf->keys->keys[i].publish || zone->signconf->keys->keys[i].zsk || zone->signconf->keys->keys[i].ksk ? 0 : 1);
416         status = lhsm_get_key(ctx, zone->apex, &zone->signconf->keys->keys[i], skip_hsm_access);
417         if (status != ODS_STATUS_OK) {
418             ods_log_error("[%s] unable to prepare signing keys for zone %s: error getting dnskey", zone_str, zone->name);
419             break;
420         }
421         ods_log_assert(zone->signconf->keys->keys[i].params);
422     }
423     /* done */
424     hsm_destroy_context(ctx);
425     return status;
426 }
427 
428 
429 /**
430  * Update serial.
431  *
432  */
433 ods_status
zone_update_serial(zone_type * zone)434 zone_update_serial(zone_type* zone)
435 {
436     ods_status status = ODS_STATUS_OK;
437     rrset_type* rrset = NULL;
438     rr_type* soa = NULL;
439     ldns_rr* rr = NULL;
440     ldns_rdf* soa_rdata = NULL;
441 
442     ods_log_assert(zone);
443     ods_log_assert(zone->apex);
444     ods_log_assert(zone->name);
445     ods_log_assert(zone->db);
446     ods_log_assert(zone->signconf);
447 
448     if (zone->db->serial_updated) {
449         /* already done, unmark and return ok */
450         ods_log_debug("[%s] zone %s soa serial already up to date",
451             zone_str, zone->name);
452         zone->db->serial_updated = 0;
453         return ODS_STATUS_OK;
454     }
455     rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
456     if (!rrset || !rrset->rrs || !rrset->rrs[0].rr) {
457         ods_log_error("[%s] unable to update zone %s soa serial: failed to "
458             "find soa rrset", zone_str, zone->name);
459         return ODS_STATUS_ERR;
460     }
461     ods_log_assert(rrset);
462     ods_log_assert(rrset->rrs);
463     ods_log_assert(rrset->rrs[0].rr);
464     rr = ldns_rr_clone(rrset->rrs[0].rr);
465     if (!rr) {
466         ods_log_error("[%s] unable to update zone %s soa serial: failed to "
467             "clone soa rr", zone_str, zone->name);
468         return ODS_STATUS_ERR;
469     }
470     status = namedb_update_serial(zone->db, zone->name,
471         zone->signconf->soa_serial, zone->db->inbserial);
472     if (status != ODS_STATUS_OK) {
473         ods_log_error("[%s] unable to update zone %s soa serial: %s",
474             zone_str, zone->name, ods_status2str(status));
475         if (status == ODS_STATUS_CONFLICT_ERR) {
476             ods_log_error("[%s] If this is the result of a key rollover, "
477                 "please increment the serial in the unsigned zone %s",
478                 zone_str, zone->name);
479         }
480         ldns_rr_free(rr);
481         return status;
482     }
483     ods_log_verbose("[%s] zone %s set soa serial to %u", zone_str,
484         zone->name, zone->db->intserial);
485     soa_rdata = ldns_rr_set_rdf(rr,
486         ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
487         zone->db->intserial), SE_SOA_RDATA_SERIAL);
488     if (soa_rdata) {
489         ldns_rdf_deep_free(soa_rdata);
490         soa_rdata = NULL;
491     } else {
492         ods_log_error("[%s] unable to update zone %s soa serial: failed to "
493             "replace soa serial rdata", zone_str, zone->name);
494         ldns_rr_free(rr);
495         return ODS_STATUS_ERR;
496     }
497     soa = rrset_add_rr(rrset, rr);
498     ods_log_assert(soa);
499     rrset_diff(rrset, 0, 0);
500     zone->db->serial_updated = 0;
501     return ODS_STATUS_OK;
502 }
503 
504 
505 /**
506  * Lookup RRset.
507  *
508  */
509 rrset_type*
zone_lookup_rrset(zone_type * zone,ldns_rdf * owner,ldns_rr_type type)510 zone_lookup_rrset(zone_type* zone, ldns_rdf* owner, ldns_rr_type type)
511 {
512     domain_type* domain = NULL;
513     if (!zone || !owner || !type) {
514         return NULL;
515     }
516     domain = namedb_lookup_domain(zone->db, owner);
517     if (!domain) {
518         return NULL;
519     }
520     return domain_lookup_rrset(domain, type);
521 }
522 
523 
524 /**
525  * Add RR.
526  *
527  */
528 ods_status
zone_add_rr(zone_type * zone,ldns_rr * rr,int do_stats)529 zone_add_rr(zone_type* zone, ldns_rr* rr, int do_stats)
530 {
531     domain_type* domain = NULL;
532     rrset_type* rrset = NULL;
533     rr_type* record = NULL;
534     ods_status status = ODS_STATUS_OK;
535 
536     ods_log_assert(rr);
537     ods_log_assert(zone);
538     ods_log_assert(zone->name);
539     ods_log_assert(zone->db);
540     ods_log_assert(zone->signconf);
541     /* If we already have this RR, return ODS_STATUS_UNCHANGED */
542     domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
543     if (!domain) {
544         domain = namedb_add_domain(zone->db, ldns_rr_owner(rr));
545         if (!domain) {
546             ods_log_error("[%s] unable to add RR to zone %s: "
547                 "failed to add domain", zone_str, zone->name);
548             return ODS_STATUS_ERR;
549         }
550         if (ldns_dname_compare(domain->dname, zone->apex) == 0) {
551             domain->is_apex = 1;
552         } else {
553             status = namedb_domain_entize(zone->db, domain, zone->apex);
554             if (status != ODS_STATUS_OK) {
555                 ods_log_error("[%s] unable to add RR to zone %s: "
556                     "failed to entize domain", zone_str, zone->name);
557                 return ODS_STATUS_ERR;
558             }
559         }
560     }
561     rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
562     if (!rrset) {
563         rrset = rrset_create(domain->zone, ldns_rr_get_type(rr));
564         if (!rrset) {
565             ods_log_error("[%s] unable to add RR to zone %s: "
566                 "failed to add RRset", zone_str, zone->name);
567             return ODS_STATUS_ERR;
568         }
569         domain_add_rrset(domain, rrset);
570     }
571     record = rrset_lookup_rr(rrset, rr);
572 
573     uint32_t ttl_rr = ldns_rr_ttl(rr);
574     uint32_t ttl_rrset = rrset_lookup_ttl(rrset, ttl_rr);
575 
576     if (record && ttl_rr == ttl_rrset && ttl_rr == ldns_rr_ttl(record->rr)) {
577         record->is_added = 1; /* already exists, just mark added */
578         record->is_removed = 0; /* unset is_removed */
579         return ODS_STATUS_UNCHANGED;
580     } else {
581         record = rrset_add_rr(rrset, rr);
582         ods_log_assert(record);
583         ods_log_assert(record->rr);
584         ods_log_assert(record->is_added);
585         if (ttl_rr != ttl_rrset) {
586             char *str = ldns_rr2str(rr);
587             str[(strlen(str)) - 1] = '\0';
588             for (int i = 0; i < strlen(str); i++) {
589                 if (str[i] == '\t') {
590                     str[i] = ' ';
591                 }
592             }
593             ods_log_error("In zone file %s: TTL for the record '%s' (%d) not"
594                 " equal to recordset TTL (%d)", zone->name, str, ttl_rr, ttl_rrset);
595             LDNS_FREE(str);
596         }
597     }
598     /* update stats */
599     if (do_stats && zone->stats) {
600         zone->stats->sort_count += 1;
601     }
602     return ODS_STATUS_OK;
603 }
604 
605 
606 /**
607  * Delete RR.
608  *
609  */
610 ods_status
zone_del_rr(zone_type * zone,ldns_rr * rr,int do_stats)611 zone_del_rr(zone_type* zone, ldns_rr* rr, int do_stats)
612 {
613     domain_type* domain = NULL;
614     rrset_type* rrset = NULL;
615     rr_type* record = NULL;
616     ods_log_assert(rr);
617     ods_log_assert(zone);
618     ods_log_assert(zone->name);
619     ods_log_assert(zone->db);
620     ods_log_assert(zone->signconf);
621     domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
622     if (!domain) {
623         ods_log_warning("[%s] unable to delete RR from zone %s: "
624             "domain not found", zone_str, zone->name);
625         return ODS_STATUS_UNCHANGED;
626     }
627     rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
628     if (!rrset) {
629         ods_log_warning("[%s] unable to delete RR from zone %s: "
630             "RRset not found", zone_str, zone->name);
631         return ODS_STATUS_UNCHANGED;
632     }
633     record = rrset_lookup_rr(rrset, rr);
634     if (!record) {
635         ods_log_error("[%s] unable to delete RR from zone %s: "
636             "RR not found", zone_str, zone->name);
637         return ODS_STATUS_UNCHANGED;
638     }
639 
640     record->is_removed = 1;
641     record->is_added = 0; /* unset is_added */
642     /* update stats */
643     if (do_stats && zone->stats) {
644         zone->stats->sort_count -= 1;
645     }
646     return ODS_STATUS_OK;
647 }
648 
649 /**
650  * Delete NSEC3PARAM RRs.
651  *
652  * Marks all NSEC3PARAM records as removed.
653  */
654 ods_status
zone_del_nsec3params(zone_type * zone)655 zone_del_nsec3params(zone_type* zone)
656 {
657     domain_type* domain = NULL;
658     rrset_type* rrset = NULL;
659     int i;
660 
661     ods_log_assert(zone);
662     ods_log_assert(zone->name);
663     ods_log_assert(zone->db);
664 
665     domain = namedb_lookup_domain(zone->db, zone->apex);
666     if (!domain) {
667         ods_log_verbose("[%s] unable to delete RR from zone %s: "
668             "domain not found", zone_str, zone->name);
669         return ODS_STATUS_UNCHANGED;
670     }
671 
672     rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_NSEC3PARAMS);
673     if (!rrset) {
674         ods_log_verbose("[%s] NSEC3PARAM in zone %s not found: "
675             "skipping delete", zone_str, zone->name);
676         return ODS_STATUS_UNCHANGED;
677     }
678 
679     /* We don't actually delete the record as we still need the
680      * information in the IXFR. Just set it as removed. The code
681      * inserting the new record may flip this flag when the record
682      * hasn't changed. */
683     for (i=0; i < rrset->rr_count; i++) {
684         rrset->rrs[i].is_removed = 1;
685     }
686     return ODS_STATUS_OK;
687 }
688 
689 /**
690  * Merge zones.
691  *
692  */
693 void
zone_merge(zone_type * z1,zone_type * z2)694 zone_merge(zone_type* z1, zone_type* z2)
695 {
696     const char* str;
697     adapter_type* adtmp = NULL;
698 
699     if (!z1 || !z2) {
700         return;
701     }
702     /* policy name */
703     if (ods_strcmp(z2->policy_name, z1->policy_name) != 0) {
704         if (z2->policy_name) {
705             str = strdup(z2->policy_name);
706             if (!str) {
707                 ods_log_error("[%s] failed to merge policy %s name to zone "
708                     "%s", zone_str, z2->policy_name, z1->name);
709             } else {
710                 free((void*)z1->policy_name);
711                 z1->policy_name = str;
712                 z1->zl_status = ZONE_ZL_UPDATED;
713             }
714         } else {
715             free((void*)z1->policy_name);
716             z1->policy_name = NULL;
717             z1->zl_status = ZONE_ZL_UPDATED;
718         }
719     }
720     /* signconf filename */
721     if (ods_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) {
722         if (z2->signconf_filename) {
723             str = strdup(z2->signconf_filename);
724             if (!str) {
725                 ods_log_error("[%s] failed to merge signconf filename %s to "
726                     "zone %s", zone_str, z2->policy_name, z1->name);
727             } else {
728                 free((void*)z1->signconf_filename);
729                 z1->signconf_filename = str;
730                 z1->zl_status = ZONE_ZL_UPDATED;
731             }
732         } else {
733             free((void*)z1->signconf_filename);
734             z1->signconf_filename = NULL;
735             z1->zl_status = ZONE_ZL_UPDATED;
736         }
737     }
738     /* adapters */
739     if (adapter_compare(z2->adinbound, z1->adinbound) != 0) {
740         adtmp = z2->adinbound;
741         z2->adinbound = z1->adinbound;
742         z1->adinbound = adtmp;
743         adtmp = NULL;
744     }
745     if (adapter_compare(z2->adoutbound, z1->adoutbound) != 0) {
746         adtmp = z2->adoutbound;
747         z2->adoutbound = z1->adoutbound;
748         z1->adoutbound = adtmp;
749         adtmp = NULL;
750     }
751 }
752 
753 
754 /**
755  * Clean up zone.
756  *
757  */
758 void
zone_cleanup(zone_type * zone)759 zone_cleanup(zone_type* zone)
760 {
761     if (!zone) {
762         return;
763     }
764 pthread_mutex_lock(&zone->zone_lock);
765     ldns_rdf_deep_free(zone->apex);
766     adapter_cleanup(zone->adinbound);
767     adapter_cleanup(zone->adoutbound);
768     namedb_cleanup(zone->db);
769     ixfr_cleanup(zone->ixfr);
770     xfrd_cleanup(zone->xfrd, 1);
771     notify_cleanup(zone->notify);
772     signconf_cleanup(zone->signconf);
773 pthread_mutex_unlock(&zone->zone_lock);
774     stats_cleanup(zone->stats);
775     free(zone->notify_command);
776     free(zone->notify_args);
777     free((void*)zone->policy_name);
778     free((void*)zone->signconf_filename);
779     free((void*)zone->name);
780     collection_class_destroy(&zone->rrstore);
781     pthread_mutex_destroy(&zone->xfr_lock);
782     pthread_mutex_destroy(&zone->zone_lock);
783     free(zone);
784 }
785 
786 
787 /**
788  * Recover zone from backup.
789  *
790  */
791 ods_status
zone_recover2(engine_type * engine,zone_type * zone)792 zone_recover2(engine_type* engine, zone_type* zone)
793 {
794     char* filename = NULL;
795     FILE* fd = NULL;
796     const char* token = NULL;
797     time_t when = 0;
798     ods_status status = ODS_STATUS_OK;
799     /* zone part */
800     int klass = 0;
801     uint32_t inbound = 0, internal = 0, outbound = 0;
802     /* signconf part */
803     time_t lastmod = 0;
804     /* nsec3params part */
805     const char* salt = NULL;
806 
807     ods_log_assert(zone);
808     ods_log_assert(zone->name);
809     ods_log_assert(zone->signconf);
810     ods_log_assert(zone->db);
811 
812     filename = ods_build_path(zone->name, ".backup2", 0, 1);
813     if (!filename) {
814         return ODS_STATUS_MALLOC_ERR;
815     }
816     fd = ods_fopen(filename, NULL, "r");
817     if (fd) {
818         /* start recovery */
819         if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC_V3)) {
820             ods_log_error("[%s] corrupted backup file zone %s: read magic "
821                 "error", zone_str, zone->name);
822             goto recover_error2;
823         }
824         if (!backup_read_check_str(fd, ";;Time:") |
825             !backup_read_time_t(fd, &when)) {
826             ods_log_error("[%s] corrupted backup file zone %s: read time "
827                 "error", zone_str, zone->name);
828             goto recover_error2;
829         }
830         /* zone stuff */
831         if (!backup_read_check_str(fd, ";;Zone:") |
832             !backup_read_check_str(fd, "name") |
833             !backup_read_check_str(fd, zone->name)) {
834             ods_log_error("[%s] corrupted backup file zone %s: read name "
835                 "error", zone_str, zone->name);
836             goto recover_error2;
837         }
838         if (!backup_read_check_str(fd, "class") |
839             !backup_read_int(fd, &klass)) {
840             ods_log_error("[%s] corrupted backup file zone %s: read class "
841                 "error", zone_str, zone->name);
842             goto recover_error2;
843         }
844         if (!backup_read_check_str(fd, "inbound") |
845             !backup_read_uint32_t(fd, &inbound) |
846             !backup_read_check_str(fd, "internal") |
847             !backup_read_uint32_t(fd, &internal) |
848             !backup_read_check_str(fd, "outbound") |
849             !backup_read_uint32_t(fd, &outbound)) {
850             ods_log_error("[%s] corrupted backup file zone %s: read serial "
851                 "error", zone_str, zone->name);
852             goto recover_error2;
853         }
854         zone->klass = (ldns_rr_class) klass;
855         zone->db->inbserial = inbound;
856         zone->db->intserial = internal;
857         zone->db->outserial = outbound;
858         /* signconf part */
859         if (!backup_read_check_str(fd, ";;Signconf:") |
860             !backup_read_check_str(fd, "lastmod") |
861             !backup_read_time_t(fd, &lastmod) |
862             !backup_read_check_str(fd, "maxzonettl") |
863             !backup_read_check_str(fd, "0") |
864             !backup_read_check_str(fd, "resign") |
865             !backup_read_duration(fd, &zone->signconf->sig_resign_interval) |
866             !backup_read_check_str(fd, "refresh") |
867             !backup_read_duration(fd, &zone->signconf->sig_refresh_interval) |
868             !backup_read_check_str(fd, "valid") |
869             !backup_read_duration(fd, &zone->signconf->sig_validity_default) |
870             !backup_read_check_str(fd, "denial") |
871             !backup_read_duration(fd,&zone->signconf->sig_validity_denial) |
872             !backup_read_check_str(fd, "keyset") |
873             !backup_read_duration(fd,&zone->signconf->sig_validity_keyset) |
874             !backup_read_check_str(fd, "jitter") |
875             !backup_read_duration(fd, &zone->signconf->sig_jitter) |
876             !backup_read_check_str(fd, "offset") |
877             !backup_read_duration(fd, &zone->signconf->sig_inception_offset) |
878             !backup_read_check_str(fd, "nsec") |
879             !backup_read_rr_type(fd, &zone->signconf->nsec_type) |
880             !backup_read_check_str(fd, "dnskeyttl") |
881             !backup_read_duration(fd, &zone->signconf->dnskey_ttl) |
882             !backup_read_check_str(fd, "soattl") |
883             !backup_read_duration(fd, &zone->signconf->soa_ttl) |
884             !backup_read_check_str(fd, "soamin") |
885             !backup_read_duration(fd, &zone->signconf->soa_min) |
886             !backup_read_check_str(fd, "serial") |
887             !backup_read_str(fd, &zone->signconf->soa_serial)) {
888             ods_log_error("[%s] corrupted backup file zone %s: read signconf "
889                 "error", zone_str, zone->name);
890             goto recover_error2;
891         }
892         /* nsec3params part */
893         if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
894             if (!backup_read_check_str(fd, ";;Nsec3parameters:") |
895                 !backup_read_check_str(fd, "salt") |
896                 !backup_read_str(fd, &salt) |
897                 !backup_read_check_str(fd, "algorithm") |
898                 !backup_read_uint32_t(fd, &zone->signconf->nsec3_algo) |
899                 !backup_read_check_str(fd, "optout") |
900                 !backup_read_int(fd, &zone->signconf->nsec3_optout) |
901                 !backup_read_check_str(fd, "iterations") |
902                 !backup_read_uint32_t(fd, &zone->signconf->nsec3_iterations)) {
903                 ods_log_error("[%s] corrupted backup file zone %s: read "
904                     "nsec3parameters error", zone_str, zone->name);
905                 goto recover_error2;
906             }
907             zone->signconf->nsec3_salt = strdup(salt);
908             free((void*) salt);
909             salt = NULL;
910             zone->signconf->nsec3params = nsec3params_create(
911                 zone->signconf,
912                 (uint8_t) zone->signconf->nsec3_algo,
913                 (uint8_t) zone->signconf->nsec3_optout,
914                 (uint16_t) zone->signconf->nsec3_iterations,
915                 zone->signconf->nsec3_salt);
916             if (!zone->signconf->nsec3params) {
917                 ods_log_error("[%s] corrupted backup file zone %s: unable to "
918                     "create nsec3param", zone_str, zone->name);
919                 goto recover_error2;
920             }
921         }
922         zone->signconf->last_modified = lastmod;
923         zone->zoneconfigvalid = 1;
924         zone->default_ttl = (uint32_t) duration2time(zone->signconf->soa_min);
925         /* keys part */
926         zone->signconf->keys = keylist_create((void*) zone->signconf);
927         while (backup_read_str(fd, &token)) {
928             if (ods_strcmp(token, ";;Key:") == 0) {
929                 if (!key_recover2(fd, zone->signconf->keys)) {
930                     ods_log_error("[%s] corrupted backup file zone %s: read "
931                         "key error", zone_str, zone->name);
932                     goto recover_error2;
933                 }
934             } else if (ods_strcmp(token, ";;") == 0) {
935                 /* keylist done */
936                 free((void*) token);
937                 token = NULL;
938                 break;
939             } else {
940                 /* keylist corrupted */
941                 goto recover_error2;
942             }
943             free((void*) token);
944             token = NULL;
945         }
946         /* publish dnskeys */
947         status = zone_publish_dnskeys(zone, 1);
948         if (status != ODS_STATUS_OK) {
949             ods_log_error("[%s] corrupted backup file zone %s: unable to "
950                 "publish dnskeys (%s)", zone_str, zone->name,
951                 ods_status2str(status));
952             goto recover_error2;
953         }
954         /* publish nsec3param */
955         if (!zone->signconf->passthrough)
956             status = zone_publish_nsec3param(zone);
957         if (status != ODS_STATUS_OK) {
958             ods_log_error("[%s] corrupted backup file zone %s: unable to "
959                 "publish nsec3param (%s)", zone_str, zone->name,
960                 ods_status2str(status));
961             goto recover_error2;
962         }
963         /* publish other records */
964         status = backup_read_namedb(fd, zone);
965         if (status != ODS_STATUS_OK) {
966             ods_log_error("[%s] corrupted backup file zone %s: unable to "
967                 "read resource records (%s)", zone_str, zone->name,
968                 ods_status2str(status));
969             goto recover_error2;
970         }
971         /* task */
972         schedule_scheduletask(engine->taskq, TASK_SIGN, zone->name, zone, &zone->zone_lock, schedule_PROMPTLY);
973         free((void*)filename);
974         ods_fclose(fd);
975         zone->db->is_initialized = 1;
976         zone->db->have_serial = 1;
977         /* journal */
978         filename = ods_build_path(zone->name, ".ixfr", 0, 1);
979         if (filename) {
980             fd = ods_fopen(filename, NULL, "r");
981         }
982         if (fd) {
983             status = backup_read_ixfr(fd, zone);
984             if (status != ODS_STATUS_OK) {
985                 ods_log_warning("[%s] corrupted journal file zone %s, "
986                     "skipping (%s)", zone_str, zone->name,
987                     ods_status2str(status));
988                 (void)unlink(filename);
989                 ixfr_cleanup(zone->ixfr);
990                 zone->ixfr = ixfr_create();
991             }
992         }
993         pthread_mutex_lock(&zone->ixfr->ixfr_lock);
994         ixfr_purge(zone->ixfr, zone->name);
995         pthread_mutex_unlock(&zone->ixfr->ixfr_lock);
996 
997         /* all ok */
998         free((void*)filename);
999         if (fd) {
1000             ods_fclose(fd);
1001         }
1002         if (zone->stats) {
1003             pthread_mutex_lock(&zone->stats->stats_lock);
1004             stats_clear(zone->stats);
1005             pthread_mutex_unlock(&zone->stats->stats_lock);
1006         }
1007         return ODS_STATUS_OK;
1008     }
1009     free(filename);
1010     return ODS_STATUS_UNCHANGED;
1011 
1012 recover_error2:
1013     free((void*)filename);
1014     ods_fclose(fd);
1015     /* signconf cleanup */
1016     free((void*)salt);
1017     salt = NULL;
1018     signconf_cleanup(zone->signconf);
1019     zone->signconf = signconf_create();
1020     ods_log_assert(zone->signconf);
1021     /* namedb cleanup */
1022     namedb_cleanup(zone->db);
1023     zone->db = namedb_create((void*)zone);
1024     ods_log_assert(zone->db);
1025     /* stats reset */
1026     if (zone->stats) {
1027        pthread_mutex_lock(&zone->stats->stats_lock);
1028        stats_clear(zone->stats);
1029        pthread_mutex_unlock(&zone->stats->stats_lock);
1030     }
1031     return ODS_STATUS_ERR;
1032 }
1033 
1034 
1035 /**
1036  * Backup zone.
1037  *
1038  */
1039 ods_status
zone_backup2(zone_type * zone,time_t nextResign)1040 zone_backup2(zone_type* zone, time_t nextResign)
1041 {
1042     char* filename = NULL;
1043     char* tmpfile = NULL;
1044     FILE* fd = NULL;
1045     int ret = 0;
1046     ods_status status = ODS_STATUS_OK;
1047 
1048     ods_log_assert(zone);
1049     ods_log_assert(zone->name);
1050     ods_log_assert(zone->db);
1051     ods_log_assert(zone->signconf);
1052 
1053     tmpfile = ods_build_path(zone->name, ".backup2.tmp", 0, 1);
1054     filename = ods_build_path(zone->name, ".backup2", 0, 1);
1055     if (!tmpfile || !filename) {
1056         free(tmpfile);
1057         free(filename);
1058         return ODS_STATUS_MALLOC_ERR;
1059     }
1060     fd = ods_fopen(tmpfile, NULL, "w");
1061     if (fd) {
1062         fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC_V3);
1063         fprintf(fd, ";;Time: %u\n", (unsigned) nextResign);
1064         /** Backup zone */
1065         fprintf(fd, ";;Zone: name %s class %i inbound %u internal %u "
1066             "outbound %u\n", zone->name, (int) zone->klass,
1067             (unsigned) zone->db->inbserial,
1068             (unsigned) zone->db->intserial,
1069             (unsigned) zone->db->outserial);
1070         /** Backup signconf */
1071         signconf_backup(fd, zone->signconf, ODS_SE_FILE_MAGIC_V3);
1072         /** Backup NSEC3 parameters */
1073         if (zone->signconf->nsec3params) {
1074             nsec3params_backup(fd,
1075                 zone->signconf->nsec3_algo,
1076                 zone->signconf->nsec3_optout,
1077                 zone->signconf->nsec3_iterations,
1078                 zone->signconf->nsec3_salt,
1079                 zone->signconf->nsec3params->rr,
1080                 ODS_SE_FILE_MAGIC_V3);
1081         }
1082         /** Backup keylist */
1083         keylist_backup(fd, zone->signconf->keys, ODS_SE_FILE_MAGIC_V3);
1084         fprintf(fd, ";;\n");
1085         /** Backup domains and stuff */
1086         namedb_backup2(fd, zone->db);
1087         /** Done */
1088         fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC_V3);
1089         ods_fclose(fd);
1090         ret = rename(tmpfile, filename);
1091         if (ret != 0) {
1092             ods_log_error("[%s] unable to rename zone %s backup %s to %s: %s",
1093                 zone_str, zone->name, tmpfile, filename, strerror(errno));
1094             status = ODS_STATUS_RENAME_ERR;
1095         }
1096     } else {
1097         status = ODS_STATUS_FOPEN_ERR;
1098     }
1099 
1100     free((void*) tmpfile);
1101     free((void*) filename);
1102     return status;
1103 }
1104