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