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: we should be a stub file - not needing acl code. +#include "acl.h" + #if SQUID_SNMP #include "snmp.h" #endif @@ -58,34 +61,75 @@ static struct cache_dir_option common_cachedir_options[]; static void update_maxobjsize(void); -static void configDoConfigure(void); -static void parse_refreshpattern(refresh_t **); +static int configDoConfigure(void); +static PARSER_PARSE parse_refreshpattern; static int parseTimeUnits(const char *unit); static void parseTimeLine(time_t * tptr, const char *units); -static void parse_ushort(u_short * var); -static void parse_string(char **); -void parse_wordlist(wordlist **); -static void default_all(void); +static PARSER_PARSE parse_ushort; +static PARSER_PARSE parse_string; +PARSER_PARSE parse_wordlist; static void defaults_if_none(void); +void default_line(const char *); static int parse_line(char *); static void parseBytesLine(size_t * bptr, const char *units); static size_t parseBytesUnits(const char *unit); static void free_all(void); +static void parserRegisterAllTypes(void); +static void parserRegisterCFTypes(void); +static void parserDeregisterAllTypes(void); +static void parserRegisterAllNames(void); +static void parserRegisterCFNames(void); +static void parserDeregisterAllNames(void); void requirePathnameExists(const char *name, const char *path); static OBJH dump_config; -static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]); -static void parse_http_header_access(header_mangler header[]); -static void free_http_header_access(header_mangler header[]); -static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]); -static void parse_http_header_replace(header_mangler * header); -static void free_http_header_replace(header_mangler * header); -static void parse_denyinfo(acl_deny_info_list ** var); -static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var); -static void free_denyinfo(acl_deny_info_list ** var); -static void parse_sockaddr_in_list(sockaddr_in_list **); -static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *); -static void free_sockaddr_in_list(sockaddr_in_list **); +static PARSER_DUMP dump_http_header_access; +static PARSER_PARSE parse_http_header_access; +static PARSER_FREE free_http_header_access; +static PARSER_DUMP dump_http_header_replace; +static PARSER_PARSE parse_http_header_replace; +static PARSER_FREE free_http_header_replace; +static PARSER_PARSE parse_sockaddr_in_list; +static PARSER_DUMP dump_sockaddr_in_list; +static PARSER_FREE free_sockaddr_in_list; static int check_null_sockaddr_in_list(const sockaddr_in_list *); + +/* create instances */ +static PARSER_PARSE parse_instance_node; +static PARSER_FREE free_instance_node; +static PARSER_DUMP dump_instance_node; +/* refer to instances */ +static PARSER_PARSE parse_instance_reference; +static PARSER_FREE free_instance_reference; +static PARSER_DUMP dump_instance_reference; + +/* self documentating support */ +typedef struct _docoptionNode docoptionNode; +typedef struct _docoptions docoptions; +struct _docoptionNode { + docoptionNode *next; + char *name; +}; +struct _docoptions { + docoptionNode *head; + struct { + unsigned int internalonly:1; + unsigned int all:1; + } flags; +}; + +static docoptions *DoDocumentOptions = NULL; + +/* dynamic type and name support */ +parserTypeNode *parserTypeByName(const char *); +void parserRegisterType(const char *, PARSER_PARSE *, PARSER_FREE *, PARSER_DUMP *); +void parserDeregisterType(parserTypeNode *); +parserNameNode *parserNameByName(const char *name); +void parserRegisterName(parserNameNode *, const char *, parserTypeNode *, void *, PARSER_DEFAULT_NONE *, PARSER_NAME_DOCUMENT *, PARSER_POST_PARSE *); +void parserDeregisterName(parserNameNode *); +static int parserNameDoPostParse(void); +static int parse_line(char *buff); +static void free_all(void); + #if USE_SSL static void parse_https_port_list(https_port_list **); static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *); @@ -102,6 +146,8 @@ cfg_filename, config_lineno, config_input_line); } +/* Generic wordlist routines - should be in a library! */ + void wordlistDestroy(wordlist ** list) { @@ -166,9 +212,13 @@ return D; } +/****************** END OF WORDLIST ROUTINES ****************/ + void -intlistDestroy(intlist ** list) +free_intlist(parserNameNode *parserName, void *data) { + intlist ** list=data; + intlist *w = NULL; intlist *n = NULL; for (w = *list; w; w = n) { @@ -188,12 +238,6 @@ return 0; } - -/* - * Use this #define in all the parse*() functions. Assumes char *token is - * defined - */ - int GetInteger(void) { @@ -226,21 +270,22 @@ char *token = NULL; char *tmp_line; int err_count = 0; - free_all(); - default_all(); + int local_lineno; + const char *local_filename; if ((fp = fopen(file_name, "r")) == NULL) fatalf("Unable to open configuration file: %s: %s", file_name, xstrerror()); #if defined(_SQUID_CYGWIN_) setmode(fileno(fp), O_TEXT); #endif - cfg_filename = file_name; - if ((token = strrchr(cfg_filename, '/'))) - cfg_filename = token + 1; + local_filename = file_name; + if ((token = strrchr(local_filename, '/'))) + local_filename = token + 1; memset(config_input_line, '\0', BUFSIZ); - config_lineno = 0; + local_lineno = 0; while (fgets(config_input_line, BUFSIZ, fp)) { - config_lineno++; + config_lineno=(local_lineno++); + cfg_filename = local_filename; if ((token = strchr(config_input_line, '\n'))) *token = '\0'; if (config_input_line[0] == '#') @@ -258,8 +303,21 @@ safe_free(tmp_line); } fclose(fp); + return err_count; +} + +int +parserReconfigure(const char *file_name) +{ + int err_count = 0; + free_all(); + parserDeregisterAllNames(); + parserDeregisterAllTypes(); + parserRegisterAllTypes(); + parserRegisterAllNames(); + err_count=parseConfigFile(file_name); defaults_if_none(); - configDoConfigure(); + err_count += configDoConfigure(); cachemgrRegister("config", "Current Squid Configuration", dump_config, @@ -267,10 +325,11 @@ return err_count; } -static void +static int configDoConfigure(void) { LOCAL_ARRAY(char, buf, BUFSIZ); + int rv=0; memset(&Config2, '\0', sizeof(SquidConfig2)); /* init memory as early as possible */ memConfigure(); @@ -415,6 +474,8 @@ Config2.effectiveGroupID = grp->gr_gid; } urlExtMethodConfigure(); + rv += parserNameDoPostParse(); + return rv; } /* Parse a time specification from the config file. Store the @@ -509,43 +570,16 @@ * Max *****************************************************************************/ -static void -dump_acl(StoreEntry * entry, const char *name, acl * ae) -{ - wordlist *w; - wordlist *v; - while (ae != NULL) { - debug(3, 3) ("dump_acl: %s %s\n", name, ae->name); - v = 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, - aclTypeToStr(ae->type), - v->key); - v = v->next; - } - wordlistDestroy(&w); - ae = ae->next; - } -} - -static void -parse_acl(acl ** ae) -{ - aclParseAclLine(ae); -} - -static void -free_acl(acl ** ae) +static int +check_null_acl_access(acl_access * a) { - aclDestroyAcls(ae); + return a == NULL; } static void -dump_acl_access(StoreEntry * entry, const char *name, acl_access * head) +dump_acl_access(StoreEntry * entry, const char *name, void const * const data) { + acl_access *head=*(acl_access **)data; acl_list *l; while (head != NULL) { storeAppendPrintf(entry, "%s %s", @@ -562,26 +596,37 @@ } static void -parse_acl_access(acl_access ** head) +parse_acl_access(parserNameNode *parserName, void * data) { + acl_access ** head=(acl_access **)data; + if (check_null_acl_access(*head)) + cbdataLock(parserName); aclParseAccessLine(head); } static void -free_acl_access(acl_access ** head) +free_acl_access(parserNameNode *parserName, void * data) { + int used; + acl_access ** head=(acl_access **)data; + used = !check_null_acl_access(*head); aclDestroyAccessList(head); + if (used) + cbdataUnlock(parserName); } static void -dump_address(StoreEntry * entry, const char *name, struct in_addr addr) +dump_address(StoreEntry * entry, const char *name, void const * const data) { + struct in_addr addr=*(struct in_addr *)data; storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr)); } static void -parse_address(struct in_addr *addr) +parse_address(parserNameNode *parserName, void * data) { + /* no memory allocated - no need to lock the NameNode */ + struct in_addr *addr=data; const struct hostent *hp; char *token = strtok(NULL, w_space); @@ -596,26 +641,29 @@ } static void -free_address(struct in_addr *addr) +free_address(parserNameNode *parserName, void * data) { + struct in_addr *addr=data; memset(addr, '\0', sizeof(struct in_addr)); } #if DELAY_POOLS +/* + * TODO: FIXME: Delay pools spits out an incorrect config on dump with the new dump code. + * The delay pools parseing code is one big chunk, not broken out per type. + * The parserName should get locked and freed here, but to hard for now + */ + + /* do nothing - free_delay_pool_count is the magic free function. * this is why delay_pool_count isn't just marked TYPE: ushort */ -#define free_delay_pool_class(X) -#define free_delay_pool_access(X) -#define free_delay_pool_rates(X) -#define dump_delay_pool_class(X, Y, Z) -#define dump_delay_pool_access(X, Y, Z) -#define dump_delay_pool_rates(X, Y, Z) static void -free_delay_pool_count(delayConfig * cfg) +free_delay_pool_count(parserNameNode *parserName, void * data) { + delayConfig * cfg=data; int i; if (!cfg->pools) @@ -634,9 +682,14 @@ memset(cfg, 0, sizeof(*cfg)); } +#define free_delay_pool_class free_delay_pool_count +#define free_delay_pool_access free_delay_pool_count +#define free_delay_pool_rates free_delay_pool_count + static void -dump_delay_pool_count(StoreEntry * entry, const char *name, delayConfig cfg) +dump_delay_pool_count(StoreEntry * entry, const char *name, void const * const data) { + delayConfig cfg=*(delayConfig *)data; int i; LOCAL_ARRAY(char, nom, 32); @@ -666,14 +719,19 @@ } } +#define dump_delay_pool_class dump_delay_pool_count +#define dump_delay_pool_access dump_delay_pool_count +#define dump_delay_pool_rates dump_delay_pool_count + static void -parse_delay_pool_count(delayConfig * cfg) +parse_delay_pool_count(parserNameNode *parserName, void * data) { + delayConfig * cfg=data; if (cfg->pools) { debug(3, 0) ("parse_delay_pool_count: multiple delay_pools lines, aborting all previous delay_pools config\n"); - free_delay_pool_count(cfg); + free_delay_pool_count(parserName, cfg); } - parse_ushort(&cfg->pools); + parse_ushort(parserName, &cfg->pools); delayInitDelayData(cfg->pools); cfg->class = xcalloc(cfg->pools, sizeof(u_char)); cfg->rates = xcalloc(cfg->pools, sizeof(delaySpecSet *)); @@ -681,16 +739,17 @@ } static void -parse_delay_pool_class(delayConfig * cfg) +parse_delay_pool_class(parserNameNode *parserName, void * data) { + delayConfig * cfg=data; ushort pool, class; - parse_ushort(&pool); + parse_ushort(parserName, &pool); if (pool < 1 || pool > cfg->pools) { debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools); return; } - parse_ushort(&class); + parse_ushort(parserName, &class); if (class < 1 || class > 3) { debug(3, 0) ("parse_delay_pool_class: Ignoring pool %d class %d not in 1 .. 3\n", pool, class); return; @@ -711,14 +770,15 @@ } static void -parse_delay_pool_rates(delayConfig * cfg) +parse_delay_pool_rates(parserNameNode *parserName, void * data) { + delayConfig * cfg=data; ushort pool, class; int i; delaySpec *ptr; char *token; - parse_ushort(&pool); + parse_ushort(parserName, &pool); if (pool < 1 || pool > cfg->pools) { debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools); return; @@ -756,35 +816,38 @@ } static void -parse_delay_pool_access(delayConfig * cfg) +parse_delay_pool_access(parserNameNode *parserName, void * data) { + delayConfig * cfg=data; ushort pool; - parse_ushort(&pool); + parse_ushort(parserName, &pool); if (pool < 1 || pool > cfg->pools) { debug(3, 0) ("parse_delay_pool_rates: Ignoring pool %d not in 1 .. %d\n", pool, cfg->pools); return; } - aclParseAccessLine(&cfg->access[pool - 1]); + parse_acl_access(parserName, &cfg->access[pool - 1]); } #endif static void -dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]) +dump_http_header_access(StoreEntry * entry, const char *name, void const * const data) { + header_mangler *header=(header_mangler *)data; int i; for (i = 0; i < HDR_ENUM_END; i++) { if (header[i].access_list != NULL) { storeAppendPrintf(entry, "%s ", name); dump_acl_access(entry, httpHeaderNameById(i), - header[i].access_list); + &header[i].access_list); } } } static void -parse_http_header_access(header_mangler header[]) +parse_http_header_access(parserNameNode *parserName, void * data) { + header_mangler *header=data; int id, i; char *t = NULL; if ((t = strtok(NULL, w_space)) == NULL) { @@ -806,7 +869,7 @@ return; } if (id != HDR_ENUM_END) { - parse_acl_access(&header[id].access_list); + parse_acl_access(parserName, &header[id].access_list); } else { char *next_string = t + strlen(t) - 1; *next_string = 'A'; @@ -814,25 +877,26 @@ for (i = 0; i < HDR_ENUM_END; i++) { char *new_string = xstrdup(next_string); strtok(new_string, w_space); - parse_acl_access(&header[i].access_list); + parse_acl_access(parserName, &header[i].access_list); safe_free(new_string); } } } static void -free_http_header_access(header_mangler header[]) +free_http_header_access(parserNameNode *parserName, void * data) { + header_mangler *header=data; int i; for (i = 0; i < HDR_ENUM_END; i++) { - free_acl_access(&header[i].access_list); + free_acl_access(parserName, &header[i].access_list); } } static void -dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler - header[]) +dump_http_header_replace(StoreEntry * entry, const char *name, void const * const data) { + header_mangler *header=(header_mangler *)data; int i; for (i = 0; i < HDR_ENUM_END; i++) { if (NULL == header[i].replacement) @@ -843,8 +907,9 @@ } static void -parse_http_header_replace(header_mangler header[]) +parse_http_header_replace(parserNameNode *parserName, void * data) { + header_mangler *header=data; int id, i; char *t = NULL; if ((t = strtok(NULL, w_space)) == NULL) { @@ -880,8 +945,9 @@ } static void -free_http_header_replace(header_mangler header[]) +free_http_header_replace(parserNameNode *parserName, void * data) { + header_mangler *header=data; int i; for (i = 0; i < HDR_ENUM_END; i++) { if (header[i].replacement != NULL) @@ -900,8 +966,9 @@ } static void -dump_cachedir(StoreEntry * entry, const char *name, cacheSwap swap) +dump_cachedir(StoreEntry * entry, const char *name, void const * const data) { + cacheSwap swap=*(cacheSwap *)data; SwapDir *s; int i; for (i = 0; i < swap.n_configured; i++) { @@ -926,68 +993,66 @@ return s == NULL; } +/* + * TODO: this is a bit clunky... + * + */ + static void -allocate_new_authScheme(authConfig * cfg) +allocate_new_authScheme(authSchemes * cfg) { if (cfg->schemes == NULL) { - cfg->n_allocated = 4; - cfg->schemes = xcalloc(cfg->n_allocated, sizeof(authScheme)); + cfg->n_allocated = 4; + cfg->schemes = xcalloc(cfg->n_allocated, sizeof(authScheme)); } if (cfg->n_allocated == cfg->n_configured) { - authScheme *tmp; - cfg->n_allocated <<= 1; - tmp = xcalloc(cfg->n_allocated, sizeof(authScheme)); - xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme)); - xfree(cfg->schemes); - cfg->schemes = tmp; + authScheme *tmp; + cfg->n_allocated <<= 1; + tmp = xcalloc(cfg->n_allocated, sizeof(authScheme)); + xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme)); + xfree(cfg->schemes); + cfg->schemes = tmp; } } static void -parse_authparam(authConfig * config) +parse_authscheme(parserNameNode *parserName, void * data) { + authSchemes * config=(authSchemes *) data; char *type_str; - char *param_str; authScheme *scheme = NULL; int type, i; if ((type_str = strtok(NULL, w_space)) == NULL) - self_destruct(); - - if ((param_str = strtok(NULL, w_space)) == NULL) - self_destruct(); + self_destruct(); if ((type = authenticateAuthSchemeId(type_str)) == -1) { - debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str); - return; + debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str); + return; } for (i = 0; i < config->n_configured; i++) { - if (config->schemes[i].Id == type) { - scheme = config->schemes + i; - } + if (config->schemes[i].Id == type) { + scheme = config->schemes + i; + } } if (scheme == NULL) { - allocate_new_authScheme(config); - scheme = config->schemes + config->n_configured; - config->n_configured++; - scheme->Id = type; - scheme->typestr = authscheme_list[type].typestr; + allocate_new_authScheme(config); + scheme = config->schemes + config->n_configured; + config->n_configured++; + scheme->Id = type; + scheme->typestr = authscheme_list[type].typestr; } - authscheme_list[type].parse(scheme, config->n_configured, param_str); } static void -free_authparam(authConfig * cfg) +free_authscheme(parserNameNode *parserName, void * data) { - authScheme *scheme; + authSchemes * cfg=(authSchemes *) data; + authScheme *scheme = NULL; int i; - /* DON'T FREE THESE FOR RECONFIGURE */ - if (reconfiguring) - return; for (i = 0; i < cfg->n_configured; i++) { - scheme = cfg->schemes + i; - authscheme_list[scheme->Id].freeconfig(scheme); + scheme = cfg->schemes + i; } safe_free(cfg->schemes); cfg->schemes = NULL; @@ -996,13 +1061,145 @@ } static void -dump_authparam(StoreEntry * entry, const char *name, authConfig cfg) +dump_authscheme(StoreEntry * entry, const char *name, void const * data) { + authSchemes * cfg=*(authSchemes **) data; authScheme *scheme; int i; - for (i = 0; i < cfg.n_configured; i++) { - scheme = cfg.schemes + i; - authscheme_list[scheme->Id].dump(entry, name, scheme); + for (i = 0; i < cfg->n_configured; i++) { + scheme = cfg->schemes + i; + storeAppendPrintf(entry, "%s %s\n", name, scheme->typestr); + } +} + + + +CBDATA_TYPE(modNode); +/* Operation of modNode cbdata: + * config allocates the record, and free frees it. + * any configuration that depends on the record + * locks it and + * any matching free configuration + * unlocks it + */ + +const char * +mod_type_str(const mod_t type) +{ + switch (type) { + case MOD_INTERNAL: + return "internal"; + break; + case MOD_EXTERNAL: + return "external"; + break; + default: + return "unknown"; + break; + } +} + + +/* TODO: write a cbdataFree handler for modNode's. */ +static void +parse_mod_install(parserNameNode *parserName, void *data) +{ + modConfig * cfg = data; + char *type_str = NULL, *name_str = NULL; + mod_t type = MOD_NONE; + modNode *node = NULL; + dlink_node *linknode; + + int rv; + + linknode = cfg->modules.head; + if (!linknode) + /* first run */ + CBDATA_INIT_TYPE(modNode); + + if ((type_str = strtok(NULL, w_space)) == NULL) + self_destruct(); + + if ((name_str = strtok(NULL, w_space)) == NULL) + self_destruct(); + + /* find the module if it's currently configured */ + while (linknode && strcasecmp((*(modNode *) (linknode->data)).namestr, name_str)) { + linknode = linknode->next; + } + + if (linknode == NULL) { + /* ignore the type if it is already configured. */ + if (strcasecmp(type_str, "internal") == 0) { + /* internal module */ + type = MOD_INTERNAL; + } else if (strcasecmp(type_str, "external") == 0) { + /* external module */ + debug(3, 0) ("external modules not supported yet\n"); + } + if (type == MOD_NONE) + self_destruct(); + + node = cbdataAlloc(modNode); + assert(node); + node->type = type; + node->namestr = xstrdup(name_str); + if (type == MOD_INTERNAL) + rv = mod_internal_install(node->namestr, node); +#if 0 + else if (type == MOD_EXTERNAL) + rv = mod_external_install(node->namestr, node); +#endif + else + rv = 0; + if (rv) + dlinkAddTail(node, &node->node, &cfg->modules); + else { + safe_free(node->namestr); + cbdataFree(node); + node=NULL; + } + } else { + node = linknode->data; + } + + if (node) + cbdataLock(parserName); + /* call the modules configuration routine, if any */ + +} + +static void +free_mod_install(parserNameNode *parserName, void *data) +{ + modConfig * cfg=data; + dlink_node *node, *tmpnode; + modNode *module; + node = cfg->modules.head; + while (node) { + tmpnode = node; + module = node->data; + node = node->next; + if (module->uninstall(module->namestr)) { + dlinkDelete(tmpnode, &cfg->modules); + safe_free(module->namestr); + cbdataFree(module); + cbdataUnlock(parserName); + } + } +} + +static void +dump_mod_install(StoreEntry * entry, const char *name, void const *data) +{ + modConfig const * cfg=data; + dlink_node *node; + modNode *module; + node = cfg->modules.head; + while (node) { + module = node->data; + storeAppendPrintf(entry, "mod_install %s %s\n",mod_type_str(module->type),module->namestr); + node = node->next; } } @@ -1027,6 +1224,10 @@ find_fstype(char *type) { int i; + if (!storefs_list) { + debug(3,0)("No fs module installed\n"); + return (-1); + } for (i = 0; storefs_list[i].typestr != NULL; i++) { if (strcasecmp(type, storefs_list[i].typestr) == 0) { return i; @@ -1035,9 +1236,11 @@ return (-1); } + static void -parse_cachedir(cacheSwap * swap) +parse_cachedir(parserNameNode *parserName, void * data) { + cacheSwap * swap=data; char *type_str; char *path_str; SwapDir *sd; @@ -1100,6 +1303,8 @@ swap->n_configured++; /* Update the max object size */ update_maxobjsize(); + /* lock the Name so it doesn't get freed out from under us */ + cbdataLock(parserName); } static void @@ -1194,17 +1399,23 @@ } static void -free_cachedir(cacheSwap * swap) +free_cachedir(parserNameNode *parserName, void * data) { + cacheSwap * swap=data; SwapDir *s; int i; /* DON'T FREE THESE FOR RECONFIGURE */ + /* TODO: implement runtime cache_dir removal. + * in progress items should have the cachedir cbdata locked via some reference chain + * so the actual free will only occur when the last reference disappears + */ if (reconfiguring) return; for (i = 0; i < swap->n_configured; i++) { s = swap->swapDirs + i; s->freefs(s); xfree(s->path); + cbdataUnlock(parserName); } safe_free(swap->swapDirs); swap->swapDirs = NULL; @@ -1232,8 +1443,9 @@ } static void -dump_peer(StoreEntry * entry, const char *name, peer * p) +dump_peer(StoreEntry * entry, const char *name, void const * const data) { + peer * p=*(peer **)data; domain_ping *d; domain_type *t; LOCAL_ARRAY(char, xname, 128); @@ -1266,8 +1478,9 @@ } static void -parse_peer(peer ** head) +parse_peer(parserNameNode *parserName, void * data) { + peer ** head=(peer **)data; char *token = NULL; peer *p; int i; @@ -1371,11 +1584,13 @@ *head = p; Config.npeers++; peerClearRR(p); + cbdataLock(parserName); } static void -free_peer(peer ** P) +free_peer(parserNameNode *parserName, void * data) { + peer ** P=(peer **)data; peer *p; while ((p = *P) != NULL) { *P = p->next; @@ -1385,13 +1600,15 @@ p->digest = NULL; #endif cbdataFree(p); + cbdataUnlock(parserName); } Config.npeers = 0; } static void -dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list) +dump_cachemgrpasswd(StoreEntry * entry, const char *name, void const * const data) { + cachemgr_passwd * list=*(cachemgr_passwd **)data; wordlist *w; while (list != NULL) { if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable")) @@ -1407,14 +1624,15 @@ } static void -parse_cachemgrpasswd(cachemgr_passwd ** head) +parse_cachemgrpasswd(parserNameNode *parserName, void * data) { + cachemgr_passwd ** head=(cachemgr_passwd **)data; char *passwd = NULL; wordlist *actions = NULL; cachemgr_passwd *p; cachemgr_passwd **P; - parse_string(&passwd); - parse_wordlist(&actions); + parse_string(parserName, &passwd); + parse_wordlist(parserName, &actions); p = xcalloc(1, sizeof(cachemgr_passwd)); p->passwd = passwd; p->actions = actions; @@ -1423,8 +1641,9 @@ } static void -free_cachemgrpasswd(cachemgr_passwd ** head) +free_cachemgrpasswd(parserNameNode *parserName, void * data) { + cachemgr_passwd ** head=(cachemgr_passwd **)data; cachemgr_passwd *p; while ((p = *head) != NULL) { *head = p->next; @@ -1435,46 +1654,7 @@ } static void -dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var) -{ - 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 -parse_denyinfo(acl_deny_info_list ** var) -{ - aclParseDenyInfoLine(var); -} - -void -free_denyinfo(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; - memFree(l, MEM_ACL_NAME_LIST); - l = NULL; - } - a_next = a->next; - memFree(a, MEM_ACL_DENY_INFO_LIST); - a = NULL; - } - *list = NULL; -} - -static void -parse_peer_access(void) +parse_peer_access(parserNameNode *parserName, void * data) { char *host = NULL; peer *p; @@ -1485,11 +1665,23 @@ cfg_filename, config_lineno, host); return; } - aclParseAccessLine(&p->access); + parse_acl_access(parserName, &p->access); +} + +static void +free_peer_access(parserNameNode *parserName, void * data) +{ + /* nop as it's currently freed with the peer */ } static void -parse_hostdomain(void) +dump_peer_access(StoreEntry * entry, const char *name, void const * const data) +{ + /* nop as it's currently dumped with the peer settings */ +} + +static void +parse_hostdomain(parserNameNode *parserName, void * data) { char *host = NULL; char *domain = NULL; @@ -1517,7 +1709,19 @@ } static void -parse_hostdomaintype(void) +free_hostdomain(parserNameNode *parserName, void * data) +{ + /* nop as it's currently freed with the peer */ +} + +static void +dump_hostdomain(StoreEntry * entry, const char *name, void const * const data) +{ + /* nop as it's currently dumped with the peer settings */ +} + +static void +parse_hostdomaintype(parserNameNode *parserName, void * data) { char *host = NULL; char *type = NULL; @@ -1543,10 +1747,23 @@ } } +static void +free_hostdomaintype(parserNameNode *parserName, void * data) +{ + /* nop as it's currently freed with the peer */ +} + +static void +dump_hostdomaintype(StoreEntry * entry, const char *name, void const * const data) +{ + /* nop as it's currently dumped with the peer settings */ +} + #if UNUSED_CODE static void -dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u) +dump_ushortlist(StoreEntry * entry, const char *name, void const * const data) { + ushortlist * u=*(ushortlist **)data; while (u) { storeAppendPrintf(entry, "%s %d\n", name, (int) u->i); u = u->next; @@ -1590,34 +1807,39 @@ #endif static void -dump_int(StoreEntry * entry, const char *name, int var) +dump_int(StoreEntry * entry, const char *name, void const * const data) { + int var=*(int *)data; storeAppendPrintf(entry, "%s %d\n", name, var); } void -parse_int(int *var) +parse_int(parserNameNode *parserName, void * data) { + int *var=data; int i; i = GetInteger(); *var = i; } static void -free_int(int *var) +free_int(parserNameNode *parserName, void * data) { + int *var=data; *var = 0; } static void -dump_onoff(StoreEntry * entry, const char *name, int var) +dump_onoff(StoreEntry * entry, const char *name, void const * const data) { + int var=*(int *)data; storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off"); } static void -parse_onoff(int *var) +parse_onoff(parserNameNode *parserName, void * data) { + int *var=data; char *token = strtok(NULL, w_space); if (token == NULL) @@ -1633,8 +1855,9 @@ #define free_eol free_string static void -dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head) +dump_refreshpattern(StoreEntry * entry, const char *name, void const * const data) { + refresh_t * head=*(refresh_t **)data; while (head != NULL) { storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n", name, @@ -1659,8 +1882,9 @@ } static void -parse_refreshpattern(refresh_t ** head) +parse_refreshpattern(parserNameNode *parserName, void * data) { + refresh_t ** head=(refresh_t **)data; char *token; char *pattern; time_t min = 0; @@ -1758,8 +1982,9 @@ } static void -free_refreshpattern(refresh_t ** head) +free_refreshpattern(parserNameNode *parserName, void * data) { + refresh_t ** head=(refresh_t **)data; refresh_t *t; while ((t = *head) != NULL) { *head = t->next; @@ -1770,15 +1995,17 @@ } static void -dump_string(StoreEntry * entry, const char *name, char *var) +dump_string(StoreEntry * entry, const char *name, void const * const data) { + char *var=*(char **)data; if (var != NULL) storeAppendPrintf(entry, "%s %s\n", name, var); } static void -parse_string(char **var) +parse_string(parserNameNode *parserName, void * data) { + char **var=(char **)data; char *token = strtok(NULL, w_space); safe_free(*var); if (token == NULL) @@ -1787,14 +2014,16 @@ } static void -free_string(char **var) +free_string(parserNameNode *parserName, void * data) { + char **var=(char **) data; safe_free(*var); } void -parse_eol(char *volatile *var) +parse_eol(parserNameNode *parserName, void * data) { + char *volatile *var=(char *volatile*)data; unsigned char *token = strtok(NULL, null_string); safe_free(*var); if (token == NULL) @@ -1807,64 +2036,74 @@ } static void -dump_time_t(StoreEntry * entry, const char *name, time_t var) +dump_time_t(StoreEntry * entry, const char *name, void const * const data) { + time_t var=*(time_t *)data; storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var); } void -parse_time_t(time_t * var) +parse_time_t(parserNameNode *parserName, void * data) { + time_t * var=data; parseTimeLine(var, T_SECOND_STR); } static void -free_time_t(time_t * var) +free_time_t(parserNameNode *parserName, void * data) { + time_t * var=data; *var = 0; } static void -dump_size_t(StoreEntry * entry, const char *name, size_t var) +dump_size_t(StoreEntry * entry, const char *name, void const * const data) { + size_t var=*(size_t *)data; storeAppendPrintf(entry, "%s %d\n", name, (int) var); } static void -dump_b_size_t(StoreEntry * entry, const char *name, size_t var) +dump_b_size_t(StoreEntry * entry, const char *name, void const * const data) { + size_t var=*(size_t *)data; storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR); } static void -dump_kb_size_t(StoreEntry * entry, const char *name, size_t var) +dump_kb_size_t(StoreEntry * entry, const char *name, void const * const data) { + size_t var=*(size_t *)data; storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR); } static void -parse_size_t(size_t * var) +parse_size_t(parserNameNode *parserName, void * data) { + size_t * var=data; int i; i = GetInteger(); *var = (size_t) i; } static void -parse_b_size_t(size_t * var) +parse_b_size_t(parserNameNode *parserName, void * data) { + size_t * var=data; parseBytesLine(var, B_BYTES_STR); } static void -parse_kb_size_t(size_t * var) +parse_kb_size_t(parserNameNode *parserName, void * data) { + size_t * var=data; parseBytesLine(var, B_KBYTES_STR); } static void -free_size_t(size_t * var) +free_size_t(parserNameNode *parserName, void * data) { + size_t * var=data; *var = 0; } @@ -1874,20 +2113,23 @@ #define free_gb_size_t free_size_t static void -dump_ushort(StoreEntry * entry, const char *name, u_short var) +dump_ushort(StoreEntry * entry, const char *name, void const * const data) { + u_short var=*(u_short *)data; storeAppendPrintf(entry, "%s %d\n", name, var); } static void -free_ushort(u_short * u) +free_ushort(parserNameNode *parserName, void * data) { + u_short * u=data; *u = 0; } static void -parse_ushort(u_short * var) +parse_ushort(parserNameNode *parserName, void * data) { + u_short * var=data; int i; i = GetInteger(); @@ -1896,9 +2138,10 @@ *var = (u_short) i; } -static void -dump_wordlist(StoreEntry * entry, const char *name, wordlist * list) +void +dump_wordlist(StoreEntry * entry, const char *name, void const * const data) { + wordlist * list=*(wordlist **)data; while (list != NULL) { storeAppendPrintf(entry, "%s %s\n", name, list->key); list = list->next; @@ -1906,32 +2149,41 @@ } void -parse_wordlist(wordlist ** list) +parse_wordlist(parserNameNode *parserName, void * data) { + wordlist ** list=data; char *token; while ((token = strtok(NULL, w_space))) wordlistAdd(list, token); } +void +parse_wordlistFromFile(parserNameNode *parserName, void * data) +{ + wordlist ** list=data; + char *token; + while ((token = strtokFile())) + wordlistAdd(list, token); +} + static int check_null_wordlist(wordlist * w) { return w == NULL; } -static int -check_null_acl_access(acl_access * a) +void +free_wordlist(parserNameNode *parserName, void * data) { - return a == NULL; + wordlistDestroy(data); } -#define free_wordlist wordlistDestroy - #define free_uri_whitespace free_int static void -parse_uri_whitespace(int *var) +parse_uri_whitespace(parserNameNode *parserName, void * data) { + int *var=data; char *token = strtok(NULL, w_space); if (token == NULL) self_destruct(); @@ -1951,8 +2203,9 @@ static void -dump_uri_whitespace(StoreEntry * entry, const char *name, int var) +dump_uri_whitespace(StoreEntry * entry, const char *name, void const * const data) { + int var=*(int *)data; char *s; if (var == URI_WHITESPACE_ALLOW) s = "allow"; @@ -1967,30 +2220,41 @@ storeAppendPrintf(entry, "%s %s\n", name, s); } +/* TODO: allow named removal policies. Then the cachedir takes the first + * removal policy, or a named override. + * Reason for this: removal policies have to copy their settings when being + * assigned to cache_dir's at the moment. Is this good ? + * Result of this change: removal policies cblock their settings, and + * when freed only release if no cache dir is using them + */ + static void -free_removalpolicy(RemovalPolicySettings ** settings) +free_removalpolicy(parserNameNode *parserName, void * data) { + RemovalPolicySettings ** settings=(RemovalPolicySettings **)data; if (!*settings) return; - free_string(&(*settings)->type); - free_wordlist(&(*settings)->args); + free_string(parserName, &(*settings)->type); + free_wordlist(parserName, &(*settings)->args); xfree(*settings); *settings = NULL; } static void -parse_removalpolicy(RemovalPolicySettings ** settings) +parse_removalpolicy(parserNameNode *parserName, void * data) { + RemovalPolicySettings ** settings=(RemovalPolicySettings **)data; if (*settings) - free_removalpolicy(settings); + free_removalpolicy(parserName, settings); *settings = xcalloc(1, sizeof(**settings)); - parse_string(&(*settings)->type); - parse_wordlist(&(*settings)->args); + parse_string(parserName, &(*settings)->type); + parse_wordlist(parserName, &(*settings)->args); } static void -dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings) +dump_removalpolicy(StoreEntry * entry, const char *name, void const * const data) { + RemovalPolicySettings * settings=*(RemovalPolicySettings * *)data; wordlist *args; storeAppendPrintf(entry, "%s %s", name, settings->type); args = settings->args; @@ -2002,6 +2266,130 @@ } +CBDATA_TYPE(includefile_t); + +static void +parse_include(parserNameNode *parserName, void * data) +{ + includefile_t **includefile=(includefile_t **)data; + includefile_t *link,*tmp_link; + char *tempstr=NULL; + if (! *includefile) + CBDATA_INIT_TYPE(includefile_t); + + parse_eol(parserName, &tempstr); + + link=*includefile; + while (link && link->next) + link=link->next; + + tmp_link=cbdataAlloc(includefile_t); + tmp_link->next=NULL; + tmp_link->filename=tempstr; + + if (link) + link->next=tmp_link; + else + *includefile=tmp_link; + + parseConfigFile(tmp_link->filename); +} + +static void +free_include(parserNameNode *parserName, void * data) +{ + /* we don't need to process the file data, just free the linked list */ + includefile_t **includefile=(includefile_t **)data; + includefile_t *link; + while (*includefile) { + free_eol(parserName, &(*includefile)->filename); + link=(*includefile)->next; + cbdataFree(*includefile); + *includefile=link; + } +} + +static void +dump_include(StoreEntry * entry, const char *name, void const * const data) +{ + includefile_t *link=*(includefile_t **)data; + while (link) { + storeAppendPrintf(entry,"%s %s\n",name,link->filename); + link=link->next; + } +} + +/* Insert any new 'core' types here for registration */ +static void +parserRegisterAllTypes(void) +{ + parserRegisterCFTypes(); + parserRegisterType("instance_node", parse_instance_node, free_instance_node, dump_instance_node); + +// parserRegisterType("acl",aclParseAclLine,free_acl,dump_acl); +} + + +//parserRegisterType("acl",parse_acl,free_acl,dump_acl); + + +void *parserRegisterInstanceName(const char *, parserTypeNode *, PARSER_DEFAULT_NONE *, PARSER_POST_PARSE *); + +#if 0 +static void * aclinstances = NULL; + +#define default_if_none_acl NULL +#define name_document_acl NULL +#endif + +PARSER_DEFAULT_NONE default_if_no_instances; + +/* Insert any new 'core' names here for registration */ +static void +parserRegisterAllNames(void) +{ + + parserRegisterCFNames(); + + /* ACL.C routines: should be in acl.c */ + + aclParserRegister(); + +// parserRegisterName("acl",parserTypeByName("instance_node"),&Config.aclList2,default_if_none_acl,name_document_acl, NULL); + +#if 0 + if (aclinstances) + debug(3,0)("bwahhahhahaha\n\n"); + aclinstances = parserRegisterInstanceName("acl", parserTypeByName("acl"), name_document_acl, NULL); + + parserRegisterName(NULL, "acl", parserTypeByName("instance_node"), aclinstances, default_if_none_acl, name_document_acl, NULL); + +#endif + +/* instance called acl + to parse use type foo */ + + + +/* +instance type called acl. + +registerinstancetype acl + +list referred to as acl +acl has location foo. + + +list has a new entry of type instance at location instance-location. +in foo, add to the type list, +instance, location. + +list has a new entry of type acl at location acl-location +in foo add to the type list +acl, location +*/ +} + #include "cf_parser.c" peer_t @@ -2022,8 +2410,9 @@ } static void -parse_sockaddr_in_list(sockaddr_in_list ** head) +parse_sockaddr_in_list(parserNameNode *parserName, void * data) { + sockaddr_in_list ** head =(sockaddr_in_list **)data; char *token; char *t; char *host; @@ -2062,8 +2451,9 @@ } static void -dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s) +dump_sockaddr_in_list(StoreEntry * e, const char *n, void const * const data) { + sockaddr_in_list * s=*(sockaddr_in_list **)data; while (s) { storeAppendPrintf(e, "%s %s:%d\n", n, @@ -2074,8 +2464,9 @@ } static void -free_sockaddr_in_list(sockaddr_in_list ** head) +free_sockaddr_in_list(parserNameNode *parserName, void * data) { + sockaddr_in_list ** head=(sockaddr_in_list **)data; sockaddr_in_list *s; while ((s = *head) != NULL) { *head = s->next; @@ -2089,6 +2480,147 @@ return NULL == s; } + +parserNameNode *parserNameByNodeName(dlink_list *, const char *); + +CBDATA_TYPE(instance_name); +CBDATA_TYPE(instance_node); + +/* this code is broken. The fault is that not all instances will start at root. + * the solution is to store the instance list as the config data for the parent nore + * of the instance + */ +static dlink_list instance_names = {NULL,NULL}; + +void +default_if_no_instances(void *data) +{ + instance_name *Name=data; + if (Name->instances.head==NULL) + if (Name->default_none) + Name->default_none(NULL); +} + +/* the free function only occurs when the mempoolfree is about to occur. + * for persistent types, the config function locks the Name node + */ +static void +parserInstanceNameFree(void *data) +{ + instance_name *Name=data; + dlinkDelete(&Name->node,&instance_names); + debug(3,0)("parserNameFree freed name %s\n",Name->namestr); + safe_free(Name->namestr); + cbdataUnlock(Name->type); +} + + +/* FIXME: this may need a parent option */ +instance_name * +parserInstanceNameByName(const char *name) +{ + dlink_node *node; + node=instance_names.head; + while (node && strcmp(((instance_name *)node->data)->namestr,name)) { + node=node->next; + + } + if (node) + return (instance_name *)node->data; + else + return NULL; +} + +void * parserRegisterInstanceName(const char *namestr, parserTypeNode *parserType, PARSER_DEFAULT_NONE *default_none, PARSER_POST_PARSE *post_parse_func) +{ + instance_name *Name; + if ((Name=parserInstanceNameByName(namestr))==NULL) { + /* register the type */ + debug(3,3)("parserRegisterInstanceName new name '%s'\n",Name); + if (instance_names.head==NULL) + CBDATA_INIT_TYPE_FREECB(instance_name,parserInstanceNameFree); + Name=cbdataAlloc(instance_name); + Name->namestr=xstrdup(namestr); + Name->type=parserType; + cbdataLock(parserType); + Name->default_none=default_none; + Name->post_parse_func=post_parse_func; + dlinkAddTail(Name,&Name->node,&instance_names); + return Name; +} else { + debug(3,0)("parserRegisterInstanceName already registered name '%s'\n",Name); + return NULL; + /* TODO: fatal this */ + } +} + +static void +InstanceNodeFree(void *data) +{ + instance_node *instance=data; + dlinkDelete(&instance->node, (instance->head)); + debug(3,0)("parserNameFree freed name %s\n",instance->parserName->namestr); + cbdataUnlock(instance->name); +} + +instance_node * +InstanceByNameStr(instance_name *Name, const char *namestr) +{ + dlink_node *node; + node=Name->instances.head; + while (node && strcmp(((instance_node *)node->data)->namestr,namestr)) { + node=node->next; + } + if (node) + return (instance_node *)node->data; + else + return NULL; +} + +/* Called when an unrecognised child of an "instance" type is seen */ +static void +parse_instance_node(parserNameNode *parserName, void * data) +{ + char *token = NULL; + instance_name *Name=data; + instance_node *instance=NULL; + if ((token = strtok(NULL, w_space)) == NULL) { + debug(3, 0) (" %s line %d: %s\n", + cfg_filename, config_lineno, config_input_line); + debug(3, 0) ("parse_instance_node: missing instance name.\n"); + return; + } + + if ((instance=InstanceByNameStr(Name,token))==NULL) { + /* register me */ + if (Name->instances.head==NULL) + CBDATA_INIT_TYPE_FREECB(instance_node,InstanceNodeFree); + instance=cbdataAlloc(instance_node); + + debug(3,0)("parsing new instance name %s\n",token); + + instance->namestr=xstrdup(token); + instance->head=&Name->instances; + instance->data=NULL; + parserRegisterName(parserName, instance->namestr, Name->type, &instance->data, NULL, NULL, NULL); + instance->parserName=parserNameByNodeName(&parserName->children, instance->namestr); + assert(instance->parserName); + dlinkAddTail(instance,&instance->node, instance->head); + } + /* parse that instance */ + instance->parserName->type->parsefunc(instance->parserName, instance->parserName->location); +} + +static void +free_instance_node(parserNameNode *parserName, void * data) +{ +} + +static void +dump_instance_node(StoreEntry * e, const char *n, void const * const data) +{ +} + #if USE_SSL static void parse_https_port_list(https_port_list ** head) @@ -2193,3 +2725,465 @@ if (stat(path, &sb) < 0) fatalf("%s: %s", path, xstrerror()); } + +/* dynamic parser support routines */ + +CBDATA_TYPE(parserTypeNode); +CBDATA_TYPE(parserNameNode); + +static void +parserTypeFree(void *data) +{ + parserTypeNode *parserType=data; + dlinkDelete(&parserType->node,&parserTypes); + debug(3,0)("parserTypeFree freed type %s\n",parserType->typestr); +} + +parserTypeNode * +parserTypeByName(const char *typestr) +{ + dlink_node *node; + node=parserTypes.head; + while (node && strcmp(((parserTypeNode *)node->data)->typestr,typestr)) { + node=node->next; + } + if (node) + return (parserTypeNode *)node->data; + else + return NULL; +} + +void +parserRegisterType(const char *typestr, PARSER_PARSE *parsefunc, PARSER_FREE *freefunc, PARSER_DUMP *dumpfunc) +{ + parserTypeNode *parserType; + if ((parserType=parserTypeByName(typestr))==NULL) { + /* register the type */ + debug(3,3)("parserRegisterType new type '%s'\n",typestr); + if (parserTypes.head==NULL) + CBDATA_INIT_TYPE_FREECB(parserTypeNode,parserTypeFree); + parserType=cbdataAlloc(parserTypeNode); + parserType->typestr=typestr; + parserType->parsefunc=parsefunc; + parserType->freefunc=freefunc; + parserType->dumpfunc=dumpfunc; + parserType->flags.registered=0; + dlinkAddTail(parserType,&parserType->node,&parserTypes); + } else { + /* confirm the pointers are the same */ + debug(3,3)("parserRegisterType already registered type '%s'\n",typestr); + if ((parserType->parsefunc!=parsefunc) || + (parserType->freefunc!=freefunc) || + (parserType->dumpfunc!=dumpfunc)) { + debug(3,0)("parserRegisterType already registered type '%s' has different function pointers!\n",typestr); + } + } + if (parserType->flags.registered==0) { + cbdataLock(parserType); + parserType->flags.registered=1; + } +} + +void parserDeregisterType(parserTypeNode *parserType) +{ + if (!parserType) + return; + debug(3,3)("parserDeregisterType '%s'\n",parserType->typestr); + cbdataFree(parserType); + if (parserType->flags.registered==1) { + cbdataUnlock(parserType); + parserType->flags.registered=0; + } +} + +static void +parserDeregisterAllTypes(void) +{ + dlink_node *node; + node=parserTypes.head; + while (node) { + parserDeregisterType(node->data); + node=node->next; + } +} + +/* the free function only occurs when the mempoolfree is about to occur. + * for persistent types, the config function locks the Name node + */ +static void +parserNameFree(void *data) +{ + parserNameNode *parserName=data; + dlink_node *node; + dlinkDelete(&parserName->node,parserName->head); + debug(3,0)("parserNameFree freed name %s\n",parserName->namestr); + + node=parserName->children.head; + while (node) { + parserDeregisterName(node->data); + node=node->next; + } + + cbdataUnlock(parserName->type); +} + +parserNameNode * +parserNameByNodeName(dlink_list *parent, const char *name) +{ + dlink_node *node; + node=parent->head; + while (node && strcmp(((parserNameNode *)node->data)->namestr,name)) { + node=node->next; + } + if (node) + return (parserNameNode *)node->data; + else + return NULL; +} + +parserNameNode * +parserNameByName(const char *name) +{ + return parserNameByNodeName(&parserNames,name); +} + +/* register a new name for the config file + * a name is the first symbol on a line in the config file. + * TODO: check for conflicts with cf.data.pre declared names + * TODO: check for conflicts with dynamically registered names. + * TODO: have cf_parser.c dynamically register all the config file builtin types, + * ignoring errors (because they have been migrated to auto register ). + */ +void +parserRegisterName(parserNameNode *parent, const char *name, parserTypeNode *parserType, void *location, + PARSER_DEFAULT_NONE *default_none, PARSER_NAME_DOCUMENT *documentfunc, PARSER_POST_PARSE *post_parse_func) +{ + parserNameNode *parserName; + + + if ((parserName=parserNameByNodeName(parent ? &parent->children : &parserNames, name))==NULL) { + /* register the type */ + debug(3,3)("parserRegisterName new name '%s'\n",name); + if (parserNames.head==NULL) + CBDATA_INIT_TYPE_FREECB(parserNameNode,parserNameFree); + parserName=cbdataAlloc(parserNameNode); + parserName->namestr=name; + parserName->type=parserType; + cbdataLock(parserType); + parserName->location=location; + parserName->default_none=default_none; + parserName->documentfunc=documentfunc; + parserName->post_parse_func=post_parse_func; + parserName->head = parent ? &parent->children : &parserNames; + parserName->parent = parent; + parserName->children.head=NULL; + parserName->children.tail=NULL; + dlinkAddTail(parserName,&parserName->node,parserName->head); +} else { + /* confirm the pointers are the same */ + debug(3,3)("parserRegisterName already registered name '%s'\n",name); + if ((parserName->type!=parserType) || + (parserName->location!=location) || + (parserName->default_none!=default_none) || + (parserName->documentfunc!=documentfunc) || + (parserName->post_parse_func!=post_parse_func)) { + debug(3,0)("parserRegisterName already registered name '%s' has a different type, location, default_if_none function or document function.\n",name); + } +} + if (parserName->flags.registered==0) { + cbdataLock(parserName); + parserName->flags.registered=1; + } +} + +void +parserDeregisterName(parserNameNode *parserName) +{ + if (!parserName) + return; + debug(3,0)("parserDeregisterName '%s'\n",parserName->namestr); + cbdataFree(parserName); + if (parserName->flags.registered==1) { + cbdataUnlock(parserName); + parserName->flags.registered=0; + } +} + +/* TODO: we might hit a null pointer here if the node gets unlinked under us */ +static void +parserDeregisterAllNames(void) +{ + dlink_node *node; + node=parserNames.head; + while (node) { + parserDeregisterName(node->data); + node=node->next; + } +} + +static int +parserNameDoPostParse(void) +{ + dlink_node *node; + int rv=0; + node=parserNames.head; + while (node) { + if (((parserNameNode *)node->data)->post_parse_func) + rv+=((parserNameNode *)node->data)->post_parse_func(); + node=node->next; + } + return rv; +} + +void +default_line(const char *s) +{ + LOCAL_ARRAY(char, tmp_line, BUFSIZ); + memset(tmp_line, '\0', BUFSIZ); + xstrncpy(tmp_line, s, BUFSIZ); + xstrncpy(config_input_line, s, BUFSIZ); + config_lineno++; + parse_line(tmp_line); +} + + +/* this backs strtok up a step after checking the next result. IT ALTERS THE STRING. + * (Users should copy out any needed data from the current symbol before calling) + */ +static int +peek_line(char *current_token) +{ + char *token; + char saved; + size_t saved_len; + saved=current_token[strlen(current_token)-1]; + saved_len = strlen(current_token+strlen(current_token)+1); + if ((token = strtok(NULL, w_space)) == NULL) + /* Fail if no more tokens on this line */ + return 0; + debug(3,8)("next token %s\n",token); + /* back up strtok a step. Yummy */ + if (strlen(token) != saved_len) + /* next symbol is not last sympbol */ + *(token + strlen(token))=' '; + current_token[strlen(current_token)-1] = saved; + *(token-1) = ' '; + strtok(current_token,w_space); + return 1; +} + +int +parse_directive(parserNameNode *parent) +{ + char *token="dummy"; + parserNameNode *parserName, *currentName=parent; + if ((token = strtok(NULL, w_space)) == NULL) + return 0; /* fail on directives with no data */ + while (token) { //peek_line(token) + if ((parserName=parserNameByNodeName(parent ? ¤tName->children : &parserNames, token))==NULL) { + /* unregistered child, parse as normal. */ + /* back up strtok a step. Yummy */ + debug(0,0)("parse_directive: no child for %s\n", token); + if (peek_line(token)) + /* there are more elements to the line */ + *(token + strlen(token))=' '; + *(token-2) = 'A'; + *(token-1) = ' '; + strtok(token-2,w_space); + currentName->type->parsefunc(currentName, currentName->location); + if ((token = strtok(NULL, w_space)) == NULL) + return 1; /* finish at end of the line */ + } else { + debug(0,0)("parse_directive: known child %s\n", token); + /* registered child node */ + currentName=parserName; + /* eat the token we just stepped along */ + token = strtok(NULL, w_space); +// parserName->type->parsefunc(parserName, parserName->location); +// if ((token = strtok(NULL, w_space)) == NULL) +// return 1; /* finish at end of the line */ + } + } + /* unreached */ + return 1; +} + +static int +parse_line(char *buff) +{ + char *token; + parserNameNode *parserName; + debug(0,10)("parse_line: %s\n", buff); + if ((token = strtok(buff, w_space)) == NULL) + return 1; /* ignore empty lines */ + if ((parserName=parserNameByName(token))==NULL) { + /* unregistered name */ + return 0; + } else { + /* registered name */ + if (parserName->children.head) + return parse_directive(parserName); + else + parserName->type->parsefunc(parserName, parserName->location); + return 1; + } +} + +char * +strtokFile(void) +{ + char *t, *fn; + LOCAL_ARRAY(char, buf, 256); + static int strFromFile = 0; + static FILE *strFile; + + strtok_again: + if (!strFromFile) { + 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 ((strFile = fopen(fn, "r")) == NULL) { + debug(28, 0) ("strtokFile: %s not found\n", fn); + return (NULL); + } +#if defined(_SQUID_CYGWIN_) + setmode(fileno(strFile), O_TEXT); +#endif + strFromFile = 1; + } else { + return t; + } + } + /* strFromFile */ + if (fgets(buf, 256, strFile) == NULL) { + /* stop reading from file */ + fclose(strFile); + strFromFile = 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 void +dump_config(StoreEntry *entry) +{ + dlink_node *node; + node=parserNames.head; + while (node) { + ((parserNameNode *)node->data)->type->dumpfunc(entry, + ((parserNameNode *)node->data)->namestr, + ((parserNameNode *)node->data)->location); + node=node->next; + } +} + +static void +free_all(void) +{ + dlink_node *node; + node=parserNames.head; + while (node) { + ((parserNameNode *)node->data)->type->freefunc((parserNameNode *)node->data, ((parserNameNode *)node->data)->location); + node=node->next; + } +} + +static void +defaults_if_none(void) +{ + dlink_node *node; + node=parserNames.head; + while (node) { + if (((parserNameNode *)node->data)->default_none) + ((parserNameNode *)node->data)->default_none(((parserNameNode *)node->data)->location); + node=node->next; + } +} + +void +parserAddDocumentOption(const char *option) +{ + docoptionNode *node; + if (!DoDocumentOptions) { + /* first parameter */ + DoDocumentOptions=xcalloc(1, sizeof(docoptions)); + assert(DoDocumentOptions); + DoDocumentOptions->head=NULL; + DoDocumentOptions->flags.internalonly=0; + DoDocumentOptions->flags.all=0; + } + if (strcasecmp(option,"internalonly")==0) { + DoDocumentOptions->flags.internalonly=1; + } else if (strcasecmp(option,"all")==0) { + DoDocumentOptions->flags.all=1; + } else { + node=xcalloc(1, sizeof(docoptionNode)); + assert(node); + node->next=DoDocumentOptions->head; + node->name=xstrdup(option); + DoDocumentOptions->head=node; + } +} + +int +parserDoDocument(const char *file_name) +{ + int rv; + assert(DoDocumentOptions); + /* if not internal_only */ + if (!DoDocumentOptions->flags.internalonly) { + rv= parserReconfigure(file_name); + } else { + free_all(); + parserDeregisterAllNames(); + parserDeregisterAllTypes(); + parserRegisterAllTypes(); + parserRegisterAllNames(); + rv = !mod_internal_install("all", NULL); + defaults_if_none(); + /* don't try to apply the config. configDoConfigure(); */ + } + if (DoDocumentOptions->flags.all) { + /* print all names */ + dlink_node *node; + node=parserNames.head; + while (node) { + if (((parserNameNode *)node->data)->documentfunc) + ((parserNameNode *)node->data)->documentfunc(); + else + printf("directive '%s' has no documented options\n",((parserNameNode *)node->data)->namestr); + node=node->next; + } + } else { + /* print chosen names */ + parserNameNode *parserName; + docoptionNode *node=DoDocumentOptions->head; + while (node) { + if ((parserName = parserNameByName(node->name))) + if (parserName->documentfunc) + parserName->documentfunc(); + else + printf("directive '%s' has no documented options\n",node->name); + else + printf("directive '%s' not found.\n",node->name); + node=node->next; + } + } + return rv; +} Index: squid/src/cf.data.pre diff -u squid/src/cf.data.pre:1.27 squid/src/cf.data.pre:1.21.4.15 --- squid/src/cf.data.pre:1.27 Fri May 4 06:39:12 2001 +++ squid/src/cf.data.pre Sat May 12 06:06:03 2001 @@ -48,6 +48,65 @@ COMMENT_END +NAME: include +TYPE: include +DEFAULT: none +LOC: Config.files +DOC_START + Including config files. + + Squid supports breaking the single large config file into + sub files by the use of the include directive. The include + directives can be placed at any point in the main config file, + and in included config files. +NOCOMMENT_START +# include /etc/squidacl.conf +NOCOMMENT_END +DOC_END + +COMMENT_START + MODULE OPTIONS + ----------------------------------------------------------------------------- + Squid's module architecture allows dynamic addition and removal + of code from the code base. Modules _must_ be registered before they + are used or referenced (even from other config lines). +COMMENT_END + +NAME: mod_register +TYPE: mod_install +DEFAULT: none +LOC: Config.modules +DOC_START + usage: mod_register internal|external modulename + + External modules are not implemented yet. +NOCOMMENT_START +# Uncomment the following modules to match your compiled internal modules. + +# the following line registers all compiled in modules. To turn some off, +# comment the next line out, and then uncomment the lower lines as appropriate. +mod_register internal all + +# replacement policy modules +#mod_register internal lru +#mod_register internal heap + +# object store modules +#mod_register internal ufs +#mod_register internal aufs +#mod_register internal diskd +#mod_register internal null +#mod_register internal coss + +# authentication scheme modules +#mod_register internal basic +#mod_register internal ntlm +#mod_register internal digest + +NOCOMMENT_END +DOC_END + + COMMENT_START NETWORK OPTIONS ----------------------------------------------------------------------------- @@ -357,7 +416,7 @@ NAME: cache_peer_domain cache_host_domain TYPE: hostdomain DEFAULT: none -LOC: none +LOC: Config.peers DOC_START Use to limit the domains for which a neighbor cache will be queried. Usage: @@ -390,7 +449,7 @@ NAME: neighbor_type_domain TYPE: hostdomaintype DEFAULT: none -LOC: none +LOC: Config.peers DOC_START usage: neighbor_type_domain parent|sibling domain domain ... @@ -1193,17 +1252,14 @@ are sent. DOC_END -NAME: auth_param -TYPE: authparam -LOC: Config.authConfig +NAME: authenticate_scheme +TYPE: authscheme +LOC: Config.authSchemes DEFAULT: none DOC_START - This is used to pass parameters to the various authentication - schemes. - format: auth_param scheme parameter [setting] - - auth_param basic program @DEFAULT_PREFIX@/bin/ncsa_auth @DEFAULT_PREFIX@/etc/passwd - would tell the basic authentication scheme it's program parameter. + What order the configured authentication schemes should be + presented to the user agent. + format: authenticate_scheme scheme The order that authentication prompts are presented to the client_agent is dependant on the order the scheme first appears in config file. @@ -1213,150 +1269,6 @@ have difficulties (don't recognise the schemes offered even if you are using basic) then either put basic first, or disable the other schemes (by commenting out their program entry). - - Once an authentication scheme is fully configured, it can only be shutdown - by shutting squid down and restarting. Changes can be made on the fly and - activated with a reconfigure. I.E. You can change to a different helper, - but not unconfigure the helper completely. - - === Parameters for the basic scheme follow. === - - "program" cmdline - Specify the command for the external authenticator. Such a - program reads a line containing "username password" and replies - "OK" or "ERR" in an endless loop. If you use an authenticator, - make sure you have 1 acl of type proxy_auth. By default, the - authenticate_program is not used. - - If you want to use the traditional proxy authentication, - jump over to the ../auth_modules/NCSA directory and - type: - % make - % make install - - Then, set this line to something like - - auth_param basic program @DEFAULT_PREFIX@/bin/ncsa_auth @DEFAULT_PREFIX@/etc/passwd - - "children" numberofchildren - The number of authenticator processes to spawn (no default). If you - start too few Squid will have to wait for them to process a backlog - of usercode/password verifications, slowing it down. When password - verifications are done via a (slow) network you are likely to need - lots of authenticator processes. - auth_param basic children 5 - - "realm" realmstring - Specifies the realm name which is to be reported to the client for - the basic proxy authentication scheme (part of the text the user will - see when prompted their username and password). Their is no default. - auth_param basic realm Squid proxy-caching web server - - "credentialsttl" timetolive - Specifies how long squid assumes an externally validated username:password - pair is valid for - in other words how often the helper program is called - for that user. Set this low to force revalidation with short lived passwords. - Note that setting this high does not impact your susceptability to replay - attacks unless you are using a one-time password system (such as SecureID). - If you are using such a system, you will be vulnerable to replay attacks - unless you also enable the IP ttl is strict option. - - === Parameters for the digest scheme follow === - - "program" cmdline - Specify the command for the external authenticator. Such a - program reads a line containing "username":"realm" and replies - with the appropriate H(A1) value base64 encoded. See rfc 2616 for - the definition of H(A1). If you use an authenticator, - make sure you have 1 acl of type proxy_auth. By default, - authentication is not used. - - If you want to use build a authenticator, - jump over to the ../digest_auth_modules directory and choose the - authenticator to use. It it's directory type - % make - % make install - - Then, set this line to something like - - auth_param digest program @DEFAULT_PREFIX@/bin/digest_auth_pw @DEFAULT_PREFIX@/etc/digpass - - - "children" numberofchildren - The number of authenticator processes to spawn (no default). If you - start too few Squid will have to wait for them to process a backlog - of H(A1) calculations, slowing it down. When the H(A1) calculations - are done via a (slow) network you are likely to need lots of - authenticator processes. - auth_param digest children 5 - - "realm" realmstring - Specifies the realm name which is to be reported to the client for - the digest proxy authentication scheme (part of the text the user will - see when prompted their username and password). There is no default. - auth_param digest realm Squid proxy-caching web server - - "nonce_garbage_interval" timeinterval - Specifies the interval that nonces that have been issued to client_agent's - are checked for validity. - - "nonce_max_duration" timeinterval - Specifies the maximum length of time a given nonce will be valid for. - - "nonce_max_count" number - Specifies the maximum number of times a given nonce can be used. - - === NTLM scheme options follow === - - "program" cmdline - Specify the command for the external ntlm authenticator. Such a - program reads a line containing the uuencoded NEGOTIATE and replies - with the ntlm CHALLENGE, then waits for the response and answers with - "OK" or "ERR" in an endless loop. If you use an ntlm authenticator, - make sure you have 1 acl of type proxy_auth. By default, the - ntlm authenticator_program is not used. - - auth_param ntlm program @DEFAULT_PREFIX@/bin/ntlm_auth - - "children" numberofchildren - The number of authenticator processes to spawn (no default). If you - start too few Squid will have to wait for them to process a backlog - of credential verifications, slowing it down. When crendential - verifications are done via a (slow) network you are likely to need - lots of authenticator processes. - auth_param ntlm children 5 - - "max_challenge_reuses" number - The maximum number of times a challenge given by a ntlm authentication - helper can be reused. Increasing this number increases your exposure - to replay attacks on your network. 0 means use the challenge only once. - (disable challenge caching) - See max_ntlm_challenge_lifetime for more information. - auth_param ntlm max_challenge_reuses 0 - - "max_challenge_lifetime" timespan - The maximum time period that a ntlm challenge is reused over. - The actual period will be the minimum of this time AND the number of - reused challenges. - auth_param ntlm max_challenge_lifetime 2 minutes - -NOCOMMENT_START -#Recommended minimum configuration: -#auth_param digest program -#auth_param digest children 5 -#auth_param digest realm Squid proxy-caching web server -#auth_param digest nonce_garbage_interval 5 minutes -#auth_param digest nonce_max_duration 30 minutes -#auth_param digest nonce_max_count 50 -#auth_param ntlm program -#auth_param ntlm children 5 -#auth_param ntlm max_challenge_reuses 0 -#auth_param ntlm max_challenge_lifetime 2 minutes -#auth_param basic program -auth_param basic children 5 -auth_param basic realm Squid proxy-caching web server -auth_param basic credentialsttl 2 hours -NOCOMMENT_END DOC_END NAME: authenticate_cache_garbage_interval @@ -1832,8 +1744,10 @@ NAME: acl TYPE: acl +IFDEF: NEVER LOC: Config.aclList DEFAULT: none +DEFAULT_IF_NONE: all src 0.0.0.0/0.0.0.0 DOC_START Defining an Access List @@ -1910,6 +1824,10 @@ # WARNING: proxy_auth can't be used in a transparent proxy. It # collides with any authentication done by origin servers. It may # seem like it works at first, but it doesn't. + # + # NOTE: Authentication schemes need to be defined before proxy_auth ACL's + # in the squid.conf file. + # See authenticate_* commands. acl aclname snmp_community string ... # A community string to limit access to your SNMP Agent @@ -2081,7 +1999,7 @@ NAME: cache_peer_access TYPE: peer_access DEFAULT: none -LOC: none +LOC: Config.peers DOC_START Similar to 'cache_peer_domain' but provides more flexibility by using ACL elements. @@ -2419,23 +2337,6 @@ DOC_END -NAME: deny_info -TYPE: denyinfo -LOC: Config.denyInfoList -DEFAULT: none -DOC_START - Usage: deny_info err_page_name acl - Example: deny_info ERR_CUSTOM_ACCESS_DENIED bad_guys - - This can be used to return a ERR_ page for requests which - do not pass the 'http_access' rules. A single ACL will cause - the http_access check to fail. If a 'deny_info' line exists - for that ACL then Squid returns a corresponding error page. - - You may use ERR_ pages that come with Squid or create your own pages - and put them into the configured errors/ directory. -DOC_END - NAME: memory_pools COMMENT: on|off TYPE: onoff Index: squid/src/cf_gen.c diff -u squid/src/cf_gen.c:1.7 squid/src/cf_gen.c:1.7.8.12 --- squid/src/cf_gen.c:1.7 Fri Jan 12 00:20:32 2001 +++ squid/src/cf_gen.c Sun Mar 11 13:43:09 2001 @@ -41,11 +41,11 @@ * The output files are as follows: * cf_parser.c - this file contains, default_all() which * initializes variables with the default - * values, parse_line() that parses line from - * squid.conf, dump_config that dumps the - * current the values of the variables. - * squid.conf - default configuration file given to the server - * administrator. + * values, parserRegisterCFTypes() which registers + * all the cf.data.pre types, parserRegisterCFNames() + * which registers all the cf.data.pre Names. + * squid.conf.old - legacy version of th default configuration + * file given to the server administrator. *****************************************************************************/ #include "config.h" @@ -77,7 +77,7 @@ #define MAX_LINE 1024 /* longest configuration line */ #define _PATH_PARSER "cf_parser.c" -#define _PATH_SQUID_CONF "squid.conf" +#define _PATH_SQUID_CONF "squid.conf.old" enum State { sSTART, @@ -108,12 +108,96 @@ static const char WS[] = " \t"; -static int gen_default(Entry *, FILE *); -static void gen_parse(Entry *, FILE *); -static void gen_dump(Entry *, FILE *); -static void gen_free(Entry *, FILE *); static void gen_conf(Entry *, FILE *); +static void gen_registertypes(Entry *, FILE *); +static int gen_registernames(Entry *, FILE *); static void gen_default_if_none(Entry *, FILE *); +static void gen_document(Entry *, FILE *); + + +static struct { + unsigned char code; + char *quote; +} printfstandardentities[] = + +{ + /* NOTE: The quoted form MUST not be larger than 6 character. + * see close to the MemPool commend below + */ + { + '\"', "\\\"" + }, + { + '\\',"\\\\" + }, + { + '%',"%%" + }, + { + '\t',"\\t" + }, + { + '\0', "\0" + } +}; + +/* + * printf_quote - Returns a static buffer containing the quoted + * string. + */ +char * +printf_quote(const char *string) +{ + static char *buf; + static size_t bufsize = 0; + const char *src; + char *dst; + int i; + + /* XXX This really should be implemented using a MemPool, but + * MemPools are not yet available in lib... + */ + if (buf == NULL || strlen(string) * 6 > bufsize) { + xfree(buf); + bufsize = strlen(string) * 6 + 1; + buf = xcalloc(bufsize, 1); + } + for (src = string, dst = buf; *src; src++) { + char *escape = NULL; + const unsigned char ch = *src; + + /* Walk thru the list of HTML Entities that must be quoted to + * display safely + */ + for (i = 0; printfstandardentities[i].code; i++) { + if (ch == printfstandardentities[i].code) { + escape = printfstandardentities[i].quote; + break; + } + } + /* Encode control chars just to be on the safe side, and make + * sure all 8-bit characters are encoded to protect from buggy + * clients + */ + if (!escape && (ch <= 0x1F || ch >= 0x7f) && ch != '\n' && ch != '\r') { + static char dec_encoded[7]; + snprintf(dec_encoded, sizeof dec_encoded, "\\%03o", (int) ch); + escape = dec_encoded; + } + if (escape) { + /* Ok, An escaped form was found above. Use it */ + strncpy(dst, escape, 6); + dst += strlen(escape); + } else { + /* Apparently there is no need to escape this character */ + *dst++ = ch; + } + } + /* Nullterminate and return the result */ + *dst = '\0'; + return (buf); +} + static void lineAdd(Line ** L, char *str) @@ -321,10 +405,8 @@ fclose(fp); /*-------------------------------------------------------------------* - * Generate default_all() - * Generate parse_line() - * Generate dump_config() - * Generate free_all() + * Generate parserRegisterCFTypes() + * Generate parserRegisterCFNames() * Generate example squid.conf file *-------------------------------------------------------------------*/ @@ -346,11 +428,10 @@ "\n", input_filename, argv[0] ); - rc = gen_default(entries, fp); gen_default_if_none(entries, fp); - gen_parse(entries, fp); - gen_dump(entries, fp); - gen_free(entries, fp); + gen_registertypes(entries, fp); + gen_document(entries, fp); + rc = gen_registernames(entries, fp); fclose(fp); /* Open output x.conf file */ @@ -367,73 +448,11 @@ return (rc); } -static int -gen_default(Entry * head, FILE * fp) -{ - Entry *entry; - int rc = 0; - fprintf(fp, - "static void\n" - "default_line(const char *s)\n" - "{\n" - "\tLOCAL_ARRAY(char, tmp_line, BUFSIZ);\n" - "\txstrncpy(tmp_line, s, BUFSIZ);\n" - "\txstrncpy(config_input_line, s, BUFSIZ);\n" - "\tconfig_lineno++;\n" - "\tparse_line(tmp_line);\n" - "}\n" - ); - fprintf(fp, - "static void\n" - "default_all(void)\n" - "{\n" - "\tcfg_filename = \"Default Configuration\";\n" - "\tconfig_lineno = 0;\n" - ); - for (entry = head; entry != NULL; entry = entry->next) { - assert(entry->name); - assert(entry != entry->next); - - if (!strcmp(entry->name, "comment")) - continue; - if (entry->loc == NULL) { - fprintf(stderr, "NO LOCATION FOR %s\n", entry->name); - rc |= 1; - continue; - } - if (entry->default_value == NULL) { - fprintf(stderr, "NO DEFAULT FOR %s\n", entry->name); - rc |= 1; - continue; - } - assert(entry->default_value); - if (entry->ifdef) - fprintf(fp, "#if %s\n", entry->ifdef); - if (strcmp(entry->default_value, "none") == 0) { - fprintf(fp, "\t/* No default for %s */\n", entry->name); - } else { - fprintf(fp, "\tdefault_line(\"%s %s\");\n", - entry->name, - entry->default_value); - } - if (entry->ifdef) - fprintf(fp, "#endif\n"); - } - fprintf(fp, "\tcfg_filename = NULL;\n"); - fprintf(fp, "}\n\n"); - return rc; -} - static void gen_default_if_none(Entry * head, FILE * fp) { Entry *entry; Line *line; - fprintf(fp, - "static void\n" - "defaults_if_none(void)\n" - "{\n" - ); for (entry = head; entry != NULL; entry = entry->next) { assert(entry->name); assert(entry->loc); @@ -441,124 +460,192 @@ continue; if (entry->ifdef) fprintf(fp, "#if %s\n", entry->ifdef); - if (entry->default_if_none) { + fprintf(fp, + "static void\n" + "default_if_none_%s(void * data)" + "{\n" + "\tif (check_null_%s(%s)) {\n", + entry->name, + entry->type, + entry->loc); + for (line = entry->default_if_none; line; line = line->next) fprintf(fp, - "\tif (check_null_%s(%s)) {\n", - entry->type, - entry->loc); - for (line = entry->default_if_none; line; line = line->next) - fprintf(fp, - "\t\tdefault_line(\"%s %s\");\n", - entry->name, - line->data); - fprintf(fp, "\t}\n"); - } + "\t\tdefault_line(\"%s %s\");\n", + entry->name, + line->data); + fprintf(fp, "\t}\n}\n%s", entry->ifdef ? "" : "\n"); if (entry->ifdef) - fprintf(fp, "#endif\n"); + fprintf(fp, "#endif\n%s", entry->ifdef ? "\n" : ""); } - fprintf(fp, "}\n\n"); } static void -gen_parse(Entry * head, FILE * fp) +gen_registertypes(Entry * head, FILE * fp) { Entry *entry; - fprintf(fp, - "static int\n" - "parse_line(char *buff)\n" - "{\n" - "\tint\tresult = 1;\n" - "\tchar\t*token;\n" - "\tdebug(0,10)(\"parse_line: %%s\\n\", buff);\n" - "\tif ((token = strtok(buff, w_space)) == NULL)\n" - "\t\t(void) 0;\t/* ignore empty lines */\n" - ); - + "static void\n" + "parserRegisterCFTypes(void)\n" + "{\n" + ); for (entry = head; entry != NULL; entry = entry->next) { - if (strcmp(entry->name, "comment") == 0) - continue; - if (entry->ifdef) - fprintf(fp, "#if %s\n", entry->ifdef); - fprintf(fp, "\telse if (!strcmp(token, \"%s\"))\n", - entry->name - ); - assert(entry->loc); - if (strcmp(entry->loc, "none") == 0) { - fprintf(fp, - "\t\tparse_%s();\n", - entry->type - ); - } else { - fprintf(fp, - "\t\tparse_%s(&%s%s);\n", - entry->type, entry->loc, - entry->array_flag ? "[0]" : "" - ); - } - if (entry->ifdef) - fprintf(fp, "#endif\n"); + assert(entry->loc); + if (strcmp(entry->name, "comment") == 0) + continue; + if (entry->ifdef) + fprintf(fp, "#if %s\n", entry->ifdef); + fprintf(fp, "\tparserRegisterType(\"%s\",parse_%s,free_%s,dump_%s);\n", + entry->type, + entry->type, + entry->type, + entry->type); + if (entry->ifdef) + fprintf(fp, "#endif\n"); } - - fprintf(fp, - "\telse\n" - "\t\tresult = 0; /* failure */\n" - "\treturn(result);\n" - "}\n\n" - ); + fprintf(fp, "}\n\n"); } -static void -gen_dump(Entry * head, FILE * fp) +static int +gen_registernames(Entry * head, FILE * fp) { Entry *entry; + int rc=0; fprintf(fp, - "static void\n" - "dump_config(StoreEntry *entry)\n" - "{\n" - ); + "#define default_if_none_NULL NULL\nstatic void\n" + "parserRegisterCFNames(void)\n" + "{\n" + "\tcfg_filename=\"Default Configuration\";" + "\tconfig_lineno = 0;" + ); for (entry = head; entry != NULL; entry = entry->next) { - assert(entry->loc); - if (strcmp(entry->loc, "none") == 0) - continue; + assert(entry->loc); if (strcmp(entry->name, "comment") == 0) continue; - if (entry->ifdef) - fprintf(fp, "#if %s\n", entry->ifdef); - fprintf(fp, "\tdump_%s(entry, \"%s\", %s);\n", - entry->type, - entry->name, - entry->loc); - if (entry->ifdef) - fprintf(fp, "#endif\n"); + if (strcmp(entry->loc, "none") == 0) { + printf("location \"none\" not valid for name %s\n", entry->name); + exit(1); + } + if (entry->ifdef) + fprintf(fp, "#if %s\n", entry->ifdef); + fprintf(fp, "\tparserRegisterName(NULL, \"%s\",parserTypeByName(\"%s\"),&%s%s,default_if_none_%s,name_document_%s, NULL);\n", + entry->name, + entry->type, + entry->loc, + entry->array_flag ? "[0]" : "", + entry->default_if_none ? entry->name : "NULL", + entry->name); + if (entry->default_value == NULL) { + fprintf(stderr, "NO DEFAULT FOR %s\n", entry->name); + rc |= 1; + } + if (strcmp(entry->default_value, "none") == 0) { + fprintf(fp, "\t/* No default for %s */\n", entry->name); + } else { + fprintf(fp, "\tdefault_line(\"%s %s\");\n", + entry->name, + entry->default_value); + } + if (entry->ifdef) + fprintf(fp, "#endif\n"); } fprintf(fp, "}\n\n"); + return rc; } + + + static void -gen_free(Entry * head, FILE * fp) +gen_document(Entry * head, FILE * fp) { Entry *entry; - fprintf(fp, - "static void\n" - "free_all(void)\n" - "{\n" - ); + Line *line; + Line *def = NULL; + Line *comm = NULL; + char buf[8192]; for (entry = head; entry != NULL; entry = entry->next) { - assert(entry->loc); - if (strcmp(entry->loc, "none") == 0) - continue; - if (strcmp(entry->name, "comment") == 0) + int blank = 1; + assert(entry->name); + assert(entry->loc); + if (entry->ifdef) + fprintf(fp, "#if %s\n", entry->ifdef); + if (!strcmp(entry->name, "comment")) + { + lineAdd(&comm, ""); + for (line = entry->doc; line != NULL; line = line->next) { + sprintf(buf, "#%s", line->data); + lineAdd(&comm, buf); + } + lineAdd(&comm,""); continue; - if (entry->ifdef) - fprintf(fp, "#if %s\n", entry->ifdef); - fprintf(fp, "\tfree_%s(&%s%s);\n", - entry->type, entry->loc, - entry->array_flag ? "[0]" : ""); - if (entry->ifdef) - fprintf(fp, "#endif\n"); + } + fprintf(fp, + "static void\n" + "name_document_%s(void)" + "{\n" + "\tprintf(\n", + entry->name); + + if (comm) { + while (comm != NULL) { + line = comm; + comm = line->next; + fprintf(fp, "\"%s\\n\"\n", printf_quote(line->data)); + xfree(line->data); + xfree(line); + } + blank = 1; + } + fprintf(fp, "\"# TAG: %s\"\n", + entry->name); + if (entry->comment) + fprintf(fp, "\"\t%s\"\n", printf_quote(entry->comment)); + fprintf(fp, "\"\\n\"\n"); + + for (line = entry->doc; line != NULL; line = line->next) { + fprintf(fp, "\"#%s\\n\"\n", printf_quote(line->data)); + } + if (entry->default_value && strcmp(entry->default_value, "none") != 0) { + sprintf(buf, "%s %s", entry->name, entry->default_value); + lineAdd(&def, buf); + } + if (entry->default_if_none) { + for (line = entry->default_if_none; line; line = line->next) { + sprintf(buf, "%s %s", entry->name, line->data); + lineAdd(&def, buf); + } + } + if (entry->nocomment) + blank = 0; + if (!def && entry->doc && !entry->nocomment && + strcmp(entry->name, "comment") != 0) + lineAdd(&def, "none"); + if (def && (entry->doc || entry->nocomment)) { + if (blank) + fprintf(fp, "\"#\\n\"\n"); + fprintf(fp, "\"#Default:\\n\"\n"); + while (def != NULL) { + line = def; + def = line->next; + fprintf(fp, "\"# %s\\n\"\n", printf_quote(line->data)); + xfree(line->data); + xfree(line); + } + blank = 1; + } + if (entry->nocomment && blank) + fprintf(fp, "\"#\\n\"\n"); + for (line = entry->nocomment; line != NULL; line = line->next) { + fprintf(fp, "\"%s\\n\"\n", printf_quote(line->data)); + } + if (entry->doc != NULL) { + fprintf(fp, "\"\\n\"\n"); + } + fprintf(fp, "\t);}\n%s", entry->ifdef ? "" : "\n"); + + if (entry->ifdef) + fprintf(fp, "#endif\n%s", entry->ifdef ? "\n" : ""); } - fprintf(fp, "}\n\n"); } static int Index: squid/src/client_side.c diff -u squid/src/client_side.c:1.28 squid/src/client_side.c:1.18.4.7 --- squid/src/client_side.c:1.28 Fri May 4 06:39:12 2001 +++ squid/src/client_side.c Sat May 12 08:22:30 2001 @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "acl.h" #if IPF_TRANSPARENT #if HAVE_SYS_IOCTL_H @@ -247,7 +248,10 @@ http->log_type = LOG_TCP_DENIED; http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); - if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) { + if (!strncmp(AclMatchedAcl->aclname->namestr, "proxy_auth", 10)) { +/* The test above was + * if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) { + */ if (!http->flags.accel) { /* Proxy authorisation needed */ status = HTTP_PROXY_AUTHENTICATION_REQUIRED; Index: squid/src/dlink.h diff -u /dev/null squid/src/dlink.h:1.1.2.1 --- /dev/null Tue Sep 28 18:35:58 2004 +++ squid/src/dlink.h Mon Apr 23 15:28:33 2001 @@ -0,0 +1,51 @@ + +/* + * $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 _DLINK_H_ +#define _DLINK_H_ + +typedef struct _dlink_node dlink_node; +typedef struct _dlink_list dlink_list; + +struct _dlink_node { + void *data; + dlink_node *prev; + dlink_node *next; +}; + +struct _dlink_list { + dlink_node *head; + dlink_node *tail; +}; + +#endif /* DLINK_H */ Index: squid/src/enums.h diff -u squid/src/enums.h:1.21 squid/src/enums.h:1.14.4.11 --- squid/src/enums.h:1.21 Fri Apr 20 14:35:33 2001 +++ squid/src/enums.h Sun May 13 02:49:51 2001 @@ -93,51 +93,9 @@ } err_type; typedef enum { - ACL_NONE, - ACL_SRC_IP, - ACL_DST_IP, - ACL_MY_IP, - ACL_SRC_DOMAIN, - ACL_DST_DOMAIN, - ACL_SRC_DOM_REGEX, - ACL_DST_DOM_REGEX, - ACL_TIME, - ACL_URLPATH_REGEX, - ACL_URL_REGEX, - ACL_URL_PORT, - ACL_MY_PORT, -#if USE_IDENT - ACL_IDENT, - ACL_IDENT_REGEX, -#endif - ACL_PROTO, - ACL_METHOD, - ACL_BROWSER, - ACL_PROXY_AUTH, - ACL_PROXY_AUTH_REGEX, - ACL_SRC_ASN, - ACL_DST_ASN, -#if USE_ARP_ACL - ACL_SRC_ARP, -#endif -#if SQUID_SNMP - ACL_SNMP_COMMUNITY, -#endif -#if SRC_RTT_NOT_YET_FINISHED - ACL_NETDB_SRC_RTT, -#endif - ACL_MAXCONN, - ACL_REQ_MIME_TYPE, - ACL_REP_MIME_TYPE, - ACL_ENUM_MAX -} squid_acl; - -typedef enum { ACL_LOOKUP_NONE, - ACL_LOOKUP_NEEDED, ACL_LOOKUP_PENDING, ACL_LOOKUP_DONE, - ACL_PROXY_AUTH_NEEDED, } acl_lookup_state; enum { @@ -155,6 +113,12 @@ }; typedef enum { + MOD_NONE, + MOD_INTERNAL, + MOD_EXTERNAL +} mod_t; + +typedef enum { PEER_NONE, PEER_SIBLING, PEER_PARENT, @@ -554,16 +518,16 @@ MEM_16K_BUF, MEM_32K_BUF, MEM_64K_BUF, - MEM_ACL, - MEM_ACL_DENY_INFO_LIST, - MEM_ACL_IP_DATA, +// MEM_ACL, +// MEM_ACL_DENY_INFO_LIST, +// MEM_ACL_IP_DATA, MEM_ACL_LIST, - MEM_ACL_NAME_LIST, +// MEM_ACL_NAME_LIST, MEM_AUTH_USER_T, MEM_AUTH_USER_HASH, - MEM_ACL_PROXY_AUTH_MATCH, - MEM_ACL_USER_DATA, - MEM_ACL_TIME_DATA, +// MEM_ACL_PROXY_AUTH_MATCH, +// MEM_ACL_USER_DATA, +// MEM_ACL_TIME_DATA, #if USE_CACHE_DIGESTS MEM_CACHE_DIGEST, #endif Index: squid/src/globals.h diff -u squid/src/globals.h:1.10 squid/src/globals.h:1.7.8.3 --- squid/src/globals.h:1.10 Sat May 5 13:47:38 2001 +++ squid/src/globals.h Sat May 12 06:06:03 2001 @@ -153,6 +153,8 @@ extern ssize_t store_maxobjsize; /* -1 */ extern RemovalPolicy *mem_policy; extern hash_table *proxy_auth_username_cache; /* NULL */ +extern dlink_list parserTypes; +extern dlink_list parserNames; extern int incoming_sockets_accepted; #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) extern unsigned int WIN32_OS_version; /* 0 */ Index: squid/src/internal_modules.sh diff -u /dev/null squid/src/internal_modules.sh:1.1.2.2 --- /dev/null Tue Sep 28 18:35:58 2004 +++ squid/src/internal_modules.sh Fri Feb 23 19:04:01 2001 @@ -0,0 +1,28 @@ +#!/bin/sh +echo "/* automatically generated by $0 $*" +echo " * do not edit" +echo " */" +echo "#include \"squid.h\"" +echo "" +for module in "$@"; do + echo "extern MOD_INSTALL mod_install_${module};" + echo "extern MOD_UNINSTALL mod_uninstall_${module};" +done +echo "int mod_internal_install(const char *namestr, modNode *module)" +echo "{" +echo " if (strcasecmp(namestr,\"all\")==0) {" +echo " /* register all internal modules */" +for module in "$@"; do + echo " default_line(\"mod_register internal $module\");" +done +echo " return -1;" +echo " } else" +for module in "$@"; do + echo " if (strcasecmp(namestr,\"$module\")==0) {" + echo " mod_register(\"$module\", mod_install_${module}, mod_uninstall_${module}, module);" + echo " return -1;" + echo " } else" +done +echo " debug(3,0)(\"mod_internal_install: unrecognised module '%s'.\n\",namestr);" +echo " return 0;" +echo "}" Index: squid/src/main.c diff -u squid/src/main.c:1.23 squid/src/main.c:1.19.4.8 --- squid/src/main.c:1.23 Sat May 5 13:47:38 2001 +++ squid/src/main.c Sat May 12 06:06:03 2001 @@ -38,6 +38,7 @@ /* for error reporting from xmalloc and friends */ extern void (*failure_notify) (const char *); +static int opt_do_document = 0; static int opt_send_signal = -1; static int opt_no_daemon = 0; static int opt_parse_cfg_only = 0; @@ -83,8 +84,13 @@ usage(void) { fprintf(stderr, - "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n" + "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [[-k signal]|[-c directive]]\n" " -a port Specify HTTP port number (default: %d).\n" + " -c directive\n" + " Write the configuration help for that directive to std out\n" + " Special directives:\n" + " all Write all directives\n" + " internalonly Do not parse config-file for modules\n" " -d level Write debugging to stderr also.\n" " -f file Use given config-file instead of\n" " %s\n" @@ -115,8 +121,12 @@ extern char *optarg; int c; - while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) { + while ((c = getopt(argc, argv, "CDFNRSVYXa:c:d:f:hk:m::su:vz?")) != -1) { switch (c) { + case 'c': + opt_do_document = 1; + parserAddDocumentOption(optarg); + break; case 'C': opt_catch_signals = 0; break; @@ -346,7 +356,7 @@ authenticateShutdown(); storeDirCloseSwapLogs(); errorClean(); - parseConfigFile(ConfigFile); + parserReconfigure(ConfigFile); _db_init(Config.Log.log, Config.debugOptions); ipcache_restart(); /* clear stuck entries */ authenticateUserCacheRestart(); /* clear stuck ACL entries */ @@ -359,7 +369,7 @@ idnsInit(); #endif redirectInit(); - authenticateInit(&Config.authConfig); + authenticateInit(&Config.authSchemes); #if USE_WCCP wccpInit(); #endif @@ -400,7 +410,7 @@ dnsInit(); #endif redirectInit(); - authenticateInit(&Config.authConfig); + authenticateInit(&Config.authSchemes); } static void @@ -480,7 +490,7 @@ idnsInit(); #endif redirectInit(); - authenticateInit(&Config.authConfig); + authenticateInit(&Config.authSchemes); useragentOpenLog(); refererOpenLog(); httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */ @@ -630,13 +640,15 @@ memInit(); cbdataInit(); eventInit(); /* eventInit() is required for config parsing */ - storeFsInit(); /* required for config parsing */ - authenticateSchemeInit(); /* required for config parsign */ - parse_err = parseConfigFile(ConfigFile); + if (!opt_do_document) + parse_err = parserReconfigure(ConfigFile); + else + parse_err = parserDoDocument(ConfigFile); - if (opt_parse_cfg_only) + if (opt_parse_cfg_only || opt_do_document) return parse_err; } + if (-1 == opt_send_signal) if (checkRunningPid()) exit(1); Index: squid/src/mem.c diff -u squid/src/mem.c:1.12 squid/src/mem.c:1.8.8.4 --- squid/src/mem.c:1.12 Fri Apr 20 14:35:33 2001 +++ squid/src/mem.c Fri Apr 27 07:24:57 2001 @@ -193,21 +193,21 @@ memDataInit(MEM_32K_BUF, "32K Buffer", 32768, 10); memDataInit(MEM_64K_BUF, "64K Buffer", 65536, 10); memDataInit(MEM_CLIENT_SOCK_BUF, "Client Socket Buffer", CLIENT_SOCK_SZ, 0); - memDataInit(MEM_ACL, "acl", sizeof(acl), 0); - memDataInit(MEM_ACL_DENY_INFO_LIST, "acl_deny_info_list", - sizeof(acl_deny_info_list), 0); - memDataInit(MEM_ACL_IP_DATA, "acl_ip_data", sizeof(acl_ip_data), 0); +// memDataInit(MEM_ACL, "acl", sizeof(acl), 0); +// memDataInit(MEM_ACL_DENY_INFO_LIST, "acl_deny_info_list", +// sizeof(acl_deny_info_list), 0); +// memDataInit(MEM_ACL_IP_DATA, "acl_ip_data", sizeof(acl_ip_data), 0); memDataInit(MEM_ACL_LIST, "acl_list", sizeof(acl_list), 0); - memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0); - memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0); +// memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0); +// memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0); memDataInit(MEM_AUTH_USER_T, "auth_user_t", sizeof(auth_user_t), 0); memDataInit(MEM_AUTH_USER_HASH, "auth_user_hash_pointer", sizeof(auth_user_hash_pointer), 0); - memDataInit(MEM_ACL_PROXY_AUTH_MATCH, "acl_proxy_auth_match_cache", - sizeof(acl_proxy_auth_match_cache), 0); - memDataInit(MEM_ACL_USER_DATA, "acl_user_data", - sizeof(acl_user_data), 0); +// memDataInit(MEM_ACL_PROXY_AUTH_MATCH, "acl_proxy_auth_match_cache", +// sizeof(acl_proxy_auth_match_cache), 0); +// memDataInit(MEM_ACL_USER_DATA, "acl_user_data", +// sizeof(acl_user_data), 0); #if USE_CACHE_DIGESTS memDataInit(MEM_CACHE_DIGEST, "CacheDigest", sizeof(CacheDigest), 0); #endif Index: squid/src/modules.c diff -u /dev/null squid/src/modules.c:1.1.6.1 --- /dev/null Tue Sep 28 18:35:58 2004 +++ squid/src/modules.c Wed Feb 14 05:51:42 2001 @@ -0,0 +1,54 @@ + +/* + * $Id$ + * + * DEBUG: section 84 Modules Interface + * AUTHOR: Robert Collins + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * the Regents of the University of California. Please see the + * COPYRIGHT file for full details. Squid incorporates software + * developed and/or copyrighted by other sources. Please 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. + * + */ + + +/* TEMPORARY HOME FOR DOCUMENTATION: + * + * the uninstall function returns true for 'I uninstalled succesfully' and + * not true for 'I didn't uninstall'. Some modules may not uninstall ever, + * and some may only uninstall if there are no references - it's + * up to the module. + */ + +#include "squid.h" + +void +mod_register(const char *namestr, MOD_INSTALL *install, MOD_UNINSTALL *uninstall, modNode *module) { + debug(84,1)("mod_register: registering %s\n"); + module->install=install; + module->uninstall=uninstall; + /* this may be skippable here ... */ + install(namestr); +} Index: squid/src/protos.h diff -u squid/src/protos.h:1.27 squid/src/protos.h:1.18.4.27 --- squid/src/protos.h:1.27 Tue May 8 08:27:00 2001 +++ squid/src/protos.h Sun May 13 02:49:51 2001 @@ -47,56 +47,39 @@ char *log_quote(const char *header); /* acl.c */ +extern void aclParserRegister(void); extern aclCheck_t *aclChecklistCreate(const struct _acl_access *, request_t *, const char *ident); extern void aclNBCheck(aclCheck_t *, PF *, void *); extern int aclCheckFast(const struct _acl_access *A, aclCheck_t *); extern void aclChecklistFree(aclCheck_t *); -extern int aclMatchAclList(const acl_list * list, aclCheck_t * checklist); extern void aclDestroyAccessList(struct _acl_access **list); extern void aclDestroyAcls(acl **); extern void aclParseAccessLine(struct _acl_access **); -extern void aclParseAclLine(acl **); +extern PARSER_PARSE aclParseAclLine; +#if 0 extern int aclIsProxyAuth(const char *name); +#endif extern err_type aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name); extern void aclParseDenyInfoLine(struct _acl_deny_info_list **); -extern void aclDestroyDenyInfoList(struct _acl_deny_info_list **); -extern void aclDestroyRegexList(struct _relist *data); +#if 0 +extern PARSER_FREE aclDestroyRegexList; extern int aclMatchRegex(relist * data, const char *word); -extern void aclParseRegexList(void *curlist); -extern const char *aclTypeToStr(squid_acl); -extern wordlist *aclDumpGeneric(const acl *); +extern PARSER_PARSE aclParseRegexList; +#endif extern int aclPurgeMethodInUse(acl_access *); extern void aclCacheMatchFlush(dlink_list * cache); +extern void aclRegisterAclDirective(void); /* * cache_cf.c + * FIXME: these should be registered by the appropriate "area" of squid, not in + * cache_cf.c */ -extern int parseConfigFile(const char *file_name); -extern void intlistDestroy(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 parse_int(int *var); -extern void parse_eol(char *volatile *var); -extern void parse_wordlist(wordlist ** list); -extern void requirePathnameExists(const char *name, const char *path); -extern void parse_time_t(time_t * var); extern void parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring); extern void dump_cachedir_options(StoreEntry * e, struct cache_dir_option *options, SwapDir * sd); - /* * cbdata.c */ @@ -723,16 +706,12 @@ extern void redirectInit(void); extern void redirectShutdown(void); -/* auth_modules.c */ -extern void authSchemeSetup(void); - /* authenticate.c */ extern void authenticateAuthUserMerge(auth_user_t *, auth_user_t *); extern auth_user_t *authenticateAuthUserNew(const char *); extern int authenticateAuthSchemeId(const char *typestr); extern void authenticateStart(auth_user_request_t *, RH *, void *); -extern void authenticateSchemeInit(void); -extern void authenticateInit(authConfig *); +extern void authenticateInit(authSchemes *); extern void authenticateShutdown(void); extern void authenticateFixHeader(HttpReply *, auth_user_request_t *, request_t *, int); extern void authenticateAddTrailer(HttpReply *, auth_user_request_t *, request_t *, int); @@ -760,7 +739,7 @@ extern char *authenticateUserRequestUsername(auth_user_request_t *); extern int authenticateValidateUser(auth_user_request_t *); extern void authenticateOnCloseConnection(ConnStateData * conn); -extern void authSchemeAdd(char *type, AUTHSSETUP * setup); +extern void authSchemeAdd(const char *type, AUTHSSETUP * setup); extern void refreshAddToList(const char *, int, time_t, int, time_t); extern int refreshIsCachable(const StoreEntry *); @@ -920,16 +899,9 @@ extern void storeEntryReset(StoreEntry *); extern void storeHeapPositionUpdate(StoreEntry *, SwapDir *); extern void storeSwapFileNumberSet(StoreEntry * e, sfileno filn); -extern void storeFsInit(void); extern void storeFsDone(void); -extern void storeFsAdd(char *, STSETUP *); -extern void storeReplAdd(char *, REMOVALPOLICYCREATE *); - -/* store_modules.c */ -extern void storeFsSetup(void); - -/* repl_modules.c */ -extern void storeReplSetup(void); +extern void storeFsAdd(const char *, STSETUP *); +extern void storeReplAdd(const char *, REMOVALPOLICYCREATE *); /* store_io.c */ extern storeIOState *storeCreate(StoreEntry *, STFNCB *, STIOCB *, void *); @@ -1302,6 +1274,11 @@ */ extern StatCounters *snmpStatGet(int); +/* internal_modules.sh */ +extern int mod_internal_install(const char *, modNode *); +/* modules.c */ +extern void mod_register(const char * namestr, MOD_INSTALL *, MOD_UNINSTALL *, modNode *); + /* Vary support functions */ int varyEvaluateMatch(StoreEntry * entry, request_t * req); Index: squid/src/repl_modules.sh diff -u squid/src/repl_modules.sh:1.2 squid/src/repl_modules.sh:removed --- squid/src/repl_modules.sh:1.2 Sat Oct 21 08:16:13 2000 +++ squid/src/repl_modules.sh Tue Sep 28 18:35:58 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 REMOVALPOLICYCREATE createRemovalPolicy_${module};" -done -echo "void storeReplSetup(void)" -echo "{" -for module in "$@"; do - echo " storeReplAdd(\"$module\", createRemovalPolicy_${module});" -done -echo "}" Index: squid/src/store.c diff -u squid/src/store.c:1.12 squid/src/store.c:1.9.8.4 --- squid/src/store.c:1.12 Fri Apr 13 17:31:02 2001 +++ squid/src/store.c Fri Apr 27 07:24:57 2001 @@ -1286,21 +1286,6 @@ } /* - * storeFsInit - * - * This routine calls the SETUP routine for each fs type. - * I don't know where the best place for this is, and I'm not going to shuffle - * around large chunks of code right now (that can be done once its working.) - */ -void -storeFsInit(void) -{ - storeReplSetup(); - storeFsSetup(); -} - - -/* * similar to above, but is called when a graceful shutdown is to occur * of each fs module. */ @@ -1319,7 +1304,7 @@ * called to add another store fs module */ void -storeFsAdd(char *type, STSETUP * setup) +storeFsAdd(const char *type, STSETUP * setup) { int i; /* find the number of currently known storefs types */ @@ -1338,7 +1323,7 @@ * called to add another store removal policy module */ void -storeReplAdd(char *type, REMOVALPOLICYCREATE * create) +storeReplAdd(const char *type, REMOVALPOLICYCREATE * create) { int i; /* find the number of currently known repl types */ Index: squid/src/store_modules.sh diff -u squid/src/store_modules.sh:1.2 squid/src/store_modules.sh:removed --- squid/src/store_modules.sh:1.2 Sat Oct 21 08:16:13 2000 +++ squid/src/store_modules.sh Tue Sep 28 18:35:58 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 STSETUP storeFsSetup_${module};" -done -echo "void storeFsSetup(void)" -echo "{" -for module in "$@"; do - echo " storeFsAdd(\"$module\", storeFsSetup_${module});" -done -echo "}" Index: squid/src/structs.h diff -u squid/src/structs.h:1.33 squid/src/structs.h:1.24.4.24 --- squid/src/structs.h:1.33 Tue May 8 08:27:00 2001 +++ squid/src/structs.h Sun May 13 02:49:51 2001 @@ -33,51 +33,8 @@ #include "config.h" #include "splay.h" - -struct _dlink_node { - void *data; - dlink_node *prev; - dlink_node *next; -}; - -struct _dlink_list { - dlink_node *head; - dlink_node *tail; -}; - -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 _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; -}; +/* FIXME: remove this - no global structures should refer to the parser library */ +#include "squid_parser.h" struct _auth_user_hash_pointer { /* first two items must be same as hash_link */ @@ -133,22 +90,19 @@ */ struct _authscheme_entry { - char *typestr; + const char *typestr; AUTHSACTIVE *Active; AUTHSADDHEADER *AddHeader; AUTHSADDTRAILER *AddTrailer; AUTHSAUTHED *authenticated; AUTHSAUTHUSER *authAuthenticate; AUTHSCONFIGURED *configured; - AUTHSDUMP *dump; AUTHSFIXERR *authFixHeader; AUTHSFREE *FreeUser; - AUTHSFREECONFIG *freeconfig; AUTHSUSERNAME *authUserUsername; AUTHSONCLOSEC *oncloseconnection; /*optional */ AUTHSDECODE *decodeauth; AUTHSDIRECTION *getdirection; - AUTHSPARSE *parse; AUTHSINIT *init; AUTHSREQFREE *requestFree; AUTHSSHUTDOWN *donefunc; @@ -163,11 +117,9 @@ /* private data types */ struct _authScheme { /* pointer to the authscheme_list's string entry */ - char *typestr; + const char *typestr; /* the scheme id in the authscheme_list */ int Id; - /* the scheme's configuration details. */ - void *scheme_data; }; struct _acl_deny_info_list { @@ -177,14 +129,6 @@ acl_deny_info_list *next; }; -#if USE_ARP_ACL - -struct _acl_arp_data { - char eth[6]; -}; - -#endif - struct _String { /* never reference these directly! */ unsigned short int size; /* buffer size; 64K limit */ @@ -219,14 +163,6 @@ #endif -struct _acl { - char name[ACL_NAME_SZ]; - squid_acl type; - void *data; - char *cfgline; - acl *next; -}; - struct _acl_list { int op; acl *acl; @@ -252,7 +188,8 @@ ConnStateData *conn; /* hack for ident and NTLM */ char rfc931[USER_IDENT_SZ]; auth_user_request_t *auth_user_request; - acl_lookup_state state[ACL_ENUM_MAX]; + acl_lookup_state lastcheckstate; + acl * lastcheckowner; #if SQUID_SNMP char *snmp_community; #endif @@ -292,6 +229,18 @@ sockaddr_in_list *next; }; +struct _modNode { + dlink_node node; + char *namestr; + mod_t type; + MOD_INSTALL *install; + MOD_UNINSTALL *uninstall; +}; + +struct _modConfig { + dlink_list modules; +}; + #if USE_SSL struct _https_port_list { https_port_list *next; @@ -333,6 +282,8 @@ }; struct _SquidConfig { + modConfig modules; + includefile_t *files; struct { size_t maxSize; int highWaterMark; @@ -552,7 +503,10 @@ int vary_ignore_expire; int pipeline_prefetch; } onoff; +#if 0 acl *aclList; + dlink_list aclList2; +#endif struct { acl_access *http; acl_access *icp; @@ -572,11 +526,11 @@ acl_access *reply; } accessList; acl_deny_info_list *denyInfoList; - struct _authConfig { + struct _authSchemes { authScheme *schemes; int n_allocated; - int n_configured; - } authConfig; + int n_configured; + } authSchemes; struct { size_t list_width; int list_wrap; @@ -1479,7 +1433,7 @@ }; struct _SwapDir { - char *type; + const char *type; int cur_size; int low_size; int max_size; @@ -2063,7 +2017,7 @@ */ struct _storefs_entry { - char *typestr; + const char *typestr; STFSPARSE *parsefunc; STFSRECONFIGURE *reconfigurefunc; STFSSHUTDOWN *donefunc; @@ -2074,7 +2028,7 @@ */ struct _storerepl_entry { - char *typestr; + const char *typestr; REMOVALPOLICYCREATE *create; }; Index: squid/src/typedefs.h diff -u squid/src/typedefs.h:1.21 squid/src/typedefs.h:1.15.4.17 --- squid/src/typedefs.h:1.21 Tue May 8 08:27:00 2001 +++ squid/src/typedefs.h Sat May 12 06:06:03 2001 @@ -34,6 +34,9 @@ #ifndef _TYPEDEFS_H_ #define _TYPEDEFS_H_ +/* FIXME: this shouldn't be a global include */ +#include "dlink.h" + typedef unsigned int store_status_t; typedef unsigned int mem_status_t; typedef unsigned int ping_status_t; @@ -149,12 +152,10 @@ typedef struct _refresh_t refresh_t; typedef struct _CommWriteStateData CommWriteStateData; typedef struct _ErrorState ErrorState; -typedef struct _dlink_node dlink_node; -typedef struct _dlink_list dlink_list; typedef struct _StatCounters StatCounters; typedef struct _tlv tlv; typedef struct _storeSwapLogData storeSwapLogData; -typedef struct _authConfig authConfig; +typedef struct _authSchemes authSchemes; typedef struct _cacheSwap cacheSwap; typedef struct _StatHist StatHist; typedef struct _String String; @@ -190,6 +191,15 @@ typedef struct _http_version_t http_version_t; +/* modules.c */ +typedef struct _modConfig modConfig; +typedef struct _modNode modNode; + +/* name to register under */ +typedef void MOD_INSTALL(const char *); +typedef unsigned int MOD_UNINSTALL(const char *); +/* end modules.c */ + #if SQUID_SNMP typedef variable_list *(oid_ParseFn) (variable_list *, snint *); typedef struct _snmp_request_t snmp_request_t; @@ -297,16 +307,13 @@ typedef int AUTHSCONFIGURED(void); typedef void AUTHSDECODE(auth_user_request_t *, const char *); typedef int AUTHSDIRECTION(auth_user_request_t *); -typedef void AUTHSDUMP(StoreEntry *, const char *, authScheme *); typedef void AUTHSFIXERR(auth_user_request_t *, HttpReply *, http_hdr_type, request_t *); typedef void AUTHSADDHEADER(auth_user_request_t *, HttpReply *, int); typedef void AUTHSADDTRAILER(auth_user_request_t *, HttpReply *, int); typedef void AUTHSFREE(auth_user_t *); -typedef void AUTHSFREECONFIG(authScheme *); typedef char *AUTHSUSERNAME(auth_user_t *); typedef void AUTHSONCLOSEC(ConnStateData *); -typedef void AUTHSPARSE(authScheme *, int, char *); -typedef void AUTHSINIT(authScheme *); +typedef void AUTHSINIT(void); typedef void AUTHSREQFREE(auth_user_request_t *); typedef void AUTHSSETUP(authscheme_entry_t *); typedef void AUTHSSHUTDOWN(void); Index: squid/src/auth/basic/auth_basic.c diff -u squid/src/auth/basic/auth_basic.c:1.11 squid/src/auth/basic/auth_basic.c:1.9.4.8 --- squid/src/auth/basic/auth_basic.c:1.11 Wed Mar 21 15:43:33 2001 +++ squid/src/auth/basic/auth_basic.c Sat Mar 31 01:52:20 2001 @@ -56,47 +56,135 @@ static AUTHSCONFIGURED authBasicConfigured; static AUTHSDIRECTION authenticateBasicDirection; static AUTHSDECODE authenticateBasicDecodeAuth; -static AUTHSDUMP authBasicCfgDump; static AUTHSFIXERR authenticateBasicFixErrorHeader; static AUTHSFREE authenticateBasicFreeUser; -static AUTHSFREECONFIG authBasicFreeConfig; -static AUTHSPARSE authBasicParse; static AUTHSINIT authBasicInit; static AUTHSSTART authenticateBasicStart; static AUTHSSTATS authenticateBasicStats; static AUTHSUSERNAME authenticateBasicUsername; static AUTHSSHUTDOWN authBasicDone; +static PARSER_NAME_DOCUMENT authBasicDocumentProgram; +static PARSER_NAME_DOCUMENT authBasicDocumentChildren; +static PARSER_NAME_DOCUMENT authBasicDocumentRealm; +static PARSER_NAME_DOCUMENT authBasicDocumentTTL; + static helper *basicauthenticators = NULL; -static auth_basic_config *basicConfig = NULL; +static auth_basic_config basicConfig= {0,NULL,NULL,0}; static int authbasic_initialised = 0; MemPool *basic_data_pool = NULL; +/* config parsing */ -/* - * - * Public Functions - * - */ +static void +authBasicDocumentProgram(void) +{ + printf("# TAG: authenticate_basic_program cmdline\n" +"#\tSpecify the command for the external authenticator. Such a\n" +"#\tprogram reads a line containing \"username password\" and replies\n" +"#\t\"OK\" or \"ERR\" in an endless loop. If you use an authenticator,\n" +"#\tmake sure you have 1 acl of type proxy_auth. By default, the\n" +"#\tauthenticate_program is not used.\n" +"#\n" +"#\tIf you want to use the traditional proxy authentication,\n" +"#\tjump over to the src/auth/basic/helpers/NCSA directory and\n" +"#\ttype:\n" +"#\t %% make\n" +"#\t %% make install\n" +"#\n" +"#\tThen, set this line to something like\n" +"#\n" +"#\tauth_param basic program /usr/local/squid/bin/ncsa_auth /usr/local/squid/etc/passwd\n\n"); +} + +static void +authBasicDocumentChildren(void) +{ + printf("# TAG: authenticate_basic_children children\n" +"#\tThe number of authenticator processes to spawn (no default). If you\n" +"#\tstart too few Squid will have to wait for them to process a backlog\n" +"#\tof usercode/password verifications, slowing it down. When password\n" +"#\tverifications are done via a (slow) network you are likely to need\n" +"#\tlots of authenticator processes.\n" +"#Default:\n" +"# authenticate_basic_children 5\n\n"); +} -AUTHSSETUP authSchemeSetup_basic; +static void +authBasicDocumentRealm(void) +{ + printf("# TAG: authenticate_basic_realm realm\n" +"#\tSpecifies the realm name which is to be reported to the client for\n" +"#\tthe basic proxy authentication scheme (part of the text the user will\n" +"#\tsee when prompted their username and password).\n" +"#\tauth_param basic realm Squid proxy-caching web server\n" +"#Default:\n" +"# authenticate_basic_realm Squid proxy-caching web server\n\n"); +} + +static void +authBasicDocumentTTL(void) +{ + printf("# TAG: authenticate_basic_ttl ttl\n" +"#\tSpecifies how long squid assumes an externally validated username:password\n" +"#\tpair is valid for - in other words how often the helper program is called\n" +"#\tfor that user. Set this low to force revalidation with short lived passwords.\n" +"#\tNote that setting this high does not impact your susceptability to replay\n" +"#\tattacks unless you are using a one-time password system (such as SecureID).\n" +"#\tIf you are using such a system, you will be vulnerable to replay attacks\n" +"#\tunless you also enable the IP ttl is strict option.\n" +"#Default:\n" +"# authenticate_basic_ttl 2 hours\n\n"); +} + +static AUTHSSETUP authSchemeSetup_basic; +/* register as a module */ void +mod_install_basic (const char *namestr) +{ + authSchemeAdd(namestr, authSchemeSetup_basic); + parserRegisterName(NULL, "authenticate_basic_program", parserTypeByName("wordlist"), &basicConfig.authenticate, NULL, authBasicDocumentProgram, NULL); + parserRegisterName(NULL, "authenticate_basic_children", parserTypeByName("int"), &basicConfig.authenticateChildren, NULL, authBasicDocumentChildren, NULL); + default_line("authenticate_basic_children 5"); + parserRegisterName(NULL, "authenticate_basic_realm", parserTypeByName("eol"), &basicConfig.basicAuthRealm, NULL, authBasicDocumentRealm, NULL); + default_line("authenticate_basic_realm Squid proxy-caching web server"); + parserRegisterName(NULL, "authenticate_basic_ttl", parserTypeByName("time_t"), &basicConfig.credentialsTTL, NULL, authBasicDocumentTTL, NULL); + default_line("authenticate_basic_ttl 2 hours"); + + /* until we support mod_uninstall we need to keep the names active indefinately */ + cbdataLock(parserNameByName("authenticate_basic_program")); + cbdataLock(parserNameByName("authenticate_basic_children")); + cbdataLock(parserNameByName("authenticate_basic_realm")); + cbdataLock(parserNameByName("authenticate_basic_ttl")); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_basic(const char *namestr) { + /* deregistration should simply _queue_ the wish to deregister. + * Actual deregistration takes place when their are no more references + * to anything. + * this work will be undertaken in auth_rewrite when the configuration + * and modules work is merged via HEAD. + */ + return 0; +} + + +static void authSchemeSetup_basic(authscheme_entry_t * authscheme) { assert(!authbasic_initialised); authscheme->Active = authenticateBasicActive; - authscheme->parse = authBasicParse; - authscheme->dump = authBasicCfgDump; authscheme->init = authBasicInit; authscheme->authAuthenticate = authenticateBasicAuthenticateUser; authscheme->authenticated = authenticateBasicAuthenticated; authscheme->configured = authBasicConfigured; authscheme->authFixHeader = authenticateBasicFixErrorHeader; authscheme->FreeUser = authenticateBasicFreeUser; - authscheme->freeconfig = authBasicFreeConfig; authscheme->authStart = authenticateBasicStart; authscheme->authStats = authenticateBasicStats; authscheme->authUserUsername = authenticateBasicUsername; @@ -135,9 +223,10 @@ static int authBasicConfigured() { - if ((basicConfig != NULL) && (basicConfig->authenticate != NULL) && - (basicConfig->authenticateChildren != 0) && - (basicConfig->basicAuthRealm != NULL)) { + if ((basicConfig.authenticate != NULL) && + (basicConfig.authenticateChildren != 0) && + (basicConfig.basicAuthRealm != NULL)) { + requirePathnameExists("authenticate_basic_program", basicConfig.authenticate->key); debug(29, 9) ("authBasicConfigured: returning configured\n"); return 1; } @@ -149,7 +238,7 @@ authenticateBasicAuthenticated(auth_user_request_t * auth_user_request) { basic_data *basic_auth = auth_user_request->auth_user->scheme_data; - if ((auth_user_request->auth_user->flags.credentials_ok == 1) && (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL > squid_curtime)) + if ((auth_user_request->auth_user->flags.credentials_ok == 1) && (basic_auth->credentials_checkedtime + basicConfig.credentialsTTL > squid_curtime)) return 1; debug(29, 4) ("User not authenticated or credentials need rechecking.\n"); return 0; @@ -182,7 +271,7 @@ basic_auth = auth_user->scheme_data; /* are we about to recheck the credentials externally? */ - if ((basic_auth->credentials_checkedtime + basicConfig->credentialsTTL) <= squid_curtime) { + if ((basic_auth->credentials_checkedtime + basicConfig.credentialsTTL) <= squid_curtime) { debug(29, 4) ("authBasicAuthenticate: credentials expired - rechecking\n"); return; } @@ -207,7 +296,7 @@ case 0: /* not checked */ return -1; case 1: /* checked & ok */ - if (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL <= squid_curtime) + if (basic_auth->credentials_checkedtime + basicConfig.credentialsTTL <= squid_curtime) return -1; return 0; case 2: /* paused while waiting for a username:password check on another request */ @@ -221,27 +310,12 @@ void authenticateBasicFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request) { - if (basicConfig->authenticate) { - debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicConfig->basicAuthRealm); - httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicConfig->basicAuthRealm); + if (basicConfig.authenticate) { + debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicConfig.basicAuthRealm); + httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicConfig.basicAuthRealm); } } -/* free any allocated configuration details */ -void -authBasicFreeConfig(authScheme * scheme) -{ - if (basicConfig == NULL) - return; - assert(basicConfig == scheme->scheme_data); - if (basicConfig->authenticate) - wordlistDestroy(&basicConfig->authenticate); - if (basicConfig->basicAuthRealm) - safe_free(basicConfig->basicAuthRealm); - xfree(basicConfig); - basicConfig = NULL; -} - void authenticateBasicFreeUser(auth_user_t * auth_user) { @@ -297,52 +371,6 @@ } static void -authBasicCfgDump(StoreEntry * entry, const char *name, authScheme * scheme) -{ - auth_basic_config *config = scheme->scheme_data; - wordlist *list = config->authenticate; - storeAppendPrintf(entry, "%s %s", name, "basic"); - while (list != NULL) { - storeAppendPrintf(entry, " %s", list->key); - list = list->next; - } - storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s credentialsttl %d seconds\n", - name, "basic", config->basicAuthRealm, - name, "basic", config->authenticateChildren, - name, "basic", config->credentialsTTL); - -} - -static void -authBasicParse(authScheme * scheme, int n_configured, char *param_str) -{ - if (scheme->scheme_data == NULL) { - assert(basicConfig == NULL); - /* this is the first param to be found */ - scheme->scheme_data = xmalloc(sizeof(auth_basic_config)); - memset(scheme->scheme_data, 0, sizeof(auth_basic_config)); - basicConfig = scheme->scheme_data; - basicConfig->authenticateChildren = 5; - basicConfig->credentialsTTL = 2 * 60 * 60; /* two hours */ - } - basicConfig = scheme->scheme_data; - if (strcasecmp(param_str, "program") == 0) { - if (basicConfig->authenticate) - wordlistDestroy(&basicConfig->authenticate); - parse_wordlist(&basicConfig->authenticate); - requirePathnameExists("authparam basic program", basicConfig->authenticate->key); - } else if (strcasecmp(param_str, "children") == 0) { - parse_int(&basicConfig->authenticateChildren); - } else if (strcasecmp(param_str, "realm") == 0) { - parse_eol(&basicConfig->basicAuthRealm); - } else if (strcasecmp(param_str, "credentialsttl") == 0) { - parse_time_t(&basicConfig->credentialsTTL); - } else { - debug(28, 0) ("unrecognised basic auth scheme parameter '%s'\n", param_str); - } -} - -static void authenticateBasicStats(StoreEntry * sentry) { storeAppendPrintf(sentry, "Basic Authenticator Statistics:\n"); @@ -533,17 +561,17 @@ /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the * config file */ static void -authBasicInit(authScheme * scheme) +authBasicInit(void) { static int init = 0; - if (basicConfig->authenticate) { + if (basicConfig.authenticate) { if (!basic_data_pool) basic_data_pool = memPoolCreate("Basic Scheme User Data", sizeof(basic_data)); authbasic_initialised = 1; if (basicauthenticators == NULL) basicauthenticators = helperCreate("basicauthenticator"); - basicauthenticators->cmdline = basicConfig->authenticate; - basicauthenticators->n_to_start = basicConfig->authenticateChildren; + basicauthenticators->cmdline = basicConfig.authenticate; + basicauthenticators->n_to_start = basicConfig.authenticateChildren; basicauthenticators->ipc_type = IPC_TCP_SOCKET; helperOpenServers(basicauthenticators); if (!init) { @@ -570,7 +598,7 @@ basic_auth = auth_user_request->auth_user->scheme_data; debug(29, 9) ("authenticateStart: '%s:%s'\n", basic_auth->username, basic_auth->passwd); - if (basicConfig->authenticate == NULL) { + if (basicConfig.authenticate == NULL) { handler(data, NULL); return; } Index: squid/src/auth/digest/auth_digest.c diff -u squid/src/auth/digest/auth_digest.c:1.5 squid/src/auth/digest/auth_digest.c:1.4.4.6 --- squid/src/auth/digest/auth_digest.c:1.5 Sat Mar 3 02:44:33 2001 +++ squid/src/auth/digest/auth_digest.c Sat Mar 31 01:52:20 2001 @@ -48,6 +48,9 @@ cbdataFree(r); } +/* register with the authentication framework */ +static AUTHSSETUP authSchemeSetup_digest; + /* Digest Scheme */ static HLPCB authenticateDigestHandleReply; @@ -61,12 +64,9 @@ static AUTHSCONFIGURED authDigestConfigured; static AUTHSDIRECTION authenticateDigestDirection; static AUTHSDECODE authenticateDigestDecodeAuth; -static AUTHSDUMP authDigestCfgDump; static AUTHSFIXERR authenticateDigestFixHeader; static AUTHSFREE authenticateDigestUserFree; -static AUTHSFREECONFIG authDigestFreeConfig; static AUTHSINIT authDigestInit; -static AUTHSPARSE authDigestParse; static AUTHSREQFREE authDigestAURequestFree; static AUTHSSTART authenticateDigestStart; static AUTHSSTATS authenticateDigestStats; @@ -77,7 +77,7 @@ static hash_table *digest_nonce_cache; -static auth_digest_config *digestConfig = NULL; +static auth_digest_config digestConfig = { 0, NULL, NULL, 0, 0, 0}; static int authdigest_initialised = 0; MemPool *digest_user_pool = NULL; @@ -208,7 +208,7 @@ if (!digest_nonce_cache) { digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string); assert(digest_nonce_cache); - eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1); + eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig.nonceGCInterval, 1); } } @@ -268,7 +268,7 @@ } debug(29, 3) ("authenticateDigestNonceCacheCleanup: Finished cleaning the nonce cache.\n"); if (authenticateDigestActive()) - eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig->nonceGCInterval, 1); + eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig.nonceGCInterval, 1); } void @@ -354,8 +354,8 @@ if (!nonce) return -1; /* has it's max duration expired? */ - if (nonce->noncedata.creationtime + digestConfig->noncemaxduration < current_time.tv_sec) { - debug(29, 4) ("authDigestNonceIsStale: Nonce is too old. %d %d %d\n", nonce->noncedata.creationtime, digestConfig->noncemaxduration, current_time.tv_sec); + if (nonce->noncedata.creationtime + digestConfig.noncemaxduration < current_time.tv_sec) { + debug(29, 4) ("authDigestNonceIsStale: Nonce is too old. %d %d %d\n", nonce->noncedata.creationtime, digestConfig.noncemaxduration, current_time.tv_sec); nonce->flags.valid = 0; return -1; } @@ -364,7 +364,7 @@ nonce->flags.valid = 0; return -1; } - if (nonce->nc > digestConfig->noncemaxuses) { + if (nonce->nc > digestConfig.noncemaxuses) { debug(29, 4) ("authDigestNoncelastRequest: Nonce count over user limit\n"); nonce->flags.valid = 0; return -1; @@ -383,7 +383,7 @@ debug(29, 4) ("authDigestNoncelastRequest: Nonce count about to overflow\n"); return -1; } - if (nonce->nc == digestConfig->noncemaxuses - 1) { + if (nonce->nc == digestConfig.noncemaxuses - 1) { debug(29, 4) ("authDigestNoncelastRequest: Nonce count about to hit user limit\n"); return -1; } @@ -552,34 +552,116 @@ debug(29, 2) ("authenticateDigestDone: Digest authentication shut down.\n"); } +/* register as a module */ + +static void +authDigestDocumentProgram(void) +{ + printf("# TAG: authenticate_digest_program cmdline\n" +"#\tSpecify the command for the external authenticator. Such a\n" +"#\tprogram reads a line containing \"username\":\"realm\" and replies\n" +"#\twith the appropriate H(A1) value base64 encoded. See rfc 2616 for\n" +"#\tthe definition of H(A1). If you use an authenticator,\n" +"#\tmake sure you have 1 acl of type proxy_auth. By default,\n" +"#\tauthentication is not used.\n" +"#\n" +"#\tIf you want to use build a authenticator,\n" +"#\tjump over to the ../digest_auth_modules directory and choose the\n" +"#\tauthenticator to use. It it's directory type\n" +"#\t %% make\n" +"#\t %% make install\n" +"#\n" +"#\tThen, set this line to something like\n" +"#\n" +"#\tauthenticate_digest_program @DEFAULT_PREFIX@/bin/digest_auth_pw @DEFAULT_PREFIX@/etc/digpass\n\n"); +} + +static void +authBasicDocumentChildren(void) +{ + printf("# TAG: authenticate_digest_children numberofchildren\n" +"#\tThe number of authenticator processes to spawn (no default). If you\n" +"#\tstart too few Squid will have to wait for them to process a backlog\n" +"#\tof H(A1) calculations, slowing it down. When the H(A1) calculations\n" +"#\tare done via a (slow) network you are likely to need lots of\n" +"#\tauthenticator processes.\n" +"#Default:\n" +"# authenticate_digest_childrem 5\n\n"); +} + +static void +authBasicDocumentRealm(void) +{ + printf("# TAG: authenticate_digest_realm realmstring\n" +"#\tSpecifies the realm name which is to be reported to the client for\n" +"#\tthe digest proxy authentication scheme (part of the text the user will\n" +"#\tsee when prompted their username and password).\n" +"#\tauth_param digest realm Squid proxy-caching web server\n" +"#Default:\n" +"# authenticate_digest_realm Squid proxy-caching web server\n\n"); +} + +static void +authBasicDocumentGCInterval(void) +{ + printf("# TAG: authenticate_digest_nonce_garbage_interval interval\n" +"#\tSpecifies the interval that nonces that have been issued to client_agent's\n" +"#\tare checked for validity.\n" +"#Default:\n" +"# authenticate_digest_nonce_garbage_interval 5 minutes\n\n"); +} + +static void +authBasicDocumentNonceDuration(void) +{ + printf("# TAG: authenticate_digest_nonce_max_duration duration\n" +"#\tSpecifies the maximum length of time a given nonce will be valid for.\n" +"#Default:\n" +"# authenticate_digest_nonce_max_duration 30 minutes\n\n"); +} + static void -authDigestCfgDump(StoreEntry * entry, const char *name, authScheme * scheme) +authBasicDocumentNonceCount(void) { - auth_digest_config *config = scheme->scheme_data; - wordlist *list = config->authenticate; - debug(29, 9) ("authDigestCfgDump: Dumping configuration\n"); - storeAppendPrintf(entry, "%s %s", name, "digest"); - while (list != NULL) { - storeAppendPrintf(entry, " %s", list->key); - list = list->next; - } - storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s nonce_max_count %d\n%s %s nonce_max_duration %d seconds\n%s %s nonce_garbage_interval %d seconds\n", - name, "digest", config->digestAuthRealm, - name, "digest", config->authenticateChildren, - name, "digest", config->noncemaxuses, - name, "digest", config->noncemaxduration, - name, "digest", config->nonceGCInterval); + printf("# TAG: authenticate_digest_nonce_max_count count\n" +"#\tSpecifies the maximum number of times a given nonce can be used.\n" +"#Default:\n" +"# authenticate_digest_nonce_max_count 50\n\n"); } void +mod_install_digest (const char *namestr) +{ + authSchemeAdd(namestr, authSchemeSetup_digest); + parserRegisterName(NULL, "authenticate_digest_program", parserTypeByName("wordlist"), &digestConfig.authenticate, NULL, authDigestDocumentProgram, NULL); + parserRegisterName(NULL, "authenticate_digest_children", parserTypeByName("int"), &digestConfig.authenticateChildren, NULL, authBasicDocumentChildren, NULL); + parserRegisterName(NULL, "authenticate_digest_realm", parserTypeByName("eol"), &digestConfig.digestAuthRealm, NULL, authBasicDocumentRealm, NULL); + parserRegisterName(NULL, "authenticate_digest_nonce_garbage_interval", parserTypeByName("time_t"), &digestConfig.nonceGCInterval, NULL, authBasicDocumentGCInterval, NULL); + parserRegisterName(NULL, "authenticate_digest_nonce_max_duration", parserTypeByName("time_t"), &digestConfig.noncemaxduration, NULL, authBasicDocumentNonceDuration, NULL); + parserRegisterName(NULL, "authenticate_digest_nonce_max_count", parserTypeByName("int"), &digestConfig.noncemaxuses, NULL, authBasicDocumentNonceCount, NULL); + + /* until we support mod_uninstall we need to keep the names active indefinately */ + cbdataLock(parserNameByName("authenticate_digest_program")); + cbdataLock(parserNameByName("authenticate_digest_children")); + cbdataLock(parserNameByName("authenticate_digest_realm")); + cbdataLock(parserNameByName("authenticate_digest_nonce_garbage_interval")); + cbdataLock(parserNameByName("authenticate_digest_nonce_max_duration")); + cbdataLock(parserNameByName("authenticate_digest_nonce_max_count")); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_digest(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} + +static void authSchemeSetup_digest(authscheme_entry_t * authscheme) { assert(!authdigest_initialised); authscheme->Active = authenticateDigestActive; authscheme->configured = authDigestConfigured; - authscheme->parse = authDigestParse; - authscheme->freeconfig = authDigestFreeConfig; - authscheme->dump = authDigestCfgDump; authscheme->init = authDigestInit; authscheme->authAuthenticate = authenticateDigestAuthenticateUser; authscheme->authenticated = authDigestAuthenticated; @@ -607,10 +689,12 @@ int authDigestConfigured() { - if ((digestConfig != NULL) && (digestConfig->authenticate != NULL) && - (digestConfig->authenticateChildren != 0) && - (digestConfig->digestAuthRealm != NULL) && (digestConfig->noncemaxduration > -1)) + if ((digestConfig.authenticate != NULL) && + (digestConfig.authenticateChildren != 0) && + (digestConfig.digestAuthRealm != NULL) && (digestConfig.noncemaxduration > -1)) { + requirePathnameExists("authenticate_digest_program", digestConfig.authenticate->key); return 1; + } return 0; } @@ -733,7 +817,7 @@ return; #endif - if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) { + if ((digestConfig.authenticate) && authDigestNonceLastRequest(digest_request->nonce)) { digest_request->flags.authinfo_sent = 1; debug(29, 9) ("authDigestAddHead: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce)); httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce)); @@ -759,7 +843,7 @@ return; type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO; - if ((digestConfig->authenticate) && authDigestNonceLastRequest(digest_request->nonce)) { + if ((digestConfig.authenticate) && authDigestNonceLastRequest(digest_request->nonce)) { debug(29, 9) ("authDigestAddTrailer: Sending type:%d header: 'nextnonce=\"%s\"", type, authenticateDigestNonceNonceb64(digest_request->nonce)); httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(digest_request->nonce)); } @@ -777,10 +861,10 @@ digest_request = auth_user_request->scheme_data; stale = authDigestNonceIsStale(digest_request->nonce); } - if (digestConfig->authenticate) { - debug(29, 9) ("authenticateFixHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s\n", type, digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false"); + if (digestConfig.authenticate) { + debug(29, 9) ("authenticateFixHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s\n", type, digestConfig.digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false"); /* in the future, for WWW auth we may want to support the domain entry */ - httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s", digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false"); + httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s", digestConfig.digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false"); } } @@ -845,18 +929,18 @@ /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the * config file */ static void -authDigestInit(authScheme * scheme) +authDigestInit(void) { static int init = 0; - if (digestConfig->authenticate) { + if (digestConfig.authenticate) { authDigestUserSetup(); authDigestRequestSetup(); authenticateDigestNonceSetup(); authdigest_initialised = 1; if (digestauthenticators == NULL) digestauthenticators = helperCreate("digestauthenticator"); - digestauthenticators->cmdline = digestConfig->authenticate; - digestauthenticators->n_to_start = digestConfig->authenticateChildren; + digestauthenticators->cmdline = digestConfig.authenticate; + digestauthenticators->n_to_start = digestConfig.authenticateChildren; digestauthenticators->ipc_type = IPC_TCP_SOCKET; helperOpenServers(digestauthenticators); if (!init) { @@ -868,61 +952,6 @@ } } - -/* free any allocated configuration details */ -void -authDigestFreeConfig(authScheme * scheme) -{ - if (digestConfig == NULL) - return; - assert(digestConfig == scheme->scheme_data); - if (digestConfig->authenticate) - wordlistDestroy(&digestConfig->authenticate); - if (digestConfig->digestAuthRealm) - safe_free(digestConfig->digestAuthRealm); - xfree(digestConfig); - digestConfig = NULL; -} - -static void -authDigestParse(authScheme * scheme, int n_configured, char *param_str) -{ - if (scheme->scheme_data == NULL) { - assert(digestConfig == NULL); - /* this is the first param to be found */ - scheme->scheme_data = xmalloc(sizeof(auth_digest_config)); - memset(scheme->scheme_data, 0, sizeof(auth_digest_config)); - digestConfig = scheme->scheme_data; - digestConfig->authenticateChildren = 5; - /* 5 minutes */ - digestConfig->nonceGCInterval = 5 * 60; - /* 30 minutes */ - digestConfig->noncemaxduration = 30 * 60; - /* 50 requests */ - digestConfig->noncemaxuses = 50; - } - digestConfig = scheme->scheme_data; - if (strcasecmp(param_str, "program") == 0) { - if (digestConfig->authenticate) - wordlistDestroy(&digestConfig->authenticate); - parse_wordlist(&digestConfig->authenticate); - requirePathnameExists("authparam digest program", digestConfig->authenticate->key); - } else if (strcasecmp(param_str, "children") == 0) { - parse_int(&digestConfig->authenticateChildren); - } else if (strcasecmp(param_str, "realm") == 0) { - parse_eol(&digestConfig->digestAuthRealm); - } else if (strcasecmp(param_str, "nonce_garbage_interval") == 0) { - parse_time_t(&digestConfig->nonceGCInterval); - } else if (strcasecmp(param_str, "nonce_max_duration") == 0) { - parse_time_t(&digestConfig->noncemaxduration); - } else if (strcasecmp(param_str, "nonce_max_count") == 0) { - parse_int(&digestConfig->noncemaxuses); - } else { - debug(28, 0) ("unrecognised digest auth scheme parameter '%s'\n", param_str); - } -} - - static void authenticateDigestStats(StoreEntry * sentry) { @@ -1309,7 +1338,7 @@ digest_user = auth_user_request->auth_user->scheme_data; debug(29, 9) ("authenticateStart: '\"%s\":\"%s\"'\n", digest_user->username, digest_request->realm); - if (digestConfig->authenticate == NULL) { + if (digestConfig.authenticate == NULL) { handler(data, NULL); return; } Index: squid/src/auth/ntlm/auth_ntlm.c diff -u squid/src/auth/ntlm/auth_ntlm.c:1.9 squid/src/auth/ntlm/auth_ntlm.c:1.7.6.7 --- squid/src/auth/ntlm/auth_ntlm.c:1.9 Fri Mar 9 16:58:00 2001 +++ squid/src/auth/ntlm/auth_ntlm.c Sat Mar 31 03:07:23 2001 @@ -47,6 +47,9 @@ cbdataFree(r); } +/* register with the authentication framework */ +static AUTHSSETUP authSchemeSetup_ntlm; + /* NTLM Scheme */ static HLPSCB authenticateNTLMHandleReply; static HLPSCB authenticateNTLMHandleplaceholder; @@ -58,13 +61,10 @@ static AUTHSFREE authenticateNTLMFreeUser; static AUTHSDIRECTION authenticateNTLMDirection; static AUTHSDECODE authenticateDecodeNTLMAuth; -static AUTHSDUMP authNTLMCfgDump; -static AUTHSFREECONFIG authNTLMFreeConfig; static AUTHSINIT authNTLMInit; static AUTHSONCLOSEC authenticateNTLMOnCloseConnection; static AUTHSUSERNAME authenticateNTLMUsername; static AUTHSREQFREE authNTLMAURequestFree; -static AUTHSPARSE authNTLMParse; static AUTHSSTART authenticateNTLMStart; static AUTHSSTATS authenticateNTLMStats; static AUTHSSHUTDOWN authNTLMDone; @@ -82,10 +82,98 @@ MemPool *ntlm_helper_state_pool = NULL; MemPool *ntlm_user_pool = NULL; MemPool *ntlm_request_pool = NULL; -static auth_ntlm_config *ntlmConfig = NULL; +static auth_ntlm_config ntlmConfig = { 0, NULL, 0, 0 }; static hash_table *proxy_auth_cache = NULL; +/* + * Module support + */ + +/* parse functions */ + +static void +authNTLMDocumentProgram(void) +{ + printf("# TAG: authenticate_ntlm_program cmdline\n" +"#\tSpecify the command for the external ntlm authenticator. Such a\n" +"#\tprogram reads a line containing the uuencoded NEGOTIATE and replies\n" +"#\twith the ntlm CHALLENGE, then waits for the response and answers with\n" +"#\t\"OK\" or \"ERR\" in an endless loop. If you use an ntlm authenticator,\n" +"#\tmake sure you have 1 acl of type proxy_auth. By default, the\n" +"#\tntlm authenticator_program is not used.\n" +"#\n" +"#\tauth_param ntlm program /usr/local/squid/bin/ntlm_auth\n\n"); +} + +static void +authNTLMDocumentChildren(void) +{ + printf("# TAG: authenticate_ntlm_children children\n" +"#\tThe number of authenticator processes to spawn (no default). If you\n" +"#\tstart too few Squid will have to wait for them to process a backlog\n" +"#\tof credential verifications, slowing it down. When crendential\n" +"#\tverifications are done via a (slow) network you are likely to need\n" +"#\tlots of authenticator processes.\n" +"#Default:\n" +"# authenticate_ntlm_children 5\n\n"); +} + +static void +authNTLMDocumentChallengeUses(void) +{ + printf("# TAG: authenticate_ntlm_max_challenge_reuses reusecount\n" +"#\tThe maximum number of times a challenge given by a ntlm authentication\n" +"#\thelper can be reused. Increasing this number increases your exposure\n" +"#\tto replay attacks on your network. 0 means use the challenge only once.\n" +"#\t(disable challenge caching)\n" +"#\tSee max_ntlm_challenge_lifetime for more information.\n" +"#Default:\n" +"# authenticate_ntlm_max_challenge_reuses 0\n\n"); +} + +static void +authNTLMDocumentChallengeLifetime(void) +{ + printf("# TAG: authenticate_ntlm_max_challenge_lifetime lifetime\n" +"#\tThe maximum time period that a ntlm challenge is reused over.\n" +"#\tThe actual period will be the minimum of this time AND the number of\n" +"#\treused challenges.\n" +"#Default:\n" +"# authenticate_ntlm_max_challenge_lifetime 2 minutes\n\n"); +} + +/* register as a module */ +void +mod_install_ntlm (const char *namestr) +{ + authSchemeAdd(namestr, authSchemeSetup_ntlm); + parserRegisterName(NULL, "authenticate_ntlm_program", parserTypeByName("wordlist"), &ntlmConfig.authenticate, NULL, authNTLMDocumentProgram, NULL); + parserRegisterName(NULL, "authenticate_ntlm_children", parserTypeByName("int"), &ntlmConfig.authenticateChildren, NULL, authNTLMDocumentChildren, NULL); + default_line("authenticate_ntlm_children 5"); + parserRegisterName(NULL, "authenticate_ntlm_max_challenge_reuses", parserTypeByName("int"), &ntlmConfig.challengeuses, NULL, authNTLMDocumentChallengeUses, NULL); + default_line("authenticate_ntlm_max_challenge_reuses 0"); + parserRegisterName(NULL, "authenticate_ntlm_max_challenge_lifetime", parserTypeByName("time_t"), &ntlmConfig.challengelifetime, NULL, authNTLMDocumentChallengeLifetime, NULL); + default_line("authenticate_ntlm_max_challenge_lifetime 2 minutes"); + + /* until we support mod_uninstall we need to keep the names active indefinately */ + cbdataLock(parserNameByName("authenticate_ntlm_program")); + cbdataLock(parserNameByName("authenticate_ntlm_children")); + cbdataLock(parserNameByName("authenticate_max_challenge_reuses")); + cbdataLock(parserNameByName("authenticate_max_challenge_lifetime")); +} + + + + +/* deregister as a module */ +unsigned int +mod_uninstall_ntlm(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} + + /* * * Private Functions @@ -122,77 +210,13 @@ debug(29, 2) ("authNTLMDone: NTLM authentication Shutdown.\n"); } -/* free any allocated configuration details */ -void -authNTLMFreeConfig(authScheme * scheme) -{ - if (ntlmConfig == NULL) - return; - assert(ntlmConfig == scheme->scheme_data); - if (ntlmConfig->authenticate) - wordlistDestroy(&ntlmConfig->authenticate); - xfree(ntlmConfig); - ntlmConfig = NULL; -} - static void -authNTLMCfgDump(StoreEntry * entry, const char *name, authScheme * scheme) -{ - auth_ntlm_config *config = scheme->scheme_data; - wordlist *list = config->authenticate; - storeAppendPrintf(entry, "%s %s", name, "ntlm"); - while (list != NULL) { - storeAppendPrintf(entry, " %s", list->key); - list = list->next; - } - storeAppendPrintf(entry, "\n%s %s children %d\n%s %s max_challenge_reuses %d\n%s %s max_challenge_lifetime %d seconds\n", - name, "ntlm", config->authenticateChildren, - name, "ntlm", config->challengeuses, - name, "ntlm", config->challengelifetime); - -} - -static void -authNTLMParse(authScheme * scheme, int n_configured, char *param_str) -{ - if (scheme->scheme_data == NULL) { - assert(ntlmConfig == NULL); - /* this is the first param to be found */ - scheme->scheme_data = xmalloc(sizeof(auth_ntlm_config)); - memset(scheme->scheme_data, 0, sizeof(auth_ntlm_config)); - ntlmConfig = scheme->scheme_data; - ntlmConfig->authenticateChildren = 5; - ntlmConfig->challengeuses = 0; - ntlmConfig->challengelifetime = 60; - } - ntlmConfig = scheme->scheme_data; - if (strcasecmp(param_str, "program") == 0) { - if (ntlmConfig->authenticate) - wordlistDestroy(&ntlmConfig->authenticate); - parse_wordlist(&ntlmConfig->authenticate); - requirePathnameExists("authparam ntlm program", ntlmConfig->authenticate->key); - } else if (strcasecmp(param_str, "children") == 0) { - parse_int(&ntlmConfig->authenticateChildren); - } else if (strcasecmp(param_str, "max_challenge_reuses") == 0) { - parse_int(&ntlmConfig->challengeuses); - } else if (strcasecmp(param_str, "max_challenge_lifetime") == 0) { - parse_time_t(&ntlmConfig->challengelifetime); - } else { - debug(28, 0) ("unrecognised ntlm auth scheme parameter '%s'\n", param_str); - } -} - - -void authSchemeSetup_ntlm(authscheme_entry_t * authscheme) { assert(!authntlm_initialised); authscheme->Active = authenticateNTLMActive; authscheme->configured = authNTLMConfigured; - authscheme->parse = authNTLMParse; - authscheme->dump = authNTLMCfgDump; authscheme->requestFree = authNTLMAURequestFree; - authscheme->freeconfig = authNTLMFreeConfig; authscheme->init = authNTLMInit; authscheme->authAuthenticate = authenticateNTLMAuthenticateUser; authscheme->authenticated = authNTLMAuthenticated; @@ -210,10 +234,10 @@ /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the * config file */ static void -authNTLMInit(authScheme * scheme) +authNTLMInit(void) { static int ntlminit = 0; - if (ntlmConfig->authenticate) { + if (ntlmConfig.authenticate) { if (!ntlm_helper_state_pool) ntlm_helper_state_pool = memPoolCreate("NTLM Helper State data", sizeof(ntlm_helper_state_t)); if (!ntlm_user_pool) @@ -226,8 +250,8 @@ if (!proxy_auth_cache) proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string); assert(proxy_auth_cache); - ntlmauthenticators->cmdline = ntlmConfig->authenticate; - ntlmauthenticators->n_to_start = ntlmConfig->authenticateChildren; + ntlmauthenticators->cmdline = ntlmConfig.authenticate; + ntlmauthenticators->n_to_start = ntlmConfig.authenticateChildren; ntlmauthenticators->ipc_type = IPC_TCP_SOCKET; ntlmauthenticators->datapool = ntlm_helper_state_pool; ntlmauthenticators->IsAvailable = authenticateNTLMHelperServerAvailable; @@ -253,7 +277,10 @@ int authNTLMConfigured() { - if ((ntlmConfig != NULL) && (ntlmConfig->authenticate != NULL) && (ntlmConfig->authenticateChildren != 0) && (ntlmConfig->challengeuses > -1) && (ntlmConfig->challengelifetime > -1)) { + if ((ntlmConfig.authenticate != NULL) && + (ntlmConfig.authenticateChildren != 0) && (ntlmConfig.challengeuses > -1) + && (ntlmConfig.challengelifetime > -1)) { + requirePathnameExists("authenticate_ntlm_program", ntlmConfig.authenticate->key); debug(29, 9) ("authNTLMConfigured: returning configured\n"); return 1; } @@ -292,7 +319,7 @@ authenticateNTLMFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request) { ntlm_request_t *ntlm_request; - if (ntlmConfig->authenticate) { + if (ntlmConfig.authenticate) { /* New request, no user details */ if (auth_user_request == NULL) { debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type); @@ -605,12 +632,12 @@ debug(29, 5) ("authenticateNTLMChangeChallenge: first use\n"); return 0; } - if (helperstate->challengeuses > ntlmConfig->challengeuses) { - debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge uses (%d) exceeded max uses (%d)\n", helperstate->challengeuses, ntlmConfig->challengeuses); + if (helperstate->challengeuses > ntlmConfig.challengeuses) { + debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge uses (%d) exceeded max uses (%d)\n", helperstate->challengeuses, ntlmConfig.challengeuses); return 1; } - if (helperstate->renewed + ntlmConfig->challengelifetime < squid_curtime) { - debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge exceeded max lifetime by %d seconds\n", squid_curtime - (helperstate->renewed + ntlmConfig->challengelifetime)); + if (helperstate->renewed + ntlmConfig.challengelifetime < squid_curtime) { + debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge exceeded max lifetime by %d seconds\n", squid_curtime - (helperstate->renewed + ntlmConfig.challengelifetime)); return 1; } debug(29, 9) ("Challenge is to be reused\n"); @@ -661,7 +688,7 @@ debug(29, 9) ("authenticateNTLMStart: state '%d'\n", ntlm_request->auth_state); debug(29, 9) ("authenticateNTLMStart: '%s'\n", sent_string); - if (ntlmConfig->authenticate == NULL) { + if (ntlmConfig.authenticate == NULL) { debug(29, 0) ("authenticateNTLMStart: no NTLM program specified:'%s'\n", sent_string); handler(data, NULL); return; Index: squid/src/fs/aufs/store_dir_aufs.c diff -u squid/src/fs/aufs/store_dir_aufs.c:1.18 squid/src/fs/aufs/store_dir_aufs.c:1.13.4.5 --- squid/src/fs/aufs/store_dir_aufs.c:1.18 Tue May 8 08:27:00 2001 +++ squid/src/fs/aufs/store_dir_aufs.c Sat May 12 06:06:03 2001 @@ -118,8 +118,22 @@ static void storeAufsDirInitBitmap(SwapDir *); static int storeAufsDirValidFileno(SwapDir *, sfileno, int); -/* The MAIN externally visible function */ -STSETUP storeFsSetup_aufs; +static STSETUP storeFsSetup_aufs; + +/* register as a module + */ +void +mod_install_aufs (const char *namestr) +{ + storeFsAdd(namestr, storeFsSetup_aufs); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_aufs(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} /* * These functions were ripped straight out of the heart of store_dir.c. @@ -1697,7 +1711,7 @@ asyncufs_initialised = 0; } -void +static void storeFsSetup_aufs(storefs_entry_t * storefs) { assert(!asyncufs_initialised); Index: squid/src/fs/coss/store_dir_coss.c diff -u squid/src/fs/coss/store_dir_coss.c:1.13 squid/src/fs/coss/store_dir_coss.c:1.10.4.4 --- squid/src/fs/coss/store_dir_coss.c:1.13 Tue May 8 08:35:26 2001 +++ squid/src/fs/coss/store_dir_coss.c Sat May 12 06:06:26 2001 @@ -87,8 +87,22 @@ static STFSRECONFIGURE storeCossDirReconfigure; static STDUMP storeCossDirDump; -/* The "only" externally visible function */ -STSETUP storeFsSetup_coss; +static STSETUP storeFsSetup_coss; + +/* register as a module + */ +void +mod_install_coss (const char *namestr) +{ + storeFsAdd(namestr, storeFsSetup_coss); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_coss(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} static char * storeCossDirSwapLogFile(SwapDir * sd, const char *ext) @@ -851,7 +865,7 @@ coss_initialised = 0; } -void +static void storeFsSetup_coss(storefs_entry_t * storefs) { assert(!coss_initialised); Index: squid/src/fs/diskd/store_dir_diskd.c diff -u squid/src/fs/diskd/store_dir_diskd.c:1.23 squid/src/fs/diskd/store_dir_diskd.c:1.14.4.6 --- squid/src/fs/diskd/store_dir_diskd.c:1.23 Tue May 8 08:27:01 2001 +++ squid/src/fs/diskd/store_dir_diskd.c Sat May 12 06:06:26 2001 @@ -128,8 +128,22 @@ static void storeDiskdStats(StoreEntry * sentry); static void storeDiskdDirSync(SwapDir *); -/* The only externally visible interface */ -STSETUP storeFsSetup_diskd; +static STSETUP storeFsSetup_diskd; + +/* register as a module + */ +void +mod_install_diskd (const char *namestr) +{ + storeFsAdd(namestr, storeFsSetup_diskd); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_diskd(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} /* * These functions were ripped straight out of the heart of store_dir.c. @@ -1940,7 +1954,7 @@ diskd_initialised = 0; } -void +static void storeFsSetup_diskd(storefs_entry_t * storefs) { assert(!diskd_initialised); Index: squid/src/fs/null/store_null.c diff -u squid/src/fs/null/store_null.c:1.2 squid/src/fs/null/store_null.c:1.2.6.2 --- squid/src/fs/null/store_null.c:1.2 Sat Feb 10 08:49:07 2001 +++ squid/src/fs/null/store_null.c Thu Feb 15 14:29:25 2001 @@ -49,8 +49,22 @@ static STLOGCLEANDONE storeNullDirWriteCleanDone; static EVH storeNullDirRebuildComplete; -/* The only externally visible interface */ -STSETUP storeFsSetup_null; +static STSETUP storeFsSetup_null; + +/* register as a module + */ +void +mod_install_null (const char *namestr) +{ + storeFsAdd(namestr, storeFsSetup_null); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_null(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} static void storeNullDirReconfigure(SwapDir * sd, int index, char *path) @@ -118,7 +132,7 @@ /* Setup and register the store module */ -void +static void storeFsSetup_null(storefs_entry_t * storefs) { assert(!null_initialised); Index: squid/src/fs/ufs/store_dir_ufs.c diff -u squid/src/fs/ufs/store_dir_ufs.c:1.17 squid/src/fs/ufs/store_dir_ufs.c:1.12.4.5 --- squid/src/fs/ufs/store_dir_ufs.c:1.17 Tue May 8 08:27:01 2001 +++ squid/src/fs/ufs/store_dir_ufs.c Sat May 12 06:06:26 2001 @@ -116,7 +116,22 @@ static void storeUfsDirInitBitmap(SwapDir *); static int storeUfsDirValidFileno(SwapDir *, sfileno, int); -STSETUP storeFsSetup_ufs; +static STSETUP storeFsSetup_ufs; + +/* register as a module + */ +void +mod_install_ufs (const char *namestr) +{ + storeFsAdd(namestr, storeFsSetup_ufs); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_ufs(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} /* * These functions were ripped straight out of the heart of store_dir.c. @@ -1676,7 +1691,7 @@ ufs_initialised = 0; } -void +static void storeFsSetup_ufs(storefs_entry_t * storefs) { assert(!ufs_initialised); Index: squid/src/modules/Makefile.in diff -u /dev/null squid/src/modules/Makefile.in:1.1.6.1 --- /dev/null Tue Sep 28 18:36:02 2004 +++ squid/src/modules/Makefile.in Wed Feb 14 05:51:42 2001 @@ -0,0 +1,36 @@ +# Makefile for modules in the Squid Object Cache server +# +# $Id$ +# + +SUBDIRS = @CONF_MODULES@ +OUTLIBS = @CONF_MODULE_LIBS@ + +all install: + @test -z "$(SUBDIRS)" || for dir in $(SUBDIRS); do \ + sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1; \ + done; + +$(OUTLIBS): + @sh -c "cd `basename $@ .a` && $(MAKE) $(MFLAGS) ../$@" + +clean: + -rm -f *.a stamp + -for dir in *; do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1;\ + fi; \ + done + +distclean: + -rm -f *.a Makefile + -for dir in *; do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) $(MFLAGS) distclean"; \ + fi; \ + done + +.DEFAULT: + @test -z "$(SUBDIRS)" || for dir in $(SUBDIRS); do \ + sh -c "cd $$dir && $(MAKE) $(MFLAGS) $@" || exit 1; \ + done Index: squid/src/modules/acl_arp/Makefile.in diff -u /dev/null squid/src/modules/acl_arp/Makefile.in:1.1.2.1 --- /dev/null Tue Sep 28 18:36:02 2004 +++ squid/src/modules/acl_arp/Makefile.in Fri Apr 27 01:30:04 2001 @@ -0,0 +1,70 @@ +# +# Makefile for the ntlm authentication scheme module for the Squid Object Cache server +# +# $Id$ +# + +MODULE = acl_arp + +#SUBDIRS = helpers + +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +MAKEDEPEND = @MAKEDEPEND@ +AR_R = @AR_R@ +RANLIB = @RANLIB@ +AC_CFLAGS = @CFLAGS@ +SHELL = /bin/sh + +INCLUDE = -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/ +CFLAGS = $(AC_CFLAGS) $(INCLUDE) $(DEFINES) + +OUT = ../$(MODULE).a + +OBJS = \ + acl_arp.o + + +all install: $(OUT) + @for dir in $(SUBDIRS); do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) $@" || exit 1; \ + fi; \ + done; + +$(OUT): $(OBJS) + @rm -f ../stamp + $(AR_R) $(OUT) $(OBJS) + $(RANLIB) $(OUT) + +$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h + +.c.o: + @rm -f ../stamp + $(CC) $(CFLAGS) -c $< + +clean: + -rm -rf *.o *pure_* core ../$(MODULE).a + -for dir in *; do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) clean"; \ + fi; \ + done + +distclean: clean + -rm -f Makefile + -rm -f Makefile.bak + -rm -f tags + -for dir in *; do \ + if [ -f $$dir/Makefile ]; then \ + sh -c "cd $$dir && $(MAKE) distclean"; \ + fi; \ + done + +tags: + ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch] + +depend: + $(MAKEDEPEND) $(INCLUDE) -fMakefile *.c Index: squid/src/modules/acl_arp/acl_arp.c diff -u /dev/null squid/src/modules/acl_arp/acl_arp.c:1.1.2.1 --- /dev/null Tue Sep 28 18:36:02 2004 +++ squid/src/modules/acl_arp/acl_arp.c Fri Apr 27 01:30:04 2001 @@ -0,0 +1,487 @@ + +/* + * $Id$ + * + * DEBUG: section 28 ACL + * AUTHOR: Several + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * the Regents of the University of California. Please see the + * COPYRIGHT file for full details. Squid incorporates software + * developed and/or copyrighted by other sources. Please 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. + * + */ + +#include "squid.h" +#include "squid_parser.h" +#include "acl.h" + +struct _acl_arp_data { + char eth[6]; +}; + + +static PARSER_PARSE aclParseArpList; +static PARSER_FREE aclDestroyArpList; +static PARSER_DUMP dump_ArpList; +static ACLMATCH aclMatchSrcArp; +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; + +/* register as a module */ +void +mod_install_acl_arp (const char *namestr) +{ + parserRegisterType("arplist", aclParseArpList, aclDestroyArpList, dump_ArpList); + aclRegisterAclName("arp", parserTypeByName("arplist"), aclMatchSrcArp); + /* Register global configuration parameters */ +} + +/* deregister as a module */ +void +mod_uninstall_acl_arp(const char *namestr) { + /* Deregister global configurationparameters */ +//FIXME: aclDeregisterAclName("arp"); +//FIXME: parserDeregisterName("arplist"); + +} + + +/* ==== BEGIN ARP ACL SUPPORT ============================================= */ + +/* + * 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) +{ + 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; +} + +static acl_arp_data * +aclParseArpData(const char *t) +{ + 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; + } + return q; +} + + +/*******************/ +/* aclParseArpList */ +/*******************/ +static void +aclParseArpList(parserNameNode *parserName, void *curlist) +{ + 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); + } +} + +/***************/ +/* aclMatchArp */ +/***************/ +static int +aclMatchArp(void *dataptr, struct in_addr c) +{ +#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; +#endif + /* + * Address was not found on any interface + */ + debug(28, 3) ("aclMatchArp: %s NOT found\n", inet_ntoa(c)); + return 0; +} + +static int +aclMatchSrcArp(void **dataptr, aclCheck_t *checklist) +{ + return aclMatchArp(dataptr, checklist->src_addr); +} + + +static void +aclDestroyArpList(parserNameNode *parserName, void * data) +{ + acl ** head=(acl **)data; + acl *a=*head; + if (a) + splay_destroy(a->data, xfree); +} + +static void +dump_ArpList(StoreEntry * entry, const char *name, void const * const data) +{ + acl * ae=*(acl * *)data; + wordlist *w; + wordlist *v; + while (ae != NULL) { + debug(3, 3) ("dump_ArpList: %s %s\n", name, ae->name); + v = w = aclDumpArpList(ae->data); + while (v != NULL) { + debug(3, 3) ("dump_ArpList: %s %s %s\n", name, ae->name, v->key); + storeAppendPrintf(entry, "%s %s %s %s\n", + name, + ae->name, + aclTypeToStr(ae->type), + v->key); + v = v->next; + } + wordlistDestroy(&w); + ae = ae->next; + } +} + +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; +#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; +} +**********************************************************************/ +#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); +} + +static wordlist * +aclDumpArpList(void *data) +{ + wordlist *w = NULL; + splay_walk(data, aclDumpArpListWalkee, &w); + return w; +} + +/* ==== END ARP ACL SUPPORT =============================================== */ + Index: squid/src/repl/heap/store_repl_heap.c diff -u squid/src/repl/heap/store_repl_heap.c:1.8 squid/src/repl/heap/store_repl_heap.c:1.6.4.3 --- squid/src/repl/heap/store_repl_heap.c:1.8 Fri Mar 16 09:22:14 2001 +++ squid/src/repl/heap/store_repl_heap.c Sat Mar 31 01:52:21 2001 @@ -37,7 +37,26 @@ #include "heap.h" #include "store_heap_replacement.h" -REMOVALPOLICYCREATE createRemovalPolicy_heap; +static REMOVALPOLICYCREATE createRemovalPolicy_heap; + +/* Module Support + */ + +/* register as a module + */ +void +mod_install_heap (const char *namestr) +{ + storeReplAdd(namestr, createRemovalPolicy_heap); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_heap(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} + static int nr_heap_policies = 0; @@ -250,7 +269,7 @@ cbdataFree(policy); } -RemovalPolicy * +static RemovalPolicy * createRemovalPolicy_heap(wordlist * args) { RemovalPolicy *policy; Index: squid/src/repl/lru/store_repl_lru.c diff -u squid/src/repl/lru/store_repl_lru.c:1.7 squid/src/repl/lru/store_repl_lru.c:1.6.4.3 --- squid/src/repl/lru/store_repl_lru.c:1.7 Sat Mar 3 02:44:34 2001 +++ squid/src/repl/lru/store_repl_lru.c Sat Mar 31 01:52:21 2001 @@ -35,7 +35,7 @@ #include "squid.h" -REMOVALPOLICYCREATE createRemovalPolicy_lru; +static REMOVALPOLICYCREATE createRemovalPolicy_lru; typedef struct _LruPolicyData LruPolicyData; struct _LruPolicyData { @@ -48,6 +48,26 @@ } type; }; + +/* Module Support + */ + +/* register as a module + */ +void +mod_install_lru (const char *namestr) +{ + storeReplAdd(namestr, createRemovalPolicy_lru); +} + +/* deregister as a module */ +unsigned int +mod_uninstall_lru(const char *namestr) { + /* deregistration not supported for this module */ + return 0; +} + + /* Hack to avoid having to remember the RemovalPolicyNode location. * Needed by the purge walker to clear the policy information */ @@ -256,7 +276,7 @@ cbdataFree(policy); } -RemovalPolicy * +static RemovalPolicy * createRemovalPolicy_lru(wordlist * args) { RemovalPolicy *policy;