/*
- * $Id: acl.cc,v 1.105 1997/07/26 04:48:22 wessels Exp $
+ * $Id: acl.cc,v 1.106 1997/08/25 23:45:22 wessels Exp $
*
* DEBUG: section 28 Access Control
* AUTHOR: Duane Wessels
static squid_acl aclType _PARAMS((const char *s));
static int decode_addr _PARAMS((const char *, struct in_addr *, struct in_addr *));
static void aclCheck _PARAMS((aclCheck_t * checklist));
-
static void aclCheckCallback _PARAMS((aclCheck_t * checklist, int answer));
static IPH aclLookupDstIPDone;
static FQDNH aclLookupSrcFQDNDone;
static FQDNH aclLookupDstFQDNDone;
-
+static int aclReadProxyAuth _PARAMS((struct _acl_proxy_auth * p));
#if defined(USE_SPLAY_TREE)
static int aclIpNetworkCompare _PARAMS((const void *, splayNode *));
return ACL_METHOD;
if (!strcmp(s, "browser"))
return ACL_BROWSER;
+ if (!strcmp(s, "proxy_auth"))
+ return ACL_PROXY_AUTH;
return ACL_NONE;
}
#endif /* USE_SPLAY_TREE */
+/* check for change password file each 300 seconds */
+#define CHECK_PROXY_FILE_TIME 300
+static void
+aclParseProxyAuth(void *data)
+{
+ struct _acl_proxy_auth *p;
+ struct _acl_proxy_auth **q = data;
+ char *t;
+ t = strtok(NULL, w_space);
+ if (t) {
+ p = xcalloc(1, sizeof(struct _acl_proxy_auth));
+ p->filename = xstrdup(t);
+ p->last_time = 0;
+ p->change_time = 0;
+ t = strtok(NULL, w_space);
+ if (t == NULL) {
+ p->check_interval = CHECK_PROXY_FILE_TIME;
+ } else {
+ p->check_interval = atoi(t);
+ }
+ if (p->check_interval < 1)
+ p->check_interval = 1;
+ p->hash = 0; /* force creation of a new hash table */
+ if (aclReadProxyAuth(p)) {
+ *q = p;
+ return;
+ } else {
+ debug(28, 0) ("cannot read proxy_auth %s, ignoring\n", p->filename);
+ }
+ } else {
+ debug(28, 0) ("no filename in acl proxy_auth, ignoring\n");
+ }
+ *q = NULL;
+ return;
+}
+
void
aclParseAclLine(acl ** head)
{
case ACL_BROWSER:
aclParseRegexList(&A->data);
break;
+ case ACL_PROXY_AUTH:
+ aclParseProxyAuth(&A->data);
+ break;
case ACL_NONE:
default:
debug_trap("Bad ACL type");
return 0;
}
+#define SKIP_BASIC_SZ 6
+static int
+aclMatchProxyAuth(struct _acl_proxy_auth *p, aclCheck_t * checklist)
+{
+ LOCAL_ARRAY(char, sent_user, ICP_IDENT_SZ);
+ char *s;
+ char *cleartext;
+ char *sent_auth;
+ char *passwd = NULL;
+ hash_link *hashr = NULL;
+ s = mime_get_header(checklist->request->headers, "Proxy-authorization:");
+ if (s == NULL)
+ return 0;
+ if (strlen(s) < SKIP_BASIC_SZ)
+ return 0;
+ s += SKIP_BASIC_SZ;
+ sent_auth = xstrdup(s); /* username and password */
+ /* Trim trailing \n before decoding */
+ strtok(sent_auth, "\n");
+ cleartext = uudecode(sent_auth);
+ xfree(sent_auth);
+ debug(28, 3) ("aclMatchProxyAuth: cleartext = '%s'\n", cleartext);
+ xstrncpy(sent_user, cleartext, ICP_IDENT_SZ);
+ xfree(cleartext);
+ strtok(sent_user, ":"); /* Remove :password */
+ debug(28, 5) ("aclMatchProxyAuth: checking user %s\n", sent_user);
+ /* reread password file if necessary */
+ aclReadProxyAuth(p);
+ hashr = hash_lookup(p->hash, sent_user);
+ if (hashr == NULL) {
+ /* User doesn't exist; deny them */
+ debug(28, 4) ("aclMatchProxyAuth: user %s does not exist\n", sent_user);
+ return 0;
+ }
+ passwd = strtok(sent_user, null_string);
+ passwd++;
+ /* See if we've already validated them */
+ passwd[0] |= 0x80;
+ if (strcmp(hashr->item, passwd) == 0) {
+ debug(28, 5) ("aclMatchProxyAuth: user %s previously validated\n",
+ sent_user);
+ return 1;
+ }
+ passwd[0] &= (~0x80);
+ if (strcmp(hashr->item, (char *) crypt(passwd, hashr->item))) {
+ /* Passwords differ, deny access */
+ debug(28, 4) ("aclMatchProxyAuth: authentication failed: user %s: "
+ "passwords differ\n", sent_user);
+ return 0;
+ }
+ passwd[0] |= 0x80;
+ debug(28, 5) ("proxyAuthenticate: user %s validated OK\n", sent_user);
+ hash_delete(p->hash, sent_user);
+ hash_insert(p->hash, xstrdup(sent_user), (void *) xstrdup(passwd));
+ return 1;
+}
+
static int
aclMatchInteger(intlist * data, int i)
{
return aclMatchInteger(acl->data, r->port);
/* NOTREACHED */
case ACL_USER:
- /* debug(28, 0)("aclMatchAcl: ACL_USER unimplemented\n"); */
- /* return 0; */
return aclMatchIdent(acl->data, checklist->ident);
/* NOTREACHED */
case ACL_PROTO:
case ACL_BROWSER:
return aclMatchRegex(acl->data, checklist->browser);
/* NOTREACHED */
+ case ACL_PROXY_AUTH:
+ if (!aclMatchProxyAuth(acl->data, checklist)) {
+ /* no such user OR we need a proxy authentication header */
+ checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_NEEDED;
+ return 0;
+ } else {
+ /* register that we used the proxy authentication header */
+ checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE;
+ return 1;
+ }
+ /* NOTREACHED */
case ACL_NONE:
default:
debug(28, 0) ("aclMatchAcl: '%s' has bad type %d\n",
}
}
+static void
+aclDestroyProxyAuth(struct _acl_proxy_auth *p)
+{
+ int i;
+ hash_link *hashr = NULL;
+ /* destroy hash list contents */
+ for (i = 0, hashr = hash_first(p->hash); hashr; hashr = hash_next(p->hash))
+ hash_delete(p->hash, hashr->key);
+ /* destroy and free the hash table itself */
+ hashFreeMemory(p->hash);
+ p->hash = NULL;
+ safe_free(p->filename);
+ safe_free(p);
+}
+
void
aclDestroyAcls(acl ** head)
{
case ACL_METHOD:
intlistDestroy((intlist **) & a->data);
break;
+ case ACL_PROXY_AUTH:
+ aclDestroyProxyAuth(a->data);
+ break;
case ACL_NONE:
default:
fatal_dump("aclDestroyAcls: Found ACL_NONE?");
#endif /* USE_BIN_TREE || SPLAY_TREE */
+/* Original ProxyAuth code by Jon Thackray <jrmt@uk.gdscorp.com> */
+/* Generalized to ACL's by Arjan.deVet <Arjan.deVet@adv.IAEhv.nl> */
+static int
+aclReadProxyAuth(struct _acl_proxy_auth *p)
+{
+ struct stat buf;
+ static char *passwords = NULL;
+ char *user = NULL;
+ char *passwd = NULL;
+ int i;
+ hash_link *hashr = NULL;
+ FILE *f = NULL;
+ if ((squid_curtime - p->last_time) >= p->check_interval) {
+ if (stat(p->filename, &buf) == 0) {
+ if (buf.st_mtime != p->change_time) {
+ debug(28, 1) ("aclReadProxyAuth: reloading changed proxy authentication file %s\n", p->filename);
+ p->change_time = buf.st_mtime;
+ if (p->hash != 0) {
+ debug(28, 5) ("aclReadProxyAuth: invalidating old entries\n");
+ for (i = 0, hashr = hash_first(p->hash); hashr; hashr = hash_next(p->hash)) {
+ debug(28, 6) ("aclReadProxyAuth: deleting %s\n", hashr->key);
+ hash_delete(p->hash, hashr->key);
+ }
+ } else {
+ /* First time around, 7921 should be big enough */
+ if ((p->hash = hash_create(urlcmp, 7921, hash_string)) < 0) {
+ debug(28, 0) ("aclReadProxyAuth: can't create hash table, turning auth off\n");
+ return 0;
+ }
+ }
+ passwords = xmalloc((size_t) buf.st_size + 2);
+ f = fopen(p->filename, "r");
+ fread(passwords, (size_t) buf.st_size, 1, f);
+ *(passwords + buf.st_size) = '\0';
+ strcat(passwords, "\n");
+ fclose(f);
+ user = strtok(passwords, ":");
+ passwd = strtok(NULL, "\n");
+ debug(28, 5) ("aclReadProxyAuth: adding new passwords to hash table\n");
+ while (user != NULL) {
+ if (strlen(user) > 1 && passwd && strlen(passwd) > 1) {
+ debug(28, 6) ("aclReadProxyAuth: adding %s, %s to hash table\n", user, passwd);
+ hash_insert(p->hash, xstrdup(user), (void *) xstrdup(passwd));
+ }
+ user = strtok(NULL, ":");
+ passwd = strtok(NULL, "\n");
+ }
+ xfree(passwords);
+ } else {
+ debug(28, 5) ("aclReadProxyAuth: %s not changed (old=%d,new=%d)\n",
+ p->filename, p->change_time, buf.st_mtime);
+ }
+ } else {
+ debug(28, 0) ("aclReadProxyAuth: can't access proxy_auth file %s, turning authentication off\n", p->filename);
+ return 0;
+ }
+ p->last_time = squid_curtime;
+ }
+ return 1;
+}
+
+
/* compare a host and a domain */
#if defined(USE_SPLAY_TREE)
acl aclname user username ... # string match on ident output.
# use REQUIRED to accept any
# non-null ident.
+ acl aclname proxy_auth passwd_file [ refresh ]
+ # 'passwd_file' is an Apache-style file of passwords for
+ # authenticated proxy access. Looks like user:password, with
+ # the password being standard crypt() format. 'refresh' is
+ # the time in seconds to check for a changes in the file
+ # (default = 300 secs). When using a proxy_auth ACL in an
+ # ACL list, make sure it is the *last* in the list and the
+ # only proxy_auth ACL in the list. NOTE: when a
+ # Proxy-Authentication header is sent but it is not needed
+ # during ACL checking the username is NOT logged in
+ # access.log.
acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255
tcp_recv_bufsize 0 bytes
DOC_END
-NAME: proxy_auth_passwd
-TYPE: string
-LOC: Config.proxyAuth.File
-DEFAULT: none
-DOC_NONE
-
-NAME: proxy_auth_ignore
-TYPE: regexlist
-LOC: Config.proxyAuth.IgnoreDomains
-DEFAULT: none
-DOC_START
- 'passwd_file' is an apache-style file of passwords for
- authenticated proxy access Looks like user:password, with the
- password being standard crypt() format. Proxy authentication
- is disabled by default.
-
- 'proxy_auth_ignore' is a regular-expression list of domain names
- (source or destination??)
- for which authorization will *not* be required.
-
- NOTE, proxy_auth support is not compiled into Squid by default.
- To use this feature you must enable the USE_PROXY_AUTH option
- near the top of src/Makefile.
-
- Insert -i to get case-insensitive regular expressions.
-
-proxy_auth_passwd /dev/null
-proxy_auth_ignore
-DOC_END
-
-
NAME: err_html_text
TYPE: eol
LOC: Config.errHtmlText
+
/*
- * $Id: client.cc,v 1.28 1997/08/25 22:35:51 wessels Exp $
+ * $Id: client.cc,v 1.29 1997/08/25 23:45:24 wessels Exp $
*
* DEBUG: section 0 WWW Client
* AUTHOR: Harvest Derived
/*
- * $Id: client_side.cc,v 1.124 1997/08/25 16:37:18 wessels Exp $
+ * $Id: client_side.cc,v 1.125 1997/08/25 23:45:25 wessels Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
static int clientGetsOldEntry _PARAMS((StoreEntry * new, StoreEntry * old, request_t * request));
static int checkAccelOnly _PARAMS((clientHttpRequest *));
-#if USE_PROXY_AUTH
-/* ProxyAuth code by Jon Thackray <jrmt@uk.gdscorp.com> */
-/* return 1 if allowed, 0 if denied */
-static int
-clientProxyAuthCheck(clientHttpRequest * http)
-{
- const char *proxy_user;
-
- /* Check that the user is allowed to access via this proxy-cache
- * don't restrict if they're accessing a local domain or
- * an object of type cacheobj:// */
- if (Config.proxyAuth.File == NULL)
- return 1;
- if (urlParseProtocol(http->url) == PROTO_CACHEOBJ)
- return 1;
-
- if (Config.proxyAuth.IgnoreDomains) {
- if (aclMatchRegex(Config.proxyAuth.IgnoreDomains, http->request->host)) {
- debug(33, 2) ("clientProxyAuthCheck: host \"%s\" matched proxyAuthIgnoreDomains\n", http->request->host);
- return 1;
- }
- }
- proxy_user = proxyAuthenticate(http->request_hdr);
- xstrncpy(http->ident.ident, proxy_user, ICP_IDENT_SZ);
- debug(33, 6) ("clientProxyAuthCheck: user = %s\n", http->ident.ident);
-
- if (strcmp(http->ident.ident, dash_str) == 0)
- return 0;
- return 1;
-}
-#endif /* USE_PROXY_AUTH */
-
static int
checkAccelOnly(clientHttpRequest * http)
{
identStart(-1, conn, clientAccessCheck);
return;
}
-#if USE_PROXY_AUTH
- if (clientProxyAuthCheck(http) == 0) {
- char *wbuf = NULL;
- int fd = conn->fd;
- debug(33, 4) ("Proxy Denied: %s\n", http->url);
- http->log_type = ERR_PROXY_DENIED;
- http->http_code = 407;
- wbuf = xstrdup(proxy_denied_msg(http->http_code,
- http->request->method,
- http->url,
- fd_table[fd].ipaddr));
- icpSendERROR(fd, http->log_type, wbuf, conn, http->http_code);
- safe_free(http->aclChecklist);
- return;
- }
-#endif /* USE_PROXY_AUTH */
if (checkAccelOnly(http)) {
clientAccessCheckDone(0, http);
return;
icpProcessRequest(fd, http);
}
-#if USE_PROXY_AUTH
-/* Check the modification time on the file that holds the proxy
- * passwords every 'n' seconds, and if it has changed, reload it
- */
-#define CHECK_PROXY_FILE_TIME 300
-
-const char *
-proxyAuthenticate(const char *headers)
-{
- /* Keep the time measurements and the hash
- * table of users and passwords handy */
- static time_t last_time = 0;
- static time_t change_time = 0;
- static hash_table *validated = NULL;
- static char *passwords = NULL;
- LOCAL_ARRAY(char, sent_user, ICP_IDENT_SZ);
-
- char *s = NULL;
- char *sent_userandpw = NULL;
- char *user = NULL;
- char *passwd = NULL;
- char *clear_userandpw = NULL;
- struct stat buf;
- int i;
- hash_link *hashr = NULL;
- FILE *f = NULL;
-
- /* Look for Proxy-authorization: Basic in the
- * headers sent by the client
- */
- if ((s = mime_get_header(headers, "Proxy-authorization:")) == NULL) {
- debug(33, 5) ("proxyAuthenticate: Can't find authorization header\n");
- return (dash_str);
- }
- /* Skip the 'Basic' part */
- s += strlen(" Basic");
- sent_userandpw = xstrdup(s);
- strtok(sent_userandpw, "\n"); /* Trim trailing \n before decoding */
- clear_userandpw = uudecode(sent_userandpw);
- xfree(sent_userandpw);
-
- xstrncpy(sent_user, clear_userandpw, ICP_IDENT_SZ);
- strtok(sent_user, ":"); /* Remove :password */
- debug(33, 5) ("proxyAuthenticate: user = %s\n", sent_user);
-
- /* Look at the Last-modified time of the proxy.passwords
- * file every five minutes, to see if it's been changed via
- * a cgi-bin script, etc. If so, reload a fresh copy into memory
- */
-
- if ((squid_curtime - last_time) > CHECK_PROXY_FILE_TIME) {
- debug(33, 5) ("proxyAuthenticate: checking password file %s hasn't changed\n", Config.proxyAuth.File);
-
- if (stat(Config.proxyAuth.File, &buf) == 0) {
- if (buf.st_mtime != change_time) {
- debug(33, 0) ("proxyAuthenticate: reloading changed proxy authentication password file %s \n", Config.proxyAuth.File);
- change_time = buf.st_mtime;
-
- if (validated != 0) {
- debug(33, 5) ("proxyAuthenticate: invalidating old entries\n");
- for (i = 0, hashr = hash_first(validated); hashr; hashr = hash_next(validated)) {
- debug(33, 6) ("proxyAuthenticate: deleting %s\n", hashr->key);
- hash_delete(validated, hashr->key);
- }
- } else {
- /* First time around, 7921 should be big enough */
- if ((validated = hash_create(urlcmp, 7921, hash_string)) < 0) {
- debug(33, 1) ("ERK: can't create hash table. Turning auth off");
- xfree(Config.proxyAuth.File);
- Config.proxyAuth.File = NULL;
- return (dash_str);
- }
- }
-
- passwords = xmalloc((size_t) buf.st_size + 2);
- f = fopen(Config.proxyAuth.File, "r");
- fread(passwords, (size_t) buf.st_size, 1, f);
- *(passwords + buf.st_size) = '\0';
- strcat(passwords, "\n");
- fclose(f);
-
- user = strtok(passwords, ":");
- passwd = strtok(NULL, "\n");
-
- debug(33, 5) ("proxyAuthenticate: adding new passwords to hash table\n");
- while (user != NULL) {
- if (strlen(user) > 1 && passwd && strlen(passwd) > 1) {
- debug(33, 6) ("proxyAuthenticate: adding %s, %s to hash table\n", user, passwd);
- hash_insert(validated, xstrdup(user), (void *) xstrdup(passwd));
- }
- user = strtok(NULL, ":");
- passwd = strtok(NULL, "\n");
- }
-
- xfree(passwords);
- }
- } else {
- debug(33, 1) ("ERK: can't access proxy_auth file %s. Turning authentication off", Config.proxyAuth.File);
- xfree(Config.proxyAuth.File);
- Config.proxyAuth.File = NULL;
- return (dash_str);
- }
- last_time = squid_curtime;
- }
- hashr = hash_lookup(validated, sent_user);
- if (hashr == NULL) {
- /* User doesn't exist; deny them */
- debug(33, 4) ("proxyAuthenticate: user %s doesn't exist\n", sent_user);
- xfree(clear_userandpw);
- return (dash_str);
- }
- passwd = strstr(clear_userandpw, ":");
- passwd++;
-
- /* See if we've already validated them */
- passwd[0] |= 0x80; /* check mutated password */
- if (strcmp(hashr->item, passwd) == 0) {
- debug(33, 5) ("proxyAuthenticate: user %s previously validated\n", sent_user);
- xfree(clear_userandpw);
- return sent_user;
- }
- passwd[0] &= ~(0x80); /* check vs crypt */
- if (strcmp(hashr->item, (char *) crypt(passwd, hashr->item))) {
- /* Passwords differ, deny access */
- debug(33, 4) ("proxyAuthenticate: authentication failed: user %s passwords differ\n", sent_user);
- xfree(clear_userandpw);
- return (dash_str);
- }
- passwd[0] |= 0x80; /* store mutated password away */
- debug(33, 5) ("proxyAuthenticate: user %s validated\n", sent_user);
- hash_delete(validated, sent_user);
- hash_insert(validated, xstrdup(sent_user), xstrdup(passwd));
-
- xfree(clear_userandpw);
- return (sent_user);
-}
-#endif /* USE_PROXY_AUTH */
-
void
icpProcessExpired(int fd, void *data)
{
ACL_PROTO,
ACL_METHOD,
ACL_BROWSER,
+ ACL_PROXY_AUTH,
ACL_ENUM_MAX
} squid_acl;
/*
- * $Id: fqdncache.cc,v 1.58 1997/07/26 04:48:28 wessels Exp $
+ * $Id: fqdncache.cc,v 1.59 1997/08/25 23:45:26 wessels Exp $
*
* DEBUG: section 35 FQDN Cache
* AUTHOR: Harvest Derived
}
xfree(list);
hashFreeMemory(fqdn_table);
+ fqdn_table = NULL;
}
static void
/*
- * $Id: http.cc,v 1.185 1997/08/25 22:35:55 wessels Exp $
+ * $Id: http.cc,v 1.186 1997/08/25 23:45:27 wessels Exp $
*
* DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
* AUTHOR: Harvest Derived
debug(11, 5) ("httpBuildRequestHeader: %s\n", xbuf);
if (strncasecmp(xbuf, "Proxy-Connection:", 17) == 0)
continue;
-#if USE_PROXY_AUTH
if (strncasecmp(xbuf, "Proxy-authorization:", 20) == 0)
+ /* If we're not going to do proxy auth, then it must be passed on */
if (Config.proxyAuth.File)
continue;
-#endif
if (strncasecmp(xbuf, "Connection:", 11) == 0)
continue;
if (strncasecmp(xbuf, "Host:", 5) == 0) {
/*
- * $Id: ipcache.cc,v 1.128 1997/07/16 20:32:11 wessels Exp $
+ * $Id: ipcache.cc,v 1.129 1997/08/25 23:45:28 wessels Exp $
*
* DEBUG: section 14 IP Cache
* AUTHOR: Harvest Derived
}
xfree(list);
hashFreeMemory(ip_table);
+ ip_table = NULL;
}
static void
/*
- * $Id: net_db.cc,v 1.47 1997/08/25 02:26:04 wessels Exp $
+ * $Id: net_db.cc,v 1.48 1997/08/25 23:45:29 wessels Exp $
*
* DEBUG: section 37 Network Measurement Database
* AUTHOR: Duane Wessels
xfree(L2);
hashFreeMemory(addr_table);
hashFreeMemory(host_table);
+ addr_table = NULL;
+ host_table = NULL;
wordlistDestroy(&peer_names);
peer_names = NULL;
peer_names_tail = &peer_names;
/*
- * $Id: store.cc,v 1.283 1997/08/25 22:36:01 wessels Exp $
+ * $Id: store.cc,v 1.284 1997/08/25 23:45:30 wessels Exp $
*
* DEBUG: section 20 Storeage Manager
* AUTHOR: Harvest Derived
destroy_StoreEntry(*(list + j));
xfree(list);
hashFreeMemory(store_table);
+ store_table = NULL;
safe_free(MaintBucketsOrder);
}
struct _acl_name_list *next;
};
+struct _acl_proxy_auth {
+ char *filename;
+ time_t last_time;
+ time_t change_time;
+ int check_interval;
+ hash_table *hash;
+};
+
struct _acl_deny_info_list {
char url[MAX_URL];
struct _acl_name_list *acl_list;
char *useragent;
int rotateNumber;
} Log;
- struct {
- char *File;
- relist *IgnoreDomains;
- } proxyAuth;
char *adminEmail;
char *effectiveUser;
char *effectiveGroup;