/* * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels * * SQUID Web Proxy Cache http://www.squid-cache.org/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from * the Internet community; see the CONTRIBUTORS file for full * details. Many organizations have provided support for Squid's * development; see the SPONSORS file for full details. Squid is * Copyrighted (C) 2001 by the Regents of the University of * California; see the COPYRIGHT file for full details. Squid * incorporates software developed and/or copyrighted by other * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * * * Copyright (c) 2003, Robert Collins */ #include "squid.h" #include "acl/DomainData.h" #include "acl/Checklist.h" #include "cache_cf.h" #include "Debug.h" #include "wordlist.h" #include "src/URL.h" template inline void xRefFree(T &thing) { xfree (thing); } ACLDomainData::~ACLDomainData() { if (domains) domains->destroy(xRefFree); } template inline int splaystrcasecmp (T&l, T&r) { return strcasecmp ((char *)l,(char *)r); } template inline int splaystrcmp (T&l, T&r) { return strcmp ((char *)l,(char *)r); } /* general compare functions, these are used for tree search algorithms * so they return <0, 0 or >0 */ /* compare a host and a domain */ static int aclHostDomainCompare( char *const &a, char * const &b) { const char *h = static_cast(a); const char *d = static_cast(b); return matchDomainName(h, d); } /* compare two domains */ template int aclDomainCompare(T const &a, T const &b) { char * const d1 = static_cast(b); char * const d2 = static_cast(a); int ret; ret = aclHostDomainCompare(d1, d2); if (ret != 0) { char *const d3 = d2; char *const d4 = d1; ret = aclHostDomainCompare(d3, d4); if (ret == 0) { // When a.example.com comes after .example.com in an ACL // sub-domain is ignored. That is okay. Just important bool d3big = (strlen(d3) > strlen(d4)); // Always suggest removing the longer one. debugs(28, DBG_IMPORTANT, "WARNING: '" << (d3big?d3:d4) << "' is a subdomain of '" << (d3big?d4:d3) << "'"); debugs(28, DBG_IMPORTANT, "WARNING: You should remove '" << (d3big?d3:d4) << "' from the ACL named '" << AclMatchedName << "'"); debugs(28, 2, HERE << "Ignore '" << d3 << "' to keep splay tree searching predictable"); } } else if (ret == 0) { // It may be an exact duplicate. No problem. Just drop. if (strcmp(d1,d2)==0) { debugs(28, 2, "WARNING: '" << d2 << "' is duplicated in the list."); debugs(28, 2, "WARNING: You should remove one '" << d2 << "' from the ACL named '" << AclMatchedName << "'"); return ret; } // When a.example.com comes before .example.com in an ACL // discarding the wildcard is critically bad. // or Maybe even both are wildcards. Things are very weird in those cases. bool d1big = (strlen(d1) > strlen(d2)); // Always suggest removing the longer one. debugs(28, DBG_CRITICAL, "ERROR: '" << (d1big?d1:d2) << "' is a subdomain of '" << (d1big?d2:d1) << "'"); debugs(28, DBG_CRITICAL, "ERROR: You need to remove '" << (d1big?d1:d2) << "' from the ACL named '" << AclMatchedName << "'"); self_destruct(); } return ret; } bool ACLDomainData::match(char const *host) { if (host == NULL) return 0; debugs(28, 3, "aclMatchDomainList: checking '" << host << "'"); domains = domains->splay((char *)host, aclHostDomainCompare); debugs(28, 3, "aclMatchDomainList: '" << host << "' " << (splayLastResult ? "NOT found" : "found")); return !splayLastResult; } static void aclDumpDomainListWalkee(char * const & node_data, void *outlist) { /* outlist is really a wordlist ** */ wordlistAdd((wordlist **)outlist, (char const *)node_data); } wordlist * ACLDomainData::dump() { wordlist *wl = NULL; /* damn this is VERY inefficient for long ACL lists... filling * a wordlist this way costs Sum(1,N) iterations. For instance * a 1000-elements list will be filled in 499500 iterations. */ domains->walk(aclDumpDomainListWalkee, &wl); return wl; } void ACLDomainData::parse() { char *t = NULL; while ((t = strtokFile())) { Tolower(t); domains = domains->insert(xstrdup(t), aclDomainCompare); } } bool ACLDomainData::empty() const { return domains->empty(); } ACLData * ACLDomainData::clone() const { /* Splay trees don't clone yet. */ assert (!domains); return new ACLDomainData; }