diff options
Diffstat (limited to 'contrib/bind/bin/named/ns_update.c')
-rw-r--r-- | contrib/bind/bin/named/ns_update.c | 959 |
1 files changed, 784 insertions, 175 deletions
diff --git a/contrib/bind/bin/named/ns_update.c b/contrib/bind/bin/named/ns_update.c index 48db0765b72c..4f9817fb138e 100644 --- a/contrib/bind/bin/named/ns_update.c +++ b/contrib/bind/bin/named/ns_update.c @@ -1,9 +1,9 @@ #if !defined(lint) && !defined(SABER) -static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $"; +static const char rcsid[] = "$Id: ns_update.c,v 8.68 1999/11/05 04:40:58 vixie Exp $"; #endif /* not lint */ /* - * Copyright (c) 1996, 1997 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,6 +20,26 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" */ /* + * Portions Copyright (c) 1999 by Check Point Software Technologies, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Check Point Software Technologies Incorporated not be used + * in advertising or publicity pertaining to distribution of the document + * or software without specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND CHECK POINT SOFTWARE TECHNOLOGIES + * INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL CHECK POINT SOFTWARE TECHNOLOGIES INCORPRATED + * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* * Based on the Dynamic DNS reference implementation by Viraj Bais * <viraj_bais@ccm.fm.intel.com> */ @@ -31,6 +51,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <sys/file.h> #include <sys/socket.h> #include <sys/stat.h> +#include <sys/un.h> #include <netinet/in.h> #include <arpa/nameser.h> @@ -40,6 +61,7 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <fcntl.h> #include <limits.h> #include <resolv.h> +#include <res_update.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -52,10 +74,14 @@ static char rcsid[] = "$Id: ns_update.c,v 8.26 1998/05/05 19:45:10 halley Exp $" #include <isc/logging.h> #include <isc/memcluster.h> +#include <isc/dst.h> + #include "port_after.h" #include "named.h" +static ns_updque curupd; + #define WRITEABLE_MASK (S_IWUSR | S_IWGRP | S_IWOTH) /* XXXRTH almost all funcs. in here should be static! @@ -106,14 +132,8 @@ static struct map m_section[] = { }; #define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map)) +/* Forward. */ -/* from ns_req.c */ - -static ns_updrec *rrecp_start = NULL, *rrecp_last = NULL; - - -/* forward */ -static int findzone(const char *, int, int, int *, int); static int rdata_expand(const u_char *, const u_char *, const u_char *, u_int, size_t, u_char *, size_t); @@ -134,6 +154,21 @@ open_transaction_log(struct zoneinfo *zp) { return (fp); } +static FILE * +open_ixfr_log(struct zoneinfo *zp) { + FILE *fp; + + fp = fopen(zp->z_ixfr_base, "a+"); + if (fp == NULL) { + ns_error(ns_log_update, "can't open %s: %s", zp->z_ixfr_base, + strerror(errno)); + return (NULL); + } + if (ftell(fp) == 0L) { + fprintf(fp, "%s", LogSignature); + } + return (fp); +} static int close_transaction_log(struct zoneinfo *zp, FILE *fp) { @@ -155,13 +190,69 @@ close_transaction_log(struct zoneinfo *zp, FILE *fp) { return (0); } +static int +close_ixfr_log(struct zoneinfo *zp, FILE *fp) { + if (fflush(fp) == EOF) { + ns_error(ns_log_update, "fflush() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + fclose(fp); + return (-1); + } + if (fsync(fileno(fp)) < 0) { + ns_error(ns_log_update, "fsync() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + fclose(fp); + return (-1); + } + if (fclose(fp) == EOF) { + ns_error(ns_log_update, "fclose() of %s failed: %s", + zp->z_ixfr_base, strerror(errno)); + return (-1); + } + return (0); +} + +/* + * return true if 'db' had been added. + */ +static int +was_added(const ns_updque *updlist, struct databuf *dp) { + ns_updrec *rrecp; + + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) + if (rrecp->r_section == S_UPDATE && rrecp->r_dp == dp) + return (1); + return (0); +} + +/* + * return true if 'db' had been deleted. + */ +static int +was_deleted(const ns_updque *updlist, struct databuf *dp) { + ns_updrec *rrecp; + struct databuf *adp; + + + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) + if (rrecp->r_section == S_UPDATE && + rrecp->r_deldp != NULL) { + adp = rrecp->r_deldp; + do { + if (adp == dp) + return (1); + } while ((adp = adp->d_next) != NULL); + } + return (0); +} + /* - * printupdatelog(srcaddr, firstp, hp, zp, old_serial) + * printupdatelog(srcaddr, updlist, hp, zp, old_serial) * append an ascii form to the zone's transaction log file. */ static void printupdatelog(struct sockaddr_in srcaddr, - ns_updrec *firstp, + const ns_updque *updlist, HEADER *hp, struct zoneinfo *zp, u_int32_t old_serial) @@ -171,25 +262,35 @@ printupdatelog(struct sockaddr_in srcaddr, ns_updrec *rrecp; int opcode; char time[25]; - FILE *fp; + FILE *fp, *ifp; - if (!firstp) + if (EMPTY(*updlist)) return; fp = open_transaction_log(zp); if (fp == NULL) return; + ifp = open_ixfr_log(zp); + if (ifp == NULL) { + (void) close_transaction_log(zp, fp); + return; + } sprintf(time, "at %lu", (u_long)tt.tv_sec); fprintf(fp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n", - hp->id, sin_ntoa(srcaddr), time, (long)getpid()); - for (rrecp = firstp; rrecp; rrecp = rrecp->r_next) { + ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid()); + fprintf(ifp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n", + ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid()); + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) { INSIST(zp == &zones[rrecp->r_zone]); switch (rrecp->r_section) { case S_ZONE: fprintf(fp, "zone:\torigin %s class %s serial %u\n", zp->z_origin, p_class(zp->z_class), old_serial); + fprintf(ifp, "zone:\torigin %s class %s serial %u\n", + zp->z_origin, p_class(zp->z_class), + old_serial); break; case S_PREREQ: opcode = rrecp->r_opcode; @@ -207,6 +308,45 @@ printupdatelog(struct sockaddr_in srcaddr, break; case S_UPDATE: opcode = rrecp->r_opcode; + /* + * Translate all deletes into explict actions by + * looking at what was actually deleted from the + * zone for the ixfr log. + */ + dp = rrecp->r_deldp; + while (dp != NULL) { + if (dp->d_rcode == 0 && + !was_added(updlist, dp)) { + fprintf(ifp, + "update:\t{%s} %s. %u %s %s ", + "delete", + rrecp->r_dname, + dp->d_ttl, + p_class(dp->d_class), + p_type(dp->d_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + dp = dp->d_next; + } + /* + * Only successful adds should be recorded. + * Don't add changes that are undone later. + * SOA additions performed later. + */ + if (opcode == ADD && (dp = rrecp->r_dp) != NULL && + dp->d_type != T_SOA && + (dp->d_mark & D_MARK_ADDED) != 0 && + !was_deleted(updlist, dp)) { + fprintf(ifp, "update:\t{%s} %s. ", + opcodes[opcode], rrecp->r_dname); + fprintf(ifp, "%u ", rrecp->r_ttl); + fprintf(ifp, "%s ", p_class(zp->z_class)); + fprintf(ifp, "%s ", p_type(rrecp->r_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + /* Update log. */ fprintf(fp, "update:\t{%s} %s. ", opcodes[opcode], rrecp->r_dname); if (opcode == ADD) @@ -228,8 +368,37 @@ printupdatelog(struct sockaddr_in srcaddr, /*NOTREACHED*/ } } + /* + * SOA additions must be last in this update as they + * (or [INCR_SERIAL]) terminate an IXFR chunk. Only the last SOA + * addition will be emitted for any dynamic update regardless + * of the number of SOA changes in the update. + */ + for (rrecp = HEAD(*updlist); rrecp != NULL; rrecp = NEXT(rrecp, r_link)) { + INSIST(zp == &zones[rrecp->r_zone]); + switch (rrecp->r_section) { + case S_UPDATE: + opcode = rrecp->r_opcode; + if (opcode == ADD && (dp = rrecp->r_dp) != NULL && + dp->d_type == T_SOA && + (dp->d_mark & D_MARK_ADDED) != 0 && + !was_deleted(updlist, dp)) { + fprintf(ifp, "update:\t{%s} %s. ", + opcodes[opcode], rrecp->r_dname); + fprintf(ifp, "%u ", rrecp->r_ttl); + fprintf(ifp, "%s ", p_class(zp->z_class)); + fprintf(ifp, "%s ", p_type(rrecp->r_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n[END_DELTA]\n"); + } + break; + default: + break; + } + } fprintf(fp, "\n"); (void) close_transaction_log(zp, fp); + (void) close_ixfr_log(zp, ifp); } static void @@ -379,8 +548,15 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } htp = hashtab; np = nlookup(dname, &htp, &fname, 0); - if (fname != dname) - np = NULL; /* Matching by wildcard not allowed here. */ + /* + * Matching by wildcard not allowed here. + * We need to post check for a wildcard match. + */ + if (fname != dname || + (np != NULL && ns_wildcard(NAME(*np)) && + (dname[0] != '*' || (dname[1] != '.' && dname[1] != '\0')))) + np = NULL; + if (class == C_ANY) { if (rdp->d_size) { ns_debug(ns_log_update, 1, @@ -411,7 +587,8 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { for (dp = np->n_data; dp && !found; dp = dp->d_next) - if (match(dp, class, type)) + if (match(dp, class, type) && + dp->d_type == type) found = 1; if (!found) { ns_debug(ns_log_update, 1, @@ -485,12 +662,12 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { return (0); } for (dp = np->n_data; dp; dp = dp->d_next) { - if (match(dp, class, type)) { + if (match(dp, class, type) && dp->d_type == type) { int found = 0; for (tmp = ur; - tmp && !found; - tmp = tmp->r_next) { + tmp != NULL && !found; + tmp = NEXT(tmp, r_link)) { if (tmp->r_section != S_PREREQ) break; if (!db_cmp(dp, tmp->r_dp)) { @@ -505,9 +682,9 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } } } - for (tmp = ur; tmp; tmp = tmp->r_next) + for (tmp = ur; tmp != NULL; tmp = NEXT(tmp, r_link)) if (tmp->r_section == S_PREREQ && - !strcasecmp(dname, tmp->r_dname) && + ns_samename(dname, tmp->r_dname) == 1 && tmp->r_class == class && tmp->r_type == type && (ur->r_dp->d_mark & D_MARK_FOUND) == 0) { @@ -527,6 +704,153 @@ process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { return (1); } +static int +prescan_nameok(ns_updrec *ur, int *rcodep, u_int16_t zclass, + struct zoneinfo *zp) { + const char *dname = ur->r_dname; + const char *owner = ur->r_dname; + u_int16_t class = ur->r_class; + u_int16_t type = ur->r_type; + char *cp = (char *)ur->r_dp->d_data; + enum context context; + + int ret = 1; + + /* We don't care about deletes */ + if (ur->r_class != zclass) + return (1); + + context = ns_ownercontext(type, primary_trans); + if (!ns_nameok(NULL, owner, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + + switch (type) { + case ns_t_soa: + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_rp: + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_minfo: + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + context = mailname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_ns: + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_ptr: + context = ns_ptrcontext(owner); + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_naptr: + /* + * Order (2) + * Preference (2) + * Flags (1) + */ + cp += 5; + /* Service (txt) */ + cp += strlen(cp) + 1; + /* Pattern (txt) */ + cp += strlen(cp) + 1; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_srv: + cp += 4; + /* FALLTHROUGH */ + case ns_t_mx: + case ns_t_afsdb: + case ns_t_rt: + case ns_t_kx: + cp += 2; + context = hostname_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_px: + cp += 2; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + cp += strlen(cp) + 1; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_sig: + /* + * Type covered (2) + * Alg (1) * + * Labels (1) + * ttl (4) + * expires (4) + * signed (4) + * footprint (2) + */ + cp += 18; + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + case ns_t_nxt: + context = domain_ctx; + if (!ns_nameok(NULL, cp, class, zp, primary_trans, context, owner, + inaddr_any)) + goto refused; + break; + default: + break; + } + return (1); + refused: + *rcodep = REFUSED; + return (0); +} + /* * int * prescan_update(ur, rcodep) @@ -549,9 +873,7 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { struct namebuf *np; if (class == zclass) { - if (type == T_ANY || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + if (!ns_t_rr_p(type)) { ns_debug(ns_log_update, 1, "prescan_update: invalid type (%s)", p_type(type)); @@ -560,19 +882,18 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { } } else if (class == C_ANY) { if (ttl != 0 || rdp->d_size || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + (!ns_t_rr_p(type) && type != T_ANY)) + { ns_debug(ns_log_update, 1, "prescan_update: formerr(#2)"); *rcodep = FORMERR; return (0); } } else if (class == C_NONE) { - if (ttl != 0 || type == T_ANY || - type == T_AXFR || type == T_IXFR || - type == T_MAILA || type == T_MAILB) { + if (ttl != 0 || !ns_t_rr_p(type)) { ns_debug(ns_log_update, 1, - "prescan_update: formerr(#3)"); + "prescan_update: formerr(#3) %d %s", + ttl, p_type(type)); *rcodep = FORMERR; return (0); } @@ -589,7 +910,7 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { /* * int - * process_updates(firstp, rcodep, from) + * process_updates(updlist, rcodep, from) * Process prerequisites and apply updates from the list to the database. * returns: * number of successful updates, 0 if none were successful. @@ -598,7 +919,9 @@ prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { * can schedule maintainance for zone dumps and soa.serial# increments. */ static int -process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { +process_updates(const ns_updque *updlist, int *rcodep, + struct sockaddr_in from) +{ int i, j, n, dbflags, matches, zonenum; int numupdated = 0, soaupdated = 0, schedmaint = 0; u_int16_t zclass; @@ -609,11 +932,12 @@ process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { int zonelist[MAXDNAME]; *rcodep = SERVFAIL; - if (!firstp) + if (EMPTY(*updlist)) return (0); - if (firstp->r_section == S_ZONE) { - zclass = firstp->r_class; - zonenum = firstp->r_zone; + ur = HEAD(*updlist); + if (ur->r_section == S_ZONE) { + zclass = ur->r_class; + zonenum = ur->r_zone; zp = &zones[zonenum]; } else { ns_debug(ns_log_update, 1, @@ -622,7 +946,7 @@ process_updates(ns_updrec *firstp, int *rcodep, struct sockaddr_in from) { } /* Process prereq records and prescan update records. */ - for (ur = firstp; ur != NULL; ur = ur->r_next) { + for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) { const char * dname = ur->r_dname; u_int16_t class = ur->r_class; u_int16_t type = ur->r_type; @@ -642,7 +966,9 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", for (j = 0; j < matches && !ur->r_zone; j++) if (zonelist[j] == zonenum) ur->r_zone = zonelist[j]; - if (!ur->r_zone) { + if (!ur->r_zone || + (section != S_ADDT && type == T_SOA && + ns_samename(dname, zp->z_origin) != 1)) { ns_debug(ns_log_update, 1, "process_updates: record does not belong to the zone %s", zones[zonenum].z_origin); @@ -661,6 +987,8 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", case S_UPDATE: if (!prescan_update(ur, rcodep, zclass)) return (0); /* *rcodep has been set. */ + if (!prescan_nameok(ur, rcodep, zclass, zp)) + return (0); /* *rcodep has been set. */ ns_debug(ns_log_update, 3, "update prescan succeeded"); break; case S_ADDT: @@ -673,7 +1001,7 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", } /* Now process the records in update section. */ - for (ur = firstp; ur != NULL; ur = ur->r_next) { + for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) { const char * dname = ur->r_dname; u_int16_t class = ur->r_class; @@ -689,10 +1017,11 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", * is done in db_update(). */ ur->r_opcode = ADD; - dbflags |= DB_NODATA; + dbflags |= DB_NODATA | DB_REPLACE; n = db_update(dname, dp, dp, &savedp, dbflags, hashtab, from); - if (n != OK) { + if (!((n == OK) || + ((zp->z_xferpid == XFER_ISIXFR) && (n == DATAEXISTS)))) { ns_debug(ns_log_update, 3, "process_updates: failed to add databuf (%d)", n); @@ -723,10 +1052,11 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", dbflags |= DB_DELETE; n = db_update(dname, dp, NULL, &savedp, dbflags, hashtab, from); - if (n != OK) + if (!((n == OK) || + ((zp->z_xferpid == XFER_ISIXFR) && (n == NODATA)))) { ns_debug(ns_log_update, 3, "process_updates: delete failed"); - else { + } else { ns_debug(ns_log_update, 3, "process_updates: delete succeeded"); numupdated++; @@ -771,7 +1101,7 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", schedmaint = 1; #ifdef BIND_NOTIFY if (!loading) - sysnotify(zp->z_origin, zp->z_class, T_SOA); + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); #endif } else { if (schedule_soa_update(zp, numupdated)) @@ -784,7 +1114,8 @@ class=%s, type=%s, ttl=%d, dp=0x%0x", static enum req_action req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, - struct qstream *qsp, int dfd, struct sockaddr_in from) + struct qstream *qsp, int dfd, struct sockaddr_in from, + struct tsig_record *in_tsig) { char dnbuf[MAXDNAME], *dname; u_int zocount, prcount, upcount, adcount, class, type, dlen; @@ -801,6 +1132,9 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, int zonelist[MAXDNAME]; int should_use_tcp; u_int32_t old_serial; + int unapproved_ip = 0; + int tsig_len; + DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL; nsp[0] = NULL; @@ -854,7 +1188,7 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * Begin Access Control Point */ - if (!ip_address_allowed(zp->z_update_acl, from.sin_addr)) { + if (!ip_addr_or_key_allowed(zp->z_update_acl, from.sin_addr, in_key)) { ns_notice(ns_log_security, "unapproved update from %s for %s", sin_ntoa(from), *dname ? dname : "."); return (Refuse); @@ -864,8 +1198,6 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * End Access Control Point */ - /* XXXVIX should check update key when we have one. */ - /* we should be authoritative */ if (!(zp->z_flags & Z_AUTH)) { ns_debug(ns_log_update, 1, @@ -877,11 +1209,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, if (zp->z_type == Z_SECONDARY) { /* - * XXX the code below is broken. Until fixed, we just - * refuse. + * XXX The code below is broken. + * Until fixed, we just refuse. */ +#if 1 return (Refuse); - +#else /* We are a slave for this zone, forward it to the master. */ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) *nspp++ = savedata(zp->z_class, T_A, USE_MINIMUM, @@ -892,8 +1225,15 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, * If the request came in over TCP, forward it over TCP */ should_use_tcp = (qsp != NULL); + if (in_tsig != NULL) { + tsig_len = ns_skiprr(eom, eom + TSIG_BUF_SIZE, + ns_s_ar, 1); + eom += tsig_len; + } n = ns_forw(nsp, msg, eom-msg, from, qsp, dfd, &qp, - dname, class, type, NULL, should_use_tcp); + dname, class, type, NULL, should_use_tcp, NULL); + if (in_tsig != NULL) + eom -= tsig_len; free_nsp(nsp); switch (n) { case FW_OK: @@ -905,6 +1245,7 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, hp->rcode = SERVFAIL; return (Finish); } +#endif } /* * We are the primary master server for this zone, @@ -920,11 +1261,10 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, ns_debug(ns_log_update, 3, "req_update: update request for zone %s, class %s", zp->z_origin, p_class(class)); - rrecp_start = res_mkupdrec(S_ZONE, dname, class, type, 0); - rrecp_start->r_zone = zonenum; - rrecp_start->r_prev = NULL; - rrecp_start->r_next = NULL; - rrecp_last = rrecp_start; + rrecp = res_mkupdrec(S_ZONE, dname, class, type, 0); + rrecp->r_zone = zonenum; + + APPEND(curupd, rrecp, r_link); /* * Parse the prerequisite and update sections for format errors. @@ -946,6 +1286,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, } GETSHORT(type, cp); GETSHORT(class, cp); + if (class > CLASS_MAX) { + ns_debug(ns_log_update, 1, + "req_update: bad class"); + hp->rcode = FORMERR; + return (Finish); + } GETLONG(ttl, cp); GETSHORT(dlen, cp); n = 0; @@ -972,14 +1318,12 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, dp = savedata(class, type, ttl, rdata, n); dp->d_zone = zonenum; dp->d_cred = DB_C_ZONE; + dp->d_secure = DB_S_INSECURE; /* should be UNCHECKED */ dp->d_clev = nlabels(zp->z_origin); /* XXX - also record in dp->d_ns, which host this came from */ rrecp->r_dp = dp; /* Append the current record to the end of list of records. */ - rrecp_last->r_next = rrecp; - rrecp->r_prev = rrecp_last; - rrecp->r_next = NULL; - rrecp_last = rrecp; + APPEND(curupd, rrecp, r_link); if (cp > eom) { ns_info(ns_log_update, "Malformed response from %s (overrun)", @@ -990,44 +1334,47 @@ req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, } /* Now process all parsed records in the prereq and update sections. */ - numupdated = process_updates(rrecp_start, &rcode, from); + numupdated = process_updates(&curupd, &rcode, from); hp->rcode = rcode; if (numupdated <= 0) { - ns_error(ns_log_update, - "error processing update packet id %d from %s", - hp->id, sin_ntoa(from)); + if (rcode != NOERROR) + ns_error(ns_log_update, + "error processing update packet (%s) id %d from %s", + p_rcode(rcode), ntohs(hp->id), sin_ntoa(from)); return (Finish); } + /* + * Stop any outbound zone transfers. + * (Eventlib is synchronous for this.) + */ + ns_stopxfrs(zp); + /* Make a log of the update. */ - (void) printupdatelog(from, rrecp_start, hp, zp, old_serial); + (void) printupdatelog(from, &curupd, hp, zp, old_serial); return (Finish); } -static void -free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, - struct sockaddr_in from) -{ +void +free_rrecp(ns_updque *updlist, int rcode, struct sockaddr_in from) { ns_updrec *rrecp, *first_rrecp, *next_rrecp; struct databuf *dp, *tmpdp; char *dname, *msg; - REQUIRE(startpp != NULL && lastpp != NULL); - if (rcode == NOERROR) { - first_rrecp = *startpp; + first_rrecp = HEAD(*updlist); msg = "free_rrecp: update transaction succeeded, cleaning up"; } else { - first_rrecp = *lastpp; + first_rrecp = TAIL(*updlist); msg = "free_rrecp: update transaction aborted, rolling back"; } ns_debug(ns_log_update, 1, msg); for (rrecp = first_rrecp; rrecp != NULL; rrecp = next_rrecp) { if (rcode == NOERROR) - next_rrecp = rrecp->r_next; + next_rrecp = NEXT(rrecp, r_link); else - next_rrecp = rrecp->r_prev; + next_rrecp = PREV(rrecp, r_link); if (rrecp->r_section != S_UPDATE) { if (rrecp->r_dp) db_freedata(rrecp->r_dp); @@ -1096,7 +1443,7 @@ free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, /* Add the databuf back. */ tmpdp->d_mark &= ~D_MARK_DELETED; if (db_update(dname, tmpdp, tmpdp, NULL, - 0, hashtab, from) != OK) { + DB_REPLACE, hashtab, from) != OK) { ns_error(ns_log_update, "free_rrecp: failed to add back databuf: dname=%s, type=%s", dname, p_type(tmpdp->d_type)); @@ -1109,18 +1456,19 @@ free_rrecp(ns_updrec **startpp, ns_updrec **lastpp, int rcode, } res_freeupdrec(rrecp); } - *startpp = NULL; - *lastpp = NULL; + INIT_LIST(*updlist); } enum req_action req_update(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, - struct qstream *qsp, int dfd, struct sockaddr_in from) + struct qstream *qsp, int dfd, struct sockaddr_in from, + struct tsig_record *in_tsig) { enum req_action ret; - ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from); - free_rrecp(&rrecp_start, &rrecp_last, hp->rcode, from); + INIT_LIST(curupd); + ret = req_update_private(hp, cp, eom, msg, qsp, dfd, from, in_tsig); + free_rrecp(&curupd, ret == Refuse ? ns_r_refused : hp->rcode, from); if (ret == Finish) { hp->qdcount = hp->ancount = hp->nscount = hp->arcount = 0; memset(msg + HFIXEDSZ, 0, (eom - msg) - HFIXEDSZ); @@ -1139,11 +1487,13 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, { const u_char *cpinit = cp; const u_char *cp1init = cp1; - int n, i; + int n, i, n1; switch (type) { case T_A: - if (dlen != INT32SZ) + case T_AAAA: + if ((type == T_A && dlen != INT32SZ) || + (type == T_AAAA && dlen != NS_IN6ADDRSZ)) return (0); /*FALLTHROUGH*/ case T_WKS: @@ -1153,6 +1503,8 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, case T_ISDN: case T_NSAP: case T_LOC: + case T_KEY: + case ns_t_cert: if (size < dlen) return (0); memcpy(cp1, cp, dlen); @@ -1249,6 +1601,56 @@ rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, if (cp != cpinit + dlen) return (0); return (cp1 - cp1init); + case T_SIG: + if (dlen < SIG_HDR_SIZE || size < dlen) + return (0); + memcpy(cp1, cp, SIG_HDR_SIZE); + size -= SIG_HDR_SIZE; + cp += SIG_HDR_SIZE; + cp1 += SIG_HDR_SIZE; + n = dn_expand(msg, eom, cp, (char *)cp1, size); + if (n < 0 || n + SIG_HDR_SIZE > dlen) + return (0); + cp += n; + n1 = dlen - n - SIG_HDR_SIZE; + n = strlen((char *)cp1) + 1; + cp1 += n; + if (size < n1) + return (0); + memcpy(cp1, cp, n1); + cp1 += n1; + return (cp1 - cp1init); + case T_NXT: + n = dn_expand(msg, eom, cp, (char *)cp1, size); + if (n < 0 || (u_int)n >= dlen) + return (0); + size -= n; + cp += n; + n1 = dlen - n; + n = strlen((char *)cp1) + 1; + cp1 += n; + /* + * The first bit of the first octet determines the format + * of the NXT record. A format for types >= 128 has not + * yet been defined, so if bit zero is set, we just copy + * what's there because we don't understand it. + */ + if ((*cp & 0x80) == 0) { + /* + * Bit zero is not set; this is an ordinary NXT + * record. The bitmap must be at least 4 octets + * because the NXT bit should be set. It should be + * less than or equal to 16 octets because this NXT + * format is only defined for types < 128. + */ + if (n1 < 4 || n1 > 16) + return (0); + } + if (n1 > size) + return (0); + memcpy(cp1, cp, n1); + cp1 += n1; + return (cp1 - cp1init); default: ns_debug(ns_log_update, 3, "unknown type %d", type); return (0); @@ -1267,6 +1669,10 @@ rdata_dump(struct databuf *dp, FILE *fp) { u_char *cp, *end; int i, j; const char *proto; + u_char *savecp; + char temp_base64[NS_MD5RSA_MAX_BASE64]; + u_int16_t keyflags; + u_char *sigdata, *certdata; cp = (u_char *)dp->d_data; switch (dp->d_type) { @@ -1339,6 +1745,15 @@ rdata_dump(struct databuf *dp, FILE *fp) { fprintf(fp, "%u", n); fprintf(fp, " %s.", cp); break; + case T_SRV: + GETSHORT(n, cp); /* priority */ + fprintf(fp, "%u ", n); + GETSHORT(n, cp); /* weight */ + fprintf(fp, "%u ", n); + GETSHORT(n, cp); /* port */ + fprintf(fp, "%u ", n); + fprintf(fp, " %s.", cp); + break; case T_PX: GETSHORT(n, cp); fprintf(fp, "%u", n); @@ -1353,12 +1768,16 @@ rdata_dump(struct databuf *dp, FILE *fp) { while (cp < end) { if ((n = *cp++) != '\0') { for (j = n; j > 0 && cp < end; j--) - if (*cp == '\n') { - (void) putc('\\', fp); - (void) putc(*cp++, fp); + if ((*cp < ' ') || (*cp > '~')) { + fprintf(fp, "\\%03.3d", *cp++); + } else if (*cp == '\\' || *cp =='"') { + putc('\\', fp); + putc(*cp++, fp); } else (void) putc(*cp++, fp); } + if (cp != end) + fputs("\" \"", fp); } /* XXXVIX need to keep the segmentation (see 4.9.5). */ (void) fputs("\"", fp); @@ -1393,6 +1812,91 @@ rdata_dump(struct databuf *dp, FILE *fp) { cp += strlen((char *)cp) + 1; fprintf(fp, " %s.", cp); break; + case T_KEY: + savecp = cp; /* save the beginning */ + /*>>> Flags (unsigned_16) */ + NS_GET16(keyflags,cp); + fprintf(fp, "0x%04x ", keyflags); + /*>>> Protocol (8-bit decimal) */ + fprintf(fp, "%3u ", *cp++); + /*>>> Algorithm id (8-bit decimal) */ + fprintf(fp, "%3u ", *cp++); + + /*>>> Public-Key Data (multidigit BASE64) */ + /* containing ExponentLen, Exponent, and Modulus */ + i = b64_ntop(cp, dp->d_size - (cp - savecp), + temp_base64, sizeof temp_base64); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + case T_SIG: + sigdata = cp; + /* RRtype (char *) */ + NS_GET16(n,cp); + fprintf(fp, "%s ", p_type(n)); + /* Algorithm id (8-bit decimal) */ + fprintf(fp, "%d ", *cp++); + /* Labels (8-bit decimal) (not saved in file) */ + /* XXXX FIXME -- check value and print err if bad */ + cp++; + /* OTTL (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%u ", n); + /* Texp (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%s ", p_secstodate (n)); + /* Tsig (u_long) */ + NS_GET32(n, cp); + fprintf(fp, "%s ", p_secstodate (n)); + /* Kfootprint (unsigned_16) */ + NS_GET16(n, cp); + fprintf(fp, "%u ", n); + /* Signer's Name (char *) */ + fprintf(fp, "%s ", cp); + cp += strlen((char *)cp) + 1; + /* Signature (base64 of any length) */ + i = b64_ntop(cp, dp->d_size - (cp - sigdata), + temp_base64, sizeof temp_base64); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + + case T_NXT: + fprintf(fp, "%s.", cp); + n = strlen ((char *)cp) + 1; + cp += n; + i = 8 * (dp->d_size - n); /* How many bits? */ + for (n = 0; n < (u_int32_t)i; n++) { + if (NS_NXT_BIT_ISSET(n, cp)) + fprintf(fp," %s",__p_type(n)); + } + break; + case ns_t_cert: + certdata = cp; + NS_GET16(n,cp); + fprintf(fp, "%d ", n); /* cert type */ + + NS_GET16(n,cp); + fprintf(fp, "%d %d ", n, *cp++); /* tag & alg */ + + /* Certificate (base64 of any length) */ + i = b64_ntop(cp, dp->d_size - (cp - certdata), + temp_base64, sizeof(temp_base64)); + if (i < 0) + fprintf(fp, "; BAD BASE64"); + else + fprintf(fp, "%s", temp_base64); + break; + case ns_t_aaaa: { + char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + + (void) fputs(inet_ntop(AF_INET6, dp->d_data, t, sizeof t), fp); + break; + } default: fprintf(fp, "\t;?d_type=%d?", dp->d_type); } @@ -1404,7 +1908,7 @@ rdata_dump(struct databuf *dp, FILE *fp) { * authoritative zone numbers will be stored in "zonelist", ordered * deepest match first. */ -static int +int findzone(const char *dname, int class, int depth, int *zonelist, int maxzones){ char *tmpdname; char tmpdnamebuf[MAXDNAME]; @@ -1428,7 +1932,7 @@ zonelist=0x%x, maxzones=%d)", tmpdname = tmpdnamebuf; /* * The code to handle trailing dots and escapes is adapted - * from samedomain(). + * from ns_samedomain(). */ tmpdnamelen = strlen(tmpdname); /* @@ -1538,7 +2042,7 @@ zonelist=0x%x, maxzones=%d)", * returns -1 on error, 0 on success, 1 if dump reload needed */ int -merge_logs(struct zoneinfo *zp) { +merge_logs(struct zoneinfo *zp, char *logname) { char origin[MAXDNAME], data[MAXDATA], dnbuf[MAXDNAME], sclass[3]; char buf[BUFSIZ], buf2[100]; FILE *fp; @@ -1558,6 +2062,7 @@ merge_logs(struct zoneinfo *zp) { u_char *serialp; struct sockaddr_in empty_from; int datasize; + unsigned long l; empty_from.sin_family = AF_INET; empty_from.sin_addr.s_addr = htonl(INADDR_ANY); @@ -1568,64 +2073,67 @@ merge_logs(struct zoneinfo *zp) { * getword() is used here just to be consistent with db_load() */ + ns_debug(ns_log_update, 3, "merge_logs(%s)", logname); + /* If there is no log file, just return. */ - if (stat(zp->z_updatelog, &st) < 0) { + if (stat(logname, &st) < 0) { if (errno != ENOENT) ns_error(ns_log_update, "unexpected stat(%s) failure: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); return (-1); } - fp = fopen(zp->z_updatelog, "r"); + fp = fopen(logname, "r"); if (fp == NULL) { ns_error(ns_log_update, "fopen(%s) failed: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); return (-1); } /* * See if we really have a log file -- it might be a zone dump - * that was in the process of being renamed, or it might + * that was in the process of being movefiled, or it might * be garbage! */ if (fgets(buf, sizeof(buf), fp)==NULL) { ns_error(ns_log_update, "fgets() from %s failed: %s", - zp->z_updatelog, strerror(errno)); + logname, strerror(errno)); fclose(fp); return (-1); } if (strcmp(buf, DumpSignature) == 0) { - /* It's a dump; finish rename that was interrupted. */ + /* It's a dump; finish movefile that was interrupted. */ ns_info(ns_log_update, - "completing interrupted dump rename for %s", + "completing interrupted dump movefile for %s", zp->z_source); - if (rename(zp->z_updatelog, zp->z_source) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - zp->z_updatelog, zp->z_source, + fclose(fp); + if (movefile(logname, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :1", + logname, zp->z_source, strerror(errno)); + fclose(fp); return (-1); } - fclose(fp); /* Finally, tell caller to reload zone. */ return (1); } if (strcmp(buf, LogSignature) != 0) { /* Not a dump and not a log; complain and then bail out. */ ns_error(ns_log_update, "invalid log file %s", - zp->z_updatelog); + logname); fclose(fp); return (-1); } ns_debug(ns_log_update, 3, "merging logs for %s from %s", - zp->z_origin, zp->z_updatelog); + zp->z_origin, logname); lineno = 1; - rrecp_start = NULL; - rrecp_last = NULL; + INIT_LIST(curupd); for (;;) { + err = 0; if (!getword(buf, sizeof buf, fp, 0)) { - if (lineno == (nonempty_lineno + 1)) { + if (lineno == (nonempty_lineno + 1) && !(feof(fp))) { /* * End of a nonempty line inside an update * packet or not inside an update packet. @@ -1644,7 +2152,8 @@ merge_logs(struct zoneinfo *zp) { nonempty_lineno = lineno; } - if (!strcasecmp(buf, "[DYNAMIC_UPDATE]")) { + if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") || + !strcasecmp(buf, "[IXFR_UPDATE]")) { err = 0; rcode = NOERROR; cp = fgets(buf, sizeof buf, fp); @@ -1665,13 +2174,13 @@ merge_logs(struct zoneinfo *zp) { &old_serial, &new_serial)) { ns_error(ns_log_update, "incr_serial problem with %s", - zp->z_updatelog); + logname); } else { serial = get_serial(zp); if (serial != old_serial) { ns_error(ns_log_update, "serial number mismatch (log=%u, zone=%u) in %s", old_serial, - serial, zp->z_updatelog); + serial, logname); } else { set_serial(zp, new_serial); /* @@ -1682,26 +2191,30 @@ merge_logs(struct zoneinfo *zp) { sched_zone_maint(zp); ns_info(ns_log_update, "set serial to %u (log file %s)", - new_serial, zp->z_updatelog); + new_serial, logname); } } prev_pktdone = 1; cont = 1; + } else if (!strcasecmp(buf, "[END_DELTA]")) { + prev_pktdone = 1; + cont = 1; } if (prev_pktdone) { - if (rrecp_start) { - n = process_updates(rrecp_start, &rcode, + if (!EMPTY(curupd)) { + n = process_updates(&curupd, &rcode, empty_from); if (n > 0) ns_info(ns_log_update, "successfully merged update id %d from log file %s", - id, zp->z_updatelog); - else + id, logname); + else { ns_error(ns_log_update, "error merging update id %d from log file %s", - id, zp->z_updatelog); - free_rrecp(&rrecp_start, &rrecp_last, rcode, - empty_from); + id, logname); + return(-1); + } + free_rrecp(&curupd, rcode, empty_from); } prev_pktdone = 0; if (feof(fp)) @@ -1738,7 +2251,7 @@ merge_logs(struct zoneinfo *zp) { *buf = '\0'; n = sscanf(cp, "origin %s class %s serial %ul", origin, sclass, &serial); - if (n != 3 || strcasecmp(origin, zp->z_origin)) + if (n != 3 || ns_samename(origin, zp->z_origin) != 1) err++; if (cp) lineno++; @@ -1746,7 +2259,7 @@ merge_logs(struct zoneinfo *zp) { ns_error(ns_log_update, "serial number mismatch in update id %d (log=%u, zone=%u) in %s", id, serial, zp->z_serial, - zp->z_updatelog); + logname); inside_next = 0; err++; } @@ -1809,11 +2322,11 @@ merge_logs(struct zoneinfo *zp) { data[0] = '\0'; (void) getword(buf, sizeof buf, fp, 1); if (isdigit(buf[0])) { /* ttl */ - ttl = strtoul(buf, 0, 10); - if (errno == ERANGE && ttl == ULONG_MAX) { + if (ns_parse_ttl(buf, &l) < 0) { err++; break; } + ttl = l; (void) getword(buf, sizeof buf, fp, 1); } @@ -1888,45 +2401,56 @@ merge_logs(struct zoneinfo *zp) { case T_MINFO: case T_RP: (void) strcpy(data, buf); - cp = data + strlen(data) + 1; + cp = data + strlen(data) -1; + *(cp++) = 0; /* ditch dot */ if (!getword((char *)cp, sizeof data - (cp - data), fp, 1)) { err++; break; } - cp += strlen((char *)cp) + 1; + cp += strlen((char *)cp) -1; + *(cp++) = 0; /* ditch dot */ if (type != T_SOA) { n = cp - data; break; } + else + n = cp - data; if (class != zp->z_class || - strcasecmp(dname, zp->z_origin)) { + ns_samename(dname, zp->z_origin) != 1) { err++; break; } - c = getnonblank(fp, zp->z_updatelog); + c = getnonblank(fp, logname); if (c == '(') { multiline = 1; } else { multiline = 0; ungetc(c, fp); } - for (i = 0; i < 5; i++) { - n = getnum(fp, zp->z_updatelog, - GETNUM_SERIAL); - if (getnum_error) { + n = getnum(fp, logname, GETNUM_SERIAL); + if (getnum_error) { + err++; + break; + } + PUTLONG(n, cp); + for (i = 0; i < 4; i++) { + if (getttl(fp, logname, lineno, + &n, &multiline) <= 0) + { err++; break; } PUTLONG(n, cp); } if (multiline && - getnonblank(fp, zp->z_updatelog) - != ')') { + (getnonblank(fp, logname) + != ')')) { err++; break; } + n = cp - data; endline(fp); break; case T_WKS: @@ -1938,11 +2462,11 @@ merge_logs(struct zoneinfo *zp) { cp = data; PUTLONG(n, cp); *cp = (char)getprotocol(fp, - zp->z_updatelog + logname ); n = INT32SZ + sizeof(char); n = getservices((int)n, data, - fp, zp->z_updatelog); + fp, logname); break; case T_NS: case T_CNAME: @@ -2012,22 +2536,24 @@ merge_logs(struct zoneinfo *zp) { cp = data; datasize = sizeof data; cp1 = buf; - while (i > 255) { - if (datasize < 256) { + while (i > MAXCHARSTRING) { + if (datasize <= MAXCHARSTRING){ ns_error(ns_log_update, "record too big"); + fclose(fp); return (-1); } - datasize -= 255; - *cp++ = 255; - memcpy(cp, cp1, 255); - cp += 255; - cp1 += 255; - i -= 255; + datasize -= MAXCHARSTRING; + *cp++ = (char)MAXCHARSTRING; + memcpy(cp, cp1, MAXCHARSTRING); + cp += MAXCHARSTRING; + cp1 += MAXCHARSTRING; + i -= MAXCHARSTRING; } if (datasize < i + 1) { ns_error(ns_log_update, "record too big"); + fclose(fp); return (-1); } *cp++ = i; @@ -2064,6 +2590,29 @@ merge_logs(struct zoneinfo *zp) { } endline(fp); break; + case ns_t_sig: + case ns_t_key: + case ns_t_nxt: + case ns_t_cert: + { + char * errmsg = NULL; + int s; + + s = parse_sec_rdata(buf, sizeof(buf), + 1, + (u_char *)data, + sizeof(data), + fp, zp, dnbuf, + ttl, type, + domain_ctx, + primary_trans, + &errmsg); + if (s < 0) { + err++; + break; + } + break; + } default: err++; } @@ -2086,11 +2635,22 @@ merge_logs(struct zoneinfo *zp) { } } else { /* section == S_UPDATE */ if (opcode == DELETE) { + ttl = 0; if (n == 0) { class = C_ANY; if (type == -1) type = T_ANY; - } else { + /* WTF? C_NONE or C_ANY _must_ be the case if + * we really are to delete this. If + * C_NONE is used, according to process_updates(), + * the class is gotten from the zone's class. + * This still isn't perfect, but it will at least + * work. + * + * Question: What is so special about the class + * of the update while we are deleting?? + */ + } else /* if (zp->z_xferpid != XFER_ISIXFR) */ { class = C_NONE; } } @@ -2108,8 +2668,7 @@ merge_logs(struct zoneinfo *zp) { ns_debug(ns_log_update, 1, "merge of update id %d failed due to error at line %d", id, lineno); - free_rrecp(&rrecp_start, &rrecp_last, rcode, - empty_from); + free_rrecp(&curupd, FORMERR, empty_from); continue; } rrecp = res_mkupdrec(section, dname, class, type, ttl); @@ -2118,21 +2677,12 @@ merge_logs(struct zoneinfo *zp) { dp->d_zone = zonenum; dp->d_cred = DB_C_ZONE; dp->d_clev = nlabels(zp->z_origin); + dp->d_secure = DB_S_INSECURE; /* should be UNCHECKED */ rrecp->r_dp = dp; } else { rrecp->r_zone = zonenum; } - if (rrecp_start == NULL) { - rrecp_start = rrecp; - rrecp_last = rrecp; - rrecp->r_prev = NULL; - rrecp->r_next = NULL; - } else { - rrecp_last->r_next = rrecp; - rrecp->r_prev = rrecp_last; - rrecp->r_next = NULL; - rrecp_last = rrecp; - } + APPEND(curupd, rrecp, r_link); } /* for (;;) */ fclose(fp); @@ -2144,9 +2694,7 @@ merge_logs(struct zoneinfo *zp) { * Create a disk database to back up zones */ int -zonedump(zp) - struct zoneinfo *zp; -{ +zonedump(struct zoneinfo *zp, int mode) { FILE *fp; const char *fname; struct hashbuf *htp; @@ -2213,11 +2761,13 @@ zonedump(zp) if (fflush(fp) == EOF) { ns_error(ns_log_update, "fflush() of %s failed: %s", tmp_name, strerror(errno)); + fclose(fp); return (-1); } if (fsync(fileno(fp)) < 0) { ns_error(ns_log_update, "fsync() of %s failed: %s", tmp_name, strerror(errno)); + fclose(fp); return (-1); } if (fclose(fp) == EOF) { @@ -2242,16 +2792,47 @@ zonedump(zp) tmp_name, st.st_mode, strerror(errno)); } - if (rename(tmp_name, zp->z_updatelog) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - tmp_name, zp->z_updatelog, strerror(errno)); - return (-1); - } - if (rename(zp->z_updatelog, zp->z_source) < 0) { - ns_error(ns_log_update, "rename(%s,%s) failed: %s", - zp->z_updatelog, zp->z_source, - strerror(errno)); - return (-1); + + if (mode == ISIXFR) { + if (movefile(tmp_name, zp->z_ixfr_tmp) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :2", + tmp_name, zp->z_ixfr_tmp, strerror(errno)); + return (-1); + } + if (chmod(zp->z_source, 0644) < 0) + ns_error(ns_log_update, + "chmod(%s,%o) failed, pressing on: %s", + zp->z_source, st.st_mode, + strerror(errno)); + if (movefile(zp->z_ixfr_tmp, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :3", + zp->z_ixfr_tmp, zp->z_source, + strerror(errno)); + return (-1); + } + st.st_mode &= ~WRITEABLE_MASK; + if (chmod(zp->z_source, st.st_mode) < 0) + ns_error(ns_log_update, + "chmod(%s,%o) failed, pressing on: %s", + zp->z_source, st.st_mode, + strerror(errno)); + } else if (mode == ISNOTIXFR) { + if (movefile(tmp_name, zp->z_updatelog) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s :4", + tmp_name, zp->z_updatelog, strerror(errno)); + return (-1); + } + if (movefile(zp->z_updatelog, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: %s:5", + zp->z_updatelog, zp->z_source, + strerror(errno)); + return (-1); + } + } else { + if (movefile(tmp_name, zp->z_source) < 0) { + ns_error(ns_log_update, "movefile(%s,%s) failed: % s :6", tmp_name, zp->z_source, strerror(errno)); + return (-1); + } } } else ns_debug(ns_log_update, 1, "zonedump: no zone to dump"); @@ -2332,10 +2913,10 @@ set_serial(struct zoneinfo *zp, u_int32_t serial) { zp->z_updatecnt = 0; #ifdef BIND_NOTIFY if (!loading) - sysnotify(zp->z_origin, zp->z_class, T_SOA); + ns_notify(zp->z_origin, zp->z_class, ns_t_soa); #endif /* - * Note: caller is responsible for scheduling a dump + * Note: caller is responsible for scheduling a dump. */ } @@ -2346,8 +2927,10 @@ set_serial(struct zoneinfo *zp, u_int32_t serial) { int incr_serial(struct zoneinfo *zp) { u_int32_t serial, old_serial; - FILE *fp; + FILE *fp, *ifp; time_t t; + struct databuf *dp, *olddp; + unsigned char *cp; old_serial = get_serial(zp); serial = old_serial + 1; @@ -2364,6 +2947,32 @@ incr_serial(struct zoneinfo *zp) { old_serial, serial, checked_ctime(&t)); if (close_transaction_log(zp, fp)<0) return (-1); + ifp = open_ixfr_log(zp); + if (ifp == NULL) + return (-1); + dp = findzonesoa(zp); + if (dp) { + olddp = memget(DATASIZE(dp->d_size)); + if (olddp != NULL) { + memcpy(olddp, dp, DATASIZE(dp->d_size)); + cp = findsoaserial(olddp->d_data); + PUTLONG(old_serial, cp); + fprintf(ifp, "update: {delete} %s. %u %s %s ", + zp->z_origin, dp->d_ttl, + p_class(dp->d_class), p_type(dp->d_type)); + (void) rdata_dump(olddp, ifp); + fprintf(ifp, "\n"); + memput(olddp, DATASIZE(dp->d_size)); + } + fprintf(ifp, "update: {add} %s. %u %s %s ", + zp->z_origin, dp->d_ttl, + p_class(dp->d_class), p_type(dp->d_type)); + (void) rdata_dump(dp, ifp); + fprintf(ifp, "\n"); + } + fprintf(ifp, "[END_DELTA]\n"); + if (close_ixfr_log(zp, ifp)<0) + return (-1); /* * This shouldn't happen, but we check to be sure. @@ -2390,6 +2999,6 @@ dynamic_about_to_exit(void) { if ((zp->z_flags & Z_DYNAMIC) && ((zp->z_flags & Z_NEED_SOAUPDATE) || (zp->z_flags & Z_NEED_DUMP))) - (void)zonedump(zp); + (void)zonedump(zp, ISNOTIXFR); } } |