OpenDNSSEC-signer  2.0.2
adfile.c
Go to the documentation of this file.
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 
32 #include "config.h"
33 #include "adapter/adapi.h"
34 #include "adapter/adapter.h"
35 #include "adapter/adfile.h"
36 #include "adapter/adutil.h"
37 #include "duration.h"
38 #include "file.h"
39 #include "log.h"
40 #include "status.h"
41 #include "util.h"
42 #include "signer/zone.h"
43 
44 #include <ldns/ldns.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 
48 static const char* adapter_str = "adapter";
49 static ods_status adfile_read_file(FILE* fd, zone_type* zone);
50 
51 
56 static ldns_rr*
57 adfile_read_rr(FILE* fd, zone_type* zone, char* line, ldns_rdf** orig,
58  ldns_rdf** prev, uint32_t* ttl, ldns_status* status, unsigned int* l)
59 {
60  ldns_rr* rr = NULL;
61  ldns_rdf* tmp = NULL;
62  FILE* fd_include = NULL;
63  int len = 0;
64  ods_status s = ODS_STATUS_OK;
65  uint32_t new_ttl = 0;
66  const char *endptr; /* unused */
67  int offset = 0;
68 
69 adfile_read_line:
70  if (ttl) {
71  new_ttl = *ttl;
72  }
73  len = adutil_readline_frm_file(fd, line, l, 0);
74  adutil_rtrim_line(line, &len);
75  if (len >= 0) {
76  switch (line[0]) {
77  /* directive */
78  case '$':
79  if (strncmp(line, "$ORIGIN", 7) == 0 && isspace((int)line[7])) {
80  /* copy from ldns */
81  if (*orig) {
82  ldns_rdf_deep_free(*orig);
83  *orig = NULL;
84  }
85  offset = 8;
86  while (isspace((int)line[offset])) {
87  offset++;
88  }
89  tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME,
90  line + offset);
91  if (!tmp) {
92  /* could not parse what next to $ORIGIN */
93  *status = LDNS_STATUS_SYNTAX_DNAME_ERR;
94  return NULL;
95  }
96  *orig = tmp;
97  /* end copy from ldns */
98  goto adfile_read_line; /* perhaps next line is rr */
99  break;
100  } else if (strncmp(line, "$TTL", 4) == 0 &&
101  isspace((int)line[4])) {
102  /* override default ttl */
103  offset = 5;
104  while (isspace((int)line[offset])) {
105  offset++;
106  }
107  if (ttl) {
108  *ttl = ldns_str2period(line + offset, &endptr);
109  new_ttl = *ttl;
110  }
111  goto adfile_read_line; /* perhaps next line is rr */
112  break;
113  } else if (strncmp(line, "$INCLUDE", 8) == 0 &&
114  isspace((int)line[8])) {
115  /* dive into this file */
116  offset = 9;
117  while (isspace((int)line[offset])) {
118  offset++;
119  }
120  fd_include = ods_fopen(line + offset, NULL, "r");
121  if (fd_include) {
122  s = adfile_read_file(fd_include, zone);
123  ods_fclose(fd_include);
124  } else {
125  ods_log_error("[%s] unable to open include file %s",
126  adapter_str, (line+offset));
127  *status = LDNS_STATUS_SYNTAX_ERR;
128  return NULL;
129  }
130  if (s != ODS_STATUS_OK) {
131  *status = LDNS_STATUS_SYNTAX_ERR;
132  ods_log_error("[%s] error in include file %s",
133  adapter_str, (line+offset));
134  return NULL;
135  }
136  /* restore current ttl */
137  if (ttl) {
138  *ttl = new_ttl;
139  }
140  goto adfile_read_line; /* perhaps next line is rr */
141  break;
142  }
143  goto adfile_read_rr; /* this can be an owner name */
144  break;
145  /* comments, empty lines */
146  case ';':
147  case '\n':
148  goto adfile_read_line; /* perhaps next line is rr */
149  break;
150  /* let's hope its a RR */
151  default:
152 adfile_read_rr:
153  if (adutil_whitespace_line(line, len)) {
154  goto adfile_read_line; /* perhaps next line is rr */
155  break;
156  }
157  *status = ldns_rr_new_frm_str(&rr, line, new_ttl, *orig, prev);
158  if (*status == LDNS_STATUS_OK) {
159  return rr;
160  } else if (*status == LDNS_STATUS_SYNTAX_EMPTY) {
161  if (rr) {
162  ldns_rr_free(rr);
163  rr = NULL;
164  }
165  *status = LDNS_STATUS_OK;
166  goto adfile_read_line; /* perhaps next line is rr */
167  break;
168  } else {
169  ods_log_error("[%s] error parsing RR at line %i (%s): %s",
170  adapter_str, l&&*l?*l:0,
171  ldns_get_errorstr_by_id(*status), line);
172  while (len >= 0) {
173  len = adutil_readline_frm_file(fd, line, l, 0);
174  }
175  if (rr) {
176  ldns_rr_free(rr);
177  rr = NULL;
178  }
179  return NULL;
180  }
181  break;
182  }
183  }
184  /* -1, EOF */
185  *status = LDNS_STATUS_OK;
186  return NULL;
187 }
188 
189 
194 static ods_status
195 adfile_read_file(FILE* fd, zone_type* zone)
196 {
197  ods_status result = ODS_STATUS_OK;
198  ldns_rr* rr = NULL;
199  ldns_rdf* prev = NULL;
200  ldns_rdf* orig = NULL;
201  ldns_rdf* dname = NULL;
202  uint32_t ttl = 0;
203  uint32_t new_serial = 0;
204  ldns_status status = LDNS_STATUS_OK;
205  char line[SE_ADFILE_MAXLINE];
206  unsigned int line_update_interval = 100000;
207  unsigned int line_update = line_update_interval;
208  unsigned int l = 0;
209 
210  ods_log_assert(fd);
211  ods_log_assert(zone);
212 
213  /* $ORIGIN <zone name> */
214  dname = adapi_get_origin(zone);
215  if (!dname) {
216  ods_log_error("[%s] error getting default value for $ORIGIN",
217  adapter_str);
218  return ODS_STATUS_ERR;
219  }
220  orig = ldns_rdf_clone(dname);
221  if (!orig) {
222  ods_log_error("[%s] error setting default value for $ORIGIN",
223  adapter_str);
224  return ODS_STATUS_ERR;
225  }
226  /* $TTL <default ttl> */
227  ttl = adapi_get_ttl(zone);
228  /* read RRs */
229  while ((rr = adfile_read_rr(fd, zone, line, &orig, &prev, &ttl,
230  &status, &l)) != NULL) {
231  /* check status */
232  if (status != LDNS_STATUS_OK) {
233  ods_log_error("[%s] error reading RR at line %i (%s): %s",
234  adapter_str, l, ldns_get_errorstr_by_id(status), line);
235  result = ODS_STATUS_ERR;
236  break;
237  }
238  /* debug update */
239  if (l > line_update) {
240  ods_log_debug("[%s] ...at line %i: %s", adapter_str, l, line);
241  line_update += line_update_interval;
242  }
243  /* SOA? */
244  if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
245  new_serial =
246  ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL));
247  }
248  /* add to the database */
249  result = adapi_add_rr(zone, rr, 0);
250  if (result == ODS_STATUS_UNCHANGED) {
251  ods_log_debug("[%s] skipping RR at line %i (duplicate): %s",
252  adapter_str, l, line);
253  ldns_rr_free(rr);
254  rr = NULL;
255  result = ODS_STATUS_OK;
256  continue;
257  } else if (result != ODS_STATUS_OK) {
258  ods_log_error("[%s] error adding RR at line %i: %s",
259  adapter_str, l, line);
260  ldns_rr_free(rr);
261  rr = NULL;
262  break;
263  }
264  }
265  /* and done */
266  if (orig) {
267  ldns_rdf_deep_free(orig);
268  orig = NULL;
269  }
270  if (prev) {
271  ldns_rdf_deep_free(prev);
272  prev = NULL;
273  }
274  if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) {
275  ods_log_error("[%s] error reading RR at line %i (%s): %s",
276  adapter_str, l, ldns_get_errorstr_by_id(status), line);
277  result = ODS_STATUS_ERR;
278  }
279  /* input zone ok, set inbound serial and apply differences */
280  if (result == ODS_STATUS_OK) {
281  result = namedb_examine(zone->db);
282  if (result != ODS_STATUS_OK) {
283  ods_log_error("[%s] unable to read file: zonefile contains errors",
284  adapter_str);
285  return result;
286  }
287  adapi_set_serial(zone, new_serial);
288  }
289  return result;
290 }
291 
292 
297 ods_status
298 adfile_read(void* zone)
299 {
300  FILE* fd = NULL;
301  zone_type* adzone = (zone_type*) zone;
302  ods_status status = ODS_STATUS_OK;
303  if (!adzone || !adzone->adinbound || !adzone->adinbound->configstr) {
304  ods_log_error("[%s] unable to read file: no input adapter",
305  adapter_str);
306  return ODS_STATUS_ASSERT_ERR;
307  }
308  fd = ods_fopen(adzone->adinbound->configstr, NULL, "r");
309  if (!fd) {
310  return ODS_STATUS_FOPEN_ERR;
311  }
312  status = adfile_read_file(fd, adzone);
313  ods_fclose(fd);
314  if (status == ODS_STATUS_OK) {
315  adapi_trans_full(zone, 0);
316  }
317  return status;
318 }
319 
320 
325 ods_status
326 adfile_write(void* zone, const char* filename)
327 {
328  FILE* fd = NULL;
329  char* tmpname = NULL;
330  zone_type* adzone = (zone_type*) zone;
331  ods_status status = ODS_STATUS_OK;
332 
333  /* [start] sanity parameter checking */
334  if (!adzone || !adzone->adoutbound) {
335  ods_log_error("[%s] unable to write file: no output adapter",
336  adapter_str);
337  return ODS_STATUS_ASSERT_ERR;
338  }
339  if (!filename) {
340  ods_log_error("[%s] unable to write file: no filename given",
341  adapter_str);
342  return ODS_STATUS_ASSERT_ERR;
343  }
344  /* [end] sanity parameter checking */
345 
346  /* [start] write zone */
347  tmpname = ods_build_path(filename, ".tmp", 0, 0);
348  if (!tmpname) {
349  return ODS_STATUS_MALLOC_ERR;
350  }
351  fd = ods_fopen(tmpname, NULL, "w");
352  if (fd) {
353  status = adapi_printzone(fd, adzone);
354  ods_fclose(fd);
355  if (status == ODS_STATUS_OK) {
356  if (adzone->adoutbound->error) {
357  ods_log_error("[%s] unable to write zone %s file %s: one or "
358  "more RR print failed", adapter_str, adzone->name,
359  filename);
360  /* clear error */
361  adzone->adoutbound->error = 0;
362  status = ODS_STATUS_FWRITE_ERR;
363  }
364  }
365  } else {
366  status = ODS_STATUS_FOPEN_ERR;
367  }
368 
369  if (status == ODS_STATUS_OK) {
370  if (rename((const char*) tmpname, filename) != 0) {
371  ods_log_error("[%s] unable to write file: failed to rename %s "
372  "to %s (%s)", adapter_str, tmpname, filename, strerror(errno));
373  status = ODS_STATUS_RENAME_ERR;
374  }
375  }
376  free(tmpname);
377  /* [end] write zone */
378  return status;
379 }
const char * configstr
Definition: adapter.h:60
unsigned error
Definition: adapter.h:63
adapter_type * adoutbound
Definition: zone.h:73
ods_status adfile_read(void *zone)
Definition: adfile.c:298
void adapi_set_serial(zone_type *zone, uint32_t serial)
Definition: adapi.c:64
namedb_type * db
Definition: zone.h:77
ods_status adfile_write(void *zone, const char *filename)
Definition: adfile.c:326
ldns_rdf * adapi_get_origin(zone_type *zone)
Definition: adapi.c:78
int adutil_whitespace_line(char *line, int line_len)
Definition: adutil.c:183
adapter_type * adinbound
Definition: zone.h:72
void adutil_rtrim_line(char *line, int *line_len)
Definition: adutil.c:154
ods_status adapi_printzone(FILE *fd, zone_type *zone)
Definition: adapi.c:382
void adapi_trans_full(zone_type *zone, unsigned more_coming)
Definition: adapi.c:106
ods_status namedb_examine(namedb_type *db)
Definition: namedb.c:903
ods_status adapi_add_rr(zone_type *zone, ldns_rr *rr, int backup)
Definition: adapi.c:360
const char * name
Definition: zone.h:67
#define SE_ADFILE_MAXLINE
Definition: adutil.h:40
int adutil_readline_frm_file(FILE *fd, char *line, unsigned int *l, int keep_comments)
Definition: adutil.c:47
uint32_t adapi_get_ttl(zone_type *zone)
Definition: adapi.c:92