| /* $NetBSD: ns_samedomain.c,v 1.2 2004/05/20 20:35:05 christos Exp $ */ |
| |
| /* |
| * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") |
| * Copyright (c) 1995,1999 by Internet Software Consortium. |
| * |
| * Permission to use, copy, modify, and distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
| * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include <sys/cdefs.h> |
| #ifndef lint |
| #ifdef notdef |
| static const char rcsid[] = "Id: ns_samedomain.c,v 1.1.2.2.4.2 2004/03/16 12:34:17 marka Exp"; |
| #else |
| __RCSID("$NetBSD: ns_samedomain.c,v 1.2 2004/05/20 20:35:05 christos Exp $"); |
| #endif |
| #endif |
| |
| #include <sys/types.h> |
| #include "arpa_nameser.h" |
| #include <errno.h> |
| #include <string.h> |
| |
| #ifndef _LIBC |
| /* |
| * int |
| * ns_samedomain(a, b) |
| * Check whether a name belongs to a domain. |
| * Inputs: |
| * a - the domain whose ancestory is being verified |
| * b - the potential ancestor we're checking against |
| * Return: |
| * boolean - is a at or below b? |
| * Notes: |
| * Trailing dots are first removed from name and domain. |
| * Always compare complete subdomains, not only whether the |
| * domain name is the trailing string of the given name. |
| * |
| * "host.foobar.top" lies in "foobar.top" and in "top" and in "" |
| * but NOT in "bar.top" |
| */ |
| |
| int |
| ns_samedomain(const char *a, const char *b) { |
| size_t la, lb; |
| int diff, i, escaped; |
| const char *cp; |
| |
| la = strlen(a); |
| lb = strlen(b); |
| |
| /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ |
| if (la != 0U && a[la - 1] == '.') { |
| escaped = 0; |
| /* Note this loop doesn't get executed if la==1. */ |
| for (i = la - 2; i >= 0; i--) |
| if (a[i] == '\\') { |
| if (escaped) |
| escaped = 0; |
| else |
| escaped = 1; |
| } else |
| break; |
| if (!escaped) |
| la--; |
| } |
| |
| /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ |
| if (lb != 0U && b[lb - 1] == '.') { |
| escaped = 0; |
| /* note this loop doesn't get executed if lb==1 */ |
| for (i = lb - 2; i >= 0; i--) |
| if (b[i] == '\\') { |
| if (escaped) |
| escaped = 0; |
| else |
| escaped = 1; |
| } else |
| break; |
| if (!escaped) |
| lb--; |
| } |
| |
| /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ |
| if (lb == 0U) |
| return (1); |
| |
| /* 'b' longer than 'a' means 'a' can't be in 'b'. */ |
| if (lb > la) |
| return (0); |
| |
| /* 'a' and 'b' being equal at this point indicates sameness. */ |
| if (lb == la) |
| return (strncasecmp(a, b, lb) == 0); |
| |
| /* Ok, we know la > lb. */ |
| |
| diff = la - lb; |
| |
| /* |
| * If 'a' is only 1 character longer than 'b', then it can't be |
| * a subdomain of 'b' (because of the need for the '.' label |
| * separator). |
| */ |
| if (diff < 2) |
| return (0); |
| |
| /* |
| * If the character before the last 'lb' characters of 'b' |
| * isn't '.', then it can't be a match (this lets us avoid |
| * having "foobar.com" match "bar.com"). |
| */ |
| if (a[diff - 1] != '.') |
| return (0); |
| |
| /* |
| * We're not sure about that '.', however. It could be escaped |
| * and thus not a really a label separator. |
| */ |
| escaped = 0; |
| for (i = diff - 2; i >= 0; i--) |
| if (a[i] == '\\') { |
| if (escaped) |
| escaped = 0; |
| else |
| escaped = 1; |
| } else |
| break; |
| if (escaped) |
| return (0); |
| |
| /* Now compare aligned trailing substring. */ |
| cp = a + diff; |
| return (strncasecmp(cp, b, lb) == 0); |
| } |
| |
| /* |
| * int |
| * ns_subdomain(a, b) |
| * is "a" a subdomain of "b"? |
| */ |
| int |
| ns_subdomain(const char *a, const char *b) { |
| return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); |
| } |
| #endif |
| |
| /* |
| * int |
| * ns_makecanon(src, dst, dstsize) |
| * make a canonical copy of domain name "src" |
| * notes: |
| * foo -> foo. |
| * foo. -> foo. |
| * foo.. -> foo. |
| * foo\. -> foo\.. |
| * foo\\. -> foo\\. |
| */ |
| |
| int |
| ns_makecanon(const char *src, char *dst, size_t dstsize) { |
| size_t n = strlen(src); |
| |
| if (n + sizeof "." > dstsize) { /* Note: sizeof == 2 */ |
| errno = EMSGSIZE; |
| return (-1); |
| } |
| strcpy(dst, src); |
| while (n >= 1U && dst[n - 1] == '.') /* Ends in "." */ |
| if (n >= 2U && dst[n - 2] == '\\' && /* Ends in "\." */ |
| (n < 3U || dst[n - 3] != '\\')) /* But not "\\." */ |
| break; |
| else |
| dst[--n] = '\0'; |
| dst[n++] = '.'; |
| dst[n] = '\0'; |
| return (0); |
| } |
| |
| /* |
| * int |
| * ns_samename(a, b) |
| * determine whether domain name "a" is the same as domain name "b" |
| * return: |
| * -1 on error |
| * 0 if names differ |
| * 1 if names are the same |
| */ |
| |
| int |
| ns_samename(const char *a, const char *b) { |
| char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; |
| |
| if (ns_makecanon(a, ta, sizeof ta) < 0 || |
| ns_makecanon(b, tb, sizeof tb) < 0) |
| return (-1); |
| if (strcasecmp(ta, tb) == 0) |
| return (1); |
| else |
| return (0); |
| } |