OpenDNSSEC-signer  1.3.9
tools.c
Go to the documentation of this file.
1 /*
2  * $Id: tools.c 6318 2012-05-09 08:56:43Z 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 "config.h"
35 #include "adapter/adapter.h"
36 #include "shared/file.h"
37 #include "shared/log.h"
38 #include "signer/tools.h"
39 #include "signer/zone.h"
40 
41 static const char* tools_str = "tools";
42 
43 
50 {
51  ods_status status = ODS_STATUS_OK;
52  char* tmpname = NULL;
53  char* lockname = NULL;
54  time_t start = 0;
55  time_t end = 0;
56  FILE* fd = NULL;
57 
58  if (!zone) {
59  ods_log_error("[%s] unable to read zone: no zone", tools_str);
60  return ODS_STATUS_ASSERT_ERR;
61  }
62  ods_log_assert(zone);
63 
64  if (!zone->zonedata) {
65  ods_log_error("[%s] unable to read zone: no zone data", tools_str);
66  return ODS_STATUS_ASSERT_ERR;
67  }
68  ods_log_assert(zone->zonedata);
69 
71  ods_log_assert(zone->signconf);
72 
73  if (zone->stats) {
75  zone->stats->sort_done = 0;
76  zone->stats->sort_count = 0;
77  zone->stats->sort_time = 0;
79  }
80 
81  if (zone->adinbound->type == ADAPTER_FILE) {
82  if (zone->fetch) {
83  ods_log_verbose("[%s] fetch zone %s", tools_str,
84  zone->name?zone->name:"(null)");
85  tmpname = ods_build_path(
86  zone->adinbound->configstr, ".axfr", 0, 0);
87  lockname = ods_build_path(
88  zone->adinbound->configstr, ".lock", 0, 0);
89 
90 lock_fetch:
91  if (access(lockname, F_OK) == 0) {
92  ods_log_deeebug("[%s] axfr file %s is locked, "
93  "waiting...", tools_str, tmpname);
94  sleep(1);
95  goto lock_fetch;
96  } else {
97  fd = fopen(lockname, "w");
98  if (!fd) {
99  ods_log_error("[%s] cannot lock AXFR file %s",
100  tools_str, lockname);
101  free((void*)tmpname);
102  free((void*)lockname);
103  return ODS_STATUS_ERR;
104  }
105  }
106  ods_log_assert(fd); /* locked */
107 
108  status = ods_file_copy(tmpname, zone->adinbound->configstr);
109 
110  fclose(fd);
111  (void) unlink(lockname); /* unlocked */
112 
113  if (status != ODS_STATUS_OK) {
114  ods_log_error("[%s] unable to copy axfr file %s to %s: %s",
115  tools_str, tmpname, zone->adinbound->configstr,
116  ods_status2str(status));
117  free((void*)tmpname);
118  free((void*)lockname);
119  return status;
120  }
121  free((void*)tmpname);
122  free((void*)lockname);
123  }
124  }
125 
126  start = time(NULL);
127  status = adapter_read(zone);
128  if (status != ODS_STATUS_OK) {
129  ods_log_error("[%s] unable to read from input adapter for zone %s: "
130  "%s", tools_str, zone->name?zone->name:"(null)",
131  ods_status2str(status));
132  } else {
133  tmpname = ods_build_path(zone->name, ".inbound", 0, 1);
134  status = ods_file_copy(zone->adinbound->configstr, tmpname);
135  if (status != ODS_STATUS_OK) {
136  ods_log_error("[%s] unable to copy zone input file %s: %s",
137  tools_str, tmpname, ods_status2str(status));
138  }
139  free((void*)tmpname);
140  tmpname = NULL;
141  }
142 
143  if (status == ODS_STATUS_OK) {
144  ods_log_verbose("[%s] commit updates for zone %s", tools_str,
145  zone->name?zone->name:"(null)");
146  status = zonedata_commit(zone->zonedata);
147  } else {
148  ods_log_warning("[%s] rollback updates for zone %s", tools_str,
149  zone->name?zone->name:"(null)");
151  }
152  end = time(NULL);
153 
154  if (status == ODS_STATUS_OK && zone->stats) {
156  zone->stats->start_time = start;
157  zone->stats->sort_time = (end-start);
158  zone->stats->sort_done = 1;
160  }
161  return status;
162 }
163 
164 
171 {
172  ods_status status = ODS_STATUS_OK;
173  time_t start = 0;
174  time_t end = 0;
175  uint32_t ttl = 0;
176  uint32_t num_added = 0;
177 
178  if (!zone) {
179  ods_log_error("[%s] unable to nsecify zone: no zone", tools_str);
180  return ODS_STATUS_ASSERT_ERR;
181  }
182  ods_log_assert(zone);
183 
184  if (!zone->zonedata) {
185  ods_log_error("[%s] unable to nsecify zone %s: no zonedata",
186  tools_str, zone->name);
187  return ODS_STATUS_ASSERT_ERR;
188  }
189  ods_log_assert(zone->zonedata);
190 
191  if (!zone->signconf) {
192  ods_log_error("[%s] unable to nsecify zone %s: no signconf",
193  tools_str, zone->name);
194  return ODS_STATUS_ASSERT_ERR;
195  }
196  ods_log_assert(zone->signconf);
197 
198  if (zone->stats) {
200  zone->stats->nsec_time = 0;
201  zone->stats->nsec_count = 0;
203  }
204 
205  start = time(NULL);
206  /* determine denial ttl */
207  ttl = zone->zonedata->default_ttl;
208  if (zone->signconf->soa_min) {
209  ttl = (uint32_t) duration2time(zone->signconf->soa_min);
210  }
211  /* add missing empty non-terminals */
212  status = zonedata_entize(zone->zonedata, zone->dname);
213  if (status != ODS_STATUS_OK) {
214  ods_log_error("[%s] unable to nsecify zone %s: failed to add empty ",
215  "non-terminals", tools_str, zone->name);
216  return status;
217  }
218  /* nsecify(3) */
219  if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC) {
220  status = zonedata_nsecify(zone->zonedata, zone->klass, ttl,
221  &num_added);
222  } else if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
223  if (zone->signconf->nsec3_optout) {
224  ods_log_debug("[%s] OptOut is being used for zone %s",
225  tools_str, zone->name);
226  }
228  status = zonedata_nsecify3(zone->zonedata, zone->klass, ttl,
229  zone->nsec3params, &num_added);
230  } else {
231  ods_log_error("[%s] unable to nsecify zone %s: unknown RRtype %u for ",
232  "denial of existence", tools_str, zone->name,
233  (unsigned) zone->signconf->nsec_type);
234  return ODS_STATUS_ERR;
235  }
236  end = time(NULL);
237  if (status == ODS_STATUS_OK && zone->stats) {
239  if (!zone->stats->start_time) {
240  zone->stats->start_time = start;
241  }
242  zone->stats->nsec_time = (end-start);
243  zone->stats->nsec_count = num_added;
245  }
246  return status;
247 }
248 
249 
255 tools_audit(zone_type* zone, char* working_dir, char* cfg_filename)
256 {
257  ods_status status = ODS_STATUS_OK;
258 #ifdef HAVE_AUDITOR
259  char* inbound = NULL;
260  char* finalized = NULL;
261  char str[SYSTEM_MAXLEN];
262  int error = 0;
263  time_t start = 0;
264  time_t end = 0;
265 
266  if (!zone) {
267  ods_log_error("[%s] unable to audit zone: no zone", tools_str);
268  return ODS_STATUS_ASSERT_ERR;
269  }
270  ods_log_assert(zone);
271 
272  if (!zone->signconf) {
273  ods_log_error("[%s] unable to audit zone %s: no signconf",
274  tools_str, zone->name?zone->name:"(null)");
275  return ODS_STATUS_ASSERT_ERR;
276  }
277  ods_log_assert(zone->signconf);
278 
279  if (zone->stats) {
281  if (zone->stats->sort_done == 0 &&
282  (zone->stats->sig_count <= zone->stats->sig_soa_count)) {
284  return ODS_STATUS_OK;
285  }
287  }
288 
289  if (zone->signconf->audit) {
290  inbound = ods_build_path(zone->name, ".inbound", 0, 1);
291  finalized = ods_build_path(zone->name, ".finalized", 0, 1);
292  status = adfile_write(zone, finalized);
293  if (status != ODS_STATUS_OK) {
294  ods_log_error("[%s] audit zone %s failed: unable to write zone",
295  tools_str, finalized);
296  free((void*)inbound);
297  free((void*)finalized);
298  return status;
299  }
300 
301  snprintf(str, SYSTEM_MAXLEN, "%s -c %s -u %s/%s -s %s/%s -z %s > /dev/null",
302  ODS_SE_AUDITOR,
303  cfg_filename?cfg_filename:ODS_SE_CFGFILE,
304  working_dir?working_dir:"",
305  inbound?inbound:"(null)",
306  working_dir?working_dir:"",
307  finalized?finalized:"(null)",
308  zone->name?zone->name:"(null)");
309 
310  start = time(NULL);
311  ods_log_debug("system call: %s", str);
312  error = system(str);
313  if (finalized) {
314  if (!error) {
315  unlink(finalized);
316  }
317  free((void*)finalized);
318  }
319  free((void*)inbound);
320 
321  if (error) {
322  ods_log_error("[%s] audit failed for zone %s", tools_str,
323  zone->name);
324  status = ODS_STATUS_ERR;
325  } else {
326  ods_log_info("[%s] audit passed for zone %s", tools_str,
327  zone->name);
328  }
329  end = time(NULL);
330  if (status == ODS_STATUS_OK && zone->stats) {
332  zone->stats->audit_time = (end-start);
334  }
335  }
336 #else
337  ods_log_error("[%s] unable to audit zone %s: ods-auditor not installed",
338  tools_str, zone->name?zone->name:"(null)");
339  status = ODS_STATUS_ERR;
340 #endif
341  return status;
342 }
343 
344 
351 {
352  ods_status status = ODS_STATUS_OK;
353  char str[SYSTEM_MAXLEN];
354  int error = 0;
355  uint32_t outbound_serial = 0;
356 
357  if (!zone) {
358  ods_log_error("[%s] unable to write zone: no zone", tools_str);
359  return ODS_STATUS_ASSERT_ERR;
360  }
361  ods_log_assert(zone);
362 
363  if (!zone->adoutbound) {
364  ods_log_error("[%s] unable to write zone %s: no outbound adapter",
365  tools_str, zone->name?zone->name:"(null)");
366  return ODS_STATUS_ASSERT_ERR;
367  }
368  ods_log_assert(zone->adoutbound);
369 
370  if (zone->stats) {
372  if (zone->stats->sort_done == 0 &&
373  (zone->stats->sig_count <= zone->stats->sig_soa_count)) {
374  ods_log_verbose("[%s] skip write zone %s serial %u (zone not "
375  "changed)", tools_str, zone->name?zone->name:"(null)",
376  zone->zonedata->internal_serial);
377  stats_clear(zone->stats);
379  zone->zonedata->internal_serial =
380  zone->zonedata->outbound_serial;
381  return ODS_STATUS_OK;
382  }
384  }
385 
386  outbound_serial = zone->zonedata->outbound_serial;
388  status = adapter_write(zone);
389  if (status != ODS_STATUS_OK) {
390  ods_log_error("[%s] unable to write zone %s: adapter failed (%s)",
391  tools_str, zone->name, ods_status2str(status));
392  zone->zonedata->outbound_serial = outbound_serial;
393  return status;
394  }
395 
396  /* initialize zonedata */
397  zone->zonedata->initialized = 1;
398 
399  /* kick the nameserver */
400  if (zone->notify_ns) {
401  ods_log_verbose("[%s] notify nameserver: %s", tools_str,
402  zone->notify_ns);
403  snprintf(str, SYSTEM_MAXLEN, "%s > /dev/null",
404  zone->notify_ns);
405  error = system(str);
406  if (error) {
407  ods_log_error("[%s] failed to notify nameserver", tools_str);
408  status = ODS_STATUS_ERR;
409  }
410  }
411  /* log stats */
412  if (zone->stats) {
414  zone->stats->end_time = time(NULL);
415  ods_log_debug("[%s] log stats for zone %s", tools_str,
416  zone->name?zone->name:"(null)");
417  stats_log(zone->stats, zone->name, zone->signconf->nsec_type);
418  stats_clear(zone->stats);
420  }
421  return status;
422 }