16e778a7eSPedro F. Giffuni /*- 26e778a7eSPedro F. Giffuni * SPDX-License-Identifier: ISC 36e778a7eSPedro F. Giffuni * 465e96449SHajimu UMEMOTO * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 565e96449SHajimu UMEMOTO * Copyright (c) 1995,1999 by Internet Software Consortium. 665e96449SHajimu UMEMOTO * 765e96449SHajimu UMEMOTO * Permission to use, copy, modify, and distribute this software for any 865e96449SHajimu UMEMOTO * purpose with or without fee is hereby granted, provided that the above 965e96449SHajimu UMEMOTO * copyright notice and this permission notice appear in all copies. 1065e96449SHajimu UMEMOTO * 1165e96449SHajimu UMEMOTO * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 1265e96449SHajimu UMEMOTO * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1365e96449SHajimu UMEMOTO * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 1465e96449SHajimu UMEMOTO * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1565e96449SHajimu UMEMOTO * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1665e96449SHajimu UMEMOTO * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 1765e96449SHajimu UMEMOTO * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1865e96449SHajimu UMEMOTO */ 1965e96449SHajimu UMEMOTO 2065e96449SHajimu UMEMOTO #ifndef lint 21046c3635SPedro F. Giffuni static const char rcsid[] = "$Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp $"; 2265e96449SHajimu UMEMOTO #endif 23ab96eeabSHajimu UMEMOTO #include <sys/cdefs.h> 24ab96eeabSHajimu UMEMOTO __FBSDID("$FreeBSD$"); 2565e96449SHajimu UMEMOTO 2665e96449SHajimu UMEMOTO #include "port_before.h" 2765e96449SHajimu UMEMOTO 2865e96449SHajimu UMEMOTO #include <sys/types.h> 2965e96449SHajimu UMEMOTO #include <arpa/nameser.h> 3065e96449SHajimu UMEMOTO #include <errno.h> 3165e96449SHajimu UMEMOTO #include <string.h> 3265e96449SHajimu UMEMOTO 3365e96449SHajimu UMEMOTO #include "port_after.h" 3465e96449SHajimu UMEMOTO 35dde4a85dSHajimu UMEMOTO /*% 3665e96449SHajimu UMEMOTO * Check whether a name belongs to a domain. 37dde4a85dSHajimu UMEMOTO * 3865e96449SHajimu UMEMOTO * Inputs: 3932223c1bSPedro F. Giffuni *\li a - the domain whose ancestry is being verified 40dde4a85dSHajimu UMEMOTO *\li b - the potential ancestor we're checking against 41dde4a85dSHajimu UMEMOTO * 4265e96449SHajimu UMEMOTO * Return: 43dde4a85dSHajimu UMEMOTO *\li boolean - is a at or below b? 44dde4a85dSHajimu UMEMOTO * 4565e96449SHajimu UMEMOTO * Notes: 46dde4a85dSHajimu UMEMOTO *\li Trailing dots are first removed from name and domain. 4765e96449SHajimu UMEMOTO * Always compare complete subdomains, not only whether the 4865e96449SHajimu UMEMOTO * domain name is the trailing string of the given name. 4965e96449SHajimu UMEMOTO * 50dde4a85dSHajimu UMEMOTO *\li "host.foobar.top" lies in "foobar.top" and in "top" and in "" 5165e96449SHajimu UMEMOTO * but NOT in "bar.top" 5265e96449SHajimu UMEMOTO */ 5365e96449SHajimu UMEMOTO 5465e96449SHajimu UMEMOTO int 5565e96449SHajimu UMEMOTO ns_samedomain(const char *a, const char *b) { 5665e96449SHajimu UMEMOTO size_t la, lb; 5765e96449SHajimu UMEMOTO int diff, i, escaped; 5865e96449SHajimu UMEMOTO const char *cp; 5965e96449SHajimu UMEMOTO 6065e96449SHajimu UMEMOTO la = strlen(a); 6165e96449SHajimu UMEMOTO lb = strlen(b); 6265e96449SHajimu UMEMOTO 6365e96449SHajimu UMEMOTO /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ 6465e96449SHajimu UMEMOTO if (la != 0U && a[la - 1] == '.') { 6565e96449SHajimu UMEMOTO escaped = 0; 6665e96449SHajimu UMEMOTO /* Note this loop doesn't get executed if la==1. */ 6765e96449SHajimu UMEMOTO for (i = la - 2; i >= 0; i--) 6865e96449SHajimu UMEMOTO if (a[i] == '\\') { 6965e96449SHajimu UMEMOTO if (escaped) 7065e96449SHajimu UMEMOTO escaped = 0; 7165e96449SHajimu UMEMOTO else 7265e96449SHajimu UMEMOTO escaped = 1; 7365e96449SHajimu UMEMOTO } else 7465e96449SHajimu UMEMOTO break; 7565e96449SHajimu UMEMOTO if (!escaped) 7665e96449SHajimu UMEMOTO la--; 7765e96449SHajimu UMEMOTO } 7865e96449SHajimu UMEMOTO 7965e96449SHajimu UMEMOTO /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ 8065e96449SHajimu UMEMOTO if (lb != 0U && b[lb - 1] == '.') { 8165e96449SHajimu UMEMOTO escaped = 0; 8265e96449SHajimu UMEMOTO /* note this loop doesn't get executed if lb==1 */ 8365e96449SHajimu UMEMOTO for (i = lb - 2; i >= 0; i--) 8465e96449SHajimu UMEMOTO if (b[i] == '\\') { 8565e96449SHajimu UMEMOTO if (escaped) 8665e96449SHajimu UMEMOTO escaped = 0; 8765e96449SHajimu UMEMOTO else 8865e96449SHajimu UMEMOTO escaped = 1; 8965e96449SHajimu UMEMOTO } else 9065e96449SHajimu UMEMOTO break; 9165e96449SHajimu UMEMOTO if (!escaped) 9265e96449SHajimu UMEMOTO lb--; 9365e96449SHajimu UMEMOTO } 9465e96449SHajimu UMEMOTO 9565e96449SHajimu UMEMOTO /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ 9665e96449SHajimu UMEMOTO if (lb == 0U) 9765e96449SHajimu UMEMOTO return (1); 9865e96449SHajimu UMEMOTO 9965e96449SHajimu UMEMOTO /* 'b' longer than 'a' means 'a' can't be in 'b'. */ 10065e96449SHajimu UMEMOTO if (lb > la) 10165e96449SHajimu UMEMOTO return (0); 10265e96449SHajimu UMEMOTO 10365e96449SHajimu UMEMOTO /* 'a' and 'b' being equal at this point indicates sameness. */ 10465e96449SHajimu UMEMOTO if (lb == la) 10565e96449SHajimu UMEMOTO return (strncasecmp(a, b, lb) == 0); 10665e96449SHajimu UMEMOTO 10765e96449SHajimu UMEMOTO /* Ok, we know la > lb. */ 10865e96449SHajimu UMEMOTO 10965e96449SHajimu UMEMOTO diff = la - lb; 11065e96449SHajimu UMEMOTO 11165e96449SHajimu UMEMOTO /* 11265e96449SHajimu UMEMOTO * If 'a' is only 1 character longer than 'b', then it can't be 11365e96449SHajimu UMEMOTO * a subdomain of 'b' (because of the need for the '.' label 11465e96449SHajimu UMEMOTO * separator). 11565e96449SHajimu UMEMOTO */ 11665e96449SHajimu UMEMOTO if (diff < 2) 11765e96449SHajimu UMEMOTO return (0); 11865e96449SHajimu UMEMOTO 11965e96449SHajimu UMEMOTO /* 12065e96449SHajimu UMEMOTO * If the character before the last 'lb' characters of 'b' 12165e96449SHajimu UMEMOTO * isn't '.', then it can't be a match (this lets us avoid 12265e96449SHajimu UMEMOTO * having "foobar.com" match "bar.com"). 12365e96449SHajimu UMEMOTO */ 12465e96449SHajimu UMEMOTO if (a[diff - 1] != '.') 12565e96449SHajimu UMEMOTO return (0); 12665e96449SHajimu UMEMOTO 12765e96449SHajimu UMEMOTO /* 12865e96449SHajimu UMEMOTO * We're not sure about that '.', however. It could be escaped 12965e96449SHajimu UMEMOTO * and thus not a really a label separator. 13065e96449SHajimu UMEMOTO */ 13165e96449SHajimu UMEMOTO escaped = 0; 13265e96449SHajimu UMEMOTO for (i = diff - 2; i >= 0; i--) 13365e96449SHajimu UMEMOTO if (a[i] == '\\') { 13465e96449SHajimu UMEMOTO if (escaped) 13565e96449SHajimu UMEMOTO escaped = 0; 13665e96449SHajimu UMEMOTO else 13765e96449SHajimu UMEMOTO escaped = 1; 13865e96449SHajimu UMEMOTO } else 13965e96449SHajimu UMEMOTO break; 14065e96449SHajimu UMEMOTO if (escaped) 14165e96449SHajimu UMEMOTO return (0); 14265e96449SHajimu UMEMOTO 14365e96449SHajimu UMEMOTO /* Now compare aligned trailing substring. */ 14465e96449SHajimu UMEMOTO cp = a + diff; 14565e96449SHajimu UMEMOTO return (strncasecmp(cp, b, lb) == 0); 14665e96449SHajimu UMEMOTO } 14765e96449SHajimu UMEMOTO 148d808369aSHajimu UMEMOTO #ifndef _LIBC 149dde4a85dSHajimu UMEMOTO /*% 15065e96449SHajimu UMEMOTO * is "a" a subdomain of "b"? 15165e96449SHajimu UMEMOTO */ 15265e96449SHajimu UMEMOTO int 15365e96449SHajimu UMEMOTO ns_subdomain(const char *a, const char *b) { 15465e96449SHajimu UMEMOTO return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); 15565e96449SHajimu UMEMOTO } 156ab96eeabSHajimu UMEMOTO #endif 15765e96449SHajimu UMEMOTO 158dde4a85dSHajimu UMEMOTO /*% 15965e96449SHajimu UMEMOTO * make a canonical copy of domain name "src" 160dde4a85dSHajimu UMEMOTO * 16165e96449SHajimu UMEMOTO * notes: 162dde4a85dSHajimu UMEMOTO * \code 16365e96449SHajimu UMEMOTO * foo -> foo. 16465e96449SHajimu UMEMOTO * foo. -> foo. 16565e96449SHajimu UMEMOTO * foo.. -> foo. 16665e96449SHajimu UMEMOTO * foo\. -> foo\.. 16765e96449SHajimu UMEMOTO * foo\\. -> foo\\. 168dde4a85dSHajimu UMEMOTO * \endcode 16965e96449SHajimu UMEMOTO */ 17065e96449SHajimu UMEMOTO 17165e96449SHajimu UMEMOTO int 17265e96449SHajimu UMEMOTO ns_makecanon(const char *src, char *dst, size_t dstsize) { 17365e96449SHajimu UMEMOTO size_t n = strlen(src); 17465e96449SHajimu UMEMOTO 175dde4a85dSHajimu UMEMOTO if (n + sizeof "." > dstsize) { /*%< Note: sizeof == 2 */ 17665e96449SHajimu UMEMOTO errno = EMSGSIZE; 17765e96449SHajimu UMEMOTO return (-1); 17865e96449SHajimu UMEMOTO } 17965e96449SHajimu UMEMOTO strcpy(dst, src); 180dde4a85dSHajimu UMEMOTO while (n >= 1U && dst[n - 1] == '.') /*%< Ends in "." */ 181dde4a85dSHajimu UMEMOTO if (n >= 2U && dst[n - 2] == '\\' && /*%< Ends in "\." */ 182dde4a85dSHajimu UMEMOTO (n < 3U || dst[n - 3] != '\\')) /*%< But not "\\." */ 18365e96449SHajimu UMEMOTO break; 18465e96449SHajimu UMEMOTO else 18565e96449SHajimu UMEMOTO dst[--n] = '\0'; 18665e96449SHajimu UMEMOTO dst[n++] = '.'; 18765e96449SHajimu UMEMOTO dst[n] = '\0'; 18865e96449SHajimu UMEMOTO return (0); 18965e96449SHajimu UMEMOTO } 19065e96449SHajimu UMEMOTO 191dde4a85dSHajimu UMEMOTO /*% 19265e96449SHajimu UMEMOTO * determine whether domain name "a" is the same as domain name "b" 193dde4a85dSHajimu UMEMOTO * 19465e96449SHajimu UMEMOTO * return: 195dde4a85dSHajimu UMEMOTO *\li -1 on error 196dde4a85dSHajimu UMEMOTO *\li 0 if names differ 197dde4a85dSHajimu UMEMOTO *\li 1 if names are the same 19865e96449SHajimu UMEMOTO */ 19965e96449SHajimu UMEMOTO 20065e96449SHajimu UMEMOTO int 20165e96449SHajimu UMEMOTO ns_samename(const char *a, const char *b) { 20265e96449SHajimu UMEMOTO char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; 20365e96449SHajimu UMEMOTO 20465e96449SHajimu UMEMOTO if (ns_makecanon(a, ta, sizeof ta) < 0 || 20565e96449SHajimu UMEMOTO ns_makecanon(b, tb, sizeof tb) < 0) 20665e96449SHajimu UMEMOTO return (-1); 20765e96449SHajimu UMEMOTO if (strcasecmp(ta, tb) == 0) 20865e96449SHajimu UMEMOTO return (1); 20965e96449SHajimu UMEMOTO else 21065e96449SHajimu UMEMOTO return (0); 21165e96449SHajimu UMEMOTO } 212dde4a85dSHajimu UMEMOTO 213dde4a85dSHajimu UMEMOTO /*! \file */ 214