-Special thanks go to people who have volunteered their time, effort,
-and ideas to make this software available.
+Special thanks go to people who have volunteered their time, effort, and ideas to make this software available.
Henrik Nordstrom <henrik.nordstrom@ida.his.se>
Daniel O'Callaghan <danny@miriworld.its.unimelb.EDU.AU>
Russell Street <r.street@auckland.ac.nz>
Cord Beermann <webadm@cc.fh-lippe.de>
Stephen R. van den Berg <srb@cuci.nl>
+ Jon Thackray <jrmt@uk.gdscorp.com>
Development of this caching software is funded by the National Science
/*
- * $Id: util.h,v 1.9 1996/08/26 19:56:59 wessels Exp $
+ * $Id: util.h,v 1.10 1996/08/26 22:47:46 wessels Exp $
*
* AUTHOR: Harvest Derived
*
extern void Tolower _PARAMS((char *));
+extern char *uudecode _PARAMS((char *));
+
#endif /* ndef _UTIL_H_ */
#
# Darren Hardy, hardy@cs.colorado.edu, April 1994
#
-# $Id: Makefile.in,v 1.11 1996/08/26 19:57:00 wessels Exp $
+# $Id: Makefile.in,v 1.12 1996/08/26 22:47:47 wessels Exp $
#
prefix = @prefix@
srcdir = @srcdir@
debug.o \
log.o \
tempnam.o \
- base64.o
+ base64.o \
+ uudecode.o
REGEXOBJS = GNUregex.o
LIBS = libmiscutil.a libregex.a
--- /dev/null
+#include "util.h"
+
+extern char** environ;
+
+/* aaaack but it's fast and const should make it shared text page. */
+const int pr2six[256]={
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
+ 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
+ 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
+ 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64
+};
+
+char *uudecode(char *bufcoded) {
+ int nbytesdecoded;
+ register unsigned char *bufin;
+ register char *bufplain;
+ register unsigned char *bufout;
+ register int nprbytes;
+
+ /* Strip leading whitespace. */
+
+ while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
+
+ /* Figure out how many characters are in the input buffer.
+ * Allocate this many from the per-transaction pool for the result.
+ */
+ bufin = (unsigned char *)bufcoded;
+ while(pr2six[*(bufin++)] <= 63);
+ nprbytes = (char *)bufin - bufcoded - 1;
+ nbytesdecoded = ((nprbytes+3)/4) * 3;
+
+ bufplain = xmalloc(nbytesdecoded + 1);
+ if (bufplain == NULL)
+ return(NULL);
+ bufout = (unsigned char *)bufplain;
+
+ bufin = (unsigned char *)bufcoded;
+
+ while (nprbytes > 0) {
+ *(bufout++) =
+ (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
+ *(bufout++) =
+ (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
+ *(bufout++) =
+ (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
+ bufin += 4;
+ nprbytes -= 4;
+ }
+
+ if(nprbytes & 03) {
+ if(pr2six[bufin[-2]] > 63)
+ nbytesdecoded -= 2;
+ else
+ nbytesdecoded -= 1;
+ }
+ bufplain[nbytesdecoded] = '\0';
+ return bufplain;
+}
/*
- * $Id: cache_cf.cc,v 1.71 1996/08/26 22:00:04 wessels Exp $
+ * $Id: cache_cf.cc,v 1.72 1996/08/26 22:47:49 wessels Exp $
*
* DEBUG: section 3 Configuration File Parsing
* AUTHOR: Harvest Derived
#define DefaultCacheLogFile DEFAULT_CACHE_LOG
#define DefaultAccessLogFile DEFAULT_ACCESS_LOG
#define DefaultStoreLogFile DEFAULT_STORE_LOG
+#if USE_PROXY_AUTH
+#define DefaultProxyAuthFile (char *)NULL /* default NONE */
+#define DefaultProxyAuthIgnoreDomain "none-at-all"
+#endif /* USE_PROXY_AUTH */
#define DefaultLogRotateNumber 10
#define DefaultAdminEmail "webmaster"
#define DefaultFtpgetProgram DEFAULT_FTPGET
wordlistAdd(&Config.cache_dirs, token);
}
+#if USE_PROXY_AUTH
+static void parseProxyAuthLine()
+{
+ char *token;
+
+ token = strtok(NULL, w_space);
+ if (token == NULL)
+ self_destruct();
+ safe_free(Config.proxyAuthFile);
+ safe_free(Config.proxyAuthIgnoreDomain);
+ Config.proxyAuthFile = xstrdup(token);
+ if ((token = strtok(NULL, w_space)))
+ Config.proxyAuthIgnoreDomain = xstrdup(token);
+}
+#endif /* USE_PROXY_AUTH */
+
static void parseHttpdAccelLine()
{
char *token;
else if (!strcmp(token, "redirect_children"))
parseIntegerValue(&Config.redirectChildren);
+#if USE_PROXY_AUTH
+ else if (!strcmp(token, "proxy_authentication"))
+ parseProxyAuthLine();
+#endif /* USE_PROXY_AUTH */
+
else if (!strcmp(token, "source_ping"))
parseOnOff(&Config.sourcePing);
safe_free(Config.pidFilename);
safe_free(Config.visibleHostname);
safe_free(Config.ftpUser);
+#if USE_PROXY_AUTH
+ safe_free(Config.proxyAuthFile);
+ safe_free(Config.proxyAuthIgnoreDomain);
+#endif /* USE_PROXY_AUTH */
safe_free(Config.Announce.host);
safe_free(Config.Announce.file);
safe_free(Config.errHtmlText);
Config.Accel.withProxy = DefaultAccelWithProxy;
Config.pidFilename = safe_xstrdup(DefaultPidFilename);
Config.visibleHostname = safe_xstrdup(DefaultVisibleHostname);
+#if USE_PROXY_AUTH
+ Config.proxyAuthFile = safe_xstrdup(DefaultProxyAuthFile);
+ Config.proxyAuthIgnoreDomain = safe_xstrdup(DefaultProxyAuthIgnoreDomain);
+#endif /* USE_PROXY_AUTH */
Config.ftpUser = safe_xstrdup(DefaultFtpUser);
Config.Announce.host = safe_xstrdup(DefaultAnnounceHost);
Config.Announce.port = DefaultAnnouncePort;
/*
- * $Id: client_side.cc,v 1.9 1996/08/20 15:44:17 wessels Exp $
+ * $Id: client_side.cc,v 1.10 1996/08/26 22:47:50 wessels Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
{
}
+#if USE_PROXY_AUTH
+/* return 1 if allowed, 0 if denied */
+static int clientProxyAuthCheck(icpState)
+ icpStateData *icpState;
+{
+ 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.proxyAuthFile == NULL)
+ return 1;
+ if (strstr(icpState->url, Config.proxyAuthIgnoreDomain))
+ return 1;
+ if (urlParseProtocol(icpState->url) == PROTO_CACHEOBJ)
+ return 1;
+
+ proxy_user = proxyAuthenticate(icpState->request_hdr);
+ strncpy(icpState->ident, proxy_user, ICP_IDENT_SZ);
+ debug(12, 6, "jrmt: user = %s\n", icpState->ident);
+
+ if (strcmp(icpState->ident, dash_str) == 0)
+ return 0;
+ return 1;
+}
+#endif /* USE_PROXY_AUTH */
+
void clientAccessCheck(icpState, handler)
icpStateData *icpState;
void (*handler) _PARAMS((icpStateData *, int));
int answer = 1;
request_t *r = icpState->request;
aclCheck_t *ch = NULL;
+
if (icpState->aclChecklist == NULL) {
icpState->aclChecklist = xcalloc(1, sizeof(aclCheck_t));
icpState->aclChecklist->src_addr = icpState->peer.sin_addr;
icpState->aclChecklist->request = requestLink(icpState->request);
}
+#if USE_PROXY_AUTH
+ if (clientProxyAuthCheck == 0) {
+ char *wbuf = NULL;
+ int fd = icpState->fd;
+ debug(12, 4, "Proxy Denied: %s\n", icpState->url);
+ icpState->log_type = ERR_PROXY_DENIED;
+ icpState->http_code = 407;
+ wbuf = xstrdup(proxy_denied_msg(icpState->http_code,
+ icpState->method,
+ icpState->url,
+ fd_table[fd].ipaddr));
+ icpSendERROR(fd, icpState->log_type, wbuf, icpState, icpState->http_code);
+ return;
+ }
+#endif /* USE_PROXY_AUTH */
+
ch = icpState->aclChecklist;
icpState->aclHandler = handler;
if (httpd_accel_mode && !Config.Accel.withProxy && r->protocol != PROTO_CACHEOBJ) {
(PF) icpDetectClientClose,
(void *) icpState);
icp_hit_or_miss(fd, icpState);
+#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
+
+char *proxyAuthenticate(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 HashID validated = 0;
+ 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;
+ time_t current_time;
+ struct stat buf;
+ int i;
+ hash_link *hashr = NULL;
+ FILE *f = NULL;
+
+ /* Look for Proxy-[Aa]uthorization: Basic in the
+ * headers sent by the client
+ */
+ if ((s = mime_get_header(headers, "Proxy-authorization:")) == NULL) {
+ /* Check for MS Internet Explorer too, as well as Netscape
+ * FIXME: Need a version of mime_get_header that uses strcasecmp()
+ */
+ if ((s = mime_get_header(headers, "Proxy-Authorization:")) == NULL) {
+ debug(12, 5, "jrmt: 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);
+
+ strncpy(sent_user, clear_userandpw, ICP_IDENT_SZ);
+ strtok(sent_user, ":"); /* Remove :password */
+ debug(12, 5, "jrmt: user = %s\n", sent_user);
+
+ /* Look at the Last-modified time of the proxy.passwords
+ * file every ten seconds, to see if it's been changed via
+ * a cgi-bin script, etc. If so, reload a fresh copy into memory
+ */
+
+ current_time = time(NULL);
+
+ if ((current_time - last_time) > CHECK_PROXY_FILE_TIME) {
+ debug(12, 5, "jrmt: checking password file %s hasn't changed\n", Config.proxyAuthFile);
+
+ if (stat(Config.proxyAuthFile, &buf) == 0) {
+ if (buf.st_mtime != change_time) {
+ debug(12, 0, "jrmt: reloading changed proxy authentication password file %s \n", Config.proxyAuthFile);
+ change_time = buf.st_mtime;
+
+ if (passwords != NULL)
+ xfree(passwords);
+
+ if (validated != 0) {
+ debug(12, 5, "jrmt: invalidating old entries\n");
+ for (i = 0, hashr = hash_first(validated); hashr; hashr = hash_next(validated)) {
+ debug(12, 6, "jrmt: deleting %s\n", hashr->key);
+ hash_delete(validated, hashr->key);
+ }
+ } else {
+ /* First time around, 7921 should be big enough for GDS :-) */
+ if ((validated = hash_create(urlcmp, 7921, hash_string)) < 0) {
+ debug(1, 1, "ERK: can't create hash table. Turning auth off");
+ Config.proxyAuthOn = 0;
+ return (dash_str);
+ }
+ }
+
+ passwords = xmalloc((size_t) buf.st_size + 2);
+ f = fopen(Config.proxyAuthFile, "r");
+ fread(passwords, buf.st_size, 1, f);
+ *(passwords + buf.st_size) = '\0';
+ strcat(passwords, "\n");
+ fclose(f);
+
+ user = strtok(passwords, ":");
+ passwd = strtok(NULL, "\n");
+
+ debug(12, 5, "jrmt: adding new passwords to hash table\n");
+ while (user != NULL) {
+ if (strlen(user) > 1 && strlen(passwd) > 1) {
+ debug(12, 6, "jrmt: adding %s, %s to hash table\n", user, passwd);
+ hash_insert(validated, user, (void *) passwd);
+ }
+ user = strtok(NULL, ":");
+ passwd = strtok(NULL, "\n");
+ }
+ }
+ } else {
+ debug(1, 1, "ERK: can't access proxy_auth_file %s. Turning authentication off until SIGHUPed", Config.proxyAuthFile);
+ Config.proxyAuthOn = 0;
+ return (dash_str);
+ }
+ }
+ last_time = current_time;
+
+ hashr = hash_lookup(validated, sent_user);
+ if (hashr == NULL) {
+ /* User doesn't exist; deny them */
+ debug(12, 4, "jrmt: user %s doesn't exist\n", sent_user);
+ xfree(clear_userandpw);
+ return (dash_str);
+ }
+ /* See if we've already validated them */
+ if (strcmp(hashr->item, "OK") == 0) {
+ debug(12, 5, "jrmt: user %s previously validated\n", sent_user);
+ xfree(clear_userandpw);
+ return sent_user;
+ }
+ passwd = strstr(clear_userandpw, ":");
+ passwd++;
+
+ if (strcmp(hashr->item, (char *) crypt(passwd, hashr->item))) {
+ /* Passwords differ, deny access */
+ debug(12, 4, "jrmt: authentication failed: user %s passwords differ\n", sent_user);
+ debug(12, 6, "jrmt: password given: %s, actual %s\n", passwd, hashr->item);
+ xfree(clear_userandpw);
+ return (dash_str);
+ }
+ debug(12, 5, "jrmt: user %s validated\n", sent_user);
+ hash_insert(validated, sent_user, (void *) "OK");
+
+ xfree(clear_userandpw);
+ return (sent_user);
+#endif /* USE_PROXY_AUTH */
}
/*
- * $Id: errorpage.cc,v 1.31 1996/08/26 19:09:59 wessels Exp $
+ * $Id: errorpage.cc,v 1.32 1996/08/26 22:47:51 wessels Exp $
*
* DEBUG: section 4 Error Generation
* AUTHOR: Duane Wessels
void errorInitialize()
{
+#ifndef USE_PROXY_AUTH
tmp_error_buf = xmalloc(MAX_URL * 4);
+#else
+ tmp_error_buf = xmalloc(8192);
+#endif /* USE_PROXY_AUTH */
meta_data.misc += MAX_URL * 4;
tbuf = xmalloc(MAX_URL * 3);
meta_data.misc += MAX_URL * 3;
tbuf, realm, auth_msg);
return tmp_error_buf;
}
+
+
+#define PROXY_AUTH_ERR_MSG "\
+HTTP/1.0 %d Cache Access Denied\r\n\
+Proxy-Authenticate: Basic realm=\"Squid proxy-caching web server\"\r\n\
+Content-type: text/html\r\n\
+\r\n\
+<TITLE>Cache Access Denied</TITLE>\n\
+<H2>Cache Access Denied</H2>\n\
+<P>\n\
+Sorry, you are not currently allowed to request\n\
+<PRE> %s</PRE>\n\
+from this cache until you have authenticated yourself.\n\
+\n<p>\
+You need to use Netscape version 2.0 or greater, or Microsoft Internet Explorer 3.0\n\
+or an HTTP/1.1 compliant browser for this to work.\n\
+Please contact the <a href=\"mailto:%s\">cache administrator</a>\n\
+if you have difficulties authenticating yourself, or\n\
+<a href=\"http://%s/cgi-bin/chpasswd.cgi\">change</a>\n\
+your default password.\n\
+<P>\n\
+%s\n\
+<HR>\n\
+<ADDRESS>\n\
+Generated by %s/%s@%s\n\
+</ADDRESS>\n\
+"
+
+char *proxy_denied_msg(code, method, url, client)
+ int code;
+ int method;
+ char *url;
+ char *client;
+{
+ sprintf(tmp_error_buf, PROXY_AUTH_ERR_MSG,
+ code,
+ url,
+ Config.adminEmail,
+ getMyHostname(),
+ Config.errHtmlText,
+ appname,
+ version_string,
+ getMyHostname());
+ return tmp_error_buf;
+}
+
/*
- * $Id: main.cc,v 1.62 1996/08/26 19:13:03 wessels Exp $
+ * $Id: main.cc,v 1.63 1996/08/26 22:47:54 wessels Exp $
*
* DEBUG: section 1 Startup and Main Loop
* AUTHOR: Harvest Derived
char appname[] = "squid";
char localhost[] = "127.0.0.1";
struct in_addr local_addr;
+char *dash_str = "-";
/* for error reporting from xmalloc and friends */
extern void (*failure_notify) _PARAMS((char *));
/*
- * $Id: redirect.cc,v 1.11 1996/08/20 15:44:18 wessels Exp $
+ * $Id: redirect.cc,v 1.12 1996/08/26 22:47:55 wessels Exp $
*
* DEBUG: section 29 Redirector
* AUTHOR: Duane Wessels
static int NRedirectorsOpen = 0;
static struct redirectQueueData *redirectQueueHead = NULL;
static struct redirectQueueData **redirectQueueTailP = &redirectQueueHead;
-static char *dash_str = "-";
static int redirectCreateRedirector(command)
char *command;
/*
- * $Id: squid.h,v 1.40 1996/08/26 22:00:07 wessels Exp $
+ * $Id: squid.h,v 1.41 1996/08/26 22:47:56 wessels Exp $
*
* AUTHOR: Duane Wessels
*
extern void ttlAddToForceList _PARAMS((char *, time_t, time_t));
extern int waisStart _PARAMS((int, char *, method_t, char *, StoreEntry *));
extern void storeDirClean _PARAMS((void));
+extern char *dash_str;
/*
- * $Id: stat.cc,v 1.53 1996/08/14 21:58:03 wessels Exp $
+ * $Id: stat.cc,v 1.54 1996/08/26 22:47:57 wessels Exp $
*
* DEBUG: section 18 Cache Manager Statistics
* AUTHOR: Harvest Derived
{
LOCAL_ARRAY(char, tmp, 6000); /* MAX_URL is 4096 */
int x;
- static char *dash = "-";
char *client = NULL;
hier_code hier_code = HIER_NONE;
- char *hier_host = dash;
+ char *hier_host = dash_str;
int hier_timeout = 0;
if (Config.Log.log_fqdn)
getCurrentTime();
if (!method)
- method = dash;
+ method = dash_str;
if (!url)
- url = dash;
+ url = dash_str;
if (!ident || ident[0] == '\0')
- ident = dash;
+ ident = dash_str;
if (hierData) {
hier_code = hierData->code;
- hier_host = hierData->host ? hierData->host : dash;
+ hier_host = hierData->host ? hierData->host : dash_str;
hier_timeout = hierData->timeout;
}
if (obj->logfile_status == LOG_ENABLE) {