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