Home | History | Annotate | Line # | Download | only in nameser
ns_samedomain.c revision 1.4.12.1
      1  1.4.12.1  wrstuden /*	$NetBSD: ns_samedomain.c,v 1.4.12.1 2008/06/23 04:29:32 wrstuden Exp $	*/
      2       1.1  christos 
      3       1.1  christos /*
      4       1.1  christos  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
      5       1.1  christos  * Copyright (c) 1995,1999 by Internet Software Consortium.
      6       1.1  christos  *
      7       1.1  christos  * Permission to use, copy, modify, and distribute this software for any
      8       1.1  christos  * purpose with or without fee is hereby granted, provided that the above
      9       1.1  christos  * copyright notice and this permission notice appear in all copies.
     10       1.1  christos  *
     11       1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     12       1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13       1.1  christos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     14       1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15       1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16       1.1  christos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     17       1.1  christos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18       1.1  christos  */
     19       1.1  christos 
     20       1.2  christos #include <sys/cdefs.h>
     21       1.1  christos #ifndef lint
     22       1.2  christos #ifdef notdef
     23  1.4.12.1  wrstuden static const char rcsid[] = "Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp";
     24       1.2  christos #else
     25  1.4.12.1  wrstuden __RCSID("$NetBSD: ns_samedomain.c,v 1.4.12.1 2008/06/23 04:29:32 wrstuden Exp $");
     26       1.2  christos #endif
     27       1.1  christos #endif
     28       1.1  christos 
     29       1.1  christos #include "port_before.h"
     30       1.1  christos 
     31       1.1  christos #include <sys/types.h>
     32       1.1  christos #include <arpa/nameser.h>
     33       1.1  christos #include <errno.h>
     34       1.1  christos #include <string.h>
     35       1.1  christos 
     36       1.1  christos #include "port_after.h"
     37       1.1  christos 
     38       1.2  christos #ifndef _LIBC
     39       1.3  christos /*%
     40       1.1  christos  *	Check whether a name belongs to a domain.
     41       1.3  christos  *
     42       1.1  christos  * Inputs:
     43       1.3  christos  *\li	a - the domain whose ancestory is being verified
     44       1.3  christos  *\li	b - the potential ancestor we're checking against
     45       1.3  christos  *
     46       1.1  christos  * Return:
     47       1.3  christos  *\li	boolean - is a at or below b?
     48       1.3  christos  *
     49       1.1  christos  * Notes:
     50       1.3  christos  *\li	Trailing dots are first removed from name and domain.
     51       1.1  christos  *	Always compare complete subdomains, not only whether the
     52       1.1  christos  *	domain name is the trailing string of the given name.
     53       1.1  christos  *
     54       1.3  christos  *\li	"host.foobar.top" lies in "foobar.top" and in "top" and in ""
     55       1.1  christos  *	but NOT in "bar.top"
     56       1.1  christos  */
     57       1.1  christos 
     58       1.1  christos int
     59       1.1  christos ns_samedomain(const char *a, const char *b) {
     60       1.1  christos 	size_t la, lb;
     61       1.1  christos 	int diff, i, escaped;
     62       1.1  christos 	const char *cp;
     63       1.1  christos 
     64       1.1  christos 	la = strlen(a);
     65       1.1  christos 	lb = strlen(b);
     66       1.1  christos 
     67       1.1  christos 	/* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
     68       1.1  christos 	if (la != 0U && a[la - 1] == '.') {
     69       1.1  christos 		escaped = 0;
     70       1.1  christos 		/* Note this loop doesn't get executed if la==1. */
     71       1.1  christos 		for (i = la - 2; i >= 0; i--)
     72       1.1  christos 			if (a[i] == '\\') {
     73       1.1  christos 				if (escaped)
     74       1.1  christos 					escaped = 0;
     75       1.1  christos 				else
     76       1.1  christos 					escaped = 1;
     77       1.1  christos 			} else
     78       1.1  christos 				break;
     79       1.1  christos 		if (!escaped)
     80       1.1  christos 			la--;
     81       1.1  christos 	}
     82       1.1  christos 
     83       1.1  christos 	/* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
     84       1.1  christos 	if (lb != 0U && b[lb - 1] == '.') {
     85       1.1  christos 		escaped = 0;
     86       1.1  christos 		/* note this loop doesn't get executed if lb==1 */
     87       1.1  christos 		for (i = lb - 2; i >= 0; i--)
     88       1.1  christos 			if (b[i] == '\\') {
     89       1.1  christos 				if (escaped)
     90       1.1  christos 					escaped = 0;
     91       1.1  christos 				else
     92       1.1  christos 					escaped = 1;
     93       1.1  christos 			} else
     94       1.1  christos 				break;
     95       1.1  christos 		if (!escaped)
     96       1.1  christos 			lb--;
     97       1.1  christos 	}
     98       1.1  christos 
     99       1.1  christos 	/* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
    100       1.1  christos 	if (lb == 0U)
    101       1.1  christos 		return (1);
    102       1.1  christos 
    103       1.1  christos 	/* 'b' longer than 'a' means 'a' can't be in 'b'. */
    104       1.1  christos 	if (lb > la)
    105       1.1  christos 		return (0);
    106       1.1  christos 
    107       1.1  christos 	/* 'a' and 'b' being equal at this point indicates sameness. */
    108       1.1  christos 	if (lb == la)
    109       1.1  christos 		return (strncasecmp(a, b, lb) == 0);
    110       1.1  christos 
    111       1.1  christos 	/* Ok, we know la > lb. */
    112       1.1  christos 
    113       1.1  christos 	diff = la - lb;
    114       1.1  christos 
    115       1.1  christos 	/*
    116       1.1  christos 	 * If 'a' is only 1 character longer than 'b', then it can't be
    117       1.1  christos 	 * a subdomain of 'b' (because of the need for the '.' label
    118       1.1  christos 	 * separator).
    119       1.1  christos 	 */
    120       1.1  christos 	if (diff < 2)
    121       1.1  christos 		return (0);
    122       1.1  christos 
    123       1.1  christos 	/*
    124       1.1  christos 	 * If the character before the last 'lb' characters of 'b'
    125       1.1  christos 	 * isn't '.', then it can't be a match (this lets us avoid
    126       1.1  christos 	 * having "foobar.com" match "bar.com").
    127       1.1  christos 	 */
    128       1.1  christos 	if (a[diff - 1] != '.')
    129       1.1  christos 		return (0);
    130       1.1  christos 
    131       1.1  christos 	/*
    132       1.1  christos 	 * We're not sure about that '.', however.  It could be escaped
    133       1.1  christos          * and thus not a really a label separator.
    134       1.1  christos 	 */
    135       1.1  christos 	escaped = 0;
    136       1.1  christos 	for (i = diff - 2; i >= 0; i--)
    137       1.1  christos 		if (a[i] == '\\') {
    138       1.1  christos 			if (escaped)
    139       1.1  christos 				escaped = 0;
    140       1.1  christos 			else
    141       1.1  christos 				escaped = 1;
    142       1.1  christos 		} else
    143       1.1  christos 			break;
    144       1.1  christos 	if (escaped)
    145       1.1  christos 		return (0);
    146       1.1  christos 
    147       1.1  christos 	/* Now compare aligned trailing substring. */
    148       1.1  christos 	cp = a + diff;
    149       1.1  christos 	return (strncasecmp(cp, b, lb) == 0);
    150       1.1  christos }
    151       1.1  christos 
    152       1.3  christos /*%
    153       1.1  christos  *	is "a" a subdomain of "b"?
    154       1.1  christos  */
    155       1.1  christos int
    156       1.1  christos ns_subdomain(const char *a, const char *b) {
    157       1.1  christos 	return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
    158       1.1  christos }
    159       1.2  christos #endif
    160       1.1  christos 
    161       1.3  christos /*%
    162       1.1  christos  *	make a canonical copy of domain name "src"
    163       1.3  christos  *
    164       1.1  christos  * notes:
    165       1.3  christos  * \code
    166       1.1  christos  *	foo -> foo.
    167       1.1  christos  *	foo. -> foo.
    168       1.1  christos  *	foo.. -> foo.
    169       1.1  christos  *	foo\. -> foo\..
    170       1.1  christos  *	foo\\. -> foo\\.
    171       1.3  christos  * \endcode
    172       1.1  christos  */
    173       1.1  christos 
    174       1.1  christos int
    175       1.1  christos ns_makecanon(const char *src, char *dst, size_t dstsize) {
    176       1.1  christos 	size_t n = strlen(src);
    177       1.1  christos 
    178       1.3  christos 	if (n + sizeof "." > dstsize) {			/*%< Note: sizeof == 2 */
    179       1.1  christos 		errno = EMSGSIZE;
    180       1.1  christos 		return (-1);
    181       1.1  christos 	}
    182       1.1  christos 	strcpy(dst, src);
    183       1.3  christos 	while (n >= 1U && dst[n - 1] == '.')		/*%< Ends in "." */
    184       1.3  christos 		if (n >= 2U && dst[n - 2] == '\\' &&	/*%< Ends in "\." */
    185       1.3  christos 		    (n < 3U || dst[n - 3] != '\\'))	/*%< But not "\\." */
    186       1.1  christos 			break;
    187       1.1  christos 		else
    188       1.1  christos 			dst[--n] = '\0';
    189       1.1  christos 	dst[n++] = '.';
    190       1.1  christos 	dst[n] = '\0';
    191       1.1  christos 	return (0);
    192       1.1  christos }
    193       1.1  christos 
    194       1.3  christos /*%
    195       1.1  christos  *	determine whether domain name "a" is the same as domain name "b"
    196       1.3  christos  *
    197       1.1  christos  * return:
    198       1.3  christos  *\li	-1 on error
    199       1.3  christos  *\li	0 if names differ
    200       1.3  christos  *\li	1 if names are the same
    201       1.1  christos  */
    202       1.1  christos 
    203       1.1  christos int
    204       1.1  christos ns_samename(const char *a, const char *b) {
    205       1.1  christos 	char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
    206       1.1  christos 
    207       1.1  christos 	if (ns_makecanon(a, ta, sizeof ta) < 0 ||
    208       1.1  christos 	    ns_makecanon(b, tb, sizeof tb) < 0)
    209       1.1  christos 		return (-1);
    210       1.1  christos 	if (strcasecmp(ta, tb) == 0)
    211       1.1  christos 		return (1);
    212       1.1  christos 	else
    213       1.1  christos 		return (0);
    214       1.1  christos }
    215       1.3  christos 
    216       1.3  christos /*! \file */
    217