xref: /freebsd/lib/libc/nameser/ns_samedomain.c (revision ab96eeab)
165e96449SHajimu UMEMOTO /*
265e96449SHajimu UMEMOTO  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
365e96449SHajimu UMEMOTO  * Copyright (c) 1995,1999 by Internet Software Consortium.
465e96449SHajimu UMEMOTO  *
565e96449SHajimu UMEMOTO  * Permission to use, copy, modify, and distribute this software for any
665e96449SHajimu UMEMOTO  * purpose with or without fee is hereby granted, provided that the above
765e96449SHajimu UMEMOTO  * copyright notice and this permission notice appear in all copies.
865e96449SHajimu UMEMOTO  *
965e96449SHajimu UMEMOTO  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
1065e96449SHajimu UMEMOTO  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1165e96449SHajimu UMEMOTO  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
1265e96449SHajimu UMEMOTO  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1365e96449SHajimu UMEMOTO  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1465e96449SHajimu UMEMOTO  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
1565e96449SHajimu UMEMOTO  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1665e96449SHajimu UMEMOTO  */
1765e96449SHajimu UMEMOTO 
1865e96449SHajimu UMEMOTO #ifndef lint
1965e96449SHajimu UMEMOTO static const char rcsid[] = "$Id: ns_samedomain.c,v 1.1.2.2.4.2 2004/03/16 12:34:17 marka Exp $";
2065e96449SHajimu UMEMOTO #endif
21ab96eeabSHajimu UMEMOTO #include <sys/cdefs.h>
22ab96eeabSHajimu UMEMOTO __FBSDID("$FreeBSD$");
2365e96449SHajimu UMEMOTO 
2465e96449SHajimu UMEMOTO #include "port_before.h"
2565e96449SHajimu UMEMOTO 
2665e96449SHajimu UMEMOTO #include <sys/types.h>
2765e96449SHajimu UMEMOTO #include <arpa/nameser.h>
2865e96449SHajimu UMEMOTO #include <errno.h>
2965e96449SHajimu UMEMOTO #include <string.h>
3065e96449SHajimu UMEMOTO 
3165e96449SHajimu UMEMOTO #include "port_after.h"
3265e96449SHajimu UMEMOTO 
33ab96eeabSHajimu UMEMOTO #ifndef _LIBC
3465e96449SHajimu UMEMOTO /*
3565e96449SHajimu UMEMOTO  * int
3665e96449SHajimu UMEMOTO  * ns_samedomain(a, b)
3765e96449SHajimu UMEMOTO  *	Check whether a name belongs to a domain.
3865e96449SHajimu UMEMOTO  * Inputs:
3965e96449SHajimu UMEMOTO  *	a - the domain whose ancestory is being verified
4065e96449SHajimu UMEMOTO  *	b - the potential ancestor we're checking against
4165e96449SHajimu UMEMOTO  * Return:
4265e96449SHajimu UMEMOTO  *	boolean - is a at or below b?
4365e96449SHajimu UMEMOTO  * Notes:
4465e96449SHajimu UMEMOTO  *	Trailing dots are first removed from name and domain.
4565e96449SHajimu UMEMOTO  *	Always compare complete subdomains, not only whether the
4665e96449SHajimu UMEMOTO  *	domain name is the trailing string of the given name.
4765e96449SHajimu UMEMOTO  *
4865e96449SHajimu UMEMOTO  *	"host.foobar.top" lies in "foobar.top" and in "top" and in ""
4965e96449SHajimu UMEMOTO  *	but NOT in "bar.top"
5065e96449SHajimu UMEMOTO  */
5165e96449SHajimu UMEMOTO 
5265e96449SHajimu UMEMOTO int
5365e96449SHajimu UMEMOTO ns_samedomain(const char *a, const char *b) {
5465e96449SHajimu UMEMOTO 	size_t la, lb;
5565e96449SHajimu UMEMOTO 	int diff, i, escaped;
5665e96449SHajimu UMEMOTO 	const char *cp;
5765e96449SHajimu UMEMOTO 
5865e96449SHajimu UMEMOTO 	la = strlen(a);
5965e96449SHajimu UMEMOTO 	lb = strlen(b);
6065e96449SHajimu UMEMOTO 
6165e96449SHajimu UMEMOTO 	/* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
6265e96449SHajimu UMEMOTO 	if (la != 0U && a[la - 1] == '.') {
6365e96449SHajimu UMEMOTO 		escaped = 0;
6465e96449SHajimu UMEMOTO 		/* Note this loop doesn't get executed if la==1. */
6565e96449SHajimu UMEMOTO 		for (i = la - 2; i >= 0; i--)
6665e96449SHajimu UMEMOTO 			if (a[i] == '\\') {
6765e96449SHajimu UMEMOTO 				if (escaped)
6865e96449SHajimu UMEMOTO 					escaped = 0;
6965e96449SHajimu UMEMOTO 				else
7065e96449SHajimu UMEMOTO 					escaped = 1;
7165e96449SHajimu UMEMOTO 			} else
7265e96449SHajimu UMEMOTO 				break;
7365e96449SHajimu UMEMOTO 		if (!escaped)
7465e96449SHajimu UMEMOTO 			la--;
7565e96449SHajimu UMEMOTO 	}
7665e96449SHajimu UMEMOTO 
7765e96449SHajimu UMEMOTO 	/* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
7865e96449SHajimu UMEMOTO 	if (lb != 0U && b[lb - 1] == '.') {
7965e96449SHajimu UMEMOTO 		escaped = 0;
8065e96449SHajimu UMEMOTO 		/* note this loop doesn't get executed if lb==1 */
8165e96449SHajimu UMEMOTO 		for (i = lb - 2; i >= 0; i--)
8265e96449SHajimu UMEMOTO 			if (b[i] == '\\') {
8365e96449SHajimu UMEMOTO 				if (escaped)
8465e96449SHajimu UMEMOTO 					escaped = 0;
8565e96449SHajimu UMEMOTO 				else
8665e96449SHajimu UMEMOTO 					escaped = 1;
8765e96449SHajimu UMEMOTO 			} else
8865e96449SHajimu UMEMOTO 				break;
8965e96449SHajimu UMEMOTO 		if (!escaped)
9065e96449SHajimu UMEMOTO 			lb--;
9165e96449SHajimu UMEMOTO 	}
9265e96449SHajimu UMEMOTO 
9365e96449SHajimu UMEMOTO 	/* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
9465e96449SHajimu UMEMOTO 	if (lb == 0U)
9565e96449SHajimu UMEMOTO 		return (1);
9665e96449SHajimu UMEMOTO 
9765e96449SHajimu UMEMOTO 	/* 'b' longer than 'a' means 'a' can't be in 'b'. */
9865e96449SHajimu UMEMOTO 	if (lb > la)
9965e96449SHajimu UMEMOTO 		return (0);
10065e96449SHajimu UMEMOTO 
10165e96449SHajimu UMEMOTO 	/* 'a' and 'b' being equal at this point indicates sameness. */
10265e96449SHajimu UMEMOTO 	if (lb == la)
10365e96449SHajimu UMEMOTO 		return (strncasecmp(a, b, lb) == 0);
10465e96449SHajimu UMEMOTO 
10565e96449SHajimu UMEMOTO 	/* Ok, we know la > lb. */
10665e96449SHajimu UMEMOTO 
10765e96449SHajimu UMEMOTO 	diff = la - lb;
10865e96449SHajimu UMEMOTO 
10965e96449SHajimu UMEMOTO 	/*
11065e96449SHajimu UMEMOTO 	 * If 'a' is only 1 character longer than 'b', then it can't be
11165e96449SHajimu UMEMOTO 	 * a subdomain of 'b' (because of the need for the '.' label
11265e96449SHajimu UMEMOTO 	 * separator).
11365e96449SHajimu UMEMOTO 	 */
11465e96449SHajimu UMEMOTO 	if (diff < 2)
11565e96449SHajimu UMEMOTO 		return (0);
11665e96449SHajimu UMEMOTO 
11765e96449SHajimu UMEMOTO 	/*
11865e96449SHajimu UMEMOTO 	 * If the character before the last 'lb' characters of 'b'
11965e96449SHajimu UMEMOTO 	 * isn't '.', then it can't be a match (this lets us avoid
12065e96449SHajimu UMEMOTO 	 * having "foobar.com" match "bar.com").
12165e96449SHajimu UMEMOTO 	 */
12265e96449SHajimu UMEMOTO 	if (a[diff - 1] != '.')
12365e96449SHajimu UMEMOTO 		return (0);
12465e96449SHajimu UMEMOTO 
12565e96449SHajimu UMEMOTO 	/*
12665e96449SHajimu UMEMOTO 	 * We're not sure about that '.', however.  It could be escaped
12765e96449SHajimu UMEMOTO          * and thus not a really a label separator.
12865e96449SHajimu UMEMOTO 	 */
12965e96449SHajimu UMEMOTO 	escaped = 0;
13065e96449SHajimu UMEMOTO 	for (i = diff - 2; i >= 0; i--)
13165e96449SHajimu UMEMOTO 		if (a[i] == '\\') {
13265e96449SHajimu UMEMOTO 			if (escaped)
13365e96449SHajimu UMEMOTO 				escaped = 0;
13465e96449SHajimu UMEMOTO 			else
13565e96449SHajimu UMEMOTO 				escaped = 1;
13665e96449SHajimu UMEMOTO 		} else
13765e96449SHajimu UMEMOTO 			break;
13865e96449SHajimu UMEMOTO 	if (escaped)
13965e96449SHajimu UMEMOTO 		return (0);
14065e96449SHajimu UMEMOTO 
14165e96449SHajimu UMEMOTO 	/* Now compare aligned trailing substring. */
14265e96449SHajimu UMEMOTO 	cp = a + diff;
14365e96449SHajimu UMEMOTO 	return (strncasecmp(cp, b, lb) == 0);
14465e96449SHajimu UMEMOTO }
14565e96449SHajimu UMEMOTO 
14665e96449SHajimu UMEMOTO /*
14765e96449SHajimu UMEMOTO  * int
14865e96449SHajimu UMEMOTO  * ns_subdomain(a, b)
14965e96449SHajimu UMEMOTO  *	is "a" a subdomain of "b"?
15065e96449SHajimu UMEMOTO  */
15165e96449SHajimu UMEMOTO int
15265e96449SHajimu UMEMOTO ns_subdomain(const char *a, const char *b) {
15365e96449SHajimu UMEMOTO 	return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
15465e96449SHajimu UMEMOTO }
155ab96eeabSHajimu UMEMOTO #endif
15665e96449SHajimu UMEMOTO 
15765e96449SHajimu UMEMOTO /*
15865e96449SHajimu UMEMOTO  * int
15965e96449SHajimu UMEMOTO  * ns_makecanon(src, dst, dstsize)
16065e96449SHajimu UMEMOTO  *	make a canonical copy of domain name "src"
16165e96449SHajimu UMEMOTO  * notes:
16265e96449SHajimu UMEMOTO  *	foo -> foo.
16365e96449SHajimu UMEMOTO  *	foo. -> foo.
16465e96449SHajimu UMEMOTO  *	foo.. -> foo.
16565e96449SHajimu UMEMOTO  *	foo\. -> foo\..
16665e96449SHajimu UMEMOTO  *	foo\\. -> foo\\.
16765e96449SHajimu UMEMOTO  */
16865e96449SHajimu UMEMOTO 
16965e96449SHajimu UMEMOTO int
17065e96449SHajimu UMEMOTO ns_makecanon(const char *src, char *dst, size_t dstsize) {
17165e96449SHajimu UMEMOTO 	size_t n = strlen(src);
17265e96449SHajimu UMEMOTO 
17365e96449SHajimu UMEMOTO 	if (n + sizeof "." > dstsize) {			/* Note: sizeof == 2 */
17465e96449SHajimu UMEMOTO 		errno = EMSGSIZE;
17565e96449SHajimu UMEMOTO 		return (-1);
17665e96449SHajimu UMEMOTO 	}
17765e96449SHajimu UMEMOTO 	strcpy(dst, src);
17865e96449SHajimu UMEMOTO 	while (n >= 1U && dst[n - 1] == '.')		/* Ends in "." */
17965e96449SHajimu UMEMOTO 		if (n >= 2U && dst[n - 2] == '\\' &&	/* Ends in "\." */
18065e96449SHajimu UMEMOTO 		    (n < 3U || dst[n - 3] != '\\'))	/* But not "\\." */
18165e96449SHajimu UMEMOTO 			break;
18265e96449SHajimu UMEMOTO 		else
18365e96449SHajimu UMEMOTO 			dst[--n] = '\0';
18465e96449SHajimu UMEMOTO 	dst[n++] = '.';
18565e96449SHajimu UMEMOTO 	dst[n] = '\0';
18665e96449SHajimu UMEMOTO 	return (0);
18765e96449SHajimu UMEMOTO }
18865e96449SHajimu UMEMOTO 
18965e96449SHajimu UMEMOTO /*
19065e96449SHajimu UMEMOTO  * int
19165e96449SHajimu UMEMOTO  * ns_samename(a, b)
19265e96449SHajimu UMEMOTO  *	determine whether domain name "a" is the same as domain name "b"
19365e96449SHajimu UMEMOTO  * return:
19465e96449SHajimu UMEMOTO  *	-1 on error
19565e96449SHajimu UMEMOTO  *	0 if names differ
19665e96449SHajimu UMEMOTO  *	1 if names are the same
19765e96449SHajimu UMEMOTO  */
19865e96449SHajimu UMEMOTO 
19965e96449SHajimu UMEMOTO int
20065e96449SHajimu UMEMOTO ns_samename(const char *a, const char *b) {
20165e96449SHajimu UMEMOTO 	char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
20265e96449SHajimu UMEMOTO 
20365e96449SHajimu UMEMOTO 	if (ns_makecanon(a, ta, sizeof ta) < 0 ||
20465e96449SHajimu UMEMOTO 	    ns_makecanon(b, tb, sizeof tb) < 0)
20565e96449SHajimu UMEMOTO 		return (-1);
20665e96449SHajimu UMEMOTO 	if (strcasecmp(ta, tb) == 0)
20765e96449SHajimu UMEMOTO 		return (1);
20865e96449SHajimu UMEMOTO 	else
20965e96449SHajimu UMEMOTO 		return (0);
21065e96449SHajimu UMEMOTO }
211