OpenDNSSEC-signer 1.3.0
|
00001 /* 00002 * $Id: adfile.c 5320 2011-07-12 10:42:26Z jakob $ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00034 #include "config.h" 00035 #include "adapter/adapi.h" 00036 #include "adapter/adfile.h" 00037 #include "adapter/adutil.h" 00038 #include "shared/duration.h" 00039 #include "shared/file.h" 00040 #include "shared/log.h" 00041 #include "shared/status.h" 00042 #include "shared/util.h" 00043 #include "signer/zone.h" 00044 00045 #include <ldns/ldns.h> 00046 #include <stdio.h> 00047 #include <stdlib.h> 00048 00049 static const char* adapter_str = "adapter"; 00050 static ods_status adfile_read_file(FILE* fd, zone_type* zone); 00051 00052 00057 ods_status 00058 adfile_init(void) 00059 { 00060 /* nothing to initialize */ 00061 return ODS_STATUS_OK; 00062 } 00063 00064 00069 static ldns_rr* 00070 adfile_read_rr(FILE* fd, zone_type* zone, char* line, ldns_rdf** orig, 00071 ldns_rdf** prev, uint32_t* ttl, ldns_status* status, unsigned int* l) 00072 { 00073 ldns_rr* rr = NULL; 00074 ldns_rdf* tmp = NULL; 00075 FILE* fd_include = NULL; 00076 int len = 0; 00077 ods_status s = ODS_STATUS_OK; 00078 uint32_t new_ttl = 0; 00079 const char *endptr; /* unused */ 00080 int offset = 0; 00081 00082 adfile_read_line: 00083 if (ttl) { 00084 new_ttl = *ttl; 00085 } 00086 00087 len = adutil_readline_frm_file(fd, line, l); 00088 adutil_rtrim_line(line, &len); 00089 00090 if (len >= 0) { 00091 switch (line[0]) { 00092 /* directive */ 00093 case '$': 00094 if (strncmp(line, "$ORIGIN", 7) == 0 && isspace(line[7])) { 00095 /* copy from ldns */ 00096 if (*orig) { 00097 ldns_rdf_deep_free(*orig); 00098 *orig = NULL; 00099 } 00100 offset = 8; 00101 while (isspace(line[offset])) { 00102 offset++; 00103 } 00104 tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, 00105 line + offset); 00106 if (!tmp) { 00107 /* could not parse what next to $ORIGIN */ 00108 *status = LDNS_STATUS_SYNTAX_DNAME_ERR; 00109 return NULL; 00110 } 00111 *orig = tmp; 00112 /* end copy from ldns */ 00113 goto adfile_read_line; /* perhaps next line is rr */ 00114 break; 00115 } else if (strncmp(line, "$TTL", 4) == 0 && 00116 isspace(line[4])) { 00117 /* override default ttl */ 00118 offset = 5; 00119 while (isspace(line[offset])) { 00120 offset++; 00121 } 00122 if (ttl) { 00123 *ttl = ldns_str2period(line + offset, &endptr); 00124 new_ttl = *ttl; 00125 } 00126 goto adfile_read_line; /* perhaps next line is rr */ 00127 break; 00128 } else if (strncmp(line, "$INCLUDE", 8) == 0 && 00129 isspace(line[8])) { 00130 /* dive into this file */ 00131 offset = 9; 00132 while (isspace(line[offset])) { 00133 offset++; 00134 } 00135 fd_include = ods_fopen(line + offset, NULL, "r"); 00136 if (fd_include) { 00137 s = adfile_read_file(fd_include, zone); 00138 ods_fclose(fd_include); 00139 } else { 00140 ods_log_error("[%s] unable to open include file %s", 00141 adapter_str, (line+offset)); 00142 *status = LDNS_STATUS_SYNTAX_ERR; 00143 return NULL; 00144 } 00145 if (s != ODS_STATUS_OK) { 00146 *status = LDNS_STATUS_SYNTAX_ERR; 00147 ods_log_error("[%s] error in include file %s", 00148 adapter_str, (line+offset)); 00149 return NULL; 00150 } 00151 /* restore current ttl */ 00152 if (ttl) { 00153 *ttl = new_ttl; 00154 } 00155 goto adfile_read_line; /* perhaps next line is rr */ 00156 break; 00157 } 00158 goto adfile_read_rr; /* this can be an owner name */ 00159 break; 00160 /* comments, empty lines */ 00161 case ';': 00162 case '\n': 00163 goto adfile_read_line; /* perhaps next line is rr */ 00164 break; 00165 /* let's hope its a RR */ 00166 default: 00167 adfile_read_rr: 00168 if (adutil_whitespace_line(line, len)) { 00169 goto adfile_read_line; /* perhaps next line is rr */ 00170 break; 00171 } 00172 00173 *status = ldns_rr_new_frm_str(&rr, line, new_ttl, *orig, prev); 00174 if (*status == LDNS_STATUS_OK) { 00175 ldns_rr2canonical(rr); /* TODO: canonicalize or not? */ 00176 return rr; 00177 } else if (*status == LDNS_STATUS_SYNTAX_EMPTY) { 00178 if (rr) { 00179 ldns_rr_free(rr); 00180 rr = NULL; 00181 } 00182 *status = LDNS_STATUS_OK; 00183 goto adfile_read_line; /* perhaps next line is rr */ 00184 break; 00185 } else { 00186 ods_log_error("[%s] error parsing RR at line %i (%s): %s", 00187 adapter_str, l&&*l?*l:0, 00188 ldns_get_errorstr_by_id(*status), line); 00189 while (len >= 0) { 00190 len = adutil_readline_frm_file(fd, line, l); 00191 } 00192 if (rr) { 00193 ldns_rr_free(rr); 00194 rr = NULL; 00195 } 00196 return NULL; 00197 } 00198 break; 00199 } 00200 } 00201 00202 /* -1, EOF */ 00203 *status = LDNS_STATUS_OK; 00204 return NULL; 00205 } 00206 00207 00212 static ods_status 00213 adfile_read_file(FILE* fd, zone_type* zone) 00214 { 00215 ods_status result = ODS_STATUS_OK; 00216 ldns_rr* rr = NULL; 00217 ldns_rdf* prev = NULL; 00218 ldns_rdf* orig = NULL; 00219 ldns_rdf* dname = NULL; 00220 uint32_t ttl = 0; 00221 ldns_status status = LDNS_STATUS_OK; 00222 char line[SE_ADFILE_MAXLINE]; 00223 unsigned int line_update_interval = 100000; 00224 unsigned int line_update = line_update_interval; 00225 unsigned int l = 0; 00226 00227 ods_log_assert(fd); 00228 ods_log_assert(zone); 00229 00230 /* $ORIGIN <zone name> */ 00231 dname = adapi_get_origin(zone); 00232 if (!dname) { 00233 ods_log_error("[%s] error getting default value for $ORIGIN", 00234 adapter_str); 00235 return ODS_STATUS_ERR; 00236 } 00237 orig = ldns_rdf_clone(dname); 00238 if (!orig) { 00239 ods_log_error("[%s] error setting default value for $ORIGIN", 00240 adapter_str); 00241 return ODS_STATUS_ERR; 00242 } 00243 00244 /* $TTL <default ttl> */ 00245 ttl = adapi_get_ttl(zone); 00246 00247 /* read RRs */ 00248 while ((rr = adfile_read_rr(fd, zone, line, &orig, &prev, &ttl, 00249 &status, &l)) != NULL) { 00250 00251 if (status != LDNS_STATUS_OK) { 00252 ods_log_error("[%s] error reading RR at line %i (%s): %s", 00253 adapter_str, l, ldns_get_errorstr_by_id(status), line); 00254 result = ODS_STATUS_ERR; 00255 break; 00256 } 00257 00258 if (l > line_update) { 00259 ods_log_debug("[%s] ...at line %i: %s", adapter_str, l, line); 00260 line_update += line_update_interval; 00261 } 00262 00263 /* filter out DNSSEC RRs (except DNSKEY) from the Input File Adapter */ 00264 if (util_is_dnssec_rr(rr)) { 00265 ldns_rr_free(rr); 00266 rr = NULL; 00267 continue; 00268 } 00269 00270 /* add to the zonedata */ 00271 result = adapi_add_rr(zone, rr); 00272 if (result != ODS_STATUS_OK) { 00273 ods_log_error("[%s] error adding RR at line %i: %s", 00274 adapter_str, l, line); 00275 break; 00276 } 00277 } 00278 00279 /* and done */ 00280 if (orig) { 00281 ldns_rdf_deep_free(orig); 00282 orig = NULL; 00283 } 00284 if (prev) { 00285 ldns_rdf_deep_free(prev); 00286 prev = NULL; 00287 } 00288 00289 if (result == ODS_STATUS_OK && status != LDNS_STATUS_OK) { 00290 ods_log_error("[%s] error reading RR at line %i (%s): %s", 00291 adapter_str, l, ldns_get_errorstr_by_id(status), line); 00292 result = ODS_STATUS_ERR; 00293 } 00294 return result; 00295 } 00296 00297 00302 ods_status 00303 adfile_read(struct zone_struct* zone, const char* filename) 00304 { 00305 FILE* fd = NULL; 00306 zone_type* adzone = (zone_type*) zone; 00307 ods_status status = ODS_STATUS_OK; 00308 uint32_t new_serial = 0; 00309 ldns_rr* rr = NULL; 00310 00311 /* [start] sanity parameter checking */ 00312 if (!adzone) { 00313 ods_log_error("[%s] unable to read file: no zone (or no name given)", 00314 adapter_str); 00315 return ODS_STATUS_ASSERT_ERR; 00316 } 00317 ods_log_assert(adzone); 00318 if (!filename) { 00319 ods_log_error("[%s] unable to read file: no filename given", 00320 adapter_str); 00321 return ODS_STATUS_ASSERT_ERR; 00322 } 00323 ods_log_assert(filename); 00324 /* [end] sanity parameter checking */ 00325 00326 /* [start] read zone */ 00327 fd = ods_fopen(filename, NULL, "r"); 00328 if (fd) { 00329 /* serial */ 00330 rr = adutil_lookup_soa_rr(fd); 00331 if (rr) { 00332 new_serial = 00333 ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL)); 00334 } 00335 ldns_rr_free(rr); 00336 rewind(fd); 00337 00338 status = adfile_read_file(fd, adzone); 00339 ods_fclose(fd); 00340 } else { 00341 status = ODS_STATUS_FOPEN_ERR; 00342 } 00343 if (status != ODS_STATUS_OK) { 00344 ods_log_error("[%s] unable to read file: %s", adapter_str, 00345 ods_status2str(status)); 00346 return status; 00347 } 00348 /* [end] read zone */ 00349 00350 /* [start] full transaction */ 00351 status = adapi_trans_full(adzone); 00352 if (status != ODS_STATUS_OK) { 00353 ods_log_error("[%s] unable to read file: start transaction failed", 00354 adapter_str); 00355 return status; 00356 } 00357 /* [end] full transaction */ 00358 00359 /* [start] validate updates */ 00360 status = zone_examine(adzone); 00361 if (status != ODS_STATUS_OK) { 00362 ods_log_error("[%s] unable to read file: zonefile contains errors", 00363 adapter_str); 00364 return status; 00365 } 00366 /* [end] validate updates */ 00367 adapi_set_serial(adzone, new_serial); 00368 return ODS_STATUS_OK; 00369 } 00370 00371 00376 ods_status 00377 adbackup_read(struct zone_struct* zone, const char* filename) 00378 { 00379 FILE* fd = NULL; 00380 zone_type* adzone = (zone_type*) zone; 00381 ods_status status = ODS_STATUS_OK; 00382 00383 /* [start] sanity parameter checking */ 00384 if (!adzone) { 00385 ods_log_error("[%s] unable to read file: no zone (or no name given)", 00386 adapter_str); 00387 return ODS_STATUS_ASSERT_ERR; 00388 } 00389 ods_log_assert(adzone); 00390 if (!filename) { 00391 ods_log_error("[%s] unable to read file: no filename given", 00392 adapter_str); 00393 return ODS_STATUS_ASSERT_ERR; 00394 } 00395 ods_log_assert(filename); 00396 /* [end] sanity parameter checking */ 00397 00398 /* [start] read zone */ 00399 fd = ods_fopen(filename, NULL, "r"); 00400 if (fd) { 00401 status = adfile_read_file(fd, adzone); 00402 ods_fclose(fd); 00403 } else { 00404 status = ODS_STATUS_FOPEN_ERR; 00405 } 00406 if (status != ODS_STATUS_OK) { 00407 ods_log_error("[%s] unable to recover file: %s", adapter_str, 00408 ods_status2str(status)); 00409 return status; 00410 } 00411 /* [end] read zone */ 00412 00413 /* [start] full transaction */ 00414 status = adapi_trans_full(adzone); 00415 if (status != ODS_STATUS_OK) { 00416 ods_log_error("[%s] unable to recover file: start transaction failed", 00417 adapter_str); 00418 return status; 00419 } 00420 /* [end] full transaction */ 00421 return ODS_STATUS_OK; 00422 } 00423 00424 00429 ods_status 00430 adfile_write(struct zone_struct* zone, const char* filename) 00431 { 00432 FILE* fd = NULL; 00433 zone_type* adzone = (zone_type*) zone; 00434 ods_status status = ODS_STATUS_OK; 00435 00436 /* [start] sanity parameter checking */ 00437 if (!adzone) { 00438 ods_log_error("[%s] unable to write file: no zone (or no " 00439 "name given)", adapter_str); 00440 return ODS_STATUS_ASSERT_ERR; 00441 } 00442 ods_log_assert(adzone); 00443 if (!filename) { 00444 ods_log_error("[%s] unable to write file: no filename given", 00445 adapter_str); 00446 return ODS_STATUS_ERR; 00447 } 00448 ods_log_assert(filename); 00449 /* [end] sanity parameter checking */ 00450 00451 /* [start] write zone */ 00452 fd = ods_fopen(filename, NULL, "w"); 00453 if (fd) { 00454 status = zone_print(fd, adzone); 00455 ods_fclose(fd); 00456 } else { 00457 status = ODS_STATUS_FOPEN_ERR; 00458 } 00459 /* [end] write zone */ 00460 00461 return status; 00462 }