]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
external proxy_auth code from Arjan
authorwessels <>
Tue, 18 Aug 1998 04:04:52 +0000 (04:04 +0000)
committerwessels <>
Tue, 18 Aug 1998 04:04:52 +0000 (04:04 +0000)
src/Makefile.in
src/acl.cc
src/cache_cf.cc
src/cf.data.pre
src/defines.h
src/enums.h
src/main.cc
src/protos.h
src/structs.h

index 7c535a92170d28db56c93ef48d21a2e2becadfff..c624227a39aadd2823d91d7e6ad788728a75c228 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.in,v 1.157 1998/07/31 00:15:31 wessels Exp $
+#  $Id: Makefile.in,v 1.158 1998/08/17 22:04:52 wessels Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -26,6 +26,7 @@ DNSSERVER_EXE = dnsserver$(exec_suffix)
 UNLINKD_EXE    = unlinkd$(exec_suffix)
 PINGER_EXE     = pinger$(exec_suffix)
 CACHEMGR_EXE   = cachemgr$(cgi_suffix)
+NCSA_AUTH_EXE  = ncsa_auth$(exec_suffix)
 
 DEFAULT_CONFIG_FILE     = $(sysconfdir)/squid.conf
 DEFAULT_MIME_TABLE     = $(sysconfdir)/mime.conf
@@ -40,6 +41,8 @@ DEFAULT_UNLINKD               = $(libexecdir)/$(UNLINKD_EXE)
 DEFAULT_ICON_DIR       = $(sysconfdir)/icons
 DEFAULT_ERROR_DIR      = $(sysconfdir)/errors
 DEFAULT_MIB_PATH       = $(sysconfdir)/mib.txt
+DEFAULT_AUTH_PROGRAM   = $(bindir)/$(NCSA_AUTH_EXE)
+DEFAULT_PASSWD_FILE    = $(sysconfdir)/passwd
 
 CC             = @CC@
 MAKEDEPEND     = @MAKEDEPEND@
@@ -72,9 +75,10 @@ CLIENT_LIBS  = -L../lib -lmiscutil $(XTRA_LIBS)
 DNSSERVER_LIBS = -L../lib -lmiscutil $(XTRA_LIBS)
 PINGER_LIBS    = -L../lib -lmiscutil $(XTRA_LIBS)
 STD_APP_LIBS    = -L../lib -lmiscutil $(XTRA_LIBS)
+AUTH_LIBS      = -L../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
 
 PROGS           = $(SQUID_EXE) $(CLIENT_EXE)
-UTILS           = $(DNSSERVER_EXE) $(UNLINKD_EXE)
+UTILS           = $(DNSSERVER_EXE) $(UNLINKD_EXE) $(NCSA_AUTH_EXE)
 SUID_UTILS     = $(PINGER_EXE)
 CGIPROGS       = $(CACHEMGR_EXE)
 OBJS           = \
@@ -82,6 +86,7 @@ OBJS          = \
                acl.o \
                asn.o \
                @ASYNC_OBJS@ \
+               authenticate.o \
                cache_cf.o \
                CacheDigest.o \
                cache_manager.o \
@@ -220,6 +225,9 @@ $(PINGER_EXE): pinger.o
 $(UNLINKD_EXE): unlinkd-daemon.o
        $(CC) $(LDFLAGS) unlinkd-daemon.o -o $@
 
+$(NCSA_AUTH_EXE): ncsa_auth.o hash.o debug.o globals.o
+       $(CC) $(LDFLAGS) ncsa_auth.o hash.o debug.o globals.o -o $@ $(AUTH_LIBS)
+
 unlinkd-daemon.o: unlinkd.c
        $(CC) -c $(CFLAGS) -DUNLINK_DAEMON $(srcdir)/unlinkd.c -o $@
 
@@ -250,7 +258,9 @@ cf.data: cf.data.pre Makefile
        s%@DEFAULT_SWAP_DIR@%$(DEFAULT_SWAP_DIR)%g;\
        s%@DEFAULT_ICON_DIR@%$(DEFAULT_ICON_DIR)%g;\
         s%@DEFAULT_MIB_PATH@%$(DEFAULT_MIB_PATH)%g;\
-       s%@DEFAULT_ERROR_DIR@%$(DEFAULT_ERROR_DIR)%g" < $(srcdir)/cf.data.pre >$@
+       s%@DEFAULT_ERROR_DIR@%$(DEFAULT_ERROR_DIR)%g;\
+       s%@DEFAULT_AUTH_PROGRAM@%$(DEFAULT_AUTH_PROGRAM)%g;\
+       s%@DEFAULT_PASSWD_FILE@%$(DEFAULT_PASSWD_FILE)%g" < $(srcdir)/cf.data.pre >$@
 
 install-mkdirs:
        -@if test ! -d $(prefix); then \
index 5d3b7d12f96dc72f48e65e44d74da4500dcf4870..9c78e187691bf514bdebcb4b202412b5262ef779 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: acl.cc,v 1.175 1998/08/14 19:25:13 wessels Exp $
+ * $Id: acl.cc,v 1.176 1998/08/17 22:04:54 wessels Exp $
  *
  * DEBUG: section 28    Access Control
  * AUTHOR: Duane Wessels
@@ -60,7 +60,7 @@ static IPH aclLookupDstIPDone;
 static IPH aclLookupDstIPforASNDone;
 static FQDNH aclLookupSrcFQDNDone;
 static FQDNH aclLookupDstFQDNDone;
-static int aclReadProxyAuth(acl_proxy_auth * p);
+static void aclProxyAuthDone(void *data, char *result);
 static wordlist *aclDumpIpList(acl_ip_data * ip);
 static wordlist *aclDumpDomainList(void *data);
 static wordlist *aclDumpTimeSpecList(acl_time_data *);
@@ -646,39 +646,36 @@ aclParseDomainList(void *curlist)
 
 #endif /* USE_SPLAY_TREE */
 
-/* check for change password file each 300 seconds */
-#define CHECK_PROXY_FILE_TIME 300
+/* default proxy_auth timeout is 3600 seconds */
+#define PROXY_AUTH_TIMEOUT 3600
+
 static void
 aclParseProxyAuth(void *data)
 {
     acl_proxy_auth *p;
     acl_proxy_auth **q = data;
     char *t;
+
+    p = xcalloc(1, sizeof(acl_proxy_auth));
+
+    /* read timeout value (if any) */
     t = strtok(NULL, w_space);
-    if (t) {
-       p = xcalloc(1, sizeof(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);
-       }
+    if (t == NULL) {
+       p->timeout = PROXY_AUTH_TIMEOUT;
     } else {
-       debug(28, 0) ("no filename in acl proxy_auth, ignoring\n");
+       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((HASHCMP *) strcmp, 7921, hash_string)) < 0) {
+       debug(28, 0) ("aclParseProxyAuth: cannot create hash table, turning proxy_auth off\n");
+       *q = NULL;
+       return;
     }
-    *q = NULL;
+    *q = p;
     return;
 }
 
@@ -1116,6 +1113,13 @@ aclMatchIdent(wordlist * data, const char *ident)
     return 0;
 }
 
+/* aclMatchProxyAuth can return three exit codes:
+ * 0 : No such user; invalid Proxy-authorization: header;
+ * ask for Proxy-Authorization: header
+ * 1 : user validated OK
+ * -1 : check the password for this user via an external authenticator
+ */
+
 static int
 aclMatchProxyAuth(acl_proxy_auth * p, aclCheck_t * checklist)
 {
@@ -1136,51 +1140,65 @@ aclMatchProxyAuth(acl_proxy_auth * p, aclCheck_t * checklist)
     strtok(sent_auth, "\n");
     cleartext = uudecode(sent_auth);
     xfree(sent_auth);
-    debug(28, 3) ("aclMatchProxyAuth: cleartext = '%s'\n", cleartext);
+    debug(28, 6) ("aclMatchProxyAuth: cleartext = '%s'\n", cleartext);
     xstrncpy(sent_user, cleartext, USER_IDENT_SZ);
     xfree(cleartext);
     if ((passwd = strchr(sent_user, ':')) != NULL)
        *passwd++ = '\0';
     if (passwd == NULL) {
-       debug(28, 3) ("aclMatchProxyAuth: No passwd in auth blob\n");
+       debug(28, 1) ("aclMatchProxyAuth: no passwd in proxy authorization header\n");
        return 0;
     }
-    debug(28, 5) ("aclMatchProxyAuth: checking user %s\n", sent_user);
+    debug(28, 5) ("aclMatchProxyAuth: checking user '%s'\n", sent_user);
     /* copy username to checklist for logging on client-side */
     xstrncpy(checklist->request->user_ident, sent_user, USER_IDENT_SZ);
-    /* reread password file if necessary */
-    aclReadProxyAuth(p);
+
+    /* see if we already know this user */
     u = hash_lookup(p->hash, sent_user);
     if (NULL == u) {
-       /* User doesn't exist; deny them */
-       debug(28, 4) ("aclMatchProxyAuth: user %s does not exist\n", sent_user);
-       return 0;
-    }
-    /* See if we've already validated them */
-    *passwd |= 0x80;
-    if (0 == strcmp(u->passwd, passwd)) {
-       debug(28, 5) ("aclMatchProxyAuth: user %s previously validated\n",
+       /* user not yet known, ask external authenticator */
+       debug(28, 4) ("aclMatchProxyAuth: user '%s' not yet known\n", sent_user);
+    } else {
+       /* user already known, check password with the cached one */
+       if ((0 == strcmp(u->passwd, passwd)) &&
+           (u->expiretime > current_time.tv_sec)) {
+           debug(28, 5) ("aclMatchProxyAuth: user '%s' previously validated\n",
+               sent_user);
+           return 1;
+       }
+       /* password mismatch/timeout */
+       debug(28, 4) ("aclMatchProxyAuth: user '%s' password mismatch/timeout\n",
            sent_user);
-       return 1;
+       /* remove this user from the hash, making him unknown */
+       hash_remove_link(p->hash, (hash_link *) u);
+       aclFreeProxyAuthUser(u);
+    }
+
+    /* we've got an unknown user now */
+    if (checklist->auth_user == NULL) {
+       /* we must still check this user's password */
+       u = memAllocate(MEM_ACL_PROXY_AUTH_USER);
+       u->user = xstrdup(sent_user);
+       u->passwd = xstrdup(passwd);
+       u->passwd_ok = 0;
+       u->expiretime = 0;
+       checklist->auth_user = u;
+       debug(28, 4) ("aclMatchProxyAuth: going to ask authenticator\n");
+       return -1;
     }
-    *passwd &= (~0x80);
-#if HAVE_CRYPT
-    if (strcmp(u->passwd, crypt(passwd, u->passwd))) {
-#else
-    if (strcmp(u->passwd, passwd)) {
-#endif
-       /* Passwords differ, deny access */
-       p->last_time = 0;       /* Trigger a check of the password file */
-       debug(28, 4) ("aclMatchProxyAuth: authentication failed: user %s: "
-           "passwords differ\n", sent_user);
+    /* checklist->auth_user has just been checked, check result */
+    if (checklist->auth_user->passwd_ok == -1) {
+       /* password was checked but did not match */
+       debug(28, 4) ("aclMatchProxyAuth: authentication failed for user '%s'\n",
+           sent_user);
        return 0;
     }
-    *passwd |= 0x80;
-    debug(28, 5) ("aclMatchProxyAuth: user %s validated OK\n", sent_user);
-    hash_remove_link(p->hash, (hash_link *) u);
-    safe_free(u->passwd);
-    u->passwd = xstrdup(passwd);
-    hash_join(p->hash, (hash_link *) u);
+    /* checklist->auth_user->passwd_ok == 1, passwd check OK */
+    debug(28, 4) ("aclMatchProxyAuth: user '%s' validated OK\n", sent_user);
+    /* store validated user in hash, after filling in expiretime */
+    checklist->auth_user->expiretime = current_time.tv_sec + p->timeout;
+    hash_join(p->hash, (hash_link *) checklist->auth_user);
+
     return 1;
 }
 
@@ -1344,15 +1362,20 @@ aclMatchAcl(acl * acl, aclCheck_t * checklist)
        return aclMatchRegex(acl->data, checklist->browser);
        /* NOTREACHED */
     case ACL_PROXY_AUTH:
-       if (!aclMatchProxyAuth(acl->data, checklist)) {
+       k = aclMatchProxyAuth(acl->data, checklist);
+       if (k == 0) {
            /* no such user OR we need a proxy authentication header */
-           checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_NEEDED;
+           checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED;
            return 0;
-       } else {
+       } else if (k == 1) {
            /* register that we used the proxy authentication header */
-           checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE;
+           checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_USED;
            EBIT_SET(r->flags, REQ_USED_PROXY_AUTH);
            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;
        }
        /* NOTREACHED */
     case ACL_SNMP_COMM:
@@ -1472,17 +1495,25 @@ aclCheck(aclCheck_t * checklist)
                checklist);
            return;
        }
+       /* extra case for proxy_auth */
+       if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_CHECK) {
+           debug(28, 3) ("aclCheck: checking password via authenticator\n");
+           authenticateStart(checklist->auth_user, aclProxyAuthDone,
+               checklist);
+           return;
+       }
        /*
         * We are done with this _acl_access entry.  Either the request
         * is allowed, denied, or we move on to the next entry.
         */
        cbdataUnlock(A);
-       if (checklist->state[ACL_PROXY_AUTH] == ACL_LOOKUP_NEEDED) {
+       if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED) {
            allow = ACCESS_REQ_PROXY_AUTH;
            debug(28, 3) ("aclCheck: match pending, returning %d\n", allow);
            aclCheckCallback(checklist, allow);
            return;
        }
+       /* checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_USED */
        if (match) {
            debug(28, 3) ("aclCheck: match found, returning %d\n", allow);
            aclCheckCallback(checklist, allow);
@@ -1533,6 +1564,7 @@ aclLookupDstIPDone(const ipcache_addrs * ia, void *data)
     checklist->state[ACL_DST_IP] = ACL_LOOKUP_DONE;
     aclCheck(checklist);
 }
+
 static void
 aclLookupDstIPforASNDone(const ipcache_addrs * ia, void *data)
 {
@@ -1557,6 +1589,19 @@ aclLookupDstFQDNDone(const char *fqdn, void *data)
     aclCheck(checklist);
 }
 
+static void
+aclProxyAuthDone(void *data, char *result)
+{
+    aclCheck_t *checklist = data;
+    checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE;
+    debug(28, 4) ("aclProxyAuthDone: result = %s\n", result);
+    if (result && (strncasecmp(result, "OK", 2) == 0))
+       checklist->auth_user->passwd_ok = 1;
+    else
+       checklist->auth_user->passwd_ok = -1;
+    aclCheck(checklist);
+}
+
 aclCheck_t *
 aclChecklistCreate(const acl_access * A,
     request_t * request,
@@ -1565,7 +1610,7 @@ aclChecklistCreate(const acl_access * A,
     const char *ident)
 {
     int i;
-    aclCheck_t *checklist = xcalloc(1, sizeof(aclCheck_t));;
+    aclCheck_t *checklist = xcalloc(1, sizeof(aclCheck_t));
     cbdataAdd(checklist, MEM_NONE);
     checklist->access_list = A;
     /*
@@ -1582,6 +1627,7 @@ aclChecklistCreate(const acl_access * A,
        xstrncpy(checklist->browser, user_agent, BROWSERNAMELEN);
     if (ident)
        xstrncpy(checklist->ident, ident, USER_IDENT_SZ);
+    checklist->auth_user = NULL;       /* init to NULL */
     return checklist;
 }
 
@@ -1658,7 +1704,6 @@ aclDestroyProxyAuth(acl_proxy_auth * p)
     hashFreeItems(p->hash, aclFreeProxyAuthUser);
     hashFreeMemory(p->hash);
     p->hash = NULL;
-    safe_free(p->filename);
     safe_free(p);
 }
 
@@ -1795,62 +1840,6 @@ aclDomainCompare(const void *data, splayNode * n)
 
 #endif /* 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(acl_proxy_auth * p)
-{
-    struct stat buf;
-    static char *passwords = NULL;
-    char *user = NULL;
-    char *passwd = NULL;
-    FILE *f = NULL;
-    if ((squid_curtime - p->last_time) < p->check_interval)
-       return 1;
-    if (0 != stat(p->filename, &buf)) {
-       debug(28, 0) ("aclReadProxyAuth: can't access proxy_auth file %s, turning authentication off\n", p->filename);
-       return 0;
-    }
-    if (buf.st_mtime == p->change_time) {
-       debug(28, 5) ("aclReadProxyAuth: %s not changed (old=%d,new=%d)\n",
-           p->filename, (int) p->change_time, (int) buf.st_mtime);
-       p->last_time = squid_curtime;
-       return 1;
-    }
-    debug(28, 1) ("aclReadProxyAuth: reloading changed proxy authentication file %s\n", p->filename);
-    p->change_time = buf.st_mtime;
-    if (NULL != p->hash) {
-       hashFreeItems(p->hash, aclFreeProxyAuthUser);
-       hashFreeMemory(p->hash);
-    }
-    p->hash = hash_create((HASHCMP *) strcmp, 7921, hash_string);
-    assert(NULL != p->hash);
-    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 ((int) strlen(user) > 1 && passwd && (int) strlen(passwd) > 1) {
-           acl_proxy_auth_user *u;
-           u = memAllocate(MEM_ACL_PROXY_AUTH_USER);
-           u->user = xstrdup(user);
-           u->passwd = xstrdup(passwd);
-           debug(28, 6) ("aclReadProxyAuth: adding %s, %s to hash table\n", user, passwd);
-           hash_join(p->hash, (hash_link *) u);
-       }
-       user = strtok(NULL, ":");
-       passwd = strtok(NULL, "\n");
-    }
-    xfree(passwords);
-    return 1;
-}
-
-
 /* compare a host and a domain */
 
 #if defined(USE_SPLAY_TREE)
@@ -2087,7 +2076,7 @@ aclDumpProxyAuthList(acl_proxy_auth * data)
     char buf[MAXPATHLEN];
     wordlist *w = xcalloc(1, sizeof(wordlist));
     assert(data != NULL);
-    snprintf(buf, sizeof(buf), "%s %d\n", data->filename, data->check_interval);
+    snprintf(buf, sizeof(buf), "%d\n", data->timeout);
     w->key = xstrdup(buf);
     *T = w;
     T = &w->next;
index 25744f0f52a033842317bdb961ab267eb94ef2b6..119cb28b11e8b1fd6208f09d96c28b7fc808adfe 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cache_cf.cc,v 1.296 1998/08/17 21:35:49 wessels Exp $
+ * $Id: cache_cf.cc,v 1.297 1998/08/17 22:04:55 wessels Exp $
  *
  * DEBUG: section 3     Configuration File Parsing
  * AUTHOR: Harvest Derived
@@ -267,6 +267,17 @@ configDoConfigure(void)
            Config.redirectChildren = DefaultRedirectChildrenMax;
        }
     }
+    if (Config.Program.authenticate) {
+       if (Config.authenticateChildren < 1) {
+           Config.authenticateChildren = 0;
+           safe_free(Config.Program.authenticate);
+       } else if (Config.authenticateChildren > DefaultAuthenticateChildrenMax) {
+           debug(3, 0) ("WARNING: authenticate_children was set to a bad value: %d\n",
+               Config.authenticateChildren);
+           debug(3, 0) ("Setting it to the maximum (%d).\n", DefaultAuthenticateChildrenMax);
+           Config.authenticateChildren = DefaultAuthenticateChildrenMax;
+       }
+    }
     if (Config.Accel.host) {
        snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
        Config2.Accel.prefix = xstrdup(buf);
@@ -311,19 +322,21 @@ configDoConfigure(void)
     requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
     if (Config.Program.redirect)
        requirePathnameExists("redirect_program", Config.Program.redirect);
+    if (Config.Program.authenticate)
+       requirePathnameExists("authenticate_program", Config.Program.authenticate);
     requirePathnameExists("Icon Directory", Config.icons.directory);
     requirePathnameExists("Error Directory", Config.errorDirectory);
     for (R = Config.Refresh; R; R = R->next) {
-        if (!R->flags.override_expire)
+       if (!R->flags.override_expire)
            continue;
-        debug(22,1)("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
-        break;
+       debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
+       break;
     }
     for (R = Config.Refresh; R; R = R->next) {
-        if (!R->flags.override_lastmod)
+       if (!R->flags.override_lastmod)
            continue;
-        debug(22,1)("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
-        break;
+       debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
+       break;
     }
 }
 
index f1d30a68bad2eb4bc1edbcd5b37bf7af1d1fdb6d..f2170e4ae88ac2cb139cecdd49109892d0710db9 100644 (file)
@@ -1,6 +1,6 @@
 
 #
-# $Id: cf.data.pre,v 1.96 1998/08/17 21:27:31 wessels Exp $
+# $Id: cf.data.pre,v 1.97 1998/08/17 22:04:56 wessels Exp $
 #
 #
 # SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -921,6 +921,47 @@ DOC_START
 redirect_children 5
 DOC_END
 
+NAME: authenticate_program
+TYPE: string
+LOC: Config.Program.authenticate
+DEFAULT: none
+DOC_START
+       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.
+
+authenticate_program @DEFAULT_AUTH_PROGRAM@
+DOC_END
+
+
+NAME: authenticate_options
+TYPE: wordlist
+LOC: Config.Program.authenticate_options
+DEFAULT: none
+DOC_START
+       Command line options for the authenticate program.
+
+authenticate_options @DEFAULT_PASSWD_FILE@
+DOC_END
+
+
+NAME: authenticate_children
+TYPE: int
+DEFAULT: 5
+LOC: Config.authenticateChildren
+DOC_START
+       The number of authenticator processes to spawn (default 5). If you
+       start too few Squid will have to wait for them to process a backlog
+       of usercode/password verifications, slowing it down. When password
+       verifications are done via a (slow) network you are likely to need
+       lots of authenticator processes.
+
+authenticate_children 5
+DOC_END
+
 COMMENT_START
  OPTIONS FOR TUNING THE CACHE
  -----------------------------------------------------------------------------
@@ -1300,17 +1341,22 @@ DOC_START
          # cache_peer_acl mycache.mydomain.net asexample
          # cache_peer_acl mycache_mydomain.net !all
 
-       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 aclname proxy_auth [ refresh ]
+         # Use an EXTERNAL authentication program to check username/password
+         # combinations (see authenticate_program).
+         #
+         # 'timeout' is the time a checked username/password combination
+         # remains cached (default = 3600 secs). If a wrong password
+         # is given for a cached user, the user gets removed from the
+         # username/password cache forcing a revalidation.
+         #
+         # When using a proxy_auth ACL in an http_access rule, 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
@@ -1319,6 +1365,7 @@ acl myexample dst_as 1241
 acl SSL_ports port 443 563
 acl Dangerous_ports port 7 9 19
 acl CONNECT method CONNECT
+acl password proxy_auth 300
 DOC_END
 
 NAME: http_access
index 9adf6b62b0b1941375f8c8d5b8600b0256ea65ea..4308108a49785dc6e78088629c0db2b6532c2702 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: defines.h,v 1.62 1998/07/22 20:53:54 wessels Exp $
+ * $Id: defines.h,v 1.63 1998/08/17 22:04:57 wessels Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -53,6 +53,7 @@
 
 #define DefaultDnsChildrenMax          32      /* 32 processes */
 #define DefaultRedirectChildrenMax     32      /* 32 processes */
+#define DefaultAuthenticateChildrenMax 32      /* 32 processes */
 #define MAXHTTPPORTS                   12
 
 #define COMM_OK                  (0)
 #define REDIRECT_PENDING 1
 #define REDIRECT_DONE 2
 
+#define AUTHENTICATE_AV_FACTOR 1000
+
+#define AUTHENTICATE_NONE 0
+#define AUTHENTICATE_PENDING 1
+#define AUTHENTICATE_DONE 2
+
 #define  CONNECT_PORT        443
 
 #define current_stacksize(stack) ((stack)->top - (stack)->base)
index eaff66dfff573e490519bea6dc09f8c2b92b8580..38aa57804692a4de64cfe6d22e24e9d71a4e7ce3 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: enums.h,v 1.117 1998/08/17 19:19:34 wessels Exp $
+ * $Id: enums.h,v 1.118 1998/08/17 22:04:58 wessels Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -113,7 +113,10 @@ typedef enum {
     ACL_LOOKUP_NONE,
     ACL_LOOKUP_NEEDED,
     ACL_LOOKUP_PENDING,
-    ACL_LOOKUP_DONE
+    ACL_LOOKUP_DONE,
+    ACL_PROXY_AUTH_NEEDED,
+    ACL_PROXY_AUTH_USED,
+    ACL_PROXY_AUTH_CHECK
 } acl_lookup_state;
 
 enum {
index 9acb4e78805c03f6b7498259e24c0323f1ec0996..587c780b4a1829928c614da1fffe30ecea59e5ea 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.cc,v 1.268 1998/08/11 20:07:03 wessels Exp $
+ * $Id: main.cc,v 1.269 1998/08/17 22:04:59 wessels Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
@@ -316,6 +316,7 @@ mainReconfigure(void)
 #endif
     dnsShutdownServers(NULL);
     redirectShutdownServers(NULL);
+    authenticateShutdownServers(NULL);
     storeDirCloseSwapLogs();
     errorFree();
     parseConfigFile(ConfigFile);
@@ -325,6 +326,7 @@ mainReconfigure(void)
     errorInitialize();         /* reload error pages */
     dnsOpenServers();
     redirectOpenServers();
+    authenticateOpenServers();
     serverConnectionsOpen();
     if (theOutIcpConnection >= 0 && (!Config2.Accel.on || Config.onoff.accel_with_proxy))
        neighbors_open(theOutIcpConnection);
@@ -400,6 +402,7 @@ mainInitialize(void)
     fqdncache_init();
     dnsOpenServers();
     redirectOpenServers();
+    authenticateOpenServers();
     useragentOpenLog();
     httpHeaderInitModule();    /* must go before any header processing (e.g. the one in errorInitialize) */
     httpAnonInitModule();      /* must go before accepting requests */
@@ -567,6 +570,7 @@ main(int argc, char **argv)
            serverConnectionsClose();
            eventAdd("dnsShutdownServers", dnsShutdownServers, NULL, 0.0, 1);
            eventAdd("redirectShutdownServers", redirectShutdownServers, NULL, 0.0, 1);
+           eventAdd("authenticateShutdownServers", authenticateShutdownServers, NULL, 0.0, 1);
            eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
        }
        eventRun();
index fb93f5931ecf2886eae3e87d5091c0deab7d6f1e..42d2edcca98f2efc2153ec5ae21b8353945ee611 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.248 1998/08/17 16:44:09 wessels Exp $
+ * $Id: protos.h,v 1.249 1998/08/17 22:05:01 wessels Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -645,6 +645,13 @@ extern void redirectStats(StoreEntry *);
 extern int redirectUnregister(const char *url, void *);
 extern void redirectFreeMemory(void);
 
+extern void authenticateStart(acl_proxy_auth_user *, RH *, void *);
+extern void authenticateOpenServers(void);
+extern void authenticateShutdownServers(void *);
+extern void authenticateStats(StoreEntry *);
+extern int authenticateUnregister(const char *url, void *);
+extern void authenticateFreeMemory(void);
+
 extern void refreshAddToList(const char *, int, time_t, int, time_t);
 extern int refreshCheck(const StoreEntry *, request_t *, time_t delta);
 extern time_t refreshWhen(const StoreEntry * entry);
index 227f13f0a1ab6fd07c4917572ca3eb3b25bccf60..656eb3594120040eb6a2a933e714ffb695b5fbd2 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.200 1998/08/17 21:27:33 wessels Exp $
+ * $Id: structs.h,v 1.201 1998/08/17 22:05:02 wessels Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -57,10 +57,7 @@ struct _acl_name_list {
 };
 
 struct _acl_proxy_auth {
-    char *filename;
-    time_t last_time;
-    time_t change_time;
-    int check_interval;
+    int timeout;               /* timeout value for cached usercode:password entries */
     hash_table *hash;
 };
 
@@ -68,7 +65,10 @@ struct _acl_proxy_auth_user {
     /* first two items must be same as hash_link */
     char *user;
     acl_proxy_auth_user *next;
+    /* extra fields for proxy_auth */
     char *passwd;
+    int passwd_ok;             /* 1 = passwd checked OK */
+    long expiretime;
 };
 
 struct _acl_deny_info_list {
@@ -170,6 +170,7 @@ struct _aclCheck_t {
     request_t *request;
     char ident[USER_IDENT_SZ];
     char browser[BROWSERNAMELEN];
+    acl_proxy_auth_user *auth_user;
     acl_lookup_state state[ACL_ENUM_MAX];
     PF *callback;
     void *callback_data;
@@ -282,11 +283,14 @@ struct _SquidConfig {
     struct {
        char *dnsserver;
        char *redirect;
+       char *authenticate;
+       wordlist *authenticate_options;
        char *pinger;
        char *unlinkd;
     } Program;
     int dnsChildren;
     int redirectChildren;
+    int authenticateChildren;
     struct {
        char *host;
        u_short port;