This patch is generated from the generic_modules branch of HEAD in squid Wed Sep 29 01:31:10 2004 GMT See http://devel.squid-cache.org/ Index: squid/acconfig.h diff -u squid/acconfig.h:1.8 squid/acconfig.h:1.4.18.3 --- squid/acconfig.h:1.8 Sat Apr 14 06:06:33 2001 +++ squid/acconfig.h Fri Apr 27 07:24:55 2001 @@ -110,13 +110,6 @@ #undef ALARM_UPDATES_TIME /* - * Define this to include code which lets you specify access control - * elements based on ethernet hardware addresses. This code uses - * functions found in 4.4 BSD derviations (e.g. FreeBSD, ?). - */ -#undef USE_ARP_ACL - -/* * Define this to include code for the Hypertext Cache Protocol (HTCP) */ #undef USE_HTCP Index: squid/configure.in diff -u squid/configure.in:1.21 squid/configure.in:1.17.4.6 --- squid/configure.in:1.21 Sat May 5 13:47:58 2001 +++ squid/configure.in Sat May 12 06:06:03 2001 @@ -492,7 +492,7 @@ sleep 10 ;; esac - AC_DEFINE(USE_ARP_ACL) + CONF_MODULES="$CONF_MODULES acl_arp" fi ]) @@ -864,6 +864,37 @@ fi AC_SUBST(DIGEST_AUTH_HELPERS) +dnl Select generic modules to build +dnl we may inherit preset CONF_MODULES from AUTH & FS & REPL above +AC_ARG_ENABLE(modules, +[ --enable-modules=\"list of modules\" + This option selects which generic modules to build. + Generic modules can plugin into several parts of squid + and autoregister their capabilities with squid. For a list + of available modules see the src/modules directory.], +[ case "$enableval" in + yes) + for module in $srcdir/src/modules/*; do + if test -f $module/Makefile.in; then + CONF_MODULES="$CONF_MODULES `basename $module`" + fi + done + ;; + no) + ;; + *) + CONF_MODULES="$CONF_MODULES `echo $enableval|sed -e 's/,/ /g;s/ */ /g'`" + esac +]) +if test -n "$CONF_MODULES"; then + echo "Generic modules built: $CONF_MODULES" + AC_SUBST(CONF_MODULES) + CONF_MODULE_OBJS="modules/`echo $CONF_MODULES|sed -e's% %.a modules/%g'`.a" + AC_SUBST(CONF_MODULE_OBJS) + CONF_MODULE_LIBS="`echo $CONF_MODULE_OBJS|sed -e's%module/%%g'`" + AC_SUBST(CONF_MODULE_LIBS) +fi + dnl Enable "NTLM fail open" AC_ARG_ENABLE(ntlm-fail-open, [ --enable-ntlm-fail-open Enable NTLM fail open, where a helper that fails one of the @@ -1970,6 +2001,15 @@ fi done +MOD_MAKEFILES="" +for module in `find $srcdir/src/modules -type d -print`; do + if test -f $module/Makefile.in; then + dir=`echo $module | sed -e "s|^$srcdir/||"` + MOD_MAKEFILES="$MOD_MAKEFILES ./$dir/Makefile" + fi +done + + AC_OUTPUT(\ ./makefile \ ./lib/Makefile \ @@ -1984,6 +2024,7 @@ $REPL_MAKEFILES \ ./src/auth/Makefile \ $AUTH_MAKEFILES \ + $MOD_MAKEFILES \ ./contrib/Makefile \ $SNMP_MAKEFILE \ ./icons/Makefile \ Index: squid/doc/debug-sections.txt diff -u squid/doc/debug-sections.txt:1.3 squid/doc/debug-sections.txt:1.3.10.2 --- squid/doc/debug-sections.txt:1.3 Sun Jan 7 15:53:36 2001 +++ squid/doc/debug-sections.txt Wed Feb 14 05:49:21 2001 @@ -86,3 +86,4 @@ section 79 HTTP Meter Header section 80 WCCP section 81 Store Removal/Replacement policy +section 84 Generic Module Routines Index: squid/include/squid_parser.h diff -u /dev/null squid/include/squid_parser.h:1.1.2.3 --- /dev/null Tue Sep 28 18:35:55 2004 +++ squid/include/squid_parser.h Sat Apr 28 04:16:46 2001 @@ -0,0 +1,181 @@ +/* + * $Id$ + * + * * * * * * * * Legal stuff * * * * * * * + * + * (C) 2001 Robert Collins + * + * 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 + * 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. + * + * * * * * * * * Declaration of intents * * * * * * * + * + * Here are defined an interface to squid's runtime-parser which is able + * To manage many of the issues in parsing the config file automaticall. + */ + +/* + +#include "defines.h" +#include "enums.h" +#include "typedefs.h" +#include "structs.h" +#include "protos.h" + +*/ + +#ifndef _SQUID_PARSER_H_ +#define _SQUID_PARSER_H_ + +/* parser types */ +typedef struct _parserTypeNode parserTypeNode; +typedef struct _parserNameNode parserNameNode; +typedef struct _includefile_t includefile_t; +typedef struct _instance_name instance_name; +typedef struct _instance_node instance_node; +typedef void PARSER_PARSE(parserNameNode *, void *); +typedef void PARSER_FREE (parserNameNode *, void *); +/* the next one is different to the cache_cf entries, because it has to be */ +typedef void PARSER_DUMP (StoreEntry *, const char *, void const *const); +typedef void PARSER_DEFAULT_NONE(void *); +typedef void PARSER_NAME_DOCUMENT(void); +typedef int PARSER_POST_PARSE(void); + +struct _includefile_t { + includefile_t * next; + char *filename; +}; + +struct _instance_name { + dlink_node node; + dlink_list instances; + char *namestr; + parserTypeNode *type; + PARSER_DEFAULT_NONE *default_none; + PARSER_NAME_DOCUMENT *documentfunc; + PARSER_POST_PARSE *post_parse_func; +}; + +struct _instance_node { + dlink_node node; + dlink_list *head; + char *namestr; + void *data; + parserNameNode *parserName; + instance_name *name; +}; + +struct _parserTypeNode { + dlink_node node; + const char *typestr; + PARSER_PARSE *parsefunc; + PARSER_FREE *freefunc; + PARSER_DUMP *dumpfunc; + struct { + unsigned int registered:1; + } flags; +}; + +struct _parserNameNode { + dlink_node node; + dlink_list children; + dlink_list *head; + const char *namestr; + parserTypeNode *type; + parserNameNode *parent; + PARSER_DEFAULT_NONE *default_none; + PARSER_NAME_DOCUMENT *documentfunc; + PARSER_POST_PARSE *post_parse_func; + void *location; + struct { + unsigned int registered:1; + } flags; +}; + + +/* + * cache_cf.c + */ +extern void parserAddDocumentOption(const char *option); +extern int parserDoDocument(const char *file_name); +extern int parserReconfigure(const char *file_name); +extern PARSER_FREE free_intlist; +extern int intlistFind(intlist * list, int i); +extern const char *wordlistAdd(wordlist **, const char *); +extern void wordlistAddWl(wordlist **, wordlist *); +extern void wordlistJoin(wordlist **, wordlist **); +extern wordlist *wordlistDup(const wordlist *); +extern void wordlistDestroy(wordlist **); +extern void configFreeMemory(void); +extern void wordlistCat(const wordlist *, MemBuf * mb); +extern void allocate_new_swapdir(cacheSwap *); +extern void self_destruct(void); +extern int GetInteger(void); + +/* extra functions from cache_cf.c useful for lib modules */ +extern void default_line(const char *); +extern PARSER_PARSE parse_int; +extern PARSER_PARSE parse_eol; +extern PARSER_PARSE parse_wordlist; +extern PARSER_PARSE parse_wordlistFromFile; +extern PARSER_FREE free_wordlist; +extern PARSER_DUMP dump_wordlist; +extern void requirePathnameExists(const char *name, const char *path); +extern PARSER_PARSE parse_time_t; + +/* read from a file. Acts like strtok, but reads tokens from a file. */ +extern char * strtokFile(void); + +/* support for dynamic cache types */ +extern void parserRegisterType(const char *, PARSER_PARSE *, PARSER_FREE *, PARSER_DUMP *); +extern void parserDeregisterType(parserTypeNode *); +extern parserTypeNode *parserTypeByName(const char *); +/* name, type */ +extern void parserRegisterName(parserNameNode *, const char *, parserTypeNode *, void *, PARSER_DEFAULT_NONE *, PARSER_NAME_DOCUMENT *, PARSER_POST_PARSE *); +extern void parserDeregisterName(parserNameNode *); +extern parserNameNode *parserNameByName(const char *); + +/* heirarchical parsing */ +//extern void parserRegisterInstanceType(parserNameNode *, const char *, PARSER_PARSE *, PARSER_FREE *, PARSER_DUMP *); + + +void * parserRegisterInstanceName(const char *, parserTypeNode *, PARSER_DEFAULT_NONE *, PARSER_POST_PARSE *); +extern instance_node *InstanceByNameStr(instance_name *, const char *); +extern int parse_directive(parserNameNode *); + +#endif /* _SQUID_PARSER_H_ */ Index: squid/include/version.h diff -u squid/include/version.h:1.4 squid/include/version.h:1.4.30.1 --- squid/include/version.h:1.4 Tue Nov 14 05:03:47 2000 +++ squid/include/version.h Wed Feb 21 02:21:53 2001 @@ -4,7 +4,7 @@ * SQUID_VERSION - String for version id of this distribution */ #ifndef SQUID_VERSION -#define SQUID_VERSION "2.5.DEVEL" +#define SQUID_VERSION "2.5.DEVEL-Modules" #endif #ifndef SQUID_RELEASE_TIME Index: squid/src/Makefile.in diff -u squid/src/Makefile.in:1.10 squid/src/Makefile.in:1.7.4.10 --- squid/src/Makefile.in:1.10 Sat May 5 13:47:38 2001 +++ squid/src/Makefile.in Sat May 12 06:06:03 2001 @@ -18,7 +18,7 @@ srcdir = @srcdir@ VPATH = @srcdir@ -SUBDIRS = fs repl auth +SUBDIRS = fs repl auth modules # Gotta love the DOS legacy # @@ -51,6 +51,8 @@ AUTH_OBJS = @AUTH_OBJS@ AUTH_MODULES = @AUTH_MODULES@ +INTERNAL_MODULE_OBJS = @CONF_MODULE_OBJS@ +INTERNAL_MODULES = @CONF_MODULES@ CC = @CC@ MAKEDEPEND = @MAKEDEPEND@ INSTALL = @INSTALL@ @@ -95,7 +97,6 @@ access_log.o \ acl.o \ asn.o \ - auth_modules.o \ authenticate.o \ cache_cf.o \ CacheDigest.o \ @@ -138,6 +139,7 @@ icp_v3.o \ ident.o \ internal.o \ + internal_modules.o \ ipc.o \ ipcache.o \ @LEAKFINDER_OBJS@ \ @@ -147,6 +149,7 @@ MemPool.o \ MemBuf.o \ mime.o \ + modules.o \ multicast.o \ neighbors.o \ net_db.o \ @@ -157,7 +160,6 @@ redirect.o \ referer.o \ refresh.o \ - repl_modules.o \ send-announce.o \ @SNMP_OBJS@ \ ssl.o \ @@ -173,7 +175,6 @@ store_dir.o \ store_key_md5.o \ store_log.o \ - store_modules.o \ store_rebuild.o \ store_swapin.o \ store_swapmeta.o \ @@ -206,19 +207,14 @@ DEFAULTS = \ -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -all: squid.conf - @for dir in $(SUBDIRS); do \ - echo "Making $@ in $$dir..."; \ - (cd $$dir ; $(MAKE) $(MFLAGS) prefix="$(prefix)" $@) || exit 1; \ - done - @$(MAKE) $(MFLAGS) $(PROGS) $(UTILS) $(SUID_UTILS) $(CGIPROGS) +all: squid.conf squid.conf.old $(PROGS) $(UTILS) $(SUID_UTILS) $(CGIPROGS) $(OBJS): $(top_srcdir)/include/version.h ../include/autoconf.h $(SNMP_OBJS): ../snmplib/libsnmp.a $(top_srcdir)/include/cache_snmp.h -$(SQUID_EXE): $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS) - $(CC) -o $@ $(LDFLAGS) $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS) $(SQUID_LIBS) +$(SQUID_EXE): $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS) $(INTERNAL_MODULE_OBJS) + $(CC) -o $@ $(LDFLAGS) $(OBJS) $(STORE_OBJS) $(REPL_OBJS) $(AUTH_OBJS) $(INTERNAL_MODULE_OBJS) $(SQUID_LIBS) globals.o: globals.c Makefile $(CC) -c globals.c $(CFLAGS) -I$(srcdir) $(DEFAULTS) @@ -255,8 +251,11 @@ cache_cf.o: cf_parser.c -squid.conf: cf_parser.c - @sh -c "test -f squid.conf || ./cf_gen cf.data" +squid.conf.old: cf_parser.c + @sh -c "test -f squid.conf.old || ./cf_gen cf.data" + +squid.conf: $(SQUID_EXE) + @sh -c "./$(SQUID_EXE) -c internalonly -c all > squid.conf" cf_parser.c: cf.data cf_gen ./cf_gen cf.data @@ -287,35 +286,35 @@ s%@DEFAULT_PREFIX@%$(DEFAULT_PREFIX)%g;"\ < $(srcdir)/cf.data.pre >$@ -store_modules.c: store_modules.sh Makefile - sh $(srcdir)/store_modules.sh $(STORE_MODULES) >store_modules.c +$(STORE_OBJS): store_modules -store_modules.o: store_modules.c - $(CC) -c store_modules.c $(CFLAGS) -I$(srcdir) +store_modules: + @echo "Making all in fs..."; \ + (cd fs ; $(MAKE) $(MFLAGS) prefix="$(prefix)" all) || exit 1; -$(STORE_OBJS): - @sh -c "cd `dirname $@` && $(MAKE) $(MFLAGS) `basename $@`" +$(REPL_OBJS): repl_modules -repl_modules.c: repl_modules.sh Makefile - sh $(srcdir)/repl_modules.sh $(REPL_POLICIES) >repl_modules.c +repl_modules: + @echo "Making all in repl..."; \ + (cd repl ; $(MAKE) $(MFLAGS) prefix="$(prefix)" all) || exit 1; -repl_modules.o: repl_modules.c - $(CC) -c repl_modules.c $(CFLAGS) -I$(srcdir) +$(AUTH_OBJS): auth_modules -$(REPL_OBJS): - @sh -c "cd `dirname $@` && $(MAKE) $(MFLAGS) `basename $@`" +auth_modules: + @echo "Making all in auth..."; \ + (cd auth ; $(MAKE) $(MFLAGS) prefix="$(prefix)" all) || exit 1; -repl_modules repl/stamp: - @sh -c "cd repl && $(MAKE) all" +internal_modules.c: internal_modules.sh Makefile + sh $(srcdir)/internal_modules.sh $(INTERNAL_MODULES) $(AUTH_MODULES) $(REPL_POLICIES) $(STORE_MODULES) >internal_modules.c -auth_modules.c: auth_modules.sh Makefile - sh $(srcdir)/auth_modules.sh $(AUTH_MODULES) >auth_modules.c +internal_modules.o: internal_modules.c + $(CC) -c internal_modules.c $(CFLAGS) -I$(srcdir) -auth_modules.o: auth_modules.c - $(CC) -c auth_modules.c $(CFLAGS) -I$(srcdir) +$(INTERNAL_MODULE_OBJS): internal_modules -$(AUTH_OBJS): - @sh -c "cd `dirname $@` && $(MAKE) $(MFLAGS) `basename $@`" +internal_modules: + @echo "Making all in modules..."; \ + (cd modules ; $(MAKE) $(MFLAGS) prefix="$(prefix)" all) || exit 1; install-mkdirs: -@if test ! -d $(prefix); then \ @@ -425,7 +424,7 @@ clean: -rm -rf *.o *pure_* core $(PROGS) $(UTILS) $(CGIPROGS) $(SUID_UTILS) -rm -f cf_gen cf_gen_defines.h cf_parser.c cf.data globals.c string_arrays.c - -rm -f store_modules.c repl_modules.c auth_modules.c squid.conf + -rm -f internal_modules.c squid.conf @for dir in $(SUBDIRS); do \ echo "Making $@ in $$dir..."; \ (cd $$dir ; $(MAKE) $(MFLAGS) prefix="$(prefix)" $@) || exit 1; \ Index: squid/src/MemPool.c diff -u squid/src/MemPool.c:1.5 squid/src/MemPool.c:1.5.8.1 --- squid/src/MemPool.c:1.5 Fri Jan 12 00:20:32 2001 +++ squid/src/MemPool.c Wed Apr 25 05:28:59 2001 @@ -118,13 +118,14 @@ int dirty_count = 0; for (i = 0; i < Pools.count; i++) { MemPool *pool = Pools.items[i]; - if (memPoolInUseCount(pool)) { - memPoolDescribe(pool); - dirty_count++; - } else { - memPoolDestroy(pool); - Pools.items[i] = NULL; - } + if (pool) + if (memPoolInUseCount(pool)) { + memPoolDescribe(pool); + dirty_count++; + } else { + memPoolDestroy(pool); + Pools.items[i] = NULL; + } } if (dirty_count) debug(63, 2) ("memCleanModule: %d pools are left dirty\n", dirty_count); @@ -221,9 +222,13 @@ void memPoolDestroy(MemPool * pool) { + int i; assert(pool); stackClean(&pool->pstack); xfree(pool); + for (i = 0; i < Pools.count; i++) + if (Pools.items[i]==pool) + Pools.items[i]=NULL; } void * Index: squid/src/acl.c diff -u squid/src/acl.c:1.29 squid/src/acl.c:1.21.4.22 --- squid/src/acl.c:1.29 Thu Apr 5 23:49:27 2001 +++ squid/src/acl.c Sun May 13 04:28:36 2001 @@ -35,41 +35,53 @@ #include "squid.h" #include "splay.h" +#include "squid_parser.h" +#include "acl.h" -static int aclFromFile = 0; -static FILE *aclFile; +/* this is the list of acl names to parser types */ +static dlink_list aclNames = {NULL,NULL}; -static void aclParseDomainList(void *curlist); -static void aclParseUserList(void **current); -static void aclParseIpList(void *curlist); +/* this is the parent instance_name that acls live under */ +static void * aclinstances = NULL; +static aclName * proxy_auth_name = NULL; +static aclName * proxy_auth_regex_name = NULL; + +MemPool * acl_pool = NULL; +MemPool * acl_deny_info_list_pool = NULL; +MemPool * acl_ip_data_pool = NULL; +MemPool * acl_name_list_pool = NULL; +MemPool * acl_time_data_pool = NULL; +MemPool * acl_proxy_auth_match_pool = NULL; +MemPool * acl_user_data_pool = NULL; +acl * AclMatchedAcl = NULL; + +static PARSER_PARSE aclParseDomainList; +static PARSER_PARSE aclParseUserList; +static PARSER_PARSE aclParseIpList; +static PARSER_PARSE aclParseRegexList; #if UNUSED_CODE static void aclParseIntlist(void *curlist); #endif -#if SQUID_SNMP -static void aclParseWordList(void *curlist); -#endif -static void aclParseProtoList(void *curlist); -static void aclParseMethodList(void *curlist); -static void aclParseTimeSpec(void *curlist); -static void aclParseIntRange(void *curlist); -static char *strtokFile(void); +static PARSER_PARSE aclParseProtoList; +static PARSER_PARSE aclParseMethodList; +static PARSER_PARSE aclParseTimeSpec; +static PARSER_PARSE aclParseIntRange; +static PARSER_PARSE parse_denyinfo; static void aclDestroyAclList(acl_list * list); -static void aclDestroyTimeList(acl_time_data * data); -static void aclDestroyIntRange(intrange *); +static PARSER_FREE aclDestroyTimeSpecList; +static PARSER_FREE aclDestroyIntRange; +static PARSER_FREE free_denyinfo; static void aclLookupProxyAuthStart(aclCheck_t * checklist); static void aclLookupProxyAuthDone(void *data, char *result); static struct _acl *aclFindByName(const char *name); -static int aclMatchAcl(struct _acl *, aclCheck_t *); static int aclMatchIntegerRange(intrange * data, int i); -static int aclMatchTime(acl_time_data * data, time_t when); +static int aclMatchTimeSpec(acl_time_data * data, time_t when); static int aclMatchUser(void *proxyauth_acl, char *user); -static int aclMatchIp(void *dataptr, struct in_addr c); +static int aclMatchIp(void *, struct in_addr); static int aclMatchDomainList(void *dataptr, const char *); -static int aclMatchIntegerRange(intrange * data, int i); #if SQUID_SNMP static int aclMatchWordList(wordlist *, const char *); #endif -static squid_acl aclStrToType(const char *s); static int decode_addr(const char *, struct in_addr *, struct in_addr *); static void aclCheck(aclCheck_t * checklist); static void aclCheckCallback(aclCheck_t * checklist, allow_t answer); @@ -88,6 +100,7 @@ static wordlist *aclDumpIntRangeList(intrange * data); static wordlist *aclDumpProtoList(intlist * data); static wordlist *aclDumpMethodList(intlist * data); +static PARSER_DUMP dump_denyinfo; static SPLAYCMP aclIpNetworkCompare; static SPLAYCMP aclHostDomainCompare; static SPLAYCMP aclDomainCompare; @@ -95,211 +108,105 @@ static SPLAYWALKEE aclDumpDomainListWalkee; static SPLAYFREE aclFreeIpData; -#if USE_ARP_ACL -static void aclParseArpList(void *curlist); -static int decode_eth(const char *asc, char *eth); -static int aclMatchArp(void *dataptr, struct in_addr c); -static wordlist *aclDumpArpList(void *); -static SPLAYCMP aclArpCompare; -static SPLAYWALKEE aclDumpArpListWalkee; -#endif -static int aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, char *MatchParam); - -static char * -strtokFile(void) -{ - char *t, *fn; - LOCAL_ARRAY(char, buf, 256); - - strtok_again: - if (!aclFromFile) { - t = (strtok(NULL, w_space)); - if (t && (*t == '\"' || *t == '\'')) { - /* quote found, start reading from file */ - fn = ++t; - while (*t && *t != '\"' && *t != '\'') - t++; - *t = '\0'; - if ((aclFile = fopen(fn, "r")) == NULL) { - debug(28, 0) ("strtokFile: %s not found\n", fn); - return (NULL); - } -#if defined(_SQUID_CYGWIN_) - setmode(fileno(aclFile), O_TEXT); -#endif - aclFromFile = 1; - } else { - return t; - } - } - /* aclFromFile */ - if (fgets(buf, 256, aclFile) == NULL) { - /* stop reading from file */ - fclose(aclFile); - aclFromFile = 0; - goto strtok_again; - } else { - t = buf; - /* skip leading and trailing white space */ - t += strspn(buf, w_space); - t[strcspn(t, w_space)] = '\0'; - /* skip comments */ - if (*t == '#') - goto strtok_again; - /* skip blank lines */ - if (!*t) - goto strtok_again; - return t; - } -} +static int aclCacheMatchAcl(dlink_list * cache, acl *, char *MatchParam); -static squid_acl -aclStrToType(const char *s) -{ - if (!strcmp(s, "src")) - return ACL_SRC_IP; - if (!strcmp(s, "dst")) - return ACL_DST_IP; - if (!strcmp(s, "myip")) - return ACL_MY_IP; - if (!strcmp(s, "domain")) - return ACL_DST_DOMAIN; - if (!strcmp(s, "dstdomain")) - return ACL_DST_DOMAIN; - if (!strcmp(s, "srcdomain")) - return ACL_SRC_DOMAIN; - if (!strcmp(s, "dstdom_regex")) - return ACL_DST_DOM_REGEX; - if (!strcmp(s, "srcdom_regex")) - return ACL_SRC_DOM_REGEX; - if (!strcmp(s, "time")) - return ACL_TIME; - if (!strcmp(s, "pattern")) - return ACL_URLPATH_REGEX; - if (!strcmp(s, "urlpath_regex")) - return ACL_URLPATH_REGEX; - if (!strcmp(s, "url_regex")) - return ACL_URL_REGEX; - if (!strcmp(s, "port")) - return ACL_URL_PORT; - if (!strcmp(s, "myport")) - return ACL_MY_PORT; - if (!strcmp(s, "maxconn")) - return ACL_MAXCONN; -#if USE_IDENT - if (!strcmp(s, "ident")) - return ACL_IDENT; - if (!strcmp(s, "ident_regex")) - return ACL_IDENT_REGEX; -#endif - if (!strncmp(s, "proto", 5)) - return ACL_PROTO; - if (!strcmp(s, "method")) - return ACL_METHOD; - if (!strcmp(s, "browser")) - return ACL_BROWSER; - if (!strcmp(s, "proxy_auth")) - return ACL_PROXY_AUTH; - if (!strcmp(s, "proxy_auth_regex")) - return ACL_PROXY_AUTH_REGEX; - if (!strcmp(s, "src_as")) - return ACL_SRC_ASN; - if (!strcmp(s, "dst_as")) - return ACL_DST_ASN; -#if SQUID_SNMP - if (!strcmp(s, "snmp_community")) - return ACL_SNMP_COMMUNITY; -#endif -#if SRC_RTT_NOT_YET_FINISHED - if (!strcmp(s, "src_rtt")) - return ACL_NETDB_SRC_RTT; -#endif -#if USE_ARP_ACL - if (!strcmp(s, "arp")) - return ACL_SRC_ARP; -#endif - if (!strcmp(s, "req_mime_type")) - return ACL_REQ_MIME_TYPE; - if (!strcmp(s, "rep_mime_type")) - return ACL_REP_MIME_TYPE; - return ACL_NONE; -} - -const char * -aclTypeToStr(squid_acl type) -{ - if (type == ACL_SRC_IP) - return "src"; - if (type == ACL_DST_IP) - return "dst"; - if (type == ACL_MY_IP) - return "myip"; - if (type == ACL_DST_DOMAIN) - return "dstdomain"; - if (type == ACL_SRC_DOMAIN) - return "srcdomain"; - if (type == ACL_DST_DOM_REGEX) - return "dstdom_regex"; - if (type == ACL_SRC_DOM_REGEX) - return "srcdom_regex"; - if (type == ACL_TIME) - return "time"; - if (type == ACL_URLPATH_REGEX) - return "urlpath_regex"; - if (type == ACL_URL_REGEX) - return "url_regex"; - if (type == ACL_URL_PORT) - return "port"; - if (type == ACL_MY_PORT) - return "myport"; - if (type == ACL_MAXCONN) - return "maxconn"; -#if USE_IDENT - if (type == ACL_IDENT) - return "ident"; - if (type == ACL_IDENT_REGEX) - return "ident_regex"; -#endif - if (type == ACL_PROTO) - return "proto"; - if (type == ACL_METHOD) - return "method"; - if (type == ACL_BROWSER) - return "browser"; - if (type == ACL_PROXY_AUTH) - return "proxy_auth"; - if (type == ACL_PROXY_AUTH_REGEX) - return "proxy_auth_regex"; - if (type == ACL_SRC_ASN) - return "src_as"; - if (type == ACL_DST_ASN) - return "dst_as"; -#if SQUID_SNMP - if (type == ACL_SNMP_COMMUNITY) - return "snmp_community"; -#endif -#if SRC_RTT_NOT_YET_FINISHED - if (type == ACL_NETDB_SRC_RTT) - return "src_rtt"; -#endif -#if USE_ARP_ACL - if (type == ACL_SRC_ARP) - return "arp"; -#endif - if (type == ACL_REQ_MIME_TYPE) - return "req_mime_type"; - if (type == ACL_REP_MIME_TYPE) - return "rep_mime_type"; - return "ERROR"; +static ACLMATCH aclMatchSrc; +static ACLMATCH aclMatchDst; +static ACLMATCH aclMatchMyip; +static ACLMATCH aclMatchSrcDomain; +static ACLMATCH aclMatchDstDomain; +static ACLMATCH aclMatchDstDomain; +static ACLMATCH aclMatchSrcDomain; +static ACLMATCH aclMatchSrcDomain; +static ACLMATCH aclMatchUrlPathRegex; +static ACLMATCH aclMatchUrlPathRegex; +static ACLMATCH aclMatchUrlRegex; +static ACLMATCH aclMatchBrowser; +static ACLMATCH aclMatchRepMimeType; +static ACLMATCH aclMatchReqMimeType; +static ACLMATCH aclMatchIdent; +static ACLMATCH aclMatchIdentRegex; +static ACLMATCH aclMatchProxyAuthModule; +static ACLMATCH aclMatchTime; +static ACLMATCH aclMatchMaxConn; +static ACLMATCH aclMatchUrlPort; +static ACLMATCH aclMatchMyPort; +static ACLMATCH aclMatchSNMPCommunity; +static ACLMATCH aclMatchProto; +static ACLMATCH aclMatchMethod; +static ACLMATCH aclMatchSrcAsn; +static ACLMATCH aclMatchDstAsn; +#if SRC_RTT_NOT_YET_FINISHED +static ACLMATCH aclMatchSrcRTT; +#endif + +CBDATA_TYPE (aclName); + +static void +aclNameFree(void *data) +{ + aclName *Name=data; + dlinkDelete(&Name->node,&aclNames); + debug(3,0)("aclNameFree freed name %s\n",Name->namestr); + safe_free(Name->namestr); + cbdataUnlock(Name->type); +} + + +/* FIXME: should this be merged into cache_cf ? */ +aclName * +aclNameByName(const char *name) +{ + dlink_node *node; + node=aclNames.head; + while (node && strcmp(((aclName *)node->data)->namestr,name)) { + node=node->next; + + } + if (node) + return (aclName *)node->data; + else + return NULL; +} + +aclName * +aclRegisterAclName(const char *namestr, parserTypeNode *parserType, ACLMATCH *Match) { + aclName *Name; + if ((Name=aclNameByName(namestr))==NULL) { + /* register the type */ + debug(28,3)("aclRegisterAclName new name '%s'\n",Name); + if (aclNames.head == NULL) + CBDATA_INIT_TYPE_FREECB(aclName,aclNameFree); + Name=cbdataAlloc(aclName); + Name->namestr=xstrdup(namestr); + Name->type=parserType; + Name->match=Match; + cbdataLock(parserType); +// Name->default_none=default_none; +// Name->post_parse_func=post_parse_func; + dlinkAddTail(Name,&Name->node,&aclNames); + return Name; +} else { + debug(28,0)("parserRegisterInstanceName already registered name '%s'\n",Name); + return NULL; + /* TODO: fatal this */ + } } static acl * aclFindByName(const char *name) { + instance_node *acl_instance; +#if NEVER acl *a; for (a = Config.aclList; a; a = a->next) if (!strcasecmp(a->name, name)) return a; +#endif + acl_instance=InstanceByNameStr(aclinstances,name); + if (acl_instance) + return acl_instance->data; + return NULL; } @@ -321,7 +228,7 @@ #endif static void -aclParseIntRange(void *curlist) +aclParseIntRange(parserNameNode *parserName, void *curlist) { intrange **Tail; intrange *q = NULL; @@ -341,7 +248,7 @@ } static void -aclParseProtoList(void *curlist) +aclParseProtoList(parserNameNode *parserName, void *curlist) { intlist **Tail; intlist *q = NULL; @@ -356,7 +263,7 @@ } static void -aclParseMethodList(void *curlist) +aclParseMethodList(parserNameNode *parserName, void *curlist) { intlist **Tail; intlist *q = NULL; @@ -370,6 +277,143 @@ } } +static void +name_document_deny_info(void){ + printf( +"# TAG: deny_info" +"\n" +"#\tUsage: deny_info err_page_name acl\n" +"#\tExample: deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys\n" +"#\n" +"#\tThis can be used to return a ERR_ page for requests which\n" +"#\tdo not pass the 'http_access' rules. A single ACL will cause\n" +"#\tthe http_access check to fail. If a 'deny_info' line exists\n" +"#\tfor that ACL then Squid returns a corresponding error page.\n" +"#\n" +"#\tYou may use ERR_ pages that come with Squid or create your own pages\n" +"#\tand put them into the configured errors/ directory.\n" +"#\n" +"#Default:\n" +"# none\n" +"\n" + );} + +static void +parse_denyinfo(parserNameNode *parserName, void * data) +{ + acl_deny_info_list ** head=( acl_deny_info_list **)data; +/* maex@space.net (05.09.96) + * get the info for redirecting "access denied" to info pages + * TODO (probably ;-) + * currently there is no optimization for + * - more than one deny_info line with the same url + * - a check, whether the given acl really is defined + * - a check, whether an acl is added more than once for the same url + */ + char *t = NULL; + acl_deny_info_list *A = NULL; + acl_deny_info_list *B = NULL; + acl_deny_info_list **T = NULL; + acl_name_list *L = NULL; + acl_name_list **Tail = NULL; + + /* first expect a page name */ + if ((t = strtok(NULL, w_space)) == NULL) { + debug(28, 0) ("%s line %d: %s\n", + cfg_filename, config_lineno, config_input_line); + debug(28, 0) ("parse_denyinfo: missing 'error page' parameter.\n"); + return; + } + A = memPoolAlloc(acl_deny_info_list_pool); + A->err_page_id = errorReservePageId(t); + A->err_page_name = xstrdup(t); + A->next = (acl_deny_info_list *) NULL; + /* next expect a list of ACL names */ + /* FIXME: verify the names exist, and look them up and lock them. + * Possibly a postparse thing. + */ + Tail = &A->acl_list; + while ((t = strtok(NULL, w_space))) { + L = memPoolAlloc(acl_name_list_pool); + xstrncpy(L->name, t, ACL_NAME_SZ); + *Tail = L; + Tail = &L->next; + } + if (A->acl_list == NULL) { + debug(28, 0) ("%s line %d: %s\n", + cfg_filename, config_lineno, config_input_line); + debug(28, 0) ("parse_denyinfo: deny_info line contains no ACL's, skipping\n"); + memPoolFree(acl_deny_info_list_pool, A); + return; + } + for (B = *head, T = head; B; T = &B->next, B = B->next); /* find the tail */ + *T = A; + + cbdataLock(parserName); +} + +static void +dump_denyinfo(StoreEntry * entry, const char *name, void const * const data) +{ + acl_deny_info_list *var=*(acl_deny_info_list **)data; + acl_name_list *a; + while (var != NULL) { + storeAppendPrintf(entry, "%s %s", name, var->err_page_name); + for (a = var->acl_list; a != NULL; a = a->next) + storeAppendPrintf(entry, " %s", a->name); + storeAppendPrintf(entry, "\n"); + var = var->next; + } +} + +static void +free_denyinfo(parserNameNode *parserName, void * data) +{ + acl_deny_info_list ** list=( acl_deny_info_list **)data; + acl_deny_info_list *a = NULL; + acl_deny_info_list *a_next = NULL; + acl_name_list *l = NULL; + acl_name_list *l_next = NULL; + for (a = *list; a; a = a_next) { + for (l = a->acl_list; l; l = l_next) { + l_next = l->next; + memPoolFree(acl_name_list_pool, l); + l = NULL; + } + a_next = a->next; + safe_free (a->err_page_name); + memPoolFree(acl_deny_info_list_pool, a); + a = NULL; + cbdataUnlock(parserName); + } + *list = NULL; +} + +#if 0 +/* maex@space.net (06.09.1996) + * destroy an _acl_deny_info_list */ + +void +aclDestroyDenyInfoList(acl_deny_info_list ** list) +{ + acl_deny_info_list *a = NULL; + acl_deny_info_list *a_next = NULL; + acl_name_list *l = NULL; + acl_name_list *l_next = NULL; + + for (a = *list; a; a = a_next) { + for (l = a->acl_list; l; l = l_next) { + l_next = l->next; + safe_free(l); + } + a_next = a->next; + xfree(a->err_page_name); + memPoolFree(acl_deny_info_list_pool, a); + } + *list = NULL; +} +#endif + /* * Decode a ascii representation (asc) of a IP adress, and place * adress and netmask information in addr and mask. @@ -416,7 +460,6 @@ return 1; } - #define SCAN_ACL1 "%[0123456789.]-%[0123456789.]/%[0123456789.]" #define SCAN_ACL2 "%[0123456789.]-%[0123456789.]%c" #define SCAN_ACL3 "%[0123456789.]/%[0123456789.]" @@ -428,7 +471,7 @@ LOCAL_ARRAY(char, addr1, 256); LOCAL_ARRAY(char, addr2, 256); LOCAL_ARRAY(char, mask, 256); - acl_ip_data *q = memAllocate(MEM_ACL_IP_DATA); + acl_ip_data *q = memPoolAlloc(acl_ip_data_pool); acl_ip_data *r; acl_ip_data **Q; struct hostent *hp; @@ -465,7 +508,7 @@ Q = &q; for (x = hp->h_addr_list; x != NULL && *x != NULL; x++) { if ((r = *Q) == NULL) - r = *Q = memAllocate(MEM_ACL_IP_DATA); + r = *Q = memPoolAlloc(acl_ip_data_pool); xmemcpy(&r->addr1.s_addr, *x, sizeof(r->addr1.s_addr)); r->addr2.s_addr = 0; r->mask.s_addr = no_addr.s_addr; /* 255.255.255.255 */ @@ -516,7 +559,7 @@ /******************/ static void -aclParseIpList(void *curlist) +aclParseIpList(parserNameNode *parserName, void *curlist) { char *t = NULL; splayNode **Top = curlist; @@ -531,14 +574,14 @@ } static void -aclParseTimeSpec(void *curlist) +aclParseTimeSpec(parserNameNode *parserName, void *curlist) { acl_time_data *q = NULL; acl_time_data **Tail; int h1, m1, h2, m2; char *t = NULL; for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); - q = memAllocate(MEM_ACL_TIME_DATA); + q = memPoolAlloc(acl_time_data_pool); while ((t = strtokFile())) { if (*t < '0' || *t > '9') { /* assume its day-of-week spec */ @@ -584,7 +627,7 @@ debug(28, 0) ("%s line %d: %s\n", cfg_filename, config_lineno, config_input_line); debug(28, 0) ("aclParseTimeSpec: IGNORING Bad time range\n"); - memFree(q, MEM_ACL_TIME_DATA); + memPoolFree(acl_time_data_pool, q); return; } q->start = h1 * 60 + m1; @@ -593,7 +636,7 @@ debug(28, 0) ("%s line %d: %s\n", cfg_filename, config_lineno, config_input_line); debug(28, 0) ("aclParseTimeSpec: IGNORING Reversed time range\n"); - memFree(q, MEM_ACL_TIME_DATA); + memPoolFree(acl_time_data_pool, q); return; } } @@ -607,7 +650,7 @@ } void -aclParseRegexList(void *curlist) +aclParseRegexList(parserNameNode *parserName, void *curlist) { relist **Tail; relist *q = NULL; @@ -642,19 +685,10 @@ } } -#if SQUID_SNMP -static void -aclParseWordList(void *curlist) -{ - char *t = NULL; - while ((t = strtokFile())) - wordlistAdd(curlist, t); -} -#endif - static void -aclParseUserList(void **current) +aclParseUserList(parserNameNode *parserName, void *curlist) { + void **current= curlist; char *t = NULL; acl_user_data *data; splayNode *Top = NULL; @@ -662,7 +696,7 @@ debug(28, 2) ("aclParseUserList: parsing user list\n"); if (*current == NULL) { debug(28, 3) ("aclParseUserList: current is null. Creating\n"); - *current = memAllocate(MEM_ACL_USER_DATA); + *current = memPoolAlloc(acl_user_data_pool); } data = *current; Top = data->names; @@ -700,7 +734,7 @@ /**********************/ static void -aclParseDomainList(void *curlist) +aclParseDomainList(parserNameNode *parserName, void *curlist) { char *t = NULL; splayNode **Top = curlist; @@ -711,157 +745,84 @@ } void -aclParseAclLine(acl ** head) +aclParseAclLine(parserNameNode *parserName, void *data) { + acl ** head=(acl **)data; + aclName *aclname; + /* we're already using strtok() to grok the line */ - char *t = NULL; + char *token = NULL; acl *A = NULL; - LOCAL_ARRAY(char, aclname, ACL_NAME_SZ); - squid_acl acltype; - int new_acl = 0; +// LOCAL_ARRAY(char, aclname, ACL_NAME_SZ); + parserTypeNode * parserType=NULL; - /* snarf the ACL name */ - if ((t = strtok(NULL, w_space)) == NULL) { - debug(28, 0) ("%s line %d: %s\n", - cfg_filename, config_lineno, config_input_line); - debug(28, 0) ("aclParseAclLine: missing ACL name.\n"); - return; - } - xstrncpy(aclname, t, ACL_NAME_SZ); /* snarf the ACL type */ - if ((t = strtok(NULL, w_space)) == NULL) { + if ((token = strtok(NULL, w_space)) == NULL) { debug(28, 0) ("%s line %d: %s\n", cfg_filename, config_lineno, config_input_line); debug(28, 0) ("aclParseAclLine: missing ACL type.\n"); return; } - if ((acltype = aclStrToType(t)) == ACL_NONE) { + + /* is there a aclname for this? */ + debug (28,0) ("acl name string %s\n",token); + aclname = aclNameByName(token); + if (aclname) { + parserType=aclname->type; + debug (28,0) ("found parserType %s\n",parserType->typestr); + } else { debug(28, 0) ("%s line %d: %s\n", cfg_filename, config_lineno, config_input_line); - debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", t); + debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", token); + /* flush the line */ + while (strtok(NULL, w_space)); return; } - if ((A = aclFindByName(aclname)) == NULL) { - debug(28, 3) ("aclParseAclLine: Creating ACL '%s'\n", aclname); - A = memAllocate(MEM_ACL); - xstrncpy(A->name, aclname, ACL_NAME_SZ); - A->type = acltype; - A->cfgline = xstrdup(config_input_line); - new_acl = 1; - } else { - if (acltype != A->type) { - debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different type, skipping.\n", A->name); - return; - } - debug(28, 3) ("aclParseAclLine: Appending to '%s'\n", aclname); - new_acl = 0; + + /* We only get called once to assign the function: if data is already used, bomb */ + if (*head) { + debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different type, skipp +ing.\n", parserName->namestr); + /* flush the line */ + while (strtok(NULL, w_space)); + return; } + + debug(28, 3) ("aclParseAclLine: Creating new ACL\n"); + A = memPoolAlloc(acl_pool); + xstrncpy(A->name, parserName->namestr, ACL_NAME_SZ); + A->cfgline = xstrdup(config_input_line); + A->aclname=aclname; + /* * Here we set AclMatchedName in case we need to use it in a * warning message in aclDomainCompare(). */ - AclMatchedName = aclname; /* ugly */ - switch (A->type) { - case ACL_SRC_IP: - case ACL_DST_IP: - case ACL_MY_IP: - aclParseIpList(&A->data); - break; - case ACL_SRC_DOMAIN: - case ACL_DST_DOMAIN: - aclParseDomainList(&A->data); - break; - case ACL_TIME: - aclParseTimeSpec(&A->data); - break; - case ACL_URL_REGEX: - case ACL_URLPATH_REGEX: - case ACL_BROWSER: - case ACL_SRC_DOM_REGEX: - case ACL_DST_DOM_REGEX: - case ACL_REQ_MIME_TYPE: - case ACL_REP_MIME_TYPE: - aclParseRegexList(&A->data); - break; - case ACL_SRC_ASN: - case ACL_MAXCONN: - case ACL_DST_ASN: -#if SRC_RTT_NOT_YET_FINISHED - case ACL_NETDB_SRC_RTT: - aclParseIntlist(&A->data); - break; -#endif - case ACL_URL_PORT: - case ACL_MY_PORT: - aclParseIntRange(&A->data); - break; -#if USE_IDENT - case ACL_IDENT: - aclParseUserList(&A->data); - break; - case ACL_IDENT_REGEX: - aclParseRegexList(&A->data); - break; -#endif - case ACL_PROTO: - aclParseProtoList(&A->data); - break; - case ACL_METHOD: - aclParseMethodList(&A->data); - break; - case ACL_PROXY_AUTH: - if (authenticateSchemeCount() == 0) { - debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \ -because no authentication schemes were compiled.\n", A->cfgline); - } else if (authenticateActiveSchemeCount() == 0) { - debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \ -because no authentication schemes are fully configured.\n", A->cfgline); - } else { - aclParseUserList(&A->data); - } - break; - case ACL_PROXY_AUTH_REGEX: - if (authenticateSchemeCount() == 0) { - debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \ -because no authentication schemes were compiled.\n", A->cfgline); - } else if (authenticateActiveSchemeCount() == 0) { - debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \ -because no authentication schemes are fully configured.\n", A->cfgline); - } else { - aclParseRegexList(&A->data); - } - break; -#if SQUID_SNMP - case ACL_SNMP_COMMUNITY: - aclParseWordList(&A->data); - break; -#endif -#if USE_ARP_ACL - case ACL_SRC_ARP: - aclParseArpList(&A->data); - break; -#endif - case ACL_NONE: - case ACL_ENUM_MAX: - fatal("Bad ACL type"); - break; - } +/* AclMatchedName = aclname; */ /* ugly */ +/* TODO: it might be cleaner for the sub type should be registered via a one off + * instance - no new registrations allowed. Ideally this is declaritive (list the + * allowed types, specify one type per child */ + /* back strtok up a step. Yummy - Should be macroised */ + *(token + strlen(token))=' '; + *(token-2) = 'A'; + *(token-1) = ' '; + strtok(token-2,w_space); +debug(28,0)("***%s\n",A->aclname->namestr); + parserRegisterName(parserName, A->aclname->namestr, parserType, &(A->data), NULL, NULL, NULL); + /* parse the rest of the line. */ + parse_directive(parserName); /* * Clear AclMatchedName from our temporary hack */ AclMatchedName = NULL; /* ugly */ - if (!new_acl) - return; if (A->data == NULL) { debug(28, 0) ("aclParseAclLine: IGNORING invalid ACL: %s\n", A->cfgline); - memFree(A, MEM_ACL); + memPoolFree(acl_pool, A); return; } - /* append */ - while (*head) - head = &(*head)->next; *head = A; + } /* does name lookup, returns page_id */ @@ -888,66 +849,6 @@ return ERR_NONE; } -/* does name lookup, returns if it is a proxy_auth acl */ -int -aclIsProxyAuth(const char *name) -{ - acl *a = aclFindByName(name); - if (a) - return a->type == ACL_PROXY_AUTH; - return 0; -} - - -/* maex@space.net (05.09.96) - * get the info for redirecting "access denied" to info pages - * TODO (probably ;-) - * currently there is no optimization for - * - more than one deny_info line with the same url - * - a check, whether the given acl really is defined - * - a check, whether an acl is added more than once for the same url - */ - -void -aclParseDenyInfoLine(acl_deny_info_list ** head) -{ - char *t = NULL; - acl_deny_info_list *A = NULL; - acl_deny_info_list *B = NULL; - acl_deny_info_list **T = NULL; - acl_name_list *L = NULL; - acl_name_list **Tail = NULL; - - /* first expect a page name */ - if ((t = strtok(NULL, w_space)) == NULL) { - debug(28, 0) ("%s line %d: %s\n", - cfg_filename, config_lineno, config_input_line); - debug(28, 0) ("aclParseDenyInfoLine: missing 'error page' parameter.\n"); - return; - } - A = memAllocate(MEM_ACL_DENY_INFO_LIST); - A->err_page_id = errorReservePageId(t); - A->err_page_name = xstrdup(t); - A->next = (acl_deny_info_list *) NULL; - /* next expect a list of ACL names */ - Tail = &A->acl_list; - while ((t = strtok(NULL, w_space))) { - L = memAllocate(MEM_ACL_NAME_LIST); - xstrncpy(L->name, t, ACL_NAME_SZ); - *Tail = L; - Tail = &L->next; - } - if (A->acl_list == NULL) { - debug(28, 0) ("%s line %d: %s\n", - cfg_filename, config_lineno, config_input_line); - debug(28, 0) ("aclParseDenyInfoLine: deny_info line contains no ACL's, skipping\n"); - memFree(A, MEM_ACL_DENY_INFO_LIST); - return; - } - for (B = *head, T = head; B; T = &B->next, B = B->next); /* find the tail */ - *T = A; -} - void aclParseAccessLine(acl_access ** head) { @@ -1032,12 +933,100 @@ return !splayLastResult; } +static int +aclMatchSrc(acl * ae, aclCheck_t *checklist, unsigned int flags) +{ + debug(28, 3) ("aclMatchSrc: checking '%s'\n", ae->cfgline); + return aclMatchIp(&ae->data, checklist->src_addr); +} + +static int +aclMatchMyip(acl *ae, aclCheck_t *checklist, unsigned int flags) +{ + debug(28, 3) ("aclMatchMyip: checking '%s'\n", ae->cfgline); + return aclMatchIp(&ae->data, checklist->my_addr); +} + +static int +aclMatchDst(acl * ae, aclCheck_t *checklist, unsigned int flags) +{ + request_t *r = checklist->request; + const ipcache_addrs *ia = NULL; + int k; + debug(28, 3) ("aclMatchDst: checking '%s'\n", ae->cfgline); + if (NULL == r) { + debug(28, 1) ("WARNING: '%s' ACL is used but there is no" + " HTTP request -- access denied.\n", ae->name); + return 0; + } + ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS); + if (ia) { + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + for (k = 0; k < (int) ia->count; k++) { + if (aclMatchIp(&ae->data, ia->in_addrs[k])) + return 1; + } + return 0; + } else if (checklist->lastcheckowner==NULL) { + debug(28, 3) ("aclMatchDst: Can't yet compare '%s' ACL for '%s'\n", + ae->name, r->host); + checklist->lastcheckowner=ae; + checklist->lastcheckstate=ACL_LOOKUP_PENDING; + ipcache_nbgethostbyname(checklist->request->host, + aclLookupDstIPDone, checklist); + return ACL_MATCH_NEED_LOOKUP; + } else if (checklist->lastcheckowner==ae) { + /* ACL_LOOKUP_DONE is/should be caught by if (ia) */ + debug(28, 0) ("aclMatchDst: Probable bug *****" + "Call to aclMatchDst with lastcheckowner but no IP found with" + " '%s' ACL for '%s'\n", + ae->name, r->host); + return 0; + } else { + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + return aclMatchIp(&ae->data, no_addr); + } +#if 0 + } else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) { + debug(28, 3) ("aclMatchDst: Can't yet compare '%s' ACL for '%s'\n", + ae->name, r->host); + checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEEDED; + return 0; + } else { + return aclMatchIp(&ae->data, no_addr); + } +#endif +#if 0 + if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NEEDED) { + checklist->state[ACL_DST_IP] = ACL_LOOKUP_PENDING; + ipcache_nbgethostbyname(checklist->request->host, + aclLookupDstIPDone, checklist); + return; + } +#endif +} + +static void +aclLookupDstIPDone(const ipcache_addrs * ia, void *data) +{ + aclCheck_t *checklist = data; + /* We don't reset the owner because the owner needs to test it */ + checklist->lastcheckstate = ACL_LOOKUP_DONE; + aclCheck(checklist); +} + /**********************/ /* aclMatchDomainList */ /**********************/ static int -aclMatchDomainList(void *dataptr, const char *host) +aclMatchDomainList(void * dataptr, const char *host) { splayNode **Top = dataptr; if (host == NULL) @@ -1049,31 +1038,416 @@ return !splayLastResult; } -int -aclMatchRegex(relist * data, const char *word) +static int +aclMatchDstDomain(acl * ae, aclCheck_t * checklist, unsigned int flags) { - relist *first, *prev; - if (word == NULL) - return 0; - debug(28, 3) ("aclMatchRegex: checking '%s'\n", word); - first = data; - prev = NULL; - while (data) { - debug(28, 3) ("aclMatchRegex: looking for '%s'\n", data->pattern); - if (regexec(&data->regex, word, 0, 0, 0) == 0) { - if (prev != NULL) { - /* shift the element just found to the second position - * in the list */ - prev->next = data->next; - data->next = first->next; - first->next = data; - } - return 1; - } - prev = data; - data = data->next; + request_t *r = checklist->request; + const ipcache_addrs *ia = NULL; + const char *fqdn = NULL; + if (NULL == r) { + debug(28, 1) ("WARNING: '%s' ACL is used but there is no" + " HTTP request -- access denied.\n",ae->name); + return 0; + } + debug(28, 3) ("aclMatchDstDomain: checking '%s'\n", ae->cfgline); + + if ((ia = ipcacheCheckNumeric(r->host)) == NULL) + return aclMatchDomainList(&ae->data, r->host); + fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS); + if (fqdn) { + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + return aclMatchDomainList(&ae->data, fqdn); + } + if (checklist->lastcheckowner==NULL) { + debug(28, 3) ("aclMatchDstDomain: Can't yet compare '%s' ACL for '%s'\n", + ae->name, inet_ntoa(ia->in_addrs[0])); + checklist->lastcheckowner=ae; + checklist->lastcheckstate=ACL_LOOKUP_PENDING; + checklist->dst_addr = ia->in_addrs[0]; + fqdncache_nbgethostbyaddr(checklist->dst_addr, + aclLookupDstFQDNDone, checklist); + return ACL_MATCH_NEED_LOOKUP; + } else if (checklist->lastcheckowner==ae) { + /* ACL_LOOKUP_DONE is/should be caught by if (ia) */ + debug(28, 0) ("aclMatchDstDomain: Probable bug *****" + "Call to aclMatchDstDomain with lastcheckowner but no IP found with" + " '%s' ACL for '%s'\n", + ae->name, r->host); + return 0; + } + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; } - return 0; + return aclMatchDomainList(&ae->data, "none"); +} + +static void +aclLookupDstFQDNDone(const char *fqdn, void *data) +{ + aclCheck_t *checklist = data; + /* We don't reset the owner because the owner needs to test it */ + checklist->lastcheckstate = ACL_LOOKUP_DONE; + aclCheck(checklist); +#if 0 + aclCheck_t *checklist = data; + checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE; + aclCheck(checklist); +#endif +} + +static int +aclMatchSrcDomain(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + const char *fqdn = NULL; + debug(28, 3) ("aclMatchSrcDomain: checking '%s'\n", ae->cfgline); + + fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS); + if (fqdn) { + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + return aclMatchDomainList(&ae->data, fqdn); + } else if (checklist->lastcheckowner==NULL) { + debug(28, 3) ("aclMatchSrcDomain: Can't yet compare '%s' ACL for '%s'\n", + ae->name, inet_ntoa(checklist->src_addr)); + checklist->lastcheckowner=ae; + checklist->lastcheckstate=ACL_LOOKUP_PENDING; + fqdncache_nbgethostbyaddr(checklist->src_addr, + aclLookupSrcFQDNDone, checklist); + return ACL_MATCH_NEED_LOOKUP; + } else if (checklist->lastcheckowner==ae) { + /* ACL_LOOKUP_DONE is/should be caught by if (ia) */ + debug(28, 0) ("aclMatchSrcDomain: Probable bug *****" + "Call to aclMatchSrcDomain with lastcheckowner but no host info found with" + " '%s' ACL\n", + ae->name); + return 0; + } + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + return aclMatchDomainList(&ae->data, "none"); +} + +static void +aclLookupSrcFQDNDone(const char *fqdn, void *data) +{ + aclCheck_t *checklist = data; + /* We don't reset the owner because the owner needs to test it */ + checklist->lastcheckstate = ACL_LOOKUP_DONE; + aclCheck(checklist); +#if 0 + aclCheck_t *checklist = data; + checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_DONE; + aclCheck(checklist); +#endif +} + +/***************** + * aclMatchRegex * + *****************/ + +int +aclMatchRegex(relist * data, const char *word) +{ + relist *first, *prev; + if (word == NULL) + return 0; + debug(28, 3) ("aclMatchRegex: checking '%s'\n", word); + first = data; + prev = NULL; + while (data) { + debug(28, 3) ("aclMatchRegex: looking for '%s'\n", data->pattern); + if (regexec(&data->regex, word, 0, 0, 0) == 0) { + if (prev != NULL) { + /* shift the element just found to the second position + * in the list */ + prev->next = data->next; + data->next = first->next; + first->next = data; + } + return 1; + } + prev = data; + data = data->next; + } + return 0; +} + +static int +aclMatchUrlPathRegex(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + request_t *r = checklist->request; + char *esc_buf; + int k; + if (NULL == r) { + debug(28, 1) ("WARNING: 'urlpathregex' ACL is used but there is no" + " HTTP request -- access denied.\n"); + return 0; + } + debug(28, 3) ("aclMatchUrlPathRegex: checking '%s'\n", ae->cfgline); + esc_buf = xstrdup(strBuf(r->urlpath)); + rfc1738_unescape(esc_buf); + k = aclMatchRegex(ae->data, esc_buf); + safe_free(esc_buf); + return k; +} + +static int +aclMatchUrlRegex(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + request_t *r = checklist->request; + char *esc_buf; + int k; + if (NULL == r) { + debug(28, 1) ("WARNING: 'url_regex' ACL is used but there is no" + " HTTP request -- access denied.\n"); + return 0; + } + debug(28, 3) ("aclMatchUrlRegex: checking '%s'\n", ae->cfgline); + esc_buf = xstrdup(urlCanonical(r)); + rfc1738_unescape(esc_buf); + k = aclMatchRegex(ae->data, esc_buf); + safe_free(esc_buf); + return k; +} + +static int +aclMatchBrowser(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + request_t *r = checklist->request; + const char *browser; + if (NULL == r) { + debug(28, 1) ("WARNING: 'browser' ACL is used but there is no" + " HTTP request -- access denied.\n"); + return 0; + } + browser = httpHeaderGetStr(&r->header, HDR_USER_AGENT); + if (NULL == browser) + return 0; + return aclMatchRegex(ae->data, browser); +} + +static int +aclMatchReqMimeType(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + request_t *r = checklist->request; + const char *header; + if (NULL == r) { + debug(28, 1) ("WARNING: 'req_mime_type' ACL is used but there is no" + " HTTP request -- access denied.\n"); + return 0; + } + + header = httpHeaderGetStr(&r->header, + HDR_CONTENT_TYPE); + if (NULL == header) + header = ""; + return aclMatchRegex(ae->data, header); +} + + +static int +aclMatchRepMimeType(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + const char *header; + if (!checklist->reply) { + debug(28, 1) ("WARNING: 'rep_mime_type' ACL is used but there is no" + " HTTP reply -- access denied.\n"); + return 0; + } + header = httpHeaderGetStr(&checklist->reply->header, HDR_CONTENT_TYPE); + if (NULL == header) + header = ""; + return aclMatchRegex(ae->data, header); +} + +#if USE_IDENT +static int +aclMatchIdent(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + if (checklist->rfc931[0]) { + return aclMatchUser(ae->data, checklist->rfc931); + } else { + checklist->lastcheckowner=ae; + checklist->lastcheckstate=ACL_LOOKUP_PENDING; + debug(28, 3) ("aclCheck: Doing ident lookup\n"); + if (cbdataValid(checklist->conn)) { + identStart(&checklist->conn->me, &checklist->conn->peer, + aclLookupIdentDone, checklist); + return ACL_MATCH_NEED_LOOKUP; + } else { + debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n"); + cbdataUnlock(checklist->conn); + checklist->conn = NULL; + return ACL_MATCH_INSUFFICIENT_INFORMATION; + } + } +} + +static int +aclMatchIdentRegex(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + if (checklist->rfc931[0]) { + return aclMatchRegex(ae->data, checklist->rfc931); + } else { + checklist->lastcheckowner=ae; + checklist->lastcheckstate=ACL_LOOKUP_PENDING; + debug(28, 3) ("aclCheck: Doing ident lookup\n"); + if (cbdataValid(checklist->conn)) { + identStart(&checklist->conn->me, &checklist->conn->peer, + aclLookupIdentDone, checklist); + return ACL_MATCH_NEED_LOOKUP; + } else { + debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n"); + cbdataUnlock(checklist->conn); + checklist->conn = NULL; + return ACL_MATCH_INSUFFICIENT_INFORMATION; + } + } +} + +static void +aclLookupIdentDone(const char *ident, void *data) +{ + aclCheck_t *checklist = data; + if (ident) { + xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ); +#if DONT + xstrncpy(checklist->request->authuser, ident, USER_IDENT_SZ); +#endif + } else { + xstrncpy(checklist->rfc931, dash_str, USER_IDENT_SZ); + } + /* + * Cache the ident result in the connection, to avoid redoing ident lookup + * over and over on persistent connections + */ + if (cbdataValid(checklist->conn) && !checklist->conn->rfc931[0]) + xstrncpy(checklist->conn->rfc931, checklist->rfc931, USER_IDENT_SZ); + aclCheck(checklist); +} +#endif + +static int +aclMatchProxyAuth(acl * , http_hdr_type headertype, + auth_user_request_t * auth_user_request, aclCheck_t * checklist); + +static int +aclMatchProxyAuthModule(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + request_t *r = checklist->request; + http_hdr_type headertype; + if (NULL == r) { + return ACL_MATCH_INSUFFICIENT_INFORMATION; + } else if (!r->flags.accelerated) { + /* Proxy authorization on proxy requests */ + headertype = HDR_PROXY_AUTHORIZATION; + } else if (r->flags.internal) { + /* WWW authorization on accelerated internal requests */ + headertype = HDR_AUTHORIZATION; + } else { +#if AUTH_ON_ACCELERATION + /* WWW authorization on accelerated requests */ + headertype = HDR_AUTHORIZATION; +#else +//FIXME + debug(28, 1) ("aclMatchProxyAuthModule: proxy_auth acls not applicable " + "on accelerated requests.\n"); + return ACL_MATCH_INSUFFICIENT_INFORMATION; +#endif + } + + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + /* Check the credentials */ + switch (aclMatchProxyAuth(ae, headertype, + checklist->auth_user_request, checklist)) { + case 0: + debug(28, 4) ("aclMatchProxyAuthModule: returning 0 user authenticated " + "but not authorised.\n"); + /* Authenticated but not Authorised for this ACL */ + return 0; + case 1: + debug(28, 4) ("aclMatchProxyAuthModule: returning 1 user authenticated " + "and authorised.\n"); + /* Authenticated and Authorised for this ACL */ + return 1; + case -2: + debug(28, 4) ("aclMatchProxyAuthModule: returning 0 sending authentication " + "challenge.\n"); + /* Authentication credentials invalid or missing. */ + /* Or partway through NTLM handshake. A proxy_Authenticate header + * gets sent to the client. */ + /* Client is required to resend the request with correct authentication + * credentials. (This may be part of a stateful auth protocol. + * The request is denied. + */ + debug(28, 6) ("aclCheck: requiring Proxy Auth header.\n"); + return ACL_MATCH_INSUFFICIENT_INFORMATION; + case -1: + debug(28, 4) ("aclMatchProxyAuthModule: returning 0 sending credentials " + "to helper.\n"); + /* + * we need to validate the password + */ + checklist->lastcheckowner=ae; + checklist->lastcheckstate=ACL_LOOKUP_PENDING; + debug(28, 3) + ("aclCheck: checking password via authenticator\n"); + aclLookupProxyAuthStart(checklist); + return ACL_MATCH_NEED_LOOKUP; + default: + return 0; + } +} + +static void +aclLookupProxyAuthDone(void *data, char *result) +{ + aclCheck_t *checklist = data; + auth_user_request_t *auth_user_request; + /* We don't reset the owner because the owner needs to test it */ + checklist->lastcheckstate = ACL_LOOKUP_DONE; + if (result != NULL) + fatal("AclLookupProxyAuthDone: Old code floating around somewhere.\nMake clean and + if that doesn't work, report a bug to the squid developers.\n"); + /* state info check */ + assert(checklist->conn != NULL); + auth_user_request = checklist->auth_user_request; + if (!authenticateValidateUser(auth_user_request)) { + /* credentials could not be checked either way + * restart the whole process */ + checklist->conn->auth_user_request = NULL; + checklist->conn->auth_type = AUTH_BROKEN; + checklist->auth_user_request = NULL; + authenticateAuthUserRequestUnlock(auth_user_request); + aclCheck(checklist); + return; + } + aclCheck(checklist); +} + +static int +aclMatchMaxConn(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + int k; + k = clientdbEstablished(checklist->src_addr, 0); + // FIXME we should drop the connection this request was made on or all other + // Requests will fail until the link times out. + return ((k > (int) ae->data) ? 1 : 0); } static int @@ -1122,8 +1496,7 @@ * RBC */ static int -aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, - char *MatchParam) +aclCacheMatchAcl(dlink_list * cache, acl * ae, char *MatchParam) { int matchrv; acl_proxy_auth_match_cache *auth_match; @@ -1131,29 +1504,36 @@ link = cache->head; while (link) { auth_match = link->data; - if (auth_match->acl_data == data) { - debug(28, 4) ("aclCacheMatchAcl: cache hit on acl '%d'\n", data); + if (auth_match->acl_data == ae->data) { + debug(28, 4) ("aclCacheMatchAcl: cache hit on acl '%d'\n", ae->data); return auth_match->matchrv; } link = link->next; } auth_match = NULL; /* match the user in the acl. They are not cached. */ - switch (acltype) { - case ACL_PROXY_AUTH: - matchrv = aclMatchUser(data, MatchParam); - break; - case ACL_PROXY_AUTH_REGEX: - matchrv = aclMatchRegex(data, MatchParam); - default: +#if 0 + /* WARNING: this does _not_ sanity check the ACL type. ONLY use for cacheable + * acl responses + */ + matchrv = ae->aclname->match(data, MatchParam); +#endif + /* TODO: we need a generic way of getting down to these functions to make acl + * result caching extendible... + */ + if (ae->aclname==proxy_auth_name) { + matchrv = aclMatchUser(ae->data, MatchParam); + } else if (ae->aclname==proxy_auth_regex_name) { + matchrv = aclMatchRegex(ae->data, MatchParam); + } else { /* This is a fatal to ensure that aclCacheMatchAcl calls are _only_ * made for supported acl types */ fatal("aclCacheMatchAcl: unknown or unexpected ACL type"); return 0; /* NOTREACHED */ } - auth_match = memAllocate(MEM_ACL_PROXY_AUTH_MATCH); + auth_match = memPoolAlloc(acl_proxy_auth_match_pool); auth_match->matchrv = matchrv; - auth_match->acl_data = data; + auth_match->acl_data = ae->data; dlinkAddTail(auth_match, &auth_match->link, cache); return matchrv; } @@ -1169,7 +1549,7 @@ tmplink = link; link = link->next; dlinkDelete(tmplink, cache); - memFree(auth_match, MEM_ACL_PROXY_AUTH_MATCH); + memPoolFree(acl_proxy_auth_match_pool, auth_match); } } @@ -1180,9 +1560,8 @@ * -2 : send data to the client */ static int -aclMatchProxyAuth(void *data, http_hdr_type headertype, - auth_user_request_t * auth_user_request, aclCheck_t * checklist, - squid_acl acltype) +aclMatchProxyAuth(acl * ae, http_hdr_type headertype, + auth_user_request_t * auth_user_request, aclCheck_t * checklist) { /* checklist is used to register user name when identified, nothing else */ const char *proxy_auth; @@ -1192,7 +1571,7 @@ /* General program flow in proxy_auth acls * 1. Consistency checks: are we getting sensible data * 2. Call the authenticate* functions to establish a authenticated user - * 4. look up the username in acltype (and cache the result against the + * 4. look up the username in acl (and cache the result against the * username */ @@ -1326,7 +1705,7 @@ authenticateAuthUserRequestUnlock(auth_user_request); /* check to see if we have matched the user-acl before */ return aclCacheMatchAcl(&auth_user_request->auth_user-> - proxy_match_cache, acltype, data, + proxy_match_cache, ae, authenticateUserRequestUsername(auth_user_request)); } /* this acl check completed */ @@ -1397,7 +1776,7 @@ } static int -aclMatchTime(acl_time_data * data, time_t when) +aclMatchTimeSpec(acl_time_data * data, time_t when) { static time_t last_when = 0; static struct tm tm; @@ -1408,7 +1787,7 @@ xmemcpy(&tm, localtime(&when), sizeof(struct tm)); } t = (time_t) (tm.tm_hour * 60 + tm.tm_min); - debug(28, 3) ("aclMatchTime: checking %d in %d-%d, weekbits=%x\n", + debug(28, 3) ("aclMatchTimeSpec: checking %d in %d-%d, weekbits=%x\n", (int) t, (int) data->start, (int) data->stop, data->weekbits); if (t < data->start || t > data->stop) @@ -1416,6 +1795,30 @@ return data->weekbits & (1 << tm.tm_wday) ? 1 : 0; } +static int +aclMatchTime(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + return aclMatchTimeSpec(ae->data, squid_curtime); +} + +static int +aclMatchUrlPort(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + request_t *r = checklist->request; + if (NULL == r) { + debug(28, 1) ("WARNING: 'req_mime_type' ACL is used but there is no" + " HTTP request -- access denied.\n"); + return 0; + } + return aclMatchIntegerRange(ae->data, (int) r->port); +} + +static int +aclMatchMyPort(acl * ae, aclCheck_t * checklist, unsigned int flags) +{ + return aclMatchIntegerRange(ae->data, (int) checklist->my_port); +} + #if SQUID_SNMP static int aclMatchWordList(wordlist * w, const char *word) @@ -1429,279 +1832,129 @@ } return 0; } + +static int +aclMatchSNMPCommunity(acl * ae, aclCheck_t *checklist, unsigned int flags) +{ + return aclMatchWordList(ae->data, checklist->snmp_community); +} #endif +static int +aclMatchProto(acl * ae, aclCheck_t *checklist, unsigned int flags) +{ + request_t *r = checklist->request; + if (NULL == r) { + debug(28, 1) ("WARNING: 'proto' ACL is used but there is no" + " HTTP request -- access denied.\n"); + return 0; + } + return aclMatchInteger(ae->data, r->protocol); +} + static int -aclMatchAcl(acl * ae, aclCheck_t * checklist) +aclMatchMethod(acl * ae, aclCheck_t *checklist, unsigned int flags) +{ + request_t *r = checklist->request; + if (NULL == r) { + debug(28, 1) ("WARNING: 'method' ACL is used but there is no" + " HTTP request -- access denied.\n"); + return 0; + } + return aclMatchInteger(ae->data, r->method); +} + + +static int +aclMatchSrcAsn(acl * ae, aclCheck_t *checklist, unsigned int flags) +{ + return asnMatchIp(ae->data, checklist->src_addr); +} + +static int +aclMatchDstAsn(acl * ae, aclCheck_t *checklist, unsigned int flags) { request_t *r = checklist->request; const ipcache_addrs *ia = NULL; - const char *fqdn = NULL; - char *esc_buf; - const char *header; - const char *browser; int k; - http_hdr_type headertype; - if (!ae) - return 0; - switch (ae->type) { - case ACL_DST_IP: - case ACL_DST_DOMAIN: - case ACL_DST_DOM_REGEX: - case ACL_URLPATH_REGEX: - case ACL_URL_PORT: - case ACL_PROTO: - case ACL_METHOD: - case ACL_DST_ASN: - /* These ACL types require checklist->request */ - if (NULL == r) { - debug(28, 1) ("WARNING: '%s' ACL is used but there is no" - " HTTP request -- access denied.\n", ae->name); - return 0; - } - break; - default: - break; - } - debug(28, 3) ("aclMatchAcl: checking '%s'\n", ae->cfgline); - switch (ae->type) { - case ACL_SRC_IP: - return aclMatchIp(&ae->data, checklist->src_addr); - /* NOTREACHED */ - case ACL_MY_IP: - return aclMatchIp(&ae->data, checklist->my_addr); - /* NOTREACHED */ - case ACL_DST_IP: - ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS); - if (ia) { - for (k = 0; k < (int) ia->count; k++) { - if (aclMatchIp(&ae->data, ia->in_addrs[k])) - return 1; - } - return 0; - } else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) { - debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", - ae->name, r->host); - checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEEDED; - return 0; - } else { - return aclMatchIp(&ae->data, no_addr); - } - /* NOTREACHED */ - case ACL_DST_DOMAIN: - if ((ia = ipcacheCheckNumeric(r->host)) == NULL) - return aclMatchDomainList(&ae->data, r->host); - fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS); - if (fqdn) - return aclMatchDomainList(&ae->data, fqdn); - if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) { - debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", - ae->name, inet_ntoa(ia->in_addrs[0])); - checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED; - return 0; - } - return aclMatchDomainList(&ae->data, "none"); - /* NOTREACHED */ - case ACL_SRC_DOMAIN: - fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS); - if (fqdn) { - return aclMatchDomainList(&ae->data, fqdn); - } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) { - debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", - ae->name, inet_ntoa(checklist->src_addr)); - checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED; - return 0; - } - return aclMatchDomainList(&ae->data, "none"); - /* NOTREACHED */ - case ACL_DST_DOM_REGEX: - if ((ia = ipcacheCheckNumeric(r->host)) == NULL) - return aclMatchRegex(ae->data, r->host); - fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS); - if (fqdn) - return aclMatchRegex(ae->data, fqdn); - if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) { - debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", - ae->name, inet_ntoa(ia->in_addrs[0])); - checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED; - return 0; - } - return aclMatchRegex(ae->data, "none"); - /* NOTREACHED */ - case ACL_SRC_DOM_REGEX: - fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS); - if (fqdn) { - return aclMatchRegex(ae->data, fqdn); - } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) { - debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", - ae->name, inet_ntoa(checklist->src_addr)); - checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED; - return 0; - } - return aclMatchRegex(ae->data, "none"); - /* NOTREACHED */ - case ACL_TIME: - return aclMatchTime(ae->data, squid_curtime); - /* NOTREACHED */ - case ACL_URLPATH_REGEX: - esc_buf = xstrdup(strBuf(r->urlpath)); - rfc1738_unescape(esc_buf); - k = aclMatchRegex(ae->data, esc_buf); - safe_free(esc_buf); - return k; - /* NOTREACHED */ - case ACL_URL_REGEX: - esc_buf = xstrdup(urlCanonical(r)); - rfc1738_unescape(esc_buf); - k = aclMatchRegex(ae->data, esc_buf); - safe_free(esc_buf); - return k; - /* NOTREACHED */ - case ACL_MAXCONN: - k = clientdbEstablished(checklist->src_addr, 0); - return ((k > ((intlist *) ae->data)->i) ? 1 : 0); - /* NOTREACHED */ - case ACL_URL_PORT: - return aclMatchIntegerRange(ae->data, (int) r->port); - /* NOTREACHED */ - case ACL_MY_PORT: - return aclMatchIntegerRange(ae->data, (int) checklist->my_port); - /* NOTREACHED */ -#if USE_IDENT - case ACL_IDENT: - if (checklist->rfc931[0]) { - return aclMatchUser(ae->data, checklist->rfc931); - } else { - checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED; - return 0; - } - /* NOTREACHED */ - case ACL_IDENT_REGEX: - if (checklist->rfc931[0]) { - return aclMatchRegex(ae->data, checklist->rfc931); - } else { - checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED; - return 0; - } - /* NOTREACHED */ -#endif - case ACL_PROTO: - return aclMatchInteger(ae->data, r->protocol); - /* NOTREACHED */ - case ACL_METHOD: - return aclMatchInteger(ae->data, r->method); - /* NOTREACHED */ - case ACL_BROWSER: - browser = httpHeaderGetStr(&checklist->request->header, HDR_USER_AGENT); - if (NULL == browser) - return 0; - return aclMatchRegex(ae->data, browser); - /* NOTREACHED */ - case ACL_PROXY_AUTH: - case ACL_PROXY_AUTH_REGEX: - if (NULL == r) { - return -1; - } else if (!r->flags.accelerated) { - /* Proxy authorization on proxy requests */ - headertype = HDR_PROXY_AUTHORIZATION; - } else if (r->flags.internal) { - /* WWW authorization on accelerated internal requests */ - headertype = HDR_AUTHORIZATION; - } else { -#if AUTH_ON_ACCELERATION - /* WWW authorization on accelerated requests */ - headertype = HDR_AUTHORIZATION; -#else - debug(28, 1) ("aclMatchAcl: proxy_auth %s not applicable on accelerated requests.\n", ae->name); - return -1; -#endif - } - /* Check the credentials */ - switch (aclMatchProxyAuth(ae->data, headertype, - checklist->auth_user_request, checklist, ae->type)) { - case 0: - debug(28, 4) ("aclMatchAcl: returning 0 user authenticated but not authorised.\n"); - /* Authenticated but not Authorised for this ACL */ - return 0; - case 1: - debug(28, 4) ("aclMatchAcl: returning 1 user authenticated and authorised.\n"); - /* Authenticated and Authorised for this ACL */ - return 1; - case -2: - debug(28, 4) ("aclMatchAcl: returning 0 sending authentication challenge.\n"); - /* Authentication credentials invalid or missing. */ - /* Or partway through NTLM handshake. A proxy_Authenticate header - * gets sent to the client. */ - checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED; - return 0; - case -1: - debug(28, 4) ("aclMatchAcl: returning 0 sending credentials to helper.\n"); - /* - * we need to validate the password - */ - checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_NEEDED; - return 0; - } - /* NOTREACHED */ -#if SQUID_SNMP - case ACL_SNMP_COMMUNITY: - return aclMatchWordList(ae->data, checklist->snmp_community); -#endif - case ACL_SRC_ASN: - return asnMatchIp(ae->data, checklist->src_addr); - case ACL_DST_ASN: - ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS); - if (ia) { - for (k = 0; k < (int) ia->count; k++) { - if (asnMatchIp(ae->data, ia->in_addrs[k])) - return 1; - } - return 0; - } else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NONE) { - debug(28, 3) ("asnMatchAcl: Can't yet compare '%s' ACL for '%s'\n", - ae->name, r->host); - checklist->state[ACL_DST_ASN] = ACL_LOOKUP_NEEDED; - } else { - return asnMatchIp(ae->data, no_addr); - } - return 0; -#if USE_ARP_ACL - case ACL_SRC_ARP: - return aclMatchArp(&ae->data, checklist->src_addr); -#endif - case ACL_REQ_MIME_TYPE: - header = httpHeaderGetStr(&checklist->request->header, - HDR_CONTENT_TYPE); - if (NULL == header) - header = ""; - return aclMatchRegex(ae->data, header); - /* NOTREACHED */ - case ACL_REP_MIME_TYPE: - if (!checklist->reply) - return 0; - header = httpHeaderGetStr(&checklist->reply->header, HDR_CONTENT_TYPE); - if (NULL == header) - header = ""; - return aclMatchRegex(ae->data, header); - /* NOTREACHED */ - case ACL_NONE: - case ACL_ENUM_MAX: - break; + if (NULL == r) { + debug(28, 1) ("WARNING: 'dst_asn' ACL is used but there is no" + " HTTP request -- access denied.\n"); + return 0; + } + + ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS); + if (ia) { + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + for (k = 0; k < (int) ia->count; k++) { + if (asnMatchIp(ae->data, ia->in_addrs[k])) + return 1; + } + return 0; + } else if (checklist->lastcheckowner==NULL) { + debug(28, 3) ("asnMatchAcl: Can't yet compare '%s' ACL for '%s'\n", + ae->name, r->host); + checklist->lastcheckowner=ae; + checklist->lastcheckstate=ACL_LOOKUP_PENDING; + ipcache_nbgethostbyname(checklist->request->host, + aclLookupDstIPforASNDone, checklist); + return ACL_MATCH_NEED_LOOKUP; + } else if (checklist->lastcheckowner==ae) { + /* ACL_LOOKUP_DONE is/should be caught by if (ia) */ + debug(28, 0) ("aclMatchDstAsn: Probable bug *****" + "Call to aclMatchDstAsn with lastcheckowner but no IP found with" + " '%s' ACL for '%s'\n", + ae->name, r->host); + return 0; + } else { + if (checklist->lastcheckowner==ae) { + checklist->lastcheckowner=NULL; + checklist->lastcheckstate=ACL_LOOKUP_NONE; + } + return asnMatchIp(ae->data, no_addr); } - debug(28, 0) ("aclMatchAcl: '%s' has bad type %d\n", - ae->name, ae->type); return 0; } -int -aclMatchAclList(const acl_list * list, aclCheck_t * checklist) +static void +aclLookupDstIPforASNDone(const ipcache_addrs * ia, void *data) +{ + aclCheck_t *checklist = data; + /* We don't reset the owner because the owner needs to test it */ + checklist->lastcheckstate = ACL_LOOKUP_DONE; + aclCheck(checklist); +} + +/* test each acl in a list for a match. + * if the result does not match the logic test, stop iterating and return + * allowed match rvs are : ACL_MATCH_NEED_LOOKUP, ACL_MATCH_FOUND, ACL_MATCH_NOTFOUND + */ + +/* TODO: cache acl results for a given request. This will lower CPU use with reused + * regex's in multiple lists (ie + * + * http_access deny !expensive_test src1 + * http_access allow exepnsive_test group2 + */ + +static int +aclMatchAclList(const acl_list * list, aclCheck_t * checklist, unsigned int flags) { + int result; while (list) { AclMatchedName = list->acl->name; + AclMatchedAcl = list->acl; debug(28, 3) ("aclMatchAclList: checking %s%s\n", list->op ? null_string : "!", list->acl->name); - if (aclMatchAcl(list->acl, checklist) != list->op) { + if ((result=list->acl->aclname->match(list->acl, checklist, flags)) != list->op) { debug(28, 3) ("aclMatchAclList: returning 0\n"); + if (result==ACL_MATCH_NEED_LOOKUP) + return ACL_MATCH_NEED_LOOKUP; + if (result==ACL_MATCH_INSUFFICIENT_INFORMATION) + return ACL_MATCH_INSUFFICIENT_INFORMATION; return 0; } list = list->next; @@ -1717,7 +1970,8 @@ debug(28, 5) ("aclCheckFast: list: %p\n", A); while (A) { allow = A->allow; - if (aclMatchAclList(A->acl_list, checklist)) + /* we never get -1 as a result, -1 is only allowed for non FASTCHECKS */ + if (aclMatchAclList(A->acl_list, checklist, ACL_FASTCHECK)) return allow == ACCESS_ALLOWED; A = A->next; } @@ -1731,7 +1985,6 @@ allow_t allow = ACCESS_DENIED; const acl_access *A; int match; - ipcache_addrs *ia; while ((A = checklist->access_list) != NULL) { /* * If the _acl_access is no longer valid (i.e. its been @@ -1744,82 +1997,32 @@ } debug(28, 3) ("aclCheck: checking '%s'\n", A->cfgline); allow = A->allow; - match = aclMatchAclList(A->acl_list, checklist); - if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NEEDED) { - checklist->state[ACL_DST_IP] = ACL_LOOKUP_PENDING; - ipcache_nbgethostbyname(checklist->request->host, - aclLookupDstIPDone, checklist); - return; - } else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NEEDED) { - checklist->state[ACL_DST_ASN] = ACL_LOOKUP_PENDING; - ipcache_nbgethostbyname(checklist->request->host, - aclLookupDstIPforASNDone, checklist); + switch (match = aclMatchAclList(A->acl_list, checklist, 0)) { + case ACL_MATCH_NEED_LOOKUP: + /* the current list needs to perform a lookup of some sort */ return; - } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NEEDED) { - checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_PENDING; - fqdncache_nbgethostbyaddr(checklist->src_addr, - aclLookupSrcFQDNDone, checklist); - return; - } else if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NEEDED) { - ia = ipcacheCheckNumeric(checklist->request->host); - if (ia == NULL) { - checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE; - return; - } - checklist->dst_addr = ia->in_addrs[0]; - checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_PENDING; - fqdncache_nbgethostbyaddr(checklist->dst_addr, - aclLookupDstFQDNDone, checklist); - return; - } else if (checklist->state[ACL_PROXY_AUTH] == ACL_LOOKUP_NEEDED) { - debug(28, 3) - ("aclCheck: checking password via authenticator\n"); - aclLookupProxyAuthStart(checklist); - checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_PENDING; - return; - } else if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED) { - /* Client is required to resend the request with correct authentication - * credentials. (This may be part of a stateful auth protocol. - * The request is denied. - */ - debug(28, 6) ("aclCheck: requiring Proxy Auth header.\n"); - allow = ACCESS_REQ_PROXY_AUTH; - match = -1; - } -#if USE_IDENT - else if (checklist->state[ACL_IDENT] == ACL_LOOKUP_NEEDED) { - debug(28, 3) ("aclCheck: Doing ident lookup\n"); - if (cbdataValid(checklist->conn)) { - identStart(&checklist->conn->me, &checklist->conn->peer, - aclLookupIdentDone, checklist); - checklist->state[ACL_IDENT] = ACL_LOOKUP_PENDING; - return; - } else { - debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n"); - cbdataUnlock(checklist->conn); - checklist->conn = NULL; - allow = 0; - match = -1; - } - } -#endif - /* - * We are done with this _acl_access entry. Either the request - * is allowed, denied, requires authentication, or we move on to - * the next entry. - */ - cbdataUnlock(A); - if (match) { + break; + case ACL_MATCH_INSUFFICIENT_INFORMATION: + /* There is not enough information in the checklist to determine a match + * or non-match + */ + allow = ACCESS_DENIED; + case ACL_MATCH_FOUND: + cbdataUnlock(A); debug(28, 3) ("aclCheck: match found, returning %d\n", allow); aclCheckCallback(checklist, allow); return; + break; + case ACL_MATCH_NOTFOUND: + cbdataUnlock(A); + checklist->access_list = A->next; + /* + * Lock the next _acl_access entry + */ + if (A->next) + cbdataLock(A->next); + break; } - checklist->access_list = A->next; - /* - * Lock the next _acl_access entry - */ - if (A->next) - cbdataLock(A->next); } debug(28, 3) ("aclCheck: NO match found, returning %d\n", allow != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED); aclCheckCallback(checklist, allow != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED); @@ -1853,91 +2056,12 @@ aclChecklistFree(checklist); } -#if USE_IDENT -static void -aclLookupIdentDone(const char *ident, void *data) -{ - aclCheck_t *checklist = data; - if (ident) { - xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ); -#if DONT - xstrncpy(checklist->request->authuser, ident, USER_IDENT_SZ); -#endif - } else { - xstrncpy(checklist->rfc931, dash_str, USER_IDENT_SZ); - } - /* - * Cache the ident result in the connection, to avoid redoing ident lookup - * over and over on persistent connections - */ - if (cbdataValid(checklist->conn) && !checklist->conn->rfc931[0]) - xstrncpy(checklist->conn->rfc931, checklist->rfc931, USER_IDENT_SZ); - aclCheck(checklist); -} -#endif - -static void -aclLookupDstIPDone(const ipcache_addrs * ia, void *data) -{ - aclCheck_t *checklist = data; - checklist->state[ACL_DST_IP] = ACL_LOOKUP_DONE; - aclCheck(checklist); -} - -static void -aclLookupDstIPforASNDone(const ipcache_addrs * ia, void *data) -{ - aclCheck_t *checklist = data; - checklist->state[ACL_DST_ASN] = ACL_LOOKUP_DONE; - aclCheck(checklist); -} - -static void -aclLookupSrcFQDNDone(const char *fqdn, void *data) -{ - aclCheck_t *checklist = data; - checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_DONE; - aclCheck(checklist); -} - -static void -aclLookupDstFQDNDone(const char *fqdn, void *data) -{ - aclCheck_t *checklist = data; - checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE; - aclCheck(checklist); -} - -static void -aclLookupProxyAuthDone(void *data, char *result) -{ - aclCheck_t *checklist = data; - auth_user_request_t *auth_user_request; - checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE; - if (result != NULL) - fatal("AclLookupProxyAuthDone: Old code floating around somewhere.\nMake clean and if that doesn't work, report a bug to the squid developers.\n"); - /* state info check */ - assert(checklist->conn != NULL); - auth_user_request = checklist->auth_user_request; - if (!authenticateValidateUser(auth_user_request)) { - /* credentials could not be checked either way - * restart the whole process */ - checklist->conn->auth_user_request = NULL; - checklist->conn->auth_type = AUTH_BROKEN; - checklist->auth_user_request = NULL; - authenticateAuthUserRequestUnlock(auth_user_request); - aclCheck(checklist); - return; - } - aclCheck(checklist); -} - aclCheck_t * aclChecklistCreate(const acl_access * A, request_t * request, const char *ident) { - int i; aclCheck_t *checklist; checklist = cbdataAlloc(aclCheck_t); + memset (checklist, '\0', sizeof (aclCheck_t)); checklist->access_list = A; /* * aclCheck() makes sure checklist->access_list is a valid @@ -1950,13 +2074,10 @@ checklist->my_addr = request->my_addr; checklist->my_port = request->my_port; } - for (i = 0; i < ACL_ENUM_MAX; i++) - checklist->state[i] = ACL_LOOKUP_NONE; #if USE_IDENT if (ident) xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ); #endif - checklist->auth_user_request = NULL; return checklist; } @@ -1969,29 +2090,25 @@ aclCheck(checklist); } - - - - - - /*********************/ /* Destroy functions */ /*********************/ static void -aclDestroyTimeList(acl_time_data * data) +aclDestroyTimeSpecList(parserNameNode *parserName, void * dataptr) { + acl_time_data * data = dataptr; acl_time_data *next = NULL; for (; data; data = next) { next = data->next; - memFree(data, MEM_ACL_TIME_DATA); + memPoolFree(acl_time_data_pool, data); } } void -aclDestroyRegexList(relist * data) +aclDestroyRegexList(parserNameNode *parserName, void * dataptr) { + relist * data = dataptr; relist *next = NULL; for (; data; data = next) { next = data->next; @@ -2004,19 +2121,36 @@ static void aclFreeIpData(void *p) { - memFree(p, MEM_ACL_IP_DATA); + memPoolFree(acl_ip_data_pool, p); +} + +static void +aclDestroyIpList(parserNameNode *parserName, void * data) +{ + acl ** head=(acl **)data; + acl *a=*head; + if (a) + splay_destroy(a->data,aclFreeIpData); +} + +static void +aclDestroyDomainList(parserNameNode *parserName, void * data) +{ + acl ** head=(acl **)data; + acl *a=*head; + if (a) + splay_destroy(a->data, xfree); } static void -aclFreeUserData(void *data) +aclDestroyUserList(parserNameNode *parserName, void *data) { acl_user_data *d = data; if (d->names) splay_destroy(d->names, xfree); - memFree(d, MEM_ACL_USER_DATA); + memPoolFree(acl_user_data_pool, d); } - void aclDestroyAcls(acl ** head) { @@ -2025,69 +2159,9 @@ for (a = *head; a; a = next) { next = a->next; debug(28, 3) ("aclDestroyAcls: '%s'\n", a->cfgline); - switch (a->type) { - case ACL_SRC_IP: - case ACL_DST_IP: - case ACL_MY_IP: - splay_destroy(a->data, aclFreeIpData); - break; -#if USE_ARP_ACL - case ACL_SRC_ARP: -#endif - case ACL_DST_DOMAIN: - case ACL_SRC_DOMAIN: - splay_destroy(a->data, xfree); - break; -#if SQUID_SNMP - case ACL_SNMP_COMMUNITY: - wordlistDestroy((wordlist **) & a->data); - break; -#endif -#if USE_IDENT - case ACL_IDENT: - aclFreeUserData(a->data); - break; -#endif - case ACL_PROXY_AUTH: - aclFreeUserData(a->data); - break; - case ACL_TIME: - aclDestroyTimeList(a->data); - break; -#if USE_IDENT - case ACL_IDENT_REGEX: -#endif - case ACL_PROXY_AUTH_REGEX: - case ACL_URL_REGEX: - case ACL_URLPATH_REGEX: - case ACL_BROWSER: - case ACL_SRC_DOM_REGEX: - case ACL_DST_DOM_REGEX: - case ACL_REP_MIME_TYPE: - case ACL_REQ_MIME_TYPE: - aclDestroyRegexList(a->data); - break; - case ACL_PROTO: - case ACL_METHOD: - case ACL_SRC_ASN: - case ACL_DST_ASN: -#if SRC_RTT_NOT_YET_FINISHED - case ACL_NETDB_SRC_RTT: -#endif - case ACL_MAXCONN: - intlistDestroy((intlist **) & a->data); - break; - case ACL_URL_PORT: - case ACL_MY_PORT: - aclDestroyIntRange(a->data); - break; - case ACL_NONE: - case ACL_ENUM_MAX: - debug(28, 1) ("aclDestroyAcls: no case for ACL type %d\n", a->type); - break; - } safe_free(a->cfgline); - memFree(a, MEM_ACL); + memPoolFree(acl_pool, a); + // Should we be locking the aclname struct and unlocking here? } *head = NULL; } @@ -2118,32 +2192,10 @@ *list = NULL; } -/* maex@space.net (06.09.1996) - * destroy an _acl_deny_info_list */ - -void -aclDestroyDenyInfoList(acl_deny_info_list ** list) -{ - acl_deny_info_list *a = NULL; - acl_deny_info_list *a_next = NULL; - acl_name_list *l = NULL; - acl_name_list *l_next = NULL; - - for (a = *list; a; a = a_next) { - for (l = a->acl_list; l; l = l_next) { - l_next = l->next; - safe_free(l); - } - a_next = a->next; - xfree(a->err_page_name); - memFree(a, MEM_ACL_DENY_INFO_LIST); - } - *list = NULL; -} - static void -aclDestroyIntRange(intrange * list) +aclDestroyIntRange(parserNameNode *parserName, void * data) { + intrange * list = data; intrange *w = NULL; intrange *n = NULL; for (w = list; w; w = n) { @@ -2375,62 +2427,211 @@ return W; } -wordlist * -aclDumpGeneric(const acl * a) +static void +dump_IpList(StoreEntry * entry, const char *name, void const * const data) { - debug(28, 3) ("aclDumpGeneric: %s type %d\n", a->name, a->type); - switch (a->type) { - case ACL_SRC_IP: - case ACL_DST_IP: - case ACL_MY_IP: - return aclDumpIpList(a->data); - case ACL_SRC_DOMAIN: - case ACL_DST_DOMAIN: - return aclDumpDomainList(a->data); -#if SQUID_SNMP - case ACL_SNMP_COMMUNITY: - return wordlistDup(a->data); -#endif -#if USE_IDENT - case ACL_IDENT: - return aclDumpUserList(a->data); - case ACL_IDENT_REGEX: - return aclDumpRegexList(a->data); -#endif - case ACL_PROXY_AUTH: - return aclDumpUserList(a->data); - case ACL_TIME: - return aclDumpTimeSpecList(a->data); - case ACL_PROXY_AUTH_REGEX: - case ACL_URL_REGEX: - case ACL_URLPATH_REGEX: - case ACL_BROWSER: - case ACL_SRC_DOM_REGEX: - case ACL_DST_DOM_REGEX: - case ACL_REQ_MIME_TYPE: - case ACL_REP_MIME_TYPE: - return aclDumpRegexList(a->data); - case ACL_SRC_ASN: - case ACL_MAXCONN: - case ACL_DST_ASN: - return aclDumpIntlistList(a->data); - case ACL_URL_PORT: - case ACL_MY_PORT: - return aclDumpIntRangeList(a->data); - case ACL_PROTO: - return aclDumpProtoList(a->data); - case ACL_METHOD: - return aclDumpMethodList(a->data); -#if USE_ARP_ACL - case ACL_SRC_ARP: - return aclDumpArpList(a->data); -#endif - case ACL_NONE: - case ACL_ENUM_MAX: - break; + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_IpList: %s %s\n", name, ae->name); + v = w = aclDumpIpList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_IpList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static void +dump_DomainList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_DomainList: %s %s\n", name, ae->name); + v = w = aclDumpDomainList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_DomainList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static void +dump_RegexList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_RegexList: %s %s\n", name, ae->name); + v = w = aclDumpRegexList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_RegexList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static void +dump_TimeSpec(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_TimeSpec: %s %s\n", name, ae->name); + v = w = aclDumpTimeSpecList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_TimeSpec: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static void +dump_intlistList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_intlistList: %s %s\n", name, ae->name); + v = w = aclDumpIntlistList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_intlistList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static void +dump_IntRangeList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_IntRangeList: %s %s\n", name, ae->name); + v = w = aclDumpIntRangeList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_IntRangeList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static void +dump_UserList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_UserList: %s %s\n", name, ae->name); + v = w = aclDumpUserList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_UserList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static void +dump_ProtoList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_ProtoList: %s %s\n", name, ae->name); + v = w = aclDumpProtoList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_ProtoList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +static void +dump_MethodList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_MethodList: %s %s\n", name, ae->name); + v = w = aclDumpMethodList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_MethodList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; } - debug(28, 1) ("aclDumpGeneric: no case for ACL type %d\n", a->type); - return NULL; } /* @@ -2443,9 +2644,13 @@ aclPurgeMethodInUse(acl_access * a) { acl_list *b; + aclName *method = aclNameByName("method"); + if (!method) + /* method name not present */ + return 0; for (; a; a = a->next) { for (b = a->acl_list; b; b = b->next) { - if (ACL_METHOD != b->acl->type) + if (method != b->acl->aclname) continue; if (aclMatchInteger(b->acl->data, METHOD_PURGE)) return 1; @@ -2454,380 +2659,310 @@ return 0; } +/* === CONFIG SUPPORT ROUTINES === */ -#if USE_ARP_ACL -/* ==== BEGIN ARP ACL SUPPORT ============================================= */ +static int +check_null_acl() +{ +// return a == NULL; + // FIXME: heal the abstraction + parserNameNode *parserName = parserNameByName("acl"); + return (parserName->children.head==NULL); +} +/* temp home to test with */ +static void +default_if_none_acl(void * data){ + if (check_null_acl()) { + default_line("acl all src 0.0.0.0/0.0.0.0"); + } +} + +static void +name_document_acl(void){ + printf( +"\n" +"# ACCESS CONTROLS\n" +"# -----------------------------------------------------------------------------\n" +"\n" +"# TAG: acl" +"\n" +"#\tDefining an Access List\n" +"#\n" +"#\tacl aclname acltype string1 ...\n" +"#\tacl aclname acltype \"file\" ...\n" +"#\n" +"#\twhen using \"file\", the file should contain one item per line\n" +"#\n" +"#\tacltype is one of src dst srcdomain dstdomain url_pattern\n" +"#\t\turlpath_pattern time port proto method browser user\n" +"#\n" +"#\tBy default, regular expressions are CASE-SENSITIVE. To make\n" +"#\tthem case-insensitive, use the -i option.\n" +"#\n" +"#\tacl aclname src ip-address/netmask ... (clients IP address)\n" +"#\tacl aclname src addr1-addr2/netmask ... (range of addresses)\n" +"#\tacl aclname dst ip-address/netmask ... (URL host's IP address)\n" +"#\tacl aclname myip ip-address/netmask ... (local socket IP address)\n" +"#\n" +"#\tacl aclname srcdomain .foo.com ... # reverse lookup, client IP\n" +"#\tacl aclname dstdomain .foo.com ... # Destination server from URL\n" +"#\tacl aclname srcdom_regex [-i] xxx ... # regex matching client name\n" +"#\tacl aclname dstdom_regex [-i] xxx ... # regex matching server\n" +"#\t # For dstdomain and dstdom_regex a reverse lookup is tried if a IP\n" +"#\t # based URL is used. The name \"none\" is used if the reverse lookup\n" +"#\t # fails.\n" +"#\n" +"#\tacl aclname time [day-abbrevs] [h1:m1-h2:m2]\n" +"#\t day-abbrevs:\n" +"#\t\tS - Sunday\n" +"#\t\tM - Monday\n" +"#\t\tT - Tuesday\n" +"#\t\tW - Wednesday\n" +"#\t\tH - Thursday\n" +"#\t\tF - Friday\n" +"#\t\tA - Saturday\n" +"#\t h1:m1 must be less than h2:m2\n" +"#\tacl aclname url_regex [-i] ^http:// ...\t# regex matching on whole URL\n" +"#\tacl aclname urlpath_regex [-i] \\.gif$ ...\t# regex matching on URL path\n" +"#\tacl aclname port 80 70 21 ...\n" +"#\tacl aclname port 0-1024 ...\t\t# ranges allowed\n" +"#\tacl aclname myport 3128 ...\t\t# (local socket TCP port)\n" +"#\tacl aclname proto HTTP FTP ...\n" +"#\tacl aclname method GET POST ...\n" +"#\tacl aclname browser [-i] regexp\n" +"#\t # pattern match on User-Agent header\n" +"#\tacl aclname ident username ...\n" +"#\tacl aclname ident_regex [-i] pattern ...\n" +"#\t # string match on ident output.\n" +"#\t # use REQUIRED to accept any non-null ident.\n" +"#\tacl aclname src_as number ... \n" +"#\tacl aclname dst_as number ...\n" +"#\t # Except for access control, AS numbers can be used for\n" +"#\t # routing of requests to specific caches. Here's an \n" +"#\t # example for routing all requests for AS#1241 and only \n" +"#\t # those to mycache.mydomain.net:\n" +"#\t # acl asexample dst_as 1241\n" +"#\t # cache_peer_access mycache.mydomain.net allow asexample\n" +"#\t # cache_peer_access mycache_mydomain.net deny all\n" +"#\n" +"#\tacl aclname proxy_auth username ...\n" +"#\tacl aclname proxy_auth_regex [-i] pattern ...\n" +"#\t # list of valid usernames\n" +"#\t # use REQUIRED to accept any valid username.\n" +"#\t #\n" +"#\t # NOTE: when a Proxy-Authentication header is sent but it is not\n" +"#\t # needed during ACL checking the username is NOT logged\n" +"#\t # in access.log.\n" +"#\t #\n" +"#\t # NOTE: proxy_auth requires a EXTERNAL authentication program\n" +"#\t # to check username/password combinations (see\n" +"#\t # authenticate_program).\n" +"#\t #\n" +"#\t # WARNING: proxy_auth can't be used in a transparent proxy. It\n" +"#\t # collides with any authentication done by origin servers. It may\n" +"#\t # seem like it works at first, but it doesn't.\n" +"#\t #\n" +"#\t # NOTE: Authentication schemes need to be defined before proxy_auth ACL's \n" +"#\t # in the squid.conf file.\n" +"#\t # See authenticate_* commands.\n" +"#\n" +"#\tacl aclname snmp_community string ...\n" +"#\t # A community string to limit access to your SNMP Agent\n" +"#\t # Example:\n" +"#\t # \n" +"#\t #\tacl snmppublic snmp_community public\n" +"#\n" +"#\tacl aclname maxconn number\n" +"#\t # This will be matched when the client's IP address has\n" +"#\t # more than HTTP connections established.\n" +"#\n" +"#\tacl req_mime_type mime-type1 ...\n" +"#\t # regex match agains the mime type of the request generated\n" +"#\t # by the client. Can be used to detect file upload or some\n" +"#\t # types HTTP tunelling requests.\n" +"#\t # NOTE: This does NOT match the reply. You cannot use this\n" +"#\t # to match the returned file type.\n" +"#\n" +"#\tacl rep_mime_type mime-type1 ...\n" +"#\t # regex match against the mime type of the reply recieved by\n" +"#\t # squid. Can be used to detect file download or some\n" +"#\t # types HTTP tunelling requests.\n" +"#\t # NOTE: This has no effect in http_access rules. It only has\n" +"#\t # effect in rules that affect the reply data stream such as\n" +"#\t # http_reply_access.\n" +"#\n" +"#\n" +"#Examples:\n" +"#acl myexample dst_as 1241\n" +"#acl password proxy_auth REQUIRED\n" +"#acl fileupload req_mime_type -i ^multipart/form-data$\n" +"#acl javascript rep_mime_type -i ^application/x-javascript$\n" +"#\n" +"#Default:\n" +"# acl all src 0.0.0.0/0.0.0.0\n" +"#\n" +"#Recommended minimum configuration:\n" +"acl all src 0.0.0.0/0.0.0.0\n" +"acl manager proto cache_object\n" +"acl localhost src 127.0.0.1/255.255.255.255\n" +"acl SSL_ports port 443 563\n" +"acl Safe_ports port 80\t\t# http\n" +"acl Safe_ports port 21\t\t# ftp\n" +"acl Safe_ports port 443 563\t# https, snews\n" +"acl Safe_ports port 70\t\t# gopher\n" +"acl Safe_ports port 210\t\t# wais\n" +"acl Safe_ports port 1025-65535\t# unregistered ports\n" +"acl Safe_ports port 280\t\t# http-mgmt\n" +"acl Safe_ports port 488\t\t# gss-http\n" +"acl Safe_ports port 591\t\t# filemaker\n" +"acl Safe_ports port 777\t\t# multiling http\n" +"acl CONNECT method CONNECT\n" +"\n" + );} -/* - * From: dale@server.ctam.bitmcnit.bryansk.su (Dale) - * To: wessels@nlanr.net - * Subject: Another Squid patch... :) - * Date: Thu, 04 Dec 1997 19:55:01 +0300 - * ============================================================================ - * - * Working on setting up a proper firewall for a network containing some - * Win'95 computers at our Univ, I've discovered that some smart students - * avoid the restrictions easily just changing their IP addresses in Win'95 - * Contol Panel... It has been getting boring, so I took Squid-1.1.18 - * sources and added a new acl type for hard-wired access control: - * - * acl arp ... - * - * For example, - * - * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38 - * - * NOTE: Linux code by David Luyer . - * Original (BSD-specific) code no longer works. - * Solaris code by R. Gancarz - */ -#ifdef _SQUID_SOLARIS_ -#include -#else -#include -#endif -#ifdef _SQUID_LINUX_ -#include -#include -#else -#include -#endif -#include -#include -#if HAVE_NETINET_IF_ETHER_H -#include -#endif -/* - * Decode an ascii representation (asc) of an ethernet adress, and place - * it in eth[6]. - */ -static int -decode_eth(const char *asc, char *eth) + +void +aclRegisterAclDirective(void) { - int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0; - if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) { - debug(28, 0) ("decode_eth: Invalid ethernet address '%s'\n", asc); - return 0; /* This is not valid address */ - } - eth[0] = (u_char) a1; - eth[1] = (u_char) a2; - eth[2] = (u_char) a3; - eth[3] = (u_char) a4; - eth[4] = (u_char) a5; - eth[5] = (u_char) a6; - return 1; + +// parserRegisterName("acl",parserTypeByName("instance_node"),&Config.aclList2,default_if_none_acl,name_document_acl, NULL); +// parserRegisterInstanceType(" } -static acl_arp_data * -aclParseArpData(const char *t) +static void +dump_acl(StoreEntry * entry, const char *name, void const * const data) { - LOCAL_ARRAY(char, eth, 256); - acl_arp_data *q = xcalloc(1, sizeof(acl_arp_data)); - debug(28, 5) ("aclParseArpData: %s\n", t); - if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) { - debug(28, 0) ("aclParseArpData: Bad ethernet address: '%s'\n", t); - safe_free(q); - return NULL; - } - if (!decode_eth(eth, q->eth)) { - debug(28, 0) ("%s line %d: %s\n", - cfg_filename, config_lineno, config_input_line); - debug(28, 0) ("aclParseArpData: Ignoring invalid ARP acl entry: can't parse '%s'\n", eth); - safe_free(q); - return NULL; + acl * ae=*(acl * *)data; +// wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 0) ("dump_acl: %s %s\n", name, ae->name); + v = NULL; // w = aclDumpGeneric(ae); + while (v != NULL) { + debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + ae->aclname->namestr, + v->key); + v = v->next; + } +// wordlistDestroy(&w); + ae = ae->next; } - return q; } - -/*******************/ -/* aclParseArpList */ -/*******************/ static void -aclParseArpList(void *curlist) +free_acl(parserNameNode *parserName, void *data) { - char *t = NULL; - splayNode **Top = curlist; - acl_arp_data *q = NULL; - while ((t = strtokFile())) { - if ((q = aclParseArpData(t)) == NULL) - continue; - *Top = splay_insert(q, *Top, aclArpCompare); - } + int used; + acl ** ae=(acl **)data; + used=!check_null_acl(*ae); + aclDestroyAcls(ae); +// if (used) +// cbdataUnlock(parserName); } -/***************/ -/* aclMatchArp */ -/***************/ -static int -aclMatchArp(void *dataptr, struct in_addr c) +void +aclParserRegister(void) { -#if defined(_SQUID_LINUX_) - struct arpreq arpReq; - struct sockaddr_in ipAddr; - unsigned char ifbuffer[sizeof(struct ifreq) * 64]; - struct ifconf ifc; - struct ifreq *ifr; - int offset; - splayNode **Top = dataptr; - /* - * The linux kernel 2.2 maintains per interface ARP caches and - * thus requires an interface name when doing ARP queries. - * - * The older 2.0 kernels appear to use a unified ARP cache, - * and require an empty interface name - * - * To support both, we attempt the lookup with a blank interface - * name first. If that does not succeed, the try each interface - * in turn - */ - /* - * Set up structures for ARP lookup with blank interface name - */ - ipAddr.sin_family = AF_INET; - ipAddr.sin_port = 0; - ipAddr.sin_addr = c; - memset(&arpReq, '\0', sizeof(arpReq)); - xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); - /* Query ARP table */ - if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) { - /* Skip non-ethernet interfaces */ - if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) { - return 0; - } - debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n", - arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff, - arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff, - arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff); - /* Do lookup */ - *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare); - debug(28, 3) ("aclMatchArp: '%s' %s\n", - inet_ntoa(c), splayLastResult ? "NOT found" : "found"); - return (0 == splayLastResult); - } - /* lookup list of interface names */ - ifc.ifc_len = sizeof(ifbuffer); - ifc.ifc_buf = ifbuffer; - if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) { - debug(28, 1) ("Attempt to retrieve interface list failed: %s\n", - xstrerror()); - return 0; - } - if (ifc.ifc_len > sizeof(ifbuffer)) { - debug(28, 1) ("Interface list too long - %d\n", ifc.ifc_len); - return 0; - } - /* Attempt ARP lookup on each interface */ - offset = 0; - while (offset < ifc.ifc_len) { - ifr = (struct ifreq *) (ifbuffer + offset); - offset += sizeof(*ifr); - /* Skip loopback and aliased interfaces */ - if (0 == strncmp(ifr->ifr_name, "lo", 2)) - continue; - if (NULL != strchr(ifr->ifr_name, ':')) - continue; - debug(28, 4) ("Looking up ARP address for %s on %s\n", inet_ntoa(c), - ifr->ifr_name); - /* Set up structures for ARP lookup */ - ipAddr.sin_family = AF_INET; - ipAddr.sin_port = 0; - ipAddr.sin_addr = c; - memset(&arpReq, '\0', sizeof(arpReq)); - xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); - strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1); - arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0'; - /* Query ARP table */ - if (-1 == ioctl(HttpSockets[0], SIOCGARP, &arpReq)) { - /* - * Query failed. Do not log failed lookups or "device - * not supported" - */ - if (ENXIO == errno) - (void) 0; - else if (ENODEV == errno) - (void) 0; - else - debug(28, 1) ("ARP query failed: %s: %s\n", - ifr->ifr_name, xstrerror()); - continue; - } - /* Skip non-ethernet interfaces */ - if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) - continue; - debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x on %s\n", - arpReq.arp_ha.sa_data[0] & 0xff, - arpReq.arp_ha.sa_data[1] & 0xff, - arpReq.arp_ha.sa_data[2] & 0xff, - arpReq.arp_ha.sa_data[3] & 0xff, - arpReq.arp_ha.sa_data[4] & 0xff, - arpReq.arp_ha.sa_data[5] & 0xff, ifr->ifr_name); - /* Do lookup */ - *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare); - /* Return if match, otherwise continue to other interfaces */ - if (0 == splayLastResult) { - debug(28, 3) ("aclMatchArp: %s found on %s\n", - inet_ntoa(c), ifr->ifr_name); - return 1; - } - /* - * Should we stop looking here? Can the same IP address - * exist on multiple interfaces? - */ - } -#elif defined(_SQUID_SOLARIS_) - struct arpreq arpReq; - struct sockaddr_in ipAddr; - unsigned char ifbuffer[sizeof(struct ifreq) * 64]; - struct ifconf ifc; - struct ifreq *ifr; - int offset; - splayNode **Top = dataptr; - /* - * Set up structures for ARP lookup with blank interface name - */ - ipAddr.sin_family = AF_INET; - ipAddr.sin_port = 0; - ipAddr.sin_addr = c; - memset(&arpReq, '\0', sizeof(arpReq)); - xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); - /* Query ARP table */ - if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) { - /* - * Solaris (at least 2.6/x86) does not use arp_ha.sa_family - - * it returns 00:00:00:00:00:00 for non-ethernet media - */ - if (arpReq.arp_ha.sa_data[0] == 0 && - arpReq.arp_ha.sa_data[1] == 0 && - arpReq.arp_ha.sa_data[2] == 0 && - arpReq.arp_ha.sa_data[3] == 0 && - arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0) - return 0; - debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n", - arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff, - arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff, - arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff); - /* Do lookup */ - *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare); - debug(28, 3) ("aclMatchArp: '%s' %s\n", - inet_ntoa(c), splayLastResult ? "NOT found" : "found"); - return (0 == splayLastResult); - } -#else - WRITE ME; + // This should be in the acl module init code. + if (!acl_pool) + acl_pool = memPoolCreate("acl", sizeof(acl)); + if (!acl_deny_info_list_pool) + acl_deny_info_list_pool = memPoolCreate("acl_deny_info_list", + sizeof(acl_deny_info_list)); + if (!acl_ip_data_pool) + acl_ip_data_pool = memPoolCreate("acl_ip_data", sizeof(acl_ip_data)); + if (!acl_name_list_pool) + acl_name_list_pool = memPoolCreate("acl_name_list", sizeof(acl_name_list)); + if (!acl_time_data_pool) + acl_time_data_pool = memPoolCreate("acl_time_data", sizeof(acl_time_data)); + if (!acl_proxy_auth_match_pool) + acl_proxy_auth_match_pool = memPoolCreate("acl_proxy_auth_match_cache", + sizeof(acl_proxy_auth_match_cache)); + if (!acl_user_data_pool) + acl_user_data_pool = memPoolCreate("acl_user_data", sizeof(acl_user_data)); + + /* register the ACL types */ + parserRegisterType("acl",aclParseAclLine,free_acl,dump_acl); + + parserRegisterType("denyinfo",parse_denyinfo,free_denyinfo,dump_denyinfo); + + parserRegisterType("iplist", aclParseIpList, aclDestroyIpList, dump_IpList ); + parserRegisterType("domainlist", aclParseDomainList, aclDestroyDomainList, dump_DomainList); + parserRegisterType("regexlist", aclParseRegexList, aclDestroyRegexList, dump_RegexList); + parserRegisterType("timespec", aclParseTimeSpec, aclDestroyTimeSpecList, dump_TimeSpec); + parserRegisterType("intlist", aclParseIntRange, free_intlist, dump_intlistList); + parserRegisterType("intrange", aclParseIntRange, aclDestroyIntRange, dump_IntRangeList); + parserRegisterType("userlist", aclParseUserList, aclDestroyUserList, dump_UserList); + parserRegisterType("aclwordlist", parse_wordlistFromFile, free_wordlist, dump_wordlist); + parserRegisterType("protolist", aclParseProtoList, free_intlist, dump_ProtoList); + parserRegisterType("methodlist", aclParseMethodList, free_intlist, dump_MethodList); +#if 0 + parserRegisterType("arplist", aclParseArpList, aclDestroyArpList, dump_ArpList); +#endif + + parserRegisterName(NULL, "deny_info",parserTypeByName("denyinfo"), + &Config.denyInfoList,NULL,name_document_deny_info, NULL); + + /* register the acl instance names */ + aclRegisterAclName("src", parserTypeByName("iplist"), aclMatchSrc); + aclRegisterAclName("dst", parserTypeByName("iplist"), aclMatchDst); + aclRegisterAclName("myip", parserTypeByName("iplist"), aclMatchMyip); + + aclRegisterAclName("srcdomain", parserTypeByName("domainlist"), aclMatchSrcDomain); + aclRegisterAclName("dstdomain", parserTypeByName("domainlist"), aclMatchDstDomain); + aclRegisterAclName("domain", parserTypeByName("domainlist"), aclMatchDstDomain); + + aclRegisterAclName("dstdom_regex", parserTypeByName("regexlist"), aclMatchSrcDomain); + aclRegisterAclName("srcdom_regex", parserTypeByName("regexlist"), aclMatchSrcDomain); + aclRegisterAclName("pattern", parserTypeByName("regexlist"), aclMatchUrlPathRegex); + aclRegisterAclName("urlpath_regex", parserTypeByName("regexlist"), aclMatchUrlPathRegex); + aclRegisterAclName("url_regex", parserTypeByName("regexlist"), aclMatchUrlRegex); + aclRegisterAclName("browser", parserTypeByName("regexlist"), aclMatchBrowser); + aclRegisterAclName("req_mime_type", parserTypeByName("regexlist"), aclMatchRepMimeType); + aclRegisterAclName("rep_mime_type", parserTypeByName("regexlist"), aclMatchReqMimeType); +#if USE_IDENT + aclRegisterAclName("ident", parserTypeByName("userlist"), aclMatchIdent); + aclRegisterAclName("ident_regex", parserTypeByName("regexlist"), aclMatchIdentRegex); #endif - /* - * Address was not found on any interface - */ - debug(28, 3) ("aclMatchArp: %s NOT found\n", inet_ntoa(c)); - return 0; -} + proxy_auth_name = aclRegisterAclName("proxy_auth", parserTypeByName("userlist"), aclMatchProxyAuthModule); + proxy_auth_regex_name = aclRegisterAclName("proxy_auth_regex", parserTypeByName("regexlist"), aclMatchProxyAuthModule); -static int -aclArpCompare(const void *a, const void *b) -{ -#if defined(_SQUID_LINUX_) - const unsigned short *d1 = a; - const unsigned short *d2 = b; - if (d1[0] != d2[0]) - return (d1[0] > d2[0]) ? 1 : -1; - if (d1[1] != d2[1]) - return (d1[1] > d2[1]) ? 1 : -1; - if (d1[2] != d2[2]) - return (d1[2] > d2[2]) ? 1 : -1; -#elif defined(_SQUID_SOLARIS_) - const unsigned char *d1 = a; - const unsigned char *d2 = b; - if (d1[0] != d2[0]) - return (d1[0] > d2[0]) ? 1 : -1; - if (d1[1] != d2[1]) - return (d1[1] > d2[1]) ? 1 : -1; - if (d1[2] != d2[2]) - return (d1[2] > d2[2]) ? 1 : -1; - if (d1[3] != d2[3]) - return (d1[3] > d2[3]) ? 1 : -1; - if (d1[4] != d2[4]) - return (d1[4] > d2[4]) ? 1 : -1; - if (d1[5] != d2[5]) - return (d1[5] > d2[5]) ? 1 : -1; -#else - WRITE ME; + aclRegisterAclName("time", parserTypeByName("timespec"), aclMatchTime); + + aclRegisterAclName("maxconn", parserTypeByName("int"), aclMatchMaxConn); + + aclRegisterAclName("port", parserTypeByName("intrange"), aclMatchUrlPort); + aclRegisterAclName("myport", parserTypeByName("intrange"), aclMatchMyPort); +#if SQUID_SNMP + aclRegisterAclName("snmp_community", parserTypeByName("aclwordlist"), aclMatchSNMPCommunity); #endif - return 0; -} -#if UNUSED_CODE -/********************************************************************** -* This is from the pre-splay-tree code for BSD -* I suspect the Linux approach will work on most O/S and be much -* better - -*********************************************************************** -static int -checkARP(u_long ip, char *eth) -{ - int mib[6] = - {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO}; - size_t needed; - char *buf, *next, *lim; - struct rt_msghdr *rtm; - struct sockaddr_inarp *sin; - struct sockaddr_dl *sdl; - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { - debug(28, 0) ("Can't estimate ARP table size!\n"); - return 0; - } - if ((buf = xmalloc(needed)) == NULL) { - debug(28, 0) ("Can't allocate temporary ARP table!\n"); - return 0; - } - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - debug(28, 0) ("Can't retrieve ARP table!\n"); - xfree(buf); - return 0; - } - lim = buf + needed; - for (next = buf; next < lim; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *) next; - sin = (struct sockaddr_inarp *) (rtm + 1); - sdl = (struct sockaddr_dl *) (sin + 1); - if (sin->sin_addr.s_addr == ip) { - if (sdl->sdl_alen) - if (!memcmp(LLADDR(sdl), eth, 6)) { - xfree(buf); - return 1; - } - break; - } - } - xfree(buf); - return 0; -} -**********************************************************************/ + aclRegisterAclName("proto", parserTypeByName("protolist"), aclMatchProto); + aclRegisterAclName("method", parserTypeByName("methodlist"), aclMatchMethod); + + aclRegisterAclName("src_as", parserTypeByName("intlist"), aclMatchSrcAsn); + aclRegisterAclName("dst_as", parserTypeByName("intlist"), aclMatchDstAsn); + +#if 0 +#if USE_ARP_ACL + aclRegisterAclName("arp", parserTypeByName("arplist"), aclMatchSrcArp); +#endif #endif -static void -aclDumpArpListWalkee(void *node, void *state) -{ - acl_arp_data *arp = node; - wordlist **W = state; - static char buf[24]; - while (*W != NULL) - W = &(*W)->next; - snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", - arp->eth[0], arp->eth[1], arp->eth[2], arp->eth[3], - arp->eth[4], arp->eth[5]); - wordlistAdd(state, buf); -} +#if SRC_RTT_NOT_YET_FINISHED + aclRegisterAclName("src_rtt", parserTypeByName("intlist"),aclMatchSrcRTT); +#endif -static wordlist * -aclDumpArpList(void *data) -{ - wordlist *w = NULL; - splay_walk(data, aclDumpArpListWalkee, &w); - return w; -} -/* ==== END ARP ACL SUPPORT =============================================== */ -#endif /* USE_ARP_ACL */ + if (aclinstances) + debug(3,0)("reconfiguring is broken just now!!! \n\n"); + /* this creates a hierarchical branch */ + aclinstances = parserRegisterInstanceName("acl", parserTypeByName("acl"), NULL, NULL); + /* this registers the hierarchical branch as "acl" */ + parserRegisterName(NULL, "acl", parserTypeByName("instance_node"), aclinstances, default_if_none_acl, name_document_acl, NULL); +} Index: squid/src/acl.h diff -u /dev/null squid/src/acl.h:1.1.2.6 --- /dev/null Tue Sep 28 18:35:57 2004 +++ squid/src/acl.h Sat May 12 08:22:30 2001 @@ -0,0 +1,109 @@ + +/* + * $Id$ + * + * + * 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. + * + */ + +#ifndef _ACL_H_ +#define _ACL_H_ + +typedef enum { + /* callback in progress */ + ACL_MATCH_NEED_LOOKUP = -1, + /* as it says */ + ACL_MATCH_NOTFOUND = 0, + /* likewise */ + ACL_MATCH_FOUND = 1, + /* cannot check at all, but don't treat as a match or a non-match */ + ACL_MATCH_INSUFFICIENT_INFORMATION = 2 +} acl_match_rv; + +typedef struct _aclName aclName; +/* pointer to a pointer to the acl data, a pointer to the checklist, and a flag block */ +typedef int ACLMATCH(acl * , aclCheck_t *, unsigned int); + +struct _acl { + char name[ACL_NAME_SZ]; + aclName *aclname; + void *data; + char *cfgline; + acl *next; +}; + +struct _acl_user_data { + splayNode *names; + struct { + unsigned int case_insensitive:1; + unsigned int required:1; + } flags; +}; + + +struct _acl_ip_data { + struct in_addr addr1; /* if addr2 non-zero then its a range */ + struct in_addr addr2; + struct in_addr mask; + acl_ip_data *next; /* used for parsing, not for storing */ +}; + +struct _acl_time_data { + int weekbits; + int start; + int stop; + acl_time_data *next; +}; + +struct _aclName { + dlink_node node; + char * namestr; + parserTypeNode *type; + ACLMATCH *match; +}; + +struct _acl_name_list { + char name[ACL_NAME_SZ]; + acl_name_list *next; +}; + +struct _acl_proxy_auth_match_cache { + dlink_node link; + int matchrv; + void *acl_data; +}; + +extern aclName *aclRegisterAclName(const char *, parserTypeNode *, ACLMATCH *); +extern aclName *aclNameByName(const char *); + +/* global variables for acl code */ +extern acl * AclMatchedAcl; + +#define ACL_FASTCHECK 0x0001 + +#endif /* ACL_H */ Index: squid/src/asn.c diff -u squid/src/asn.c:1.10 squid/src/asn.c:1.9.4.4 --- squid/src/asn.c:1.10 Sat Mar 3 02:44:31 2001 +++ squid/src/asn.c Wed Apr 25 17:09:08 2001 @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "acl.h" #define WHOIS_PORT 43 @@ -88,7 +89,7 @@ static STCB asHandleReply; static int destroyRadixNode(struct radix_node *rn, void *w); static int printRadixNode(struct radix_node *rn, void *w); -static void asnAclInitialize(acl * acls); +static void asnAclInitialize(); static void asStateFree(void *data); static void destroyRadixNodeInfo(as_info *); static OBJH asnStats; @@ -133,13 +134,32 @@ } static void -asnAclInitialize(acl * acls) +asnAclInitialize() { acl *a; intlist *i; + parserNameNode *aclparserName = parserNameByName("acl"); + parserNameNode *parserName; + aclName *srcName, *dstName; + dlink_node *node; debug(53, 3) ("asnAclInitialize\n"); - for (a = acls; a; a = a->next) { - if (a->type != ACL_DST_ASN && a->type != ACL_SRC_ASN) + + // FIXME: heal the abstraction + if (!aclparserName || aclparserName->children.head==NULL) + return; + + srcName = aclNameByName("src_as"); + dstName = aclNameByName("dst_as"); + /* we're not a module yet: these _must_be registered */ + assert(srcName); + assert(dstName); + + node=aclparserName->children.head; + while (node) { + parserName=node->data; + node=node->next; + a=parserName->location; + if (a->aclname != srcName && a->aclname != dstName) continue; for (i = a->data; i; i = i->next) asnCacheStart(i->i); @@ -159,7 +179,7 @@ if (0 == inited++) rn_init(); rn_inithead((void **) &AS_tree_head, 8); - asnAclInitialize(Config.aclList); + asnAclInitialize(); cachemgrRegister("asndb", "AS Number Database", asnStats, 0, 1); } Index: squid/src/auth_modules.sh diff -u squid/src/auth_modules.sh:1.2 squid/src/auth_modules.sh:removed --- squid/src/auth_modules.sh:1.2 Sun Jan 7 16:02:37 2001 +++ squid/src/auth_modules.sh Tue Sep 28 18:35:57 2004 @@ -1,15 +0,0 @@ -#!/bin/sh -echo "/* automatically generated by $0 $*" -echo " * do not edit" -echo " */" -echo "#include \"squid.h\"" -echo "" -for module in "$@"; do - echo "extern AUTHSSETUP authSchemeSetup_${module};" -done -echo "void authSchemeSetup(void)" -echo "{" -for module in "$@"; do - echo " authSchemeAdd(\"$module\", authSchemeSetup_${module});" -done -echo "}" Index: squid/src/authenticate.c diff -u squid/src/authenticate.c:1.13 squid/src/authenticate.c:1.12.4.3 --- squid/src/authenticate.c:1.13 Fri Mar 9 16:58:00 2001 +++ squid/src/authenticate.c Sat Mar 31 01:52:19 2001 @@ -59,8 +59,8 @@ { authScheme *scheme; int i; - for (i = 0; i < Config.authConfig.n_configured; i++) { - scheme = Config.authConfig.schemes + i; + for (i = 0; i < Config.authSchemes.n_configured; i++) { + scheme = Config.authSchemes.schemes + i; if ((strncasecmp(proxy_auth, scheme->typestr, strlen(scheme->typestr)) == 0) && (authscheme_list[scheme->Id].Active())) return 1; @@ -345,20 +345,14 @@ } void -authenticateSchemeInit(void) -{ - authSchemeSetup(); -} - -void -authenticateInit(authConfig * config) +authenticateInit(authSchemes * config) { int i; authScheme *scheme; for (i = 0; i < config->n_configured; i++) { scheme = config->schemes + i; if (authscheme_list[scheme->Id].init && authscheme_list[scheme->Id].configured()) { - authscheme_list[scheme->Id].init(scheme); + authscheme_list[scheme->Id].init(); } } if (!proxy_auth_username_cache) @@ -416,8 +410,8 @@ int i; authScheme *scheme; /* call each configured & running authscheme */ - for (i = 0; i < Config.authConfig.n_configured; i++) { - scheme = Config.authConfig.schemes + i; + for (i = 0; i < Config.authSchemes.n_configured; i++) { + scheme = Config.authSchemes.schemes + i; if (authscheme_list[scheme->Id].Active()) authscheme_list[scheme->Id].authFixHeader(auth_user_request, rep, type, request); @@ -635,7 +629,7 @@ * called to add another auth scheme module */ void -authSchemeAdd(char *type, AUTHSSETUP * setup) +authSchemeAdd(const char *type, AUTHSSETUP * setup) { int i; debug(29, 4) ("authSchemeAdd: adding %s", type); Index: squid/src/cache_cf.c diff -u squid/src/cache_cf.c:1.24 squid/src/cache_cf.c:1.18.4.32 --- squid/src/cache_cf.c:1.24 Tue May 8 08:27:00 2001 +++ squid/src/cache_cf.c Sat May 12 06:06:03 2001 @@ -35,6 +35,9 @@ #include "squid.h" +// FIXME: