diff -urN squid-2.3.DEVEL2.DJL0/src/Makefile.in squid-2.3.DEVEL2.DJL1/src/Makefile.in --- squid-2.3.DEVEL2.DJL0/src/Makefile.in Mon Oct 18 21:31:48 1999 +++ squid-2.3.DEVEL2.DJL1/src/Makefile.in Mon Oct 18 21:53:15 1999 @@ -84,6 +84,7 @@ asn.o \ @ASYNC_OBJS@ \ authenticate.o \ + charge.o \ cache_cf.o \ CacheDigest.o \ cache_manager.o \ diff -urN squid-2.3.DEVEL2.DJL0/src/acl.c squid-2.3.DEVEL2.DJL1/src/acl.c --- squid-2.3.DEVEL2.DJL0/src/acl.c Sat Jul 24 05:19:40 1999 +++ squid-2.3.DEVEL2.DJL1/src/acl.c Mon Oct 18 21:53:15 1999 @@ -70,6 +70,8 @@ static void aclCheckCallback(aclCheck_t * checklist, allow_t answer); #if USE_IDENT static IDCB aclLookupIdentDone; +static void aclChargeStartIdent(aclCheck_t * checklist); +static void aclChargeDoneIdent(void * data, char *result); #endif static IPH aclLookupDstIPDone; static IPH aclLookupDstIPforASNDone; @@ -77,6 +79,8 @@ static FQDNH aclLookupDstFQDNDone; static void aclLookupProxyAuthStart(aclCheck_t * checklist); static void aclLookupProxyAuthDone(void *data, char *result); +static void aclChargeStartAuth(aclCheck_t * checklist); +static void aclChargeDoneAuth(void * data, char *result); static wordlist *aclDumpIpList(void *); static wordlist *aclDumpDomainList(void *data); static wordlist *aclDumpTimeSpecList(acl_time_data *); @@ -981,6 +985,8 @@ debug(28, 3) ("aclMatchUser: looking for '%s'\n", data->key); if (strcmp(data->key, "REQUIRED") == 0 && *user != '\0' && strcmp(user, "-") != 0) return 1; + if (strcmp(data->key, "CHARGE") == 0 && *user != '\0' && strcmp(user, "-") != 0) + return -3; if (strcmp(data->key, user) == 0) return 1; data = data->next; @@ -1025,9 +1031,10 @@ return 1; } -/* aclMatchProxyAuth can return three exit codes: +/* aclMatchProxyAuth can return five exit codes: * 0 : user denied access * 1 : user validated OK + * 2 : user validated OK, CHARGE * -1 : check the password for this user via an external authenticator * -2 : invalid Proxy-authorization: header; * ask for Proxy-Authorization: header @@ -1147,6 +1154,48 @@ checklist); } +#if USE_IDENT +static void +aclChargeDoneIdent(void *data, char *result) +{ + aclCheck_t *checklist = data; + debug(28, 4) ("aclChargeDoneIdent: result = %s\n", + result ? result : "NULL"); + if (result && (strncasecmp(result, "OK", 2) == 0)) + checklist->state[ACL_IDENT] = ACL_CHARGE_DONE_OK; + else + checklist->state[ACL_IDENT] = ACL_CHARGE_DONE_FAIL; + aclCheck(checklist); +} +#endif + +#if USE_IDENT +static void +aclChargeStartIdent(aclCheck_t * checklist) +{ + chargeStartCheck(checklist->request->user_ident, aclChargeDoneIdent, checklist); +} +#endif + +static void +aclChargeDoneAuth(void *data, char *result) +{ + aclCheck_t *checklist = data; + debug(28, 4) ("aclChargeDoneAuth: result = %s\n", + result ? result : "NULL"); + if (result && (strncasecmp(result, "OK", 2) == 0)) + checklist->state[ACL_PROXY_AUTH] = ACL_CHARGE_DONE_OK; + else + checklist->state[ACL_PROXY_AUTH] = ACL_CHARGE_DONE_FAIL; + aclCheck(checklist); +} + +static void +aclChargeStartAuth(aclCheck_t * checklist) +{ + chargeStartCheck(checklist->auth_user->user, aclChargeDoneAuth, checklist); +} + static int aclMatchInteger(intlist * data, int i) { @@ -1343,8 +1392,23 @@ /* NOTREACHED */ #if USE_IDENT case ACL_IDENT: - if (checklist->ident[0]) { - return aclMatchUser(ae->data, checklist->ident); + if (checklist->state[ACL_IDENT] == ACL_CHARGE_DONE_OK) { + r->flags.charge = 1; + return 1; + } else if (checklist->state[ACL_IDENT] == ACL_CHARGE_DONE_FAIL) { + return 0; + } else if (checklist->ident[0]) { + switch (aclMatchUser(ae->data, checklist->ident)) { + case 1: + /* matched */ + return 1; + case -3: + /* need charging info */ + checklist->state[ACL_IDENT] = ACL_CHARGE_NEEDED; + default: + /* fall-thru or not matched */ + return 0; + } } else { checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED; return 0; @@ -1386,6 +1450,13 @@ * it is not forwarded to the next proxy */ r->flags.used_proxy_auth = 1; + /* Post-charging-lookup return */ + if (checklist->state[ACL_PROXY_AUTH] == ACL_CHARGE_DONE_OK) { + r->flags.charge = 1; + return 1; + } else if (checklist->state[ACL_PROXY_AUTH] == ACL_CHARGE_DONE_FAIL) { + return 0; + } /* Check the password */ switch (aclMatchProxyAuth(ae->data, header, @@ -1397,6 +1468,9 @@ case 1: /* user validated OK */ return 1; + case -3: + checklist->state[ACL_PROXY_AUTH] = ACL_CHARGE_NEEDED; + return 0; case -2: /* no such user OR we need a proxy authentication header */ checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED; @@ -1486,6 +1560,7 @@ allow_t allow = ACCESS_DENIED; const acl_access *A; int match; + int saved_charge0, saved_charge1; ipcache_addrs *ia; while ((A = checklist->access_list) != NULL) { /* @@ -1499,7 +1574,10 @@ } debug(28, 3) ("aclCheck: checking '%s'\n", A->cfgline); allow = A->allow; + saved_charge0 = checklist->request->flags.charge; match = aclMatchAclList(A->acl_list, checklist); + saved_charge1 = checklist->request->flags.charge; + checklist->request->flags.charge = saved_charge0; if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NEEDED) { checklist->state[ACL_DST_IP] = ACL_LOOKUP_PENDING; ipcache_nbgethostbyname(checklist->request->host, @@ -1535,6 +1613,9 @@ aclLookupProxyAuthStart(checklist); checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_PENDING; return; + } else if (checklist->state[ACL_PROXY_AUTH] == ACL_CHARGE_NEEDED) { + aclChargeStartAuth(checklist); + return; } else if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED) { /* Special case. Client is required to resend the request * with authentication. The request is denied. @@ -1557,6 +1638,9 @@ allow = 0; match = -1; } + } else if(checklist->state[ACL_IDENT] == ACL_CHARGE_NEEDED) { + aclChargeStartIdent(checklist); + return; } #endif /* @@ -1567,6 +1651,7 @@ cbdataUnlock(A); if (match) { debug(28, 3) ("aclCheck: match found, returning %d\n", allow); + checklist->request->flags.charge = saved_charge1; aclCheckCallback(checklist, allow); return; } diff -urN squid-2.3.DEVEL2.DJL0/src/cache_cf.c squid-2.3.DEVEL2.DJL1/src/cache_cf.c --- squid-2.3.DEVEL2.DJL0/src/cache_cf.c Fri Jun 25 04:19:56 1999 +++ squid-2.3.DEVEL2.DJL1/src/cache_cf.c Mon Oct 18 21:53:15 1999 @@ -973,6 +973,8 @@ } else if (!strcasecmp(token, "no-delay")) { p->options.no_delay = 1; #endif + } else if (!strcasecmp(token, "no-charge")) { + p->options.no_charge = 1; } else if (!strncasecmp(token, "login=", 6)) { p->login = xstrdup(token + 6); } else if (!strncasecmp(token, "connect-timeout=", 16)) { diff -urN squid-2.3.DEVEL2.DJL0/src/cf.data.pre squid-2.3.DEVEL2.DJL1/src/cf.data.pre --- squid-2.3.DEVEL2.DJL0/src/cf.data.pre Sat Jul 24 23:37:44 1999 +++ squid-2.3.DEVEL2.DJL1/src/cf.data.pre Mon Oct 18 21:53:15 1999 @@ -223,6 +223,7 @@ no-digest no-netdb-exchange no-delay + no-charge login=user:password connect-timeout=nn @@ -270,6 +271,9 @@ use 'no-delay' to prevent access to this neighbor from influencing the delay pools. + use 'no-charge' to prevent access to this neighbor + from being charged to the user. + use 'login=user:password' if this is a personal/workgroup proxy and your parent requires proxy authentication. @@ -1020,6 +1024,47 @@ authenticate_ttl 3600 DOC_END +NAME: charge_program +TYPE: wordlist +LOC: Config.Program.charge +DEFAULT: none +DOC_START + Specify the command for the external charger. Such a program + reads a line containing "? username" or "- username bytes" and + replies with "OK" or "ERR" indicating if traffic should be + permitted in the case of "? username" or if the bytes have been + successfully charged for in the case of "- username bytes". + If you use an charger, make sure you have a proxy_auth acl with + a value of CHARGE. By default, the charge_program is not used. + + IMPORTANT: Charging is based on the logged username. If a + single request uses both proxy_auth and ident during its + acl checks, and finds it neccessary to look both up this will + probably (if you're doing something this strange you should + check the latest source code) be the proxy_auth, regardless of + which has the CHARGE tag on it. You should not find yourself + doing this. + + no-charge peer traffic is not charged, and cache hits are also + not charged. Otherwise, the charge program is called with a + reasonable estimation of the amount of incoming traffic. + +charge_program none +DOC_END + +NAME: charge_children +TYPE: int +DEFAULT: 5 +LOC: Config.chargeChildren +DOC_START + The number of charger processes to spawn (default 5). If you start + too few Squid will have to wait for them to process a backlog of + charging requests, slowing it down. When charging is done via a + (slow) network you are likely to need lots of charger processes. + +charge_children 5 +DOC_END + COMMENT_START OPTIONS FOR TUNING THE CACHE ----------------------------------------------------------------------------- @@ -1546,6 +1591,7 @@ acl aclname ident username ... # string match on ident output. # use REQUIRED to accept any non-null ident. + # use CHARGE to accept based on a charge_program [see charge_program]. acl aclname src_as number ... acl aclname dst_as number ... # Except for access control, AS numbers can be used for @@ -1559,6 +1605,7 @@ acl aclname proxy_auth username ... # list of valid usernames # use REQUIRED to accept any valid username. + # use CHARGE to accept based on a charge_program [see charge_program]. # # NOTE: when a Proxy-Authentication header is sent but it is not # needed during ACL checking the username is NOT logged diff -urN squid-2.3.DEVEL2.DJL0/src/charge.c squid-2.3.DEVEL2.DJL1/src/charge.c --- squid-2.3.DEVEL2.DJL0/src/charge.c Thu Jan 1 08:00:00 1970 +++ squid-2.3.DEVEL2.DJL1/src/charge.c Mon Oct 18 21:53:15 1999 @@ -0,0 +1,160 @@ + +/* + * $Id: charge.c,v 1.10 1998/12/05 00:54:15 wessels Exp $ + * + * DEBUG: section 29 Charger + * AUTHOR: David Luyer (from Duane Wessels' authenticate.c) + * + * 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 + * Duane Wessels and the University of California San Diego. 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" + +typedef struct { + void *data; + RH *handler; +} chargeStateData; + +static HLPCB chargeHandleReply; +static void chargeStateFree(chargeStateData * r); +static helper *chargers = NULL; + +static void +chargeHandleReply(void *data, char *reply) +{ + chargeStateData *r = data; + int valid; + char *t = NULL; + debug(29, 5) ("chargeHandleReply: {%s}\n", reply ? reply : ""); + if (reply) { + if ((t = strchr(reply, ' '))) + *t = '\0'; + if (*reply == '\0') + reply = NULL; + } + valid = cbdataValid(r->data); + cbdataUnlock(r->data); + if (valid) + r->handler(r->data, reply); + chargeStateFree(r); +} + +static void +chargeStateFree(chargeStateData * r) +{ + cbdataFree(r); +} + +static void +chargeStats(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "Authenticator Statistics:\n"); + helperStats(sentry, chargers); +} + +static void +dummyCallback(void * data, char * unused) +{ + /* dummy */ + cbdataUnlock(data); +} + +static char * dummyData = "dummy"; + +/**** PUBLIC FUNCTIONS ****/ + +void +chargeStartCharge(const char * user, long qty) +{ + chargeStateData *r = NULL; + char buf[8192]; + assert(user); + debug(29, 5) ("chargeStartCharge: '%s' - %d\n", user, qty); + if (Config.Program.charge == NULL) + return; + r = xcalloc(1, sizeof(chargeStateData)); + cbdataAdd(r, cbdataXfree, 0); + r->handler = dummyCallback; + cbdataLock(dummyData); + r->data = dummyData; + snprintf(buf, 8192, "- %s %ld\n", user, qty); + helperSubmit(chargers, buf, dummyCallback, dummyData); +} + +void +chargeStartCheck(const char * user, RH * handler, void *data) +{ + chargeStateData *r = NULL; + char buf[8192]; + assert(user); + assert(handler); + debug(29, 5) ("chargeStartCheck: '%s'\n", user); + if (Config.Program.charge == NULL) { + handler(data, NULL); + return; + } + r = xcalloc(1, sizeof(chargeStateData)); + cbdataAdd(r, cbdataXfree, 0); + r->handler = handler; + cbdataLock(data); + r->data = data; + snprintf(buf, 8192, "? %s\n", user); + helperSubmit(chargers, buf, chargeHandleReply, r); +} + +void +chargeInit(void) +{ + static int init = 0; + if (!Config.Program.charge) + return; + if (chargers == NULL) + chargers = helperCreate("charger"); + chargers->cmdline = Config.Program.charge; + chargers->n_to_start = Config.chargeChildren; + chargers->ipc_type = IPC_TCP_SOCKET; + helperOpenServers(chargers); + if (!init) { + cachemgrRegister("charger", + "User Charger Stats", + chargeStats, 0, 1); + init++; + } +} + +void +chargeShutdown(void) +{ + if (!chargers) + return; + helperShutdown(chargers); + if (!shutting_down) + return; + helperFree(chargers); + chargers = NULL; +} diff -urN squid-2.3.DEVEL2.DJL0/src/enums.h squid-2.3.DEVEL2.DJL1/src/enums.h --- squid-2.3.DEVEL2.DJL0/src/enums.h Sat Jul 31 08:03:15 1999 +++ squid-2.3.DEVEL2.DJL1/src/enums.h Mon Oct 18 21:53:15 1999 @@ -122,7 +122,10 @@ ACL_LOOKUP_NEEDED, ACL_LOOKUP_PENDING, ACL_LOOKUP_DONE, - ACL_PROXY_AUTH_NEEDED + ACL_PROXY_AUTH_NEEDED, + ACL_CHARGE_NEEDED, + ACL_CHARGE_DONE_OK, + ACL_CHARGE_DONE_FAIL } acl_lookup_state; enum { diff -urN squid-2.3.DEVEL2.DJL0/src/forward.c squid-2.3.DEVEL2.DJL1/src/forward.c --- squid-2.3.DEVEL2.DJL0/src/forward.c Mon Oct 18 21:31:48 1999 +++ squid-2.3.DEVEL2.DJL1/src/forward.c Mon Oct 18 21:53:15 1999 @@ -312,6 +312,10 @@ * is closed. */ assert(fwdState->server_fd > -1); + /* This is for requests which are failed as a no_charge peer request + * then re-tried from a parent. + */ + request->flags.charge |= request->flags.orig_charge; if (fwdState->servers && (p = fwdState->servers->peer)) { p->stats.fetches++; fwdState->request->peer_login = p->login; diff -urN squid-2.3.DEVEL2.DJL0/src/http.c squid-2.3.DEVEL2.DJL1/src/http.c --- squid-2.3.DEVEL2.DJL0/src/http.c Sat Jul 31 07:46:09 1999 +++ squid-2.3.DEVEL2.DJL1/src/http.c Mon Oct 18 21:53:15 1999 @@ -875,6 +875,11 @@ if (httpState->peer->options.no_delay) delaySetNoDelay(fd); #endif + if (httpState->peer->options.no_charge && orig_req->flags.charge) { + orig_req->flags.charge = 0; + orig_req->flags.orig_charge = 1; + /* client_side.c & hence the logging never sees proxy_req */ + } } else { httpState->request = requestLink(orig_req); httpState->orig_request = requestLink(orig_req); diff -urN squid-2.3.DEVEL2.DJL0/src/main.c squid-2.3.DEVEL2.DJL1/src/main.c --- squid-2.3.DEVEL2.DJL0/src/main.c Thu Jul 29 05:03:27 1999 +++ squid-2.3.DEVEL2.DJL1/src/main.c Mon Oct 18 21:53:15 1999 @@ -335,6 +335,7 @@ #endif redirectShutdown(); authenticateShutdown(); + chargeShutdown(); storeDirCloseSwapLogs(); errorClean(); mimeFreeMemory(); @@ -349,6 +350,7 @@ #endif redirectInit(); authenticateInit(); + chargeInit(); #if USE_WCCP wccpInit(); #endif @@ -460,6 +462,7 @@ #endif redirectInit(); authenticateInit(); + chargeInit(); useragentOpenLog(); httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */ httpReplyInitModule(); /* must go before accepting replies */ @@ -648,6 +651,7 @@ #endif redirectShutdown(); authenticateShutdown(); + chargeShutdown(); eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1); } eventRun(); diff -urN squid-2.3.DEVEL2.DJL0/src/neighbors.c squid-2.3.DEVEL2.DJL1/src/neighbors.c --- squid-2.3.DEVEL2.DJL0/src/neighbors.c Thu Jun 17 06:10:40 1999 +++ squid-2.3.DEVEL2.DJL1/src/neighbors.c Mon Oct 18 21:53:15 1999 @@ -1167,6 +1167,8 @@ if (p->options.no_delay) storeAppendPrintf(sentry, " no-delay"); #endif + if (p->options.no_charge) + storeAppendPrintf(sentry, " no-charge"); if (p->login) storeAppendPrintf(sentry, " login=%s", p->login); if (p->mcast.ttl > 0) diff -urN squid-2.3.DEVEL2.DJL0/src/protos.h squid-2.3.DEVEL2.DJL1/src/protos.h --- squid-2.3.DEVEL2.DJL0/src/protos.h Sat Jul 31 07:35:22 1999 +++ squid-2.3.DEVEL2.DJL1/src/protos.h Mon Oct 18 21:53:15 1999 @@ -695,6 +695,11 @@ extern void authenticateInit(void); extern void authenticateShutdown(void); +extern void chargeStartCheck(const char *, RH *, void *); +extern void chargeStartCharge(const char *, long); +extern void chargeInit(void); +extern void chargeShutdown(void); + extern void refreshAddToList(const char *, int, time_t, int, time_t); extern int refreshIsCachable(const StoreEntry *); extern int refreshCheckHTTP(const StoreEntry *, request_t *); diff -urN squid-2.3.DEVEL2.DJL0/src/ssl.c squid-2.3.DEVEL2.DJL1/src/ssl.c --- squid-2.3.DEVEL2.DJL0/src/ssl.c Mon Oct 18 21:31:48 1999 +++ squid-2.3.DEVEL2.DJL1/src/ssl.c Mon Oct 18 21:53:15 1999 @@ -547,6 +547,8 @@ sslState->delay_id = 0; } #endif + if (g && g->options.no_charge) + sslState->request->flags.charge = 0; hierarchyNote(&sslState->request->hier, fs->peer ? fs->code : DIRECT, sslState->host); diff -urN squid-2.3.DEVEL2.DJL0/src/structs.h squid-2.3.DEVEL2.DJL1/src/structs.h --- squid-2.3.DEVEL2.DJL0/src/structs.h Wed Jul 28 15:07:14 1999 +++ squid-2.3.DEVEL2.DJL1/src/structs.h Mon Oct 18 21:53:15 1999 @@ -303,12 +303,14 @@ char *dnsserver; wordlist *redirect; wordlist *authenticate; + wordlist *charge; char *pinger; char *unlinkd; } Program; int dnsChildren; int redirectChildren; int authenticateChildren; + int chargeChildren; int authenticateTTL; struct { char *host; @@ -1048,6 +1050,7 @@ #if DELAY_POOLS unsigned int no_delay:1; #endif + unsigned int no_charge:1; } options; int weight; struct { @@ -1337,6 +1340,8 @@ #endif unsigned int accelerated:1; unsigned int internal:1; + unsigned int charge:1; + unsigned int orig_charge:1; }; struct _link_list {