OpenDNSSEC-signer  1.3.14
adfile.c
Go to the documentation of this file.
1 /*
2  * $Id: adfile.c 6244 2012-04-03 13:56:27Z 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/adapi.h"
36 #include "adapter/adfile.h"
37 #include "adapter/adutil.h"
38 #include "shared/duration.h"
39 #include "shared/file.h"
40 #include "shared/log.h"
41 #include "shared/status.h"
42 #include "shared/util.h"
43 #include "signer/zone.h"
44 
45 #include <ldns/ldns.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 
49 static const char* adapter_str = "adapter";
50 static ods_status adfile_read_file(FILE* fd, zone_type* zone);
51 
52 
59 {
60  /* nothing to initialize */
61  return ODS_STATUS_OK;
62 }
63 
64 
69 static ldns_rr*
70 adfile_read_rr(FILE* fd, zone_type* zone, char* line, ldns_rdf** orig,
71  ldns_rdf** prev, uint32_t* ttl, ldns_status* status, unsigned int* l)
72 {
73  ldns_rr* rr = NULL;
74  ldns_rdf* tmp = NULL;
75  FILE* fd_include = NULL;
76  int len = 0;
78  uint32_t new_ttl = 0;
79  const char *endptr; /* unused */
80  int offset = 0;
81 
82 adfile_read_line:
83  if (ttl) {
84  new_ttl = *ttl;
85  }
86 
87  len = adutil_readline_frm_file(fd, line, l);
88  adutil_rtrim_line(line, &len);
89 
90  if (len >= 0) {
91  switch (line[0]) {
92  /* directive */
93  case '$':
94  if (strncmp(line, "$ORIGIN", 7) == 0 && isspace(line[7])) {
95  /* copy from ldns */
96  if (*orig) {
97  ldns_rdf_deep_free(*orig);
98  *orig = NULL;
99  }
100  offset = 8;
101  while (isspace(line[offset])) {
102  offset++;
103  }
104  tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME,
105  line + offset);
106  if (!tmp) {
107  /* could not parse what next to $ORIGIN */
108  *status = LDNS_STATUS_SYNTAX_DNAME_ERR;
109  return NULL;
110  }
111  *orig = tmp;
112  /* end copy from ldns */
113  goto adfile_read_line; /* perhaps next line is rr */
114  break;
115  } else if (strncmp(line, "$TTL", 4) == 0 &&
116  isspace(line[4])) {
117  /* override default ttl */
118  offset = 5;
119  while (isspace(line[offset])) {
120  offset++;
121  }
122  if (ttl) {
123  *ttl = ldns_str2period(line + offset, &endptr);
124  new_ttl = *ttl;
125  }
126  goto adfile_read_line; /* perhaps next line is rr */
127  break;
128  } else if (strncmp(line, "$INCLUDE", 8) == 0 &&
129  isspace(line[8])) {
130  /* dive into this file */
131  offset = 9;
132  while (isspace(line[offset])) {
133  offset++;
134  }
135  fd_include = ods_fopen(line + offset, NULL, "r");
136  if (fd_include) {
137  s = adfile_read_file(fd_include, zone);
138  ods_fclose(fd_include);
139  } else {
140  ods_log_error("[%s] unable to open include file %s",
141  adapter_str, (line+offset));
142  *status = LDNS_STATUS_SYNTAX_ERR;
143  return NULL;
144  }
145  if (s != ODS_STATUS_OK) {
146  *status = LDNS_STATUS_SYNTAX_ERR;
147  ods_log_error("[%s] error in include file %s",
148  adapter_str, (line+offset));
149  return NULL;
150  }
151  /* restore current ttl */
152  if (ttl) {
153  *ttl = new_ttl;
154  }
155  goto adfile_read_line; /* perhaps next line is rr */
156  break;
157  }
158  goto adfile_read_rr; /* this can be an owner name */
159  break;
160  /* comments, empty lines */
161  case ';':
162  case '\n':
163  goto adfile_read_line; /* perhaps next line is rr */
164  break;
165  /* let's hope its a RR */
166  default:
167 adfile_read_rr:
168  if (adutil_whitespace_line(line, len)) {
169  goto adfile_read_line; /* perhaps next line is rr */
170  break;
171  }
172 
173  *status = ldns_rr_new_frm_str(&rr, line, new_ttl, *orig, prev);
174  if (*status == LDNS_STATUS_OK) {
175  ldns_rr2canonical(rr); /* TODO: canonicalize or not? */
176  return rr;
177  } else if (*status == LDNS_STATUS_SYNTAX_EMPTY) {
178  if (rr) {
179  ldns_rr_free(rr);
180  rr = NULL;
181  }
182  *status = LDNS_STATUS_OK;
183  goto adfile_read_line; /* perhaps next line is rr */
184  break;
185  } else {
186  ods_log_error("[%s] error parsing RR at line %i (%s): %s",
187  adapter_str, l&&*l?*l:0,
188  ldns_get_errorstr_by_id(*status), line);
189  while (len >= 0) {
190  len = adutil_readline_frm_file(fd, line, l);
191  }
192  if (rr) {
193  ldns_rr_free(rr);
194  rr = NULL;
195  }
196  return NULL;
197  }
198  break;
199  }
200  }
201 
202  /* -1, EOF */
203  *status = LDNS_STATUS_OK;
204  return NULL;
205 }
206 
207 
212 static ods_status
213 adfile_read_file(FILE* fd, zone_type* zone)
214 {
215  ods_status result = ODS_STATUS_OK;
216  ldns_rr* rr = NULL;
217  ldns_rdf* prev = NULL;
218  ldns_rdf* orig = NULL;
219  ldns_rdf* dname = NULL;
220  uint32_t ttl = 0;
221  ldns_status status = LDNS_STATUS_OK;
222  char line[SE_ADFILE_MAXLINE];
223  unsigned int line_update_interval = 100000;
224  unsigned int line_update = line_update_interval;
225  unsigned int l = 0;
226 
227  ods_log_assert(fd);
228  ods_log_assert(zone);
229 
230  /* $ORIGIN <zone name> */
231  dname = adapi_get_origin(zone);
232  if (!dname) {
233  ods_log_error("[%s] error getting default value for $ORIGIN",
234  adapter_str);
235  return ODS_STATUS_ERR;
236  }
237  orig = ldns_rdf_clone(dname);
238  if (!orig) {
239  ods_log_error("[%s] error setting default value for $ORIGIN",
240  adapter_str);
241  return ODS_STATUS_ERR;
242  }
243 
244  /* $TTL <default ttl> */
245  ttl = adapi_get_ttl(zone);
246 
247  /* read RRs */
248  while ((rr = adfile_read_rr(fd, zone, line, &orig, &prev, &ttl,
249  &status, &l)) != NULL) {
250 
251  if (status != LDNS_STATUS_OK) {
252  ods_log_error("[%s] error reading RR at line %i (%s): %s",
253  adapter_str, l, ldns_get_errorstr_by_id(status), line);
254  result = ODS_STATUS_ERR;
255  break;
256  }
257 
258  if (l > line_update) {
259  ods_log_debug("[%s] ...at line %i: %s", adapter_str, l, line);
260  line_update += line_update_interval;
261  }
262 
263  /* filter out DNSSEC RRs (except DNSKEY) from the Input File Adapter */
264  if (util_is_dnssec_rr(rr)) {
265  ldns_rr_free(rr);
266  rr = NULL;
267  continue;
268  }
269 
270  /* add to the zonedata */
271  result = adapi_add_rr(zone, rr);
272  if (result != ODS_STATUS_OK) {
273  ods_log_error("[%s] error adding RR at line %i: %s",
274  adapter_str, l, line);
275  break;
276  }
277  }
278 
279  /* and done */
280  if (orig) {
281  ldns_rdf_deep_free(orig);
282  orig = NULL;
283  }
284  if (prev) {
285  ldns_rdf_deep_free(prev);
286  prev = NULL;
287  }
288 
289  if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) {
290  ods_log_error("[%s] error reading RR at line %i (%s): %s",
291  adapter_str, l, ldns_get_errorstr_by_id(status), line);
292  result = ODS_STATUS_ERR;
293  }
294  return result;
295 }
296 
297 
303 adfile_read(struct zone_struct* zone, const char* filename)
304 {
305  FILE* fd = NULL;
306  zone_type* adzone = (zone_type*) zone;
307  ods_status status = ODS_STATUS_OK;
308  uint32_t new_serial = 0;
309  ldns_rr* rr = NULL;
310 
311  /* [start] sanity parameter checking */
312  if (!adzone) {
313  ods_log_error("[%s] unable to read file: no zone (or no name given)",
314  adapter_str);
315  return ODS_STATUS_ASSERT_ERR;
316  }
317  ods_log_assert(adzone);
318  if (!filename) {
319  ods_log_error("[%s] unable to read file: no filename given",
320  adapter_str);
321  return ODS_STATUS_ASSERT_ERR;
322  }
323  ods_log_assert(filename);
324  /* [end] sanity parameter checking */
325 
326  /* [start] read zone */
327  fd = ods_fopen(filename, NULL, "r");
328  if (fd) {
329  /* serial */
330  rr = adutil_lookup_soa_rr(fd);
331  if (rr) {
332  new_serial =
333  ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
334  }
335  ldns_rr_free(rr);
336  rewind(fd);
337 
338  status = adfile_read_file(fd, adzone);
339  ods_fclose(fd);
340  } else {
341  status = ODS_STATUS_FOPEN_ERR;
342  }
343  if (status != ODS_STATUS_OK) {
344  ods_log_error("[%s] unable to read file %s: %s", adapter_str,
345  filename, ods_status2str(status));
346  return status;
347  }
348  /* [end] read zone */
349 
350  /* [start] full transaction */
351  status = adapi_trans_full(adzone);
352  if (status != ODS_STATUS_OK) {
353  ods_log_error("[%s] unable to read file: start transaction failed",
354  adapter_str);
355  return status;
356  }
357  /* [end] full transaction */
358 
359  /* [start] validate updates */
360  status = zone_examine(adzone);
361  if (status != ODS_STATUS_OK) {
362  ods_log_error("[%s] unable to read file: zonefile contains errors",
363  adapter_str);
364  return status;
365  }
366  /* [end] validate updates */
367  adapi_set_serial(adzone, new_serial);
368  return ODS_STATUS_OK;
369 }
370 
371 
377 adbackup_read(struct zone_struct* zone, const char* filename)
378 {
379  FILE* fd = NULL;
380  zone_type* adzone = (zone_type*) zone;
381  ods_status status = ODS_STATUS_OK;
382 
383  /* [start] sanity parameter checking */
384  if (!adzone) {
385  ods_log_error("[%s] unable to read file: no zone (or no name given)",
386  adapter_str);
387  return ODS_STATUS_ASSERT_ERR;
388  }
389  ods_log_assert(adzone);
390  if (!filename) {
391  ods_log_error("[%s] unable to read file: no filename given",
392  adapter_str);
393  return ODS_STATUS_ASSERT_ERR;
394  }
395  ods_log_assert(filename);
396  /* [end] sanity parameter checking */
397 
398  /* [start] read zone */
399  fd = ods_fopen(filename, NULL, "r");
400  if (fd) {
401  status = adfile_read_file(fd, adzone);
402  ods_fclose(fd);
403  } else {
404  status = ODS_STATUS_FOPEN_ERR;
405  }
406  if (status != ODS_STATUS_OK) {
407  ods_log_error("[%s] unable to recover file: %s", adapter_str,
408  ods_status2str(status));
409  return status;
410  }
411  /* [end] read zone */
412 
413  /* [start] full transaction */
414  status = adapi_trans_full(adzone);
415  if (status != ODS_STATUS_OK) {
416  ods_log_error("[%s] unable to recover file: start transaction failed",
417  adapter_str);
418  return status;
419  }
420  /* [end] full transaction */
421  return ODS_STATUS_OK;
422 }
423 
424 
430 adfile_write(struct zone_struct* zone, const char* filename)
431 {
432  FILE* fd = NULL;
433  char* tmpname = NULL;
434  zone_type* adzone = (zone_type*) zone;
435  ods_status status = ODS_STATUS_OK;
436 
437  /* [start] sanity parameter checking */
438  if (!adzone) {
439  ods_log_error("[%s] unable to write file: no zone (or no "
440  "name given)", adapter_str);
441  return ODS_STATUS_ASSERT_ERR;
442  }
443  ods_log_assert(adzone);
444  if (!filename) {
445  ods_log_error("[%s] unable to write file: no filename given",
446  adapter_str);
447  return ODS_STATUS_ERR;
448  }
449  ods_log_assert(filename);
450  /* [end] sanity parameter checking */
451 
452  /* [start] write zone */
453  tmpname = ods_build_path(filename, ".tmp", 0, 0);
454  fd = ods_fopen(tmpname, NULL, "w");
455  if (fd) {
456  status = zone_print(fd, adzone);
457  ods_fclose(fd);
458  } else {
459  status = ODS_STATUS_FOPEN_ERR;
460  }
461  if (status == ODS_STATUS_OK) {
462  if (rename((const char*) tmpname, filename) != 0) {
463  ods_log_error("[%s] unable to write file: failed to rename %s "
464  "to %s (%s)", adapter_str, tmpname, filename, strerror(errno));
465  status = ODS_STATUS_RENAME_ERR;
466  }
467  }
468  free(tmpname);
469  /* [end] write zone */
470 
471  return status;
472 }