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