1156952Sume/* 2156952Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3156952Sume * Copyright (c) 1995,1999 by Internet Software Consortium. 4156952Sume * 5156952Sume * Permission to use, copy, modify, and distribute this software for any 6156952Sume * purpose with or without fee is hereby granted, provided that the above 7156952Sume * copyright notice and this permission notice appear in all copies. 8156952Sume * 9156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11156952Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16156952Sume */ 17156952Sume 18156952Sume#ifndef lint 19170244Sumestatic const char rcsid[] = "$Id: ns_samedomain.c,v 1.5.18.1 2005/04/27 05:01:09 sra Exp $"; 20156952Sume#endif 21156956Sume#include <sys/cdefs.h> 22156956Sume__FBSDID("$FreeBSD$"); 23156952Sume 24156952Sume#include "port_before.h" 25156952Sume 26156952Sume#include <sys/types.h> 27156952Sume#include <arpa/nameser.h> 28156952Sume#include <errno.h> 29156952Sume#include <string.h> 30156952Sume 31156952Sume#include "port_after.h" 32156952Sume 33170244Sume/*% 34156952Sume * Check whether a name belongs to a domain. 35170244Sume * 36156952Sume * Inputs: 37170244Sume *\li a - the domain whose ancestory is being verified 38170244Sume *\li b - the potential ancestor we're checking against 39170244Sume * 40156952Sume * Return: 41170244Sume *\li boolean - is a at or below b? 42170244Sume * 43156952Sume * Notes: 44170244Sume *\li Trailing dots are first removed from name and domain. 45156952Sume * Always compare complete subdomains, not only whether the 46156952Sume * domain name is the trailing string of the given name. 47156952Sume * 48170244Sume *\li "host.foobar.top" lies in "foobar.top" and in "top" and in "" 49156952Sume * but NOT in "bar.top" 50156952Sume */ 51156952Sume 52156952Sumeint 53156952Sumens_samedomain(const char *a, const char *b) { 54156952Sume size_t la, lb; 55156952Sume int diff, i, escaped; 56156952Sume const char *cp; 57156952Sume 58156952Sume la = strlen(a); 59156952Sume lb = strlen(b); 60156952Sume 61156952Sume /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ 62156952Sume if (la != 0U && a[la - 1] == '.') { 63156952Sume escaped = 0; 64156952Sume /* Note this loop doesn't get executed if la==1. */ 65156952Sume for (i = la - 2; i >= 0; i--) 66156952Sume if (a[i] == '\\') { 67156952Sume if (escaped) 68156952Sume escaped = 0; 69156952Sume else 70156952Sume escaped = 1; 71156952Sume } else 72156952Sume break; 73156952Sume if (!escaped) 74156952Sume la--; 75156952Sume } 76156952Sume 77156952Sume /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ 78156952Sume if (lb != 0U && b[lb - 1] == '.') { 79156952Sume escaped = 0; 80156952Sume /* note this loop doesn't get executed if lb==1 */ 81156952Sume for (i = lb - 2; i >= 0; i--) 82156952Sume if (b[i] == '\\') { 83156952Sume if (escaped) 84156952Sume escaped = 0; 85156952Sume else 86156952Sume escaped = 1; 87156952Sume } else 88156952Sume break; 89156952Sume if (!escaped) 90156952Sume lb--; 91156952Sume } 92156952Sume 93156952Sume /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ 94156952Sume if (lb == 0U) 95156952Sume return (1); 96156952Sume 97156952Sume /* 'b' longer than 'a' means 'a' can't be in 'b'. */ 98156952Sume if (lb > la) 99156952Sume return (0); 100156952Sume 101156952Sume /* 'a' and 'b' being equal at this point indicates sameness. */ 102156952Sume if (lb == la) 103156952Sume return (strncasecmp(a, b, lb) == 0); 104156952Sume 105156952Sume /* Ok, we know la > lb. */ 106156952Sume 107156952Sume diff = la - lb; 108156952Sume 109156952Sume /* 110156952Sume * If 'a' is only 1 character longer than 'b', then it can't be 111156952Sume * a subdomain of 'b' (because of the need for the '.' label 112156952Sume * separator). 113156952Sume */ 114156952Sume if (diff < 2) 115156952Sume return (0); 116156952Sume 117156952Sume /* 118156952Sume * If the character before the last 'lb' characters of 'b' 119156952Sume * isn't '.', then it can't be a match (this lets us avoid 120156952Sume * having "foobar.com" match "bar.com"). 121156952Sume */ 122156952Sume if (a[diff - 1] != '.') 123156952Sume return (0); 124156952Sume 125156952Sume /* 126156952Sume * We're not sure about that '.', however. It could be escaped 127156952Sume * and thus not a really a label separator. 128156952Sume */ 129156952Sume escaped = 0; 130156952Sume for (i = diff - 2; i >= 0; i--) 131156952Sume if (a[i] == '\\') { 132156952Sume if (escaped) 133156952Sume escaped = 0; 134156952Sume else 135156952Sume escaped = 1; 136156952Sume } else 137156952Sume break; 138156952Sume if (escaped) 139156952Sume return (0); 140156952Sume 141156952Sume /* Now compare aligned trailing substring. */ 142156952Sume cp = a + diff; 143156952Sume return (strncasecmp(cp, b, lb) == 0); 144156952Sume} 145156952Sume 146158787Sume#ifndef _LIBC 147170244Sume/*% 148156952Sume * is "a" a subdomain of "b"? 149156952Sume */ 150156952Sumeint 151156952Sumens_subdomain(const char *a, const char *b) { 152156952Sume return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); 153156952Sume} 154156956Sume#endif 155156952Sume 156170244Sume/*% 157156952Sume * make a canonical copy of domain name "src" 158170244Sume * 159156952Sume * notes: 160170244Sume * \code 161156952Sume * foo -> foo. 162156952Sume * foo. -> foo. 163156952Sume * foo.. -> foo. 164156952Sume * foo\. -> foo\.. 165156952Sume * foo\\. -> foo\\. 166170244Sume * \endcode 167156952Sume */ 168156952Sume 169156952Sumeint 170156952Sumens_makecanon(const char *src, char *dst, size_t dstsize) { 171156952Sume size_t n = strlen(src); 172156952Sume 173170244Sume if (n + sizeof "." > dstsize) { /*%< Note: sizeof == 2 */ 174156952Sume errno = EMSGSIZE; 175156952Sume return (-1); 176156952Sume } 177156952Sume strcpy(dst, src); 178170244Sume while (n >= 1U && dst[n - 1] == '.') /*%< Ends in "." */ 179170244Sume if (n >= 2U && dst[n - 2] == '\\' && /*%< Ends in "\." */ 180170244Sume (n < 3U || dst[n - 3] != '\\')) /*%< But not "\\." */ 181156952Sume break; 182156952Sume else 183156952Sume dst[--n] = '\0'; 184156952Sume dst[n++] = '.'; 185156952Sume dst[n] = '\0'; 186156952Sume return (0); 187156952Sume} 188156952Sume 189170244Sume/*% 190156952Sume * determine whether domain name "a" is the same as domain name "b" 191170244Sume * 192156952Sume * return: 193170244Sume *\li -1 on error 194170244Sume *\li 0 if names differ 195170244Sume *\li 1 if names are the same 196156952Sume */ 197156952Sume 198156952Sumeint 199156952Sumens_samename(const char *a, const char *b) { 200156952Sume char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; 201156952Sume 202156952Sume if (ns_makecanon(a, ta, sizeof ta) < 0 || 203156952Sume ns_makecanon(b, tb, sizeof tb) < 0) 204156952Sume return (-1); 205156952Sume if (strcasecmp(ta, tb) == 0) 206156952Sume return (1); 207156952Sume else 208156952Sume return (0); 209156952Sume} 210170244Sume 211170244Sume/*! \file */ 212