diff -urwN squid-1.1.20-orig/src/Makefile.in squid-1.1.20/src/Makefile.in
--- squid-1.1.20-orig/src/Makefile.in Fri Oct 24 19:57:11 1997
+++ squid-1.1.20/src/Makefile.in Sat Mar 7 18:01:23 1998
@@ -73,13 +73,15 @@
DNSSERVER_LIBS = -L../lib -lmiscutil $(XTRA_LIBS)
FTPGET_LIBS = -L../lib -lmiscutil $(XTRA_LIBS)
PINGER_LIBS = -L../lib -lmiscutil $(XTRA_LIBS)
+AUTH_LIBS = -L../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
PROGS = squid client
-UTILS = dnsserver ftpget unlinkd
+UTILS = dnsserver ftpget unlinkd ncsa_auth
SUID_UTILS = pinger
CGIPROGS = cachemgr.cgi
OBJS = \
acl.o \
+ authenticate.o \
cache_cf.o \
client_db.o \
client_side.o \
@@ -164,6 +166,9 @@
unlinkd: unlinkd.c
$(CC) $(CFLAGS) -DUNLINK_DAEMON $(srcdir)/unlinkd.c -o $@ $(LDFLAGS)
+
+ncsa_auth: ncsa_auth.o hash.o
+ $(CC) -o $@ $(LDFLAGS) $@.o hash.o $(AUTH_LIBS)
squid.conf: squid.conf.pre Makefile
sed "\
diff -urwN squid-1.1.20-orig/src/acl.c squid-1.1.20/src/acl.c
--- squid-1.1.20-orig/src/acl.c Mon Nov 3 20:27:08 1997
+++ squid-1.1.20/src/acl.c Thu Feb 12 22:13:39 1998
@@ -171,6 +171,10 @@
return ACL_METHOD;
if (!strcmp(s, "browser"))
return ACL_BROWSER;
+#ifdef USE_PROXY_AUTH
+ if (!strcmp(s, "proxy_auth"))
+ return ACL_PROXY_AUTH;
+#endif /* USE_PROXY_AUTH */
return ACL_NONE;
}
@@ -572,6 +576,42 @@
#endif /* USE_SPLAY_TREE */
+#ifdef USE_PROXY_AUTH
+
+/* default proxy_auth timeout is 3600 seconds */
+#define PROXY_AUTH_TIMEOUT 3600
+
+static void
+aclParseProxyAuth(void *data)
+{
+ struct _acl_proxy_auth *p;
+ struct _acl_proxy_auth **q = data;
+ char *t;
+
+ p = xcalloc(1, sizeof(struct _acl_proxy_auth));
+
+ /* read timeout value (if any) */
+ t = strtok(NULL, w_space);
+ if (t == NULL) {
+ p->timeout = PROXY_AUTH_TIMEOUT;
+ } else {
+ p->timeout = atoi(t);
+ }
+ /* the minimum timeout is 10 seconds */
+ if (p->timeout < 10)
+ p->timeout = 10;
+
+ /* First time around, 7921 should be big enough */
+ if ((p->hash = hash_create(urlcmp, 7921, hash_string)) < 0) {
+ debug(28, 0, "aclParseProxyAuth: can't create hash table, turning auth off\n");
+ *q = NULL;
+ return;
+ }
+ *q = p;
+ return;
+}
+#endif /* USE_PROXY_AUTH */
+
void
aclParseAclLine(void)
{
@@ -650,6 +690,11 @@
case ACL_BROWSER:
aclParseRegexList(&A->data, 0);
break;
+#ifdef USE_PROXY_AUTH
+ case ACL_PROXY_AUTH:
+ aclParseProxyAuth(&A->data);
+ break;
+#endif /* USE_PROXY_AUTH */
case ACL_NONE:
default:
debug_trap("Bad ACL type");
@@ -998,6 +1043,78 @@
return 0;
}
+#ifdef USE_PROXY_AUTH
+static int
+aclMatchProxyAuth(struct _acl_proxy_auth *p, struct _auth_r *auth)
+{
+ LOCAL_ARRAY(char, user, ICP_IDENT_SZ);
+ char *passwd = NULL;
+ hash_link *hashr = NULL;
+ struct _passwd_r *pwd;
+
+ /* do some basic checking on the basic authentication string */
+ if ((auth->basic == NULL) || (*auth->basic == '\0') ||
+ (strstr(auth->basic, ":") == NULL))
+ return 0;
+
+ /* separate user and password */
+ xstrncpy(user, auth->basic, ICP_IDENT_SZ);
+ passwd = strstr(user, ":");
+ *passwd = '\0';
+ passwd++;
+ debug(28, 5, "aclMatchProxyAuth: checking user %s\n", user);
+
+ hashr = hash_lookup(p->hash, user);
+ if (hashr == NULL) {
+ /* user not yet in hash, ask authenticator */
+ debug(28, 4, "aclMatchProxyAuth: user %s not yet in hash\n", user);
+ } else {
+ /* See if we've already validated this user before */
+ pwd = (struct _passwd_r *) hashr->item;
+ passwd[0] |= 0x80; /* check mutated password */
+ if ((strcmp(pwd->passwd, passwd) == 0) &&
+ (pwd->expiretime > current_time.tv_sec)) {
+ debug(28, 5, "aclMatchProxyAuth: user %s previously validated\n",
+ user);
+ return 1;
+ }
+ /* password mismatch/timeout, lookup password again for user */
+ passwd[0] &= ~(0x80); /* remove mutation */
+ debug(28, 4, "aclMatchProxyAuth: user %s passwd mismatch/timeout\n",
+ user);
+ xfree(pwd->passwd);
+ xfree(pwd);
+ hash_delete(p->hash, user);
+ }
+
+ if (auth->checked == -1) {
+ /* password was checked but didn't match */
+ debug(28, 4, "aclMatchProxyAuth: authenticate failed for user %s\n",
+ user);
+ return 0;
+ }
+
+ if (auth->checked == 0) {
+ /* password was not yet checked, force password check */
+ debug(28, 4, "aclMatchProxyAuth: user %s not yet checked\n", user);
+ return -1;
+ }
+
+ /* auth->checked == 1 */
+
+ debug(28, 5, "aclMatchProxyAuth: user %s validated OK, stored in hash\n",
+ user);
+ passwd[0] |= 0x80; /* store mutated password away */
+
+ pwd = xmalloc(sizeof(struct _passwd_r));
+ pwd->expiretime = current_time.tv_sec + p->timeout;
+ pwd->passwd = xstrdup(passwd);
+ hash_insert(p->hash, xstrdup(user), (void *) pwd);
+
+ return 1;
+}
+#endif /* USE_PROXY_AUTH */
+
static int
aclMatchInteger(intlist * data, int i)
{
@@ -1114,8 +1231,6 @@
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:
@@ -1127,6 +1242,29 @@
case ACL_BROWSER:
return aclMatchRegex(acl->data, checklist->browser);
/* NOTREACHED */
+#ifdef USE_PROXY_AUTH
+ case ACL_PROXY_AUTH:
+ /* checklist->auth containts user:passwd */
+ k = aclMatchProxyAuth(acl->data, &checklist->auth);
+ if (k == 0) {
+ /* No such user OR we need proxy authentication info;
+ This means that a 407 HTTP return code should be sent
+ to the client */
+ checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED;
+ return 0;
+ } else if (k == 1) {
+ /* user validated OK */
+ /* register that we used the proxy authentication header
+ so that it will be logged in access.log */
+ checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_USED;
+ return 1;
+ } else if (k == -1) {
+ /* register that we need to check the password */
+ checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_CHECK;
+ return 0; /* XXX */
+ }
+ /* NOTREACHED */
+#endif /* USE_PROXY_AUTH */
case ACL_NONE:
default:
debug(28, 0, "aclMatchAcl: '%s' has bad type %d\n",
@@ -1223,6 +1361,27 @@
}
}
+#ifdef USE_PROXY_AUTH
+void
+aclDestroyProxyAuth(struct _acl_proxy_auth *p)
+{
+ int i;
+ hash_link *hashr = NULL;
+ struct _passwd_r *pwd;
+
+ /* destroy hash list contents */
+ for (i = 0, hashr = hash_first(p->hash); hashr; hashr = hash_next(p->hash)) {
+ pwd = (struct _passwd_r *) hashr->item;
+ safe_free(pwd->passwd);
+ safe_free(pwd);
+ hash_delete(p->hash, hashr->key);
+ }
+ /* destroy and free the hash table itself */
+ hash_destroy(p->hash);
+ safe_free(p);
+}
+#endif
+
void
aclDestroyAcls(void)
{
@@ -1268,6 +1427,11 @@
case ACL_METHOD:
intlistDestroy((intlist **) & a->data);
break;
+#ifdef USE_PROXY_AUTH
+ case ACL_PROXY_AUTH:
+ aclDestroyProxyAuth(a->data);
+ break;
+#endif /* USE_PROXY_AUTH */
case ACL_NONE:
default:
fatal_dump("aclDestroyAcls: Found ACL_NONE?");
diff -urwN squid-1.1.20-orig/src/acl.h squid-1.1.20/src/acl.h
--- squid-1.1.20-orig/src/acl.h Thu Feb 20 22:03:10 1997
+++ squid-1.1.20/src/acl.h Thu Feb 12 21:54:54 1998
@@ -44,6 +44,9 @@
ACL_PROTO,
ACL_METHOD,
ACL_BROWSER,
+#ifdef USE_PROXY_AUTH
+ ACL_PROXY_AUTH,
+#endif /* USE_PROXY_AUTH */
ACL_ENUM_MAX
} squid_acl;
@@ -78,6 +81,20 @@
struct _acl_name_list *next;
};
+#ifdef USE_PROXY_AUTH
+struct _acl_proxy_auth {
+ int timeout; /* timeout value for cached usercode:password entries */
+ HashID hash;
+};
+
+/* a password record to be stored in the hash table; each password has
+ it's own expiretime */
+struct _passwd_r {
+ long expiretime;
+ char *passwd;
+};
+#endif /* USE_PROXY_AUTH */
+
struct _acl_deny_info_list {
char url[MAX_URL];
struct _acl_name_list *acl_list;
@@ -116,15 +133,28 @@
ACL_LOOKUP_NONE,
ACL_LOOKUP_NEED,
ACL_LOOKUP_PENDING,
- ACL_LOOKUP_DONE
+ ACL_LOOKUP_DONE,
+ ACL_PROXY_AUTH_NEEDED,
+ ACL_PROXY_AUTH_USED,
+ ACL_PROXY_AUTH_CHECK
} acl_lookup_state;
+#ifdef USE_PROXY_AUTH
+struct _auth_r {
+ char basic[ICP_IDENT_SZ]; /* usercode:password */
+ int checked; /* 0 = not yet, 1 = OK, -1 = NOT OK */
+};
+#endif
+
struct _aclCheck_t {
struct in_addr src_addr;
struct in_addr dst_addr;
char src_fqdn[SQUIDHOSTNAMELEN];
request_t *request;
char ident[ICP_IDENT_SZ];
+#ifdef USE_PROXY_AUTH
+ struct _auth_r auth;
+#endif
char browser[BROWSERNAMELEN];
acl_lookup_state state[ACL_ENUM_MAX];
};
diff -urwN squid-1.1.20-orig/src/authenticate.c squid-1.1.20/src/authenticate.c
--- squid-1.1.20-orig/src/authenticate.c Thu Jan 1 01:00:00 1970
+++ squid-1.1.20/src/authenticate.c Sat Mar 7 16:31:44 1998
@@ -0,0 +1,531 @@
+/*
+ * $Id: authenticate.c,v 1.34.2.1 1997/04/15 23:26:02 wessels Exp $
+ *
+ * created from redirect.c
+ *
+ * DEBUG: section 44 Authenticator
+ * AUTHOR: Duane Wessels
+ *
+ * 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef USE_PROXY_AUTH
+
+#include "squid.h"
+
+#define AUTHENTICATE_FLAG_ALIVE 0x01
+#define AUTHENTICATE_FLAG_BUSY 0x02
+#define AUTHENTICATE_FLAG_CLOSING 0x04
+
+typedef struct {
+ int fd;
+ void *data;
+ const char *client_ident;
+ const char *client_passwd;
+ AH handler;
+} authenticateStateData;
+
+typedef struct _authenticator {
+ int index;
+ int flags;
+ int fd;
+ char *inbuf;
+ unsigned int size;
+ unsigned int offset;
+ struct timeval dispatch_time;
+ authenticateStateData *authenticateState;
+} authenticator_t;
+
+static struct {
+ int requests;
+ int replies;
+ int errors;
+ int avg_svc_time;
+ int queue_size;
+ int use_hist[DefaultAuthenticateChildrenMax];
+ int rewrites[DefaultAuthenticateChildrenMax];
+} AuthenticateStats;
+
+
+struct authenticateQueueData {
+ struct authenticateQueueData *next;
+ authenticateStateData *authenticateState;
+};
+
+static authenticator_t *GetFirstAvailable _PARAMS((void));
+static int authenticateCreateAuthenticator _PARAMS((const char *command));
+static int authenticateHandleRead _PARAMS((int, authenticator_t *));
+static authenticateStateData *Dequeue _PARAMS((void));
+static void Enqueue _PARAMS((authenticateStateData *));
+static void authenticateDispatch _PARAMS((authenticator_t *, authenticateStateData *));
+
+static authenticator_t **authenticate_child_table = NULL;
+static int NAuthenticators = 0;
+static int NAuthenticatorsOpen = 0;
+static struct authenticateQueueData *authenticateQueueHead = NULL;
+static struct authenticateQueueData **authenticateQueueTailP = &authenticateQueueHead;
+
+static char *authenticator_args[32];
+
+static int
+authenticateCreateAuthenticator(const char *command)
+{
+ pid_t pid;
+ struct sockaddr_in S;
+ static int n_authenticator = 0;
+ int cfd;
+ int sfd;
+ int len;
+ int fd;
+ struct timeval slp;
+ cfd = comm_open(SOCK_STREAM,
+ 0,
+ local_addr,
+ 0,
+ COMM_NOCLOEXEC,
+ "socket to authenticator");
+ if (cfd == COMM_ERROR) {
+ debug(44, 0, "authenticate_create_authenticator: Failed to create authenticator\n");
+ return -1;
+ }
+ len = sizeof(S);
+ memset(&S, '\0', len);
+ if (getsockname(cfd, (struct sockaddr *) &S, &len) < 0) {
+ debug(50, 0, "authenticate_create_authenticator: getsockname: %s\n", xstrerror());
+ comm_close(cfd);
+ return -1;
+ }
+ listen(cfd, 1);
+ if ((pid = fork()) < 0) {
+ debug(50, 0, "authenticate_create_authenticator: fork: %s\n", xstrerror());
+ comm_close(cfd);
+ return -1;
+ }
+ if (pid > 0) { /* parent */
+ comm_close(cfd); /* close shared socket with child */
+ /* open new socket for parent process */
+ sfd = comm_open(SOCK_STREAM,
+ 0,
+ local_addr,
+ 0,
+ 0,
+ NULL); /* blocking! */
+ if (sfd == COMM_ERROR)
+ return -1;
+ if (comm_connect_addr(sfd, &S) == COMM_ERROR) {
+ comm_close(sfd);
+ return -1;
+ }
+ comm_set_fd_lifetime(sfd, -1);
+ debug(44, 4, "authenticate_create_authenticator: FD %d connected to %s #%d.\n",
+ sfd, command, ++n_authenticator);
+ slp.tv_sec = 0;
+ slp.tv_usec = 250000;
+ select(0, NULL, NULL, NULL, &slp);
+ return sfd;
+ }
+ /* child */
+ no_suid(); /* give up extra priviliges */
+ if ((fd = accept(cfd, NULL, NULL)) < 0) {
+ debug(50, 0, "authenticate_create_authenticator: FD %d accept: %s\n",
+ cfd, xstrerror());
+ _exit(1);
+ }
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fileno(debug_log), 2);
+ fclose(debug_log);
+ close(fd);
+ close(cfd);
+
+ execvp(command, authenticator_args);
+ debug(50, 0, "authenticate_create_authenticator: %s: %s\n", command, xstrerror());
+ _exit(1);
+ return 0;
+}
+
+static int
+authenticateHandleRead(int fd, authenticator_t * authenticator)
+{
+ int len;
+ authenticateStateData *r = authenticator->authenticateState;
+ char *t = NULL;
+ int n;
+ int svc_time;
+
+ len = read(fd,
+ authenticator->inbuf + authenticator->offset,
+ authenticator->size - authenticator->offset);
+ debug(44, 5, "authenticateHandleRead: %d bytes from Authenticator #%d.\n",
+ len, authenticator->index + 1);
+ if (len <= 0) {
+ if (len < 0)
+ debug(50, 1, "authenticateHandleRead: FD %d read: %s\n", fd, xstrerror());
+ debug(44, authenticator->flags & AUTHENTICATE_FLAG_CLOSING ? 5 : 1,
+ "FD %d: Connection from Authenticator #%d is closed, disabling\n",
+ fd, authenticator->index + 1);
+ authenticator->flags = 0;
+ put_free_8k_page(authenticator->inbuf);
+ authenticator->inbuf = NULL;
+ comm_close(fd);
+ if (--NAuthenticatorsOpen == 0 && !shutdown_pending && !reread_pending)
+ fatal_dump("All authenticators have exited!");
+ return 0;
+ }
+ if (len != 1)
+ AuthenticateStats.rewrites[authenticator->index]++;
+ authenticator->offset += len;
+ authenticator->inbuf[authenticator->offset] = '\0';
+ /* reschedule */
+ commSetSelect(authenticator->fd,
+ COMM_SELECT_READ,
+ (PF) authenticateHandleRead,
+ authenticator, 0);
+ if ((t = strchr(authenticator->inbuf, '\n'))) {
+ /* end of record found */
+ *t = '\0';
+ if ((t = strchr(authenticator->inbuf, ' ')))
+ *t = '\0'; /* terminate at space */
+ if (r == NULL) {
+ /* A naughty authenticator has spoken without being spoken to */
+ /* B.R.Foster@massey.ac.nz, SQUID/1.1.3 */
+ debug(44, 0, "authenticateHandleRead: unexpected reply: '%s'\n",
+ authenticator->inbuf);
+ authenticator->offset = 0;
+ } else {
+ debug(44, 5, "authenticateHandleRead: reply: '%s'\n",
+ authenticator->inbuf);
+ /* careful here. r->data might point to something which
+ * has recently been freed. If so, we require that r->handler
+ * be NULL */
+ if (r->handler) {
+ r->handler(r->data,
+ t == authenticator->inbuf ? NULL : authenticator->inbuf);
+ }
+ safe_free(r);
+ authenticator->authenticateState = NULL;
+ authenticator->flags &= ~AUTHENTICATE_FLAG_BUSY;
+ authenticator->offset = 0;
+ n = ++AuthenticateStats.replies;
+ svc_time = tvSubMsec(authenticator->dispatch_time, current_time);
+ if (n > AUTHENTICATE_AV_FACTOR)
+ n = AUTHENTICATE_AV_FACTOR;
+ AuthenticateStats.avg_svc_time
+ = (AuthenticateStats.avg_svc_time * (n - 1) + svc_time) / n;
+ }
+ }
+ while ((authenticator = GetFirstAvailable()) && (r = Dequeue()))
+ authenticateDispatch(authenticator, r);
+ return 0;
+}
+
+static void
+Enqueue(authenticateStateData * r)
+{
+ struct authenticateQueueData *new = xcalloc(1, sizeof(struct authenticateQueueData));
+ new->authenticateState = r;
+ *authenticateQueueTailP = new;
+ authenticateQueueTailP = &new->next;
+ AuthenticateStats.queue_size++;
+}
+
+static authenticateStateData *
+Dequeue(void)
+{
+ struct authenticateQueueData *old = NULL;
+ authenticateStateData *r = NULL;
+ if (authenticateQueueHead) {
+ r = authenticateQueueHead->authenticateState;
+ old = authenticateQueueHead;
+ authenticateQueueHead = authenticateQueueHead->next;
+ if (authenticateQueueHead == NULL)
+ authenticateQueueTailP = &authenticateQueueHead;
+ safe_free(old);
+ AuthenticateStats.queue_size--;
+ }
+ return r;
+}
+
+static authenticator_t *
+GetFirstAvailable(void)
+{
+ int k;
+ authenticator_t *authenticate = NULL;
+ for (k = 0; k < NAuthenticators; k++) {
+ authenticate = *(authenticate_child_table + k);
+ if (BIT_TEST(authenticate->flags, AUTHENTICATE_FLAG_BUSY))
+ continue;
+ if (!BIT_TEST(authenticate->flags, AUTHENTICATE_FLAG_ALIVE))
+ continue;
+ return authenticate;
+ }
+ return NULL;
+}
+
+
+static void
+authenticateDispatch(authenticator_t * authenticate, authenticateStateData * r)
+{
+ char *buf = NULL;
+ int len;
+ if (r->handler == NULL) {
+ debug(44, 1, "authenticateDispatch: skipping '%s' because no handler\n",
+ r->client_ident);
+ safe_free(r);
+ return;
+ }
+ authenticate->flags |= AUTHENTICATE_FLAG_BUSY;
+ authenticate->authenticateState = r;
+ authenticate->dispatch_time = current_time;
+ buf = get_free_8k_page();
+ sprintf(buf, "%s %s\n",
+ r->client_ident,
+ r->client_passwd);
+ len = strlen(buf);
+ comm_write(authenticate->fd,
+ buf,
+ len,
+ 0, /* timeout */
+ NULL, /* Handler */
+ NULL, /* Handler-data */
+ put_free_8k_page);
+ debug(44, 5, "authenticateDispatch: Request sent to Authenticator #%d, %d bytes\n",
+ authenticate->index + 1, len);
+ AuthenticateStats.use_hist[authenticate->index]++;
+ AuthenticateStats.requests++;
+}
+
+
+/**** PUBLIC FUNCTIONS ****/
+
+
+void
+authenticateStart(int cfd, icpStateData * icpState, AH handler, void *data)
+{
+ authenticateStateData *r = NULL;
+ authenticator_t *authenticator = NULL;
+ debug(44, 5, "authenticateStart: '%s'\n", icpState->url);
+ if (!handler)
+ fatal_dump("authenticateStart: NULL handler");
+ if (!icpState)
+ fatal_dump("authenticateStart: NULL icpState");
+ if (Config.Program.authenticate == NULL) {
+ handler(data, NULL);
+ return;
+ }
+ r = xcalloc(1, sizeof(authenticateStateData));
+ r->fd = cfd;
+ if (icpState->ident.ident == NULL || *icpState->ident.ident == '\0') {
+ r->client_ident = dash_str;
+ } else {
+ r->client_ident = icpState->ident.ident;
+ }
+ if (icpState->ident.passwd == NULL || *icpState->ident.passwd == '\0') {
+ r->client_passwd = dash_str;
+ } else {
+ r->client_passwd = icpState->ident.passwd;
+ }
+ r->handler = handler;
+ r->data = data;
+ if ((authenticator = GetFirstAvailable()))
+ authenticateDispatch(authenticator, r);
+ else
+ Enqueue(r);
+}
+
+void
+authenticateFreeMemory(void)
+{
+ int k;
+ /* free old structures if present */
+ if (authenticate_child_table) {
+ for (k = 0; k < NAuthenticators; k++) {
+ if (authenticate_child_table[k]->inbuf)
+ put_free_8k_page(authenticate_child_table[k]->inbuf);
+ safe_free(authenticate_child_table[k]);
+ }
+ safe_free(authenticate_child_table);
+ }
+}
+
+void
+authenticateOpenServers(void)
+{
+ char *prg = Config.Program.authenticate;
+ int k;
+ int authenticatesocket;
+ LOCAL_ARRAY(char, fd_note_buf, FD_ASCII_NOTE_SZ);
+ static int first_time = 0;
+ char **av, *p;
+
+ authenticateFreeMemory();
+ if (Config.Program.authenticate == NULL)
+ return;
+ NAuthenticators = NAuthenticatorsOpen = Config.authenticateChildren;
+ authenticate_child_table = xcalloc(NAuthenticators, sizeof(authenticator_t *));
+
+ av = authenticator_args;
+ *av = strdup("(authenticator)");
+ av++; k = 1;
+ p = strtok(Config.Program.authenticate_opts, " \t");
+ while ((p != NULL) && (k < 32)) {
+ *av = p;
+ av++; k++;
+ p = strtok(NULL, " \t");
+ }
+ *av = NULL;
+
+ debug(44, 1, "authenticateOpenServers: Starting %d '%s' processes\n",
+ NAuthenticators, prg);
+ for (k = 0; k < NAuthenticators; k++) {
+ authenticate_child_table[k] = xcalloc(1, sizeof(authenticator_t));
+ if ((authenticatesocket = authenticateCreateAuthenticator(prg)) < 0) {
+ debug(44, 1, "WARNING: Cannot run '%s' process.\n", prg);
+ authenticate_child_table[k]->flags &= ~AUTHENTICATE_FLAG_ALIVE;
+ } else {
+ authenticate_child_table[k]->flags |= AUTHENTICATE_FLAG_ALIVE;
+ authenticate_child_table[k]->index = k;
+ authenticate_child_table[k]->fd = authenticatesocket;
+ authenticate_child_table[k]->inbuf = get_free_8k_page();
+ authenticate_child_table[k]->size = 8192;
+ authenticate_child_table[k]->offset = 0;
+ sprintf(fd_note_buf, "%s #%d",
+ prg,
+ authenticate_child_table[k]->index + 1);
+ fd_note(authenticate_child_table[k]->fd, fd_note_buf);
+ commSetNonBlocking(authenticate_child_table[k]->fd);
+ /* set handler for incoming result */
+ commSetSelect(authenticate_child_table[k]->fd,
+ COMM_SELECT_READ,
+ (PF) authenticateHandleRead,
+ (void *) authenticate_child_table[k], 0);
+ debug(44, 3, "authenticateOpenServers: 'authenticate_server' %d started\n",
+ k);
+ }
+ }
+ if (first_time == 0) {
+ first_time++;
+ memset(&AuthenticateStats, '\0', sizeof(AuthenticateStats));
+ }
+}
+
+void
+authenticateShutdownServers(void)
+{
+ authenticator_t *authenticate = NULL;
+ authenticateStateData *r = NULL;
+ int k;
+ if (Config.Program.authenticate == NULL)
+ return;
+ if (authenticateQueueHead) {
+ while ((authenticate = GetFirstAvailable()) && (r = Dequeue()))
+ authenticateDispatch(authenticate, r);
+ return;
+ }
+ for (k = 0; k < NAuthenticators; k++) {
+ authenticate = *(authenticate_child_table + k);
+ if (!(authenticate->flags & AUTHENTICATE_FLAG_ALIVE))
+ continue;
+ if (authenticate->flags & AUTHENTICATE_FLAG_BUSY)
+ continue;
+ if (authenticate->flags & AUTHENTICATE_FLAG_CLOSING)
+ continue;
+ debug(44, 3, "authenticateShutdownServers: closing authenticator #%d, FD %d\n",
+ authenticate->index + 1, authenticate->fd);
+ comm_close(authenticate->fd);
+ authenticate->flags |= AUTHENTICATE_FLAG_CLOSING;
+ authenticate->flags |= AUTHENTICATE_FLAG_BUSY;
+ }
+}
+
+
+int
+authenticateUnregister(const char *url, int fd)
+{
+ authenticator_t *authenticate = NULL;
+ authenticateStateData *r = NULL;
+ struct authenticateQueueData *rq = NULL;
+ int k;
+ int n = 0;
+ if (Config.Program.authenticate == NULL)
+ return 0;
+ debug(44, 3, "authenticateUnregister: FD %d '%s'\n", fd, url);
+ for (k = 0; k < NAuthenticators; k++) {
+ authenticate = *(authenticate_child_table + k);
+ if ((r = authenticate->authenticateState) == NULL)
+ continue;
+ if (r->fd != fd)
+ continue;
+#if 0
+ if (strcmp(r->orig_url, url))
+ continue;
+#endif
+ debug(44, 3, "authenticateUnregister: Found match\n");
+ r->handler = NULL;
+ n++;
+ }
+ for (rq = authenticateQueueHead; rq; rq = rq->next) {
+ if ((r = rq->authenticateState) == NULL)
+ continue;
+ if (r->fd != fd)
+ continue;
+#if 0
+ if (strcmp(r->orig_url, url))
+ continue;
+#endif
+ debug(44, 3, "authenticateUnregister: Found match.\n");
+ r->handler = NULL;
+ n++;
+ }
+ debug(44, 3, "authenticateUnregister: Unregistered %d handlers\n", n);
+ return n;
+}
+
+void
+authenticateStats(StoreEntry * sentry)
+{
+ int k;
+ storeAppendPrintf(sentry, open_bracket);
+ storeAppendPrintf(sentry, "{Authenticator Statistics:}\n");
+ storeAppendPrintf(sentry, "{requests: %d}\n",
+ AuthenticateStats.requests);
+ storeAppendPrintf(sentry, "{replies: %d}\n",
+ AuthenticateStats.replies);
+ storeAppendPrintf(sentry, "{queue length: %d}\n",
+ AuthenticateStats.queue_size);
+ storeAppendPrintf(sentry, "{avg service time: %d msec}\n",
+ AuthenticateStats.avg_svc_time);
+ storeAppendPrintf(sentry, "{number of authenticators: %d}\n",
+ NAuthenticators);
+ storeAppendPrintf(sentry, "{use histogram:}\n");
+ for (k = 0; k < NAuthenticators; k++) {
+ storeAppendPrintf(sentry, "{ authenticator #%d: %d (%d rewrites)}\n",
+ k + 1,
+ AuthenticateStats.use_hist[k],
+ AuthenticateStats.rewrites[k]);
+ }
+ storeAppendPrintf(sentry, close_bracket);
+}
+
+#endif
diff -urwN squid-1.1.20-orig/src/authenticate.h squid-1.1.20/src/authenticate.h
--- squid-1.1.20-orig/src/authenticate.h Thu Jan 1 01:00:00 1970
+++ squid-1.1.20/src/authenticate.h Sun Feb 8 20:52:50 1998
@@ -0,0 +1,48 @@
+/*
+ * $Id: authenticate.h,v 1.8.4.1 1997/04/15 23:26:03 wessels Exp $
+ *
+ * AUTHOR: Duane Wessels
+ *
+ * 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef AUTHENTICATE_H
+#define AUTHENTICATE_H
+
+#define AUTHENTICATE_AV_FACTOR 1000
+
+typedef void (*AH) (void *data, char *result);
+
+extern void authenticateStart _PARAMS((int cfd, icpStateData *, AH, void *));
+extern void authenticateOpenServers _PARAMS((void));
+extern void authenticateShutdownServers _PARAMS((void));
+extern void authenticateStats _PARAMS((StoreEntry *));
+extern int authenticateUnregister _PARAMS((const char *url, int fd));
+extern void authenticateFreeMemory _PARAMS((void));
+
+#define AUTHENTICATE_NONE 0
+#define AUTHENTICATE_PENDING 1
+#define AUTHENTICATE_DONE 2
+
+#endif /* AUTHENTICATE_H */
diff -urwN squid-1.1.20-orig/src/cache_cf.c squid-1.1.20/src/cache_cf.c
--- squid-1.1.20-orig/src/cache_cf.c Wed Dec 31 22:36:58 1997
+++ squid-1.1.20/src/cache_cf.c Sat Mar 7 16:25:38 1998
@@ -134,6 +134,9 @@
#define DefaultOptionsAnonymizer 0 /* default off */
#define DefaultOptionsIcpHitStale 0 /* default off */
#define DefaultRedirectChildren 5 /* 5 processes */
+#ifdef USE_PROXY_AUTH
+#define DefaultAuthenticateChildren 5 /* 5 processes */
+#endif
#define DefaultMaxRequestSize (100 << 10) /* 100Kb */
#define DefaultHttpPortNum CACHE_HTTP_PORT
@@ -145,9 +148,6 @@
#define DefaultUseragentLogFile (char *)NULL /* default NONE */
#define DefaultStoreLogFile DEFAULT_STORE_LOG
#define DefaultSwapLogFile (char *)NULL /* default swappath(0) */
-#if USE_PROXY_AUTH
-#define DefaultProxyAuthFile (char *)NULL /* default NONE */
-#endif /* USE_PROXY_AUTH */
#define DefaultLogRotateNumber 10
#define DefaultAdminEmail "webmaster"
#define DefaultFtpgetProgram DEFAULT_FTPGET
@@ -156,6 +156,10 @@
#define DefaultPingerProgram DEFAULT_PINGER
#define DefaultUnlinkdProgram DEFAULT_UNLINKD
#define DefaultRedirectProgram (char *)NULL /* default NONE */
+#ifdef USE_PROXY_AUTH
+#define DefaultAuthenticateProgram (char *)NULL /* default NONE */
+#define DefaultAuthenticateOptions ""
+#endif
#define DefaultEffectiveUser (char *)NULL /* default NONE */
#define DefaultEffectiveGroup (char *)NULL /* default NONE */
#define DefaultAppendDomain (char *)NULL /* default NONE */
@@ -654,22 +658,6 @@
Config.adminEmail = xstrdup(token);
}
-#if USE_PROXY_AUTH
-static void
-parseProxyAuthLine(void)
-{
- char *token;
- token = strtok(NULL, w_space);
- if (token == NULL)
- self_destruct();
- safe_free(Config.proxyAuth.File);
- aclDestroyRegexList(Config.proxyAuth.IgnoreDomains);
- Config.proxyAuth.IgnoreDomains = NULL;
- Config.proxyAuth.File = xstrdup(token);
- aclParseRegexList(&Config.proxyAuth.IgnoreDomains, 1);
-}
-#endif /* USE_PROXY_AUTH */
-
static void
parseHttpdAccelLine(void)
{
@@ -1226,19 +1214,23 @@
else if (!strcmp(token, "redirect_children"))
parseIntegerValue(&Config.redirectChildren);
+#ifdef USE_PROXY_AUTH
+ else if (!strcmp(token, "authenticate_program"))
+ parsePathname(&Config.Program.authenticate, 1);
+
+ else if (!strcmp(token, "authenticate_options"))
+ parseToEndOfLine(&Config.Program.authenticate_opts);
+
+ else if (!strcmp(token, "authenticate_children"))
+ parseIntegerValue(&Config.authenticateChildren);
+#endif
+
else if (!strcmp(token, "pinger_program"))
parsePathname(&Config.Program.pinger, 1);
else if (!strcmp(token, "unlinkd_program"))
parsePathname(&Config.Program.unlinkd, 1);
-#if USE_PROXY_AUTH
- else if (!strcmp(token, "proxy_auth"))
- parseProxyAuthLine();
- else if (!strcmp(token, "proxy_auth_ignore"))
- aclParseRegexList(&Config.proxyAuth.IgnoreDomains, 1);
-#endif /* USE_PROXY_AUTH */
-
else if (!strcmp(token, "source_ping"))
parseOnOff(&Config.sourcePing);
@@ -1477,6 +1469,10 @@
safe_free(Config.Program.ftpget_opts);
safe_free(Config.Program.dnsserver);
safe_free(Config.Program.redirect);
+#ifdef USE_PROXY_AUTH
+ safe_free(Config.Program.authenticate);
+ safe_free(Config.Program.authenticate_opts);
+#endif
safe_free(Config.Program.unlinkd);
safe_free(Config.Program.pinger);
safe_free(Config.Accel.host);
@@ -1486,11 +1482,6 @@
safe_free(Config.pidFilename);
safe_free(Config.visibleHostname);
safe_free(Config.ftpUser);
-#if USE_PROXY_AUTH
- safe_free(Config.proxyAuth.File);
- aclDestroyRegexList(Config.proxyAuth.IgnoreDomains);
- Config.proxyAuth.IgnoreDomains = NULL;
-#endif /* USE_PROXY_AUTH */
safe_free(Config.Announce.host);
safe_free(Config.Announce.file);
safe_free(Config.errHtmlText);
@@ -1539,6 +1530,9 @@
Config.cleanRate = DefaultCleanRate;
Config.dnsChildren = DefaultDnsChildren;
Config.redirectChildren = DefaultRedirectChildren;
+#ifdef USE_PROXY_AUTH
+ Config.authenticateChildren = DefaultAuthenticateChildren;
+#endif
Config.sourcePing = DefaultSourcePing;
Config.quickAbort.min = DefaultQuickAbortMin;
Config.quickAbort.pct = DefaultQuickAbortPct;
@@ -1572,6 +1566,10 @@
Config.Program.ftpget_opts = safe_xstrdup(DefaultFtpgetOptions);
Config.Program.dnsserver = safe_xstrdup(DefaultDnsserverProgram);
Config.Program.redirect = safe_xstrdup(DefaultRedirectProgram);
+#ifdef USE_PROXY_AUTH
+ Config.Program.authenticate = safe_xstrdup(DefaultAuthenticateProgram);
+ Config.Program.authenticate_opts = safe_xstrdup(DefaultAuthenticateOptions);
+#endif
Config.Program.pinger = safe_xstrdup(DefaultPingerProgram);
Config.Program.unlinkd = safe_xstrdup(DefaultUnlinkdProgram);
Config.Accel.host = safe_xstrdup(DefaultAccelHost);
@@ -1580,10 +1578,6 @@
Config.Accel.withProxy = DefaultAccelWithProxy;
Config.pidFilename = safe_xstrdup(DefaultPidFilename);
Config.visibleHostname = safe_xstrdup(DefaultVisibleHostname);
-#if USE_PROXY_AUTH
- Config.proxyAuth.File = safe_xstrdup(DefaultProxyAuthFile);
-/* Config.proxyAuth.IgnoreDomains = safe_xstrdup(DefaultproxyAuthIgnoreDomains); */
-#endif /* USE_PROXY_AUTH */
Config.ftpUser = safe_xstrdup(DefaultFtpUser);
Config.Announce.host = safe_xstrdup(DefaultAnnounceHost);
Config.Announce.port = DefaultAnnouncePort;
diff -urwN squid-1.1.20-orig/src/cache_cf.h squid-1.1.20/src/cache_cf.h
--- squid-1.1.20-orig/src/cache_cf.h Mon Dec 1 08:07:57 1997
+++ squid-1.1.20/src/cache_cf.h Sat Mar 7 15:27:19 1998
@@ -108,6 +108,9 @@
#define DefaultDnsChildrenMax 32 /* 32 processes */
#define DefaultRedirectChildrenMax 32 /* 32 processes */
+#ifdef USE_PROXY_AUTH
+#define DefaultAuthenticateChildrenMax 32 /* 32 processes */
+#endif
typedef struct _wordlist {
char *key;
@@ -177,12 +180,6 @@
int rotateNumber;
int log_fqdn;
} Log;
-#if USE_PROXY_AUTH
- struct {
- char *File;
- relist *IgnoreDomains;
- } proxyAuth;
-#endif /* USE_PROXY_AUTH */
char *adminEmail;
char *effectiveUser;
char *effectiveGroup;
@@ -191,11 +188,18 @@
char *ftpget_opts;
char *dnsserver;
char *redirect;
+#ifdef USE_PROXY_AUTH
+ char *authenticate;
+ char *authenticate_opts;
+#endif
char *pinger;
char *unlinkd;
} Program;
int dnsChildren;
int redirectChildren;
+#ifdef USE_PROXY_AUTH
+ int authenticateChildren;
+#endif
int sourcePing;
int commonLogFormat;
#if LOG_FULL_HEADERS
diff -urwN squid-1.1.20-orig/src/cachemgr.c squid-1.1.20/src/cachemgr.c
--- squid-1.1.20-orig/src/cachemgr.c Wed Jan 7 23:59:04 1998
+++ squid-1.1.20/src/cachemgr.c Mon Feb 9 22:00:38 1998
@@ -225,6 +225,7 @@
STATS_F,
STATS_D,
STATS_R,
+ STATS_A,
STATS_O,
STATS_VM,
STATS_U,
@@ -252,6 +253,7 @@
"stats/fqdncache",
"stats/dns",
"stats/redirector",
+ "stats/authenticator",
"stats/objects",
"stats/vm_objects",
"stats/utilization",
@@ -279,6 +281,7 @@
"FQDN Cache Contents",
"DNS Server Statistics",
"Redirector Statistics",
+ "Authenticator Statistics",
"Objects",
"VM Objects",
"Utilization",
@@ -374,6 +377,7 @@
print_option(op, STATS_F);
print_option(op, STATS_D);
print_option(op, STATS_R);
+ print_option(op, STATS_A);
print_option(op, SHUTDOWN);
print_option(op, REFRESH);
#ifdef REMOVE_OBJECT
@@ -730,6 +734,7 @@
case STATS_F:
case STATS_D:
case STATS_R:
+ case STATS_A:
case STATS_O:
case STATS_VM:
case STATS_U:
@@ -784,6 +789,7 @@
print_option(op, STATS_F);
print_option(op, STATS_D);
print_option(op, STATS_R);
+ print_option(op, STATS_A);
printf("\n");
printf("\n", hostname);
printf("\n", portnum);
@@ -826,6 +832,7 @@
case STATS_F:
case STATS_D:
case STATS_R:
+ case STATS_A:
case STATS_O:
case STATS_VM:
case STATS_IO:
@@ -914,6 +921,7 @@
case STATS_F:
case STATS_D:
case STATS_R:
+ case STATS_A:
case STATS_IO:
case STATS_HDRS:
case STATS_FDS:
diff -urwN squid-1.1.20-orig/src/client_side.c squid-1.1.20/src/client_side.c
--- squid-1.1.20-orig/src/client_side.c Wed Nov 19 17:44:51 1997
+++ squid-1.1.20/src/client_side.c Sun Jun 7 22:14:25 1998
@@ -32,6 +32,9 @@
#include "squid.h"
static void clientRedirectDone _PARAMS((void *data, char *result));
+#ifdef USE_PROXY_AUTH
+static void clientAuthenticateDone _PARAMS((void *data, char *result));
+#endif
static void icpHandleIMSReply _PARAMS((int fd, StoreEntry * entry, void *data));
static void clientLookupDstIPDone _PARAMS((int fd, const ipcache_addrs *, void *data));
static void clientLookupSrcFQDNDone _PARAMS((int fd, const char *fqdn, void *data));
@@ -89,39 +92,6 @@
clientAccessCheck(icpState, icpState->aclHandler);
}
-#if USE_PROXY_AUTH
-/* ProxyAuth code by Jon Thackray */
-/* return 1 if allowed, 0 if denied */
-static int
-clientProxyAuthCheck(icpStateData * icpState)
-{
- 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(icpState->url) == PROTO_CACHEOBJ)
- return 1;
-
- if (Config.proxyAuth.IgnoreDomains) {
- if (aclMatchRegex(Config.proxyAuth.IgnoreDomains, icpState->request->host)) {
- debug(33, 2, "clientProxyAuthCheck: host \"%s\" matched proxyAuthIgnoreDomains\n", icpState->request->host);
- return 1;
- }
- }
- proxy_user = proxyAuthenticate(icpState->request_hdr);
- xstrncpy(icpState->ident.ident, proxy_user, ICP_IDENT_SZ);
- xstrncpy(icpState->aclChecklist->ident, proxy_user, ICP_IDENT_SZ);
- debug(33, 6, "clientProxyAuthCheck: user = %s\n", icpState->ident.ident);
-
- if (strcmp(icpState->ident.ident, dash_str) == 0)
- return 0;
- return 1;
-}
-#endif /* USE_PROXY_AUTH */
-
static int
checkAccelOnly(icpStateData * icpState)
{
@@ -145,6 +115,9 @@
aclCheck_t *ch = NULL;
char *browser = NULL;
const ipcache_addrs *ia = NULL;
+#ifdef USE_PROXY_AUTH
+ int proxy_auth_hdr = 0;
+#endif
if (Config.identLookup && icpState->ident.state == IDENT_NONE) {
icpState->aclHandler = handler;
@@ -164,11 +137,90 @@
xstrncpy(icpState->aclChecklist->ident,
icpState->ident.ident,
ICP_IDENT_SZ);
+#ifdef USE_PROXY_AUTH
+ /* Initialize auth.checked on 0 because we don't have any
+ usercode/password validation done yet */
+ icpState->aclChecklist->auth.checked = 0;
+#endif
}
/* This so we can have SRC ACLs for cache_host_acl. */
icpState->request->client_addr = icpState->peer.sin_addr;
-#if USE_PROXY_AUTH
- if (clientProxyAuthCheck(icpState) == 0) {
+
+#ifdef USE_PROXY_AUTH
+ if (urlParseProtocol(icpState->url) != PROTO_CACHEOBJ) {
+ char *s = NULL;
+ /* Look for Proxy-authorization: Basic in the
+ * headers sent by the client
+ */
+ if ((s = mime_get_header(icpState->request_hdr,
+ "Proxy-authorization:")) == NULL) {
+ debug(33, 5, "clientAccessCheck: Can't find authorization header\n");
+ xstrncpy(icpState->aclChecklist->auth.basic, "-:-", ICP_IDENT_SZ);
+ } else {
+ LOCAL_ARRAY(char, sent_user, ICP_IDENT_SZ);
+ char *sent_userandpw = NULL;
+ char *clear_userandpw = NULL;
+ /* Skip the 'Basic' part */
+ s += strlen(" Basic");
+ sent_userandpw = xstrdup(s);
+ /* Trim trailing \n before decoding */
+ strtok(sent_userandpw, "\n");
+ clear_userandpw = uudecode(sent_userandpw);
+ xfree(sent_userandpw);
+ xstrncpy(icpState->aclChecklist->auth.basic, clear_userandpw,
+ ICP_IDENT_SZ);
+ xstrncpy(sent_user, clear_userandpw, ICP_IDENT_SZ);
+ xfree(clear_userandpw);
+ if ((s = strstr(sent_user, ":")) != NULL) {
+ *s = '\0'; s++;
+ xstrncpy(icpState->ident.ident, sent_user, ICP_IDENT_SZ);
+ /* we need this in authenticate.c */
+ xstrncpy(icpState->ident.passwd, s, ICP_IDENT_SZ);
+ proxy_auth_hdr = 1;
+ } else {
+ /* invalid Basic proxy authorization */
+ s = mime_get_header(icpState->request_hdr,
+ "Proxy-authorization:");
+ debug(33, 0, "clientAccessCheck: invalid proxy authorization header: %s\n",
+ s);
+ xstrncpy(icpState->aclChecklist->auth.basic, "-:-", ICP_IDENT_SZ);
+ }
+ }
+ }
+#endif /* USE_PROXY_AUTH */
+
+ ch = icpState->aclChecklist;
+ icpState->aclHandler = handler;
+ if (checkAccelOnly(icpState)) {
+ answer = 0;
+ } else {
+ answer = aclCheck(HTTPAccessList, ch);
+
+#ifdef USE_PROXY_AUTH
+ if (ch->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_CHECK) {
+ /* we need to check the usercode/password combination
+ stored in icpState->ident */
+ debug(33, 5, "clientAccessCheck: check the password\n");
+ if (icpState->authenticate_state != AUTHENTICATE_NONE)
+ fatal_dump("clientAccessCheck: wrong authenticate_state");
+ icpState->authenticate_state = AUTHENTICATE_PENDING;
+ authenticateStart(icpState->fd, icpState,
+ clientAuthenticateDone, icpState);
+ return;
+ }
+ /* We can have received a Proxy-authentication: header
+ * but there may be no proxy authentication needed.
+ * In that case we erase the username from icpState->ident.
+ */
+ if (proxy_auth_hdr &&
+ (ch->state[ACL_PROXY_AUTH] != ACL_PROXY_AUTH_USED)) {
+ debug(33, 5, "clientAccessCheck: proxy_auth not used, resetting ident\n");
+ xstrncpy(icpState->ident.ident, "-", ICP_IDENT_SZ);
+ xstrncpy(icpState->ident.passwd, "-", ICP_IDENT_SZ);
+ }
+ /* check whether we need a proxy authentication header */
+ if (ch->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED) {
+ /* We need proxy authentication, send 407 error code */
char *wbuf = NULL;
int fd = icpState->fd;
debug(33, 4, "Proxy Denied: %s\n", icpState->url);
@@ -184,12 +236,6 @@
}
#endif /* USE_PROXY_AUTH */
- ch = icpState->aclChecklist;
- icpState->aclHandler = handler;
- if (checkAccelOnly(icpState)) {
- answer = 0;
- } else {
- answer = aclCheck(HTTPAccessList, ch);
if (ch->state[ACL_DST_IP] == ACL_LOOKUP_NEED) {
ch->state[ACL_DST_IP] = ACL_LOOKUP_PENDING; /* first */
icpState->ip_lookup_pending = 1;
@@ -317,143 +363,32 @@
icpProcessRequest(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
-
-const char *
-proxyAuthenticate(const char *headers)
+#ifdef USE_PROXY_AUTH
+static void
+clientAuthenticateDone(void *data, char *result)
{
- /* 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;
- 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);
+ icpStateData *icpState = data;
- 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);
- }
+ debug(33, 5, "clientAuthenticateDone: '%s' result=%s\n", icpState->url,
+ result ? result : "NULL");
+ if (icpState->authenticate_state != AUTHENTICATE_PENDING)
+ fatal_dump("clientAuthenticateDone: wrong authenticate_state");
+ icpState->authenticate_state = AUTHENTICATE_DONE;
+ if (result) {
+ if (strcmp(result, "OK") == 0) {
+ icpState->aclChecklist->auth.checked = 1;
} 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);
+ icpState->aclChecklist->auth.checked = -1;
}
} 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);
+ /* no result */
+ debug(33, 1, "clientAuthenticateDone: no result from authenticator!\n");
+ icpState->aclChecklist->auth.checked = -1;
}
- 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), (void *) xstrdup(passwd));
-
- xfree(clear_userandpw);
- return (sent_user);
+ clientAccessCheck(icpState, icpState->aclHandler);
+ return;
}
-#endif /* USE_PROXY_AUTH */
+#endif
void
icpProcessExpired(int fd, void *data)
diff -urwN squid-1.1.20-orig/src/client_side.h squid-1.1.20/src/client_side.h
--- squid-1.1.20-orig/src/client_side.h Tue Feb 4 00:03:06 1997
+++ squid-1.1.20/src/client_side.h Sat Feb 7 13:06:31 1998
@@ -38,8 +38,4 @@
extern char *clientConstructTraceEcho _PARAMS((icpStateData *));
extern void clientPurgeRequest _PARAMS((icpStateData *));
-#if USE_PROXY_AUTH
-const char *proxyAuthenticate(const char *headers);
-#endif /* USE_PROXY_AUTH */
-
#endif /* CLIENT_SIDE_H */
diff -urwN squid-1.1.20-orig/src/comm.c squid-1.1.20/src/comm.c
--- squid-1.1.20-orig/src/comm.c Mon Dec 1 08:09:41 1997
+++ squid-1.1.20/src/comm.c Sun Feb 8 23:26:31 1998
@@ -809,6 +809,9 @@
ftpServerClose();
dnsShutdownServers();
redirectShutdownServers();
+#ifdef USE_PROXY_AUTH
+ authenticateShutdownServers();
+#endif
/* shutdown_pending will be set to
* +1 for SIGTERM
* -1 for SIGINT */
@@ -994,6 +997,9 @@
ftpServerClose();
dnsShutdownServers();
redirectShutdownServers();
+#ifdef USE_PROXY_AUTH
+ authenticateShutdownServers();
+#endif
/* shutdown_pending will be set to
* +1 for SIGTERM
* -1 for SIGINT */
diff -urwN squid-1.1.20-orig/src/hash.c squid-1.1.20/src/hash.c
--- squid-1.1.20-orig/src/hash.c Thu Nov 28 08:08:48 1996
+++ squid-1.1.20/src/hash.c Sat Feb 7 13:06:31 1998
@@ -369,6 +369,21 @@
}
/*
+ * hash_destroy - destroy hash list
+ */
+void
+hash_destroy(HashID hid)
+{
+ if (hid >= MAX_HTABLE)
+ return;
+ if (htbl[hid].valid == 0)
+ return;
+ safe_free(htbl[hid].buckets);
+ htbl[hid].valid = 0;
+ return;
+}
+
+/*
* hash_insert - inserts the given item 'item' under the given key 'k'
* into the hash table 'hid'. Returns non-zero on error; otherwise,
* returns 0 and inserts the item.
diff -urwN squid-1.1.20-orig/src/hash.h squid-1.1.20/src/hash.h
--- squid-1.1.20-orig/src/hash.h Thu Nov 7 00:14:38 1996
+++ squid-1.1.20/src/hash.h Sat Feb 7 13:06:31 1998
@@ -144,6 +144,7 @@
extern HashID hash_create _PARAMS((int (*)_PARAMS((const char *, const char *)),
int,
unsigned int (*)_PARAMS((const char *, HashID))));
+extern void hash_destroy _PARAMS((HashID));
/* insert/delete */
extern int hash_insert _PARAMS((HashID, const char *, void *));
diff -urwN squid-1.1.20-orig/src/http.c squid-1.1.20/src/http.c
--- squid-1.1.20-orig/src/http.c Tue Oct 28 19:07:29 1997
+++ squid-1.1.20/src/http.c Sat Feb 7 13:06:31 1998
@@ -764,7 +764,7 @@
continue;
#if USE_PROXY_AUTH
if (strncasecmp(xbuf, "Proxy-authorization:", 20) == 0)
- if (Config.proxyAuth.File)
+ /* if (Config.proxyAuth.File) */
continue;
#endif
if (strncasecmp(xbuf, "Connection:", 11) == 0)
diff -urwN squid-1.1.20-orig/src/icp.h squid-1.1.20/src/icp.h
--- squid-1.1.20-orig/src/icp.h Mon Dec 15 09:43:21 1997
+++ squid-1.1.20/src/icp.h Sun Feb 8 23:27:11 1998
@@ -196,11 +196,17 @@
struct {
int fd;
char ident[ICP_IDENT_SZ];
+#ifdef USE_PROXY_AUTH
+ char passwd[ICP_IDENT_SZ];
+#endif
void (*callback) _PARAMS((void *));
int state;
} ident;
int ip_lookup_pending;
int redirect_state;
+#ifdef USE_PROXY_AUTH
+ int authenticate_state;
+#endif
} icpStateData;
extern void *icpCreateMessage _PARAMS((icp_opcode opcode,
diff -urwN squid-1.1.20-orig/src/main.c squid-1.1.20/src/main.c
--- squid-1.1.20-orig/src/main.c Mon Dec 15 09:43:21 1997
+++ squid-1.1.20/src/main.c Sun Feb 8 23:28:13 1998
@@ -512,6 +512,9 @@
fqdncache_restart(); /* sigh, fqdncache too */
dnsOpenServers();
redirectOpenServers();
+#ifdef USE_PROXY_AUTH
+ authenticateOpenServers();
+#endif
serverConnectionsOpen();
ftpInitialize();
if (theOutIcpConnection >= 0 && (!httpd_accel_mode || Config.Accel.withProxy))
@@ -569,6 +572,9 @@
fqdncache_init();
dnsOpenServers();
redirectOpenServers();
+#ifdef USE_PROXY_AUTH
+ authenticateOpenServers();
+#endif
useragentOpenLog();
ftpInitialize();
diff -urwN squid-1.1.20-orig/src/ncsa_auth.c squid-1.1.20/src/ncsa_auth.c
--- squid-1.1.20-orig/src/ncsa_auth.c Thu Jan 1 01:00:00 1970
+++ squid-1.1.20/src/ncsa_auth.c Sat Mar 7 18:17:53 1998
@@ -0,0 +1,114 @@
+/*
+ * ncsa_auth.c
+ *
+ * AUTHOR: Arjan de Vet
+ *
+ * Example authentication program for Squid, based on the original
+ * proxy_auth code from client_side.c, written by
+ * Jon Thackray .
+ *
+ * Uses a NCSA httpd style password file for authentication.
+ *
+ */
+
+#include "squid.h"
+
+#define CHECK_INTERVAL 10
+
+static HashID hash = NULL;
+static time_t last_time = 0;
+static time_t change_time = 0;
+
+static void
+read_passwd_file(const char *passwdfile)
+{
+ struct stat buf;
+ FILE *f;
+ int i;
+ hash_link *hashr;
+ static char *passwords = NULL;
+ char *user;
+ char *passwd;
+
+ if (stat(passwdfile, &buf) == 0) {
+ if (buf.st_mtime != change_time) {
+ /* file has changed */
+ change_time = buf.st_mtime;
+ if (hash != NULL) {
+ for (i = 0, hashr = hash_first(hash); hashr; hashr = hash_next(hash)) {
+ hash_delete(hash, hashr->key);
+ }
+ } else {
+ /* initial setup */
+ if ((hash = hash_create(strcmp, 7921, hash_string)) < 0) {
+ fprintf(stderr, "ncsa_auth: cannot create hash table\n");
+ exit(1);
+ }
+ }
+ passwords = xmalloc((size_t) buf.st_size + 2);
+ f = fopen(passwdfile, "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");
+ while (user != NULL) {
+ if (strlen(user) > 0 && passwd && strlen(passwd) > 0) {
+ hash_insert(hash, xstrdup(user), (void *) xstrdup(passwd));
+ }
+ user = strtok(NULL, ":");
+ passwd = strtok(NULL, "\n");
+ }
+ xfree(passwords);
+ }
+ } else {
+ fprintf(stderr, "ncsa_auth: cannot stat %s\n", passwdfile);
+ exit(1);
+ }
+}
+
+/* this is only needed for hash.c */
+void
+fatal_dump(const char *message)
+{
+ fprintf(stderr, "ncsa_auth: fatal_dump: %s\n", message);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ char buf[256];
+ time_t now = 0;
+ char *user, *passwd;
+ hash_link *hashr;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: ncsa_auth \n");
+ exit(1);
+ }
+ read_passwd_file(argv[1]);
+ last_time = time(NULL);
+
+ while (fgets(buf, 256, stdin) != NULL) {
+ now = time(NULL);
+ if ((now - last_time) >= CHECK_INTERVAL) {
+ last_time = now;
+ read_passwd_file(argv[1]);
+ }
+ user = strtok(buf, " ");
+ passwd = strtok(NULL, " \n");
+ hashr = hash_lookup(hash, user);
+ if (hashr &&
+ strcmp(hashr->item, (char *) crypt(passwd, hashr->item)) == 0) {
+ printf("OK\n");
+ } else {
+ printf("ERR\n");
+ }
+ fflush(stdout);
+ }
+
+ exit(0);
+}
diff -urwN squid-1.1.20-orig/src/objcache.c squid-1.1.20/src/objcache.c
--- squid-1.1.20-orig/src/objcache.c Wed Mar 26 08:29:52 1997
+++ squid-1.1.20/src/objcache.c Mon Feb 9 22:00:38 1998
@@ -163,6 +163,8 @@
op = MGR_DNSSERVERS;
else if (!strcmp(buf, "stats/redirector"))
op = MGR_REDIRECTORS;
+ else if (!strcmp(buf, "stats/authenticator"))
+ op = MGR_AUTHENTICATORS;
else if (!strcmp(buf, "stats/io"))
op = MGR_IO;
else if (!strcmp(buf, "stats/reply_headers"))
@@ -288,6 +290,9 @@
break;
case MGR_REDIRECTORS:
HTTPCacheInfo->stat_get(HTTPCacheInfo, "redirector", entry);
+ break;
+ case MGR_AUTHENTICATORS:
+ HTTPCacheInfo->stat_get(HTTPCacheInfo, "authenticator", entry);
break;
case MGR_IO:
HTTPCacheInfo->stat_get(HTTPCacheInfo, "io", entry);
diff -urwN squid-1.1.20-orig/src/objcache_opcodes.h squid-1.1.20/src/objcache_opcodes.h
--- squid-1.1.20-orig/src/objcache_opcodes.h Fri Dec 13 23:26:38 1996
+++ squid-1.1.20/src/objcache_opcodes.h Mon Feb 9 22:00:38 1998
@@ -47,6 +47,7 @@
MGR_NETDB,
MGR_OBJECTS,
MGR_REDIRECTORS,
+ MGR_AUTHENTICATORS,
MGR_REFRESH,
MGR_REMOVE,
MGR_REPLY_HDRS,
@@ -77,6 +78,7 @@
"netdb",
"objects",
"redirectors",
+ "authenticators",
"refresh",
"remove",
"reply_headers",
diff -urwN squid-1.1.20-orig/src/squid.conf.pre.in squid-1.1.20/src/squid.conf.pre.in
--- squid-1.1.20-orig/src/squid.conf.pre.in Wed Dec 31 22:36:59 1997
+++ squid-1.1.20/src/squid.conf.pre.in Sat Mar 7 16:37:21 1998
@@ -587,6 +587,27 @@
#
#redirect_children 5
+# TAG: authenticate_program
+# Specify the location of the executable for the authenticator.
+# Such a program reads a line containing "username password"
+# and replies "OK" or "ERR" in an endless loop.
+# If you use an authenticator, make sure you have 1 acl of type
+# proxy_auth.
+# By default, the authenticator_program is not used. You must
+# define USE_PROXY_AUTH during compilation.
+#
+#authenticate_program /bin/false
+
+# TAG: authenticate_options
+# Options for the authenticate program.
+#
+#authenticate_options
+
+# TAG: authenticate_children
+# The number of authenticate programs to spawn.
+#
+#authenticate_children 5
+
# OPTIONS FOR TUNING THE CACHE
#-----------------------------------------------------------------------------
@@ -778,6 +799,22 @@
# acl aclname user username ... # string match on ident output.
# # use REQUIRED to accept any
# # non-null ident.
+# acl aclname proxy_auth [ timeout ]
+# Use an EXTERNAL authenticate program to check username/password
+# combinations (see authenticate_program).
+#
+# 'timeout' is the time a cached username/password entry remains
+# cached (default = 3600 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.
+#
+# 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.
acl manager proto cache_object
acl localhost src 127.0.0.1/255.255.255.255
@@ -997,23 +1034,6 @@
# passthrough_proxy host:port
#
#passthrough_proxy
-
-# TAG: proxy_auth
-# Usage: proxy_auth passwd_file [ ignore-domain ]
-#
-# '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.
-#
-# 'ignore-domain' is a domain name 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.
-#
-#proxy_auth /dev/null
# TAG: err_html_text
# HTML text to include in error messages. Make this a "mailto"
diff -urwN squid-1.1.20-orig/src/squid.h squid-1.1.20/src/squid.h
--- squid-1.1.20-orig/src/squid.h Tue Oct 21 18:08:53 1997
+++ squid-1.1.20/src/squid.h Thu Feb 12 21:55:35 1998
@@ -302,6 +302,9 @@
#include "acl.h"
#include "async_io.h"
#include "redirect.h"
+#ifdef USE_PROXY_AUTH
+#include "authenticate.h"
+#endif
#include "client_side.h"
#include "useragent.h"
#include "icmp.h"
diff -urwN squid-1.1.20-orig/src/stat.c squid-1.1.20/src/stat.c
--- squid-1.1.20-orig/src/stat.c Thu Aug 21 21:29:01 1997
+++ squid-1.1.20/src/stat.c Mon Feb 9 22:32:21 1998
@@ -423,6 +423,10 @@
dnsStats(sentry);
} else if (strcmp(req, "redirector") == 0) {
redirectStats(sentry);
+#ifdef USE_PROXY_AUTH
+ } else if (strcmp(req, "authenticator") == 0) {
+ authenticateStats(sentry);
+#endif
} else if (strcmp(req, "utilization") == 0) {
stat_utilization_get(HTTPCacheInfo, sentry, "HTTP");
stat_utilization_get(ICPCacheInfo, sentry, "ICP");