aboutsummaryrefslogtreecommitdiff
path: root/contrib/bind/bin/named-xfer/named-xfer.c
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>1998-05-03 04:11:49 +0000
committerPeter Wemm <peter@FreeBSD.org>1998-05-03 04:11:49 +0000
commit4e0ffe0baef832be2a8161229e9e4f7cb18a586a (patch)
tree759849259eae9f7cb0d3ddbd7a131081c6688068 /contrib/bind/bin/named-xfer/named-xfer.c
parente2f1a81473c07cf46c3104b8dcfdd992a2fe7ca8 (diff)
Import (trimmed) ISC bind-8.1.2-t3b. This will be updated to 8.1.2 on
final release. Obtained from: ftp.isc.org
Notes
Notes: svn path=/vendor/bind/dist/; revision=35629
Diffstat (limited to 'contrib/bind/bin/named-xfer/named-xfer.c')
-rw-r--r--contrib/bind/bin/named-xfer/named-xfer.c2177
1 files changed, 2177 insertions, 0 deletions
diff --git a/contrib/bind/bin/named-xfer/named-xfer.c b/contrib/bind/bin/named-xfer/named-xfer.c
new file mode 100644
index 000000000000..292714e444f0
--- /dev/null
+++ b/contrib/bind/bin/named-xfer/named-xfer.c
@@ -0,0 +1,2177 @@
+/*
+ * The original version of xfer by Kevin Dunlap.
+ * Completed and integrated with named by David Waitzman
+ * (dwaitzman@bbn.com) 3/14/88.
+ * Modified by M. Karels and O. Kure 10-88.
+ * Modified extensively since then by just about everybody.
+ */
+
+/*
+ * Copyright (c) 1988, 1990
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * 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 Digital Equipment Corporation 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 DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION 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) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/* Portions Copyright (c) 1996, 1997 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.
+ */
+
+#if !defined(lint) && !defined(SABER)
+char copyright[] =
+"@(#) Copyright (c) 1988, 1990 The Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ portions Copyright (c) 1995, 1996 Internet Software Consorium\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91";
+static char rcsid[] = "$Id: named-xfer.c,v 8.38 1998/03/27 00:19:28 halley Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+
+#include "port_after.h"
+
+#define MAIN_PROGRAM
+#include "../named/named.h"
+#undef MAIN_PROGRAM
+
+#define MAX_XFER_RESTARTS 2
+
+# ifdef SHORT_FNAMES
+extern long pathconf __P((const char *path, int name)); /* XXX */
+# endif
+
+static struct zoneinfo zone; /* zone information */
+
+static char ddtfilename[] = _PATH_TMPXFER,
+ *ddtfile = ddtfilename,
+ *tmpname,
+ *domain; /* domain being xfered */
+
+static int quiet = 0,
+ read_interrupted = 0,
+ curclass,
+ domain_len; /* strlen(domain) */
+
+static FILE *fp = NULL,
+ *dbfp = NULL;
+
+static char *ProgName;
+
+static void usage(const char *);
+static int getzone(struct zoneinfo *, u_int32_t, int),
+ print_output(struct zoneinfo *, u_int32_t,
+ u_char *, int, u_char *),
+ netread(int, char *, int, int),
+ writemsg(int, const u_char *, int);
+static SIG_FN read_alarm(void);
+static SIG_FN term_handler(void);
+static const char *soa_zinfo(struct zoneinfo *, u_char *, u_char*);
+
+struct zoneinfo zp_start, zp_finish;
+
+static int restarts = 0;
+
+FILE *ddt = NULL;
+
+/*
+ * Debugging printf.
+ */
+#ifdef DEBUG
+void
+dprintf(int level, const char *format, ...) {
+ va_list ap;
+
+ va_start(ap, format);
+ if (ddt != NULL && debug >= level)
+ (void) vfprintf(ddt, format, ap);
+ va_end(ap);
+}
+#endif /*DEBUG*/
+
+static
+int init_xfer_logging() {
+ log_channel chan;
+
+ if (log_new_context(ns_log_max_category, NULL, &log_ctx) < 0) {
+ perror("log_new_context");
+ return (0);
+ }
+ log_option(log_ctx, LOG_OPTION_DEBUG, debug);
+ log_option(log_ctx, LOG_OPTION_LEVEL, debug);
+
+ log_ctx_valid = 1;
+
+ chan = log_new_syslog_channel(0, 0, LOG_DAEMON);
+ if (chan == NULL)
+ return (0);
+ if (log_add_channel(log_ctx, ns_log_default, chan) < 0) {
+ perror("log_add_channel syslog");
+ return (0);
+ }
+
+ if (debug) {
+ unsigned int flags = LOG_USE_CONTEXT_LEVEL|LOG_REQUIRE_DEBUG;
+
+ chan = log_new_file_channel(flags, 0, NULL, ddt, 0, ULONG_MAX);
+ if (chan == NULL)
+ return (0);
+ if (log_add_channel(log_ctx, ns_log_default, chan) < 0) {
+ perror("log_add_channel debug");
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+void cleanup_for_exit(void) {
+#ifdef DEBUG
+ if (!debug)
+#endif
+ (void) unlink(tmpname);
+}
+
+
+int
+main(int argc, char *argv[]) {
+ struct zoneinfo *zp;
+ struct hostent *hp;
+ struct in_addr axfr_src;
+ char *dbfile = NULL, *tracefile = NULL, *tm = NULL;
+ int dbfd, ddtd, result, c, fd, closed = 0;
+ u_int32_t serial_no = 0;
+ u_int port = htons(NAMESERVER_PORT);
+ struct stat statbuf;
+#ifdef STUBS
+ int stub_only = 0;
+#endif
+ int class = C_IN;
+ int n;
+ long num_files;
+
+ ProgName = strrchr(argv[0], '/');
+ if (ProgName != NULL)
+ ProgName++;
+ else
+ ProgName = argv[0];
+
+ (void) umask(022);
+
+ /* this is a hack; closing everything in the parent is hard. */
+ num_files = MIN(sysconf(_SC_OPEN_MAX), FD_SETSIZE);
+ for (fd = num_files - 1; fd > STDERR_FILENO; fd--)
+ closed += (close(fd) == 0);
+
+#ifdef RENICE
+ nice(-40); /* this is the recommended procedure to */
+ nice(20); /* reset the priority of the current process */
+ nice(0); /* to "normal" (== 0) - see nice(3) */
+#endif
+
+#ifdef LOG_PERROR
+ n = LOG_PERROR;
+#else
+ n = 0;
+#endif
+#ifdef SYSLOG_42BSD
+ openlog(ProgName, LOG_PID);
+#else
+ openlog(ProgName, LOG_PID|LOG_CONS|n, LOG_DAEMON);
+#endif
+ axfr_src.s_addr = 0;
+#ifdef STUBS
+ while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:S")) != EOF)
+#else
+ while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qx:")) != EOF)
+#endif
+ switch (c) {
+ case 'C':
+ class = get_class(optarg);
+ break;
+ case 'd':
+#ifdef DEBUG
+ debug = atoi(optarg);
+#endif
+ break;
+ case 'l':
+ ddtfile = (char *)malloc(strlen(optarg) +
+ sizeof(".XXXXXX") + 1);
+ if (!ddtfile)
+ panic("malloc(ddtfile)", NULL);
+#ifdef SHORT_FNAMES
+ filenamecpy(ddtfile, optarg);
+#else
+ (void) strcpy(ddtfile, optarg);
+#endif /* SHORT_FNAMES */
+ (void) strcat(ddtfile, ".XXXXXX");
+ break;
+ case 's':
+ serial_no = strtoul(optarg, (char **)NULL, 10);
+ break;
+ case 't':
+ tracefile = optarg;
+ break;
+ case 'z': /* zone == domain */
+ domain = optarg;
+ domain_len = strlen(domain);
+ while ((domain_len > 0) &&
+ (domain[domain_len-1] == '.'))
+ domain[--domain_len] = '\0';
+ break;
+ case 'f':
+ dbfile = optarg;
+ tmpname = (char *)malloc((unsigned)strlen(optarg) +
+ sizeof(".XXXXXX") + 1);
+ if (!tmpname)
+ panic("malloc(tmpname)", NULL);
+#ifdef SHORT_FNAMES
+ filenamecpy(tmpname, optarg);
+#else
+ (void) strcpy(tmpname, optarg);
+#endif /* SHORT_FNAMES */
+ break;
+ case 'p':
+ port = htons((u_int16_t)atoi(optarg));
+ break;
+ case 'P':
+ port = (u_int16_t)atoi(optarg);
+ break;
+#ifdef STUBS
+ case 'S':
+ stub_only = 1;
+ break;
+#endif
+ case 'q':
+ quiet++;
+ break;
+ case 'x':
+ if (!inet_aton(optarg, &axfr_src))
+ panic("bad -x addr: %s", optarg);
+ break;
+ case '?':
+ default:
+ usage("unrecognized argument");
+ /* NOTREACHED */
+ }
+
+ if (!domain || !dbfile || optind >= argc) {
+ if (!domain)
+ usage("no domain");
+ if (!dbfile)
+ usage("no dbfile");
+ if (optind >= argc)
+ usage("not enough arguments");
+ /* NOTREACHED */
+ }
+ if (stat(dbfile, &statbuf) != -1 &&
+ !S_ISREG(statbuf.st_mode) &&
+ !S_ISFIFO(statbuf.st_mode))
+ usage("dbfile must be a regular file or FIFO");
+ if (tracefile && (fp = fopen(tracefile, "w")) == NULL)
+ perror(tracefile);
+ (void) strcat(tmpname, ".XXXXXX");
+ /* tmpname is now something like "/etc/named/named.bu.db.XXXXXX" */
+ if ((dbfd = mkstemp(tmpname)) == -1) {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't make tmpfile (%s): %m\n",
+ tmpname);
+ exit(XFER_FAIL);
+ }
+#ifdef HAVE_FCHMOD /* XXX */
+ if (fchmod(dbfd, 0644) == -1)
+#else
+ if (chmod(tmpname, 0644) == -1)
+#endif
+ {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't [f]chmod tmpfile (%s): %m\n",
+ tmpname);
+ exit(XFER_FAIL);
+ }
+ if ((dbfp = fdopen(dbfd, "r+")) == NULL) {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't fdopen tmpfile (%s)", tmpname);
+ exit(XFER_FAIL);
+ }
+#ifdef DEBUG
+ if (debug) {
+ /* ddtfile is now something like "/usr/tmp/xfer.ddt.XXXXXX" */
+ if ((ddtd = mkstemp(ddtfile)) == -1) {
+ perror(ddtfile);
+ debug = 0;
+ }
+#ifdef HAVE_FCHMOD
+ else if (fchmod(ddtd, 0644) == -1)
+#else
+ else if (chmod(ddtfile, 0644) == -1)
+#endif
+ {
+ perror(ddtfile);
+ debug = 0;
+ } else if ((ddt = fdopen(ddtd, "w")) == NULL) {
+ perror(ddtfile);
+ debug = 0;
+ } else
+ setvbuf(ddt, NULL, _IOLBF, 0);
+ }
+#endif
+
+ if (!init_xfer_logging()) {
+ perror("init_xfer_logging");
+ }
+
+ /*
+ * Ignore many types of signals that named (assumed to be our parent)
+ * considers important- if not, the user controlling named with
+ * signals usually kills us.
+ */
+ (void) signal(SIGHUP, SIG_IGN);
+#ifdef SIGSYS
+ (void) signal(SIGSYS, SIG_IGN);
+#endif
+#ifdef DEBUG
+ if (debug == 0)
+#endif
+ {
+ (void) signal(SIGINT, SIG_IGN);
+ (void) signal(SIGQUIT, SIG_IGN);
+ }
+ (void) signal(SIGILL, SIG_IGN);
+
+#if defined(SIGUSR1) && defined(SIGUSR2)
+ (void) signal(SIGUSR1, SIG_IGN);
+ (void) signal(SIGUSR2, SIG_IGN);
+#else /* SIGUSR1&&SIGUSR2 */
+ (void) signal(SIGEMT, SIG_IGN);
+ (void) signal(SIGFPE, SIG_IGN);
+#endif /* SIGUSR1&&SIGUSR2 */
+
+ dprintf(1, "domain `%s'; file `%s'; serial %u; closed %d\n",
+ domain, dbfile, serial_no, closed);
+
+ buildservicelist();
+ buildprotolist();
+
+ /* init zone data */
+
+ zp = &zone;
+#ifdef STUBS
+ if (stub_only)
+ zp->z_type = Z_STUB;
+ else
+#endif
+ zp->z_type = Z_SECONDARY;
+ zp->z_class = class;
+ zp->z_origin = domain;
+ zp->z_source = dbfile;
+ zp->z_axfr_src = axfr_src;
+ zp->z_addrcnt = 0;
+ dprintf(1, "zone found (%d): \"%s\", source = %s\n",
+ zp->z_type,
+ (zp->z_origin[0] == '\0') ? "." : zp->z_origin,
+ zp->z_source);
+
+ for (; optind != argc; optind++) {
+ tm = argv[optind];
+ if (!inet_aton(tm, &zp->z_addr[zp->z_addrcnt])) {
+ hp = gethostbyname(tm);
+ if (hp == NULL) {
+ syslog(LOG_NOTICE,
+ "uninterpretable server (%s) for %s\n",
+ tm, zp->z_origin);
+ continue;
+ }
+ memcpy(&zp->z_addr[zp->z_addrcnt],
+ hp->h_addr,
+ INADDRSZ);
+ dprintf(1, "Arg: \"%s\"\n", tm);
+ }
+ if (++zp->z_addrcnt >= NSMAX) {
+ zp->z_addrcnt = NSMAX;
+ dprintf(1, "NSMAX reached\n");
+ break;
+ }
+ }
+ dprintf(1, "addrcnt = %d\n", zp->z_addrcnt);
+
+ res_init();
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+ result = getzone(zp, serial_no, port);
+ (void) my_fclose(dbfp);
+ switch (result) {
+
+ case XFER_SUCCESS: /* ok exit */
+ if (rename(tmpname, dbfile) == -1) {
+ perror("rename");
+ if (!quiet)
+ syslog(LOG_ERR, "rename %s to %s: %m",
+ tmpname, dbfile);
+ exit(XFER_FAIL);
+ }
+ exit(XFER_SUCCESS);
+
+ case XFER_UPTODATE: /* the zone was already uptodate */
+ (void) unlink(tmpname);
+ exit(XFER_UPTODATE);
+
+ default:
+ result = XFER_FAIL;
+ /* fall through */
+ case XFER_TIMEOUT:
+ case XFER_FAIL:
+ cleanup_for_exit();
+ exit(result); /* error or timeout */
+ }
+ /*NOTREACHED*/
+ return (0); /* Make gcc happy. */
+}
+
+static char *UsageText[] = {
+ "\t-z zone_to_transfer\n",
+ "\t-f db_file\n",
+ "\t-s serial_no\n",
+ "\t[-d debug_level]\n",
+ "\t[-l debug_log_file]\n",
+ "\t[-t trace_file]\n",
+ "\t[-p port]\n",
+#ifdef STUBS
+ "\t[-S]\n",
+#endif
+ "\t[-C class]\n",
+ "\t[-x axfr-src]\n",
+ "\tservers...\n",
+ NULL
+};
+
+static void
+usage(const char *msg) {
+ char * const *line;
+
+ fprintf(stderr, "Usage error: %s\n", msg);
+ fprintf(stderr, "Usage: %s\n", ProgName);
+ for (line = UsageText; *line; line++)
+ fputs(*line, stderr);
+ exit(XFER_FAIL);
+}
+
+#define DEF_DNAME '\001' /* '\0' means the root domain */
+/* XXX: The following variables should probably all be "static" */
+u_int32_t minimum_ttl = 0;
+int soa_cnt = 0;
+#ifdef STUBS
+int ns_cnt = 0;
+#endif
+int query_type = 0;
+int prev_comment = 0; /* was previous record a comment? */
+char zone_top[MAXDNAME]; /* the top of the zone */
+char prev_origin[MAXDNAME]; /* from most recent $ORIGIN line */
+char prev_dname[MAXDNAME] = { DEF_DNAME }; /* from previous record */
+char prev_ns_dname[MAXDNAME] = { DEF_DNAME }; /* from most recent NS record */
+
+static int
+getzone(struct zoneinfo *zp, u_int32_t serial_no, int port) {
+ HEADER *hp;
+ u_int len;
+ u_int32_t serial;
+ int s, n, l, error = 0;
+ u_int cnt;
+ u_char *cp, *nmp, *eom, *tmp ;
+ u_char *buf = NULL;
+ u_int bufsize = 0;
+ char name[MAXDNAME], name2[MAXDNAME];
+ struct sockaddr_in sin;
+#ifdef POSIX_SIGNALS
+ struct sigaction sv, osv;
+#else
+ struct sigvec sv, osv;
+#endif
+ int qdcount, ancount, aucount, class, type;
+ const char *badsoa_msg = "Nil";
+
+#ifdef DEBUG
+ if (debug) {
+ (void)fprintf(ddt,"getzone() %s ", zp->z_origin);
+ switch (zp->z_type) {
+ case Z_STUB:
+ fprintf(ddt,"stub\n");
+ break;
+ case Z_SECONDARY:
+ fprintf(ddt,"secondary\n");
+ break;
+ default:
+ fprintf(ddt,"unknown type\n");
+ }
+ }
+#endif
+#ifdef POSIX_SIGNALS
+ memset(&sv, 0, sizeof sv);
+ sv.sa_handler = (SIG_FN (*)()) read_alarm;
+ /* SA_ONSTACK isn't recommended for strict POSIX code */
+ /* is it absolutely necessary? */
+ /* sv.sa_flags = SA_ONSTACK; */
+ sigfillset(&sv.sa_mask);
+ (void) sigaction(SIGALRM, &sv, &osv);
+ memset(&sv, 0, sizeof sv);
+ sv.sa_handler = (SIG_FN (*)()) term_handler;
+ sigfillset(&sv.sa_mask);
+ (void) sigaction(SIGTERM, &sv, &osv);
+#else
+ memset(&sv, 0, sizeof sv);
+ sv.sv_handler = read_alarm;
+ sv.sv_mask = ~0;
+ (void) sigvec(SIGALRM, &sv, &osv);
+ memset(&sv, 0, sizeof sv);
+ sv.sv_handler = term_handler;
+ sv.sv_mask = ~0;
+ (void) sigvec(SIGTERM, &sv, &osv);
+#endif
+
+ strcpy(zone_top, zp->z_origin);
+ if ((l = strlen(zone_top)) != 0 && zone_top[l - 1] == '.')
+ zone_top[l - 1] = '\0';
+ strcpy(prev_origin, zone_top);
+
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) {
+ curclass = zp->z_class;
+ error = 0;
+ if (buf == NULL) {
+ if ((buf = (u_char *)malloc(2 * PACKETSZ)) == NULL) {
+ syslog(LOG_INFO, "malloc(%u) failed",
+ 2 * PACKETSZ);
+ error++;
+ break;
+ }
+ bufsize = 2 * PACKETSZ;
+ }
+ if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
+ syslog(LOG_INFO, "socket: %m");
+ error++;
+ break;
+ }
+ if (zp->z_axfr_src.s_addr != 0) {
+ memset(&sin, 0, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0; /* "ANY" */
+ sin.sin_addr = zp->z_axfr_src;
+ dprintf(2, "binding to address [%s]\n",
+ inet_ntoa(sin.sin_addr));
+ if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0)
+ syslog(LOG_INFO, "warning: bind(%s) failed",
+ inet_ntoa(zp->z_axfr_src));
+ }
+ memset(&sin, 0, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = port;
+ sin.sin_addr = zp->z_addr[cnt];
+ dprintf(2, "connecting to server #%d [%s].%d\n",
+ cnt+1, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ if (!quiet)
+ syslog(LOG_INFO,
+ "connect(%s) for zone %s failed: %m",
+ inet_ntoa(sin.sin_addr), zp->z_origin);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ n = res_mkquery(QUERY, zp->z_origin, curclass,
+ T_SOA, NULL, 0, NULL, buf, bufsize);
+ if (n < 0) {
+ if (!quiet)
+ syslog(LOG_INFO,
+ "zone %s: res_mkquery T_SOA failed",
+ zp->z_origin);
+ (void) my_close(s);
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv, (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ return (XFER_FAIL);
+ }
+ /*
+ * Send length & message for SOA query
+ */
+ if (writemsg(s, buf, n) < 0) {
+ syslog(LOG_INFO, "writemsg: %m");
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ /*
+ * Get out your butterfly net and catch the SOA
+ */
+ if (netread(s, (char *)buf, INT16SZ, XFER_TIMER) < 0) {
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ if ((len = ns_get16(buf)) == 0) {
+ (void) my_close(s);
+ continue;
+ }
+ if (len > bufsize) {
+ if ((buf = (u_char *)realloc(buf, len)) == NULL) {
+ syslog(LOG_INFO,
+ "malloc(%u) failed for SOA from server [%s], zone %s\n",
+ len,
+ inet_ntoa(sin.sin_addr),
+ zp->z_origin);
+ (void) my_close(s);
+ continue;
+ }
+ bufsize = len;
+ }
+ if (netread(s, (char *)buf, len, XFER_TIMER) < 0) {
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+#ifdef DEBUG
+ if (debug >= 3) {
+ (void)fprintf(ddt,"len = %d\n", len);
+ fp_nquery(buf, len, ddt);
+ }
+#endif
+ hp = (HEADER *) buf;
+ qdcount = ntohs(hp->qdcount);
+ ancount = ntohs(hp->ancount);
+ aucount = ntohs(hp->nscount);
+
+ /*
+ * close socket if any of these apply:
+ * 1) rcode != NOERROR
+ * 2) not an authority response
+ * 3) not an answer to our question
+ * 4) both the number of answers and authority count < 1)
+ */
+ if (hp->rcode != NOERROR || !hp->aa || qdcount != 1 ||
+ (ancount < 1 && aucount < 1)) {
+#ifndef ultrix /*XXX*/
+ syslog(LOG_NOTICE,
+ "[%s] %s for %s, SOA query got rcode %d, aa %d, ancount %d, aucount %d",
+ inet_ntoa(sin.sin_addr),
+ (hp->aa
+ ? (qdcount==1 ?"no SOA found" :"bad response")
+ : "not authoritative"),
+ zp->z_origin[0] != '\0' ? zp->z_origin : ".",
+ hp->rcode, hp->aa, ancount, aucount);
+#endif
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ zp_start = *zp;
+ if ((int)len < HFIXEDSZ + QFIXEDSZ) {
+ badsoa_msg = "too short";
+ badsoa:
+ syslog(LOG_INFO,
+ "malformed SOA from [%s], zone %s: %s",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ badsoa_msg);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ /*
+ * Step through response.
+ */
+ tmp = buf + HFIXEDSZ;
+ eom = buf + len;
+ /* Query Section. */
+ n = dn_expand(buf, eom, tmp, name2, sizeof name2);
+ if (n < 0) {
+ badsoa_msg = "qname error";
+ goto badsoa;
+ }
+ tmp += n;
+ if (tmp + 2 * INT16SZ > eom) {
+ badsoa_msg = "query error";
+ goto badsoa;
+ }
+ NS_GET16(type, tmp);
+ NS_GET16(class, tmp);
+ if (class != curclass || type != T_SOA ||
+ strcasecmp(zp->z_origin, name2) != 0) {
+ syslog(LOG_INFO,
+ "wrong query in resp from [%s], zone %s: [%s %s %s]\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ name2, p_class(class), p_type(type));
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ /* ... Answer Section.
+ * We may have to loop a little, to bypass SIG SOA's in
+ * the response.
+ */
+ do {
+ u_char *cp4;
+ u_short type, class, dlen;
+ u_int32_t ttl;
+
+ n = dn_expand(buf, eom, tmp, name2, sizeof name2);
+ if (n < 0) {
+ badsoa_msg = "aname error";
+ goto badsoa;
+ }
+ tmp += n;
+
+ /* Are type, class, and ttl OK? */
+ cp4 = tmp; /* Leave tmp pointing to type field */
+ if (eom - cp4 < 3 * INT16SZ + INT32SZ) {
+ badsoa_msg = "zinfo too short";
+ goto badsoa;
+ }
+ NS_GET16(type, cp4);
+ NS_GET16(class, cp4);
+ NS_GET32(ttl, cp4);
+ NS_GET16(dlen, cp4);
+ if (cp4 + dlen > eom) {
+ badsoa_msg = "zinfo dlen too big";
+ goto badsoa;
+ }
+ if (type == T_SOA)
+ break;
+ /* Skip to next record, if any. */
+ dprintf(1, "skipping %s %s RR in response\n",
+ name2, p_type(type));
+ tmp = cp4 + dlen;
+ } while (1);
+
+ if (strcasecmp(zp->z_origin, name2) != 0) {
+ syslog(LOG_INFO,
+ "wrong answer in resp from [%s], zone %s: [%s %s %s]\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ name2, p_class(class), p_type(type));
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ badsoa_msg = soa_zinfo(&zp_start, tmp, eom);
+ if (badsoa_msg)
+ goto badsoa;
+ if (SEQ_GT(zp_start.z_serial, serial_no) || !serial_no) {
+ const char *l, *nl;
+ dprintf(1, "need update, serial %u\n",
+ zp_start.z_serial);
+ hp = (HEADER *) buf;
+ soa_cnt = 0;
+#ifdef STUBS
+ ns_cnt = 0;
+#endif
+ gettime(&tt);
+ for (l = Version; l; l = nl) {
+ size_t len;
+ if ((nl = strchr(l, '\n')) != NULL) {
+ len = nl - l;
+ nl = nl + 1;
+ } else {
+ len = strlen(l);
+ nl = NULL;
+ }
+ while (isspace((unsigned char) *l))
+ l++;
+ if (*l)
+ fprintf(dbfp, "; BIND version %.*s\n",
+ (int)len, l);
+ }
+ fprintf(dbfp, "; zone '%s' last serial %u\n",
+ domain, serial_no);
+ fprintf(dbfp, "; from %s at %s",
+ inet_ntoa(sin.sin_addr),
+ ctimel(tt.tv_sec));
+ for (;;) {
+ if ((soa_cnt == 0) || (zp->z_type == Z_STUB)) {
+#ifdef STUBS
+ if (zp->z_type == Z_STUB) {
+ if (soa_cnt == 1 &&
+ ns_cnt == 0)
+ query_type = T_NS;
+ else
+ query_type = T_SOA;
+ } else
+#endif
+ query_type = T_AXFR;
+ n = res_mkquery(QUERY, zp->z_origin,
+ curclass, query_type,
+ NULL, 0,
+ NULL, buf, bufsize);
+ if (n < 0) {
+ if (!quiet) {
+#ifdef STUBS
+ if (zp->z_type == Z_STUB)
+ syslog(LOG_INFO,
+ (query_type == T_SOA)
+ ? "zone %s: res_mkquery T_SOA failed"
+ : "zone %s: res_mkquery T_NS failed",
+ zp->z_origin);
+ else
+#endif
+ syslog(LOG_INFO,
+ "zone %s: res_mkquery T_AXFR failed",
+ zp->z_origin);
+ }
+ (void) my_close(s);
+#ifdef POSIX_SIGNALS
+ sigaction(SIGALRM, &osv,
+ (struct sigaction *)0);
+#else
+ sigvec(SIGALRM, &osv,
+ (struct sigvec *)0);
+#endif
+ return (XFER_FAIL);
+ }
+ /*
+ * Send length & msg for zone transfer
+ */
+ if (writemsg(s, buf, n) < 0) {
+ syslog(LOG_INFO,
+ "writemsg: %m");
+ error++;
+ (void) my_close(s);
+ break;
+ }
+ }
+ /*
+ * Receive length & response
+ */
+ if (netread(s, (char *)buf, INT16SZ,
+ (soa_cnt == 0) ?300 :XFER_TIMER)
+ < 0) {
+ error++;
+ break;
+ }
+ if ((len = ns_get16(buf)) == 0)
+ break;
+ if (len > bufsize) {
+ buf = (u_char *)realloc(buf, len);
+ if (buf == NULL) {
+ syslog(LOG_INFO,
+ "malloc(%u) failed for packet from server [%s], zone %s\n",
+ len,
+ inet_ntoa(sin.sin_addr),
+ zp->z_origin);
+ error++;
+ break;
+ }
+ bufsize = len;
+ }
+ hp = (HEADER *)buf;
+ eom = buf + len;
+ if (netread(s, (char *)buf, len, XFER_TIMER)
+ < 0) {
+ error++;
+ break;
+ }
+#ifdef DEBUG
+ if (debug >= 3) {
+ (void)fprintf(ddt,"len = %d\n", len);
+ fp_nquery(buf, len, ddt);
+ }
+ if (fp)
+ fp_nquery(buf, len, fp);
+#endif
+ if (len < HFIXEDSZ) {
+ struct sockaddr_in my_addr;
+ char my_addr_text[30];
+ int alen;
+
+ badrec:
+ error++;
+ alen = sizeof my_addr;
+ if (getsockname(s, (struct sockaddr *)
+ &my_addr, &alen) < 0)
+ sprintf(my_addr_text,
+ "[errno %d]", errno);
+ else
+ sprintf(my_addr_text,
+ "[%s].%u",
+ inet_ntoa(my_addr.
+ sin_addr),
+ ntohs(my_addr.sin_port)
+ );
+ syslog(LOG_INFO,
+ "[%s] record too short from [%s], zone %s\n",
+ my_addr_text,
+ inet_ntoa(sin.sin_addr),
+ zp->z_origin);
+ break;
+ }
+ cp = buf + HFIXEDSZ;
+ if (hp->qdcount) {
+ if ((n = dn_skipname(cp, eom)) == -1
+ || n + QFIXEDSZ >= eom - cp)
+ goto badrec;
+ cp += n + QFIXEDSZ;
+ }
+ nmp = cp;
+ if ((n = dn_skipname(cp, eom)) == -1)
+ goto badrec;
+ tmp = cp + n;
+#ifdef STUBS
+ if (zp->z_type == Z_STUB) {
+ ancount = ntohs(hp->ancount);
+ n = 0;
+ for (cnt = 0; cnt < (u_int)ancount; cnt++) {
+ n = print_output(zp, serial_no, buf,
+ len, cp);
+ if (n < 0)
+ break;
+ cp += n;
+ }
+ /*
+ * If we've processed the answer section and
+ * didn't get any useful answers, bail out.
+ */
+ if (query_type == T_SOA && soa_cnt == 0) {
+ syslog(LOG_ERR,
+ "stubs: no SOA in answer");
+ error++;
+ break;
+ }
+ if (query_type == T_NS && ns_cnt == 0) {
+ syslog(LOG_ERR,
+ "stubs: no NS in answer");
+ error++;
+ break;
+ }
+ if (n >= 0 && hp->nscount) {
+ ancount = ntohs(hp->nscount);
+ for (cnt = 0;
+ cnt < (u_int)ancount;
+ cnt++) {
+ n = print_output(zp, serial_no,
+ buf, len,
+ cp);
+ if (n < 0)
+ break;
+ cp += n;
+ }
+ }
+ ancount = ntohs(hp->arcount);
+ for (cnt = 0;
+ n > 0 && cnt < (u_int)ancount;
+ cnt++) {
+ n = print_output(zp, serial_no, buf,
+ len, cp);
+ cp += n;
+ }
+ if (n < 0) {
+ syslog(LOG_INFO,
+ "print_output: unparseable answer (%d), zone %s",
+ hp->rcode, zp->z_origin);
+ error++;
+ break;
+ }
+ if (cp != eom) {
+ syslog(LOG_INFO,
+ "print_output: short answer (%d, %d), zone %s",
+ cp - buf, eom - buf,
+ zp->z_origin);
+ error++;
+ break;
+ }
+ } else {
+#endif /*STUBS*/
+ ancount = ntohs(hp->ancount);
+ for (n = cnt = 0;
+ cnt < (u_int)ancount;
+ cnt++) {
+ n = print_output(zp, serial_no, buf,
+ len, cp);
+ if (n < 0)
+ break;
+ cp += n;
+ }
+ if (n < 0) {
+ syslog(LOG_INFO,
+ "print_output: unparseable answer (%d), zone %s",
+ hp->rcode, zp->z_origin);
+ error++;
+ break;
+ }
+ if (cp != eom) {
+ syslog(LOG_INFO,
+ "print_output: short answer (%d, %d), zone %s",
+ cp - buf, eom - buf,
+ zp->z_origin);
+ error++;
+ break;
+ }
+#ifdef STUBS
+ }
+#endif
+
+ if (soa_cnt >= 2)
+ break;
+
+ }
+ (void) my_close(s);
+ if (error == 0) {
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv,
+ (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ return (XFER_SUCCESS);
+ }
+ dprintf(2, "error receiving zone transfer\n");
+ } else if (zp_start.z_serial == serial_no) {
+ (void) my_close(s);
+ dprintf(1, "zone up-to-date, serial %u\n", zp_start.z_serial);
+ return (XFER_UPTODATE);
+ } else {
+ (void) my_close(s);
+ if (!quiet)
+ syslog(LOG_NOTICE,
+ "serial from [%s], zone %s: %u lower than current: %u\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ zp_start.z_serial, serial_no);
+ return (XFER_FAIL);
+ }
+ }
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv, (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ if (!error)
+ return (XFER_TIMEOUT);
+ return (XFER_FAIL);
+}
+
+static SIG_FN
+term_handler() {
+ cleanup_for_exit();
+ _exit(XFER_FAIL); /* not safe to call exit() from a signal handler */
+}
+
+/*
+ * Set flag saying to read was interrupted
+ * used for a read timer
+ */
+static SIG_FN
+read_alarm() {
+ read_interrupted = 1;
+}
+
+static int
+netread(int fd, char *buf, int len, int timeout) {
+ static const char setitimerStr[] = "setitimer: %m";
+ struct itimerval ival, zeroival;
+ struct sockaddr_in sa;
+ int n, salen;
+#if defined(NETREAD_BROKEN)
+ int retries = 0;
+#endif
+
+ memset(&zeroival, 0, sizeof zeroival);
+ ival = zeroival;
+ ival.it_value.tv_sec = timeout;
+ while (len > 0) {
+ if (setitimer(ITIMER_REAL, &ival, NULL) < 0) {
+ syslog(LOG_INFO, setitimerStr);
+ return (-1);
+ }
+ errno = 0;
+ salen = sizeof sa;
+ n = recvfrom(fd, buf, len, 0, (struct sockaddr *)&sa, &salen);
+ if (n == 0 && errno == 0) {
+#if defined(NETREAD_BROKEN)
+ if (++retries < 42) /* doug adams */
+ continue;
+#endif
+ syslog(LOG_INFO, "premature EOF, fetching \"%s\"",
+ domain);
+ return (-1);
+ }
+ if (n < 0) {
+ if (errno == 0) {
+#if defined(NETREAD_BROKEN)
+ if (++retries < 42) /* doug adams */
+ continue;
+#endif
+ syslog(LOG_INFO,
+ "recv(len=%d): n=%d && !errno",
+ len, n);
+ return (-1);
+ }
+ if (errno == EINTR) {
+ if (!read_interrupted) {
+ /* It wasn't a timeout; ignore it. */
+ continue;
+ }
+ errno = ETIMEDOUT;
+ }
+ syslog(LOG_INFO, "recv(len=%d): %m", len);
+ return (-1);
+ }
+ buf += n;
+ len -= n;
+ }
+ if (setitimer(ITIMER_REAL, &zeroival, NULL) < 0) {
+ syslog(LOG_INFO, setitimerStr);
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Write a counted buffer to a file descriptor preceded by a length word.
+ */
+static int
+writemsg(int rfd, const u_char *msg, int msglen) {
+ struct iovec iov[2];
+ u_char len[INT16SZ];
+ int ret;
+
+ __putshort(msglen, len);
+ iov[0].iov_base = (char *)len;
+ iov[0].iov_len = INT16SZ;
+ iov[1].iov_base = (char *)msg;
+ iov[1].iov_len = msglen;
+ ret = writev(rfd, iov, 2);
+ if (ret != INT16SZ + msglen) {
+ syslog(LOG_DEBUG, "writemsg(%d,%#x,%d) failed: %s",
+ rfd, msg, msglen, strerror(errno));
+ return (-1);
+ }
+ return (ret);
+}
+
+static const char *
+soa_zinfo(struct zoneinfo *zp, u_char *cp, u_char *eom) {
+ int n, type, class;
+ u_int32_t ttl;
+ u_int16_t dlen;
+ u_char *rdatap;
+
+ /* Are type, class, and ttl OK? */
+ if (eom - cp < 3 * INT16SZ + INT32SZ)
+ return ("zinfo too short");
+ NS_GET16(type, cp);
+ NS_GET16(class, cp);
+ NS_GET32(ttl, cp);
+ NS_GET16(dlen, cp);
+ rdatap = cp;
+ if (type != T_SOA || class != curclass)
+ return ("zinfo wrong typ/cla/ttl");
+ /* Skip master name and contact name, we can't validate them. */
+ if ((n = dn_skipname(cp, eom)) == -1)
+ return ("zinfo mname");
+ cp += n;
+ if ((n = dn_skipname(cp, eom)) == -1)
+ return ("zinfo hname");
+ cp += n;
+ /* Grab the data fields. */
+ if (eom - cp < 5 * INT32SZ)
+ return ("zinfo dlen");
+ NS_GET32(zp->z_serial, cp);
+ NS_GET32(zp->z_refresh, cp);
+ NS_GET32(zp->z_retry, cp);
+ NS_GET32(zp->z_expire, cp);
+ NS_GET32(zp->z_minimum, cp);
+ if (cp != rdatap + dlen)
+ return ("bad soa dlen");
+ return (NULL);
+}
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) { \
+ hp->rcode = FORMERR; \
+ return (-1); \
+ } \
+ } while (0)
+
+/*
+ * Parse the message, determine if it should be printed, and if so, print it
+ * in .db file form. Does minimal error checking on the message content.
+ *
+ * XXX why aren't we using ns_sprintrr() ?
+ */
+static int
+print_output(struct zoneinfo *zp, u_int32_t serial_no, u_char *msg,
+ int msglen, u_char *rrp) {
+ u_char *cp;
+ HEADER *hp = (HEADER *) msg;
+ u_int32_t addr, ttl, tmpnum;
+ int i, j, tab, result, n1, n;
+ u_int class, type, dlen;
+ char data[MAXDATA];
+ u_char *cp1, *cp2, *temp_ptr, *eom, *rr_type_ptr;
+ u_char *cdata, *rdatap;
+ char *origin, dname[MAXDNAME];
+ const char *proto;
+ const char *ignore = "";
+ const char *badsoa_msg;
+ int escaped = 0;
+
+ eom = msg + msglen;
+ cp = rrp;
+ n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+ rr_type_ptr = cp;
+ NS_GET16(type, cp);
+ NS_GET16(class, cp);
+ NS_GET32(ttl, cp);
+ /*
+ * Following the Clarification draft's direction, we treat TTLs with
+ * the MSB set as if they were 0.
+ */
+ if (ttl > MAXIMUM_TTL) {
+ syslog(LOG_INFO, "%s: TTL > %u, converted to 0", dname,
+ MAXIMUM_TTL);
+ ttl = 0;
+ }
+ NS_GET16(dlen, cp);
+ BOUNDS_CHECK(cp, dlen);
+ rdatap = cp;
+
+ origin = dname;
+ while (*origin) {
+ if (!escaped && *origin == '.') {
+ origin++; /* skip over '.' */
+ break;
+ }
+ escaped = (*origin++ == '\\') && !escaped;
+ }
+ dprintf(3, "print_output: dname %s type %d class %d ttl %u\n",
+ dname, type, class, ttl);
+ /*
+ * Convert the resource record data into the internal database format.
+ * CP points to the raw resource record.
+ * After this switch:
+ * CP has been updated to point past the RR.
+ * CP1 points to the internal database version.
+ * N is the length of the internal database version.
+ */
+ switch (type) {
+ case T_A:
+ case T_WKS:
+ case T_HINFO:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+ case T_LOC:
+ case T_NSAP:
+ case T_AAAA:
+ case T_KEY:
+ cp1 = cp;
+ n = dlen;
+ cp += n;
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ n = dn_expand(msg, msg + msglen, cp, data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = (u_char *)data;
+ n = strlen(data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, msg + msglen, cp, data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ n = strlen(data) + 1;
+ cp1 = (u_char *)data + n;
+ n1 = sizeof data - n;
+ if (type == T_SOA)
+ n1 -= 5 * INT32SZ;
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *) cp1) + 1;
+ if (type == T_SOA) {
+ BOUNDS_CHECK(cp, 5 * INT32SZ);
+ temp_ptr = cp + 4 * INT32SZ;
+ NS_GET32(minimum_ttl, temp_ptr);
+ /*
+ * Following the Clarification draft's direction,
+ * we treat TTLs with the MSB set as if they were 0.
+ */
+ if (minimum_ttl > MAXIMUM_TTL) {
+ syslog(LOG_INFO,
+ "%s: SOA minimum TTL > %u, converted to 0",
+ dname, MAXIMUM_TTL);
+ minimum_ttl = 0;
+ }
+ n = 5 * INT32SZ;
+ memcpy(cp1, cp, n);
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ case T_NAPTR:
+ /* Grab weight and port. */
+ BOUNDS_CHECK(cp, INT16SZ*2);
+ memcpy(data, cp, INT16SZ*2);
+ cp1 = (u_char *)data + INT16SZ*2;
+ cp += INT16SZ*2;
+
+ /* Flags */
+ BOUNDS_CHECK(cp, 1);
+ n = *cp++;
+ BOUNDS_CHECK(cp, n);
+ *cp1++ = n;
+ memcpy(cp1, cp, n);
+ cp += n; cp1 += n;
+
+ /* Service */
+ BOUNDS_CHECK(cp, 1);
+ n = *cp++;
+ BOUNDS_CHECK(cp, n);
+ *cp1++ = n;
+ memcpy(cp1, cp, n);
+ cp += n; cp1 += n;
+
+ /* Regexp */
+ BOUNDS_CHECK(cp, 1);
+ n = *cp++;
+ BOUNDS_CHECK(cp, n);
+ *cp1++ = n;
+ memcpy(cp1, cp, n);
+ cp += n; cp1 += n;
+
+ /* Replacement */
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
+ sizeof data - ((char *)cp1 - data));
+ if (n < 0)
+ return (-1);
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *)cp1) + 1;
+ /* compute size of data */
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ case T_SRV:
+ /* grab preference */
+ BOUNDS_CHECK(cp, INT16SZ);
+ memcpy(data, cp, INT16SZ);
+ cp1 = (u_char *)data + INT16SZ;
+ cp += INT16SZ;
+
+ if (type == T_SRV) {
+ BOUNDS_CHECK(cp, INT16SZ*2);
+ memcpy(cp1, cp, INT16SZ*2);
+ cp1 += INT16SZ*2;
+ cp += INT16SZ*2;
+ }
+
+ /* get name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1,
+ sizeof data - (cp1 - (u_char *)data));
+ if (n < 0)
+ return (-1);
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *) cp1) + 1;
+ /* compute size of data */
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ case T_PX:
+ /* grab preference */
+ BOUNDS_CHECK(cp, INT16SZ);
+ memcpy(data, cp, INT16SZ);
+ cp1 = (u_char *)data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get MAP822 name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, sizeof data - INT16SZ);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ cp1 += (n = (strlen((char *) cp1) + 1));
+ n1 = sizeof data - n;
+
+ /* get MAPX400 name */
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ cp1 += strlen((char *) cp1) + 1;
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ case T_SIG:
+ /* CP is the raw resource record as it arrived.
+ * CP1, after this switch, points to the internal database version. */
+ cp1 = (u_char *)data;
+
+ /* first just copy over the type_covered, algorithm, */
+ /* labels, orig ttl, two timestamps, and the footprint */
+ BOUNDS_CHECK(cp, NS_SIG_SIGNER);
+ memcpy(cp1, cp, NS_SIG_SIGNER);
+ cp += NS_SIG_SIGNER;
+ cp1 += NS_SIG_SIGNER;
+
+ /* then the signer's name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, (sizeof data) - 18);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ cp1 += strlen((char*)cp1)+1;
+
+ /* finally, we copy over the variable-length signature.
+ Its size is the total data length, minus what we copied. */
+ n = dlen - (NS_SIG_SIGNER + n);
+ if (n > ((int)(sizeof data) - (int)(cp1 - (u_char *)data))) {
+ hp->rcode = FORMERR;
+ return (-1); /* out of room! */
+ }
+ memcpy(cp1, cp, n);
+ cp += n;
+ cp1 += n;
+
+ /* compute size of data */
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ case T_NXT:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = (u_char *)data + strlen(data) + 1;
+ n = dlen - n;
+ if (n > ((int)(sizeof data) - (int)(cp1 - (u_char *)data))) {
+ hp->rcode = FORMERR;
+ return (-1); /* out of room! */
+ }
+ if (n > 0) { /* Actually, n should never be less than 4 */
+ memcpy(cp1, cp, n);
+ cp += n;
+ } else {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ n += cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ default:
+ syslog(LOG_INFO, "\"%s %s %s\" - unknown type (%d)",
+ dname, p_class(class), p_type(type), type);
+ hp->rcode = NOTIMP;
+ return (-1);
+ }
+
+ if (n > MAXDATA) {
+ dprintf(1, "update type %d: %d bytes is too much data\n",
+ type, n);
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (cp != rdatap + dlen) {
+ dprintf(1,
+ "encoded rdata length is %u, but actual length was %u\n",
+ dlen, (u_int)(cp - rdatap));
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+
+ cdata = cp1;
+ result = cp - rrp;
+
+ /*
+ * Special handling for SOA records.
+ */
+
+ if (type == T_SOA) {
+ if (strcasecmp(dname, zp->z_origin) != 0) {
+ syslog(LOG_INFO,
+ "wrong zone name in AXFR (wanted \"%s\", got \"%s\")",
+ zp->z_origin, dname);
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (!soa_cnt) {
+ badsoa_msg = soa_zinfo(&zp_start, rr_type_ptr, eom);
+ if (badsoa_msg) {
+ syslog(LOG_INFO,
+ "malformed SOA for zone %s: %s",
+ zp->z_origin, badsoa_msg);
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if (SEQ_GT(zp_start.z_serial, serial_no) ||
+ !serial_no)
+ soa_cnt++;
+ else {
+ syslog(LOG_INFO,
+ "serial went backwards after transfer started");
+ return (-1);
+ }
+ } else {
+ badsoa_msg = soa_zinfo(&zp_finish, rr_type_ptr, eom);
+ if (badsoa_msg) {
+ syslog(LOG_INFO,
+ "malformed SOA for zone %s: %s",
+ zp->z_origin, badsoa_msg);
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ dprintf(2, "SOA, serial %u\n", zp_finish.z_serial);
+ if (zp_start.z_serial != zp_finish.z_serial) {
+ dprintf(1, "serial changed, restart\n");
+ restarts++;
+ if (restarts > MAX_XFER_RESTARTS) {
+ syslog(LOG_INFO,
+ "too many transfer restarts for zone %s",
+ zp->z_origin);
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ soa_cnt = 0;
+#ifdef STUBS
+ ns_cnt = 0;
+#endif
+ minimum_ttl = 0;
+ strcpy(prev_origin, zp->z_origin);
+ prev_dname[0] = DEF_DNAME;
+ /*
+ * Flush buffer, truncate file
+ * and seek to beginning to restart.
+ */
+ fflush(dbfp);
+ if (ftruncate(fileno(dbfp), 0) != 0) {
+ if (!quiet)
+ syslog(LOG_INFO,
+ "ftruncate %s: %m\n",
+ tmpname);
+ return (-1);
+ }
+ fseek(dbfp, 0L, 0);
+ return (result);
+ }
+ soa_cnt++;
+ return (result);
+ }
+ }
+
+#ifdef STUBS
+ if (zp->z_type == Z_STUB) {
+ if (query_type == T_NS && type == T_NS)
+ ns_cnt++;
+ /*
+ * If we're processing a response to an SOA query, we don't
+ * want to print anything from the response except for the SOA.
+ * We do want to check everything in the packet, which is
+ * why we do this check now instead of earlier.
+ */
+ if (query_type == T_SOA && type != T_SOA)
+ return (result);
+ }
+#endif
+
+ if (!soa_cnt || soa_cnt >= 2) {
+ char *gripe;
+
+ if (!soa_cnt)
+ gripe = "got RR before first SOA";
+ else
+ gripe = "got RR after second SOA";
+ syslog(LOG_INFO, "%s in zone %s", gripe, zp->z_origin);
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+
+ /*
+ * If they are trying to tell us info about something that is
+ * not in the zone that we are transfering, then ignore it!
+ * They don't have the authority to tell us this info.
+ *
+ * We have to do a bit of checking here - the name that we are
+ * checking is is fully qualified & may be in a subdomain of the
+ * zone in question. We also need to ignore any final dots.
+ *
+ * If a domain has both NS records and non-NS records, (for
+ * example, NS and MX records), then we should ignore the non-NS
+ * records (except that we should not ignore glue A records).
+ * XXX: It is difficult to do this properly, so we just compare
+ * the current dname with that in the most recent NS record.
+ * This defends against the most common error case,
+ * where the remote server sends MX records soon after the
+ * NS records for a particular domain. If sent earlier, we lose. XXX
+ */
+ if (!samedomain(dname, domain)) {
+ (void) fprintf(dbfp, "; Ignoring info about %s, not in zone %s.\n",
+ dname, domain);
+ ignore = "; ";
+ } else if (type != T_NS && type != T_A &&
+ strcasecmp(zone_top, dname) != 0 &&
+ strcasecmp(prev_ns_dname, dname) == 0)
+ {
+ (void) fprintf(dbfp, "; Ignoring extra info about %s, invalid after NS delegation.\n",
+ dname);
+ ignore = "; ";
+ }
+
+ /*
+ * If the current record is not being ignored, but the
+ * previous record was ignored, then we invalidate information
+ * that might have been altered by ignored records.
+ * (This means that we sometimes output unnecessary $ORIGIN
+ * lines, but that is harmless.)
+ *
+ * Also update prev_comment now.
+ */
+ if (prev_comment && ignore[0] == '\0') {
+ prev_dname[0] = DEF_DNAME;
+ prev_origin[0] = DEF_DNAME;
+ }
+ prev_comment = (ignore[0] != '\0');
+
+ /*
+ * set prev_ns_dname if necessary
+ */
+ if (type == T_NS) {
+ (void) strcpy(prev_ns_dname, dname);
+ }
+
+ /*
+ * If the origin has changed, print the new origin
+ */
+ if (strcasecmp(prev_origin, origin)) {
+ (void) strcpy(prev_origin, origin);
+ (void) fprintf(dbfp, "%s$ORIGIN %s.\n", ignore, origin);
+ }
+ tab = 0;
+
+ if (strcasecmp(prev_dname, dname)) {
+ /*
+ * set the prev_dname to be the current dname, then cut off all
+ * characters of dname after (and including) the first '.'
+ */
+ char *cutp;
+
+ (void) strcpy(prev_dname, dname);
+ escaped = 0;
+ cutp = dname;
+ while (*cutp) {
+ if (!escaped && *cutp == '.')
+ break;
+ escaped = (*cutp++ == '\\') && !escaped;
+ }
+ *cutp = '\0';
+
+ if (dname[0] == 0) {
+ if (origin[0] == 0)
+ (void) fprintf(dbfp, "%s.\t", ignore);
+ else
+ (void) fprintf(dbfp, "%s.%s.\t",
+ ignore, origin); /* ??? */
+ } else {
+ char *backslash;
+ backslash = (*dname == '@' || *dname == '$') ?
+ "\\" : "";
+ (void) fprintf(dbfp, "%s%s%s\t", ignore,
+ backslash, dname);
+ }
+ if (strlen(dname) < (size_t)8)
+ tab = 1;
+ } else {
+ (void) fprintf(dbfp, "%s\t", ignore);
+ tab = 1;
+ }
+
+ if (ttl != minimum_ttl)
+ (void) fprintf(dbfp, "%d\t", (int) ttl);
+ else if (tab)
+ (void) putc('\t', dbfp);
+
+ (void) fprintf(dbfp, "%s\t%s\t", p_class(class), p_type(type));
+ cp = cdata;
+
+ /*
+ * Print type specific data
+ */
+ switch (type) {
+
+ case T_A:
+ switch (class) {
+ case C_IN:
+ case C_HS:
+ fputs(inet_ntoa(ina_get(cp)), dbfp);
+ break;
+ }
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ if (cp[0] == '\0')
+ (void) fprintf(dbfp, ".\n");
+ else
+ (void) fprintf(dbfp, "%s.\n", cp);
+ break;
+
+ case T_NS:
+ cp = cdata;
+ if (cp[0] == '\0')
+ (void) fprintf(dbfp, ".\t");
+ else
+ (void) fprintf(dbfp, "%s.", cp);
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_HINFO:
+ case T_ISDN:
+ cp2 = cp + n;
+ for (i = 0; i < 2; i++) {
+ if (i != 0)
+ (void) putc(' ', dbfp);
+ n = *cp++;
+ cp1 = cp + n;
+ if (cp1 > cp2)
+ cp1 = cp2;
+ (void) putc('"', dbfp);
+ j = 0;
+ while (cp < cp1) {
+ if (*cp == '\0') {
+ cp = cp1;
+ break;
+ }
+ if (strchr("\n\"\\", *cp))
+ (void) putc('\\', dbfp);
+ (void) putc(*cp++, dbfp);
+ j++;
+ }
+ if (j == 0 && (type != T_ISDN || i == 0))
+ (void) putc('?', dbfp);
+ (void) putc('"', dbfp);
+ }
+ (void) putc('\n', dbfp);
+ break;
+
+ case T_SOA:
+ (void) fprintf(dbfp, "%s.", cp);
+ cp += strlen((char *) cp) + 1;
+ (void) fprintf(dbfp, " %s. (\n", cp);
+ cp += strlen((char *) cp) + 1;
+ NS_GET32(tmpnum, cp);
+ (void) fprintf(dbfp, "%s\t\t%u", ignore, tmpnum);
+ NS_GET32(tmpnum, cp);
+ (void) fprintf(dbfp, " %u", tmpnum);
+ NS_GET32(tmpnum, cp);
+ (void) fprintf(dbfp, " %u", tmpnum);
+ NS_GET32(tmpnum, cp);
+ (void) fprintf(dbfp, " %u", tmpnum);
+ NS_GET32(tmpnum, cp);
+ (void) fprintf(dbfp, " %u )\n", tmpnum);
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ NS_GET16(tmpnum, cp);
+ (void) fprintf(dbfp, "%u", tmpnum);
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ case T_PX:
+ NS_GET16(tmpnum, cp);
+ (void) fprintf(dbfp, "%u", tmpnum);
+ (void) fprintf(dbfp, " %s.", cp);
+ cp += strlen((char *) cp) + 1;
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ cp1 = cp + n;
+ while (cp < cp1) {
+ (void) putc('"', dbfp);
+ if ((i = *cp++) != 0) {
+ for (j = i; j > 0 && cp < cp1; j--) {
+ if (strchr("\n\"\\", *cp))
+ (void) putc('\\', dbfp);
+ (void) putc(*cp++, dbfp);
+ }
+ }
+ (void) putc('"', dbfp);
+ if (cp < cp1)
+ (void) putc(' ', dbfp);
+ }
+ (void) putc('\n', dbfp);
+ break;
+
+ case T_NSAP:
+ fprintf(dbfp, "%s\n", inet_nsap_ntoa(n, cp, NULL));
+ break;
+
+ case T_AAAA: {
+ char t[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+ fprintf(dbfp, "%s\n", inet_ntop(AF_INET6, cp, t, sizeof t));
+ break;
+ }
+
+ case T_LOC: {
+ char t[255];
+
+ (void) fprintf(dbfp, "%s\n", loc_ntoa(cp, t));
+ break;
+ }
+
+ case T_NAPTR: {
+ u_int32_t order, preference;
+
+ /* Order */
+ NS_GET16(order, cp);
+ fprintf(dbfp, "%u", order);
+
+ /* Preference */
+ NS_GET16(preference, cp);
+ fprintf(dbfp, " %u", preference);
+
+ /* Flags */
+ if ((n = *cp++) != 0) {
+ fprintf(dbfp, " \"%.*s\"", (int)n, cp);
+ cp += n;
+ }
+
+ /* Service */
+ if ((n = *cp++) != 0) {
+ fprintf(dbfp, " \"%.*s\"", (int)n, cp);
+ cp += n;
+ }
+
+ /* Regexp */
+ if ((n = *cp++) != 0) {
+ fprintf(dbfp, " \"%.*s\"", (int)n, cp);
+ cp += n;
+ }
+
+ /* Replacement */
+ fprintf(dbfp, " %s.\n", cp);
+
+ break;
+ }
+ case T_SRV: {
+ u_int priority, weight, port;
+
+ NS_GET16(priority, cp);
+ NS_GET16(weight, cp);
+ NS_GET16(port, cp);
+ fprintf(dbfp, "\t%u %u %u %s.\n",
+ priority, weight, port, cp);
+ break;
+ }
+
+ case T_WKS:
+ fputs(inet_ntoa(ina_get(cp)), dbfp);
+ cp += INADDRSZ;
+ fputc(' ', dbfp);
+ proto = protocolname(*cp);
+ cp += sizeof(char);
+ (void) fprintf(dbfp, "%s ", proto);
+ i = 0;
+ while (cp < cdata + n) {
+ j = *cp++;
+ do {
+ if (j & 0200)
+ (void) fprintf(dbfp, " %s",
+ servicename(i, proto));
+ j <<= 1;
+ } while (++i & 07);
+ }
+ (void) fprintf(dbfp, "\n");
+ break;
+
+ case T_MINFO:
+ case T_RP:
+ (void) fprintf(dbfp, "%s.", cp);
+ cp += strlen((char *) cp) + 1;
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ case T_KEY: {
+ char databuf[16+NS_MD5RSA_MAX_BASE64]; /* 16 for slop */
+ u_int keyflags;
+
+ /* get & format key flags */
+ keyflags = ns_get16(cp);
+ (void) fprintf(dbfp, "0x%04x ", keyflags);
+ cp += INT16SZ;
+
+ /* protocol id */
+ (void) fprintf(dbfp, " %u", *cp++);
+
+ /* algorithm id */
+ (void) fprintf(dbfp, " %u ", *cp++);
+
+ /* key itself (which may have zero length) */
+ n = b64_ntop(cp, (cp1 + n) - cp, databuf, sizeof databuf);
+ if (n < 0)
+ fprintf(dbfp, "; BAD BASE64\n");
+ else
+ fprintf(dbfp, "%s\n", databuf);
+ break;
+ }
+
+ case T_SIG: {
+ char databuf[16+NS_MD5RSA_MAX_BASE64]; /* 16 for slop */
+
+ /* get & format rr type which signature covers */
+ (void) fprintf(dbfp,"%s", p_type(ns_get16((u_char*)cp)));
+ cp += INT16SZ;
+
+ /* algorithm id */
+ (void) fprintf(dbfp," %d",*cp++);
+
+ /* labels (# of labels in name) - skip in textual record */
+ cp++;
+
+ /* orig time to live (TTL)) */
+ (void) fprintf(dbfp," %u", (u_int32_t)ns_get32((u_char*)cp));
+ cp += INT32SZ;
+
+ /* expiration time */
+ (void) fprintf(dbfp," %s", p_secstodate(ns_get32((u_char*)cp)));
+ cp += INT32SZ;
+
+ /* time signed */
+ (void) fprintf(dbfp," %s", p_secstodate(ns_get32((u_char*)cp)));
+ cp += INT32SZ;
+
+ /* Key footprint */
+ (void) fprintf(dbfp," %d", ns_get16((u_char*)cp));
+ cp += INT16SZ;
+
+ /* signer's name */
+ (void) fprintf(dbfp, " %s. ", cp);
+ cp += strlen((char *) cp) + 1;
+
+ /* signature itself */
+ n = b64_ntop(cp, (cdata + n) - cp, databuf, sizeof databuf);
+ if (n < 0)
+ fprintf (dbfp, "; BAD BASE64\n");
+ else
+ fprintf (dbfp, "%s\n", databuf);
+ break;
+ }
+
+ case T_NXT:
+ fprintf(dbfp, "%s.", (char *)cp);
+ i = strlen((char *)cp)+1;
+ cp += i;
+ n -= i;
+ for (i=0; i < n*NS_NXT_BITS; i++)
+ if (NS_NXT_BIT_ISSET (i, cp))
+ fprintf(dbfp, " %s", p_type(i));
+ fprintf(dbfp,"\n");
+ break;
+
+ default:
+ cp1 = cp + n;
+ while (cp < cp1)
+ fprintf(dbfp, "0x%02.2X ", *cp++ & 0xFF);
+ (void) fprintf(dbfp, "???\n");
+ }
+ if (ferror(dbfp)) {
+ syslog(LOG_ERR, "%s: %m", tmpname);
+ cleanup_for_exit();
+ exit(XFER_FAIL);
+ }
+ return (result);
+}
+
+#ifdef SHORT_FNAMES
+/*
+** This routine handles creating temporary files with mkstemp
+** in the presence of a 14 char filename system. Pathconf()
+** does not work over NFS.
+*/
+filenamecpy(char *ddtfile, char *optarg) {
+ int namelen, extra, len;
+ char *dirname, *filename;
+
+ /* determine the length of filename allowed */
+ if((dirname = strrchr(optarg, '/')) == NULL){
+ filename = optarg;
+ } else {
+ *dirname++ = '\0';
+ filename = dirname;
+ }
+ namelen = pathconf(dirname == NULL? "." : optarg, _PC_NAME_MAX);
+ if(namelen <= 0)
+ namelen = 255; /* length could not be determined */
+ if(dirname != NULL)
+ *--dirname = '/';
+
+ /* copy a shorter name if it will be longer than allowed */
+ extra = (strlen(filename)+strlen(".XXXXXX")) - namelen;
+ if(extra > 0){
+ len = strlen(optarg) - extra;
+ (void) strncpy(ddtfile, optarg, len);
+ ddtfile[len] = '\0';
+ } else
+ (void) strcpy(ddtfile, optarg);
+}
+#endif /* SHORT_FNAMES */