OpenDNSSEC-signer  1.4.1
zone.c
Go to the documentation of this file.
1 /*
2  * $Id: zone.c 7149 2013-06-12 08:33:21Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "adapter/adapter.h"
35 #include "shared/allocator.h"
36 #include "shared/file.h"
37 #include "shared/hsm.h"
38 #include "shared/locks.h"
39 #include "shared/log.h"
40 #include "shared/status.h"
41 #include "shared/util.h"
42 #include "signer/backup.h"
43 #include "signer/zone.h"
44 #include "wire/netio.h"
45 
46 #include <ldns/ldns.h>
47 
48 static const char* zone_str = "zone";
49 
50 
55 zone_type*
56 zone_create(char* name, ldns_rr_class klass)
57 {
58  allocator_type* allocator = NULL;
59  zone_type* zone = NULL;
60 
61  if (!name || !klass) {
62  return NULL;
63  }
64  allocator = allocator_create(malloc, free);
65  if (!allocator) {
66  ods_log_error("[%s] unable to create zone %s: allocator_create() "
67  "failed", zone_str, name);
68  return NULL;
69  }
70  zone = (zone_type*) allocator_alloc(allocator, sizeof(zone_type));
71  if (!zone) {
72  ods_log_error("[%s] unable to create zone %s: allocator_alloc()",
73  "failed", zone_str, name);
74  allocator_cleanup(allocator);
75  return NULL;
76  }
77  zone->allocator = allocator;
78  /* [start] PS 9218653: Drop trailing dot in domain name */
79  if (strlen(name) > 1 && name[strlen(name)-1] == '.') {
80  name[strlen(name)-1] = '\0';
81  }
82  /* [end] PS 9218653 */
83  zone->name = allocator_strdup(allocator, name);
84  if (!zone->name) {
85  ods_log_error("[%s] unable to create zone %s: allocator_strdup() "
86  "failed", zone_str, name);
87  zone_cleanup(zone);
88  return NULL;
89  }
90  zone->klass = klass;
91  zone->default_ttl = 3600; /* TODO: configure --default-ttl option? */
92  zone->apex = ldns_dname_new_frm_str(name);
93  /* check zone->apex? */
94  zone->notify_command = NULL;
95  zone->notify_ns = NULL;
96  zone->notify_args = NULL;
97  zone->policy_name = NULL;
98  zone->signconf_filename = NULL;
99  zone->adinbound = NULL;
100  zone->adoutbound = NULL;
101  zone->zl_status = ZONE_ZL_OK;
102  zone->task = NULL;
103  zone->xfrd = NULL;
104  zone->notify = NULL;
105  zone->db = namedb_create((void*)zone);
106  if (!zone->db) {
107  ods_log_error("[%s] unable to create zone %s: namedb_create() "
108  "failed", zone_str, name);
109  zone_cleanup(zone);
110  return NULL;
111  }
112  zone->ixfr = ixfr_create((void*)zone);
113  if (!zone->ixfr) {
114  ods_log_error("[%s] unable to create zone %s: ixfr_create() "
115  "failed", zone_str, name);
116  zone_cleanup(zone);
117  return NULL;
118  }
119  zone->signconf = signconf_create();
120  if (!zone->signconf) {
121  ods_log_error("[%s] unable to create zone %s: signconf_create() "
122  "failed", zone_str, name);
123  zone_cleanup(zone);
124  return NULL;
125  }
126  zone->stats = stats_create();
127  lock_basic_init(&zone->zone_lock);
128  lock_basic_init(&zone->xfr_lock);
129  return zone;
130 }
131 
132 
139 {
140  ods_status status = ODS_STATUS_OK;
141  signconf_type* signconf = NULL;
142  char* datestamp = NULL;
143 
144  if (!zone || !zone->name || !zone->signconf) {
145  return ODS_STATUS_ASSERT_ERR;
146  }
147  if (!zone->signconf_filename) {
148  ods_log_warning("[%s] zone %s has no signconf filename, treat as "
149  "insecure?", zone_str, zone->name);
150  return ODS_STATUS_INSECURE;
151  }
152  status = signconf_update(&signconf, zone->signconf_filename,
153  zone->signconf->last_modified);
154  if (status == ODS_STATUS_OK) {
155  if (!signconf) {
156  /* this is unexpected */
157  ods_log_alert("[%s] unable to load signconf for zone %s: signconf "
158  "status ok but no signconf stored", zone_str, zone->name);
159  return ODS_STATUS_ASSERT_ERR;
160  }
161  (void)time_datestamp(signconf->last_modified, "%Y-%m-%d %T",
162  &datestamp);
163  ods_log_debug("[%s] zone %s signconf file %s is modified since %s",
164  zone_str, zone->name, zone->signconf_filename,
165  datestamp?datestamp:"Unknown");
166  free((void*)datestamp);
167  *new_signconf = signconf;
168  } else if (status == ODS_STATUS_UNCHANGED) {
170  "%Y-%m-%d %T", &datestamp);
171  ods_log_verbose("[%s] zone %s signconf file %s is unchanged since "
172  "%s", zone_str, zone->name, zone->signconf_filename,
173  datestamp?datestamp:"Unknown");
174  free((void*)datestamp);
175  } else {
176  ods_log_error("[%s] unable to load signconf for zone %s: signconf %s "
177  "%s", zone_str, zone->name, zone->signconf_filename,
178  ods_status2str(status));
179  }
180  return status;
181 }
182 
183 
190 {
191  task_type* task = NULL;
192  ods_status status = ODS_STATUS_OK;
193 
194  ods_log_assert(taskq);
195  ods_log_assert(zone);
196  ods_log_assert(zone->name);
197  ods_log_assert(zone->task);
198  ods_log_debug("[%s] reschedule task for zone %s", zone_str, zone->name);
200  task = unschedule_task(taskq, (task_type*) zone->task);
201  if (task != NULL) {
202  if (task->what != what) {
203  task->halted = task->what;
204  task->halted_when = task->when;
205  task->interrupt = what;
206  }
208  if (task->what > what) {
209  task->what = what;
210  }
211  task->when = time_now();
212  status = schedule_task(taskq, task, 0);
213  } else {
214  /* task not queued, being worked on? */
215  ods_log_verbose("[%s] unable to reschedule task for zone %s now: "
216  "task is not queued (task will be rescheduled when it is put "
217  "back on the queue)", zone_str, zone->name);
218  task = (task_type*) zone->task;
219  task->interrupt = what;
220  /* task->halted(_when) set by worker */
221  }
223  zone->task = task;
224  return status;
225 }
226 
227 
234 {
235  hsm_ctx_t* ctx = NULL;
236  uint32_t ttl = 0;
237  uint16_t i = 0;
238  ods_status status = ODS_STATUS_OK;
239  rrset_type* rrset = NULL;
240  rr_type* dnskey = NULL;
241 
242  if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
243  return ODS_STATUS_ASSERT_ERR;
244  }
245  ods_log_assert(zone->name);
246 
247  /* hsm access */
248  ctx = hsm_create_context();
249  if (ctx == NULL) {
250  ods_log_error("[%s] unable to publish keys for zone %s: "
251  "error creating libhsm context", zone_str, zone->name);
252  return ODS_STATUS_HSM_ERR;
253  }
254  /* dnskey ttl */
255  ttl = zone->default_ttl;
256  if (zone->signconf->dnskey_ttl) {
257  ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
258  }
259  /* publish keys */
260  for (i=0; i < zone->signconf->keys->count; i++) {
261  if (!zone->signconf->keys->keys[i].publish) {
262  continue;
263  }
264  if (!zone->signconf->keys->keys[i].dnskey) {
265  /* get dnskey */
266  status = lhsm_get_key(ctx, zone->apex,
267  &zone->signconf->keys->keys[i]);
268  if (status != ODS_STATUS_OK) {
269  ods_log_error("[%s] unable to publish dnskeys for zone %s: "
270  "error creating dnskey", zone_str, zone->name);
271  break;
272  }
273  }
274  ods_log_assert(zone->signconf->keys->keys[i].dnskey);
275  ldns_rr_set_ttl(zone->signconf->keys->keys[i].dnskey, ttl);
276  ldns_rr_set_class(zone->signconf->keys->keys[i].dnskey, zone->klass);
277  status = zone_add_rr(zone, zone->signconf->keys->keys[i].dnskey, 0);
278  if (status == ODS_STATUS_UNCHANGED) {
279  /* rr already exists, adjust pointer */
280  rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
281  ods_log_assert(rrset);
282  dnskey = rrset_lookup_rr(rrset,
283  zone->signconf->keys->keys[i].dnskey);
284  ods_log_assert(dnskey);
285  if (dnskey->rr != zone->signconf->keys->keys[i].dnskey) {
286  ldns_rr_free(zone->signconf->keys->keys[i].dnskey);
287  }
288  zone->signconf->keys->keys[i].dnskey = dnskey->rr;
289  status = ODS_STATUS_OK;
290  } else if (status != ODS_STATUS_OK) {
291  ods_log_error("[%s] unable to publish dnskeys for zone %s: "
292  "error adding dnskey", zone_str, zone->name);
293  break;
294  }
295  }
296  /* done */
297  hsm_destroy_context(ctx);
298  return status;
299 }
300 
301 
306 void
308 {
309  uint16_t i = 0;
310  rrset_type* rrset = NULL;
311  rr_type* dnskey = NULL;
312  if (!zone || !zone->signconf || !zone->signconf->keys) {
313  return;
314  }
315  rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
316  /* unlink dnskey rrs */
317  for (i=0; i < zone->signconf->keys->count; i++) {
318  if (rrset && zone->signconf->keys->keys[i].dnskey) {
319  dnskey = rrset_lookup_rr(rrset,
320  zone->signconf->keys->keys[i].dnskey);
321  if (dnskey && !dnskey->exists &&
322  dnskey->rr == zone->signconf->keys->keys[i].dnskey) {
323  zone->signconf->keys->keys[i].dnskey = NULL;
324  }
325  }
326  }
327  /* done */
328  return;
329 }
330 
331 
338 {
339  rrset_type* rrset = NULL;
340  rr_type* n3prr = NULL;
341  ldns_rr* rr = NULL;
342  ods_status status = ODS_STATUS_OK;
343 
344  if (!zone || !zone->name || !zone->db || !zone->signconf) {
345  return ODS_STATUS_ASSERT_ERR;
346  }
347  if (!zone->signconf->nsec3params) {
348  /* NSEC */
349  ods_log_assert(zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC);
350  return ODS_STATUS_OK;
351  }
352 
353  if (!zone->signconf->nsec3params->rr) {
354  rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
355  if (!rr) {
356  ods_log_error("[%s] unable to publish nsec3params for zone %s: "
357  "error creating rr (%s)", zone_str, zone->name,
358  ods_status2str(status));
359  return ODS_STATUS_MALLOC_ERR;
360  }
361  ldns_rr_set_class(rr, zone->klass);
362  ldns_rr_set_ttl(rr, 0);
363  ldns_rr_set_owner(rr, ldns_rdf_clone(zone->apex));
364  ldns_nsec3_add_param_rdfs(rr,
365  zone->signconf->nsec3params->algorithm, 0,
367  zone->signconf->nsec3params->salt_len,
368  zone->signconf->nsec3params->salt_data);
373  ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(rr, 1)), 7, 0);
374  zone->signconf->nsec3params->rr = rr;
375  }
377  status = zone_add_rr(zone, zone->signconf->nsec3params->rr, 0);
378  if (status == ODS_STATUS_UNCHANGED) {
379  /* rr already exists, adjust pointer */
380  rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS);
381  ods_log_assert(rrset);
382  n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr);
383  ods_log_assert(n3prr);
384  if (n3prr->rr != zone->signconf->nsec3params->rr) {
385  ldns_rr_free(zone->signconf->nsec3params->rr);
386  }
387  zone->signconf->nsec3params->rr = n3prr->rr;
388  status = ODS_STATUS_OK;
389  } else if (status != ODS_STATUS_OK) {
390  ods_log_error("[%s] unable to publish nsec3params for zone %s: "
391  "error adding nsec3params (%s)", zone_str,
392  zone->name, ods_status2str(status));
393  }
394  return status;
395 }
396 
397 
402 void
404 {
405  rrset_type* rrset = NULL;
406  rr_type* n3prr = NULL;
407 
408  if (!zone || !zone->signconf || !zone->signconf->nsec3params) {
409  return;
410  }
411  rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS);
412  if (rrset && zone->signconf->nsec3params->rr) {
413  n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr);
414  if (n3prr && !n3prr->exists &&
415  n3prr->rr == zone->signconf->nsec3params->rr) {
416  zone->signconf->nsec3params->rr = NULL;
417  }
418  }
419  return;
420 }
421 
422 
429 {
430  ods_status status = ODS_STATUS_OK;
431  rrset_type* rrset = NULL;
432  rr_type* soa = NULL;
433  ldns_rr* rr = NULL;
434  ldns_rdf* soa_rdata = NULL;
435 
436  ods_log_assert(zone);
437  ods_log_assert(zone->apex);
438  ods_log_assert(zone->name);
439  ods_log_assert(zone->db);
440  ods_log_assert(zone->signconf);
441 
442  if (zone->db->serial_updated) {
443  /* already done, unmark and return ok */
444  ods_log_debug("[%s] zone %s soa serial already up to date",
445  zone_str, zone->name);
446  zone->db->serial_updated = 0;
447  return ODS_STATUS_OK;
448  }
449  rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
450  ods_log_assert(rrset);
451  ods_log_assert(rrset->rrs);
452  ods_log_assert(rrset->rrs[0].rr);
453  rr = ldns_rr_clone(rrset->rrs[0].rr);
454  if (!rr) {
455  ods_log_error("[%s] unable to update zone %s soa serial: failed to "
456  "clone soa rr", zone_str, zone->name);
457  return ODS_STATUS_ERR;
458  }
459  status = namedb_update_serial(zone->db, zone->name,
460  zone->signconf->soa_serial, zone->db->inbserial);
461  if (status != ODS_STATUS_OK) {
462  ods_log_error("[%s] unable to update zone %s soa serial: %s",
463  zone_str, zone->name, ods_status2str(status));
464  ldns_rr_free(rr);
465  return status;
466  }
467  ods_log_verbose("[%s] zone %s set soa serial to %u", zone_str,
468  zone->name, zone->db->intserial);
469  soa_rdata = ldns_rr_set_rdf(rr,
470  ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
471  zone->db->intserial), SE_SOA_RDATA_SERIAL);
472  if (soa_rdata) {
473  ldns_rdf_deep_free(soa_rdata);
474  soa_rdata = NULL;
475  } else {
476  ods_log_error("[%s] unable to update zone %s soa serial: failed to "
477  "replace soa serial rdata", zone_str, zone->name);
478  ldns_rr_free(rr);
479  return ODS_STATUS_ERR;
480  }
481  soa = rrset_add_rr(rrset, rr);
482  ods_log_assert(soa);
483  rrset_diff(rrset, 0, 0);
484  zone->db->serial_updated = 0;
485  return ODS_STATUS_OK;
486 }
487 
488 
493 rrset_type*
494 zone_lookup_rrset(zone_type* zone, ldns_rdf* owner, ldns_rr_type type)
495 {
496  domain_type* domain = NULL;
497  if (!zone || !owner || !type) {
498  return NULL;
499  }
500  domain = namedb_lookup_domain(zone->db, owner);
501  if (!domain) {
502  return NULL;
503  }
504  return domain_lookup_rrset(domain, type);
505 }
506 
507 
513 zone_add_rr(zone_type* zone, ldns_rr* rr, int do_stats)
514 {
515  domain_type* domain = NULL;
516  rrset_type* rrset = NULL;
517  rr_type* record = NULL;
518  ods_status status = ODS_STATUS_OK;
519 
520  ods_log_assert(rr);
521  ods_log_assert(zone);
522  ods_log_assert(zone->name);
523  ods_log_assert(zone->db);
524  ods_log_assert(zone->signconf);
525  /* If we already have this RR, return ODS_STATUS_UNCHANGED */
526  domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
527  if (!domain) {
528  domain = namedb_add_domain(zone->db, ldns_rr_owner(rr));
529  if (!domain) {
530  ods_log_error("[%s] unable to add RR to zone %s: "
531  "failed to add domain", zone_str, zone->name);
532  return ODS_STATUS_ERR;
533  }
534  if (ldns_dname_compare(domain->dname, zone->apex) == 0) {
535  domain->is_apex = 1;
536  } else {
537  status = namedb_domain_entize(zone->db, domain, zone->apex);
538  if (status != ODS_STATUS_OK) {
539  ods_log_error("[%s] unable to add RR to zone %s: "
540  "failed to entize domain", zone_str, zone->name);
541  return ODS_STATUS_ERR;
542  }
543  }
544  }
545  rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
546  if (!rrset) {
547  rrset = rrset_create(domain->zone, ldns_rr_get_type(rr));
548  if (!rrset) {
549  ods_log_error("[%s] unable to add RR to zone %s: "
550  "failed to add RRset", zone_str, zone->name);
551  return ODS_STATUS_ERR;
552  }
553  domain_add_rrset(domain, rrset);
554  }
555  record = rrset_lookup_rr(rrset, rr);
556  if (record) {
557  record->is_added = 1; /* already exists, just mark added */
558  record->is_removed = 0; /* unset is_removed */
559  if (ldns_rr_ttl(rr) != ldns_rr_ttl(record->rr)) {
560  ldns_rr_set_ttl(record->rr, ldns_rr_ttl(rr));
561  rrset->needs_signing = 1;
562  }
563  return ODS_STATUS_UNCHANGED;
564  } else {
565  record = rrset_add_rr(rrset, rr);
566  ods_log_assert(record);
567  ods_log_assert(record->rr);
568  ods_log_assert(record->is_added);
569  }
570  /* update stats */
571  if (do_stats && zone->stats) {
572  zone->stats->sort_count += 1;
573  }
574  return ODS_STATUS_OK;
575 }
576 
577 
583 zone_del_rr(zone_type* zone, ldns_rr* rr, int do_stats)
584 {
585  domain_type* domain = NULL;
586  rrset_type* rrset = NULL;
587  rr_type* record = NULL;
588  ods_log_assert(rr);
589  ods_log_assert(zone);
590  ods_log_assert(zone->name);
591  ods_log_assert(zone->db);
592  ods_log_assert(zone->signconf);
593  domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
594  if (!domain) {
595  ods_log_warning("[%s] unable to delete RR from zone %s: "
596  "domain not found", zone_str, zone->name);
597  return ODS_STATUS_UNCHANGED;
598  }
599  rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
600  if (!rrset) {
601  ods_log_warning("[%s] unable to delete RR from zone %s: "
602  "RRset not found", zone_str, zone->name);
603  return ODS_STATUS_UNCHANGED;
604  }
605  record = rrset_lookup_rr(rrset, rr);
606  if (!record) {
607  ods_log_error("[%s] unable to delete RR from zone %s: "
608  "RR not found", zone_str, zone->name);
609  return ODS_STATUS_UNCHANGED;
610  }
611 
612  record->is_removed = 1;
613  record->is_added = 0; /* unset is_added */
614  /* update stats */
615  if (do_stats && zone->stats) {
616  zone->stats->sort_count -= 1;
617  }
618  return ODS_STATUS_OK;
619 }
620 
621 
626 void
628 {
629  const char* str;
630  adapter_type* adtmp = NULL;
631 
632  if (!z1 || !z2) {
633  return;
634  }
635  /* policy name */
636  if (ods_strcmp(z2->policy_name, z1->policy_name) != 0) {
637  if (z2->policy_name) {
638  str = strdup(z2->policy_name);
639  if (!str) {
640  ods_log_error("[%s] failed to merge policy %s name to zone "
641  "%s", zone_str, z2->policy_name, z1->name);
642  } else {
643  free((void*)z1->policy_name);
644  z1->policy_name = str;
646  }
647  } else {
648  free((void*)z1->policy_name);
649  z1->policy_name = NULL;
651  }
652  }
653  /* signconf filename */
654  if (ods_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) {
655  if (z2->signconf_filename) {
656  str = strdup(z2->signconf_filename);
657  if (!str) {
658  ods_log_error("[%s] failed to merge signconf filename %s to "
659  "zone %s", zone_str, z2->policy_name, z1->name);
660  } else {
661  free((void*)z1->signconf_filename);
662  z1->signconf_filename = str;
664  }
665  } else {
666  free((void*)z1->signconf_filename);
667  z1->signconf_filename = NULL;
669  }
670  }
671  /* adapters */
672  if (adapter_compare(z2->adinbound, z1->adinbound) != 0) {
673  adtmp = z2->adinbound;
674  z2->adinbound = z1->adinbound;
675  z1->adinbound = adtmp;
676  adtmp = NULL;
677  }
678  if (adapter_compare(z2->adoutbound, z1->adoutbound) != 0) {
679  adtmp = z2->adoutbound;
680  z2->adoutbound = z1->adoutbound;
681  z1->adoutbound = adtmp;
682  adtmp = NULL;
683  }
684  return;
685 }
686 
687 
692 void
694 {
695  allocator_type* allocator;
696  lock_basic_type zone_lock;
697  lock_basic_type xfr_lock;
698  if (!zone) {
699  return;
700  }
701  allocator = zone->allocator;
702  zone_lock = zone->zone_lock;
703  xfr_lock = zone->xfr_lock;
704  ldns_rdf_deep_free(zone->apex);
705  adapter_cleanup(zone->adinbound);
707  namedb_cleanup(zone->db);
708  ixfr_cleanup(zone->ixfr);
709  xfrd_cleanup(zone->xfrd);
710  notify_cleanup(zone->notify);
711  signconf_cleanup(zone->signconf);
712  stats_cleanup(zone->stats);
713  allocator_deallocate(allocator, (void*) zone->notify_command);
714  allocator_deallocate(allocator, (void*) zone->notify_args);
715  allocator_deallocate(allocator, (void*) zone->policy_name);
716  allocator_deallocate(allocator, (void*) zone->signconf_filename);
717  allocator_deallocate(allocator, (void*) zone->name);
718  allocator_deallocate(allocator, (void*) zone);
719  allocator_cleanup(allocator);
720  lock_basic_destroy(&xfr_lock);
721  lock_basic_destroy(&zone_lock);
722  return;
723 }
724 
725 
732 {
733  char* filename = NULL;
734  FILE* fd = NULL;
735  const char* token = NULL;
736  time_t when = 0;
737  task_type* task = NULL;
738  ods_status status = ODS_STATUS_OK;
739  /* zone part */
740  int klass = 0;
741  uint32_t inbound = 0, internal = 0, outbound = 0;
742  /* signconf part */
743  time_t lastmod = 0;
744  /* nsec3params part */
745  const char* salt = NULL;
746 
747  ods_log_assert(zone);
748  ods_log_assert(zone->name);
749  ods_log_assert(zone->signconf);
750  ods_log_assert(zone->db);
751 
752  filename = ods_build_path(zone->name, ".backup2", 0, 1);
753  if (!filename) {
754  return ODS_STATUS_MALLOC_ERR;
755  }
756  fd = ods_fopen(filename, NULL, "r");
757  if (fd) {
758  /* start recovery */
759  if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC_V3)) {
760  ods_log_error("[%s] corrupted backup file zone %s: read magic "
761  "error", zone_str, zone->name);
762  goto recover_error2;
763  }
764  if (!backup_read_check_str(fd, ";;Time:") |
765  !backup_read_time_t(fd, &when)) {
766  ods_log_error("[%s] corrupted backup file zone %s: read time "
767  "error", zone_str, zone->name);
768  goto recover_error2;
769  }
770  /* zone stuff */
771  if (!backup_read_check_str(fd, ";;Zone:") |
772  !backup_read_check_str(fd, "name") |
773  !backup_read_check_str(fd, zone->name)) {
774  ods_log_error("[%s] corrupted backup file zone %s: read name "
775  "error", zone_str, zone->name);
776  goto recover_error2;
777  }
778  if (!backup_read_check_str(fd, "class") |
779  !backup_read_int(fd, &klass)) {
780  ods_log_error("[%s] corrupted backup file zone %s: read class "
781  "error", zone_str, zone->name);
782  goto recover_error2;
783  }
784  if (!backup_read_check_str(fd, "inbound") |
785  !backup_read_uint32_t(fd, &inbound) |
786  !backup_read_check_str(fd, "internal") |
787  !backup_read_uint32_t(fd, &internal) |
788  !backup_read_check_str(fd, "outbound") |
789  !backup_read_uint32_t(fd, &outbound)) {
790  ods_log_error("[%s] corrupted backup file zone %s: read serial "
791  "error", zone_str, zone->name);
792  goto recover_error2;
793  }
794  zone->klass = (ldns_rr_class) klass;
795  zone->db->inbserial = inbound;
796  zone->db->intserial = internal;
797  zone->db->outserial = outbound;
798  /* signconf part */
799  if (!backup_read_check_str(fd, ";;Signconf:") |
800  !backup_read_check_str(fd, "lastmod") |
801  !backup_read_time_t(fd, &lastmod) |
802  !backup_read_check_str(fd, "maxzonettl") |
803  !backup_read_check_str(fd, "0") |
804  !backup_read_check_str(fd, "resign") |
806  !backup_read_check_str(fd, "refresh") |
808  !backup_read_check_str(fd, "valid") |
810  !backup_read_check_str(fd, "denial") |
812  !backup_read_check_str(fd, "jitter") |
814  !backup_read_check_str(fd, "offset") |
816  !backup_read_check_str(fd, "nsec") |
817  !backup_read_rr_type(fd, &zone->signconf->nsec_type) |
818  !backup_read_check_str(fd, "dnskeyttl") |
820  !backup_read_check_str(fd, "soattl") |
821  !backup_read_duration(fd, &zone->signconf->soa_ttl) |
822  !backup_read_check_str(fd, "soamin") |
823  !backup_read_duration(fd, &zone->signconf->soa_min) |
824  !backup_read_check_str(fd, "serial") |
825  !backup_read_str(fd, &zone->signconf->soa_serial)) {
826  ods_log_error("[%s] corrupted backup file zone %s: read signconf "
827  "error", zone_str, zone->name);
828  goto recover_error2;
829  }
830  /* nsec3params part */
831  if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
832  if (!backup_read_check_str(fd, ";;Nsec3parameters:") |
833  !backup_read_check_str(fd, "salt") |
834  !backup_read_str(fd, &salt) |
835  !backup_read_check_str(fd, "algorithm") |
837  !backup_read_check_str(fd, "optout") |
838  !backup_read_int(fd, &zone->signconf->nsec3_optout) |
839  !backup_read_check_str(fd, "iterations") |
841  ods_log_error("[%s] corrupted backup file zone %s: read "
842  "nsec3parameters error", zone_str, zone->name);
843  goto recover_error2;
844  }
846  zone->signconf->allocator, salt);
847  free((void*) salt);
848  salt = NULL;
850  (void*) zone->signconf,
851  (uint8_t) zone->signconf->nsec3_algo,
852  (uint8_t) zone->signconf->nsec3_optout,
853  (uint16_t) zone->signconf->nsec3_iterations,
854  zone->signconf->nsec3_salt);
855  if (!zone->signconf->nsec3params) {
856  ods_log_error("[%s] corrupted backup file zone %s: unable to "
857  "create nsec3param", zone_str, zone->name);
858  goto recover_error2;
859  }
860  }
861  zone->signconf->last_modified = lastmod;
862  zone->default_ttl = (uint32_t) duration2time(zone->signconf->soa_min);
863  /* keys part */
864  zone->signconf->keys = keylist_create((void*) zone->signconf);
865  while (backup_read_str(fd, &token)) {
866  if (ods_strcmp(token, ";;Key:") == 0) {
867  if (!key_recover2(fd, zone->signconf->keys)) {
868  ods_log_error("[%s] corrupted backup file zone %s: read "
869  "key error", zone_str, zone->name);
870  goto recover_error2;
871  }
872  } else if (ods_strcmp(token, ";;") == 0) {
873  /* keylist done */
874  free((void*) token);
875  token = NULL;
876  break;
877  } else {
878  /* keylist corrupted */
879  goto recover_error2;
880  }
881  free((void*) token);
882  token = NULL;
883  }
884  /* publish dnskeys */
885  status = zone_publish_dnskeys(zone);
886  if (status != ODS_STATUS_OK) {
887  ods_log_error("[%s] corrupted backup file zone %s: unable to "
888  "publish dnskeys (%s)", zone_str, zone->name,
889  ods_status2str(status));
890  goto recover_error2;
891  }
892  /* publish nsec3param */
893  status = zone_publish_nsec3param(zone);
894  if (status != ODS_STATUS_OK) {
895  ods_log_error("[%s] corrupted backup file zone %s: unable to "
896  "publish nsec3param (%s)", zone_str, zone->name,
897  ods_status2str(status));
898  goto recover_error2;
899  }
900  /* publish other records */
901  status = backup_read_namedb(fd, zone);
902  if (status != ODS_STATUS_OK) {
903  ods_log_error("[%s] corrupted backup file zone %s: unable to "
904  "read resource records (%s)", zone_str, zone->name,
905  ods_status2str(status));
906  goto recover_error2;
907  }
908  /* task */
909  task = task_create(TASK_SIGN, when, (void*) zone);
910  if (!task) {
911  ods_log_error("[%s] failed to restore zone %s: unable to "
912  "create task", zone_str, zone->name);
913  goto recover_error2;
914  }
915  zone->task = (void*) task;
916  free((void*)filename);
917  ods_fclose(fd);
918  /* journal */
919  zone->db->is_initialized = 1;
920 
921  filename = ods_build_path(zone->name, ".ixfr", 0, 1);
922  if (filename) {
923  fd = ods_fopen(filename, NULL, "r");
924  }
925  if (fd) {
926  status = backup_read_ixfr(fd, zone);
927  if (status != ODS_STATUS_OK) {
928  ods_log_warning("[%s] corrupted journal file zone %s, "
929  "skipping (%s)", zone_str, zone->name,
930  ods_status2str(status));
931  ixfr_cleanup(zone->ixfr);
932  zone->ixfr = ixfr_create((void*)zone);
933  }
934  }
935  lock_basic_lock(&zone->ixfr->ixfr_lock);
936  ixfr_purge(zone->ixfr);
938 
939  /* all ok */
940  free((void*)filename);
941  ods_fclose(fd);
942  if (zone->stats) {
944  stats_clear(zone->stats);
946  }
947  return ODS_STATUS_OK;
948  }
949  return ODS_STATUS_UNCHANGED;
950 
951 recover_error2:
952  free((void*)filename);
953  ods_fclose(fd);
954  /* signconf cleanup */
955  free((void*)salt);
956  salt = NULL;
957  signconf_cleanup(zone->signconf);
958  zone->signconf = signconf_create();
959  ods_log_assert(zone->signconf);
960  /* namedb cleanup */
961  namedb_cleanup(zone->db);
962  zone->db = namedb_create((void*)zone);
963  ods_log_assert(zone->db);
964  /* stats reset */
965  if (zone->stats) {
967  stats_clear(zone->stats);
969  }
970  return ODS_STATUS_ERR;
971 }
972 
973 
980 {
981  char* filename = NULL;
982  char* tmpfile = NULL;
983  FILE* fd = NULL;
984  task_type* task = NULL;
985  int ret = 0;
986  ods_status status = ODS_STATUS_OK;
987 
988  ods_log_assert(zone);
989  ods_log_assert(zone->name);
990  ods_log_assert(zone->db);
991  ods_log_assert(zone->signconf);
992  ods_log_assert(zone->task);
993 
994  tmpfile = ods_build_path(zone->name, ".backup2.tmp", 0, 1);
995  filename = ods_build_path(zone->name, ".backup2", 0, 1);
996  if (!tmpfile || !filename) {
997  return ODS_STATUS_MALLOC_ERR;
998  }
999  fd = ods_fopen(tmpfile, NULL, "w");
1000  if (fd) {
1001  fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC_V3);
1002  task = (task_type*) zone->task;
1003  fprintf(fd, ";;Time: %u\n", (unsigned) task->when);
1005  fprintf(fd, ";;Zone: name %s class %i inbound %u internal %u "
1006  "outbound %u\n", zone->name, (int) zone->klass,
1007  (unsigned) zone->db->inbserial,
1008  (unsigned) zone->db->intserial,
1009  (unsigned) zone->db->outserial);
1011  signconf_backup(fd, zone->signconf, ODS_SE_FILE_MAGIC_V3);
1013  if (zone->signconf->nsec3params) {
1014  nsec3params_backup(fd,
1015  zone->signconf->nsec3_algo,
1016  zone->signconf->nsec3_optout,
1017  zone->signconf->nsec3_iterations,
1018  zone->signconf->nsec3_salt,
1019  zone->signconf->nsec3params->rr,
1020  ODS_SE_FILE_MAGIC_V3);
1021  }
1023  keylist_backup(fd, zone->signconf->keys, ODS_SE_FILE_MAGIC_V3);
1024  fprintf(fd, ";;\n");
1026  namedb_backup2(fd, zone->db);
1028  fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC_V3);
1029  ods_fclose(fd);
1030  ret = rename(tmpfile, filename);
1031  if (ret != 0) {
1032  ods_log_error("[%s] unable to rename zone %s backup %s to %s: %s",
1033  zone_str, zone->name, tmpfile, filename, strerror(errno));
1034  status = ODS_STATUS_RENAME_ERR;
1035  }
1036  } else {
1037  status = ODS_STATUS_FOPEN_ERR;
1038  }
1039 
1040  free((void*) tmpfile);
1041  free((void*) filename);
1042  return status;
1043 }