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