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