From: wessels <> Date: Tue, 27 Aug 1996 04:47:45 +0000 (+0000) Subject: added proxy authentication patch from Jon Thackray X-Git-Tag: SQUID_3_0_PRE1~5919 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e81957b7e088ee7261af8f7e86ec1dd8fc72708c;p=thirdparty%2Fsquid.git added proxy authentication patch from Jon Thackray --- diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 0e72c8abfe..141fb8f33c 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,5 +1,4 @@ -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 Daniel O'Callaghan @@ -30,6 +29,7 @@ and ideas to make this software available. Russell Street Cord Beermann Stephen R. van den Berg + Jon Thackray Development of this caching software is funded by the National Science diff --git a/include/util.h b/include/util.h index ee28cc6cdc..6cf0f81c4c 100644 --- a/include/util.h +++ b/include/util.h @@ -1,5 +1,5 @@ /* - * $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 * @@ -199,4 +199,6 @@ extern void errorlog(); extern void Tolower _PARAMS((char *)); +extern char *uudecode _PARAMS((char *)); + #endif /* ndef _UTIL_H_ */ diff --git a/lib/Makefile.in b/lib/Makefile.in index 0e2aefd8f5..6e1adbacc2 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -3,7 +3,7 @@ # # 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@ @@ -27,7 +27,8 @@ UTILOBJS = rfc850.o \ debug.o \ log.o \ tempnam.o \ - base64.o + base64.o \ + uudecode.o REGEXOBJS = GNUregex.o LIBS = libmiscutil.a libregex.a diff --git a/lib/uudecode.c b/lib/uudecode.c new file mode 100644 index 0000000000..c615f00836 --- /dev/null +++ b/lib/uudecode.c @@ -0,0 +1,65 @@ +#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; +} diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 6378d268fa..9651d9a3ba 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -1,5 +1,5 @@ /* - * $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 @@ -145,6 +145,10 @@ struct SquidConfig Config; #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 @@ -667,6 +671,22 @@ static void parseDirLine() 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; @@ -1196,6 +1216,11 @@ int parseConfigFile(file_name) 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); @@ -1386,6 +1411,10 @@ static void configFreeMemory() 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); @@ -1463,6 +1492,10 @@ static void configSetFactoryDefaults() 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; diff --git a/src/client_side.cc b/src/client_side.cc index 086bbcd3ef..aafb67a809 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -1,6 +1,6 @@ /* - * $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 @@ -74,6 +74,33 @@ static void clientLookupIdentDone(data) { } +#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)); @@ -81,11 +108,28 @@ void clientAccessCheck(icpState, handler) 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) { @@ -161,4 +205,146 @@ static void clientRedirectDone(data, result) (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 */ } diff --git a/src/errorpage.cc b/src/errorpage.cc index 925284c462..deec1c6328 100644 --- a/src/errorpage.cc +++ b/src/errorpage.cc @@ -1,6 +1,6 @@ /* - * $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 @@ -127,7 +127,11 @@ static char *auth_msg = NULL; 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; @@ -317,3 +321,49 @@ WWW-Authenticate: Basic realm=\"%s\"\r\n\ 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\ +Cache Access Denied\n\ +

Cache Access Denied

\n\ +

\n\ +Sorry, you are not currently allowed to request\n\ +

    %s
\n\ +from this cache until you have authenticated yourself.\n\ +\n

\ +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 cache administrator\n\ +if you have difficulties authenticating yourself, or\n\ +change\n\ +your default password.\n\ +

\n\ +%s\n\ +


\n\ +
\n\ +Generated by %s/%s@%s\n\ +
\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; +} + diff --git a/src/main.cc b/src/main.cc index 7c4301c086..2324b04c45 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,5 +1,5 @@ /* - * $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 @@ -127,6 +127,7 @@ char version_string[] = SQUID_VERSION; 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 *)); diff --git a/src/redirect.cc b/src/redirect.cc index 472a0f64a0..f700cb6fc8 100644 --- a/src/redirect.cc +++ b/src/redirect.cc @@ -1,5 +1,5 @@ /* - * $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 @@ -83,7 +83,6 @@ static int NRedirectors = 0; static int NRedirectorsOpen = 0; static struct redirectQueueData *redirectQueueHead = NULL; static struct redirectQueueData **redirectQueueTailP = &redirectQueueHead; -static char *dash_str = "-"; static int redirectCreateRedirector(command) char *command; diff --git a/src/squid.h b/src/squid.h index a50439f801..af6c0ada97 100644 --- a/src/squid.h +++ b/src/squid.h @@ -1,6 +1,6 @@ /* - * $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 * @@ -293,3 +293,4 @@ extern void ttlAddToList _PARAMS((char *, time_t, int, time_t)); 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; diff --git a/src/stat.cc b/src/stat.cc index 43b1dc5bad..2214cb320f 100644 --- a/src/stat.cc +++ b/src/stat.cc @@ -1,5 +1,5 @@ /* - * $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 @@ -882,10 +882,9 @@ void log_append(obj, url, caddr, size, action, method, http_code, msec, ident, h { 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) @@ -896,14 +895,14 @@ void log_append(obj, url, caddr, size, action, method, http_code, msec, ident, h 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) {