From 03b5d2689df73fa9a50ff684511fa9d81f317e6c Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 1 May 2013 22:20:02 -0700 Subject: [PATCH] [master] add hash to map files 3562. [func] Update map file header format to include a SHA-1 hash of the database content, so that corrupted map files can be rejected at load time. [RT #32459] --- CHANGES | 4 + bin/tests/system/masterformat/clean.sh | 3 +- bin/tests/system/masterformat/tests.sh | 31 +++++ lib/dns/include/dns/rbt.h | 8 +- lib/dns/master.c | 10 +- lib/dns/rbt.c | 168 +++++++++++++++++++------ lib/dns/rbtdb.c | 81 +++++++++--- 7 files changed, 244 insertions(+), 61 deletions(-) diff --git a/CHANGES b/CHANGES index 9ea6935f58..8f5c44c628 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +3562. [func] Update map file header format to include a SHA-1 hash + of the database content, so that corrupted map files + can be rejected at load time. [RT #32459] + 3561. [bug] dig: issue a warning if an EDNS query returns FORMERR or NOTIMP. Adjust usage message. [RT #33363] diff --git a/bin/tests/system/masterformat/clean.sh b/bin/tests/system/masterformat/clean.sh index 366f4b7b79..740ddef7d7 100755 --- a/bin/tests/system/masterformat/clean.sh +++ b/bin/tests/system/masterformat/clean.sh @@ -31,5 +31,4 @@ rm -f ns2/formerly-text.db rm -f ns2/db-* rm -f ns2/large.bk rm -f ns3/example.db.map ns3/dynamic.db.map -rm -f baseline.txt text.1 text.2 raw.1 raw.2 map.1 map.2 - +rm -f baseline.txt text.1 text.2 raw.1 raw.2 map.1 map.2 map.5 text.5 badmap diff --git a/bin/tests/system/masterformat/tests.sh b/bin/tests/system/masterformat/tests.sh index ba4a218fc2..63b7b4bdaf 100755 --- a/bin/tests/system/masterformat/tests.sh +++ b/bin/tests/system/masterformat/tests.sh @@ -58,6 +58,16 @@ sourceserial () { }' < $1 } +stomp () { + perl -e 'open(my $file, "+<", $ARGV[0]); + binmode $file; + seek($file, $ARGV[1], 0); + for (my $i = 0; $i < $ARGV[2]; $i++) { + print $file pack('C', $ARGV[3]); + } + close($file);' $1 $2 $3 $4 +} + restart () { sleep 1 (cd ..; $PERL start.pl --noclean --restart masterformat ns3) @@ -218,7 +228,28 @@ for i in 0 1 2 3 4 5 6 7 8 9; do [ $lret -eq 0 ] && break; done [ $lret -eq 1 ] && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` +# stomp on the file data so it hashes differently. +# these are small and subtle changes, so that the resulting file +# would appear to be a legitimate map file and would not trigger an +# assertion failure if loaded into memory, but should still fail to +# load because of a SHA1 hash mismatch. +echo "I:checking corrupt map files fail to load (bad node header)" +ret=0 +./named-compilezone -D -f text -F map -o map.5 example.nil baseline.txt > /dev/null +cp map.5 badmap +stomp badmap 2754 2 99 +./named-compilezone -D -f map -F text -o text.5 example.nil badmap > /dev/null && ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + +echo "I:checking corrupt map files fail to load (bad node data)" +ret=0 +cp map.5 badmap +stomp badmap 2897 5 127 +./named-compilezone -D -f map -F text -o text.5 example.nil badmap > /dev/null && ret=1 [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h index 3ea3021aa7..ef9f5e5f98 100644 --- a/lib/dns/include/dns/rbt.h +++ b/lib/dns/include/dns/rbt.h @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -152,7 +153,10 @@ typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node, typedef isc_result_t (*dns_rbtdatawriter_t)(FILE *file, unsigned char *data, - isc_uint32_t version); + isc_uint32_t version, + isc_sha1_t *sha1); + +typedef void (*dns_rbtdatafixer_t)(dns_rbtnode_t *rbtnode, isc_sha1_t *sha1); /***** ***** Chain Info @@ -705,7 +709,7 @@ isc_result_t dns_rbt_deserialize_tree(void *base_address, off_t header_offset, isc_mem_t *mctx, void (*deleter)(void *, void *), void *deleter_arg, - void (*data_fixer)(dns_rbtnode_t *), + dns_rbtdatafixer_t datafixer, dns_rbtnode_t **originp, dns_rbt_t **rbtp); /*%< * Read a RBT structure and its data from a file. diff --git a/lib/dns/master.c b/lib/dns/master.c index 860f59e0bb..05d28bc98e 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -2193,7 +2193,7 @@ openfile_map(dns_loadctx_t *lctx, const char *master_file) { */ static isc_result_t load_map(dns_loadctx_t *lctx) { - isc_result_t result; + isc_result_t result = ISC_R_SUCCESS; dns_rdatacallbacks_t *callbacks; REQUIRE(DNS_LCTX_VALID(lctx)); @@ -2205,12 +2205,12 @@ load_map(dns_loadctx_t *lctx) { if (result != ISC_R_SUCCESS) return (result); - (*callbacks->deserialize)(callbacks->deserialize_private, - lctx->f, - sizeof(dns_masterrawheader_t)); + result = (*callbacks->deserialize) + (callbacks->deserialize_private, + lctx->f, sizeof(dns_masterrawheader_t)); } - return (ISC_R_SUCCESS); + return (result); } static isc_result_t diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c index c7578fa342..675fc0331a 100644 --- a/lib/dns/rbt.c +++ b/lib/dns/rbt.c @@ -29,10 +29,12 @@ #endif #include +#include #include #include #include #include +#include #include #include #include @@ -117,6 +119,7 @@ struct file_header { unsigned int bigendian:1; /* big or little endian system */ unsigned int rdataset_fixed:1; /* compiled with --enable-rrset-fixed */ unsigned int nodecount; /* shadow from rbt structure */ + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; char version2[32]; /* repeated; must match version1 */ }; @@ -143,17 +146,18 @@ static isc_result_t dns_rbt_zero_header(FILE *file); static isc_result_t -write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset); +write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset, + unsigned char *digest); static isc_result_t serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, uintptr_t right, uintptr_t down, uintptr_t parent, - uintptr_t data); + uintptr_t data, isc_sha1_t *sha1); static isc_result_t serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent, dns_rbtdatawriter_t datawriter, isc_uint32_t serial, - uintptr_t *where); + uintptr_t *where, isc_sha1_t *sha1); /* * The following functions allow you to get the actual address of a pointer * without having to use an if statement to check to see if that address is @@ -302,6 +306,20 @@ Name(dns_rbtnode_t *node) { } static void printnodename(dns_rbtnode_t *node); + +static void +hexdump(const char *desc, unsigned char *data, size_t size) { + char hexdump[BUFSIZ]; + isc_buffer_t b; + isc_region_t r; + + isc_buffer_init(&b, hexdump, sizeof(hexdump)); + r.base = data; + r.length = size; + isc_hex_totext(&r, 0, "", &b); + isc_buffer_putuint8(&b, 0); + fprintf(stderr, "%s: %s\n", desc, hexdump); +} #endif static inline dns_rbtnode_t * @@ -349,7 +367,7 @@ deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp); static void treefix(dns_rbt_t *rbt, dns_rbtnode_t *n, dns_name_t *name, - void (*data_fixer)(dns_rbtnode_t *)); + dns_rbtdatafixer_t datafixer, isc_sha1_t *sha1); static isc_result_t deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node); @@ -393,7 +411,9 @@ dns_rbt_zero_header(FILE *file) { * here. */ static isc_result_t -write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset) { +write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset, + unsigned char *digest) +{ file_header_t header; isc_result_t result; long location; @@ -419,6 +439,8 @@ write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset) { header.nodecount = rbt->nodecount; + memcpy(header.digest, digest, sizeof(header.digest)); + location = ftell(file); if (location < 0) return (ISC_R_FAILURE); @@ -437,13 +459,16 @@ write_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset) { static isc_result_t serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, uintptr_t right, uintptr_t down, uintptr_t parent, - uintptr_t data) + uintptr_t data, isc_sha1_t *sha1) { dns_rbtnode_t temp_node; long file_position; unsigned char *node_data; size_t datasize; isc_result_t result; +#ifdef DEBUG + dns_name_t nodename; +#endif INSIST(node != NULL); @@ -494,9 +519,23 @@ serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, CHECK(isc_stdio_write(&temp_node, 1, sizeof(dns_rbtnode_t), file, NULL)); - CHECK(isc_stdio_write(node_data, 1, datasize, file, NULL)); +#ifdef DEBUG + dns_name_init(&nodename, NULL); + NODENAME(node, &nodename); + fprintf(stderr, "serialize "); + dns_name_print(&nodename, stderr); + fprintf(stderr, "\n"); + hexdump("node header", (unsigned char*) &temp_node, + sizeof(dns_rbtnode_t)); + hexdump("node data", node_data, datasize); +#endif + + isc_sha1_update(sha1, (const isc_uint8_t *) &temp_node, + sizeof(dns_rbtnode_t)); + isc_sha1_update(sha1, (const isc_uint8_t *) node_data, datasize); + cleanup: return (result); } @@ -504,7 +543,7 @@ serialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left, static isc_result_t serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent, dns_rbtdatawriter_t datawriter, isc_uint32_t serial, - uintptr_t *where) + uintptr_t *where, isc_sha1_t *sha1) { uintptr_t left = 0, right = 0, down = 0, data = 0; long location = 0; @@ -517,7 +556,7 @@ serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent, return (ISC_R_SUCCESS); } - /* Reserve space for current node */ + /* Reserve space for current node. */ location = ftell(file); if (location < 0) return (ISC_R_FAILURE); @@ -530,13 +569,18 @@ serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent, offset_adjust = dns_rbt_serialize_align(location + NODE_SIZE(node)); CHECK(isc_stdio_seek(file, offset_adjust, SEEK_SET)); - /* Serialize the rest of the tree */ + /* + * Serialize the rest of the tree. + * + * WARNING: A change in the order (from left, right, down) + * will break the way the sha1 hash is computed. + */ CHECK(serialize_nodes(file, getleft(node, NULL), location, - datawriter, serial, &left)); + datawriter, serial, &left, sha1)); CHECK(serialize_nodes(file, getright(node, NULL), location, - datawriter, serial, &right)); + datawriter, serial, &right, sha1)); CHECK(serialize_nodes(file, getdown(node, NULL), location, - datawriter, serial, &down)); + datawriter, serial, &down, sha1)); if (node->data != NULL) { long ret; @@ -553,14 +597,15 @@ serialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent, return (ISC_R_FAILURE); data = ret; - datawriter(file, node->data, serial); + datawriter(file, node->data, serial, sha1); } - /* Seek back to reserved space */ + /* Seek back to reserved space. */ CHECK(isc_stdio_seek(file, location, SEEK_SET)); - /* Serialize the current node */ - CHECK(serialize_node(file, node, left, right, down, parent, data)); + /* Serialize the current node. */ + CHECK(serialize_node(file, node, left, right, down, parent, data, + sha1)); /* Ensure we are always at the end of the file. */ CHECK(isc_stdio_seek(file, 0, SEEK_END)); @@ -589,11 +634,15 @@ dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt, { isc_result_t result; long header_position, node_position, end_position; + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; + isc_sha1_t sha1; REQUIRE(file != NULL); CHECK(isc_file_isplainfilefd(fileno(file))); + isc_sha1_init(&sha1); + header_position = ftell(file); if (header_position < 0) return (ISC_R_FAILURE); @@ -606,7 +655,8 @@ dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt, if (node_position < 0) return (ISC_R_FAILURE); - CHECK(serialize_nodes(file, rbt->root, 0, datawriter, serial, NULL)); + CHECK(serialize_nodes(file, rbt->root, 0, datawriter, serial, NULL, + &sha1)); end_position = ftell(file); if (end_position < 0) return (ISC_R_FAILURE); @@ -617,9 +667,14 @@ dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt, return (ISC_R_SUCCESS); } + isc_sha1_final(&sha1, digest); +#ifdef DEBUG + hexdump("serializing digest", digest, sizeof(digest)); +#endif + /* Serialize header */ CHECK(isc_stdio_seek(file, header_position, SEEK_SET)); - CHECK(write_header(file, rbt, HEADER_LENGTH)); + CHECK(write_header(file, rbt, HEADER_LENGTH, digest)); /* Ensure we are always at the end of the file. */ CHECK(isc_stdio_seek(file, 0, SEEK_END)); @@ -631,11 +686,14 @@ dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt, static void treefix(dns_rbt_t *rbt, dns_rbtnode_t *n, dns_name_t *name, - void (*data_fixer)(dns_rbtnode_t *)) + dns_rbtdatafixer_t datafixer, isc_sha1_t *sha1) { isc_result_t result; dns_fixedname_t fixed; dns_name_t nodename, *fullname; + unsigned char *node_data; + dns_rbtnode_t header; + size_t datasize; if (n == NULL) return; @@ -652,6 +710,9 @@ treefix(dns_rbt_t *rbt, dns_rbtnode_t *n, dns_name_t *name, /* XXX: we need to catch errors better than this */ } + /* memorize header contents prior to fixup */ + memcpy(&header, n, sizeof(header)); + INSIST(!n->parent_is_relative || n->parent != NULL); INSIST(!n->right_is_relative || n->right != NULL); INSIST(!n->left_is_relative || n->left != NULL); @@ -675,15 +736,32 @@ treefix(dns_rbt_t *rbt, dns_rbtnode_t *n, dns_name_t *name, hash_node(rbt, n, fullname); - if (data_fixer != NULL && n->data != NULL) - data_fixer(n); - - if (n->right != NULL) - treefix(rbt, n->right, name, data_fixer); + /* a change in the order (from left, right, down) will break hashing*/ if (n->left != NULL) - treefix(rbt, n->left, name, data_fixer); + treefix(rbt, n->left, name, datafixer, sha1); + if (n->right != NULL) + treefix(rbt, n->right, name, datafixer, sha1); if (n->down != NULL) - treefix(rbt, n->down, fullname, data_fixer); + treefix(rbt, n->down, fullname, datafixer, sha1); + + if (datafixer != NULL && n->data != NULL) + datafixer(n, sha1); + + node_data = (unsigned char *) n + sizeof(dns_rbtnode_t); + datasize = NODE_SIZE(n) - sizeof(dns_rbtnode_t); + +#ifdef DEBUG + fprintf(stderr, "deserialize "); + dns_name_print(&nodename, stderr); + fprintf(stderr, "\n"); + hexdump("node header", (unsigned char *) &header, + sizeof(dns_rbtnode_t)); + hexdump("node data", node_data, datasize); +#endif + isc_sha1_update(sha1, (const isc_uint8_t *) &header, + sizeof(dns_rbtnode_t)); + isc_sha1_update(sha1, (const isc_uint8_t *) node_data, + datasize); } isc_result_t @@ -691,14 +769,18 @@ dns_rbt_deserialize_tree(void *base_address, off_t header_offset, isc_mem_t *mctx, void (*deleter)(void *, void *), void *deleter_arg, - void (*data_fixer)(dns_rbtnode_t *), + dns_rbtdatafixer_t datafixer, dns_rbtnode_t **originp, dns_rbt_t **rbtp) { isc_result_t result; file_header_t *header; + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; + isc_sha1_t sha1; REQUIRE(originp == NULL || *originp == NULL); + isc_sha1_init(&sha1); + result = dns_rbt_create(mctx, deleter, deleter_arg, rbtp); if (result != ISC_R_SUCCESS) return (result); @@ -729,7 +811,15 @@ dns_rbt_deserialize_tree(void *base_address, off_t header_offset, (*rbtp)->root = (dns_rbtnode_t *)((char *)base_address + header_offset + header->first_node_offset); (*rbtp)->nodecount = header->nodecount; - treefix(*rbtp, (*rbtp)->root, dns_rootname, data_fixer); + treefix(*rbtp, (*rbtp)->root, dns_rootname, datafixer, &sha1); + + isc_sha1_final(&sha1, digest); +#ifdef DEBUG + hexdump("deserializing digest", digest, sizeof(digest)); +#endif + + if (memcmp(header->digest, digest, sizeof(digest)) != 0) + return (ISC_R_INVALIDFILE); if (originp != NULL) *originp = (*rbtp)->root; @@ -749,7 +839,6 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *), #endif dns_rbt_t *rbt; - REQUIRE(mctx != NULL); REQUIRE(rbtp != NULL && *rbtp == NULL); REQUIRE(deleter == NULL ? deleter_arg == NULL : 1); @@ -820,13 +909,17 @@ dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) { unsigned int dns_rbt_nodecount(dns_rbt_t *rbt) { + REQUIRE(VALID_RBT(rbt)); + return (rbt->nodecount); } unsigned int dns_rbt_hashsize(dns_rbt_t *rbt) { + REQUIRE(VALID_RBT(rbt)); + return (rbt->hashsize); } @@ -2552,6 +2645,7 @@ deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) { static isc_result_t deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) { isc_result_t result = ISC_R_SUCCESS; + REQUIRE(VALID_RBT(rbt)); if (node == NULL) @@ -2607,6 +2701,7 @@ static void deletetreeflat(dns_rbt_t *rbt, unsigned int quantum, dns_rbtnode_t **nodep) { dns_rbtnode_t *parent; dns_rbtnode_t *node = *nodep; + REQUIRE(VALID_RBT(rbt)); again: @@ -2760,6 +2855,7 @@ dns_rbt_printtree(dns_rbtnode_t *root, dns_rbtnode_t *parent, void dns_rbt_printall(dns_rbt_t *rbt, void (*data_printer)(FILE *, void *)) { + REQUIRE(VALID_RBT(rbt)); dns_rbt_printtree(rbt->root, NULL, 0, "root", data_printer); @@ -2771,12 +2867,12 @@ dns_rbt_printall(dns_rbt_t *rbt, void (*data_printer)(FILE *, void *)) { void dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) { - /* - * Initialize 'chain'. - */ REQUIRE(chain != NULL); + /* + * Initialize 'chain'. + */ chain->mctx = mctx; chain->end = NULL; chain->level_count = 0; @@ -3217,13 +3313,13 @@ dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, void dns_rbtnodechain_reset(dns_rbtnodechain_t *chain) { + + REQUIRE(VALID_CHAIN(chain)); + /* * Free any dynamic storage associated with 'chain', and then * reinitialize 'chain'. */ - - REQUIRE(VALID_CHAIN(chain)); - chain->end = NULL; chain->level_count = 0; chain->level_matches = 0; diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 2cdbfd3b61..e70342859c 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -728,6 +729,25 @@ static unsigned int init_count; * For zone databases the node for the origin of the zone MUST NOT be deleted. */ +/* + * Debugging routines + */ +#ifdef DEBUG +static void +hexdump(const char *desc, unsigned char *data, size_t size) { + char hexdump[BUFSIZ]; + isc_buffer_t b; + isc_region_t r; + + isc_buffer_init(&b, hexdump, sizeof(hexdump)); + r.base = data; + r.length = size; + isc_hex_totext(&r, 0, "", &b); + isc_buffer_putuint8(&b, 0); + fprintf(stderr, "%s: %s\n", desc, hexdump); +} +#endif + /* * DB Routines @@ -6976,7 +6996,7 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) { } static void -fix_data(dns_rbtnode_t *rbtnode) { +rbt_datafixer(dns_rbtnode_t *rbtnode, isc_sha1_t *sha1) { rdatasetheader_t *header; unsigned char *p; size_t size; @@ -6984,12 +7004,18 @@ fix_data(dns_rbtnode_t *rbtnode) { REQUIRE(rbtnode != NULL); for (header = rbtnode->data; header != NULL; header = header->next) { + p = (unsigned char *) header; + size = dns_rdataslab_size(p, sizeof(*header)); + isc_sha1_update(sha1, p, size); +#ifdef DEBUG + hexdump("hashing header", p, sizeof(rdatasetheader_t)); + hexdump("hashing slab", p + sizeof(rdatasetheader_t), + size - sizeof(rdatasetheader_t)); +#endif header->serial = 1; header->is_mmapped = 1; header->node = rbtnode; header->node_is_relative = 0; - p = (unsigned char *) header; - size = dns_rdataslab_size(p, sizeof(*header)); if (header->next != NULL) { header->next = (rdatasetheader_t *)(p + size); header->next_is_relative = 0; @@ -7002,6 +7028,7 @@ fix_data(dns_rbtnode_t *rbtnode) { */ static isc_result_t deserialize(void *arg, FILE *f, off_t offset) { + isc_result_t result; rbtdb_load_t *loadctx = arg; dns_rbtdb_t *rbtdb = loadctx->rbtdb; rbtdb_file_header_t *header; @@ -7039,11 +7066,12 @@ deserialize(void *arg, FILE *f, off_t offset) { rbtdb->origin_node = NULL; if (header->tree != 0) { - dns_rbt_deserialize_tree(base, header->tree, - rbtdb->common.mctx, delete_callback, - rbtdb, fix_data, - &rbtdb->origin_node, - &temporary_rbt); + result = dns_rbt_deserialize_tree(base, header->tree, + rbtdb->common.mctx, + delete_callback, + rbtdb, rbt_datafixer, + &rbtdb->origin_node, + &temporary_rbt); if (temporary_rbt != NULL) { dns_rbt_destroy(&rbtdb->tree); rbtdb->tree = temporary_rbt; @@ -7052,28 +7080,38 @@ deserialize(void *arg, FILE *f, off_t offset) { rbtdb->origin_node = (dns_rbtnode_t *)(header->tree + base + 1024); } + if (result != ISC_R_SUCCESS) + return (result); } if (header->nsec != 0) { - dns_rbt_deserialize_tree(base, header->nsec, - rbtdb->common.mctx, delete_callback, - rbtdb, fix_data, NULL, &temporary_rbt); + result = dns_rbt_deserialize_tree(base, header->nsec, + rbtdb->common.mctx, + delete_callback, + rbtdb, rbt_datafixer, + NULL, &temporary_rbt); if (temporary_rbt != NULL) { dns_rbt_destroy(&rbtdb->nsec); rbtdb->nsec = temporary_rbt; temporary_rbt = NULL; } + if (result != ISC_R_SUCCESS) + return (result); } if (header->nsec3 != 0) { - dns_rbt_deserialize_tree(base, header->nsec3, - rbtdb->common.mctx, delete_callback, - rbtdb, fix_data, NULL, &temporary_rbt); + result = dns_rbt_deserialize_tree(base, header->nsec3, + rbtdb->common.mctx, + delete_callback, + rbtdb, rbt_datafixer, + NULL, &temporary_rbt); if (temporary_rbt != NULL) { dns_rbt_destroy(&rbtdb->nsec3); rbtdb->nsec3 = temporary_rbt; temporary_rbt = NULL; } + if (result != ISC_R_SUCCESS) + return (result); } return (ISC_R_SUCCESS); @@ -7151,7 +7189,7 @@ endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { * If there's a KEY rdataset at the zone origin containing a * zone key, we consider the zone secure. */ - if (! IS_CACHE(rbtdb)) + if (! IS_CACHE(rbtdb) && rbtdb->origin_node != NULL) iszonesecure(db, rbtdb->current_version, rbtdb->origin_node); callbacks->add = NULL; @@ -7169,7 +7207,8 @@ endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) { * by the void *data pointer in the dns_rbtnode */ static isc_result_t -rbt_datawriter(FILE *rbtfile, unsigned char *data, isc_uint32_t serial) { +rbt_datawriter(FILE *rbtfile, unsigned char *data, isc_uint32_t serial, + isc_sha1_t *sha1) { rdatasetheader_t newheader; rdatasetheader_t *header = (rdatasetheader_t *) data, *next; size_t where, size; @@ -7210,12 +7249,22 @@ rbt_datawriter(FILE *rbtfile, unsigned char *data, isc_uint32_t serial) { newheader.next_is_relative = 1; } +#ifdef DEBUG + hexdump("writing header", (unsigned char *) &newheader, + sizeof(rdatasetheader_t)); + hexdump("writing slab", p + sizeof(rdatasetheader_t), + size - sizeof(rdatasetheader_t)); +#endif + isc_sha1_update(sha1, (unsigned char *) &newheader, + sizeof(rdatasetheader_t)); result = isc_stdio_write(&newheader, sizeof(rdatasetheader_t), 1, rbtfile, NULL); if (result != ISC_R_SUCCESS) return (result); + isc_sha1_update(sha1, p + sizeof(rdatasetheader_t), + size - sizeof(rdatasetheader_t)); result = isc_stdio_write(p + sizeof(rdatasetheader_t), size - sizeof(rdatasetheader_t), 1, rbtfile, NULL); if (result != ISC_R_SUCCESS)