From b7e031d5173476224027407d8e23eaa7557fc396 Mon Sep 17 00:00:00 2001 From: Andreas Gustafsson Date: Fri, 8 Sep 2000 21:47:03 +0000 Subject: [PATCH] 435. [bug] dns_zone_dump() overwrote existing zone files rather than writing to a temporary file and renaming. This could lead to empty or partial zone files being left around in certain error conditions involving the initial transfer of a slave zone, interfering with subsequent server startup. [RT #282] --- CHANGES | 8 ++++++ lib/dns/masterdump.c | 57 ++++++++++++++++++++++++++++++++------ lib/dns/zone.c | 55 ++++++++---------------------------- lib/isc/include/isc/file.h | 8 +++++- lib/isc/unix/file.c | 13 ++++++++- 5 files changed, 87 insertions(+), 54 deletions(-) diff --git a/CHANGES b/CHANGES index 3ccab4ae87..4479cc22ec 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ + 435. [bug] dns_zone_dump() overwrote existing zone files + rather than writing to a temporary file and + renaming. This could lead to empty or partial + zone files being left around in certain error + conditions involving the initial transfer of a + slave zone, interfering with subsequent server + startup. [RT #282] + 434. [func] New function isc_file_isabsolute(). 433. [func] isc_base64_decodestring() now accepts newlines diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index 9f43f50fb1..a136a863c5 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: masterdump.c,v 1.33 2000/08/16 22:33:32 gson Exp $ */ +/* $Id: masterdump.c,v 1.34 2000/09/08 21:47:03 gson Exp $ */ #include @@ -882,27 +882,68 @@ dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, { FILE *f = NULL; isc_result_t result; + char *tempname; + int tempnamelen; - result = isc_stdio_open(filename, "w", &f); + tempnamelen = strlen(filename) + 20; + tempname = isc_mem_get(mctx, tempnamelen); + if (tempname == NULL) + return (ISC_R_NOMEMORY); + + result = isc_file_mktemplate(filename, tempname, tempnamelen); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = isc_file_openunique(tempname, &f); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, - "dumping master file: %s: open: %s", filename, - isc_result_totext(result)); - return (ISC_R_UNEXPECTED); + "dumping master file: %s: open: %s", + tempname, isc_result_totext(result)); + goto cleanup; } result = dns_master_dumptostream(mctx, db, version, style, f); + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, + "dumping master file: %s: %s", + tempname, isc_result_totext(result)); + (void)isc_stdio_close(f); + (void)isc_file_remove(tempname); + goto cleanup; + } result = isc_stdio_close(f); if (result != ISC_R_SUCCESS) { isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, - "dumping master file: %s: close: %s", filename, - isc_result_totext(result)); - return (ISC_R_UNEXPECTED); + "dumping master file: %s: close: %s", + tempname, isc_result_totext(result)); + (void)isc_file_remove(tempname); + goto cleanup; + } + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, + "dumping master file: %s: close: %s", + tempname, isc_result_totext(result)); + goto cleanup; + } + + result = isc_file_rename(tempname, filename); + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL, + DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR, + "dumping master file: rename: %s: %s", + filename, isc_result_totext(result)); + goto cleanup; + } + + cleanup: + isc_mem_put(mctx, tempname, tempnamelen); return (result); } diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 99e58ce3bc..9ddcfd8126 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.204 2000/09/08 00:07:44 explorer Exp $ */ +/* $Id: zone.c,v 1.205 2000/09/08 21:47:01 gson Exp $ */ #include @@ -1734,11 +1734,6 @@ static isc_result_t zone_dump(dns_zone_t *zone) { isc_result_t result; dns_dbversion_t *version = NULL; - dns_db_t *db = NULL; - char *buf; - int buflen; - FILE *f = NULL; - int n; /* * 'zone' locked by caller. @@ -1747,47 +1742,19 @@ zone_dump(dns_zone_t *zone) { REQUIRE(ISLOCKED(&zone->lock)); - buflen = strlen(zone->dbname) + 20; - buf = isc_mem_get(zone->mctx, buflen); - if (buf == NULL) - return (ISC_R_NOMEMORY); + dns_db_currentversion(zone->db, &version); + + result = dns_master_dump(zone->mctx, zone->db, version, + &dns_master_style_default, + zone->dbname); + + dns_db_closeversion(zone->db, &version, ISC_FALSE); - result = isc_file_mktemplate(zone->dbname, buf, buflen); if (result != ISC_R_SUCCESS) - goto cleanup; + return (result); - result = isc_file_openunique(buf, &f); - if (result != ISC_R_SUCCESS) - goto cleanup; - - dns_db_attach(zone->db, &db); - dns_db_currentversion(db, &version); - result = dns_master_dumptostream(zone->mctx, db, version, - &dns_master_style_default, f); - dns_db_closeversion(db, &version, ISC_FALSE); - dns_db_detach(&db); - n = fflush(f); - if (n != 0 && result == ISC_R_SUCCESS) - result = ISC_R_UNEXPECTED; - n = ferror(f); - if (n != 0 && result == ISC_R_SUCCESS) - result = ISC_R_UNEXPECTED; - n = fclose(f); - if (n != 0 && result == ISC_R_SUCCESS) - result = ISC_R_UNEXPECTED; - if (result == ISC_R_SUCCESS) { - n = rename(buf, zone->dbname); - if (n == -1) { - (void)remove(buf); - result = ISC_R_UNEXPECTED; - } else { - zone->flags &= ~DNS_ZONEFLG_NEEDDUMP; - } - } else - (void)remove(buf); - cleanup: - isc_mem_put(zone->mctx, buf, buflen); - return (result); + zone->flags &= ~DNS_ZONEFLG_NEEDDUMP; + return (ISC_R_SUCCESS); } isc_result_t diff --git a/lib/isc/include/isc/file.h b/lib/isc/include/isc/file.h index cd4480d284..7ccdcb6b76 100644 --- a/lib/isc/include/isc/file.h +++ b/lib/isc/include/isc/file.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: file.h,v 1.10 2000/09/08 18:37:25 gson Exp $ */ +/* $Id: file.h,v 1.11 2000/09/08 21:46:58 gson Exp $ */ #ifndef ISC_FILE_H #define ISC_FILE_H 1 @@ -159,6 +159,12 @@ isc_file_remove(const char *filename); * Remove the file named by 'filename'. */ +isc_result_t +isc_file_rename(const char *oldname, const char *newname); +/* + * Rename the file 'oldname' to 'newname'. + */ + isc_boolean_t isc_file_isabsolute(const char *filename); /* diff --git a/lib/isc/unix/file.c b/lib/isc/unix/file.c index e67bac21c2..bec600406e 100644 --- a/lib/isc/unix/file.c +++ b/lib/isc/unix/file.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: file.c,v 1.21 2000/09/08 18:37:26 gson Exp $ */ +/* $Id: file.c,v 1.22 2000/09/08 21:46:59 gson Exp $ */ #include @@ -181,6 +181,17 @@ isc_file_remove(const char *filename) { return (isc__errno2result(errno)); } +isc_result_t +isc_file_rename(const char *oldname, const char *newname) { + int r; + + r = rename(oldname, newname); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + isc_boolean_t isc_file_isabsolute(const char *filename) { return (ISC_TF(filename[0] == '/'));