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