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