--------------------- PatchSet 6181 Date: 2004/03/19 22:59:22 Author: hno Branch: external_acl_fuzzy Tag: (none) Log: Import of external_acl_fuzzy branch Members: helpers/external_acl/Makefile.am:1.2.2.2->1.2.2.2.18.1 helpers/external_acl/ident/Makefile.am:1.1->1.1.2.1 helpers/external_acl/ident/README.txt:1.1->1.1.2.1 helpers/external_acl/ident/squid_ident_lookup.c:1.1->1.1.2.1 src/external_acl.c:1.2.4.24->1.2.4.24.2.1 src/structs.h:1.48.2.21->1.48.2.21.2.1 Index: squid/helpers/external_acl/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/helpers/external_acl/Makefile.am,v retrieving revision 1.2.2.2 retrieving revision 1.2.2.2.18.1 diff -u -r1.2.2.2 -r1.2.2.2.18.1 --- squid/helpers/external_acl/Makefile.am 17 Jul 2002 15:30:22 -0000 1.2.2.2 +++ squid/helpers/external_acl/Makefile.am 19 Mar 2004 22:59:22 -0000 1.2.2.2.18.1 @@ -1,7 +1,7 @@ # Makefile for storage modules in the Squid Object Cache server # -# $Id: Makefile.am,v 1.2.2.2 2002/07/17 15:30:22 squidadm Exp $ +# $Id: Makefile.am,v 1.2.2.2.18.1 2004/03/19 22:59:22 hno Exp $ # -DIST_SUBDIRS = ip_user ldap_group unix_group wbinfo_group winbind_group +DIST_SUBDIRS = ip_user ldap_group unix_group wbinfo_group winbind_group ident SUBDIRS = @EXTERNAL_ACL_HELPERS@ --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/helpers/external_acl/ident/Makefile.am Wed Feb 14 01:09:44 2007 @@ -0,0 +1,17 @@ +# +# Makefile for the ip_user external_acl helper by Rodrigo Campos +# +# $Id: Makefile.am,v 1.1.2.1 2004/03/19 22:59:23 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + +libexec_PROGRAMS = squid_ident_lookup + +squid_ident_lookup_SOURCES = \ + squid_ident_lookup.c + +EXTRA_DIST = \ + README + +LDADD = @XTRA_LIBS@ --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/helpers/external_acl/ident/README.txt Wed Feb 14 01:09:44 2007 @@ -0,0 +1,6 @@ +This helper expects to be called from a external_acl_type statement like + +external_acl_type ident ttl=600 negative_ttl=10 grace=20 \ + %SRC %| %SRCPORT %MYADDR %MYPORT \ + /usr/local/squid/libexec/squid_ident_lookup +acl ident external ident --- /dev/null Wed Feb 14 01:07:22 2007 +++ squid/helpers/external_acl/ident/squid_ident_lookup.c Wed Feb 14 01:09:44 2007 @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Configurable parameters */ +int timeout = 3; +unsigned short port = 113; + +/* Globals */ +volatile int remote_fd = -1; +volatile int busy; +char buf[1024]; +sigjmp_buf errjmp; +const char *program_name; + +static char * +strwordtok(char *buf, char **t) +{ + unsigned char *word = NULL; + unsigned char *p = (unsigned char *) buf; + unsigned char *d; + unsigned char ch; + int quoted = 0; + if (!p) + p = (unsigned char *) *t; + if (!p) + goto error; + while (*p && isspace(*p)) + p++; + if (!*p) + goto error; + word = d = p; + while ((ch = *p)) { + switch (ch) { + case '\\': + p++; + *d++ = ch = *p; + if (ch) + p++; + break; + case '"': + quoted = !quoted; + p++; + break; + default: + if (!quoted && isspace(*p)) { + p++; + goto done; + } + *d++ = *p++; + break; + } + } + done: + *d++ = '\0'; + error: + *t = (char *) p; + return (char *) word; +} + +static void +timeout_handler(int signum) +{ + signal(signum, timeout_handler); + if (busy) + siglongjmp(errjmp, 1); +} + +char * +ident_lookup(char *srcip, char *srcport, char *myip, char *myport) +{ + struct sockaddr_in src, my; + unsigned short sport, mport; + int len; + int size = 0; + char *type; + char *user; + char *ostype; + memset(&src, sizeof(src), 0); + memset(&my, sizeof(my), 0); + sport = strtol(srcport, NULL, 0); + src.sin_family = AF_INET; + if (!inet_aton(srcip, &src.sin_addr)) + return NULL; + src.sin_port = htons(port); + mport = strtol(myport, NULL, 0); + my.sin_family = AF_INET; + if (!inet_aton(myip, &my.sin_addr)) + return NULL; + my.sin_port = 0; + + remote_fd = socket(PF_INET, SOCK_STREAM, 0); + if (remote_fd == -1) + return NULL; + + if (bind(remote_fd, (struct sockaddr *) &my, sizeof(my)) != 0) + return NULL; + + if (connect(remote_fd, (struct sockaddr *) &src, sizeof(src)) != 0) + return NULL; + + snprintf(buf, sizeof(buf), "%d, %d\r\n", sport, mport); + write(remote_fd, buf, strlen(buf)); + while ((len = read(remote_fd, buf + size, sizeof(buf) - size - 1)) > 0) { + size += len; + if (strchr(buf, '\n')) + break; + } + if (size) + buf[size] = '\0'; + close(remote_fd); + remote_fd = -1; + + type = strchr(buf, ':'); + if (!type) + return NULL; + type++; + while (*type && isspace((unsigned char) *type)) + type++; + if (strncasecmp(type, "USERID", 6) != 0) + return NULL; + ostype = strchr(type, ':'); + if (!ostype) + return NULL; + user = strchr(ostype + 1, ':'); + if (!user) + return NULL; + user++; + while (*user && isspace((unsigned char) *user)) + user++; + while (*user && isspace((unsigned char) user[strlen(user) - 1])) + user[strlen(user) - 1] = '\0'; + if (!*user) + return NULL; + return user; +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s\n\n", program_name); + fprintf(stderr, + "Squid external ident lookup helper\n" + "(C)2003 Henrik Nordstrom \n" + "\n" + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n"); +} + +int +main(int argc, char **argv) +{ + program_name = argv[0]; + if (argc != 1) { + usage(); + exit(1); + } + setbuf(stdout, NULL); + signal(SIGALRM, timeout_handler); + while (fgets(buf, sizeof(buf), stdin)) { + char *srcip, *srcport, *myip, *myport; + char *tptr; + srcip = strwordtok(buf, &tptr); + srcport = strwordtok(NULL, &tptr); + myip = strwordtok(NULL, &tptr); + myport = strwordtok(NULL, &tptr); + if (!myport) { + printf("ERR\n"); + continue; + } + if (sigsetjmp(errjmp, 1) != 0) { + printf("ERR level=1\n"); + } else { + char *user; + alarm(timeout); + busy = 1; + user = ident_lookup(srcip, srcport, myip, myport); + busy = 0; + alarm(0); + if (user) + printf("OK level=1 user=\"%s\"\n", user); + else + printf("ERR level=1\n"); + } + if (remote_fd > -1) + close(remote_fd); + remote_fd = -1; + } + return 0; +} Index: squid/src/external_acl.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/external_acl.c,v retrieving revision 1.2.4.24 retrieving revision 1.2.4.24.2.1 diff -u -r1.2.4.24 -r1.2.4.24.2.1 --- squid/src/external_acl.c 19 Feb 2004 03:08:39 -0000 1.2.4.24 +++ squid/src/external_acl.c 19 Mar 2004 22:59:24 -0000 1.2.4.24.2.1 @@ -1,6 +1,6 @@ /* - * $Id: external_acl.c,v 1.2.4.24 2004/02/19 03:08:39 squidadm Exp $ + * $Id: external_acl.c,v 1.2.4.24.2.1 2004/03/19 22:59:24 hno Exp $ * * DEBUG: section 82 External ACL * AUTHOR: Henrik Nordstrom, MARA Systems AB @@ -49,13 +49,18 @@ #define DEFAULT_EXTERNAL_ACL_CONCURRENCY 5 #endif +#define MAX_LEVELS 20 +typedef unsigned short external_acl_levels[MAX_LEVELS]; + typedef struct _external_acl_format external_acl_format; typedef struct _external_acl_data external_acl_data; -static char *makeExternalAclKey(aclCheck_t * ch, external_acl_data * acl_data); +static char *makeExternalAclKey(aclCheck_t * ch, external_acl_data * acl_data, external_acl_levels * levels); static void external_acl_cache_delete(external_acl * def, external_acl_entry * entry); static int external_acl_entry_expired(external_acl * def, external_acl_entry * entry); +static int external_acl_grace_expired(external_acl * def, external_acl_entry * entry); static void external_acl_cache_touch(external_acl * def, external_acl_entry * entry); +static external_acl_entry *externalAclCacheLookup(const external_acl * def, const char *key, external_acl_levels levels); /******************************************************************* * external_acl cache entry @@ -78,6 +83,8 @@ external_acl *next; int ttl; int negative_ttl; + int grace; + int cache_levels; char *name; external_acl_format *format; wordlist *cmdline; @@ -98,6 +105,9 @@ EXT_ACL_IDENT, #endif EXT_ACL_SRC, + EXT_ACL_SRCPORT, + EXT_ACL_MYADDR, + EXT_ACL_MYPORT, EXT_ACL_DST, EXT_ACL_PROTO, EXT_ACL_PORT, @@ -105,7 +115,8 @@ EXT_ACL_HEADER, EXT_ACL_HEADER_MEMBER, EXT_ACL_HEADER_ID, - EXT_ACL_HEADER_ID_MEMBER + EXT_ACL_HEADER_ID_MEMBER, + EXT_ACL_LEVEL } type; external_acl_format *next; char *header; @@ -183,6 +194,8 @@ a->children = atoi(token + 12); } else if (strncmp(token, "cache=", 6) == 0) { a->cache_size = atoi(token + 6); + } else if (strncmp(token, "grace=", 6) == 0) { + a->grace = atoi(token + 6); } else { break; } @@ -245,6 +258,12 @@ #endif else if (strcmp(token, "%SRC") == 0) format->type = EXT_ACL_SRC; + else if (strcmp(token, "%SRCPORT") == 0) + format->type = EXT_ACL_SRCPORT; + else if (strcmp(token, "%MYADDR") == 0) + format->type = EXT_ACL_MYADDR; + else if (strcmp(token, "%MYPORT") == 0) + format->type = EXT_ACL_MYPORT; else if (strcmp(token, "%DST") == 0) format->type = EXT_ACL_DST; else if (strcmp(token, "%PROTO") == 0) @@ -253,7 +272,12 @@ format->type = EXT_ACL_PORT; else if (strcmp(token, "%METHOD") == 0) format->type = EXT_ACL_METHOD; - else { + else if (strcmp(token, "%|") == 0) { + format->type = EXT_ACL_LEVEL; + a->cache_levels++; + if (a->cache_levels > MAX_LEVELS) + self_destruct(); + } else { self_destruct(); } *p = format; @@ -290,8 +314,12 @@ storeAppendPrintf(sentry, " ttl=%d", node->ttl); if (node->negative_ttl != node->ttl) storeAppendPrintf(sentry, " negative_ttl=%d", node->negative_ttl); + if (node->grace) + storeAppendPrintf(sentry, " grace=%d", node->grace); if (node->children != DEFAULT_EXTERNAL_ACL_CONCURRENCY) storeAppendPrintf(sentry, " concurrency=%d", node->children); + if (node->cache_size) + storeAppendPrintf(sentry, " cache=%d", node->cache_size); for (format = node->format; format; format = format->next) { switch (format->type) { case EXT_ACL_HEADER: @@ -302,6 +330,9 @@ case EXT_ACL_HEADER_ID_MEMBER: storeAppendPrintf(sentry, " %%{%s:%s}", format->header, format->member); break; + case EXT_ACL_LEVEL: + storeAppendPrintf(sentry, " %%|"); + break; #define DUMP_EXT_ACL_TYPE(a) \ case EXT_ACL_##a: \ storeAppendPrintf(sentry, " %%%s", #a); \ @@ -311,6 +342,9 @@ DUMP_EXT_ACL_TYPE(IDENT); #endif DUMP_EXT_ACL_TYPE(SRC); + DUMP_EXT_ACL_TYPE(SRCPORT); + DUMP_EXT_ACL_TYPE(MYADDR); + DUMP_EXT_ACL_TYPE(MYPORT); DUMP_EXT_ACL_TYPE(DST); DUMP_EXT_ACL_TYPE(PROTO); DUMP_EXT_ACL_TYPE(PORT); @@ -402,6 +436,7 @@ external_acl_entry *entry = NULL; external_acl_data *acl = data; const char *key = ""; + external_acl_levels levels; debug(82, 9) ("aclMatchExternal: acl=\"%s\"\n", acl->def->name); if (ch->extacl_entry) { entry = ch->extacl_entry; @@ -418,13 +453,14 @@ return ti; } } - key = makeExternalAclKey(ch, acl); + key = makeExternalAclKey(ch, acl, &levels); if (!key) { /* Not sufficient data to process */ return -1; } if (entry) { - if (entry->def != acl->def || strcmp(entry->hash.key, key) != 0) { + int l = strlen(entry->hash.key); + if (entry->def != acl->def || strncmp(entry->hash.key, key, l) != 0 || (key[l] != '\0' && key[l] != ' ')) { /* Not ours.. get rid of it */ cbdataUnlock(ch->extacl_entry); ch->extacl_entry = NULL; @@ -432,21 +468,23 @@ } } if (!entry) { - entry = hash_lookup(acl->def->cache, key); - if (entry && external_acl_entry_expired(acl->def, entry)) { - /* Expired entry, ignore */ - debug(82, 2) ("external_acl_cache_lookup: '%s' = expired\n", key); - entry = NULL; + entry = externalAclCacheLookup(acl->def, key, levels); + if (!entry || external_acl_grace_expired(acl->def, entry)) { + debug(82, 2) ("aclMatchExternal: %s(\"%s\") = lookup needed\n", acl->def->name, key); + if (acl->def->helper->stats.queue_size <= acl->def->helper->n_running) { + ch->state[ACL_EXTERNAL] = ACL_LOOKUP_NEEDED; + return -1; + } else { + if (!entry) { + debug(82, 1) ("aclMatchExternal: '%s' queue overload. Request rejected '%s'.\n", acl->def->name, key); + return -1; + } else { + debug(82, 1) ("aclMatchExternal: '%s' queue overload. Using stale result. '%s'\n", acl->def->name, key); + /* Fall thru to processing below */ + } + } } } - if (!entry || entry->result == -1) { - debug(82, 2) ("aclMatchExternal: %s(\"%s\") = lookup needed\n", acl->def->name, key); - if (acl->def->helper->stats.queue_size >= acl->def->helper->n_running) - debug(82, 1) ("aclMatchExternal: '%s' queue overload. Request rejected.\n", acl->def->name); - else - ch->state[ACL_EXTERNAL] = ACL_LOOKUP_NEEDED; - return -1; - } external_acl_cache_touch(acl->def, entry); result = entry->result; debug(82, 2) ("aclMatchExternal: %s = %d\n", acl->def->name, result); @@ -493,11 +531,12 @@ } static char * -makeExternalAclKey(aclCheck_t * ch, external_acl_data * acl_data) +makeExternalAclKey(aclCheck_t * ch, external_acl_data * acl_data, external_acl_levels * levelptr) { static MemBuf mb = MemBufNULL; char buf[256]; int first = 1; + int levels = 0; wordlist *arg; external_acl_format *format; request_t *request = ch->request; @@ -509,6 +548,9 @@ case EXT_ACL_LOGIN: str = authenticateUserRequestUsername(request->auth_user_request); break; + case EXT_ACL_LEVEL: + (*levelptr)[levels++] = mb.size; + continue; #if USE_IDENT case EXT_ACL_IDENT: str = ch->rfc931; @@ -521,6 +563,17 @@ case EXT_ACL_SRC: str = inet_ntoa(ch->src_addr); break; + case EXT_ACL_SRCPORT: + snprintf(buf, sizeof(buf), "%d", request->client_port); + str = buf; + break; + case EXT_ACL_MYADDR: + str = inet_ntoa(request->my_addr); + break; + case EXT_ACL_MYPORT: + snprintf(buf, sizeof(buf), "%d", request->my_port); + str = buf; + break; case EXT_ACL_DST: str = request->host; break; @@ -580,6 +633,18 @@ return 0; } +static int +external_acl_grace_expired(external_acl * def, external_acl_entry * entry) +{ + int ttl; + ttl = entry->result == 1 ? def->ttl : def->negative_ttl; + ttl = (ttl * (100 - def->grace)) / 100; + if (entry->date + ttl < squid_curtime) + return 1; + else + return 0; +} + static void free_external_acl_entry(void *data) { @@ -644,6 +709,7 @@ EAH *callback; void *callback_data; char *key; + external_acl_levels levels; external_acl *def; dlink_node list; externalAclState *queue; @@ -689,6 +755,7 @@ externalAclState *state = data; externalAclState *next; int result = 0; + int level = 0; char *status; char *token; char *value; @@ -712,14 +779,22 @@ user = value; else if (strcmp(token, "error") == 0) error = value; + else if (strcmp(token, "level") == 0) + level = atoi(value); } } } dlinkDelete(&state->list, &state->def->queue); if (cbdataValid(state->def)) { - if (reply) + if (reply) { + if (level) { + external_acl_entry *oldentry = hash_lookup(state->def->cache, state->key); + if (oldentry) + external_acl_cache_delete(state->def, oldentry); + state->key[state->levels[level - 1]] = '\0'; + } entry = external_acl_cache_add(state->def, state->key, result, user, error); - else { + } else { external_acl_entry *oldentry = hash_lookup(state->def->cache, state->key); if (oldentry) external_acl_cache_delete(state->def, oldentry); @@ -729,7 +804,7 @@ cbdataUnlock(state->def); state->def = NULL; - if (cbdataValid(state->callback_data)) + if (state->callback && cbdataValid(state->callback_data)) state->callback(state->callback_data, entry); cbdataUnlock(state->callback_data); state->callback_data = NULL; @@ -740,6 +815,31 @@ } while (state); } +static external_acl_entry * +externalAclCacheLookup(const external_acl * def, const char *key, external_acl_levels levels) +{ + external_acl_entry *entry = hash_lookup(def->cache, key); + int level = 0; + char *tmpkey = NULL; + if (entry) + goto found; + tmpkey = xstrdup(key); + for (level = 1; level <= def->cache_levels; level++) { + tmpkey[levels[level - 1]] = '\0'; + entry = hash_lookup(def->cache, tmpkey); + if (entry) + break; + tmpkey[levels[level - 1]] = ' '; + } + found: + if (entry) + debug(82, 3) ("externalAclCacheLookup: found '%s'(%d) at level %d", key, entry->result, level); + else + debug(82, 3) ("externalAclCacheLookup: not found '%s'", key); + safe_free(tmpkey); + return entry; +} + void externalAclLookup(aclCheck_t * ch, void *acl_data, EAH * callback, void *callback_data) { @@ -749,6 +849,11 @@ const char *key; external_acl_entry *entry; externalAclState *state; + external_acl_levels levels; + dlink_node *node; + externalAclState *oldstate = NULL; + int graceful = 0; + if (acl->def->require_auth) { int ti; /* Make sure the user is authenticated */ @@ -758,59 +863,75 @@ return; } } - key = makeExternalAclKey(ch, acl); + key = makeExternalAclKey(ch, acl, &levels); if (!key) { debug(82, 1) ("externalAclLookup: lookup in '%s', prerequisit failure\n", def->name); callback(callback_data, NULL); return; } debug(82, 2) ("externalAclLookup: lookup in '%s' for '%s'\n", def->name, key); - entry = hash_lookup(def->cache, key); + entry = externalAclCacheLookup(def, key, levels); + if (entry && external_acl_entry_expired(def, entry)) + entry = NULL; + + /* Check for a pending lookup to hook into */ + for (node = def->queue.head; node; node = node->next) { + externalAclState *oldstatetmp = node->data; + if (strcmp(key, oldstatetmp->key) == 0) { + oldstate = oldstatetmp; + break; + } + } + + /* No need to refresh a already pending lookup during grace period */ + if (entry && external_acl_grace_expired(def, entry)) { + if (oldstate) { + callback(callback_data, entry); + return; + } else { + graceful = 1; + } + } + if (!graceful && entry && !external_acl_grace_expired(def, entry)) { + /* Should not really happen, but why not.. */ + callback(callback_data, entry); + return; + } + /* No pending lookup found. Sumbit to helper */ state = cbdataAlloc(externalAclState); state->def = def; cbdataLock(state->def); - state->callback = callback; - state->callback_data = callback_data; state->key = xstrdup(key); - cbdataLock(state->callback_data); - if (entry && !external_acl_entry_expired(def, entry)) { - if (entry->result == -1) { - /* There is a pending lookup. Hook into it */ - dlink_node *node; - for (node = def->queue.head; node; node = node->next) { - externalAclState *oldstate = node->data; - if (strcmp(state->key, oldstate->key) == 0) { - state->queue = oldstate->queue; - oldstate->queue = state; - return; - } - } - } else { - /* There is a cached valid result.. use it */ - /* This should not really happen, but what the heck.. */ - callback(callback_data, entry); + memcpy(state->levels, levels, sizeof(levels)); + if (!graceful) { + state->callback = callback; + state->callback_data = callback_data; + cbdataLock(state->callback_data); + } + if (oldstate) { + /* Hook into pending lookup */ + state->queue = oldstate->queue; + oldstate->queue = state; + } else { + /* Check for queue overload */ + if (def->helper->stats.queue_size >= def->helper->n_running) { + debug(82, 1) ("externalAclLookup: '%s' queue overload\n", def->name); cbdataFree(state); + callback(callback_data, entry); return; } + /* Send it off to the helper */ + memBufDefInit(&buf); + memBufPrintf(&buf, "%s\n", key); + helperSubmit(def->helper, buf.buf, externalAclHandleReply, state); + dlinkAdd(state, &state->list, &def->queue); + memBufClean(&buf); } - /* Check for queue overload */ - if (def->helper->stats.queue_size >= def->helper->n_running) { - int result = -1; - external_acl_entry *entry = hash_lookup(def->cache, key); - debug(82, 1) ("externalAclLookup: '%s' queue overload\n", def->name); - if (entry) - result = entry->result; - cbdataFree(state); + if (graceful) { + /* No need to wait during grace period */ callback(callback_data, entry); return; } - /* Send it off to the helper */ - memBufDefInit(&buf); - memBufPrintf(&buf, "%s\n", key); - helperSubmit(def->helper, buf.buf, externalAclHandleReply, state); - external_acl_cache_add(def, key, -1, NULL, NULL); - dlinkAdd(state, &state->list, &def->queue); - memBufClean(&buf); } static void Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.48.2.21 retrieving revision 1.48.2.21.2.1 diff -u -r1.48.2.21 -r1.48.2.21.2.1 --- squid/src/structs.h 4 Feb 2004 17:48:14 -0000 1.48.2.21 +++ squid/src/structs.h 19 Mar 2004 22:59:24 -0000 1.48.2.21.2.1 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.48.2.21 2004/02/04 17:48:14 squidadm Exp $ + * $Id: structs.h,v 1.48.2.21.2.1 2004/03/19 22:59:24 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -1659,6 +1659,7 @@ struct in_addr client_addr; struct in_addr my_addr; unsigned short my_port; + unsigned short client_port; HttpHeader header; ConnStateData *body_connection; /* used by clientReadBody() */ int content_length;