diff options
Diffstat (limited to 'contrib/bind/bin/named/ns_update.c')
-rw-r--r-- | contrib/bind/bin/named/ns_update.c | 3066 |
1 files changed, 0 insertions, 3066 deletions
diff --git a/contrib/bind/bin/named/ns_update.c b/contrib/bind/bin/named/ns_update.c deleted file mode 100644 index 1c88e25..0000000 --- a/contrib/bind/bin/named/ns_update.c +++ /dev/null @@ -1,3066 +0,0 @@ -#if !defined(lint) && !defined(SABER) -static const char rcsid[] = "$Id: ns_update.c,v 8.106 2002/07/19 22:44:07 marka Exp $"; -#endif /* not lint */ - -/* - * Copyright (c) 1996-2000 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM 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. - */ - -/* - * 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> - */ - -#include "port_before.h" - -#include <sys/param.h> -#include <sys/uio.h> -#include <sys/file.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> - -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <arpa/inet.h> - -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <resolv.h> -#include <res_update.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <syslog.h> -#include <time.h> -#include <unistd.h> - -#include <isc/eventlib.h> -#include <isc/logging.h> -#include <isc/memcluster.h> -#include <isc/dst.h> -#include <isc/misc.h> - -#include "port_after.h" - -#include "named.h" - -#define WRITEABLE_MASK (S_IWUSR | S_IWGRP | S_IWOTH) - -/* XXXRTH almost all funcs. in here should be static! - map rdata_dump to db_to_textual - map rdata_expand to wire_to_db - make a textual_to_db and use it in merge_logs? - replace all this "map" stuff with the new routines (from 4.9.5 I think) - */ - -/* from ns_req.c */ - -static struct map m_opcode[] = { - { "nxdomain", NXDOMAIN }, - { "yxdomain", YXDOMAIN }, - { "nxrrset", NXRRSET }, - { "yxrrset", YXRRSET }, - { "delete", DELETE }, - { "add", ADD }, -}; -#define M_OPCODE_CNT (sizeof(m_opcode) / sizeof(struct map)) - -/* XXXRTH workaround map difficulties */ -#define M_CLASS_CNT m_class_cnt -#define M_TYPE_CNT m_type_cnt - -static const char *opcodes[] = { - "delete", - "add", - "", - "nxdomain", - "", - "", - "yxdomain", - "yxrrset", - "nxrrset", - "", - "", -}; - - -/* from db_load.c */ - -static struct map m_section[] = { - { "zone", S_ZONE }, - { "prereq", S_PREREQ }, - { "update", S_UPDATE }, - { "reserved", S_ADDT }, -}; -#define M_SECTION_CNT (sizeof(m_section) / sizeof(struct map)) - -/* Forward. */ - -static int rdata_expand(const u_char *, const u_char *, const u_char *, - u_int, size_t, u_char *, size_t); - - -static FILE * -open_transaction_log(struct zoneinfo *zp) { - FILE *fp = fopen(zp->z_updatelog, "a+"); - - if (fp == NULL) { - ns_error(ns_log_update, "can't open %s: %s", zp->z_updatelog, - strerror(errno)); - return (NULL); - } - (void) fchown(fileno(fp), user_id, group_id); - if (fseek(fp, 0L, SEEK_END) != 0) { - ns_error(ns_log_update, "can't fseek(%s, 0, SEEK_END)", - zp->z_updatelog); - fclose(fp); - return (NULL); - } - if (ftell(fp) == 0L) { - fprintf(fp, "%s", LogSignature); - zp->z_serial_ixfr_start = get_serial(zp); - } - else - zp->z_serial_ixfr_start = 0; - return (fp); -} - -static FILE * -open_ixfr_log(struct zoneinfo *zp) { - FILE *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); - } - (void) fchown(fileno(fp), user_id, group_id); - if (fseek(fp, 0L, SEEK_END) != 0) { - ns_error(ns_log_update, "can't fseek(%s, 0, SEEK_END)", - zp->z_ixfr_base); - fclose(fp); - return (NULL); - } - if (ftell(fp) == 0L) { - fprintf(fp, "%s", LogSignature); - } - return (fp); -} - -static int -close_transaction_log(struct zoneinfo *zp, FILE *fp) { - if (fflush(fp) == EOF) { - ns_error(ns_log_update, "fflush() of %s failed: %s", - zp->z_updatelog, strerror(errno)); - return (-1); - } - if (fsync(fileno(fp)) < 0) { - ns_error(ns_log_update, "fsync() of %s failed: %s", - zp->z_updatelog, strerror(errno)); - return (-1); - } - if (fclose(fp) == EOF) { - ns_error(ns_log_update, "fclose() of %s failed: %s", - zp->z_updatelog, strerror(errno)); - return (-1); - } - 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, updlist, hp, zp, old_serial) - * append an ascii form to the zone's transaction log file. - */ -static void -printupdatelog(struct sockaddr_in srcaddr, - const ns_updque *updlist, - HEADER *hp, - struct zoneinfo *zp, - u_int32_t old_serial) -{ - struct databuf *dp; - ns_updrec *rrecp; - int opcode; - char time[25]; - FILE *fp, *ifp; - - if (EMPTY(*updlist)) - return; - - fp = open_transaction_log(zp); - if (fp == NULL) - return; - - if (zp->z_maintain_ixfr_base == 1) { - ifp = open_ixfr_log(zp); - if (ifp == NULL) { - (void) close_transaction_log(zp, fp); - return; - } - } - else - ifp = NULL; - - sprintf(time, "at %lu", (u_long)tt.tv_sec); - fprintf(fp, "[DYNAMIC_UPDATE] id %u from %s %s (named pid %ld):\n", - ntohs(hp->id), sin_ntoa(srcaddr), time, (long)getpid()); - if (ifp) - 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); - if (ifp) - fprintf(ifp, - "zone:\torigin %s class %s serial %lu\n", - zp->z_origin, p_class(zp->z_class), - (u_long)old_serial); - break; - case S_PREREQ: - opcode = rrecp->r_opcode; - fprintf(fp, "prereq:\t{%s} %s. %s ", - opcodes[opcode], rrecp->r_dname, - p_class(zp->z_class)); - if (opcode == NXRRSET || opcode == YXRRSET) { - fprintf(fp, "%s ", p_type(rrecp->r_type)); - if ((dp = rrecp->r_dp) && dp->d_size > 0) { - dp->d_class = zp->z_class; - (void) rdata_dump(dp, fp); - } - } - fprintf(fp, "\n"); - 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)) { - if (ifp) { - 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)) { - if (ifp) { - 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) - fprintf(fp, "%u ", rrecp->r_ttl); - fprintf(fp, "%s ", p_class(zp->z_class)); - if (rrecp->r_type != T_ANY) - fprintf(fp, "%s ", p_type(rrecp->r_type)); - if ((dp = rrecp->r_dp) && dp->d_size > 0) { - dp->d_class = zp->z_class; - (void) rdata_dump(dp, fp); - } - fprintf(fp, "\n"); - break; - case S_ADDT: - break; - default: - ns_panic(ns_log_update, 1, - "printupdatelog - impossible condition"); - /*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)) { - if (ifp) { - 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); - if (ifp) - (void) close_ixfr_log(zp, ifp); -} - -static void -cancel_soa_update(struct zoneinfo *zp) { - ns_debug(ns_log_update, 3, "cancel_soa_update for %s", zp->z_origin); - zp->z_flags &= ~Z_NEED_SOAUPDATE; - zp->z_soaincrtime = 0; - zp->z_updatecnt = 0; -} - -/* - * Figure out when a SOA serial number update should happen. - * Returns non-zero if the caller should call sched_zone_maint(zp). - */ -int -schedule_soa_update(struct zoneinfo *zp, int numupdated) { - (void) gettime(&tt); - - zp->z_flags |= Z_NEED_SOAUPDATE; - - /* - * Only z_deferupdcnt updates are allowed before we force - * a serial update. - */ - zp->z_updatecnt += numupdated; - if (zp->z_updatecnt >= zp->z_deferupdcnt) { - if (zp->z_soaincrtime > tt.tv_sec) { - zp->z_soaincrtime = tt.tv_sec; - return (1); - } - } - - if (zp->z_soaincrintvl > 0) { - /* We want automatic updates in this zone. */ - if (zp->z_soaincrtime > 0) { - /* Already scheduled. */ - ns_debug(ns_log_update, 3, - "schedule_soa_update('%s'): already scheduled", - zp->z_origin); - return (0); - } else { - /* First update since the soa was last incremented. */ - zp->z_updatecnt = numupdated; - zp->z_soaincrtime = tt.tv_sec + zp->z_soaincrintvl; - /* - * Never schedule soaincrtime to occur after - * dumptime. - */ - if (zp->z_soaincrtime > zp->z_dumptime) - zp->z_soaincrtime = zp->z_dumptime; - ns_debug(ns_log_update, 3, - "schedule_soa_update('%s'): scheduled for %lu", - zp->z_origin, (u_long)zp->z_soaincrtime); - return (1); - } - } - return (0); -} - -/* - * Figure out when a zone dump should happen. - * Returns non-zero if the caller should call sched_zone_maint(zp). - */ -int -schedule_dump(struct zoneinfo *zp) { - time_t half; - - (void) gettime(&tt); - - zp->z_flags |= Z_NEED_DUMP; - - if (zp->z_dumpintvl > 0) { - /* We want automatic dumping in this zone. */ - if (zp->z_dumptime > 0) { - /* Already scheduled. */ - ns_debug(ns_log_update, 3, - "schedule_dump('%s'): already scheduled", - zp->z_origin); - return (0); - } else { - /* - * Set new dump time for dynamic zone. Use a random - * number in the last half of the dump limit; we want - * it to be substantially correct while still - * preventing dump synchronization among various - * dynamic zones. - */ - half = (zp->z_dumpintvl + 1) / 2; - zp->z_dumptime = tt.tv_sec + half + (rand() % half); - /* - * Never schedule soaincrtime to occur after - * dumptime. - */ - if (zp->z_soaincrtime > zp->z_dumptime) - zp->z_soaincrtime = zp->z_dumptime; - ns_debug(ns_log_update, 3, - "schedule_dump('%s'): scheduled for %lu", - zp->z_origin, (u_long)zp->z_dumptime); - return (1); - } - } - return (0); -} - -/* - * int - * process_prereq(rec, rcodep) - * Process one prerequisite. - * returns: - * >0 prerequisite was satisfied. - * =0 prerequisite was not satisfied, or an error occurred. - * side effects: - * sets *rcodep if an error occurs or prerequisite isn't satisfied. - */ -static int -process_prereq(ns_updrec *ur, int *rcodep, u_int16_t zclass) { - const char *dname = ur->r_dname; - u_int16_t class = ur->r_class; - u_int16_t type = ur->r_type; - u_int32_t ttl = ur->r_ttl; - struct databuf *rdp = ur->r_dp; - const char *fname; - struct hashbuf *htp; - struct namebuf *np; - struct databuf *dp; - - /* - * An element in the list might have already been - * processed if it is in the same RRset as a previous - * RRset Exists (value dependent) prerequisite. - */ - if (rdp && (rdp->d_mark & D_MARK_FOUND) != 0) { - /* Already processed. */ - return (1); - } - if (ttl != 0) { - ns_debug(ns_log_update, 1, - "process_prereq: ttl!=0 in prereq section"); - *rcodep = FORMERR; - return (0); - } - htp = hashtab; - np = nlookup(dname, &htp, &fname, 0); - /* - * 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, - "process_prereq: empty rdata required in prereq section with class=ANY"); - *rcodep = FORMERR; - return (0); - } - if (type == T_ANY) { - /* Name is in use. */ - ur->r_opcode = YXDOMAIN; - if (np == NULL || np->n_data == NULL) { - /* - * Name does not exist or is - * an empty nonterminal. - */ - ns_debug(ns_log_update, 1, - "process_prereq: %s not in use", - dname); - *rcodep = NXDOMAIN; - return (0); - } - } else { - /* RRset exists (value independent). */ - int found = 0; - - ur->r_opcode = YXRRSET; - if (np != NULL) - for (dp = np->n_data; - dp && !found; - dp = dp->d_next) - if (match(dp, class, type) && - dp->d_type == type) - found = 1; - if (!found) { - ns_debug(ns_log_update, 1, - "process_prereq: RRset (%s,%s,%s) does not exist", - dname, p_type(type), p_class(zclass)); - *rcodep = NXRRSET; - return (0); - } - } - } else if (class == C_NONE) { - if (rdp->d_size) { - ns_debug(ns_log_update, 1, - "process_prereq: empty rdata required in prereq section with class=NONE"); - *rcodep = FORMERR; - return (0); - } - if (type == T_ANY) { - /* Name is not in use. */ - ur->r_opcode = NXDOMAIN; - if (np != NULL && np->n_data != NULL) { - /* - * Name exists and is not an - * empty nonterminal. - */ - ns_debug(ns_log_update, 1, - "process_prereq: %s exists", - dname); - *rcodep = YXDOMAIN; - return (0); - } - } else { - /* RRset does not exist. */ - int found = 0; - - ur->r_opcode = NXRRSET; - class = zclass; - if (np != NULL) - for (dp = np->n_data; - dp && !found; - dp = dp->d_next) - if (match(dp, class, type)) - found = 1; - if (found) { - ns_debug(ns_log_update, 1, - "process_prereq: RRset (%s,%s) exists", - dname, p_type(type)); - *rcodep = YXRRSET; - return (0); - } - } - } else if (class == zclass) { - /* - * RRset exists (value dependent). - * - * Check for RRset equality also. - */ - ns_updrec *tmp; - - ur->r_opcode = YXRRSET; - if (!rdp) { - ns_debug(ns_log_update, 1, - "process_prereq: nonempty rdata required in prereq section with class=%s", - p_class(class)); - *rcodep = FORMERR; - return (0); - } - if (np == NULL || fname != dname) { - *rcodep = NXRRSET; - return (0); - } - for (dp = np->n_data; dp; dp = dp->d_next) { - if (match(dp, class, type) && dp->d_type == type) { - int found = 0; - - for (tmp = ur; - tmp != NULL && !found; - tmp = NEXT(tmp, r_link)) { - if (tmp->r_section != S_PREREQ) - break; - if (!db_cmp(dp, tmp->r_dp)) { - tmp->r_dp->d_mark |= - D_MARK_FOUND; - found = 1; - } - } - if (!found) { - *rcodep = NXRRSET; - return (0); - } - } - } - for (tmp = ur; tmp != NULL; tmp = NEXT(tmp, r_link)) - if (tmp->r_section == S_PREREQ && - ns_samename(dname, tmp->r_dname) == 1 && - tmp->r_class == class && - tmp->r_type == type && - (ur->r_dp->d_mark & D_MARK_FOUND) == 0) { - *rcodep = NXRRSET; - return (0); - } else { - tmp->r_opcode = YXRRSET; - } - } else { - ns_debug(ns_log_update, 1, - "process_prereq: incorrect class %s", - p_class(class)); - *rcodep = FORMERR; - return (0); - } - /* Through the gauntlet, and out. */ - return (1); -} - -static int -prescan_nameok(ns_updrec *ur, int *rcodep, u_int16_t zclass, - struct zoneinfo *zp) -{ - 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; - enum transport transport; - - /* We don't care about deletes */ - if (ur->r_class != zclass) - return (1); - - if (zp->z_type == Z_PRIMARY) - transport = primary_trans; - else - transport = secondary_trans; - - context = ns_ownercontext(type, transport); - if (!ns_nameok(NULL, owner, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - - switch (type) { - case ns_t_soa: - context = hostname_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - cp += strlen(cp) + 1; - context = mailname_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - break; - case ns_t_rp: - context = mailname_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - cp += strlen(cp) + 1; - context = domain_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - break; - case ns_t_minfo: - context = mailname_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - cp += strlen(cp) + 1; - context = mailname_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - break; - case ns_t_ns: - context = hostname_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, 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, transport, context, owner, - inaddr_any)) - goto refused; - break; - case ns_t_ptr: - context = ns_ptrcontext(owner); - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - break; - case ns_t_naptr: - /* - * Order (2) - * Preference (2) - */ - cp += 4; - /* Flags (txt) */ - cp += (*cp&0xff) + 1; - /* Service (txt) */ - cp += (*cp&0xff) + 1; - /* Pattern (txt) */ - cp += (*cp&0xff) + 1; - context = domain_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, - 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, transport, context, owner, - inaddr_any)) - goto refused; - break; - case ns_t_px: - cp += 2; - context = domain_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - cp += strlen(cp) + 1; - if (!ns_nameok(NULL, cp, class, zp, transport, 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, transport, context, owner, - inaddr_any)) - goto refused; - break; - case ns_t_nxt: - context = domain_ctx; - if (!ns_nameok(NULL, cp, class, zp, transport, context, owner, - inaddr_any)) - goto refused; - break; - default: - break; - } - return (1); - refused: - *rcodep = REFUSED; - return (0); -} - -/* - * int - * prescan_update(ur, rcodep) - * Process one prerequisite. - * returns: - * >0 update looks OK (format wise; who knows if it will succeed?) - * =0 update has something wrong with it. - * side effects: - * sets *rcodep if an error occurs or prerequisite isn't satisfied. - */ -static int -prescan_update(ns_updrec *ur, int *rcodep, u_int16_t zclass) { - u_int16_t class = ur->r_class; - u_int16_t type = ur->r_type; - u_int32_t ttl = ur->r_ttl; - struct databuf *rdp = ur->r_dp; - - if (class == zclass) { - if (!ns_t_rr_p(type)) { - ns_debug(ns_log_update, 1, - "prescan_update: invalid type (%s)", - p_type(type)); - *rcodep = FORMERR; - return (0); - } - if (ttl > MAXIMUM_TTL) { - ns_debug(ns_log_update, 1, - "prescan_update: invalid ttl (%u)", ttl); - *rcodep = FORMERR; - return (0); - } - } else if (class == C_ANY) { - if (ttl != 0 || rdp->d_size || - (!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 || !ns_t_rr_p(type)) { - ns_debug(ns_log_update, 1, - "prescan_update: formerr(#3) %d %s", - ttl, p_type(type)); - *rcodep = FORMERR; - return (0); - } - } else { - ns_debug(ns_log_update, 1, - "prescan_update: invalid class (%s)", - p_class(class)); - *rcodep = FORMERR; - return (0); - } - /* No format errors found. */ - return (1); -} - -/* - * int - * 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. - * side effects: - * *rcodep gets the transaction return code. - * can schedule maintainance for zone dumps and soa.serial# increments. - */ -static int -process_updates(const ns_updque *updlist, int *rcodep, - struct sockaddr_in from) -{ - int j, n, dbflags, matches, zonenum; - int numupdated = 0, soaupdated = 0, schedmaint = 0; - u_int16_t zclass; - ns_updrec *ur; - struct databuf *dp, *savedp; - struct zoneinfo *zp; - int zonelist[MAXDNAME]; - - *rcodep = SERVFAIL; - if (EMPTY(*updlist)) - return (0); - 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, - "process_updates: missing zone record"); - return (0); - } - - /* Process prereq records and prescan update records. */ - 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; - u_int32_t ttl = ur->r_ttl; - struct databuf *rdp = ur->r_dp; - u_int section = ur->r_section; - - ns_debug(ns_log_update, 3, -"process_update: record section=%s, dname=%s, \ -class=%s, type=%s, ttl=%d, dp=%p", - p_section(section, ns_o_update), dname, - p_class(class), p_type(type), ttl, rdp); - - matches = findzone(dname, zclass, MAXDNAME, - zonelist, MAXDNAME); - ur->r_zone = 0; - for (j = 0; j < matches && !ur->r_zone; j++) - if (zonelist[j] == zonenum) - ur->r_zone = zonelist[j]; - 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); - *rcodep = NOTZONE; - return (0); - } - - switch (section) { - case S_ZONE: - break; - case S_PREREQ: - if (!process_prereq(ur, rcodep, zclass)) - return (0); /* *rcodep has been set. */ - ns_debug(ns_log_update, 3, "prerequisite satisfied"); - break; - 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: - break; - default: - ns_panic(ns_log_update, 1, - "process_updates: impossible section"); - /* NOTREACHED */ - } - } - - /* Now process the records in update section. */ - for (ur = HEAD(*updlist); ur != NULL; ur = NEXT(ur, r_link)) { - const char * dname = ur->r_dname; - u_int16_t class = ur->r_class; - - if (ur->r_section != S_UPDATE) - continue; - dbflags = 0; - savedp = NULL; - dp = ur->r_dp; - if (class == zp->z_class) { - /* ADD databuf dp to hash table */ - /* - * Handling of various SOA/WKS/CNAME scenarios - * is done in db_update(). - */ - ur->r_opcode = ADD; - dbflags |= DB_NODATA | DB_REPLACE; - n = db_update(dname, dp, dp, &savedp, - dbflags, hashtab, from); - if (!((n == OK) || - ((zp->z_xferpid == XFER_ISIXFR) && (n == DATAEXISTS)))) { - ns_debug(ns_log_update, 3, - "process_updates: failed to add databuf (%d)", - n); - } else { - ns_debug(ns_log_update, 3, - "process_updates: added databuf %p", - dp); - dp->d_mark = D_MARK_ADDED; - numupdated++; - if (dp->d_type == T_SOA) - soaupdated = 1; - } - } else if (class == C_ANY || class == C_NONE) { - /* - * DELETE databuf's matching dp from the hash table. - * - * handling of various SOA/NS scenarios done - * in db_update(). - */ - ur->r_opcode = DELETE; - /* - * we know we're deleting now, and db_update won't - * match with class==C_NONE, so we use the zone's - * class. - */ - if (class == C_NONE) - ur->r_dp->d_class = zp->z_class; - dbflags |= DB_DELETE; - n = db_update(dname, dp, NULL, &savedp, - dbflags, hashtab, from); - if (!((n == OK) || - ((zp->z_xferpid == XFER_ISIXFR) && (n == NODATA)))) { - ns_debug(ns_log_update, 3, - "process_updates: delete failed"); - } else { - ns_debug(ns_log_update, 3, - "process_updates: delete succeeded"); - numupdated++; - } - } - /* - * Even an addition could have caused some deletions like - * replacing old SOA or CNAME or WKS record or records of - * lower cred/clev. - * - * We need to save the deleted databuf's in case we wish to - * abort this update transaction and roll back all updates - * applied from this packet. - */ - ur->r_deldp = savedp; - } - - /* - * If we got here, things are OK, so set rcodep to indicate so. - */ - *rcodep = NOERROR; - - if (!numupdated) - return (0); - - /* - * schedule maintenance for dumps and SOA.serial# increment - * (this also sets Z_NEED_DUMP and Z_NEED_SOAUPDATE appropriately) - */ - schedmaint = 0; - if (schedule_dump(zp)) - schedmaint = 1; - if (soaupdated) { - /* - * SOA updated by this update transaction, so - * we need to set the zone serial number, stop any - * automatic updates that may be pending, and send out - * a NOTIFY message. - */ - zp->z_serial = get_serial_unchecked(zp); - cancel_soa_update(zp); - schedmaint = 1; -#ifdef BIND_NOTIFY - if (!loading) - ns_notify(zp->z_origin, zp->z_class, ns_t_soa); -#endif - } else { - if (schedule_soa_update(zp, numupdated)) - schedmaint = 1; - } - if (schedmaint) - sched_zone_maint(zp); - return (numupdated); -} - -static enum req_action -req_update_private(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, - struct sockaddr_in from, struct tsig_record *in_tsig, - ns_updque *curupd) -{ - char dnbuf[MAXDNAME], *dname; - u_int zocount, prcount, upcount, adcount, class, type, dlen; - u_int32_t ttl; - int i, n, matches, zonenum, numupdated = 0; - int rcode = NOERROR; - u_int section; - u_char rdata[MAXDATA]; - struct databuf *dp, *nsp[NSMAX]; - struct zoneinfo *zp; - ns_updrec *rrecp; - int zonelist[MAXDNAME]; - u_int32_t old_serial; - DST_KEY *in_key = (in_tsig != NULL) ? in_tsig->key : NULL; - - nsp[0] = NULL; - - zocount = ntohs(hp->qdcount); - prcount = ntohs(hp->ancount); - upcount = ntohs(hp->nscount); - adcount = ntohs(hp->arcount); - - /* Process zone section. */ - ns_debug(ns_log_update, 3, "req_update: section ZONE, count %d", - zocount); - if ((n = dn_expand(msg, eom, cp, dnbuf, sizeof(dnbuf))) < 0) { - ns_debug(ns_log_update, 1, "req_update: expand name failed"); - hp->rcode = FORMERR; - return (Finish); - } - dname = dnbuf; - cp += n; - if (cp + 2 * INT16SZ > eom) { - ns_debug(ns_log_update, 1, "req_update: too short"); - hp->rcode = FORMERR; - return (Finish); - } - GETSHORT(type, cp); - GETSHORT(class, cp); - if (zocount != 1 || type != T_SOA) { - ns_debug(ns_log_update, 1, - "req_update: incorrect count or type for zone section: %d", - zocount); - hp->rcode = FORMERR; - return (Finish); - } - - matches = findzone(dname, class, 0, zonelist, MAXDNAME); - if (matches == 1) { - zonenum = zonelist[0]; - zp = &zones[zonenum]; - if (zp->z_class != (int)class || - (zp->z_type != z_master && zp->z_type != z_slave)) - matches = 0; - } - if (matches != 1) { - ns_debug(ns_log_update, 1, - "req_update: non-authoritative server for %s", - dname); - hp->rcode = NOTAUTH; - return (Finish); - } - - /* - * Begin Access Control Point - */ - - if (!ip_addr_or_key_allowed(zp->z_update_acl, from.sin_addr, in_key)) { - ns_notice(ns_log_update_security, - "denied update from %s for \"%s\" %s", - sin_ntoa(from), *dname ? dname : ".", p_class(class)); - nameserIncr(from.sin_addr, nssRcvdUUpd); - return (Refuse); - } - - /* - * End Access Control Point - */ - - /* we should be authoritative */ - if (!(zp->z_flags & Z_AUTH)) { - ns_debug(ns_log_update, 1, - "req_update: zone %s: Z_AUTH not set", - dname); - hp->rcode = NOTAUTH; - return (Finish); - } - - if (zp->z_type == Z_SECONDARY) { - /* - * XXX The code below is broken. - * Until fixed, we just return NOTIMPL. - */ -#if 1 - hp->rcode = ns_r_notimpl; - return (Finish); -#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, - (u_char *)&zp->z_addr[cnt].s_addr, - INT32SZ); - *nspp = NULL; - /* - * 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, NULL); - if (in_tsig != NULL) - eom -= tsig_len; - free_nsp(nsp); - switch (n) { - case FW_OK: - case FW_DUP: - return (Return); - case FW_NOSERVER: - /* should not happen */ - case FW_SERVFAIL: - hp->rcode = SERVFAIL; - return (Finish); - } -#endif - } - /* - * We are the primary master server for this zone, - * proceed further and process update packet - */ - if (!(zp->z_flags & Z_DYNAMIC)) { - ns_debug(ns_log_update, 1, - "req_update: dynamic flag not set for zone %s", - dname); - return (Refuse); - } - old_serial = get_serial(zp); - ns_debug(ns_log_update, 3, - "req_update: update request for zone %s, class %s", - zp->z_origin, p_class(class)); - 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. - */ - for (i = 0; (u_int)i < prcount + upcount; i++) { - if ((n = dn_expand(msg, eom, cp, dnbuf, sizeof(dnbuf))) < 0) { - ns_debug(ns_log_update, 1, - "req_update: expand name failed"); - hp->rcode = FORMERR; - return (Finish); - } - dname = dnbuf; - cp += n; - if (cp + RRFIXEDSZ > eom) { - ns_debug(ns_log_update, 1, - "req_update: overrun in answer"); - hp->rcode = FORMERR; - return (Finish); - } - 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; - dp = NULL; - if (dlen > 0) { - if (cp + dlen > eom) { - ns_debug(ns_log_update, 1, - "req_update: bad dlen"); - hp->rcode = FORMERR; - return (Finish); - } - n = rdata_expand(msg, eom, cp, type, dlen, - rdata, sizeof rdata); - if (n == 0 || n > MAXDATA) { - ns_debug(ns_log_update, 1, - "req_update: failed to expand record"); - hp->rcode = FORMERR; - return (Finish); - } - cp += dlen; - } - section = ((u_int)i < prcount) ? S_PREREQ : S_UPDATE; - rrecp = res_mkupdrec(section, dname, class, type, ttl); - 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. */ - APPEND(*curupd, rrecp, r_link); - if (cp > eom) { - ns_info(ns_log_update, - "Malformed response from %s (overrun)", - inet_ntoa(from.sin_addr)); - hp->rcode = FORMERR; - return (Finish); - } - } - - /* Now process all parsed records in the prereq and update sections. */ - numupdated = process_updates(curupd, &rcode, from); - hp->rcode = rcode; - if (numupdated <= 0) { - 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, curupd, hp, zp, old_serial); - - return (Finish); -} - -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; - const char *msg; - - if (rcode == NOERROR) { - first_rrecp = HEAD(*updlist); - msg = "free_rrecp: update transaction succeeded, cleaning up"; - } else { - first_rrecp = TAIL(*updlist); - msg = "free_rrecp: update transaction aborted, rolling back"; - } - ns_debug(ns_log_update, 1, "%s", msg); - for (rrecp = first_rrecp; rrecp != NULL; rrecp = next_rrecp) { - if (rcode == NOERROR) - next_rrecp = NEXT(rrecp, r_link); - else - next_rrecp = PREV(rrecp, r_link); - UNLINK(*updlist, rrecp, r_link); - if (rrecp->r_section != S_UPDATE) { - if (rrecp->r_dp) - db_detach(&rrecp->r_dp); - INSIST(rrecp->r_deldp == NULL); - res_freeupdrec(rrecp); - continue; - } - dname = rrecp->r_dname; - dp = rrecp->r_dp; - rrecp->r_dp = NULL; - if ((dp->d_mark & D_MARK_ADDED) != 0) { - if (rcode == NOERROR) { - /* - * This databuf is now a part of hashtab, - * or has been deleted by a subsequent update. - * Either way, we must not free it. - */ - dp->d_mark &= ~D_MARK_ADDED; - } else { - /* Delete the databuf. */ - if (db_update(dname, dp, NULL, NULL, - DB_DELETE, hashtab, from) - != OK) { - ns_error(ns_log_update, - "free_rrecp: failed to delete databuf: dname=%s, type=%s", - dname, p_type(dp->d_type)); - } else { - ns_debug(ns_log_update, 3, - "free_rrecp: deleted databuf %p", - dp); - } - } - } - db_detach(&dp); - - /* Process deleted databuf's. */ - dp = rrecp->r_deldp; - rrecp->r_deldp = NULL; - while (dp != NULL) { - tmpdp = dp; - dp = dp->d_next; - tmpdp->d_next = NULL; - if (rcode != NOERROR) { - /* Add the databuf back. */ - tmpdp->d_mark &= ~D_MARK_DELETED; - if (db_update(dname, tmpdp, tmpdp, NULL, - 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)); - } else { - ns_debug(ns_log_update, 3, - "free_rrecp: added back databuf %p", - tmpdp); - } - } - db_detach(&tmpdp); - } - res_freeupdrec(rrecp); - } -} - -enum req_action -req_update(HEADER *hp, u_char *cp, u_char *eom, u_char *msg, - struct sockaddr_in from, struct tsig_record *in_tsig) -{ - enum req_action ret; - ns_updque curupd; - - INIT_LIST(curupd); - ret = req_update_private(hp, cp, eom, msg, from, in_tsig, &curupd); - 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); - } - return (ret); -} - -/* - * expand rdata portion of a compressed resource record at cp into cp1 - * and return the length of the expanded rdata (length of the compressed - * rdata is "dlen"). - */ -static int -rdata_expand(const u_char *msg, const u_char *eom, const u_char *cp, - u_int type, size_t dlen, u_char *cp1, size_t size) -{ - const u_char *cpinit = cp; - const u_char *cp1init = cp1; - int n, i, n1; - - switch (type) { - case T_A: - case T_AAAA: - if ((type == T_A && dlen != INT32SZ) || - (type == T_AAAA && dlen != NS_IN6ADDRSZ)) - return (0); - /*FALLTHROUGH*/ - case T_WKS: - case T_HINFO: - case T_TXT: - case T_X25: - 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); - return (dlen); - case T_CNAME: - case T_MB: - case T_MG: - case T_MR: - case T_NS: - case T_PTR: - n = dn_expand(msg, eom, cp, (char *)cp1, size); - if (n < 0 || (u_int)n != dlen) - return (0); - return (strlen((char *)cp1) + 1); - case T_MINFO: - case T_SOA: - case T_RP: - /* Get two compressed domain names. */ - for (i = 0; i < 2; i++) { - n = dn_expand(msg, eom, cp, (char *)cp1, size); - if (n < 0) - return (0); - cp += n; - n = strlen((char *)cp1) + 1; - cp1 += n; - size -= n; - } - if (type == T_SOA) { - n = 5 * INT32SZ; - if (size < (size_t)n || cp + n > eom) - return(0); - size -= n; - memcpy(cp1, cp, n); - cp += n; - cp1 += n; - } - if (cp != cpinit + dlen) - return (0); - return (cp1 - cp1init); - case T_MX: - case T_AFSDB: - case T_RT: - case T_SRV: - /* Grab preference. */ - if (size < INT16SZ || cp + INT16SZ > eom) - return (0); - size -= INT16SZ; - memcpy(cp1, cp, INT16SZ); - cp += INT16SZ; - cp1 += INT16SZ; - - if (type == T_SRV) { - if (size < INT16SZ*2 || cp + INT16SZ*2 > eom) - return (0); - size -= INT16SZ*2; - /* Grab weight and port. */ - memcpy(cp1, cp, INT16SZ*2); - cp1 += INT16SZ*2; - cp += INT16SZ*2; - } - - /* Get name. */ - n = dn_expand(msg, eom, cp, (char *)cp1, size); - if (n < 0) - return (0); - cp += n; - n = strlen((char *)cp1) + 1; - cp1 += n; - if (cp != cpinit + dlen) - return (0); - return (cp1 - cp1init); - case T_PX: - /* Grab preference. */ - if (size < INT16SZ || cp + INT16SZ > eom) - return (0); - size -= INT16SZ; - memcpy(cp1, cp, INT16SZ); - cp += INT16SZ; - cp1 += INT16SZ; - /* Get MAP822 name. */ - n = dn_expand(msg, eom, cp, (char *)cp1, size); - if (n < 0) - return (0); - cp += n; - n = strlen((char *)cp1) + 1; - cp1 += n; - size -= n; - n = dn_expand(msg, eom, cp, (char *)cp1, size); - if (n < 0) - return (0); - cp += n; - n = strlen((char *)cp1) + 1; - cp1 += n; - 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 > (int)dlen) - return (0); - cp += n; - n1 = dlen - n - SIG_HDR_SIZE; - n = strlen((char *)cp1) + 1; - cp1 += n; - if ((int)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 > (int)size) - return (0); - memcpy(cp1, cp, n1); - cp1 += n1; - return (cp1 - cp1init); - default: - if (size < dlen) - return (0); - memcpy(cp1, cp, dlen); - return (dlen); - } -} - -/* - * Print out rdata portion of a resource record from a databuf into a file. - * - * XXX - similar code in db_dump() should be replaced by a call to this - * function. - */ -void -rdata_dump(struct databuf *dp, FILE *fp) { - u_int32_t n, addr; - 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) { - case T_A: - switch (dp->d_class) { - case C_IN: - case C_HS: - GETLONG(n, cp); - n = htonl(n); - fputs(inet_ntoa(*(struct in_addr *)&n), fp); - break; - } - if (dp->d_nstime) - fprintf(fp, ";\tNT=%d", dp->d_nstime); - break; - case T_CNAME: - case T_MB: - case T_MG: - case T_MR: - case T_PTR: - fprintf(fp, "%s.", cp); - break; - case T_NS: - cp = (u_char *)dp->d_data; - if (cp[0] == '\0') - fprintf(fp, ".\t"); - else - fprintf(fp, "%s.", cp); - break; - case T_HINFO: - case T_ISDN: - if ((n = *cp++) != '\0') { - fprintf(fp, "\"%.*s\"", (int)n, cp); - cp += n; - } else - fprintf(fp, "\"\""); - if ((n = *cp++) != '\0') - fprintf(fp, " \"%.*s\"", (int)n, cp); - else - fprintf(fp, " \"\""); - break; - case T_SOA: - fprintf(fp, "%s.", cp); - cp += strlen((char *)cp) + 1; - fprintf(fp, " %s. ( ", cp); -#if defined(RETURNSOA) && defined(NCACHE) - if (dp->d_rcode == NXDOMAIN) - fputs(";", fp); -#endif - cp += strlen((char *)cp) + 1; - GETLONG(n, cp); - fprintf(fp, "%u", n); - GETLONG(n, cp); - fprintf(fp, " %u", n); - GETLONG(n, cp); - fprintf(fp, " %u", n); - GETLONG(n, cp); - fprintf(fp, " %u", n); - GETLONG(n, cp); - fprintf(fp, " %u )", n); -#if defined(RETURNSOA) && defined(NCACHE) - if (dp->d_rcode == NXDOMAIN) - fprintf(fp, ";%s.;NXDOMAIN;\t-$", cp); -#endif - break; - case T_MX: - case T_AFSDB: - case T_RT: - GETSHORT(n, cp); - 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); - fprintf(fp, " %s.", cp); - cp += strlen((char *)cp) + 1; - fprintf(fp, " %s.", cp); - break; - case T_TXT: - case T_X25: - end = (u_char *)dp->d_data + dp->d_size; - (void) putc('"', fp); - while (cp < end) { - if ((n = *cp++) != '\0') { - for (j = n; j > 0 && cp < end; j--) - if ((*cp < ' ') || (*cp > '~')) { - fprintf(fp, "\\%03d", *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); - break; - case T_NSAP: - (void) fputs(inet_nsap_ntoa(dp->d_size, dp->d_data, NULL), fp); - break; - case T_LOC: - (void) fputs(loc_ntoa(dp->d_data, NULL), fp); - break; - case T_WKS: - GETLONG(addr, cp); - addr = htonl(addr); - fputs(inet_ntoa(*(struct in_addr *)&addr), fp); - proto = protocolname((u_char)*cp); - cp += sizeof(char); - fprintf(fp, "%s ", proto); - i = 0; - while(cp < (u_char *)dp->d_data + dp->d_size) { - j = *cp++; - do { - if (j & 0200) - fprintf(fp, " %s", - servicename(i, proto)); - j <<= 1; - } while (++i & 07); - } - break; - case T_MINFO: - case T_RP: - fprintf(fp, "%s.", cp); - 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, "\\# %u", dp->d_size); - if (dp->d_size) { - fputs(" ( ", fp); - isc_puthexstring(fp, dp->d_data, dp->d_size, - 28, 48, "\n\t\t\t\t"); - fputs(" )", fp); - } - } -} - -/* - * Return the number of authoritative zones that "dname" could belong to by - * stripping up to "depth" labels from dname. Up to the first "maxzones" - * authoritative zone numbers will be stored in "zonelist", ordered - * deepest match first. - */ -int -findzone(const char *dname, int class, int depth, int *zonelist, int maxzones){ - char *tmpdname; - char tmpdnamebuf[MAXDNAME]; - char *zonename; - int tmpdnamelen, zonenamelen, zonenum, i, j, c; - int matches = 0; - int escaped, found, done; - - ns_debug(ns_log_update, 4, "findzone(dname=%s, class=%d, depth=%d, \ -zonelist=%p, maxzones=%d)", - dname, class, depth, zonelist, maxzones); -#ifdef DEBUG - if (debug >= 5) { - ns_debug(ns_log_update, 5, "zone dump:"); - for (zonenum = 1; zonenum < nzones; zonenum++) - printzoneinfo(zonenum, ns_log_update, 5); - } -#endif - - strcpy(tmpdnamebuf, dname); - tmpdname = tmpdnamebuf; - /* - * The code to handle trailing dots and escapes is adapted - * from ns_samedomain(). - */ - tmpdnamelen = strlen(tmpdname); - /* - * Ignore a trailing label separator (i.e. an unescaped dot) - * in 'tmpdname'. - */ - if (tmpdnamelen && tmpdname[tmpdnamelen-1] == '.') { - escaped = 0; - /* note this loop doesn't get executed if tmpdnamelen==1 */ - for (j = tmpdnamelen - 2; j >= 0; j--) - if (tmpdname[j] == '\\') { - if (escaped) - escaped = 0; - else - escaped = 1; - } else { - break; - } - if (!escaped) { - tmpdnamelen--; - tmpdname[tmpdnamelen] = '\0'; - } - } - - for (done = i = 0; i <= depth && !done; i++) { - for (zonenum = 1; zonenum < nzones; zonenum++) { - if (zones[zonenum].z_type == z_nil) - continue; - if (zones[zonenum].z_class != class) - continue; - zonename = zones[zonenum].z_origin; - zonenamelen = strlen(zonename); - /* - * Ignore a trailing label separator - * (i.e. an unescaped dot) in 'zonename'. - */ - if (zonenamelen && zonename[zonenamelen-1] == '.') { - escaped = 0; - for (j = zonenamelen - 2; j >= 0; j--) - if (zonename[j] == '\\') { - if (escaped) - escaped = 0; - else - escaped = 1; - } else { - break; - } - if (!escaped) - zonenamelen--; - } - - if (tmpdnamelen != zonenamelen) - continue; - ns_debug(ns_log_update, 5, - "about to strncasecmp('%s', '%s', %d)", - tmpdname, zonename, tmpdnamelen); - /* XXXRTH I'm doing a special test for zonenamelen == 0 - because I worry that some implementations of - strncasecmp might not handle comparisions where - n==0 correctly */ - if (zonenamelen == 0 || - !strncasecmp(tmpdname, zonename, tmpdnamelen)) { - ns_debug(ns_log_update, 5, "match"); - zonelist[matches++] = zonenum; - if (matches == maxzones) { - /* XXX should signal error */ - return (matches); - } - } - } - - /* - * Strip off the first label if we're not already at - * the root label. - */ - if (*tmpdname != '\0') { - for (escaped = found = 0; - (c = *tmpdname) && !found; - tmpdname++) { - if (!escaped && (c == '.')) - /* - * Note the loop increment will - * make tmpdname point past the '.' - * before the '!found' test causes - * us to exit the loop. - */ - found = 1; - - if (escaped) - escaped = 0; - else if (c == '\\') - escaped = 1; - } - } else - done = 1; - - tmpdnamelen = strlen(tmpdname); - } - ns_debug(ns_log_update, 4, - "findzone: returning %d match(es)", matches); - return (matches); -} - -/* - * reapply lost updates from log file for the zone to the zone - * - * returns -1 on error, 0 on success, 1 if dump reload needed - */ -int -merge_logs(struct zoneinfo *zp, char *logname) { - char origin[MAXDNAME], data[MAXDATA], dnbuf[MAXDNAME], sclass[3]; - char buf[BUFSIZ]; - FILE *fp; - u_int32_t serial, ttl, old_serial, new_serial; - char *dname, *cp, *cp1; - int type, class; - int i, c, section, opcode, matches, zonenum = 0, err, multiline; - int nonempty_lineno = -1, prev_pktdone = 0, cont = 0, inside_next = 0; - int id, rcode = NOERROR; - u_int32_t n; - struct map *mp; - ns_updrec *rrecp; - struct databuf *dp; - struct in_addr ina; - int zonelist[MAXDNAME]; - struct stat st; - struct sockaddr_in empty_from; - int datasize; - unsigned long l; - ns_updque curupd; - unsigned long lutmp; - - empty_from.sin_family = AF_INET; - empty_from.sin_addr.s_addr = htonl(INADDR_ANY); - empty_from.sin_port = htons(0); - - /* XXX - much of this stuff is similar to that in nsupdate.c - * getword_str() was used in nsupdate.c for reasons described there - * 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(logname, &st) < 0) { - if (errno != ENOENT) - ns_error(ns_log_update, - "unexpected stat(%s) failure: %s", - logname, strerror(errno)); - return (-1); - } - fp = fopen(logname, "r"); - if (fp == NULL) { - ns_error(ns_log_update, "fopen(%s) failed: %s", - 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 isc_movefiled, or it might - * be garbage! - */ - - if (fgets(buf, sizeof(buf), fp)==NULL) { - ns_error(ns_log_update, "fgets() from %s failed: %s", - logname, strerror(errno)); - fclose(fp); - return (-1); - } - if (strcmp(buf, DumpSignature) == 0) { - /* It's a dump; finish isc_movefile that was interrupted. */ - ns_info(ns_log_update, - "completing interrupted dump isc_movefile for %s", - zp->z_source); - fclose(fp); - if (isc_movefile(logname, zp->z_source) < 0) { - ns_error(ns_log_update, - "isc_movefile(%s,%s) failed: %s :1", - logname, zp->z_source, - strerror(errno)); - return (-1); - } - /* 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", - logname); - fclose(fp); - return (-1); - } - - ns_debug(ns_log_update, 3, "merging logs for %s from %s", - zp->z_origin, logname); - lineno = 1; - INIT_LIST(curupd); - for (;;) { - err = 0; - dname = NULL; - if (!getword(buf, sizeof buf, fp, 0)) { - if (lineno == (nonempty_lineno + 1) && !(feof(fp))) { - /* - * End of a nonempty line inside an update - * packet or not inside an update packet. - */ - continue; - } - /* - * Empty line or EOF. - * - * Marks completion of current update packet. - */ - inside_next = 0; - prev_pktdone = 1; - cont = 1; - } else { - nonempty_lineno = lineno; - } - - if (!strcasecmp(buf, "[DYNAMIC_UPDATE]") || - !strcasecmp(buf, "[IXFR_UPDATE]")) { - err = 0; - rcode = NOERROR; - cp = fgets(buf, sizeof buf, fp); - if (cp != NULL) - lineno++; - if (cp == NULL || !sscanf((char *)cp, "id %d", &id)) - id = -1; - inside_next = 1; - prev_pktdone = 1; - cont = 1; - } else if (!strcasecmp(buf, "[INCR_SERIAL]")) { - /* XXXRTH not enough error checking here */ - cp = fgets(buf, sizeof buf, fp); - if (cp != NULL) - lineno++; - if (cp == NULL || - !sscanf((char *)cp, "from %u to %u", - &old_serial, &new_serial)) { - ns_error(ns_log_update, - "incr_serial problem with %s", - 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, logname); - } else { - set_serial(zp, new_serial); - /* - * The zone has changed; make sure - * a dump is scheduled. - */ - (void)schedule_dump(zp); - sched_zone_maint(zp); - ns_info(ns_log_update, - "set serial to %u (log file %s)", - new_serial, logname); - } - } - prev_pktdone = 1; - cont = 1; - } else if (!strcasecmp(buf, "[END_DELTA]")) { - prev_pktdone = 1; - cont = 1; - } - if (prev_pktdone) { - if (!EMPTY(curupd)) { - n = process_updates(&curupd, &rcode, - empty_from); - free_rrecp(&curupd, rcode, empty_from); - if (n > 0) - ns_info(ns_log_update, - "successfully merged update id %d from log file %s", - id, logname); - else { - ns_error(ns_log_update, - "error merging update id %d from log file %s", - id, logname); - fclose(fp); - return(-1); - } - } - prev_pktdone = 0; - if (feof(fp)) - break; - } - if (cont) { - cont = 0; - continue; - } - if (!inside_next) - continue; - /* - * inside the same update packet, - * continue accumulating records. - */ - section = -1; - n = strlen(buf); - if (buf[n-1] == ':') - buf[--n] = '\0'; - for (mp = m_section; mp < m_section+M_SECTION_CNT; mp++) - if (!strcasecmp(buf, mp->token)) { - section = mp->val; - break; - } - ttl = 0; - type = -1; - class = zp->z_class; - n = 0; - data[0] = '\0'; - switch (section) { - case S_ZONE: - cp = fgets(buf, sizeof buf, fp); - if (!cp) - *buf = '\0'; - n = sscanf(cp, "origin %s class %s serial %lu", - origin, sclass, &lutmp); - serial = lutmp; - if (n != 3 || ns_samename(origin, zp->z_origin) != 1) - err++; - if (cp) - lineno++; - if (!err && serial != zp->z_serial) { - ns_error(ns_log_update, - "serial number mismatch in update id %d (log=%u, zone=%u) in %s", - id, serial, zp->z_serial, - logname); - inside_next = 0; - err++; - } - if (!err && inside_next) { - int success; - - dname = origin; - type = T_SOA; - class = res_nametoclass(sclass, &success); - if (!success) { - err++; - break; - } - matches = findzone(dname, class, 0, - zonelist, MAXDNAME); - if (matches) - zonenum = zonelist[0]; - else - err++; - } - break; - case S_PREREQ: - case S_UPDATE: - /* Operation code. */ - if (!getword(buf, sizeof buf, fp, 0)) { - err++; - break; - } - opcode = -1; - if (buf[0] == '{') { - n = strlen(buf); - for (i = 0; (u_int32_t)i < n; i++) - buf[i] = buf[i+1]; - if (buf[n-2] == '}') - buf[n-2] = '\0'; - } - for (mp = m_opcode; mp < m_opcode+M_OPCODE_CNT; mp++) - if (!strcasecmp(buf, mp->token)) { - opcode = mp->val; - break; - } - if (opcode == -1) { - err++; - break; - } - /* Owner's domain name. */ - if (!getword((char *)dnbuf, sizeof dnbuf, fp, 1)) { - err++; - break; - } - n = strlen((char *)dnbuf) - 1; - if (dnbuf[n] == '.') - dnbuf[n] = '\0'; - dname = dnbuf; - ttl = 0; - type = -1; - class = zp->z_class; - n = 0; - data[0] = '\0'; - (void) getword(buf, sizeof buf, fp, 1); - if (isdigit(buf[0])) { /* ttl */ - if (ns_parse_ttl(buf, &l) < 0) { - err++; - break; - } - ttl = l; - (void) getword(buf, sizeof buf, fp, 1); - } - - /* possibly class */ - if (buf[0] != '\0') { - int success; - int maybe_class; - - maybe_class = res_nametoclass(buf, &success); - if (success) { - class = maybe_class; - (void) getword(buf, - sizeof buf, - fp, 1); - } - } - /* possibly type */ - if (buf[0] != '\0') { - int success; - int maybe_type; - - maybe_type = res_nametotype(buf, &success); - - if (success) { - type = maybe_type; - (void) getword(buf, - sizeof buf, - fp, 1); - } - } - if (buf[0] != '\0') /* possibly rdata */ - /* - * Convert the ascii data 'buf' to the proper - * format based on the type and pack into - * 'data'. - * - * XXX - same as in db_load(), - * consolidation needed - */ - switch (type) { - case T_A: - if (!inet_aton(buf, &ina)) { - err++; - break; - } - n = ntohl(ina.s_addr); - cp = data; - PUTLONG(n, cp); - n = INT32SZ; - break; - case T_HINFO: - case T_ISDN: - n = strlen(buf); - data[0] = n; - memcpy(data+1, buf, n); - n++; - if (!getword(buf, sizeof buf, - fp, 0)) { - i = 0; - } else { - endline(fp); - i = strlen(buf); - } - data[n] = i; - memcpy(data+n+1, buf, i); - break; - case T_SOA: - case T_MINFO: - case T_RP: - (void) strcpy(data, buf); - 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++) = 0; /* ditch dot */ - if (type != T_SOA) { - n = cp - data; - break; - } - else - n = cp - data; - if (class != zp->z_class || - ns_samename(dname, zp->z_origin) != 1) { - err++; - break; - } - c = getnonblank(fp, logname, 1); - if (c == '(') { - multiline = 1; - } else { - multiline = 0; - ungetc(c, fp); - } - n = getnum(fp, logname, GETNUM_SERIAL, - &multiline); - 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) { - c = getnonblank(fp, logname, 1); - if (c != ')') { - ungetc(c, fp); - err++; - break; - } - } - n = cp - data; - endline(fp); - break; - case T_WKS: - if (!inet_aton(buf, &ina)) { - err++; - break; - } - n = ntohl(ina.s_addr); - cp = data; - PUTLONG(n, cp); - *cp = (char)getprotocol(fp, - logname - ); - n = INT32SZ + sizeof(char); - n = getservices((int)n, data, - fp, logname); - break; - case T_NS: - case T_CNAME: - case T_MB: - case T_MG: - case T_MR: - case T_PTR: - (void) strcpy(data, buf); - if (makename(data, origin, - sizeof(data)) == -1) { - err++; - break; - } - n = strlen(data) + 1; - break; - case T_MX: - case T_AFSDB: - case T_RT: - n = 0; - cp = buf; - while (isdigit(*cp)) - n = n * 10 + (*cp++ - '0'); - /* catch bad values */ - cp = data; - PUTSHORT((u_int16_t)n, cp); - if (!getword(buf, sizeof(buf), - fp, 1)) { - err++; - break; - } - (void) strcpy((char *)cp, buf); - if (makename((char *)cp, origin, - sizeof(data) - (cp-data)) - == -1) { - err++; - break; - } - /* advance pointer to end of data */ - cp += strlen((char *)cp) +1; - /* now save length */ - n = (cp - data); - break; - case T_PX: - n = 0; - data[0] = '\0'; - cp = buf; - while (isdigit(*cp)) - n = n * 10 + (*cp++ - '0'); - cp = data; - PUTSHORT((u_int16_t)n, cp); - for (i = 0; i < 2; i++) { - if (!getword(buf, - sizeof(buf), - fp, 0)) { - err++; - break; - } - (void) strcpy((char *)cp, - buf); - cp += strlen((char *)cp) + 1; - } - n = cp - data; - break; - case T_TXT: - case T_X25: - i = strlen(buf); - cp = data; - datasize = sizeof data; - cp1 = buf; - while (i > MAXCHARSTRING) { - if (datasize <= MAXCHARSTRING){ - ns_error(ns_log_update, - "record too big"); - fclose(fp); - return (-1); - } - 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; - memcpy(cp, cp1, i); - cp += i; - n = cp - data; - endline(fp); - /* XXXVIX: segmented texts 4.9.5 */ - break; - case T_NSAP: - n = inet_nsap_addr(buf, - (u_char *)data, - sizeof data); - endline(fp); - break; - case T_LOC: - cp = buf + (n = strlen(buf)); - *cp = ' '; - cp++; - while ((i = getc(fp), *cp = i, - i != EOF) - && *cp != '\n' - && (n < MAXDATA)) { - cp++; - n++; - } - if (*cp == '\n') - ungetc(*cp, fp); - *cp = '\0'; - n = loc_aton(buf, (u_char *)data); - if (n == 0) { - err++; - break; - } - endline(fp); - break; - case ns_t_sig: - case ns_t_key: - case ns_t_nxt: - case ns_t_cert: - { - const 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: - if (strcmp(buf, "\\#") != 0) { - err++; - break; - } - if (!getword(buf, sizeof buf, fp, 0) || - !isdigit((unsigned char)buf[0])) { - err++; - break; - } - errno = 0; - n = strtoul(buf, &cp, 10); - if (errno != 0 || n > 0xffff || - *cp != '\0') { - err++; - break; - } - multiline = 0; - i = isc_gethexstring((u_char *)data, - sizeof(data), - n, fp, &multiline); - if (i == -1) { - err++; - break; - } - if (multiline) { - c = getnonblank(fp, - zp->z_updatelog, - 1); - if (c != ')') { - ungetc(c, fp); - err++; - break; - } - multiline = 0; - } - endline(fp); - } - if (section == S_PREREQ) { - ttl = 0; - if (opcode == NXDOMAIN) { - class = C_NONE; - type = T_ANY; - n = 0; - } else if (opcode == YXDOMAIN) { - class = C_ANY; - type = T_ANY; - n = 0; - } else if (opcode == NXRRSET) { - class = C_NONE; - n = 0; - } else if (opcode == YXRRSET) { - if (n == 0) - class = C_ANY; - } - } else { /* section == S_UPDATE */ - if (opcode == DELETE) { - ttl = 0; - if (n == 0) { - class = C_ANY; - if (type == -1) - type = T_ANY; - /* 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; - } - } - } - break; - case S_ADDT: - default: - ns_debug(ns_log_update, 1, - "cannot interpret section: %d", section); - inside_next = 0; - err++; - } - if (err) { - ns_debug(ns_log_update, 1, - "merge of update id %d failed due to error at line %d", - id, lineno); - free_rrecp(&curupd, FORMERR, empty_from); - fclose(fp); - return(-1); - } - rrecp = res_mkupdrec(section, dname, class, type, ttl); - if (section != S_ZONE) { - dp = savedata(class, type, ttl, (u_char *)data, n); - 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; - } - APPEND(curupd, rrecp, r_link); - } /* for (;;) */ - INSIST(EMPTY(curupd)); - fclose(fp); - return (0); -} - - -/* - * Create a disk database to back up zones - */ -int -zonedump(struct zoneinfo *zp, int mode) { - FILE *fp; - const char *fname; - struct hashbuf *htp; - char *op; - struct stat st; - char tmp_name[MAXPATHLEN]; - int escaped; - char c; - - /* - * We must check to see if Z_NEED_SOAUPDATE is set, and if so - * we must do it. This won't be the case normally - * (when called from ns_maint()), but it is possible if we're - * exiting named. - */ - - if (zp->z_flags & Z_NEED_SOAUPDATE) { - u_int32_t serial, old_serial; - - old_serial = get_serial(zp); - serial = old_serial + 1; - if (serial == 0) - serial = 1; - set_serial(zp, serial); - } - - /* Only dump zone if there is a cache specified */ - if (zp->z_source && *(zp->z_source)) { - ns_debug(ns_log_update, 1, "zonedump(%s)", zp->z_source); - - if (strlen(zp->z_source)+strlen(DumpSuffix) >= MAXPATHLEN) { - ns_error(ns_log_update, - "filename %s too long in zonedump", - zp->z_source); - /* - * This problem won't ever get better, so we - * clear the "need dump" flag. - */ - zp->z_flags &= ~Z_NEED_DUMP; - return (-1); - } - (void)sprintf(tmp_name, "%s%s", zp->z_source, DumpSuffix); - if ((fp = write_open(tmp_name)) == NULL) { - ns_error(ns_log_update, "fopen() of %s failed: %s", - tmp_name, strerror(errno)); - return (-1); - } - fprintf(fp, "%s", DumpSignature); - op = zp->z_origin; - escaped = 0; - while (*op && (((c = *op++) != '.') || escaped)) - escaped = (c == '\\') && !escaped; - gettime(&tt); - htp = hashtab; - if (nlookup(zp->z_origin, &htp, &fname, 0) != NULL) { - if (db_dump(htp, fp, zp-zones, op) != OK) { - ns_error(ns_log_update, - "error dumping zone file %s", - zp->z_source); - (void)fclose(fp); - return (-1); - } - } - 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) { - ns_error(ns_log_update, "fclose() of %s failed: %s", - tmp_name, strerror(errno)); - return (-1); - } - /* - * Try to make read only, so people will be less likely to - * edit dynamic domains. - */ - if (stat(tmp_name, &st) < 0) { - ns_error(ns_log_update, - "stat(%s) failed, pressing on: %s", - tmp_name, strerror(errno)); - } else { - zp->z_ftime = st.st_mtime; - st.st_mode &= ~WRITEABLE_MASK; - if (chmod(tmp_name, st.st_mode) < 0) - ns_error(ns_log_update, - "chmod(%s,%o) failed, pressing on: %s", - tmp_name, st.st_mode, - strerror(errno)); - } - - if (mode == ISIXFR) { - if (isc_movefile(tmp_name, zp->z_ixfr_tmp) < 0) { - ns_error(ns_log_update, - "isc_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 (isc_movefile(zp->z_ixfr_tmp, zp->z_source) < 0) { - ns_error(ns_log_update, - "isc_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 (isc_movefile(tmp_name, zp->z_updatelog) < 0) { - ns_error(ns_log_update, - "isc_movefile(%s,%s) failed: %s :4", - tmp_name, zp->z_updatelog, - strerror(errno)); - return (-1); - } - if (isc_movefile(zp->z_updatelog, zp->z_source) < 0) { - ns_error(ns_log_update, - "isc_movefile(%s,%s) failed: %s :5", - zp->z_updatelog, zp->z_source, - strerror(errno)); - return (-1); - } - } else { - if (isc_movefile(tmp_name, zp->z_source) < 0) { - ns_error(ns_log_update, - "isc_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"); - - zp->z_flags &= ~Z_NEED_DUMP; - zp->z_dumptime = 0; - return (0); -} - -struct databuf * -findzonesoa(struct zoneinfo *zp) { - struct hashbuf *htp; - struct namebuf *np; - struct databuf *dp; - const char *fname; - - htp = hashtab; - np = nlookup(zp->z_origin, &htp, &fname, 0); - if (np == NULL || fname != zp->z_origin) - return (NULL); - foreach_rr(dp, np, T_SOA, zp->z_class, zp - zones) - return (dp); - return (NULL); -} - -u_char * -findsoaserial(u_char *data) { - char *cp = (char *)data; - - cp += strlen(cp) + 1; /* Nameserver. */ - cp += strlen(cp) + 1; /* Mailbox. */ - return ((u_char *)cp); -} - -u_int32_t -get_serial_unchecked(struct zoneinfo *zp) { - struct databuf *dp; - u_char *cp; - u_int32_t ret; - - dp = findzonesoa(zp); - if (!dp) - ns_panic(ns_log_update, 1, - "get_serial_unchecked(%s): can't locate zone SOA", - zp->z_origin); - cp = findsoaserial(dp->d_data); - GETLONG(ret, cp); - return (ret); -} - -u_int32_t -get_serial(struct zoneinfo *zp) { - u_int32_t ret; - - ret = get_serial_unchecked(zp); - if (ret != zp->z_serial) - ns_panic(ns_log_update, 1, - "get_serial(%s): db and zone serial numbers differ", - zp->z_origin); - return (ret); -} - -void -set_serial(struct zoneinfo *zp, u_int32_t serial) { - struct databuf *dp; - u_char *cp; - - dp = findzonesoa(zp); - if (!dp) - ns_panic(ns_log_update, 1, - "set_serial(%s): can't locate zone SOA", - zp->z_origin); - cp = findsoaserial(dp->d_data); - PUTLONG(serial, cp); - zp->z_serial = serial; - zp->z_flags &= ~Z_NEED_SOAUPDATE; - zp->z_soaincrtime = 0; - zp->z_updatecnt = 0; -#ifdef BIND_NOTIFY - if (!loading) - ns_notify(zp->z_origin, zp->z_class, ns_t_soa); -#endif - /* - * Note: caller is responsible for scheduling a dump. - */ -} - -/* - * Increment serial number in zoneinfo structure and hash table SOA databuf - */ - -int -incr_serial(struct zoneinfo *zp) { - u_int32_t serial, old_serial; - FILE *fp, *ifp; - time_t t; - struct databuf *dp, *olddp; - unsigned char *cp; - - old_serial = get_serial(zp); - serial = old_serial + 1; - if (serial == 0) - serial = 1; - set_serial(zp, serial); - - (void) gettime(&tt); - t = (time_t)tt.tv_sec; - fp = open_transaction_log(zp); - if (fp == NULL) - return (-1); - fprintf(fp, "[INCR_SERIAL] from %u to %u %s\n", - old_serial, serial, checked_ctime(&t)); - if (close_transaction_log(zp, fp)<0) - return (-1); - if (zp->z_maintain_ixfr_base) { - ifp = open_ixfr_log(zp); - if (ifp == NULL) - return (-1); - dp = findzonesoa(zp); - if (dp) { - olddp = memget(BIND_DATASIZE(dp->d_size)); - if (olddp != NULL) { - memcpy(olddp, dp, BIND_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, BIND_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. - */ - if (!(zp->z_flags & Z_NEED_DUMP)) { - ns_warning(ns_log_update, - "incr_serial: Z_NEED_DUMP not set for zone '%s'", - zp->z_origin); - (void)schedule_dump(zp); - } - - sched_zone_maint(zp); - - return (0); -} - -void -dynamic_about_to_exit(void) { - struct zoneinfo *zp; - - ns_debug(ns_log_update, 1, - "shutting down; dumping zones that need it"); - for (zp = zones; zp < &zones[nzones]; zp++) { - if ((zp->z_flags & Z_DYNAMIC) && - ((zp->z_flags & Z_NEED_SOAUPDATE) || - (zp->z_flags & Z_NEED_DUMP))) - (void)zonedump(zp, ISNOTIXFR); - } -} |