diff -r -u old/squid-2.4.PRE-STABLE/src/acl.c new/squid-2.4.PRE-STABLE/src/acl.c --- old/squid-2.4.PRE-STABLE/src/acl.c Mon Feb 26 18:07:51 2001 +++ new/squid-2.4.PRE-STABLE/src/acl.c Mon Feb 26 19:17:00 2001 @@ -44,6 +44,7 @@ static void aclParseIpList(void *curlist); static void aclParseIntlist(void *curlist); static void aclParseWordList(void *curlist); +static int aclRemoveWordList(void *curlist, const char *key); static void aclParseProtoList(void *curlist); static void aclParseMethodList(void *curlist); static void aclParseTimeSpec(void *curlist); @@ -637,6 +638,12 @@ wordlistAdd(curlist, t); } +static int +aclRemoveWordList(void *curlist, const char *key) +{ + return wordlistRemove(curlist, key); +} + /**********************/ /* aclParseDomainList */ /**********************/ @@ -689,6 +696,7 @@ xstrncpy(A->name, aclname, ACL_NAME_SZ); A->type = acltype; A->cfgline = xstrdup(config_input_line); + A->flags = 0; new_acl = 1; } else { if (acltype != A->type) { @@ -749,6 +757,14 @@ break; case ACL_PROXY_AUTH: aclParseWordList(&A->data); + if (aclRemoveWordList(&A->data,"BLOCK")) { + A->flags |= FLAG_ACL_REQUEST_BLOCKING; + debug(28, 4) ("aclParseAclLine: ACL '%s': mode 'BLOCK'\n", + A->name); + } else + debug(28, 6) ("aclParseAclLine: ACL '%s': not in mode 'BLOCK'\n", + A->name); + if (!proxy_auth_cache) { /* First time around, 7921 should be big enough */ proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string); @@ -1079,6 +1095,7 @@ /* aclMatchProxyAuth can return three exit codes: * 0 : user denied access * 1 : user validated OK + * -3 : user validated OK and we are still in the user blocking_ttl period. * -1 : check the password for this user via an external authenticator * -2 : invalid Proxy-authorization: header; * ask for Proxy-Authorization: header @@ -1144,6 +1161,7 @@ (auth_user->expiretime > current_time.tv_sec)) { if (checklist->src_addr.s_addr == auth_user->ipaddr.s_addr || auth_user->ip_expiretime <= squid_curtime) { + int ret; /* user already known and valid */ debug(28, 5) ("aclMatchProxyAuth: user '%s' previously validated\n", user); @@ -1154,13 +1172,31 @@ xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ); switch (acltype) { case ACL_PROXY_AUTH: - return aclMatchUser(data, user); + ret = aclMatchUser(data, user); + break; case ACL_PROXY_AUTH_REGEX: - return aclMatchRegex(data, user); + ret = aclMatchRegex(data, user); + break; default: fatal("aclMatchProxyAuth: unknown ACL type"); return 0; /* NOTREACHED */ } + if (ret != 1) + return ret; + if (!auth_user->validatedtime) + auth_user->validatedtime = current_time.tv_sec; + if (!auth_user->request_blocking_done) { + if (!Config.blockingTTL) { + auth_user->request_blocking_done = 1; + return -3; + } + if (Config.blockingTTL + auth_user->validatedtime + < current_time.tv_sec) { + auth_user->request_blocking_done = 1; + } else + return -3; + } + return 1; } else { if (Config.onoff.authenticateIpTTLStrict) { /* Access from some other IP address than the one owning @@ -1225,6 +1261,8 @@ auth_user->passwd = xstrdup(password); auth_user->passwd_ok = -1; auth_user->expiretime = -1; + auth_user->request_blocking_done = 0; + auth_user->validatedtime = 0; checklist->auth_user = auth_user; authenticateStart(checklist->auth_user, aclLookupProxyAuthDone, checklist); @@ -1517,8 +1555,19 @@ case 0: /* Correct password, but was not allowed in this ACL */ return 0; + case -3: + /* user validated OK but we may block the request */ + if (ae->flags & FLAG_ACL_REQUEST_BLOCKING) { + RequestBlockingAclMatchedName = ae->name; + debug(28, 6) ("aclMatchProxyAuth: request blocked\n"); + } + return 1; case 1: /* user validated OK */ + if (ae->flags & FLAG_ACL_REQUEST_BLOCKING) { + debug(28, 6) + ("aclMatchProxyAuth: request not blocked\n"); + } return 1; case -2: /* no such user OR we need a proxy authentication header */ @@ -1581,6 +1630,7 @@ int aclMatchAclList(const acl_list * list, aclCheck_t * checklist) { + RequestBlockingAclMatchedName = NULL; while (list) { AclMatchedName = list->acl->name; debug(28, 3) ("aclMatchAclList: checking %s%s\n", diff -r -u old/squid-2.4.PRE-STABLE/src/cache_cf.c new/squid-2.4.PRE-STABLE/src/cache_cf.c --- old/squid-2.4.PRE-STABLE/src/cache_cf.c Mon Feb 26 18:07:51 2001 +++ new/squid-2.4.PRE-STABLE/src/cache_cf.c Mon Feb 26 16:28:28 2001 @@ -112,6 +112,22 @@ return (*list)->key; } +int +wordlistRemove(wordlist ** list,const char *key) +{ + wordlist *w = NULL; + while ((w = *list) != NULL) { + if (! strcmp(key,w->key)) { + *list = w->next; + safe_free(w->key); + memFree(w, MEM_WORDLIST); + return 1; + } + list = &(*list)->next; + } + return 0; +} + void wordlistJoin(wordlist ** list, wordlist ** wl) { diff -r -u old/squid-2.4.PRE-STABLE/src/cf.data.pre new/squid-2.4.PRE-STABLE/src/cf.data.pre --- old/squid-2.4.PRE-STABLE/src/cf.data.pre Mon Feb 26 18:07:51 2001 +++ new/squid-2.4.PRE-STABLE/src/cf.data.pre Mon Feb 26 18:15:19 2001 @@ -1654,6 +1654,11 @@ # to check username/password combinations (see # authenticate_program). # + # NOTE: special word BLOCK can be added to the proxy_auth acltype + # parameters. When present, first requests of the authenticated user + # are blocked and an ACCESS_DENIED page is returned. + # See blocking_info and blocking_ttl tags below for customizations. + # # 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. @@ -2152,6 +2157,28 @@ 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: blocking_ttl +TYPE: time_t +DEFAULT: 0 seconds +LOC: Config.blockingTTL +DOC_START + The time during which a newly authenticated user will see its requests + rejected (see blocking_info below for page customization). + Default is `0' which blocks only the first request sent by the user. +DOC_END + +NAME: blocking_info +TYPE: denyinfo +LOC: Config.blockInfoList +DEFAULT: none +DOC_START + Usage: blocking_info front_page_name acl + Example: blocking_info FRONT_PAGE password + + This can be used to return a customized page to a newly authenticated + user. The page is returned in place of his request. DOC_END NAME: memory_pools diff -r -u old/squid-2.4.PRE-STABLE/src/client_side.c new/squid-2.4.PRE-STABLE/src/client_side.c --- old/squid-2.4.PRE-STABLE/src/client_side.c Mon Feb 26 18:07:51 2001 +++ new/squid-2.4.PRE-STABLE/src/client_side.c Mon Feb 26 19:01:14 2001 @@ -224,11 +224,29 @@ AclMatchedName ? AclMatchedName : "NO ACL's"); http->acl_checklist = NULL; if (answer == ACCESS_ALLOWED) { + if (RequestBlockingAclMatchedName) { + debug(33, 2) + ("The request is blocked by rule '%s'\n", + RequestBlockingAclMatchedName); + page_id = aclGetDenyInfoPage(&Config.blockInfoList, + RequestBlockingAclMatchedName); + if (page_id <= 0) + page_id = ERR_ACCESS_DENIED; + http->log_type = LOG_TAG_NONE; + http->entry = clientCreateStoreEntry(http, http->request->method, + null_request_flags); + status = HTTP_FORBIDDEN; + err = errorCon(page_id, status); + err->request = requestLink(http->request); + err->src_addr = http->conn->peer.sin_addr; + errorAppendEntry(http->entry, err); + } else { safe_free(http->uri); http->uri = xstrdup(urlCanonical(http->request)); assert(http->redirect_state == REDIRECT_NONE); http->redirect_state = REDIRECT_PENDING; redirectStart(http, clientRedirectDone, http); + } } else { debug(33, 5) ("Access Denied: %s\n", http->uri); debug(33, 5) ("AclMatchedName = %s\n", diff -r -u old/squid-2.4.PRE-STABLE/src/enums.h new/squid-2.4.PRE-STABLE/src/enums.h --- old/squid-2.4.PRE-STABLE/src/enums.h Mon Feb 26 18:07:51 2001 +++ new/squid-2.4.PRE-STABLE/src/enums.h Mon Feb 26 16:29:59 2001 @@ -133,6 +133,11 @@ ACL_PROXY_AUTH_NEEDED } acl_lookup_state; +typedef enum { + FLAG_ACL_NONE, /* 0 */ + FLAG_ACL_REQUEST_BLOCKING /* 1 */ +} acl_flags; + enum { FD_NONE, FD_LOG, diff -r -u old/squid-2.4.PRE-STABLE/src/globals.h new/squid-2.4.PRE-STABLE/src/globals.h --- old/squid-2.4.PRE-STABLE/src/globals.h Mon Feb 26 18:07:51 2001 +++ new/squid-2.4.PRE-STABLE/src/globals.h Mon Feb 26 16:30:08 2001 @@ -152,3 +152,4 @@ extern int store_pages_max; /* 0 */ extern ssize_t store_maxobjsize; /* -1 */ extern RemovalPolicy *mem_policy; +extern const char *RequestBlockingAclMatchedName; /* NULL */ diff -r -u old/squid-2.4.PRE-STABLE/src/protos.h new/squid-2.4.PRE-STABLE/src/protos.h --- old/squid-2.4.PRE-STABLE/src/protos.h Mon Feb 26 18:07:51 2001 +++ new/squid-2.4.PRE-STABLE/src/protos.h Mon Feb 26 17:37:04 2001 @@ -75,6 +75,7 @@ extern void intlistDestroy(intlist **); extern int intlistFind(intlist * list, int i); extern const char *wordlistAdd(wordlist **, const char *); +extern int wordlistRemove(wordlist **, const char *); extern void wordlistAddWl(wordlist **, wordlist *); extern void wordlistJoin(wordlist **, wordlist **); extern wordlist *wordlistDup(const wordlist *); diff -r -u old/squid-2.4.PRE-STABLE/src/structs.h new/squid-2.4.PRE-STABLE/src/structs.h --- old/squid-2.4.PRE-STABLE/src/structs.h Mon Feb 26 18:07:51 2001 +++ new/squid-2.4.PRE-STABLE/src/structs.h Mon Feb 26 19:15:39 2001 @@ -66,9 +66,11 @@ /* extra fields for proxy_auth */ char *passwd; int passwd_ok; /* 1 = passwd checked OK */ + int request_blocking_done; /* 1 = first requests already blocked */ long expiretime; struct in_addr ipaddr; /* IP addr this user authenticated from */ time_t ip_expiretime; + time_t validatedtime; }; struct _acl_deny_info_list { @@ -120,6 +122,7 @@ squid_acl type; void *data; char *cfgline; + acl_flags flags; acl *next; }; @@ -451,6 +454,8 @@ acl_access *redirector; } accessList; acl_deny_info_list *denyInfoList; + acl_deny_info_list *blockInfoList; + time_t blockingTTL; char *proxyAuthRealm; struct { size_t list_width;