---------------------
PatchSet 974 
Date: 2000/12/21 04:17:37
Author: rbcollins
Branch: auth_digest
Tag: (none) 
Log:
multiple nonces handled and invalid nonces rejected.

Members: 
	src/authenticate.c:1.1.1.3.12.17.2.11.2.1->1.1.1.3.12.17.2.11.2.2 
	src/protos.h:1.1.1.3.12.17.2.9->1.1.1.3.12.17.2.9.2.1 
	src/structs.h:1.1.1.3.4.1.2.26.2.12.2.1->1.1.1.3.4.1.2.26.2.12.2.2 
	src/tools.c:1.1.1.3.10.7.2.2->1.1.1.3.10.7.2.2.2.1 
	src/typedefs.h:1.1.1.3.12.13.2.9->1.1.1.3.12.13.2.9.2.1 
	src/auth/digest/auth_digest.c:1.1.2.5->1.1.2.6 
	src/auth/digest/auth_digest.h:1.1.2.2->1.1.2.3 

Index: squid/src/authenticate.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/authenticate.c,v
retrieving revision 1.1.1.3.12.17.2.11.2.1
retrieving revision 1.1.1.3.12.17.2.11.2.2
diff -u -r1.1.1.3.12.17.2.11.2.1 -r1.1.1.3.12.17.2.11.2.2
--- squid/src/authenticate.c	18 Dec 2000 10:02:47 -0000	1.1.1.3.12.17.2.11.2.1
+++ squid/src/authenticate.c	21 Dec 2000 04:17:37 -0000	1.1.1.3.12.17.2.11.2.2
@@ -1,6 +1,6 @@
 
 /*
- * $Id: authenticate.c,v 1.1.1.3.12.17.2.11.2.1 2000/12/18 10:02:47 rbcollins Exp $
+ * $Id: authenticate.c,v 1.1.1.3.12.17.2.11.2.2 2000/12/21 04:17:37 rbcollins Exp $
  *
  * DEBUG: section 29    Authenticator
  * AUTHOR: Duane Wessels
@@ -164,10 +164,17 @@
 int
 authenticateUserAuthenticated(auth_user_t *auth_user) {
     assert(authenticateValidateUser(auth_user));
+    if (auth_user->auth_module>0)
+        return authscheme_list[auth_user->auth_module-1].authenticated(auth_user);
+    else
+        return 0;
+#if 0
+ Digest puts users in the hash as soon as the username is known
     /* if they are in the hash they must be authenticated */
     if (auth_user->usernamehash) return 1;
     debug (29, 7) ("Couldn't find user in cache: assuming not logged in.\n");
     return 0;
+#endif
 }
 
 /*
@@ -435,7 +442,7 @@
     }
     /* free cached acl results */
     aclCacheMatchFlush(&u->proxy_match_cache);
-    if (u->auth_module>0)
+    if (u->scheme_data && u->auth_module>0)
         authscheme_list[u->auth_module-1].FreeUser(u);
 #if 0
     switch (u->auth_type) {
Index: squid/src/protos.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/protos.h,v
retrieving revision 1.1.1.3.12.17.2.9
retrieving revision 1.1.1.3.12.17.2.9.2.1
diff -u -r1.1.1.3.12.17.2.9 -r1.1.1.3.12.17.2.9.2.1
--- squid/src/protos.h	13 Dec 2000 01:23:31 -0000	1.1.1.3.12.17.2.9
+++ squid/src/protos.h	21 Dec 2000 04:17:37 -0000	1.1.1.3.12.17.2.9.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.1.1.3.12.17.2.9 2000/12/13 01:23:31 rbcollins Exp $
+ * $Id: protos.h,v 1.1.1.3.12.17.2.9.2.1 2000/12/21 04:17:37 rbcollins Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -1100,6 +1100,9 @@
 extern void dlinkAdd(void *data, dlink_node *, dlink_list *);
 extern void dlinkAddTail(void *data, dlink_node *, dlink_list *);
 extern void dlinkDelete(dlink_node * m, dlink_list * list);
+extern void dlinkNodeDelete(dlink_node * m);
+extern dlink_node *dlinkNodeNew();
+
 extern void kb_incr(kb_t *, size_t);
 extern double gb_to_double(const gb_t *);
 extern const char *gb_to_str(const gb_t *);
Index: squid/src/structs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/structs.h,v
retrieving revision 1.1.1.3.4.1.2.26.2.12.2.1
retrieving revision 1.1.1.3.4.1.2.26.2.12.2.2
diff -u -r1.1.1.3.4.1.2.26.2.12.2.1 -r1.1.1.3.4.1.2.26.2.12.2.2
--- squid/src/structs.h	15 Dec 2000 16:19:18 -0000	1.1.1.3.4.1.2.26.2.12.2.1
+++ squid/src/structs.h	21 Dec 2000 04:17:37 -0000	1.1.1.3.4.1.2.26.2.12.2.2
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.1.1.3.4.1.2.26.2.12.2.1 2000/12/15 16:19:18 rbcollins Exp $
+ * $Id: structs.h,v 1.1.1.3.4.1.2.26.2.12.2.2 2000/12/21 04:17:37 rbcollins Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -113,6 +113,7 @@
 //    STFSPARSE *parsefunc;
 //    AUTHSRECONFIGURE *reconfigurefunc;
     AUTHSACTIVE   *Active;
+    AUTHSAUTHED   *authenticated;
     AUTHSAUTHUSER *authAuthenticate;
     AUTHSFIXERR   *authFixErrorHeader;
     AUTHSFREE     *FreeUser;
Index: squid/src/tools.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/tools.c,v
retrieving revision 1.1.1.3.10.7.2.2
retrieving revision 1.1.1.3.10.7.2.2.2.1
diff -u -r1.1.1.3.10.7.2.2 -r1.1.1.3.10.7.2.2.2.1
--- squid/src/tools.c	13 Dec 2000 01:23:31 -0000	1.1.1.3.10.7.2.2
+++ squid/src/tools.c	21 Dec 2000 04:17:37 -0000	1.1.1.3.10.7.2.2.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: tools.c,v 1.1.1.3.10.7.2.2 2000/12/13 01:23:31 rbcollins Exp $
+ * $Id: tools.c,v 1.1.1.3.10.7.2.2.2.1 2000/12/21 04:17:37 rbcollins Exp $
  *
  * DEBUG: section 21    Misc Functions
  * AUTHOR: Harvest Derived
@@ -62,6 +62,8 @@
 
 extern void (*failure_notify) (const char *);
 
+MemPool *dlink_node_pool = NULL;
+
 void
 releaseServerSockets(void)
 {
@@ -753,6 +755,24 @@
     return p ? p : "(NULL)";
 }
 
+dlink_node *
+dlinkNodeNew()
+{
+    if (dlink_node_pool==NULL)
+        dlink_node_pool = memPoolCreate("Dlink list nodes", sizeof(dlink_node));
+    /* where should we call memPoolDestroy(dlink_node_pool); */
+    return memPoolAlloc(dlink_node_pool);
+}
+
+/* the node needs to be unlinked FIRST */
+void
+dlinkNodeDelete(dlink_node * m)
+{
+    if (m==NULL)
+        return;
+    memPoolFree(dlink_node_pool, m);
+}
+
 void
 dlinkAdd(void *data, dlink_node * m, dlink_list * list)
 {
Index: squid/src/typedefs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v
retrieving revision 1.1.1.3.12.13.2.9
retrieving revision 1.1.1.3.12.13.2.9.2.1
diff -u -r1.1.1.3.12.13.2.9 -r1.1.1.3.12.13.2.9.2.1
--- squid/src/typedefs.h	11 Dec 2000 23:32:15 -0000	1.1.1.3.12.13.2.9
+++ squid/src/typedefs.h	21 Dec 2000 04:17:37 -0000	1.1.1.3.12.13.2.9.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: typedefs.h,v 1.1.1.3.12.13.2.9 2000/12/11 23:32:15 rbcollins Exp $
+ * $Id: typedefs.h,v 1.1.1.3.12.13.2.9.2.1 2000/12/21 04:17:37 rbcollins Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -291,6 +291,7 @@
 
 /* authenticate.c authenticate scheme routines typedefs */
 typedef int   AUTHSACTIVE();
+typedef int   AUTHSAUTHED(auth_user_t *);
 typedef auth_user_t * AUTHSAUTHUSER(auth_user_t *, request_t *, ConnStateData *, http_hdr_type);
 typedef void  AUTHSDECODE(auth_user_t *, const char *);
 typedef int   AUTHSDIRECTION(auth_user_t *);
Index: squid/src/auth/digest/auth_digest.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/auth/digest/auth_digest.c,v
retrieving revision 1.1.2.5
retrieving revision 1.1.2.6
diff -u -r1.1.2.5 -r1.1.2.6
--- squid/src/auth/digest/auth_digest.c	18 Dec 2000 10:02:47 -0000	1.1.2.5
+++ squid/src/auth/digest/auth_digest.c	21 Dec 2000 04:17:37 -0000	1.1.2.6
@@ -52,6 +52,7 @@
 
 static HLPCB authenticateDigestHandleReply;
 static AUTHSACTIVE    authenticateDigestActive;
+static AUTHSAUTHED    authDigestAuthenticated;
 static AUTHSAUTHUSER  authenticateDigestAuthenticateUser;
 static AUTHSDIRECTION authenticateDigestDirection;
 static AUTHSDECODE    authenticateDigestDecodeAuth;
@@ -67,48 +68,230 @@
 static hash_table *digest_nonce_cache;
 
 static int authdigest_initialised = 0;
-MemPool *digest_data_pool = NULL;
+MemPool *digest_user_pool = NULL;
+MemPool *digest_request_pool = NULL;
 MemPool *digest_nonce_pool = NULL;
 
 /*
  *
- * Private Functions
+ * Nonce Functions
  *
  */
 
-digest_nonce_ptr *
-authenticateDigestNonceCreate()
+static void authenticateDigestNonceCacheCleanup (void *data);
+static digest_nonce_h *authenticateDigestNonceFindNonce(const char *nonceb64);
+
+digest_nonce_h *
+authenticateDigestNonceNew()
 {
-    digest_nonce_ptr *newnonce = memPoolAlloc(digest_nonce_pool);
-    newnonce->nonce=xstrdup("aaaaa");
+    digest_nonce_h *newnonce = memPoolAlloc(digest_nonce_pool);
+    digest_nonce_h *temp;
+
+    /* create a new nonce */
+    newnonce->noncedata.creationtime=squid_curtime+random()*10;
+    if (newnonce->nonceb64)
+        xfree(newnonce->nonceb64);
+    newnonce->nonceb64=xstrdup(base64_encode_bin((char *)&(newnonce->noncedata),sizeof(digest_nonce_data)));
+    /* loop until we get a unique nonce. The nonce creation must have a random factor*/
+    while ((temp=authenticateDigestNonceFindNonce(newnonce->nonceb64)))
+    {
+        /* create a new nonce */
+        newnonce->noncedata.creationtime=squid_curtime;
+        if (newnonce->nonceb64)
+            xfree(newnonce->nonceb64);
+        newnonce->nonceb64=xstrdup(base64_encode_bin((char *)&(newnonce->noncedata),sizeof(digest_nonce_data)));
+    }
     hash_join(digest_nonce_cache, (hash_link *) newnonce);
     return newnonce;
 }
 
 void
-authenticateDigestNonceDestroy(digest_nonce_ptr *nonce)
+authenticateDigestNonceDelete(digest_nonce_h *nonce)
 {
     if (nonce)
     {
         hash_remove_link(digest_nonce_cache, (hash_link *)nonce);
-        xfree(nonce->nonce);
+        xfree(nonce->nonceb64);
         memPoolFree(digest_nonce_pool, nonce);
     }
 } 
 
+void authenticateDigestNonceSetup()
+{
+    if (!digest_nonce_pool)
+        digest_nonce_pool = memPoolCreate("Digest Scheme nonce's", sizeof(digest_nonce_h));
+    if (!digest_nonce_cache)
+    {
+        digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
+        assert(digest_nonce_cache);
+        /* TODO: make the GCinvterval digest specific */
+        eventAdd("Digest none cache maintenance",authenticateDigestNonceCacheCleanup, NULL, Config.authenticateGCInterval,1);
+    }
+}
+
+void authenticateDigestNonceShutdown()
+{
+    /* TODO: clean and empty the cache*/
+    memPoolDestroy(digest_nonce_pool);
+}
+
+void authenticateDigestNonceReconfigure()
+{
+}
+
+void
+authenticateDigestNonceCacheCleanup(void *data)
+{
+    /*
+     * We walk the hash by nonceb64 as that is the unique key we use.
+     * For big hashs tables we could consider stepping through the cache, 100/200
+     * entries at a time. Lets see how it flys first.
+     */
+    digest_nonce_h *nonce;
+    char * nonceb64=NULL;
+    debug(29,3) ("authenticateDigestNonceCacheCleanup: Cleaning the nonce cache now\n");
+    debug(29,3) ("authenticateDigestNonceCacheCleanup: Current time: %d\n", 
+        current_time.tv_sec);
+    hash_first(digest_nonce_cache);
+    while ((nonce=((digest_nonce_h *)hash_next(digest_nonce_cache)))) {
+        debug(29,6) ("authenticateDigestNonceCacheCleanup: nonce entry  : '%s'\n", nonce->nonceb64);
+        debug(29,6) ("authenticateDigestNonceCacheCleanup: Creation time: %d\n", nonce->noncedata.creationtime);
+#if 0
+        if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
+            debug(29,3)("authenticateProxyUserCacheCleanup: Removing user %s from cache due to timeout.\n",username);
+            if (authenticateAuthUserInuse(auth_user))
+                debug(29,3)("authenticateProxyUserCacheCleanup: this cache entry has expired AND has a non-zero ref count.\n");
+            else
+                authenticateFreeProxyAuthUser(auth_user);
+        }
+#endif
+    }
+    debug(29,6) ("authenticateDigestNonceCacheCleanup: Finished cleaning the nonce cache.\n");
+        eventAdd("Digest none cache maintenance",authenticateDigestNonceCacheCleanup, NULL, Config.authenticateGCInterval,1);
+}
+
+
+const char *
+authenticateDigestNonceNonceb64(digest_nonce_h *nonce)
+{
+    if (!nonce)
+        return NULL;
+    return nonce->nonceb64;
+}
+
+digest_nonce_h *
+authenticateDigestNonceFindNonce(const char *nonceb64)
+{
+    digest_nonce_h *nonce=NULL;
+    if (nonceb64==NULL)
+        return NULL;
+    debug(29,6)("authDigestNonceFindNonce:looking for nonceb64 '%s' in the nonce cache.\n",nonceb64);
+    if ((nonce = hash_lookup(digest_nonce_cache, nonceb64))) 
+        while ((strcmp(nonce->nonceb64,nonceb64)) && (nonce->next))
+            nonce=nonce->next;
+    if ((nonce == NULL) || (strcmp(nonce->nonceb64,nonceb64)))
+        return NULL;
+    debug(29,6)("authDigestNonceFindNonce: Found nonce '%d'\n",nonce);
+    return nonce;
+}
+
+/* USER related functions */
+
+
+int
+authDigestUsercmpname(digest_user_h * u1, digest_user_h *u2)
+{
+    return strcmp(u1->username,u2->username);
+}
+
+digest_user_h *
+authDigestUserFindUsername(const char * username)
+{
+    auth_user_hash_pointer *usernamehash;
+    digest_request_h *digest_request;
+    digest_user_h * digest_user;
+    debug(29,9)("authDigestUserFindUsername: Looking for user '%s'\n",username);
+    if (username && (usernamehash = hash_lookup(proxy_auth_username_cache, username)))
+    {
+        while ((usernamehash->auth_user->auth_type != AUTH_DIGEST) &&
+            (usernamehash->next))
+            usernamehash=usernamehash->next;
+        digest_user=NULL;
+        if (usernamehash->auth_user->auth_type==AUTH_DIGEST)
+        {
+            digest_request=usernamehash->auth_user->scheme_data;
+            digest_user=digest_request->user;
+        }
+        return digest_user;
+    }
+    return NULL;
+}
+
+digest_user_h *
+authDigestUserNew()
+{
+    return memPoolAlloc(digest_user_pool);
+}
+
+void
+authDigestUserSetup()
+{
+    if (!digest_user_pool)
+        digest_user_pool = memPoolCreate("Digest Scheme User Data", sizeof(digest_user_h));
+}
+
+void
+authDigestUserShutdown()
+{
+    memPoolDestroy(digest_user_pool);
+}
+
+
+/* request related functions */
+
+/* delete the digest reuqest structure. Does NOT delete related structures */
+void
+authDigestRequestDelete(digest_request_h *digest_request)
+{
+
+}
+
+digest_request_h *
+authDigestRequestNew()
+{
+    return memPoolAlloc(digest_request_pool);
+}
+
+void
+authDigestRequestSetup()
+{
+    if (!digest_request_pool)
+        digest_request_pool = memPoolCreate("Digest Scheme Request Data", sizeof(digest_request_h));
+}
+
+void
+authDigestRequestShutdown()
+{
+    memPoolDestroy(digest_request_pool);
+}
+
+
 void
 authDigestDone(void)
 {
-//    memPoolDestroy(ufs_state_pool);
    if (digestauthenticators)
        helperShutdown(digestauthenticators);
     authdigest_initialised = 0;
     if (!shutting_down)
+    {
+        authenticateDigestNonceReconfigure();
         return;
+    }
     helperFree(digestauthenticators);
     digestauthenticators = NULL;
-    memPoolDestroy(digest_data_pool);
-    memPoolDestroy(digest_nonce_pool);
+    authDigestUserShutdown();
+    authDigestRequestShutdown();
+    authenticateDigestNonceShutdown();
 }
 
 void 
@@ -118,41 +301,35 @@
 //    authscheme->parsefunc = storeUfsDirParse;
 //    authscheme->reconfigurefunc = storeUfsDirReconfigure;
     authscheme->Active            =authenticateDigestActive;
-    if (Config.Program.digestauthenticate){
-    authscheme->authAuthenticate = authenticateDigestAuthenticateUser;
-    authscheme->authFixErrorHeader=authenticateDigestFixErrorHeader;
-    authscheme->FreeUser          =authenticateDigestFreeUser;
-    authscheme->authStart   =authenticateDigestStart;
-    authscheme->authStats   =authenticateDigestStats;
-    authscheme->authUserUsername = authenticateDigestUsername;
-    authscheme->getdirection=authenticateDigestDirection;
-    authscheme->oncloseconnection=NULL;
-    authscheme->decodeauth  =authenticateDigestDecodeAuth;
-    authscheme->donefunc = authDigestDone;
-    if (!digest_data_pool)
-        digest_data_pool = memPoolCreate("Digest Scheme User Data", sizeof(digest_data));
-    if (!digest_nonce_pool)
-        digest_nonce_pool = memPoolCreate("Digest Scheme nonce's", sizeof(digest_nonce_ptr));
-//    ufs_state_pool = memPoolCreate("UFS IO State data", sizeof(ufsstate_t));
-    authdigest_initialised = 1;
+    if (Config.Program.digestauthenticate)
+    {
+        authscheme->authAuthenticate = authenticateDigestAuthenticateUser;
+        authscheme->authenticated= authDigestAuthenticated;
+        authscheme->authFixErrorHeader=authenticateDigestFixErrorHeader;
+        authscheme->FreeUser          =authenticateDigestFreeUser;
+        authscheme->authStart   =authenticateDigestStart;
+        authscheme->authStats   =authenticateDigestStats;
+        authscheme->authUserUsername = authenticateDigestUsername;
+        authscheme->getdirection=authenticateDigestDirection;
+        authscheme->oncloseconnection=NULL;
+        authscheme->decodeauth  =authenticateDigestDecodeAuth;
+        authscheme->donefunc = authDigestDone;
+        authDigestUserSetup();
+        authDigestRequestSetup();
+        authenticateDigestNonceSetup();
+        authdigest_initialised = 1;
         if (digestauthenticators == NULL)
-                digestauthenticators = helperCreate("digestauthenticator");
-            digestauthenticators->cmdline = Config.Program.digestauthenticate;
-            digestauthenticators->n_to_start = Config.digestauthenticateChildren;
-            digestauthenticators->ipc_type = IPC_TCP_SOCKET;
-            helperOpenServers(digestauthenticators);
-            if (!init) {
-                cachemgrRegister("digestauthenticator",
-                    "User Authenticator Stats",
-                    authenticateDigestStats, 0, 1);
-                init++;
-            }
-        if (!digest_nonce_cache) 
-        {
-            digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
-            assert(digest_nonce_cache);
-            //eventAdd("Digest none cache maintenance",authenticateDigestCleanup, NULL, interval,1);
-        }
+            digestauthenticators = helperCreate("digestauthenticator");
+        digestauthenticators->cmdline = Config.Program.digestauthenticate;
+        digestauthenticators->n_to_start = Config.digestauthenticateChildren;
+        digestauthenticators->ipc_type = IPC_TCP_SOCKET;
+        helperOpenServers(digestauthenticators);
+        if (!init) 
+        {
+            cachemgrRegister("digestauthenticator", "User Authenticator Stats",
+                authenticateDigestStats, 0, 1);
+            init++;
+        }   
     }
 }
 
@@ -164,22 +341,26 @@
         return 0;
 }
 
-int authenticateDigestcmpUsername(digest_data * u1, digest_data *u2)
+int
+authDigestAuthenticated(auth_user_t * auth_user)
 {
-    return strcmp(u1->username,u2->username);
+    if (auth_user->flags.credentials_ok==1) 
+        return 1;
+    else
+        return 0;
 }
 
 /* log a digest user in
  */
 static auth_user_t *
 authenticateDigestAuthenticateUser(auth_user_t *auth_user, request_t *request, ConnStateData *conn, http_hdr_type type) {
-    auth_user_hash_pointer *usernamehash, *proxy_auth_hash=NULL;
-    digest_data * digest_auth;
-    const char * proxy_auth;
+    digest_request_h * digest_request;
+    digest_user_h * digest_user;
 
     HASHHEX SESSIONKEY;
     HASHHEX HA2 = "";
     HASHHEX Response;
+
     /* if the check has failed, just return */
     if (auth_user->flags.credentials_ok==3)
     {
@@ -187,85 +368,71 @@
     }
     
     assert(auth_user->scheme_data != NULL);
-    digest_auth = auth_user->scheme_data;  
-
-    /* get the header. */
-    proxy_auth = httpHeaderGetStr(&request->header, type);
-
-    assert(auth_user->scheme_data != NULL);
-    digest_auth = auth_user->scheme_data;
-
-    /* see if this user exists so we can use 'his' HA1 */
-   
-    if (!digest_auth->HA1created)
-    if ((usernamehash = hash_lookup(proxy_auth_username_cache,
-        digest_auth->username))) {
-        while ((usernamehash->auth_user->auth_type != auth_user->auth_type) &&
-            (usernamehash->next) &&
-           !authenticateDigestcmpUsername(usernamehash->auth_user->scheme_data,digest_auth))
-            usernamehash=usernamehash->next;
-        if (usernamehash->auth_user->auth_type==auth_user->auth_type)
-        {
-            debug(29,4)("authenticateDigestAuthenticateuser: user '%s' is in the user cache as auth_user '%d'\n", digest_auth->username,usernamehash->auth_user);
-
-            /*
-             * we don't add another link from the new proxy_auth to the
-             * auth_user structure because digest headers are unique */
-            assert(proxy_auth_hash == NULL);
-            /* TODO: Check the nonces are the same, and if not link the new nonce to 
-               this user */
-            /* remove the temporary structure */
-            authenticateAuthUserUnlock(auth_user);
-            auth_user = usernamehash->auth_user;
-            /* and reference the existing digest data structure */
-            digest_auth = auth_user->scheme_data;
-            /* lock the structure for this request */
-            authenticateAuthUserLock(auth_user);
-        }
-    }
+    digest_request = auth_user->scheme_data;
+ 
+    assert(digest_request->user != NULL);
+    digest_user=digest_request->user;
 
-/* TODO: turn the nonce/cnonce/HA tuple into a list linked against the user name */
-    if (!digest_auth->HA1created)
-    {
-        /* 
-        DigestCalcHA1("md5",digest_auth->username,digest_auth->realm,"testing",NULL,NULL,digest_auth->HA1,SESSIONKEY);
-        digest_auth->HA1created=1;
-        */
+    /* do we have the HA1 */
+    if (!digest_user->HA1created)
+    {
         auth_user->flags.credentials_ok=2;
         return auth_user;
     }
 
+    debug(29,4)("authenticateDigestAuthenticateuser: user '%s' is in the user cache as auth_user '%d', for us '%d' \n", digest_user->username,auth_user,digest_user->auth_user);
 
-    DigestCalcHA1(digest_auth->algorithm, NULL,NULL,NULL,
-        digest_auth->nonce,
-        digest_auth->cnonce,
-        digest_auth->HA1,SESSIONKEY);
-    DigestCalcResponse(SESSIONKEY, digest_auth->nonce, digest_auth->nc,
-        digest_auth->cnonce, digest_auth->qop, 
-        RequestMethodStr[request->method], digest_auth->uri, HA2, Response);
+    /*
+     * we don't add another link from the new proxy_auth to the
+     * auth_user structure because digest headers are unique */
+    if (digest_request->nonce==NULL)
+    {
+        /* this isn't a nonce we issued */
+        auth_user->flags.credentials_ok=3;
+        return auth_user;
+    }
+    DigestCalcHA1(digest_request->algorithm, NULL,NULL,NULL,
+        authenticateDigestNonceNonceb64(digest_request->nonce),
+        digest_request->cnonce,
+        digest_user->HA1,SESSIONKEY);
+    DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
+        digest_request->nc, digest_request->cnonce, digest_request->qop, 
+        RequestMethodStr[request->method], digest_request->uri, HA2, Response);
 
     debug(29,1)("\nResponse = '%s'\n"
-                  "squid is = '%s'\n" , digest_auth->response,Response);
-    if (strcasecmp(digest_auth->response,Response))
+                  "squid is = '%s'\n" , digest_request->response,Response);
+    
+    if (strcasecmp(digest_request->response,Response))
     {
-        /* Failed comparison */
         auth_user->flags.credentials_ok=3;
         return auth_user;
     }
+    /* we have authenticated this request */
+    if (auth_user != digest_user->auth_user)
+    {
+        /* remove the request auth_user structure */
+        authenticateAuthUserUnlock(auth_user);
+        auth_user = digest_user->auth_user;
+        /* and reference the existing digest data structure */
+        /* lock the old structure for this request */
+        authenticateAuthUserLock(auth_user);
+    }
 
+    auth_user->flags.credentials_ok=1;
+    /* TODO: cleanup the digest_request info that is no longer needed */ 
+#if 0
     /* we have a valid user. Are they in the hash table? */
     if (!auth_user->usernamehash)
     {
         /* store user in hash's */
         debug(29,4)("authenticateDigestAuthenticateuser: user '%s' is not in the user cache\n", digest_auth->username);
         authenticateUserNameCacheAdd(auth_user);
-        authenticateProxyAuthCacheAddLink(proxy_auth, auth_user);
     }
     auth_user->flags.credentials_ok=1;
-
+#endif
     /* password was checked and did match */
     debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n",
-        digest_auth->username);
+        digest_user->username);
 
     /* auth_user is now linked, we reset these values
      * after external auth occurs anyway */
@@ -291,26 +458,30 @@
 
 void
 authenticateDigestFixErrorHeader(auth_user_t *auth_user, HttpReply *rep, http_hdr_type type, request_t * request){
-    digest_nonce_ptr *nonce = authenticateDigestNonceCreate();
+    digest_nonce_h *nonce = authenticateDigestNonceNew();
     if (Config.Program.digestauthenticate){
-#if 0
-        debug(29, 5) ("authenticateFixErrorHeader: Sending type:%d header: 'Digest realm=\"%s\"'\n",type,Config.proxyAuthRealm);
-    httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\"", Config.proxyAuthRealm);
-#endif
-        debug(29, 5) ("authenticateFixErrorHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\"\n",type,Config.digestAuthRealm,nonce->nonce);
-    httpHeaderPutStrf(&rep->header, type, "Digest realm=\"Robsserver\", nonce=\"%s\", qop=\"auth\"",Config.digestAuthRealm,nonce->nonce);
+        debug(29, 5) ("authenticateFixErrorHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\"\n",type,Config.digestAuthRealm,authenticateDigestNonceNonceb64(nonce));
+        /* in the future, for WWW auth we may want to support the domain entry */
+        httpHeaderPutStrf(&rep->header, type, "Digest realm=\"%s\", nonce=\"%s\", qop=\"auth\"",Config.digestAuthRealm,authenticateDigestNonceNonceb64(nonce));
     }
 }
 
 void
 authenticateDigestFreeUser(auth_user_t *auth_user) {
-    digest_data * digest_auth = auth_user->scheme_data;
+    digest_request_h * digest_request = auth_user->scheme_data;
     debug(29,6) ("authenticateDigestFreeUser: Clearing Digest scheme data\n");
-    if (digest_auth->username)
-        xfree(digest_auth->username);
+/* TODO the whole shebang
+
+logic: free all the request details.
+if a nonce is reference don't free the nonce
+if a user is referenbced that != auth_user, don't free it otherwise do so 
+*/
+
+//    if (digest_auth->username)
+//        xfree(digest_auth->username);
 //    if (digest_auth->passwd)
 //        xfree(digest_auth->passwd);
-    memPoolFree(digest_data_pool, auth_user->scheme_data);
+    memPoolFree(digest_request_pool, auth_user->scheme_data);
     auth_user->scheme_data = NULL;
 }
 
@@ -319,7 +490,7 @@
 {
     authenticateStateData *r = data;
     auth_user_t *auth_user;
-    digest_data *digest_auth;
+    digest_request_h *digest_request;
     int valid;
     char *t = NULL;
     debug(29, 5) ("authenticateDigestHandleReply: {%s}\n", reply ? reply : "<NULL>");
@@ -333,13 +504,13 @@
     assert(r->auth_user->auth_type == AUTH_DIGEST);
     auth_user=r->auth_user; 
     assert(auth_user->scheme_data != NULL);
-    digest_auth = auth_user->scheme_data;   
+    digest_request = auth_user->scheme_data;   
     if (reply && (strncasecmp(reply, "ERR", 3) == 0))
         auth_user->flags.credentials_ok = 3;
     else
     {
-        CvtBin(reply,digest_auth->HA1);
-        digest_auth->HA1created=1;
+        CvtBin(reply,digest_request->user->HA1);
+        digest_request->user->HA1created=1;
     }
     valid = cbdataValid(r->data);
     cbdataUnlock(r->data);
@@ -363,9 +534,9 @@
 /* authenticateDigestUsername: return a pointer to the username in the */
 char *
 authenticateDigestUsername(auth_user_t *auth_user) {
-    digest_data * digest_auth = auth_user->scheme_data;
+    digest_request_h * digest_request = auth_user->scheme_data;
     if (auth_user->auth_type==AUTH_DIGEST)
-            return digest_auth->username;
+            return digest_request->user->username;
     return NULL;
 }
 
@@ -380,17 +551,24 @@
     const char *item;
     const char *p;
     const char *pos = NULL;
-  
+    char * username;
+    digest_nonce_h *nonce;
     int ilen;
-    digest_data * digest_auth;
+    digest_request_h * digest_request;
+    digest_user_h * digest_user;
+    dlink_node *node;
+
+    debug(29,5)("authenticateDigestDecodeAuth: beginning\n");
+    assert(auth_user != NULL);
     assert(auth_user->auth_type == AUTH_UNKNOWN);
     /* digest until proved otherwise */
     auth_user->auth_type = AUTH_DIGEST;
     /* have we been called before? */
     assert(auth_user->scheme_data == NULL);
-    auth_user->scheme_data = memPoolAlloc(digest_data_pool);
-    digest_auth=auth_user->scheme_data;
- 
+    auth_user->scheme_data = authDigestRequestNew();
+    assert (auth_user->scheme_data != NULL);
+    digest_request=auth_user->scheme_data;
+
     /* trim DIGEST from string */
     while (!xisspace(*proxy_auth))
         proxy_auth++;
@@ -411,7 +589,8 @@
                 p++;
             /* quote mark */
             p++;
-            digest_auth->username=xstrndup(p,strchr(p,'"')+1-p);
+            username=xstrndup(p,strchr(p,'"')+1-p);
+            debug(29,6)("authDigestDecodeAuth: Found Username '%s'\n",username);
         }
         else if (!strncmp(item, "realm", ilen))
         {
@@ -420,7 +599,8 @@
                 p++;
             /* quote mark */
             p++;
-            digest_auth->realm=xstrndup(p,strchr(p,'"')+1-p);
+            digest_request->realm=xstrndup(p,strchr(p,'"')+1-p);
+            debug(29,6)("authDigestDecodeAuth: Found realm '%s'\n",digest_request->realm);
         }
         else if (!strncmp(item, "qop", ilen))
         {
@@ -429,7 +609,8 @@
                 p++;
             /* quote mark */
             p++;
-            digest_auth->qop=xstrndup(p,strchr(p,'"')+1-p);
+            digest_request->qop=xstrndup(p,strchr(p,'"')+1-p);
+            debug(29,6)("authDigestDecodeAuth: Found qop '%s'\n",digest_request->qop);
         }          
         else if (!strncmp(item, "algorithm", ilen))
         {
@@ -438,7 +619,8 @@
                 p++;
             /* quote mark */
             p++;
-            digest_auth->algorithm=xstrndup(p,strchr(p,'"')+1-p);
+            digest_request->algorithm=xstrndup(p,strchr(p,'"')+1-p);
+            debug(29,6)("authDigestDecodeAuth: Found algorithm '%s'\n",digest_request->algorithm);
         }
         else if (!strncmp(item, "uri", ilen))
         {
@@ -447,7 +629,8 @@
                 p++;
             /* quote mark */
             p++;
-            digest_auth->uri=xstrndup(p,strchr(p,'"')+1-p);
+            digest_request->uri=xstrndup(p,strchr(p,'"')+1-p);
+            debug(29,6)("authDigestDecodeAuth: Found uri '%s'\n",digest_request->uri);
         }
         else if (!strncmp(item, "nonce", ilen))
         {
@@ -456,14 +639,16 @@
                 p++;
             /* quote mark */
             p++;
-            digest_auth->nonce=xstrndup(p,strchr(p,'"')+1-p);
+            digest_request->nonceb64=xstrndup(p,strchr(p,'"')+1-p);
+            debug(29,6)("authDigestDecodeAuth: Found nonce '%s'\n",digest_request->nonceb64);
         }
         else if (!strncmp(item, "nc", ilen))
         {
             /* white space */
             while (xisspace(*p))
                 p++;
-            xstrncpy(digest_auth->nc,p,9);
+            xstrncpy(digest_request->nc,p,9);
+            debug(29,6)("authDigestDecodeAuth: Found noncecount '%s'\n",digest_request->nc);
         }
         else if (!strncmp(item, "cnonce", ilen))
         {
@@ -472,7 +657,8 @@
                 p++;
             /* quote mark */
             p++;
-            digest_auth->cnonce=xstrndup(p,strchr(p,'"')+1-p);
+            digest_request->cnonce=xstrndup(p,strchr(p,'"')+1-p);
+            debug(29,6)("authDigestDecodeAuth: Found cnonce '%s'\n",digest_request->cnonce);
         }
         else if (!strncmp(item, "response", ilen))
         {
@@ -481,15 +667,67 @@
                 p++;
             /* quote mark */
             p++;
-            digest_auth->response=xstrndup(p,strchr(p,'"')+1-p);
+            digest_request->response=xstrndup(p,strchr(p,'"')+1-p);
+            debug(29,6)("authDigestDecodeAuth: Found response '%s'\n",digest_request->response);
         }
     }
     stringClean(&temp);
-    debug(29,2)("username = '%s'\nrealm = '%s'\nqop = '%s'\nalgorithm = '%s'\nuri = '%s'\nnonce = '%s'\nnc = '%s'\ncnonce = '%s'\nresponse = '%s'\n",
-    digest_auth->username, digest_auth->realm,
-    digest_auth->qop, digest_auth->algorithm,
-    digest_auth->uri, digest_auth->nonce,
-    digest_auth->nc, digest_auth->cnonce, digest_auth->response);
+    
+    if (!digest_request->nonceb64)
+    {
+        fatal("No nonce!\n");
+    }
+
+    nonce=authenticateDigestNonceFindNonce(digest_request->nonceb64);
+    if (nonce==NULL)
+    {
+        /* we couldn't find a matching nonce! */
+        debug (29,6)("authenticateDigestDecode: Unexpected nonce recieved\n");
+        authDigestRequestDelete(digest_request);
+        auth_user->scheme_data=NULL;
+        auth_user->auth_type=AUTH_BROKEN;
+        return;
+    }
+    digest_request->nonce=nonce;
+
+    /* find the user */
+
+    if ((digest_user=authDigestUserFindUsername(username))== NULL)
+    {
+        /* the user doesn't exist in the username cache yet */
+        debug(29,6)("authDigestDecodeAuth: Creating new digest user '%s'\n",username);
+        digest_user=authDigestUserNew();
+        assert (digest_user != NULL);
+        digest_user->username=username;
+        /* link the primary struct in */
+        digest_user->auth_user=auth_user;
+        digest_request->user=digest_user;
+        /* this auth_user struct is the 'luck one' to get added to the username cache */
+        /* the requests after this link to the digest_user but can't get cached acls */
+        if (!auth_user->usernamehash)
+        {
+            /* store user in hash's */
+            debug(29,4)("authenticateDigestAuthenticateuser: user '%s' is not in the user cache\n", digest_request->user->username);
+            authenticateUserNameCacheAdd(auth_user);
+        }
+    }
+    else
+    {
+        debug(29,6)("authDigestDecodeAuth: Found digest user '%s' in the user cache as '%d'\n",username,digest_user);
+        xfree(username);
+    }
+    /*link the request and the user */
+    digest_request->user=digest_user;
+    node=dlinkNodeNew();
+    dlinkAdd(digest_request, node, &digest_user->requests);
+
+    debug(29,2)("username = '%s'\nrealm = '%s'\nqop = '%s'\nalgorithm = '%s'\nuri = '%s'\nnonce = '%s'\nnc = '%s'\ncnonce = '%s'\nresponse = '%s'\ndigestnonce = '%d'\n",
+    digest_user->username, digest_request->realm,
+    digest_request->qop, digest_request->algorithm,
+    digest_request->uri, digest_request->nonceb64,
+    digest_request->nc, digest_request->cnonce, digest_request->response,nonce);
+
+
 
 #if 0
     if (*cleartext == '\0') {
@@ -523,14 +761,14 @@
 {
     authenticateStateData *r = NULL;
     char buf[8192];
-    digest_data * digest_auth;
+    digest_request_h * digest_request;
     assert(auth_user);
     assert(handler);
     assert(auth_user->auth_type==AUTH_DIGEST);
     assert(auth_user->scheme_data != NULL);
-    digest_auth = auth_user->scheme_data;
-    debug(29, 5) ("authenticateStart: '\"%s\":\"%s\"'\n", digest_auth->username,
-        digest_auth->realm);
+    digest_request = auth_user->scheme_data;
+    debug(29, 5) ("authenticateStart: '\"%s\":\"%s\"'\n", digest_request->user->username,
+        digest_request->realm);
     if (Config.Program.digestauthenticate == NULL) {
         handler(data, NULL);
         return;
@@ -541,6 +779,6 @@
     cbdataLock(data);
     r->data = data;
     r->auth_user = auth_user;
-    snprintf(buf, 8192, "\"%s\":\"%s\"\n", digest_auth->username, digest_auth->realm);
+    snprintf(buf, 8192, "\"%s\":\"%s\"\n", digest_request->user->username, digest_request->realm);
     helperSubmit(digestauthenticators, buf, authenticateDigestHandleReply, r);
 }
Index: squid/src/auth/digest/auth_digest.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/auth/digest/auth_digest.h,v
retrieving revision 1.1.2.2
retrieving revision 1.1.2.3
diff -u -r1.1.2.2 -r1.1.2.3
--- squid/src/auth/digest/auth_digest.h	15 Dec 2000 23:47:42 -0000	1.1.2.2
+++ squid/src/auth/digest/auth_digest.h	21 Dec 2000 04:17:37 -0000	1.1.2.3
@@ -14,10 +14,28 @@
     RH *handler;
 } authenticateStateData;
 
+typedef struct _digest_request_h digest_request_h;
+typedef struct _digest_user_h digest_user_h;
+typedef struct _digest_nonce_data digest_nonce_data;
 
-struct _digest_data {
+typedef struct _digest_nonce_h digest_nonce_h;
+
+struct _digest_user_h {
     char *username;
-    char * nonce;// = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
+    HASH HA1;
+    int HA1created;
+    /* workaround for incorrect division in the auth_user types 
+     * it points to the auth_user struct that has all the acl caching going on */
+    auth_user_t *auth_user;
+    /* what nonces have been allocated to this user*/
+    dlink_list nonces;
+    /* what digest requests are in progress for this user */
+    dlink_list requests;
+};
+
+/* the digest_request structure is what follows the http_request around */
+struct _digest_request_h {
+    char * nonceb64;// = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
     char * cnonce;// = "0a4f113b";
     char * realm;// = "testrealm@host.com";
     char * pszPass;// = "Circle Of Life";
@@ -27,17 +45,20 @@
     char * qop;// = "auth";
     char *uri;// = "/dir/index.html";
     char *response;
-    HASH HA1;
-    int HA1created;
+    digest_user_h *user;
+    digest_nonce_h *nonce;
 };
 
-typedef struct _digest_data digest_data;
-
-typedef struct _digest_nonce_ptr digest_nonce_ptr;
+/* nonce privates */
+struct _digest_nonce_data {
+    time_t creationtime;
+};
 
-struct _digest_nonce_ptr {
-    char *nonce;
-    digest_nonce_ptr *next;
+struct _digest_nonce_h {
+    /* the first two items are (hash_link) */
+    char *nonceb64;
+    digest_nonce_h *next;
+    digest_nonce_data noncedata;
 };
 
 
