xref: /freebsd/lib/libc/nameser/ns_samedomain.c (revision 6e778a7e)
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 #ifndef lint
21046c3635SPedro F. Giffuni static const char rcsid[] = "$Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp $";
2265e96449SHajimu UMEMOTO #endif
23ab96eeabSHajimu UMEMOTO #include <sys/cdefs.h>
24ab96eeabSHajimu UMEMOTO __FBSDID("$FreeBSD$");
2565e96449SHajimu UMEMOTO 
2665e96449SHajimu UMEMOTO #include "port_before.h"
2765e96449SHajimu UMEMOTO 
2865e96449SHajimu UMEMOTO #include <sys/types.h>
2965e96449SHajimu UMEMOTO #include <arpa/nameser.h>
3065e96449SHajimu UMEMOTO #include <errno.h>
3165e96449SHajimu UMEMOTO #include <string.h>
3265e96449SHajimu UMEMOTO 
3365e96449SHajimu UMEMOTO #include "port_after.h"
3465e96449SHajimu UMEMOTO 
35dde4a85dSHajimu UMEMOTO /*%
3665e96449SHajimu UMEMOTO  *	Check whether a name belongs to a domain.
37dde4a85dSHajimu UMEMOTO  *
3865e96449SHajimu UMEMOTO  * Inputs:
3932223c1bSPedro F. Giffuni  *\li	a - the domain whose ancestry is being verified
40dde4a85dSHajimu UMEMOTO  *\li	b - the potential ancestor we're checking against
41dde4a85dSHajimu UMEMOTO  *
4265e96449SHajimu UMEMOTO  * Return:
43dde4a85dSHajimu UMEMOTO  *\li	boolean - is a at or below b?
44dde4a85dSHajimu UMEMOTO  *
4565e96449SHajimu UMEMOTO  * Notes:
46dde4a85dSHajimu UMEMOTO  *\li	Trailing dots are first removed from name and domain.
4765e96449SHajimu UMEMOTO  *	Always compare complete subdomains, not only whether the
4865e96449SHajimu UMEMOTO  *	domain name is the trailing string of the given name.
4965e96449SHajimu UMEMOTO  *
50dde4a85dSHajimu UMEMOTO  *\li	"host.foobar.top" lies in "foobar.top" and in "top" and in ""
5165e96449SHajimu UMEMOTO  *	but NOT in "bar.top"
5265e96449SHajimu UMEMOTO  */
5365e96449SHajimu UMEMOTO 
5465e96449SHajimu UMEMOTO int
5565e96449SHajimu UMEMOTO ns_samedomain(const char *a, const char *b) {
5665e96449SHajimu UMEMOTO 	size_t la, lb;
5765e96449SHajimu UMEMOTO 	int diff, i, escaped;
5865e96449SHajimu UMEMOTO 	const char *cp;
5965e96449SHajimu UMEMOTO 
6065e96449SHajimu UMEMOTO 	la = strlen(a);
6165e96449SHajimu UMEMOTO 	lb = strlen(b);
6265e96449SHajimu UMEMOTO 
6365e96449SHajimu UMEMOTO 	/* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
6465e96449SHajimu UMEMOTO 	if (la != 0U && a[la - 1] == '.') {
6565e96449SHajimu UMEMOTO 		escaped = 0;
6665e96449SHajimu UMEMOTO 		/* Note this loop doesn't get executed if la==1. */
6765e96449SHajimu UMEMOTO 		for (i = la - 2; i >= 0; i--)
6865e96449SHajimu UMEMOTO 			if (a[i] == '\\') {
6965e96449SHajimu UMEMOTO 				if (escaped)
7065e96449SHajimu UMEMOTO 					escaped = 0;
7165e96449SHajimu UMEMOTO 				else
7265e96449SHajimu UMEMOTO 					escaped = 1;
7365e96449SHajimu UMEMOTO 			} else
7465e96449SHajimu UMEMOTO 				break;
7565e96449SHajimu UMEMOTO 		if (!escaped)
7665e96449SHajimu UMEMOTO 			la--;
7765e96449SHajimu UMEMOTO 	}
7865e96449SHajimu UMEMOTO 
7965e96449SHajimu UMEMOTO 	/* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
8065e96449SHajimu UMEMOTO 	if (lb != 0U && b[lb - 1] == '.') {
8165e96449SHajimu UMEMOTO 		escaped = 0;
8265e96449SHajimu UMEMOTO 		/* note this loop doesn't get executed if lb==1 */
8365e96449SHajimu UMEMOTO 		for (i = lb - 2; i >= 0; i--)
8465e96449SHajimu UMEMOTO 			if (b[i] == '\\') {
8565e96449SHajimu UMEMOTO 				if (escaped)
8665e96449SHajimu UMEMOTO 					escaped = 0;
8765e96449SHajimu UMEMOTO 				else
8865e96449SHajimu UMEMOTO 					escaped = 1;
8965e96449SHajimu UMEMOTO 			} else
9065e96449SHajimu UMEMOTO 				break;
9165e96449SHajimu UMEMOTO 		if (!escaped)
9265e96449SHajimu UMEMOTO 			lb--;
9365e96449SHajimu UMEMOTO 	}
9465e96449SHajimu UMEMOTO 
9565e96449SHajimu UMEMOTO 	/* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
9665e96449SHajimu UMEMOTO 	if (lb == 0U)
9765e96449SHajimu UMEMOTO 		return (1);
9865e96449SHajimu UMEMOTO 
9965e96449SHajimu UMEMOTO 	/* 'b' longer than 'a' means 'a' can't be in 'b'. */
10065e96449SHajimu UMEMOTO 	if (lb > la)
10165e96449SHajimu UMEMOTO 		return (0);
10265e96449SHajimu UMEMOTO 
10365e96449SHajimu UMEMOTO 	/* 'a' and 'b' being equal at this point indicates sameness. */
10465e96449SHajimu UMEMOTO 	if (lb == la)
10565e96449SHajimu UMEMOTO 		return (strncasecmp(a, b, lb) == 0);
10665e96449SHajimu UMEMOTO 
10765e96449SHajimu UMEMOTO 	/* Ok, we know la > lb. */
10865e96449SHajimu UMEMOTO 
10965e96449SHajimu UMEMOTO 	diff = la - lb;
11065e96449SHajimu UMEMOTO 
11165e96449SHajimu UMEMOTO 	/*
11265e96449SHajimu UMEMOTO 	 * If 'a' is only 1 character longer than 'b', then it can't be
11365e96449SHajimu UMEMOTO 	 * a subdomain of 'b' (because of the need for the '.' label
11465e96449SHajimu UMEMOTO 	 * separator).
11565e96449SHajimu UMEMOTO 	 */
11665e96449SHajimu UMEMOTO 	if (diff < 2)
11765e96449SHajimu UMEMOTO 		return (0);
11865e96449SHajimu UMEMOTO 
11965e96449SHajimu UMEMOTO 	/*
12065e96449SHajimu UMEMOTO 	 * If the character before the last 'lb' characters of 'b'
12165e96449SHajimu UMEMOTO 	 * isn't '.', then it can't be a match (this lets us avoid
12265e96449SHajimu UMEMOTO 	 * having "foobar.com" match "bar.com").
12365e96449SHajimu UMEMOTO 	 */
12465e96449SHajimu UMEMOTO 	if (a[diff - 1] != '.')
12565e96449SHajimu UMEMOTO 		return (0);
12665e96449SHajimu UMEMOTO 
12765e96449SHajimu UMEMOTO 	/*
12865e96449SHajimu UMEMOTO 	 * We're not sure about that '.', however.  It could be escaped
12965e96449SHajimu UMEMOTO          * and thus not a really a label separator.
13065e96449SHajimu UMEMOTO 	 */
13165e96449SHajimu UMEMOTO 	escaped = 0;
13265e96449SHajimu UMEMOTO 	for (i = diff - 2; i >= 0; i--)
13365e96449SHajimu UMEMOTO 		if (a[i] == '\\') {
13465e96449SHajimu UMEMOTO 			if (escaped)
13565e96449SHajimu UMEMOTO 				escaped = 0;
13665e96449SHajimu UMEMOTO 			else
13765e96449SHajimu UMEMOTO 				escaped = 1;
13865e96449SHajimu UMEMOTO 		} else
13965e96449SHajimu UMEMOTO 			break;
14065e96449SHajimu UMEMOTO 	if (escaped)
14165e96449SHajimu UMEMOTO 		return (0);
14265e96449SHajimu UMEMOTO 
14365e96449SHajimu UMEMOTO 	/* Now compare aligned trailing substring. */
14465e96449SHajimu UMEMOTO 	cp = a + diff;
14565e96449SHajimu UMEMOTO 	return (strncasecmp(cp, b, lb) == 0);
14665e96449SHajimu UMEMOTO }
14765e96449SHajimu UMEMOTO 
148d808369aSHajimu UMEMOTO #ifndef _LIBC
149dde4a85dSHajimu UMEMOTO /*%
15065e96449SHajimu UMEMOTO  *	is "a" a subdomain of "b"?
15165e96449SHajimu UMEMOTO  */
15265e96449SHajimu UMEMOTO int
15365e96449SHajimu UMEMOTO ns_subdomain(const char *a, const char *b) {
15465e96449SHajimu UMEMOTO 	return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
15565e96449SHajimu UMEMOTO }
156ab96eeabSHajimu UMEMOTO #endif
15765e96449SHajimu UMEMOTO 
158dde4a85dSHajimu UMEMOTO /*%
15965e96449SHajimu UMEMOTO  *	make a canonical copy of domain name "src"
160dde4a85dSHajimu UMEMOTO  *
16165e96449SHajimu UMEMOTO  * notes:
162dde4a85dSHajimu UMEMOTO  * \code
16365e96449SHajimu UMEMOTO  *	foo -> foo.
16465e96449SHajimu UMEMOTO  *	foo. -> foo.
16565e96449SHajimu UMEMOTO  *	foo.. -> foo.
16665e96449SHajimu UMEMOTO  *	foo\. -> foo\..
16765e96449SHajimu UMEMOTO  *	foo\\. -> foo\\.
168dde4a85dSHajimu UMEMOTO  * \endcode
16965e96449SHajimu UMEMOTO  */
17065e96449SHajimu UMEMOTO 
17165e96449SHajimu UMEMOTO int
17265e96449SHajimu UMEMOTO ns_makecanon(const char *src, char *dst, size_t dstsize) {
17365e96449SHajimu UMEMOTO 	size_t n = strlen(src);
17465e96449SHajimu UMEMOTO 
175dde4a85dSHajimu UMEMOTO 	if (n + sizeof "." > dstsize) {			/*%< Note: sizeof == 2 */
17665e96449SHajimu UMEMOTO 		errno = EMSGSIZE;
17765e96449SHajimu UMEMOTO 		return (-1);
17865e96449SHajimu UMEMOTO 	}
17965e96449SHajimu UMEMOTO 	strcpy(dst, src);
180dde4a85dSHajimu UMEMOTO 	while (n >= 1U && dst[n - 1] == '.')		/*%< Ends in "." */
181dde4a85dSHajimu UMEMOTO 		if (n >= 2U && dst[n - 2] == '\\' &&	/*%< Ends in "\." */
182dde4a85dSHajimu UMEMOTO 		    (n < 3U || dst[n - 3] != '\\'))	/*%< But not "\\." */
18365e96449SHajimu UMEMOTO 			break;
18465e96449SHajimu UMEMOTO 		else
18565e96449SHajimu UMEMOTO 			dst[--n] = '\0';
18665e96449SHajimu UMEMOTO 	dst[n++] = '.';
18765e96449SHajimu UMEMOTO 	dst[n] = '\0';
18865e96449SHajimu UMEMOTO 	return (0);
18965e96449SHajimu UMEMOTO }
19065e96449SHajimu UMEMOTO 
191dde4a85dSHajimu UMEMOTO /*%
19265e96449SHajimu UMEMOTO  *	determine whether domain name "a" is the same as domain name "b"
193dde4a85dSHajimu UMEMOTO  *
19465e96449SHajimu UMEMOTO  * return:
195dde4a85dSHajimu UMEMOTO  *\li	-1 on error
196dde4a85dSHajimu UMEMOTO  *\li	0 if names differ
197dde4a85dSHajimu UMEMOTO  *\li	1 if names are the same
19865e96449SHajimu UMEMOTO  */
19965e96449SHajimu UMEMOTO 
20065e96449SHajimu UMEMOTO int
20165e96449SHajimu UMEMOTO ns_samename(const char *a, const char *b) {
20265e96449SHajimu UMEMOTO 	char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
20365e96449SHajimu UMEMOTO 
20465e96449SHajimu UMEMOTO 	if (ns_makecanon(a, ta, sizeof ta) < 0 ||
20565e96449SHajimu UMEMOTO 	    ns_makecanon(b, tb, sizeof tb) < 0)
20665e96449SHajimu UMEMOTO 		return (-1);
20765e96449SHajimu UMEMOTO 	if (strcasecmp(ta, tb) == 0)
20865e96449SHajimu UMEMOTO 		return (1);
20965e96449SHajimu UMEMOTO 	else
21065e96449SHajimu UMEMOTO 		return (0);
21165e96449SHajimu UMEMOTO }
212dde4a85dSHajimu UMEMOTO 
213dde4a85dSHajimu UMEMOTO /*! \file */
214