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