summaryrefslogtreecommitdiffstats
path: root/contrib/bind/named/db_load.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/named/db_load.c')
-rw-r--r--contrib/bind/named/db_load.c1168
1 files changed, 978 insertions, 190 deletions
diff --git a/contrib/bind/named/db_load.c b/contrib/bind/named/db_load.c
index dda27c9..6b0a11a 100644
--- a/contrib/bind/named/db_load.c
+++ b/contrib/bind/named/db_load.c
@@ -1,6 +1,6 @@
#if !defined(lint) && !defined(SABER)
static char sccsid[] = "@(#)db_load.c 4.38 (Berkeley) 3/2/91";
-static char rcsid[] = "$Id: db_load.c,v 8.22 1996/08/05 08:31:30 vixie Exp $";
+static char rcsid[] = "$Id: db_load.c,v 8.31 1996/12/18 04:09:48 vixie Exp $";
#endif /* not lint */
/*
@@ -55,6 +55,28 @@ static char rcsid[] = "$Id: db_load.c,v 8.22 1996/08/05 08:31:30 vixie Exp $";
* 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.
* --Copyright--
*/
@@ -66,88 +88,45 @@ static char rcsid[] = "$Id: db_load.c,v 8.22 1996/08/05 08:31:30 vixie Exp $";
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
+
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
-#include <stdio.h>
-#include <syslog.h>
+
#include <ctype.h>
+#include <errno.h>
#include <netdb.h>
#include <resolv.h>
-#include <errno.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <time.h>
#include "named.h"
+#define ALLOW_LONG_TXT_RDATA
+
static int gettoken __P((register FILE *, const char *)),
getnonblank __P((FILE *, const char *)),
getprotocol __P((FILE *, const char *)),
- getservices __P((int, char *, FILE *, const char *));
+ getservices __P((int, char *, FILE *, const char *)),
+ getcharstring __P((char *, char *, int, int, int, FILE *, const char *));
static void makename __P((char *, const char *));
static int makename_ok __P((char *name, const char *origin,
int class,
enum transport transport,
enum context context,
+ const char *owner,
const char *filename, int lineno));
+static int getmlword __P((char *, int, FILE *, int));
+static int getallwords __P((char *, int, FILE *, int));
+static u_int32_t wordtouint32 __P((char *));
+static u_int32_t datetosecs __P((char *, int *));
+static int wordtouint32_error = 0;
static int empty_token = 0;
-int getnum_error;
+static int getmlword_nesting = 0;
-/*
- * Map class and type names to number
- */
-struct map {
- char token[8];
- int val;
-};
-
-struct map m_class[] = {
- { "in", C_IN },
-#ifdef notdef
- { "any", C_ANY }, /* any is a QCLASS, not CLASS */
-#endif
- { "chaos", C_CHAOS },
- { "hs", C_HS },
-};
-#define M_CLASS_CNT (sizeof(m_class) / sizeof(struct map))
-
-struct map m_type[] = {
- { "a", T_A },
- { "ns", T_NS },
- { "cname", T_CNAME },
- { "soa", T_SOA },
- { "mb", T_MB },
- { "mg", T_MG },
- { "mr", T_MR },
- { "null", T_NULL },
- { "wks", T_WKS },
- { "ptr", T_PTR },
- { "hinfo", T_HINFO },
- { "minfo", T_MINFO },
- { "mx", T_MX },
- { "uinfo", T_UINFO },
- { "txt", T_TXT },
- { "rp", T_RP },
- { "afsdb", T_AFSDB },
- { "x25", T_X25 },
- { "isdn", T_ISDN },
- { "rt", T_RT },
- { "nsap", T_NSAP },
- { "nsap_ptr", T_NSAP_PTR },
- { "uid", T_UID },
- { "gid", T_GID },
- { "px", T_PX },
- { "aaaa", T_AAAA },
-#ifdef notdef
- { "any", T_ANY }, /* any is a QTYPE, not TYPE */
-#endif
-#ifdef LOC_RR
- { "loc", T_LOC },
-#endif /* LOC_RR */
-#ifdef ALLOW_T_UNSPEC
- { "unspec", T_UNSPEC },
-#endif /* ALLOW_T_UNSPEC */
-};
-#define M_TYPE_CNT (sizeof(m_type) / sizeof(struct map))
+int getnum_error;
/*
* Parser token values
@@ -160,11 +139,11 @@ struct map m_type[] = {
#define ORIGIN 6
#define ERROR 7
-static int clev; /* a zone deeper in a heirachy has more credability */
+static int clev; /* a zone deeper in a hierachy has more credability */
#define MAKENAME_OK(N) if (!makename_ok(N, origin, class, \
transport, context, \
- filename, lineno)) { \
+ domain, filename, lineno)) { \
errs++; \
sprintf(buf, "bad name \"%s\"", N); \
goto err; \
@@ -188,14 +167,13 @@ db_load(filename, in_origin, zp, def_domain)
{
static int read_soa, read_ns, rrcount;
register char *cp;
- register struct map *mp;
char domain[MAXDNAME];
char origin[MAXDNAME];
char tmporigin[MAXDNAME];
char buf[MAXDATA];
char data[MAXDATA];
- const char *cp1, *op;
- int c, class, type, dbflags, dataflags, multiline;
+ const char *op;
+ int c, someclass, class, type, dbflags, dataflags, multiline;
u_int32_t ttl;
struct databuf *dp;
FILE *fp;
@@ -206,10 +184,19 @@ db_load(filename, in_origin, zp, def_domain)
int escape;
enum transport transport;
enum context context;
+ u_int32_t sig_type;
+ u_int32_t keyflags;
+ int success;
+ int dateerror;
#ifdef DO_WARN_SERIAL
u_int32_t serial;
#endif
+/* Simple macro for setting error messages about RR's being parsed,
+ before jumping to err label. If no SETERR is done, the last word
+ scanned into "buf" by getword will be printed. */
+#define SETERR(x) strcpy (buf, x);
+
switch (zp->z_type) {
case Z_PRIMARY:
case Z_CACHE:
@@ -347,41 +334,49 @@ db_load(filename, in_origin, zp, def_domain)
if (!getword((char *)buf, sizeof(buf), fp, 0))
break;
}
- for (mp = m_class; mp < m_class+M_CLASS_CNT; mp++)
- if (!strcasecmp((char *)buf, mp->token)) {
- class = mp->val;
- (void) getword((char *)buf,
- sizeof(buf), fp, 0);
- break;
- }
- for (mp = m_type; mp < m_type+M_TYPE_CNT; mp++)
- if (!strcasecmp((char *)buf, mp->token)) {
- type = mp->val;
- goto fndtype;
- }
- dprintf(1, (ddt, "%s: Line %d: Unknown type: %s.\n",
- filename, lineno, buf));
- errs++;
- syslog(LOG_NOTICE, "%s: Line %d: Unknown type: %s.\n",
- filename, lineno, buf);
- break;
- fndtype:
+
+ /* Parse class (IN, etc) */
+ someclass = sym_ston(__p_class_syms,
+ (char *)buf, &success);
+ if (success && someclass != C_ANY) {
+ class = someclass;
+ (void) getword((char *)buf,
+ sizeof(buf), fp, 0);
+ }
+
+ /* Parse RR type (A, MX, etc) */
+ type = sym_ston(__p_type_syms,
+ (char *)buf, &success);
+ if ((!success) || type == T_ANY) {
+ dprintf(1, (ddt, "%s: Line %d: Unknown type: %s.\n",
+ filename, lineno, buf));
+ errs++;
+ syslog(LOG_INFO, "%s: Line %d: Unknown type: %s.\n",
+ filename, lineno, buf);
+ break;
+ }
+
context = ns_ownercontext(type, transport);
- if (!ns_nameok(domain, class, transport, context)) {
+ if (!ns_nameok(domain, class, transport, context,
+ domain, inaddr_any)) {
errs++;
syslog(LOG_NOTICE,
"%s:%d: owner name error\n",
filename, lineno);
break;
}
-#ifdef ALLOW_T_UNSPEC
- /* Don't do anything here for T_UNSPEC...
- * read input separately later
- */
- if (type != T_UNSPEC) {
-#endif
+
context = domain_ctx;
switch (type) {
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ case T_KEY:
+ case T_SIG:
+ /* Don't do anything here for these types --
+ they read their own input separately later */
+ goto dont_get_word;
+
case T_SOA:
case T_MINFO:
case T_RP:
@@ -402,13 +397,11 @@ db_load(filename, in_origin, zp, def_domain)
(ddt,
"d='%s', c=%d, t=%d, ttl=%d, data='%s'\n",
domain, class, type, ttl, buf));
-#ifdef ALLOW_T_UNSPEC
- }
-#endif
/*
* Convert the ascii data 'buf' to the proper format
* based on the type and pack into 'data'.
*/
+ dont_get_word:
switch (type) {
case T_A:
if (!inet_aton(buf, &ina))
@@ -419,55 +412,6 @@ db_load(filename, in_origin, zp, def_domain)
n = INT32SZ;
break;
- case T_HINFO:
- case T_ISDN:
- n = strlen((char *)buf);
- if (n > 255) {
- syslog(LOG_INFO,
- "%s: line %d: %s too long",
- filename, lineno, (type == T_ISDN) ?
- "ISDN-address" : "CPU type");
- n = 255;
- }
- data[0] = n;
- bcopy(buf, (char *)data + 1, (int)n);
- if (n == 0)
- goto err;
- n++;
- if (!getword((char *)buf, sizeof(buf), fp, 0))
- i = 0;
- else {
- endline(fp);
- i = strlen((char *)buf);
- }
- if (i == 0) {
- if (type == T_ISDN) {
- data[n++] = 0;
- break;
- }
- else
- /* goto err; */
- /* XXX tolerate for now */
- data[n++] = 1;
- data[n++] = '?';
- syslog(LOG_INFO,
- "%s: line %d: OS-type missing",
- filename,
- empty_token ? (lineno - 1) : lineno);
- break;
- }
- if (i > 255) {
- syslog(LOG_INFO,
- "%s:%d: %s too long",
- filename, lineno, (type == T_ISDN) ?
- "ISDN-sa" : "OS type");
- i = 255;
- }
- data[n] = i;
- bcopy(buf, data + n + 1, i);
- n += i + 1;
- break;
-
case T_SOA:
context = hostname_ctx;
goto soa_rp_minfo;
@@ -481,7 +425,8 @@ db_load(filename, in_origin, zp, def_domain)
MAKENAME_OK(data);
cp = data + strlen((char *)data) + 1;
if (!getword((char *)cp,
- (sizeof data) - (cp - data),
+ (sizeof data) -
+ (cp - (char *)data),
fp, 1))
goto err;
if (type == T_RP)
@@ -491,7 +436,7 @@ db_load(filename, in_origin, zp, def_domain)
MAKENAME_OK(cp);
cp += strlen((char *)cp) + 1;
if (type != T_SOA) {
- n = cp - data;
+ n = cp - (char *)data;
break;
}
if (class != zp->z_class) {
@@ -572,18 +517,81 @@ db_load(filename, in_origin, zp, def_domain)
}
n = (u_int32_t) zp->z_minimum;
PUTLONG (n, cp);
- n = cp - data;
+ n = cp - (char *)data;
if (multiline) {
if (getnonblank(fp, filename) != ')')
goto err;
+ endline(fp);
}
read_soa++;
- if (zp->z_expire < zp->z_refresh ) {
+ if (zp->z_type != Z_PRIMARY)
+ break;
+ /* sanity checks PRIMARY ONLY */
+ /*
+ * sanity: give enough time for the
+ * zone to transfer (retry)
+ */
+ if (zp->z_expire <
+ (zp->z_refresh+zp->z_retry)) {
+ syslog(LOG_NOTICE,
+ "%s: WARNING SOA expire value is less then SOA refresh + retry (%lu < %lu + %lu)",
+ filename, zp->z_expire, zp->z_refresh,
+ zp->z_retry);
+ }
+ /* BIND specific */
+ if (zp->z_expire < maint_interval) {
+ syslog(LOG_NOTICE,
+ "%s: WARNING SOA expire value is less then maintainance interval (%lu < %lu)",
+ filename, zp->z_expire, maint_interval);
+ }
+ /* BIND Specific */
+ if (zp->z_refresh < maint_interval) {
syslog(LOG_WARNING,
- "%s: WARNING SOA expire value is less then SOA refresh (%lu < %lu)",
- filename, zp->z_expire, zp->z_refresh);
+ "%s: WARNING SOA refresh value is less then maintainance interval (%lu < %lu)",
+ filename, zp->z_refresh, maint_interval);
+ }
+ /* BIND specific */
+ if (zp->z_retry < maint_interval) {
+ syslog(LOG_WARNING,
+ "%s: WARNING SOA retry value is less then maintainance interval (%lu < %lu)",
+ filename, zp->z_retry, maint_interval);
+ }
+ /* sanity */
+ if (zp->z_expire <
+ (zp->z_refresh + 10 * zp->z_retry)) {
+ syslog(LOG_WARNING,
+ "%s: WARNING SOA expire value is less then refresh + 10 * retry (%lu < (%lu + 10 * %lu))",
+ filename, zp->z_expire, zp->z_refresh,
+ zp->z_retry);
+ }
+ /*
+ * sanity: most harware/telco faults are
+ * detected and fixed within a week,
+ * secondaries should continue to
+ * operate for this time.
+ * (minimum of 4 days for long weekends)
+ */
+ if (zp->z_expire < (7 * 24 * 3600)) {
+ syslog(LOG_WARNING,
+ "%s: WARNING SOA expire value is less then 7 days (%lu)",
+ filename, zp->z_expire);
+ }
+ /*
+ * sanity: maximum down time
+ * if we havn't talked for six months
+ * war must have broken out
+ */
+ if (zp->z_expire > ( 183 * 24 * 3600)) {
+ syslog(LOG_WARNING,
+ "%s: WARNING SOA expire value is greater then 6 months (%lu)",
+ filename, zp->z_expire);
+ }
+ /* sanity */
+ if (zp->z_refresh < (zp->z_retry * 2)) {
+ syslog(LOG_WARNING,
+ "%s: WARNING SOA refresh value is less than 2 * retry (%lu < %lu * 2)",
+ filename, zp->z_refresh, zp->z_retry);
}
- endline(fp);
break;
case T_UID:
@@ -652,9 +660,66 @@ db_load(filename, in_origin, zp, def_domain)
(char *)buf);
n = strlen((char *)data) + 1;
break;
+
+ case T_NAPTR:
+ /* Order Preference Flags Service Replacement Regexp */
+ n = 0;
+ cp = buf;
+ /* Order */
+ while (isdigit(*cp))
+ n = n * 10 + (*cp++ - '0');
+ /* catch bad values */
+ if ((cp == buf) || (n > 65535))
+ goto err;
+ cp = data;
+ PUTSHORT((u_int16_t)n, cp);
+ /* Preference */
+ n = getnum(fp, filename, GETNUM_NONE);
+ if (getnum_error || n > 65536)
+ goto err;
+ PUTSHORT((u_int16_t)n, cp);
+
+ /* Flags */
+ if (!getword((char *)buf, sizeof(buf), fp, 0))
+ goto err;
+ n = strlen((char *)buf);
+ *cp++ = n;
+ bcopy(buf, (char *)cp, (int)n);
+ cp += n;
+
+ /* Service Classes */
+ if (!getword((char *)buf, sizeof(buf), fp, 0))
+ goto err;
+ n = strlen((char *)buf);
+ *cp++ = n;
+ bcopy(buf, (char *)cp, (int)n);
+ cp += n;
+
+ /* Pattern */
+ if (!getword((char *)buf, sizeof(buf), fp, 0))
+ goto err;
+ n = strlen((char *)buf);
+ *cp++ = n;
+ bcopy(buf, (char *)cp, (int)n);
+ cp += n;
+
+ /* Replacement */
+ if (!getword((char *)buf, sizeof(buf), fp, 1))
+ goto err;
+ (void) strcpy((char *)cp, (char *)buf);
+ context = domain_ctx;
+ MAKENAME_OK(cp);
+ /* advance pointer to end of data */
+ cp += strlen((char *)cp) +1;
+
+ /* now save length */
+ n = (cp - (char *)data);
+ break;
+
case T_MX:
case T_AFSDB:
case T_RT:
+ case T_SRV:
n = 0;
cp = buf;
while (isdigit(*cp))
@@ -662,10 +727,21 @@ db_load(filename, in_origin, zp, def_domain)
/* catch bad values */
if ((cp == buf) || (n > 65535))
goto err;
-
cp = data;
PUTSHORT((u_int16_t)n, cp);
+ if (type == T_SRV) {
+ n = getnum(fp, filename, GETNUM_NONE);
+ if (getnum_error || n > 65536)
+ goto err;
+ PUTSHORT((u_int16_t)n, cp);
+
+ n = getnum(fp, filename, GETNUM_NONE);
+ if (getnum_error || n > 65536)
+ goto err;
+ PUTSHORT((u_int16_t)n, cp);
+ }
+
if (!getword((char *)buf, sizeof(buf), fp, 1))
goto err;
(void) strcpy((char *)cp, (char *)buf);
@@ -675,7 +751,7 @@ db_load(filename, in_origin, zp, def_domain)
cp += strlen((char *)cp) +1;
/* now save length */
- n = (cp - data);
+ n = (cp - (char *)data);
break;
case T_PX:
@@ -705,36 +781,31 @@ db_load(filename, in_origin, zp, def_domain)
cp += strlen((char *)cp) + 1;
/* now save length */
- n = (cp - data);
+ n = (cp - (char *)data);
+ break;
+
+ case T_HINFO:
+ n = getcharstring(buf, data, type, 2, 2, fp, filename);
+ if (n == 0)
+ goto err;
+ break;
+
+ case T_ISDN:
+ n = getcharstring(buf, data, type, 1, 2, fp, filename);
+ if (n == 0)
+ goto err;
break;
case T_TXT:
+ n = getcharstring(buf, data, type, 1, 0, fp, filename);
+ if (n == 0)
+ goto err;
+ break;
+
case T_X25:
- i = strlen((char *)buf);
- cp = data;
- cp1 = buf;
- /*
- * there is expansion here so make sure we
- * don't overflow data
- */
- if (i > (sizeof data) * 255 / 256) {
- syslog(LOG_INFO,
- "%s: line %d: TXT record truncated",
- filename, lineno);
- i = (sizeof data) * 255 / 256;
- }
- while (i > 255) {
- *cp++ = 255;
- bcopy(cp1, cp, 255);
- cp += 255;
- cp1 += 255;
- i -= 255;
- }
- *cp++ = i;
- bcopy(cp1, cp, i);
- cp += i;
- n = cp - data;
- endline(fp);
+ n = getcharstring(buf, data, type, 1, 1, fp, filename);
+ if (n == 0)
+ goto err;
break;
case T_NSAP:
@@ -750,6 +821,459 @@ db_load(filename, in_origin, zp, def_domain)
n = IN6ADDRSZ;
endline(fp);
break;
+
+ case T_KEY: {
+ /* The KEY record looks like this in the db file:
+ * Name Cl KEY Flags Proto Algid PublicKeyData
+ * where:
+ * Name,Cl per usual
+ * KEY RR type
+ * Flags 4 digit hex value (unsigned_16)
+ * Proto 8 bit u_int
+ * Algid 8 bit u_int
+ * PublicKeyData
+ * a string of base64 digits,
+ * skipping any embedded whitespace.
+ */
+ u_int32_t al, pr;
+ int nk, klen;
+ char *expstart;
+ u_int expbytes, modbytes;
+
+ i = 0;
+ data[i] = '\0';
+ cp = data;
+ getmlword_nesting = 0; /* KLUDGE err recov. */
+ /*>>> Flags (unsigned_16) */
+ if (!getmlword((char*)buf, sizeof(buf), fp, 0)
+ ) {
+ SETERR("No flags field");
+ goto err;
+ }
+ keyflags = wordtouint32(buf);
+ if (wordtouint32_error || 0xFFFF < keyflags)
+ goto err;
+ if (keyflags & KEYFLAG_RESERVED_BITMASK) {
+ SETERR("Reserved flag bits are set");
+ goto err;
+ }
+ PUTSHORT(keyflags, cp);
+
+ /*>>> Protocol (8-bit decimal) */
+ if (!getmlword((char*)buf, sizeof(buf), fp, 0)
+ ) {
+ SETERR("No protocol field");
+ goto err;
+ }
+ pr = wordtouint32(buf);
+ if (wordtouint32_error || 255 < pr)
+ goto err;
+ *cp++ = (u_char) pr;
+
+ /*>>> Algorithm id (8-bit decimal) */
+ if (!getmlword((char*)buf, sizeof(buf), fp, 0)
+ ) {
+ SETERR("No algorithm ID")
+ goto err;
+ }
+ al = wordtouint32(buf);
+ if (wordtouint32_error ||
+ 0 == al || 255 == al || 255 < al)
+ goto err;
+ *cp++ = (u_char) al;
+
+ /*>>> Public Key data is in BASE64.
+ * We don't care what algorithm it uses or what
+ * the internal structure of the BASE64 data is.
+ */
+ if (!getallwords((char *)buf, MAXDATA, fp, 0))
+ klen = 0;
+ else {
+ /* Convert from BASE64 to binary. */
+ klen = b64_pton(buf, (u_char*)cp,
+ sizeof data -
+ (cp - (char *)data));
+ if (klen < 0)
+ goto err;
+ }
+
+ /* set total length */
+ n = cp + klen - (char *)data;
+
+ /*
+ * Now check for valid key flags & algs & etc,
+ * from the RFC.
+ */
+
+ if (keyflags & (KEYFLAG_ZONEKEY | KEYFLAG_IPSEC
+ | KEYFLAG_EMAIL))
+ pr |= 1; /* A nonzero proto. */
+ if (KEYFLAG_TYPE_NO_KEY ==
+ (keyflags & KEYFLAG_TYPEMASK))
+ nk = 1; /* No-key */
+ else
+ nk = 0; /* have a key */
+ if ((keyflags & KEYFLAG_ZONEKEY) &&
+ (KEYFLAG_TYPE_CONF_ONLY ==
+ (keyflags & KEYFLAG_TYPEMASK))) {
+ /* Zone key must have Authentication bit
+ set ogud@tis.com */
+ SETERR("Zonekey needs authentication bit");
+ goto err;
+ }
+
+ if (al == 0 && nk == 0) {
+ SETERR("Key specified, but no alg");
+ goto err;
+ }
+ if (al != 0 && pr == 0) {
+ SETERR("Alg specified, but no protos");
+ goto err;
+ }
+
+ if (nk == 1 && klen != 0) {
+ SETERR("No-key flags set but key fnd");
+ goto err;
+ }
+
+ if (nk == 0 && klen == 0) {
+ SETERR("Key type spec'd, but no key");
+ goto err;
+ }
+
+ /* Check algorithm-ID and key structure, for
+ the algorithm-ID's that we know about. */
+ switch (al) {
+ case ALGORITHM_MD5RSA:
+ if (klen == 0)
+ break;
+ expstart = cp;
+ expbytes = *expstart++;
+ if (expbytes == 0)
+ GETSHORT(expbytes, expstart);
+
+ if (expbytes < 1) {
+ SETERR("Exponent too short");
+ goto err;
+ }
+ if (expbytes >
+ (MAX_MD5RSA_KEY_PART_BITS + 7) / 8
+ ) {
+ SETERR("Exponent too long");
+ goto err;
+ }
+ if (*expstart == 0) {
+ SETERR("Exponent starts w/ 0");
+ goto err;
+ }
+
+ modbytes = klen -
+ (expbytes + (expstart - cp));
+ if (modbytes <
+ (MIN_MD5RSA_KEY_PART_BITS + 7) / 8
+ ) {
+ SETERR("Modulus too short");
+ goto err;
+ }
+ if (modbytes >
+ (MAX_MD5RSA_KEY_PART_BITS + 7) / 8
+ ) {
+ SETERR("Modulus too long");
+ goto err;
+ }
+ if (*(expstart+expbytes) == 0) {
+ SETERR("Modulus starts w/ 0");
+ goto err;
+ }
+ break;
+
+ case ALGORITHM_EXPIRE_ONLY:
+ if (klen != 0) {
+ SETERR(
+ "Key provided for expire-only algorithm");
+ goto err;
+ }
+ break;
+ case ALGORITHM_PRIVATE_OID:
+ if (klen == 0) {
+ SETERR("No ObjectID in key");
+ goto err;
+ }
+ break;
+ }
+
+ endline(fp); /* flush the rest of the line */
+ break;
+ } /*T_KEY*/
+
+ case T_SIG:
+ {
+ /* The SIG record looks like this in the db file:
+ Name Cl SIG RRtype Algid [OTTL] Texp Tsig Kfoot Signer Sig
+
+ where: Name and Cl are as usual
+ SIG is a keyword
+ RRtype is a char string
+ ALGid is 8 bit u_int
+ OTTL is 32 bit u_int (optionally present)
+ Texp is YYYYMMDDHHMMSS
+ Tsig is YYYYMMDDHHMMSS
+ Kfoot is 16-bit unsigned decimal integer
+ Signer is a char string
+ Sig is 64 to 319 base-64 digits
+ A missing OTTL is detected by the magnitude of the Texp value
+ that follows it, which is larger than any u_int.
+ The Labels field in the binary RR does not appear in the
+ text RR.
+
+ It's too crazy to run these pages of SIG code at the right
+ margin. I'm exdenting them for readability.
+ */
+ int siglen;
+ u_int32_t al;
+ u_int32_t signtime, exptime, timetilexp;
+ u_int32_t origTTL;
+ time_t now;
+
+ /* The TTL gets checked against the Original TTL,
+ and bounded by the signature expiration time, which
+ are both under the signature. We can't let TTL drift
+ based on the SOA record. If defaulted, fix it now.
+ (It's not clear to me why USE_MINIMUM isn't eliminated
+ before putting ALL RR's into the database. -gnu@toad.com) */
+ if (ttl == USE_MINIMUM)
+ ttl = zp->z_minimum;
+
+ i = 0;
+ data[i] = '\0';
+ getmlword_nesting = 0; /* KLUDGE err recovery */
+
+ /* RRtype (char *) */
+ if (!getmlword((char*)buf, sizeof(buf), fp, 0)) {
+ SETERR("SIG record doesn't specify type");
+ goto err;
+ }
+ sig_type = sym_ston(__p_type_syms, (char *)buf, &success);
+ if (!success || sig_type == T_ANY) {
+ /*
+ * We'll also accept a numeric RR type,
+ * for signing RR types that this version
+ * of named doesn't yet understand.
+ * In the T_ANY case, we rely on wordtouint32
+ * to fail when scanning the string "ANY".
+ */
+ sig_type = wordtouint32 (buf);
+ if (wordtouint32_error || sig_type > 0xFFFF) {
+ SETERR("Unknown RR type in SIG record");
+ goto err;
+ }
+ }
+ cp = &data[i];
+ PUTSHORT((u_int16_t)sig_type, cp);
+ i += 2;
+
+ /* Algorithm id (8-bit decimal) */
+ if (!getmlword((char *)buf, sizeof(buf), fp, 0)) {
+ SETERR("Missing algorithm ID");
+ goto err;
+ }
+ al = wordtouint32(buf);
+ if (0 == al || wordtouint32_error || 255 <= al)
+ goto err;
+ data[i] = (u_char) al;
+ i++;
+
+ /*
+ * Labels (8-bit decimal)
+ * Not given in the file. Must compute.
+ */
+ n = dn_count_labels(domain);
+ if (0 >= n || 255 < n) {
+ SETERR ("SIG label count invalid");
+ goto err;
+ }
+ data[i] = (u_char) n;
+ i++;
+
+ /*
+ * OTTL (optional u_int32_t) and
+ * Texp (u_int32_t date)
+ */
+ if (!getmlword((char *)buf, sizeof(buf), fp, 0)) {
+ SETERR("OTTL and expiration time missing");
+ goto err;
+ }
+ /*
+ * See if OTTL is missing and this is a date.
+ * This relies on good, silent error checking
+ * in datetosecs.
+ */
+ exptime = datetosecs(buf, &dateerror);
+ if (!dateerror) {
+ /* Output TTL as OTTL */
+ origTTL = ttl;
+ cp = &data[i];
+ PUTLONG (origTTL, cp);
+ i += 4;
+ } else {
+ /* Parse and output OTTL; scan TEXP */
+ origTTL = wordtouint32(buf);
+ if (0 >= origTTL || wordtouint32_error ||
+ (origTTL > 0x7fffffff))
+ goto err;
+ cp = &data[i];
+ PUTLONG(origTTL, cp);
+ i += 4;
+ if (!getmlword((char *)buf, sizeof(buf), fp, 0)) {
+ SETERR ("Expiration time missing");
+ goto err;
+ }
+ exptime = datetosecs(buf, &dateerror);
+ }
+ if (dateerror || exptime > 0x7fffffff || exptime <= 0) {
+ SETERR("Invalid expiration time");
+ goto err;
+ }
+ cp = &data[i];
+ PUTLONG(exptime, cp);
+ i += 4;
+
+ /* Tsig (u_int32_t) */
+ if (!getmlword((char *)buf, sizeof(buf), fp, 0)) {
+ SETERR("Missing signature time");
+ goto err;
+ }
+ signtime = datetosecs(buf, &dateerror);
+ if (0 == signtime || dateerror) {
+ SETERR("Invalid signature time");
+ goto err;
+ }
+ cp = &data[i];
+ PUTLONG(signtime, cp);
+ i += 4;
+
+ /* Kfootprint (unsigned_16) */
+ if (!getmlword((char *)buf, sizeof(buf), fp, 0)) {
+ SETERR("Missing key footprint");
+ goto err;
+ }
+ n = wordtouint32(buf);
+ if (wordtouint32_error || n >= 0x0ffff) {
+ SETERR("Invalid key footprint");
+ goto err;
+ }
+ cp = &data[i];
+ PUTSHORT((u_int16_t)n, cp);
+ i += 2;
+
+ /* Signer's Name */
+ if (!getmlword((char*)buf, sizeof(buf), fp, 0)) {
+ SETERR("Missing signer's name");
+ goto err;
+ }
+ cp = &data[i];
+ strcpy(cp,buf);
+ context = domain_ctx;
+ MAKENAME_OK(cp);
+ i += strlen(cp) + 1;
+
+ /*
+ * Signature (base64 of any length)
+ * We don't care what algorithm it uses or what
+ * the internal structure of the BASE64 data is.
+ */
+ if (!getallwords((char *)buf, sizeof(buf), fp, 0)) {
+ siglen = 0;
+ } else {
+ cp = &data[i];
+ siglen = b64_pton(buf, (u_char*)cp, sizeof data - i);
+ if (siglen < 0)
+ goto err;
+ }
+
+ /* set total length and we're done! */
+ n = i + siglen;
+
+ /*
+ * Check signature time, expiration, and adjust TTL. Note
+ * that all time values are in GMT (UTC), *not* local time.
+ */
+
+ now = time (0);
+
+ /* Don't let bogus name servers increase the signed TTL */
+ if (ttl > origTTL) {
+ SETERR("TTL is greater than signed original TTL");
+ goto err;
+ }
+
+ /* Don't let bogus signers "sign" in the future. */
+ if (signtime > now) {
+ SETERR("signature time is in the future");
+ goto err;
+ }
+
+ /* Ignore received SIG RR's that are already expired. */
+ if (exptime <= now) {
+ SETERR("expiration time is in the past");
+ goto err;
+ }
+
+ /* Lop off the TTL at the expiration time. */
+ timetilexp = exptime - now;
+ if (timetilexp < ttl) {
+ dprintf(1, (ddt,
+ "shrinking expiring %s SIG TTL from %d to %d\n",
+ p_secstodate(exptime), ttl, timetilexp));
+ ttl = timetilexp;
+ }
+
+ /*
+ * Check algorithm-ID and key structure, for
+ * the algorithm-ID's that we know about.
+ */
+ switch (al) {
+ case ALGORITHM_MD5RSA:
+ if (siglen == 0) {
+ SETERR("No key for RSA algorithm");
+ goto err;
+ }
+ if (siglen < 1) {
+ SETERR("Signature too short");
+ goto err;
+ }
+ if (siglen > (MAX_MD5RSA_KEY_PART_BITS + 7) / 8) {
+ SETERR("Signature too long");
+ goto err;
+ }
+ /* We rely on cp from parse */
+ if (*cp == 0) {
+ SETERR("Signature starts with zeroes");
+ goto err;
+ }
+ break;
+
+ case ALGORITHM_EXPIRE_ONLY:
+ if (siglen != 0) {
+ SETERR(
+ "Signature supplied to expire-only algorithm"
+ );
+ goto err;
+ }
+ break;
+ case ALGORITHM_PRIVATE_OID:
+ if (siglen == 0) {
+ SETERR("No ObjectID in key");
+ goto err;
+ }
+ break;
+ }
+
+ endline(fp); /* flush the rest of the line */
+
+ break; /* Accept this RR. */
+ }
+
#ifdef LOC_RR
case T_LOC:
cp = buf + (n = strlen(buf));
@@ -832,7 +1356,7 @@ db_load(filename, in_origin, zp, def_domain)
fprintf(ddt, "update failed %s %d\n",
domain, type);
#endif
- free((char*) dp);
+ db_free(dp);
} else {
rrcount++;
}
@@ -885,8 +1409,10 @@ db_load(filename, in_origin, zp, def_domain)
zoneTypeString(zp), zp->z_origin,
errs ? "rejected due to errors" : "loaded",
(u_long)zp->z_serial);
- if (errs)
+ if (errs) {
zp->z_flags |= Z_DB_BAD;
+ zp->z_ftime = 0;
+ }
#ifdef BIND_NOTIFY
/* XXX: this needs to be delayed, both according to the spec, and
* because the metadata needed by sysnotify() (and its sysquery())
@@ -962,7 +1488,7 @@ gettoken(fp, src)
* fp - file to read from
* preserve - should we preserve \ before \\ and \.?
* return value:
- * 0 = no word; perhaps EOL or EOF
+ * 0 = no word; perhaps EOL or EOF; lineno was incremented.
* 1 = word was read
*/
int
@@ -1063,6 +1589,84 @@ getword(buf, size, fp, preserve)
return (cp != buf);
}
+/* Get multiline words. Same parameters as getword. Handles any
+ number of leading ('s or )'s in the words it sees.
+ FIXME: We kludge recognition of ( and ) for multiline input.
+ Each paren must appear at the start of a (blank-separated) word,
+ which is particularly counter-intuitive for ). Good enough for now,
+ until Paul rewrites the parser.
+*/
+static int
+getmlword(buf, size, fp, preserve)
+ char *buf;
+ int size;
+ FILE *fp;
+ int preserve;
+{
+ char *p;
+
+ do {
+ while (!getword (buf, size, fp, preserve)) {
+ /* No more words on this line. See if doing the
+ multiline thing. */
+ if (!getmlword_nesting) { /* Nope... */
+ ungetc('\n', fp); /* Push back newline */
+ lineno--; /* Unbump the lineno */
+ empty_token = 0; /* Undo this botch */
+ return 0;
+ }
+ if (feof(fp) || ferror(fp))
+ return 0; /* Error, no terminating ')' */
+ /* Continue reading til we get a word... */
+ }
+ while ('(' == *buf) {
+ /* Word starts with paren. Multiline mode.
+ Move the rest of the word down over the paren. */
+ getmlword_nesting++;
+ p = buf;
+ while (0 != (p[0]=p[1])) p++;
+ }
+ while (')' == *buf) {
+ getmlword_nesting--;
+ p = buf;
+ while (0 != (p[0]=p[1])) p++;
+ }
+ } while (buf[0] == 0); /* loop til we get a non-( non-) word */
+
+ return 1; /* Got a word... */
+}
+
+/* Get all the remaining words on a line, concatenated into one big
+ long (not too long!) string, with the whitespace squeezed out.
+ This routine, like getword(), does not swallow the newline if words seen.
+ This routine, unlike getword(), never swallows the newline if no words.
+ Parameters are the same as getword(). Result is:
+ 0 got no words at all
+ 1 got one or more words
+ -1 got too many words, they don't all fit; or missing close paren
+*/
+static int
+getallwords(buf, size, fp, preserve)
+ char *buf;
+ int size;
+ FILE *fp;
+ int preserve;
+{
+ char *runningbuf = buf;
+ int runningsize = size;
+ int len;
+
+ while (runningsize > 0) {
+ if (!getmlword (runningbuf, runningsize, fp, preserve)) {
+ return runningbuf!=buf; /* 1 or 0 */
+ }
+ len = strlen(runningbuf);
+ runningbuf += len;
+ runningsize -= len;
+ }
+ return -1; /* Error, String too long */
+}
+
/*
From: kagotani@cs.titech.ac.jp
Message-Id: <9007040716.AA26646@saeko.cs.titech.ac.jp>
@@ -1249,19 +1853,20 @@ makename(name, origin)
}
static int
-makename_ok(name, origin, class, transport, context, filename, lineno)
+makename_ok(name, origin, class, transport, context, owner, filename, lineno)
char *name;
const char *origin;
int class;
enum transport transport;
enum context context;
+ const char *owner;
const char *filename;
int lineno;
{
int ret = 1;
makename(name, origin);
- if (!ns_nameok(name, class, transport, context)) {
+ if (!ns_nameok(name, class, transport, context, owner, inaddr_any)) {
syslog(LOG_INFO, "%s:%d: database naming error\n",
filename, lineno);
ret = 0;
@@ -1297,7 +1902,7 @@ getprotocol(fp, src)
char b[MAXLEN];
(void) getword(b, sizeof(b), fp, 0);
-
+
k = protocolnumber(b);
if (k == -1)
syslog(LOG_INFO, "%s: line %d: unknown protocol: %s.",
@@ -1354,7 +1959,7 @@ getservices(n, data, fp, src)
}
else {
syslog(LOG_INFO,
- "%s: line %d: port no. (%d) too big\n",
+ "%s: line %d: port no. (%d) too big",
src, lineno, k);
dprintf(1, (ddt,
"%s: line %d: port no. (%d) too big\n",
@@ -1362,7 +1967,7 @@ getservices(n, data, fp, src)
}
}
if (bracket)
- syslog(LOG_INFO, "%s: line %d: missing close paren\n",
+ syslog(LOG_INFO, "%s: line %d: missing close paren",
src, lineno);
maxl = maxl/8+1;
bcopy(bm, data+n, maxl);
@@ -1404,7 +2009,7 @@ get_netlist(fp, netlistp, allow, print_tag)
if (!inet_aton(buf, &ntp->my_addr)) {
syslog(LOG_INFO, "%s contains bogus element (%s)",
print_tag, buf);
- continue;
+ continue;
}
if (maskp) {
if (!inet_aton(maskp, &ina)) {
@@ -1440,7 +2045,7 @@ get_netlist(fp, netlistp, allow, print_tag)
}
if (ntp)
free((char *)ntp);
-
+
dprintf(1, (ddt, "\n"));
#ifdef DEBUG
if (debug > 2)
@@ -1499,3 +2104,186 @@ free_netlist(netlistp)
}
*netlistp = NULL;
}
+
+/*
+ * Converts a word to a u_int32_t. Error if any non-numeric
+ * characters in the word, except leading or trailing white space.
+ */
+static u_int32_t
+wordtouint32(buf)
+ char *buf;
+{
+ u_long result;
+ u_int32_t res2;
+ char *bufend;
+
+ wordtouint32_error = 0;
+ result = strtoul(buf, &bufend, 0);
+ if (bufend == buf)
+ wordtouint32_error = 1;
+ else
+ while ('\0' != *bufend) {
+ if (isspace(*bufend))
+ bufend++;
+ else {
+ wordtouint32_error = 1;
+ break;
+ }
+ }
+ /* Check for truncation between u_long and u_int32_t */
+ res2 = result;
+ if (res2 != result)
+ wordtouint32_error = 1;
+ return (res2);
+}
+
+
+/*
+ * Parse part of a date. Set error flag if any error.
+ * Don't reset the flag if there is no error.
+ */
+static int
+datepart(buf, size, min, max, errp)
+ char *buf;
+ int size, min, max, *errp;
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (!isdigit(buf[i]))
+ *errp = 1;
+ result = (result * 10) + buf[i] - '0';
+ }
+ if (result < min)
+ *errp = 1;
+ if (result > max)
+ *errp = 1;
+ return (result);
+}
+
+
+/* Convert a date in ASCII into the number of seconds since
+ 1 January 1970 (GMT assumed). Format is yyyymmddhhmmss, all
+ digits required, no spaces allowed. */
+
+static u_int32_t
+datetosecs(cp, errp)
+ char *cp;
+ int *errp;
+{
+ struct tm time;
+ u_int32_t result;
+ int mdays, i;
+ static const int days_per_month[12] =
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ if (strlen(cp) != 14) {
+ *errp = 1;
+ return 0;
+ }
+ *errp = 0;
+
+ bzero((char *)&time, sizeof time);
+ time.tm_year = datepart(cp + 0, 4, 1990, 9999, errp) - 1900;
+ time.tm_mon = datepart(cp + 4, 2, 01, 12, errp) - 1;
+ time.tm_mday = datepart(cp + 6, 2, 01, 31, errp);
+ time.tm_hour = datepart(cp + 8, 2, 00, 23, errp);
+ time.tm_min = datepart(cp + 10, 2, 00, 59, errp);
+ time.tm_sec = datepart(cp + 12, 2, 00, 59, errp);
+ if (*errp) /* Any parse errors? */
+ return (0);
+
+ /*
+ * OK, now because timegm() is not available in all environments,
+ * we will do it by hand. Roll up sleeves, curse the gods, begin!
+ */
+
+#define SECS_PER_DAY ((u_int32_t)24*60*60)
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+ result = time.tm_sec; /* Seconds */
+ result += time.tm_min * 60; /* Minutes */
+ result += time.tm_hour * (60*60); /* Hours */
+ result += (time.tm_mday - 1) * SECS_PER_DAY; /* Days */
+
+ /* Months are trickier. Look without leaping, then leap */
+ mdays = 0;
+ for (i = 0; i < time.tm_mon; i++)
+ mdays += days_per_month[i];
+ result += mdays * SECS_PER_DAY; /* Months */
+ if (time.tm_mon > 1 && isleap (1900+time.tm_year))
+ result += SECS_PER_DAY; /* Add leapday for this year */
+
+ /* First figure years without leapdays, then add them in. */
+ /* The loop is slow, FIXME, but simple and accurate. */
+ result += (time.tm_year - 70) * (SECS_PER_DAY*365); /* Years */
+ for (i = 70; i < time.tm_year; i++)
+ if (isleap (1900+i))
+ result += SECS_PER_DAY; /* Add leapday for prev year */
+
+ return (result);
+}
+
+
+#define MAXCHARSTRING 255
+
+static int
+getcharstring(buf, data, type, minfields, maxfields, fp, src)
+ char *buf;
+ char *data;
+ int type;
+ int minfields;
+ int maxfields;
+ FILE *fp;
+ const char *src;
+{
+ int nfield = 0, done = 0, n = 0, i;
+ char *b = buf;
+
+ do {
+ nfield++;
+ i = strlen(buf);
+#ifdef ALLOW_LONG_TXT_RDATA
+ b = buf;
+ if (type == T_TXT || type == T_X25) {
+ while (i > MAXCHARSTRING
+ && n + MAXCHARSTRING + 1 < MAXDATA) {
+ data[n] = MAXCHARSTRING;
+ bcopy(b, data + n + 1, MAXCHARSTRING);
+ n += MAXCHARSTRING + 1;
+ b += MAXCHARSTRING;
+ i -= MAXCHARSTRING;
+ }
+ }
+#endif /* ALLOW_LONG_TXT_RDATA */
+ if (i > MAXCHARSTRING) {
+ syslog(LOG_INFO,
+ "%s: line %d: RDATA field %d too long",
+ src, lineno, nfield);
+ return (0);
+ }
+ if (n + i + 1 > MAXDATA) {
+ syslog(LOG_INFO,
+ "%s: line %d: total RDATA too long",
+ src, lineno);
+ return (0);
+ }
+ data[n] = i;
+ bcopy(b, data + n + 1, (int)i);
+ n += i + 1;
+ done = (maxfields && nfield >= maxfields);
+ } while (!done && getword(buf, MAXDATA, fp, 0));
+
+ if (nfield < minfields) {
+ syslog(LOG_INFO,
+ "%s: line %d: expected %d RDATA fields, only saw %d",
+ src, lineno, minfields, nfield);
+ return (0);
+ }
+
+ if (done)
+ endline(fp);
+
+ return (n);
+}
OpenPOWER on IntegriCloud