OpenDNSSEC-signer 2.1.13
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
48static const char* adapter_str = "adapter";
49static ods_status adfile_read_file(FILE* fd, zone_type* zone);
50
51
56static ldns_rr*
57adfile_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
69adfile_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:
152adfile_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
194static ods_status
195adfile_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
297ods_status
298adfile_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
325ods_status
326adfile_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}
void adapi_set_serial(zone_type *zone, uint32_t serial)
Definition adapi.c:64
ods_status adapi_add_rr(zone_type *zone, ldns_rr *rr, int backup)
Definition adapi.c:359
void adapi_trans_full(zone_type *zone, unsigned more_coming)
Definition adapi.c:106
ods_status adapi_printzone(FILE *fd, zone_type *zone)
Definition adapi.c:381
uint32_t adapi_get_ttl(zone_type *zone)
Definition adapi.c:92
ldns_rdf * adapi_get_origin(zone_type *zone)
Definition adapi.c:78
ods_status adfile_write(void *zone, const char *filename)
Definition adfile.c:326
ods_status adfile_read(void *zone)
Definition adfile.c:298
void adutil_rtrim_line(char *line, int *line_len)
Definition adutil.c:154
int adutil_readline_frm_file(FILE *fd, char *line, unsigned int *l, int keep_comments)
Definition adutil.c:47
int adutil_whitespace_line(char *line, int line_len)
Definition adutil.c:183
#define SE_ADFILE_MAXLINE
Definition adutil.h:40
ods_status namedb_examine(namedb_type *db)
Definition namedb.c:902
unsigned error
Definition adapter.h:63
const char * configstr
Definition adapter.h:60
namedb_type * db
Definition zone.h:79
adapter_type * adinbound
Definition zone.h:74
const char * name
Definition zone.h:69
adapter_type * adoutbound
Definition zone.h:75