diff options
Diffstat (limited to 'contrib/bind/lib/nameser')
-rw-r--r-- | contrib/bind/lib/nameser/Makefile | 33 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_date.c | 128 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_name.c | 65 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_netint.c | 10 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_parse.c | 122 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_print.c | 93 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_samedomain.c | 206 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_sign.c | 348 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_ttl.c | 6 | ||||
-rw-r--r-- | contrib/bind/lib/nameser/ns_verify.c | 471 |
10 files changed, 1382 insertions, 100 deletions
diff --git a/contrib/bind/lib/nameser/Makefile b/contrib/bind/lib/nameser/Makefile index d86dc74..52a102f 100644 --- a/contrib/bind/lib/nameser/Makefile +++ b/contrib/bind/lib/nameser/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 1996 by Internet Software Consortium +# Copyright (c) 1996,1999 by Internet Software Consortium # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,7 @@ # SOFTWARE. # -# $Id: Makefile,v 8.7 1997/05/21 19:32:08 halley Exp $ +# $Id: Makefile,v 8.16 1999/09/07 08:47:28 vixie Exp $ # these are only appropriate for BSD 4.4 or derivatives, and are used in # development. normal builds will be done in the top level directory and @@ -33,31 +33,48 @@ TOP= ../.. INCL = ${TOP}/include PORTINCL = ${TOP}/port/${SYSTYPE}/include LIBBIND = ${TOP}/lib/libbind.${A} +LIBBINDR = ../${TOP}/lib/libbind_r.${A} CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL} LD_LIBFLAGS= -x -r -AR= ar cruv +AR= ar cru RANLIB= ranlib INSTALL= install +INSTALL_EXEC= +INSTALL_LIB=-o bin -g bin +THREADED= threaded -SRCS= ns_parse.c ns_print.c ns_netint.c ns_ttl.c ns_name.c +SRCS= ns_parse.c ns_print.c ns_netint.c ns_ttl.c ns_name.c \ + ns_sign.c ns_verify.c ns_date.c ns_samedomain.c -OBJS= ns_parse.${O} ns_print.${O} ns_netint.${O} ns_ttl.${O} ns_name.${O} +OBJS= ns_parse.${O} ns_print.${O} ns_netint.${O} ns_ttl.${O} ns_name.${O} \ + ns_sign.${O} ns_verify.${O} ns_date.${O} ns_samedomain.${O} -all: ${LIBBIND} +all: ${LIBBIND} ${LIBBIND}: ${OBJS} + ( cd ${THREADED} ; \ + ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \ + ${RANLIB} ${LIBBINDR} ) ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF} ${RANLIB} ${LIBBIND} .c.${O}: - ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c - -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} && ${LDS} mv a.out $*.${O} + if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} -c $*.c \ + -o ${THREADED}/$*.${O} + -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \ + ${LDS} mv a.out ${THREADED}/$*.${O} + ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c + -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \ + ${LDS} mv a.out $*.${O} distclean: clean clean: FRC rm -f .depend a.out core ${LIB} tags rm -f *.${O} *.BAK *.CKP *~ + rm -f ${THREADED}/*.${O} + -rmdir ${THREADED} depend: FRC mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS} diff --git a/contrib/bind/lib/nameser/ns_date.c b/contrib/bind/lib/nameser/ns_date.c new file mode 100644 index 0000000..da593a5 --- /dev/null +++ b/contrib/bind/lib/nameser/ns_date.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * 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. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_date.c,v 1.2 1999/10/13 16:39:35 vixie Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" + +#include <arpa/nameser.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "port_after.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* Forward. */ + +static int datepart(const char *, int, int, int, int *); + +/* Public. */ + +/* 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. */ + +u_int32_t +ns_datetosecs(const 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; + + memset(&time, 0, 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); +} + +/* Private. */ + +/* + * Parse part of a date. Set error flag if any error. + * Don't reset the flag if there is no error. + */ +static int +datepart(const char *buf, int size, int min, int max, int *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); +} diff --git a/contrib/bind/lib/nameser/ns_name.c b/contrib/bind/lib/nameser/ns_name.c index 86c0bbb..6bd668d 100644 --- a/contrib/bind/lib/nameser/ns_name.c +++ b/contrib/bind/lib/nameser/ns_name.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * Copyright (c) 1996,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,7 +16,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_name.c,v 8.3 1997/04/24 22:10:54 vixie Exp $"; +static const char rcsid[] = "$Id: ns_name.c,v 8.12 1999/10/13 17:11:23 vixie Exp $"; #endif #include "port_before.h" @@ -29,12 +29,13 @@ static char rcsid[] = "$Id: ns_name.c,v 8.3 1997/04/24 22:10:54 vixie Exp $"; #include <errno.h> #include <resolv.h> #include <string.h> +#include <ctype.h> #include "port_after.h" /* Data. */ -static char digits[] = "0123456789"; +static const char digits[] = "0123456789"; /* Forward. */ @@ -199,7 +200,7 @@ ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { } return (1); } - if (c == 0) { + if (c == 0 || *src == '.') { errno = EMSGSIZE; return (-1); } @@ -237,6 +238,49 @@ ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { } /* + * ns_name_ntol(src, dst, dstsiz) + * Convert a network strings labels into all lowercase. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) { + const u_char *cp; + u_char *dn, *eom; + u_char c; + u_int n; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) != 0) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + *dn++ = n; + if (dn + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + for ((void)NULL; n > 0; n--) { + c = *cp++; + if (isupper(c)) + *dn++ = tolower(c); + else + *dn++ = c; + } + } + *dn++ = '\0'; + return (dn - dst); +} + +/* * ns_name_unpack(msg, eom, src, dst, dstsiz) * Unpack a domain name from a message, source may be compressed. * return: @@ -248,7 +292,7 @@ ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, { const u_char *srcp, *dstlim; u_char *dstp; - int n, c, len, checked; + int n, len, checked; len = -1; checked = 0; @@ -366,6 +410,7 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz, srcp += n + 1; } while (n != 0); + /* from here on we need to reset compression pointer array on error */ srcp = src; do { /* Look to see if we can use pointers. */ @@ -375,8 +420,7 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz, (const u_char * const *)lpp); if (l >= 0) { if (dstp + 1 >= eob) { - errno = EMSGSIZE; - return (-1); + goto cleanup; } *dstp++ = (l >> 8) | NS_CMPRSFLGS; *dstp++ = l % 256; @@ -391,12 +435,10 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz, } /* copy label to buffer */ if (n & NS_CMPRSFLGS) { /* Should not happen. */ - errno = EMSGSIZE; - return (-1); + goto cleanup; } if (dstp + 1 + n >= eob) { - errno = EMSGSIZE; - return (-1); + goto cleanup; } memcpy(dstp, srcp, n + 1); srcp += n + 1; @@ -404,6 +446,7 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz, } while (n != 0); if (dstp > eob) { +cleanup: if (msg != NULL) *lpp = NULL; errno = EMSGSIZE; diff --git a/contrib/bind/lib/nameser/ns_netint.c b/contrib/bind/lib/nameser/ns_netint.c index 1f640a5..030a2d0 100644 --- a/contrib/bind/lib/nameser/ns_netint.c +++ b/contrib/bind/lib/nameser/ns_netint.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * Copyright (c) 1996,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,21 +16,19 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_netint.c,v 8.1 1996/11/18 09:09:57 vixie Exp $"; +static const char rcsid[] = "$Id: ns_netint.c,v 8.4 1999/10/13 16:39:35 vixie Exp $"; #endif /* Import. */ #include "port_before.h" -/*#include <sys/types.h>*/ -/*#include <sys/socket.h>*/ - -/*#include <netinet/in.h>*/ #include <arpa/nameser.h> #include "port_after.h" +/* Public. */ + u_int ns_get16(const u_char *src) { u_int dst; diff --git a/contrib/bind/lib/nameser/ns_parse.c b/contrib/bind/lib/nameser/ns_parse.c index 800ea19..35f7f40 100644 --- a/contrib/bind/lib/nameser/ns_parse.c +++ b/contrib/bind/lib/nameser/ns_parse.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * Copyright (c) 1996,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,9 +16,11 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_parse.c,v 8.8 1998/02/17 17:20:33 vixie Exp $"; +static const char rcsid[] = "$Id: ns_parse.c,v 8.13 1999/10/13 16:39:35 vixie Exp $"; #endif +/* Import. */ + #include "port_before.h" #include <sys/types.h> @@ -32,6 +34,16 @@ static char rcsid[] = "$Id: ns_parse.c,v 8.8 1998/02/17 17:20:33 vixie Exp $"; #include "port_after.h" +/* Forward. */ + +static void setsection(ns_msg *msg, ns_sect sect); + +/* Macros. */ + +#define RETERR(err) do { errno = (err); return (-1); } while (0) + +/* Public. */ + /* These need to be in the same order as the nres.h:ns_flag enum. */ struct _ns_flagdata _ns_flagdata[16] = { { 0x8000, 15 }, /* qr. */ @@ -52,8 +64,8 @@ struct _ns_flagdata _ns_flagdata[16] = { { 0x0000, 0 }, /* expansion (6/6). */ }; -static int -skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { +int +ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { const u_char *optr = ptr; for ((void)NULL; count > 0; count--) { @@ -61,24 +73,19 @@ skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { b = dn_skipname(ptr, eom); if (b < 0) - goto emsgsize; + RETERR(EMSGSIZE); ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; if (section != ns_s_qd) { - if (ptr + NS_INT32SZ > eom) - goto emsgsize; + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) + RETERR(EMSGSIZE); ptr += NS_INT32SZ/*TTL*/; - if (ptr + NS_INT16SZ > eom) - goto emsgsize; NS_GET16(rdlength, ptr); ptr += rdlength/*RData*/; } } if (ptr > eom) - goto emsgsize; + RETERR(EMSGSIZE); return (ptr - optr); - emsgsize: - errno = EMSGSIZE; - return (-1); } int @@ -90,22 +97,22 @@ ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { handle->_msg = msg; handle->_eom = eom; if (msg + NS_INT16SZ > eom) - goto emsgsize; + RETERR(EMSGSIZE); NS_GET16(handle->_id, msg); if (msg + NS_INT16SZ > eom) - goto emsgsize; + RETERR(EMSGSIZE); NS_GET16(handle->_flags, msg); for (i = 0; i < ns_s_max; i++) { if (msg + NS_INT16SZ > eom) - goto emsgsize; + RETERR(EMSGSIZE); NS_GET16(handle->_counts[i], msg); } for (i = 0; i < ns_s_max; i++) if (handle->_counts[i] == 0) handle->_sections[i] = NULL; else { - int b = skiprr(msg, eom, (ns_sect)i, - handle->_counts[i]); + int b = ns_skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); if (b < 0) return (-1); @@ -113,14 +120,9 @@ ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { msg += b; } if (msg != eom) - goto emsgsize; - handle->_sect = ns_s_max; - handle->_rrnum = -1; - handle->_ptr = NULL; + RETERR(EMSGSIZE); + setsection(handle, ns_s_max); return (0); - emsgsize: - errno = EMSGSIZE; - return (-1); } int @@ -129,29 +131,26 @@ ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { /* Make section right. */ if (section < 0 || section >= ns_s_max) - goto enodev; - if ((int)section != (int)handle->_sect) { - handle->_sect = section; - handle->_rrnum = 0; - handle->_ptr = handle->_sections[(int)section]; - } + RETERR(ENODEV); + if (section != handle->_sect) + setsection(handle, section); /* Make rrnum right. */ if (rrnum == -1) rrnum = handle->_rrnum; if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) - goto enodev; - if (rrnum < handle->_rrnum) { - handle->_rrnum = 0; - handle->_ptr = handle->_sections[(int)section]; + RETERR(ENODEV); + if (rrnum < handle->_rrnum) + setsection(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr(handle->_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_ptr += b; + handle->_rrnum = rrnum; } - - b = skiprr(handle->_msg, handle->_eom, section, - rrnum - handle->_rrnum); - if (b < 0) - return (-1); - handle->_ptr += b; - handle->_rrnum = rrnum; /* Do the parse. */ b = dn_expand(handle->_msg, handle->_eom, @@ -159,36 +158,41 @@ ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { if (b < 0) return (-1); handle->_ptr += b; - if (handle->_ptr + NS_INT16SZ > handle->_eom) - goto emsgsize; + if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); NS_GET16(rr->type, handle->_ptr); - if (handle->_ptr + NS_INT16SZ > handle->_eom) - goto emsgsize; - NS_GET16(rr->class, handle->_ptr); + NS_GET16(rr->rr_class, handle->_ptr); if (section == ns_s_qd) { rr->ttl = 0; rr->rdlength = 0; rr->rdata = NULL; } else { - if (handle->_ptr + NS_INT32SZ > handle->_eom) - goto emsgsize; + if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); NS_GET32(rr->ttl, handle->_ptr); - if (handle->_ptr + NS_INT16SZ > handle->_eom) - goto emsgsize; NS_GET16(rr->rdlength, handle->_ptr); if (handle->_ptr + rr->rdlength > handle->_eom) - goto emsgsize; + RETERR(EMSGSIZE); rr->rdata = handle->_ptr; handle->_ptr += rr->rdlength; } - handle->_rrnum++; + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); /* All done. */ return (0); - enodev: - errno = ENODEV; - return (-1); - emsgsize: - errno = EMSGSIZE; - return (-1); +} + +/* Private. */ + +static void +setsection(ns_msg *msg, ns_sect sect) { + msg->_sect = sect; + if (sect == ns_s_max) { + msg->_rrnum = -1; + msg->_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_ptr = msg->_sections[(int)sect]; + } } diff --git a/contrib/bind/lib/nameser/ns_print.c b/contrib/bind/lib/nameser/ns_print.c index 8ab4766..93f1e91 100644 --- a/contrib/bind/lib/nameser/ns_print.c +++ b/contrib/bind/lib/nameser/ns_print.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998 by Internet Software Consortium. + * Copyright (c) 1996-1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,7 +16,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_print.c,v 8.4 1998/02/13 01:16:37 halley Exp $"; +static const char rcsid[] = "$Id: ns_print.c,v 8.17 1999/10/19 02:06:54 gson Exp $"; #endif /* Import. */ @@ -30,7 +30,7 @@ static char rcsid[] = "$Id: ns_print.c,v 8.4 1998/02/13 01:16:37 halley Exp $"; #include <arpa/nameser.h> #include <arpa/inet.h> -#include <assert.h> +#include <isc/assertions.h> #include <errno.h> #include <resolv.h> #include <string.h> @@ -58,6 +58,10 @@ static int addstr(const char *src, size_t len, static int addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen); +/* Proto. */ + +u_int16_t dst_s_dns_key_id(const u_char *, const int); + /* Macros. */ #define T(x) \ @@ -115,7 +119,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen, /* * Owner. */ - if (name_ctx != NULL && strcasecmp(name_ctx, name) == 0) { + if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) { T(addstr("\t\t\t", 3, &buf, &buflen)); } else { len = prune_origin(name, origin); @@ -171,7 +175,11 @@ ns_sprintrrf(const u_char *msg, size_t msglen, rdata += len; T(addstr(" ", 1, &buf, &buflen)); - /* Second word. */ + + /* Second word, optional in ISDN records. */ + if (type == ns_t_isdn && rdata == edata) + break; + T(len = charstr(rdata, edata, &buf, &buflen)); if (len == 0) goto formerr; @@ -439,7 +447,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen, case ns_t_key: { char base64_key[NS_MD5RSA_MAX_BASE64]; - u_int keyflags, protocol, algorithm; + u_int keyflags, protocol, algorithm, key_id; const char *leader; int n; @@ -447,6 +455,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen, goto formerr; /* Key flags, Protocol, Algorithm. */ + key_id = dst_s_dns_key_id(rdata, edata-rdata); keyflags = ns_get16(rdata); rdata += NS_INT16SZ; protocol = *rdata++; algorithm = *rdata++; @@ -472,6 +481,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen, } if (len > 15) T(addstr(" )", 2, &buf, &buflen)); + n = SPRINTF((tmp, " ; key_tag= %u", key_id)); + T(addstr(tmp, n, &buf, &buflen)); break; } @@ -491,10 +502,10 @@ ns_sprintrrf(const u_char *msg, size_t msglen, algorithm = *rdata++; labels = *rdata++; t = ns_get32(rdata); rdata += NS_INT32SZ; - len = SPRINTF((tmp, " %s %d %lu ", - p_type(type), algorithm, t)); + len = SPRINTF((tmp, "%s %d %d %lu ", + p_type(type), algorithm, labels, t)); T(addstr(tmp, len, &buf, &buflen)); - if (labels != (u_int)dn_count_labels(name)) + if (labels > (u_int)dn_count_labels(name)) goto formerr; /* Signature expiry. */ @@ -533,7 +544,6 @@ ns_sprintrrf(const u_char *msg, size_t msglen, } if (len > 15) T(addstr(" )", 2, &buf, &buflen)); - break; } @@ -553,6 +563,63 @@ ns_sprintrrf(const u_char *msg, size_t msglen, break; } + case ns_t_cert: { + u_int c_type, key_tag, alg; + int n, siz; + char base64_cert[8192], *leader, tmp[40]; + + c_type = ns_get16(rdata); rdata += NS_INT16SZ; + key_tag = ns_get16(rdata); rdata += NS_INT16SZ; + alg = (u_int) *rdata++; + + len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg)); + T(addstr(tmp, len, &buf, &buflen)); + siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */ + if (siz > sizeof(base64_cert) * 3/4) { + char *str = "record too long to print"; + T(addstr(str, strlen(str), &buf, &buflen)); + } + else { + len = b64_ntop(rdata, edata-rdata, base64_cert, siz); + + if (len < 0) + goto formerr; + else if (len > 15) { + T(addstr(" (", 2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } + else + leader = " "; + + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), + &buf, &buflen)); + T(addstr(base64_cert + n, MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", 2, &buf, &buflen)); + } + break; + } + + case ns_t_tsig: { + /* BEW - need to complete this */ + int n; + + T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", 1, &buf, &buflen)); + rdata += 8; /* time */ + n = ns_get16(rdata); rdata += INT16SZ; + rdata += n; /* sig */ + n = ns_get16(rdata); rdata += INT16SZ; /* original id */ + sprintf(buf, "%d", ns_get16(rdata)); + rdata += INT16SZ; + addlen(strlen(buf), &buf, &buflen); + break; + } + default: comment = "unknown RR type"; goto hexify; @@ -608,7 +675,7 @@ prune_origin(const char *name, const char *origin) { const char *oname = name; while (*name != '\0') { - if (origin != NULL && strcasecmp(name, origin) == 0) + if (origin != NULL && ns_samename(name, origin) == 1) return (name - oname - (name > oname)); while (*name != '\0') { if (*name == '\\') { @@ -712,14 +779,14 @@ addname(const u_char *msg, size_t msglen, static void addlen(size_t len, char **buf, size_t *buflen) { - assert(len <= *buflen); + INSIST(len <= *buflen); *buf += len; *buflen -= len; } static int addstr(const char *src, size_t len, char **buf, size_t *buflen) { - if (len > *buflen) { + if (len >= *buflen) { errno = ENOSPC; return (-1); } diff --git a/contrib/bind/lib/nameser/ns_samedomain.c b/contrib/bind/lib/nameser/ns_samedomain.c new file mode 100644 index 0000000..c847924 --- /dev/null +++ b/contrib/bind/lib/nameser/ns_samedomain.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1995,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * 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. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_samedomain.c,v 8.9 1999/10/15 21:06:51 vixie Exp $"; +#endif + +#include "port_before.h" + +#include <sys/types.h> +#include <arpa/nameser.h> +#include <errno.h> +#include <string.h> + +#include "port_after.h" + +/* + * int + * ns_samedomain(a, b) + * Check whether a name belongs to a domain. + * Inputs: + * a - the domain whose ancestory is being verified + * b - the potential ancestor we're checking against + * Return: + * boolean - is a at or below b? + * Notes: + * Trailing dots are first removed from name and domain. + * Always compare complete subdomains, not only whether the + * domain name is the trailing string of the given name. + * + * "host.foobar.top" lies in "foobar.top" and in "top" and in "" + * but NOT in "bar.top" + */ + +int +ns_samedomain(const char *a, const char *b) { + size_t la, lb; + int diff, i, escaped; + const char *cp; + + la = strlen(a); + lb = strlen(b); + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ + if (la != 0 && a[la - 1] == '.') { + escaped = 0; + /* Note this loop doesn't get executed if la==1. */ + for (i = la - 2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + la--; + } + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ + if (lb != 0 && b[lb - 1] == '.') { + escaped = 0; + /* note this loop doesn't get executed if lb==1 */ + for (i = lb - 2; i >= 0; i--) + if (b[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + lb--; + } + + /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ + if (lb == 0) + return (1); + + /* 'b' longer than 'a' means 'a' can't be in 'b'. */ + if (lb > la) + return (0); + + /* 'a' and 'b' being equal at this point indicates sameness. */ + if (lb == la) + return (strncasecmp(a, b, lb) == 0); + + /* Ok, we know la > lb. */ + + diff = la - lb; + + /* + * If 'a' is only 1 character longer than 'b', then it can't be + * a subdomain of 'b' (because of the need for the '.' label + * separator). + */ + if (diff < 2) + return (0); + + /* + * If the character before the last 'lb' characters of 'b' + * isn't '.', then it can't be a match (this lets us avoid + * having "foobar.com" match "bar.com"). + */ + if (a[diff - 1] != '.') + return (0); + + /* + * We're not sure about that '.', however. It could be escaped + * and thus not a really a label separator. + */ + escaped = 0; + for (i = diff - 2; i >= 0; i--) + if (a[i] == '\\') + if (escaped) + escaped = 0; + else + escaped = 1; + else + break; + if (escaped) + return (0); + + /* Now compare aligned trailing substring. */ + cp = a + diff; + return (strncasecmp(cp, b, lb) == 0); +} + +/* + * int + * ns_subdomain(a, b) + * is "a" a subdomain of "b"? + */ +int +ns_subdomain(const char *a, const char *b) { + return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); +} + +/* + * int + * ns_makecanon(src, dst, dstsize) + * make a canonical copy of domain name "src" + * notes: + * foo -> foo. + * foo. -> foo. + * foo.. -> foo. + * foo\. -> foo\.. + * foo\\. -> foo\\. + */ + +int +ns_makecanon(const char *src, char *dst, size_t dstsize) { + size_t n = strlen(src); + + if (n + sizeof "." > dstsize) { + errno = EMSGSIZE; + return (-1); + } + strcpy(dst, src); + while (n > 0 && dst[n - 1] == '.') /* Ends in "." */ + if (n > 1 && dst[n - 2] == '\\' && /* Ends in "\." */ + (n < 2 || dst[n - 3] != '\\')) /* But not "\\." */ + break; + else + dst[--n] = '\0'; + dst[n++] = '.'; + dst[n] = '\0'; + return (0); +} + +/* + * int + * ns_samename(a, b) + * determine whether domain name "a" is the same as domain name "b" + * return: + * -1 on error + * 0 if names differ + * 1 if names are the same + */ + +int +ns_samename(const char *a, const char *b) { + char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; + + if (ns_makecanon(a, ta, sizeof ta) < 0 || + ns_makecanon(b, tb, sizeof tb) < 0) + return (-1); + if (strcasecmp(ta, tb) == 0) + return (1); + else + return (0); +} diff --git a/contrib/bind/lib/nameser/ns_sign.c b/contrib/bind/lib/nameser/ns_sign.c new file mode 100644 index 0000000..75af894 --- /dev/null +++ b/contrib/bind/lib/nameser/ns_sign.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 1999 by Internet Software Consortium, 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. + * + * 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. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_sign.c,v 8.8 1999/10/13 16:39:36 vixie Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" +#include "fd_setsize.h" + +#include <sys/types.h> +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <isc/dst.h> + +#include "port_after.h" + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if ((ptr) + (count) > eob) { \ + errno = EMSGSIZE; \ + return(NS_TSIG_ERROR_NO_SPACE); \ + } \ + } while (0) + +/* ns_sign + * Parameters: + * msg message to be sent + * msglen input - length of message + * output - length of signed message + * msgsize length of buffer containing message + * error value to put in the error field + * key tsig key used for signing + * querysig (response), the signature in the query + * querysiglen (response), the length of the signature in the query + * sig a buffer to hold the generated signature + * siglen input - length of signature buffer + * output - length of signature + * + * Errors: + * - bad input data (-1) + * - bad key / sign failed (-BADKEY) + * - not enough space (NS_TSIG_ERROR_NO_SPACE) + */ +int +ns_sign(u_char *msg, int *msglen, int msgsize, int error, void *k, + const u_char *querysig, int querysiglen, u_char *sig, int *siglen, + time_t in_timesigned) +{ + HEADER *hp = (HEADER *)msg; + DST_KEY *key = (DST_KEY *)k; + u_char *cp = msg + *msglen, *eob = msg + msgsize; + u_char *lenp; + u_char *name, *alg; + int n; + time_t timesigned; + + dst_init(); + if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL) + return (-1); + + /* Name. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) + n = dn_comp(key->dk_key_name, cp, eob - cp, NULL, NULL); + else + n = dn_comp("", cp, eob - cp, NULL, NULL); + if (n < 0) + return (NS_TSIG_ERROR_NO_SPACE); + name = cp; + cp += n; + + /* Type, class, ttl, length (not filled in yet). */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(ns_t_tsig, cp); + PUTSHORT(ns_c_any, cp); + PUTLONG(0, cp); /* TTL */ + lenp = cp; + cp += 2; + + /* Alg. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + if (key->dk_alg != KEY_HMAC_MD5) + return (-ns_r_badkey); + n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL); + } + else + n = dn_comp("", cp, eob - cp, NULL, NULL); + if (n < 0) + return (NS_TSIG_ERROR_NO_SPACE); + alg = cp; + cp += n; + + /* Time. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(0, cp); + timesigned = time(NULL); + if (error != ns_r_badtime) + PUTLONG(timesigned, cp); + else + PUTLONG(in_timesigned, cp); + PUTSHORT(NS_TSIG_FUDGE, cp); + + /* Compute the signature. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + void *ctx; + u_char buf[MAXDNAME], *cp2; + int n; + + dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); + + /* Digest the query signature, if this is a response. */ + if (querysiglen > 0 && querysig != NULL) { + u_int16_t len_n = htons(querysiglen); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, + (u_char *)&len_n, INT16SZ, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, + querysig, querysiglen, NULL, 0); + } + + /* Digest the message. */ + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen, + NULL, 0); + + /* Digest the key name. */ + n = ns_name_ntol(name, buf, sizeof(buf)); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the class and TTL. */ + cp2 = buf; + PUTSHORT(ns_c_any, cp2); + PUTLONG(0, cp2); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf, + NULL, 0); + + /* Digest the algorithm. */ + n = ns_name_ntol(alg, buf, sizeof(buf)); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the time signed, fudge, error, and other data */ + cp2 = buf; + PUTSHORT(0, cp2); /* Top 16 bits of time */ + if (error != ns_r_badtime) + PUTLONG(timesigned, cp2); + else + PUTLONG(in_timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + PUTSHORT(error, cp2); /* Error */ + if (error != ns_r_badtime) + PUTSHORT(0, cp2); /* Other data length */ + else { + PUTSHORT(INT16SZ+INT32SZ, cp2); /* Other data length */ + PUTSHORT(0, cp2); /* Top 16 bits of time */ + PUTLONG(timesigned, cp2); + } + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf, + NULL, 0); + + n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, + sig, *siglen); + if (n < 0) + return (-ns_r_badkey); + *siglen = n; + } else + *siglen = 0; + + /* Add the signature. */ + BOUNDS_CHECK(cp, INT16SZ + (*siglen)); + PUTSHORT(*siglen, cp); + memcpy(cp, sig, *siglen); + cp += (*siglen); + + /* The original message ID & error. */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ); + PUTSHORT(ntohs(hp->id), cp); /* already in network order */ + PUTSHORT(error, cp); + + /* Other data. */ + BOUNDS_CHECK(cp, INT16SZ); + if (error != ns_r_badtime) + PUTSHORT(0, cp); /* Other data length */ + else { + PUTSHORT(INT16SZ+INT32SZ, cp); /* Other data length */ + BOUNDS_CHECK(cp, INT32SZ+INT16SZ); + PUTSHORT(0, cp); /* Top 16 bits of time */ + PUTLONG(timesigned, cp); + } + + /* Go back and fill in the length. */ + PUTSHORT(cp - lenp - INT16SZ, lenp); + + hp->arcount = htons(ntohs(hp->arcount) + 1); + *msglen = (cp - msg); + return (0); +} + +int +ns_sign_tcp_init(void *k, const u_char *querysig, int querysiglen, + ns_tcp_tsig_state *state) +{ + dst_init(); + if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) + return (-1); + state->counter = -1; + state->key = k; + if (state->key->dk_alg != KEY_HMAC_MD5) + return (-ns_r_badkey); + if (querysiglen > sizeof(state->sig)) + return (-1); + memcpy(state->sig, querysig, querysiglen); + state->siglen = querysiglen; + return (0); +} + +int +ns_sign_tcp(u_char *msg, int *msglen, int msgsize, int error, + ns_tcp_tsig_state *state, int done) +{ + u_char *cp, *eob, *lenp; + u_char buf[MAXDNAME], *cp2; + HEADER *hp = (HEADER *)msg; + time_t timesigned; + int n; + + if (msg == NULL || msglen == NULL || state == NULL) + return (-1); + + state->counter++; + if (state->counter == 0) + return (ns_sign(msg, msglen, msgsize, error, state->key, + state->sig, state->siglen, + state->sig, &state->siglen, 0)); + + if (state->siglen > 0) { + u_int16_t siglen_n = htons(state->siglen); + dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx, + NULL, 0, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + (u_char *)&siglen_n, INT16SZ, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + state->sig, state->siglen, NULL, 0); + state->siglen = 0; + } + + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen, + NULL, 0); + + if (done == 0 && (state->counter % 100 != 0)) + return (0); + + cp = msg + *msglen; + eob = msg + msgsize; + + /* Name. */ + n = dn_comp(state->key->dk_key_name, cp, eob - cp, NULL, NULL); + if (n < 0) + return (NS_TSIG_ERROR_NO_SPACE); + cp += n; + + /* Type, class, ttl, length (not filled in yet). */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(ns_t_tsig, cp); + PUTSHORT(ns_c_any, cp); + PUTLONG(0, cp); /* TTL */ + lenp = cp; + cp += 2; + + /* Alg. */ + n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL); + if (n < 0) + return (NS_TSIG_ERROR_NO_SPACE); + cp += n; + + /* Time. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(0, cp); + timesigned = time(NULL); + PUTLONG(timesigned, cp); + PUTSHORT(NS_TSIG_FUDGE, cp); + + /* + * Compute the signature. + */ + + /* Digest the time signed and fudge. */ + cp2 = buf; + PUTSHORT(0, cp2); /* Top 16 bits of time */ + PUTLONG(timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + buf, cp2 - buf, NULL, 0); + + n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, + state->sig, sizeof(state->sig)); + if (n < 0) + return (-ns_r_badkey); + state->siglen = n; + + /* Add the signature. */ + BOUNDS_CHECK(cp, INT16SZ + state->siglen); + PUTSHORT(state->siglen, cp); + memcpy(cp, state->sig, state->siglen); + cp += state->siglen; + + /* The original message ID & error. */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ); + PUTSHORT(ntohs(hp->id), cp); /* already in network order */ + PUTSHORT(error, cp); + + /* Other data. */ + BOUNDS_CHECK(cp, INT16SZ); + PUTSHORT(0, cp); + + /* Go back and fill in the length. */ + PUTSHORT(cp - lenp - INT16SZ, lenp); + + hp->arcount = htons(ntohs(hp->arcount) + 1); + *msglen = (cp - msg); + return (0); +} diff --git a/contrib/bind/lib/nameser/ns_ttl.c b/contrib/bind/lib/nameser/ns_ttl.c index a71d3c7..67cd976 100644 --- a/contrib/bind/lib/nameser/ns_ttl.c +++ b/contrib/bind/lib/nameser/ns_ttl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 by Internet Software Consortium. + * Copyright (c) 1996,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,7 +16,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: ns_ttl.c,v 8.5 1998/02/13 01:16:38 halley Exp $"; +static const char rcsid[] = "$Id: ns_ttl.c,v 8.8 1999/10/13 16:39:36 vixie Exp $"; #endif /* Import. */ @@ -52,7 +52,7 @@ int ns_format_ttl(u_long src, char *dst, size_t dstlen) { char *odst = dst; int secs, mins, hours, days, weeks, x; - char tmp[50], *p; + char *p; secs = src % 60; src /= 60; mins = src % 60; src /= 60; diff --git a/contrib/bind/lib/nameser/ns_verify.c b/contrib/bind/lib/nameser/ns_verify.c new file mode 100644 index 0000000..316da13 --- /dev/null +++ b/contrib/bind/lib/nameser/ns_verify.c @@ -0,0 +1,471 @@ +/* + * Copyright (c) 1999 by Internet Software Consortium, 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. + * + * 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. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_verify.c,v 8.11 1999/10/15 21:06:51 vixie Exp $"; +#endif + +/* Import. */ + +#include "port_before.h" +#include "fd_setsize.h" + +#include <sys/types.h> +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <isc/dst.h> + +#include "port_after.h" + +/* Private. */ + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if ((ptr) + (count) > eom) { \ + return (NS_TSIG_ERROR_FORMERR); \ + } \ + } while (0) + +/* Public. */ + +u_char * +ns_find_tsig(u_char *msg, u_char *eom) { + HEADER *hp = (HEADER *)msg; + int n, type; + u_char *cp = msg, *start; + + if (msg == NULL || eom == NULL || msg > eom) + return (NULL); + + if (cp + HFIXEDSZ >= eom) + return (NULL); + + if (hp->arcount == 0) + return (NULL); + + cp += HFIXEDSZ; + + n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1); + if (n < 0) + return (NULL); + cp += n; + + start = cp; + n = dn_skipname(cp, eom); + if (n < 0) + return (NULL); + cp += n; + if (cp + INT16SZ >= eom) + return (NULL); + + GETSHORT(type, cp); + if (type != ns_t_tsig) + return (NULL); + return (start); +} + +/* ns_verify + * Parameters: + * statp res stuff + * msg received message + * msglen length of message + * key tsig key used for verifying. + * querysig (response), the signature in the query + * querysiglen (response), the length of the signature in the query + * sig (query), a buffer to hold the signature + * siglen (query), input - length of signature buffer + * output - length of signature + * + * Errors: + * - bad input (-1) + * - invalid dns message (NS_TSIG_ERROR_FORMERR) + * - TSIG is not present (NS_TSIG_ERROR_NO_TSIG) + * - key doesn't match (-ns_r_badkey) + * - TSIG verification fails with BADKEY (-ns_r_badkey) + * - TSIG verification fails with BADSIG (-ns_r_badsig) + * - TSIG verification fails with BADTIME (-ns_r_badtime) + * - TSIG verification succeeds, error set to BAKEY (ns_r_badkey) + * - TSIG verification succeeds, error set to BADSIG (ns_r_badsig) + * - TSIG verification succeeds, error set to BADTIME (ns_r_badtime) + */ +int +ns_verify(u_char *msg, int *msglen, void *k, + const u_char *querysig, int querysiglen, u_char *sig, int *siglen, + time_t *timesigned, int nostrip) +{ + HEADER *hp = (HEADER *)msg; + DST_KEY *key = (DST_KEY *)k; + u_char *cp = msg, *eom; + char name[MAXDNAME], alg[MAXDNAME]; + u_char *recstart, *rdatastart; + u_char *sigstart, *otherstart; + int n; + int error; + u_int16_t type, length; + u_int16_t fudge, sigfieldlen, id, otherfieldlen; + + dst_init(); + if (msg == NULL || msglen == NULL || *msglen < 0) + return (-1); + + eom = msg + *msglen; + + recstart = ns_find_tsig(msg, eom); + if (recstart == NULL) + return (NS_TSIG_ERROR_NO_TSIG); + + cp = recstart; + + /* Read the key name. */ + n = dn_expand(msg, eom, cp, name, MAXDNAME); + if (n < 0) + return (NS_TSIG_ERROR_FORMERR); + cp += n; + + /* Read the type. */ + BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); + GETSHORT(type, cp); + if (type != ns_t_tsig) + return (NS_TSIG_ERROR_NO_TSIG); + + /* Skip the class and TTL, save the length. */ + cp += INT16SZ + INT32SZ; + GETSHORT(length, cp); + if (eom - cp != length) + return (NS_TSIG_ERROR_FORMERR); + + /* Read the algorithm name. */ + rdatastart = cp; + n = dn_expand(msg, eom, cp, alg, MAXDNAME); + if (n < 0) + return (NS_TSIG_ERROR_FORMERR); + if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) + return (-ns_r_badkey); + cp += n; + + /* Read the time signed and fudge. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + cp += INT16SZ; + GETLONG((*timesigned), cp); + GETSHORT(fudge, cp); + + /* Read the signature. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(sigfieldlen, cp); + BOUNDS_CHECK(cp, sigfieldlen); + sigstart = cp; + cp += sigfieldlen; + + /* Read the original id and error. */ + BOUNDS_CHECK(cp, 2*INT16SZ); + GETSHORT(id, cp); + GETSHORT(error, cp); + + /* Parse the other data. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(otherfieldlen, cp); + BOUNDS_CHECK(cp, otherfieldlen); + otherstart = cp; + cp += otherfieldlen; + + if (cp != eom) + return (NS_TSIG_ERROR_FORMERR); + + /* Verify that the key used is OK. */ + if (key != NULL) { + if (key->dk_alg != KEY_HMAC_MD5) + return (-ns_r_badkey); + if (error != ns_r_badsig && error != ns_r_badkey) { + if (ns_samename(key->dk_key_name, name) != 1) + return (-ns_r_badkey); + } + } + + hp->arcount = htons(ntohs(hp->arcount) - 1); + + /* + * Do the verification. + */ + + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + void *ctx; + u_char buf[MAXDNAME]; + + /* Digest the query signature, if this is a response. */ + dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); + if (querysiglen > 0 && querysig != NULL) { + u_int16_t len_n = htons(querysiglen); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + (u_char *)&len_n, INT16SZ, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + querysig, querysiglen, NULL, 0); + } + + /* Digest the message. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg, + NULL, 0); + + /* Digest the key name. */ + n = ns_name_ntol(recstart, buf, sizeof(buf)); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the class and TTL. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + recstart + dn_skipname(recstart, eom) + INT16SZ, + INT16SZ + INT32SZ, NULL, 0); + + /* Digest the algorithm. */ + n = ns_name_ntol(rdatastart, buf, sizeof(buf)); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the time signed and fudge. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + rdatastart + dn_skipname(rdatastart, eom), + INT16SZ + INT32SZ + INT16SZ, NULL, 0); + + /* Digest the error and other data. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + otherstart - INT16SZ - INT16SZ, + otherfieldlen + INT16SZ + INT16SZ, NULL, 0); + + n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, + sigstart, sigfieldlen); + + if (n < 0) + return (-ns_r_badsig); + + if (sig != NULL && siglen != NULL) { + if (*siglen < sigfieldlen) + return (NS_TSIG_ERROR_NO_SPACE); + memcpy(sig, sigstart, sigfieldlen); + *siglen = sigfieldlen; + } + } else { + if (sigfieldlen > 0) + return (NS_TSIG_ERROR_FORMERR); + if (sig != NULL && siglen != NULL) + *siglen = 0; + } + + /* Reset the counter, since we still need to check for badtime. */ + hp->arcount = htons(ntohs(hp->arcount) + 1); + + /* Verify the time. */ + if (abs((*timesigned) - time(NULL)) > fudge) + return (-ns_r_badtime); + + if (nostrip == 0) { + *msglen = recstart - msg; + hp->arcount = htons(ntohs(hp->arcount) - 1); + } + + if (error != NOERROR) + return (error); + + return (0); +} + +int +ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen, + ns_tcp_tsig_state *state) +{ + dst_init(); + if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) + return (-1); + state->counter = -1; + state->key = k; + if (state->key->dk_alg != KEY_HMAC_MD5) + return (-ns_r_badkey); + if (querysiglen > sizeof(state->sig)) + return (-1); + memcpy(state->sig, querysig, querysiglen); + state->siglen = querysiglen; + return (0); +} + +int +ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state, + int required) +{ + HEADER *hp = (HEADER *)msg; + u_char *recstart, *rdatastart, *sigstart; + int sigfieldlen, otherfieldlen; + u_char *cp, *eom = msg + *msglen, *cp2; + char name[MAXDNAME], alg[MAXDNAME]; + u_char buf[MAXDNAME]; + int n, type, length, fudge, id, error; + time_t timesigned; + + if (msg == NULL || msglen == NULL || state == NULL) + return (-1); + + state->counter++; + if (state->counter == 0) + return (ns_verify(msg, msglen, state->key, + state->sig, state->siglen, + state->sig, &state->siglen, ×igned, 0)); + + if (state->siglen > 0) { + u_int16_t siglen_n = htons(state->siglen); + + dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx, + NULL, 0, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + (u_char *)&siglen_n, INT16SZ, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + state->sig, state->siglen, NULL, 0); + state->siglen = 0; + } + + cp = recstart = ns_find_tsig(msg, eom); + + if (recstart == NULL) { + if (required) + return (NS_TSIG_ERROR_NO_TSIG); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + msg, *msglen, NULL, 0); + return (0); + } + + hp->arcount = htons(ntohs(hp->arcount) - 1); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + msg, recstart - msg, NULL, 0); + + /* Read the key name. */ + n = dn_expand(msg, eom, cp, name, MAXDNAME); + if (n < 0) + return (NS_TSIG_ERROR_FORMERR); + cp += n; + + /* Read the type. */ + BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); + GETSHORT(type, cp); + if (type != ns_t_tsig) + return (NS_TSIG_ERROR_NO_TSIG); + + /* Skip the class and TTL, save the length. */ + cp += INT16SZ + INT32SZ; + GETSHORT(length, cp); + if (eom - cp != length) + return (NS_TSIG_ERROR_FORMERR); + + /* Read the algorithm name. */ + rdatastart = cp; + n = dn_expand(msg, eom, cp, alg, MAXDNAME); + if (n < 0) + return (NS_TSIG_ERROR_FORMERR); + if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) + return (-ns_r_badkey); + cp += n; + + /* Verify that the key used is OK. */ + if ((ns_samename(state->key->dk_key_name, name) != 1 || + state->key->dk_alg != KEY_HMAC_MD5)) + return (-ns_r_badkey); + + /* Read the time signed and fudge. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + cp += INT16SZ; + GETLONG(timesigned, cp); + GETSHORT(fudge, cp); + + /* Read the signature. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(sigfieldlen, cp); + BOUNDS_CHECK(cp, sigfieldlen); + sigstart = cp; + cp += sigfieldlen; + + /* Read the original id and error. */ + BOUNDS_CHECK(cp, 2*INT16SZ); + GETSHORT(id, cp); + GETSHORT(error, cp); + + /* Parse the other data. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(otherfieldlen, cp); + BOUNDS_CHECK(cp, otherfieldlen); + cp += otherfieldlen; + + if (cp != eom) + return (NS_TSIG_ERROR_FORMERR); + + /* + * Do the verification. + */ + + /* Digest the time signed and fudge. */ + cp2 = buf; + PUTSHORT(0, cp2); /* Top 16 bits of time. */ + PUTLONG(timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + buf, cp2 - buf, NULL, 0); + + n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, + sigstart, sigfieldlen); + if (n < 0) + return (-ns_r_badsig); + + if (sigfieldlen > sizeof(state->sig)) + return (ns_r_badsig); + + if (sigfieldlen > sizeof(state->sig)) + return (NS_TSIG_ERROR_NO_SPACE); + + memcpy(state->sig, sigstart, sigfieldlen); + state->siglen = sigfieldlen; + + /* Verify the time. */ + if (abs(timesigned - time(NULL)) > fudge) + return (-ns_r_badtime); + + *msglen = recstart - msg; + + if (error != NOERROR) + return (error); + + return (0); +} |