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