---------------------
PatchSet 923 
Date: 2000/12/14 23:06:40
Author: rbcollins
Branch: auth_digest
Tag: (none) 
Log:
decode going

Members: 
	configure.in:1.1.1.3.10.17.2.5->1.1.1.3.10.17.2.5.2.1 
	makefile.in:1.1.1.3.10.3.2.1->1.1.1.3.10.3.2.1.2.1 
	src/acl.c:1.1.1.3.12.26.2.9->1.1.1.3.12.26.2.9.2.1 
	src/enums.h:1.1.1.3.12.15.2.2->1.1.1.3.12.15.2.2.2.1 
	src/auth/digest/Makefile.in:1.1->1.1.2.1 
	src/auth/digest/auth_digest.c:1.1->1.1.2.1 
	src/auth/digest/auth_digest.h:1.1->1.1.2.1 

Index: squid/configure.in
===================================================================
RCS file: /cvsroot/squid-sf//squid/configure.in,v
retrieving revision 1.1.1.3.10.17.2.5
retrieving revision 1.1.1.3.10.17.2.5.2.1
diff -u -r1.1.1.3.10.17.2.5 -r1.1.1.3.10.17.2.5.2.1
--- squid/configure.in	14 Dec 2000 11:16:48 -0000	1.1.1.3.10.17.2.5
+++ squid/configure.in	14 Dec 2000 23:06:40 -0000	1.1.1.3.10.17.2.5.2.1
@@ -3,13 +3,13 @@
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.1.1.3.10.17.2.5 2000/12/14 11:16:48 rbcollins Exp $
+dnl  $Id: configure.in,v 1.1.1.3.10.17.2.5.2.1 2000/12/14 23:06:40 rbcollins Exp $
 dnl
 dnl
 dnl
 AC_INIT(src/main.c)
 AC_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.1.1.3.10.17.2.5 $)dnl
+AC_REVISION($Revision: 1.1.1.3.10.17.2.5.2.1 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AC_CONFIG_AUX_DIR(cfgaux)
 
@@ -726,6 +726,33 @@
 fi
 AC_SUBST(AUTH_BASIC_MODULES)
 
+dnl Select basic auth scheme modules to build
+AUTH_DIGEST_MODULES=
+AC_ARG_ENABLE(digest-auth-modules,
+[  --enable-digest-auth-modules=\"list of modules\"
+                          This option selects which digest scheme authentication
+                          helper modules to build and install as part of the
+                          normal build process. For a list of available modules
+                          see the digest_auth_modules directory.],
+[ case "$enableval" in
+  yes)
+    for module in $srcdir/digest_auth_modules/*; do
+        if test -f $module/Makefile.in; then
+            AUTH_DIGEST_MODULES="$AUTH_DIGEST_MODULES `basename $module`"
+        fi
+    done
+    ;;
+  no)
+    ;;
+  *)
+    AUTH_DIGEST_MODULES="`echo $enableval| sed -e 's/,/ /g;s/  */ /g'`"
+  esac
+])
+if test -n "$AUTH_DIGEST_MODULES"; then
+    echo "Digest auth modules built: $AUTH_DIGEST_MODULES"
+fi
+AC_SUBST(AUTH_DIGEST_MODULES)
+
 dnl Disable "unlinkd" code
 AC_ARG_ENABLE(unlinkd,
 [  --disable-unlinkd       Do not use unlinkd],
@@ -1726,6 +1753,13 @@
 	fi
 done
 
+DIGEST_AUTH_MAKEFILES=""
+for module in $srcdir/digest_auth_modules/*; do
+        if test -f $module/Makefile.in; then
+            DIGEST_AUTH_MAKEFILES="$DIGEST_AUTH_MAKEFILES ./digest_auth_modules/`basename $module`/Makefile"
+        fi
+done
+
 AC_OUTPUT(\
 	./makefile \
 	./lib/Makefile \
@@ -1746,4 +1780,6 @@
         $AUTH_SCHEME_MAKEFILES \
 	./auth_modules/Makefile \
 	$AUTH_MAKEFILES \
+	./digest_auth_modules/Makefile \
+	$DIGEST_AUTH_MAKEFILES \
 )
Index: squid/makefile.in
===================================================================
RCS file: /cvsroot/squid-sf//squid/Attic/makefile.in,v
retrieving revision 1.1.1.3.10.3.2.1
retrieving revision 1.1.1.3.10.3.2.1.2.1
diff -u -r1.1.1.3.10.3.2.1 -r1.1.1.3.10.3.2.1.2.1
--- squid/makefile.in	14 Dec 2000 11:24:03 -0000	1.1.1.3.10.3.2.1
+++ squid/makefile.in	14 Dec 2000 23:06:40 -0000	1.1.1.3.10.3.2.1.2.1
@@ -1,4 +1,4 @@
-# $Id: makefile.in,v 1.1.1.3.10.3.2.1 2000/12/14 11:24:03 rbcollins Exp $
+# $Id: makefile.in,v 1.1.1.3.10.3.2.1.2.1 2000/12/14 23:06:40 rbcollins Exp $
 #
 
 srcdir		= @srcdir@
@@ -14,7 +14,7 @@
 prefix		= @prefix@
 exec_prefix	= @exec_prefix@
 
-SUBDIRS		= lib @makesnmplib@ scripts src icons errors auth_modules
+SUBDIRS		= lib @makesnmplib@ scripts src icons errors auth_modules digest_auth_modules
 
 noargs: all
 
@@ -38,6 +38,7 @@
 	rm -f config.log makefile
 	rm -f include/paths.h include/autoconf.h include/config.h
 	rm -f auth_modules/dummy
+	rm -f digest_auth_modules/dummy
 	@for dir in $(SUBDIRS) contrib; do \
 		echo Making distclean in $$dir; \
 		(cd $$dir; $(MAKE) $(MFLAGS) prefix="$(prefix)" distclean); \
Index: squid/src/acl.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/acl.c,v
retrieving revision 1.1.1.3.12.26.2.9
retrieving revision 1.1.1.3.12.26.2.9.2.1
diff -u -r1.1.1.3.12.26.2.9 -r1.1.1.3.12.26.2.9.2.1
--- squid/src/acl.c	11 Dec 2000 23:32:14 -0000	1.1.1.3.12.26.2.9
+++ squid/src/acl.c	14 Dec 2000 23:06:40 -0000	1.1.1.3.12.26.2.9.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: acl.c,v 1.1.1.3.12.26.2.9 2000/12/11 23:32:14 rbcollins Exp $
+ * $Id: acl.c,v 1.1.1.3.12.26.2.9.2.1 2000/12/14 23:06:40 rbcollins Exp $
  *
  * DEBUG: section 28    Access Control
  * AUTHOR: Duane Wessels
@@ -1350,7 +1350,8 @@
     auth_user = checklist->auth_user;
 
     assert((auth_user->auth_type==AUTH_NTLM) ||
-           (auth_user->auth_type==AUTH_BASIC));
+           (auth_user->auth_type==AUTH_BASIC) ||
+           (auth_user->auth_type==AUTH_DIGEST));
 
     authenticateStart(auth_user, aclLookupProxyAuthDone, checklist);
 }
Index: squid/src/enums.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/enums.h,v
retrieving revision 1.1.1.3.12.15.2.2
retrieving revision 1.1.1.3.12.15.2.2.2.1
diff -u -r1.1.1.3.12.15.2.2 -r1.1.1.3.12.15.2.2.2.1
--- squid/src/enums.h	13 Dec 2000 01:23:31 -0000	1.1.1.3.12.15.2.2
+++ squid/src/enums.h	14 Dec 2000 23:06:41 -0000	1.1.1.3.12.15.2.2.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: enums.h,v 1.1.1.3.12.15.2.2 2000/12/13 01:23:31 rbcollins Exp $
+ * $Id: enums.h,v 1.1.1.3.12.15.2.2.2.1 2000/12/14 23:06:41 rbcollins Exp $
  *
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
@@ -501,6 +501,7 @@
     AUTH_UNKNOWN, /* default */ 
     AUTH_BASIC,
     AUTH_NTLM,
+    AUTH_DIGEST,
     AUTH_BROKEN  /* known type, but broken data */
 } auth_type_t;
 
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/src/auth/digest/Makefile.in	Wed Feb 14 00:47:16 2007
@@ -0,0 +1,55 @@
+#
+#  Makefile for the UFS storage driver for the Squid Object Cache server
+#
+#  $Id$
+#
+
+AUTH		= digest
+
+top_srcdir	= @top_srcdir@
+VPATH		= @srcdir@
+
+CC		= @CC@
+MAKEDEPEND	= @MAKEDEPEND@
+AR_R		= @AR_R@
+RANLIB		= @RANLIB@
+AC_CFLAGS	= @CFLAGS@
+SHELL		= /bin/sh
+
+INCLUDE		= -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/
+CFLAGS 		= $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+
+OUT		= ../$(AUTH).a
+
+OBJS	 	= \
+		auth_digest.o
+
+
+all: $(OUT)
+
+$(OUT): $(OBJS)
+	@rm -f ../stamp
+	$(AR_R) $(OUT) $(OBJS)
+	$(RANLIB) $(OUT)
+
+$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h
+
+.c.o:
+	@rm -f ../stamp
+	$(CC) $(CFLAGS) -c $<
+
+clean: 
+	-rm -rf *.o *pure_* core ../$(AUTH).a
+
+distclean:	clean
+	-rm -f Makefile
+	-rm -f Makefile.bak
+	-rm -f tags
+
+install:
+
+tags:
+	ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch]
+
+depend:
+	$(MAKEDEPEND) $(INCLUDE) -fMakefile *.c
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/src/auth/digest/auth_digest.c	Wed Feb 14 00:47:16 2007
@@ -0,0 +1,652 @@
+
+/*
+ * $Id$
+ *
+ * DEBUG: section 29    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.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/* The functions in this file handle authentication.
+   They DO NOT perform access control or auditing.
+   See acl.c for access control and client_side.c for auditing */
+
+
+#include "squid.h"
+#include "auth_digest.h"
+#include "md5.h"
+
+static void
+authenticateStateFree(authenticateStateData * r)
+{
+    cbdataFree(r);
+}
+
+/* Digest Scheme */
+
+static HLPCB authenticateDigestHandleReply;
+static AUTHSACTIVE    authenticateDigestActive;
+static AUTHSAUTHUSER  authenticateDigestAuthenticateUser;
+static AUTHSDIRECTION authenticateDigestDirection;
+static AUTHSDECODE    authenticateDigestDecodeAuth;
+static AUTHSFIXERR    authenticateDigestFixErrorHeader;
+static AUTHSFREE      authenticateDigestFreeUser;
+static AUTHSSTART  authenticateDigestStart;
+static AUTHSSTATS  authenticateDigestStats;
+static AUTHSUSERNAME authenticateDigestUsername;
+static AUTHSSHUTDOWN authDigestDone;
+
+static helper *digestauthenticators = NULL;
+
+static hash_table *digest_nonce_cache;
+
+static int authdigest_initialised = 0;
+MemPool *digest_data_pool = NULL;
+MemPool *digest_nonce_pool = NULL;
+
+/*
+ *
+ * Private Functions
+ *
+ */
+
+#define HASHLEN 16
+typedef char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef char HASHHEX[HASHHEXLEN+1];
+#define IN
+#define OUT
+
+/* calculate H(A1) as per HTTP Digest spec */
+void DigestCalcHA1(
+    IN char * pszAlg,
+    IN char * pszUserName,
+    IN char * pszRealm,
+    IN char * pszPassword,
+    IN char * pszNonce,
+    IN char * pszCNonce,
+    OUT HASHHEX SessionKey
+    );
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+    IN HASHHEX HA1,           /* H(A1) */
+    IN char * pszNonce,       /* nonce from server */
+    IN char * pszNonceCount,  /* 8 hex digits */
+    IN char * pszCNonce,      /* client nonce */
+    IN char * pszQop,         /* qop-value: "", "auth", "auth-int" */
+    IN char * pszMethod,      /* method from the request */
+    IN char * pszDigestUri,   /* requested URL */
+    IN HASHHEX HEntity,       /* H(entity body) if qop="auth-int" */
+    OUT HASHHEX Response      /* request-digest or response-digest */
+    );
+
+
+void CvtHex(
+    IN HASH Bin,
+    OUT HASHHEX Hex
+    )
+{
+    unsigned short i;
+    unsigned char j;
+
+    for (i = 0; i < HASHLEN; i++) {
+        j = (Bin[i] >> 4) & 0xf;
+        if (j <= 9)
+            Hex[i*2] = (j + '0');
+         else
+            Hex[i*2] = (j + 'a' - 10);
+        j = Bin[i] & 0xf;
+        if (j <= 9)
+            Hex[i*2+1] = (j + '0');
+         else
+            Hex[i*2+1] = (j + 'a' - 10);
+    };
+    Hex[HASHHEXLEN] = '\0';
+};
+
+/* calculate H(A1) as per spec */
+void DigestCalcHA1(
+    IN char * pszAlg,
+    IN char * pszUserName,
+    IN char * pszRealm,
+    IN char * pszPassword,
+    IN char * pszNonce,
+    IN char * pszCNonce,
+    OUT HASHHEX SessionKey
+    )
+{
+      MD5_CTX Md5Ctx;
+      HASH HA1;
+
+      MD5Init(&Md5Ctx);
+      MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
+      MD5Update(&Md5Ctx, ":", 1);
+      MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm));
+      MD5Update(&Md5Ctx, ":", 1);
+      MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword));
+      MD5Final(HA1, &Md5Ctx);
+      if (stricmp(pszAlg, "md5-sess") == 0) {
+            MD5Init(&Md5Ctx);
+            MD5Update(&Md5Ctx, HA1, HASHLEN);
+            MD5Update(&Md5Ctx, ":", 1);
+            MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
+            MD5Update(&Md5Ctx, ":", 1);
+            MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
+            MD5Final(HA1, &Md5Ctx);
+      };
+      CvtHex(HA1, SessionKey);
+};
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+    IN HASHHEX HA1,           /* H(A1) */
+    IN char * pszNonce,       /* nonce from server */
+    IN char * pszNonceCount,  /* 8 hex digits */
+    IN char * pszCNonce,      /* client nonce */
+    IN char * pszQop,         /* qop-value: "", "auth", "auth-int" */
+    IN char * pszMethod,      /* method from the request */
+    IN char * pszDigestUri,   /* requested URL */
+    IN HASHHEX HEntity,       /* H(entity body) if qop="auth-int" */
+    OUT HASHHEX Response      /* request-digest or response-digest */
+    )
+{
+      MD5_CTX Md5Ctx;
+      HASH HA2;
+      HASH RespHash;
+       HASHHEX HA2Hex;
+
+      // calculate H(A2)
+      MD5Init(&Md5Ctx);
+      MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod));
+      MD5Update(&Md5Ctx, ":", 1);
+      MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));
+      if (stricmp(pszQop, "auth-int") == 0) {
+            MD5Update(&Md5Ctx, ":", 1);
+            MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
+      };
+      MD5Final(HA2, &Md5Ctx);
+       CvtHex(HA2, HA2Hex);
+
+      // calculate response
+      MD5Init(&Md5Ctx);
+      MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
+      MD5Update(&Md5Ctx, ":", 1);
+      MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
+      MD5Update(&Md5Ctx, ":", 1);
+      if (*pszQop) {
+          MD5Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount));
+          MD5Update(&Md5Ctx, ":", 1);
+          MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
+          MD5Update(&Md5Ctx, ":", 1);
+          MD5Update(&Md5Ctx, pszQop, strlen(pszQop));
+          MD5Update(&Md5Ctx, ":", 1);
+      };
+      MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
+      MD5Final(RespHash, &Md5Ctx);
+      CvtHex(RespHash, Response);
+};
+
+digest_nonce_ptr *
+authenticateDigestNonceCreate()
+{
+    digest_nonce_ptr *newnonce = memPoolAlloc(digest_nonce_pool);
+    newnonce->nonce=xstrdup("aaaaa");
+    hash_join(digest_nonce_cache, (hash_link *) newnonce);
+    return newnonce;
+}
+
+void
+authenticateDigestNonceDestroy(digest_nonce_ptr *nonce)
+{
+    if (nonce)
+    {
+        hash_remove_link(digest_nonce_cache, (hash_link *)nonce);
+        xfree(nonce->nonce);
+        memPoolFree(digest_nonce_pool, nonce);
+    }
+} 
+
+void
+authDigestDone(void)
+{
+//    memPoolDestroy(ufs_state_pool);
+   if (digestauthenticators)
+       helperShutdown(digestauthenticators);
+    authdigest_initialised = 0;
+    if (!shutting_down)
+        return;
+    helperFree(digestauthenticators);
+    digestauthenticators = NULL;
+    memPoolDestroy(digest_data_pool);
+    memPoolDestroy(digest_nonce_pool);
+}
+
+void 
+authSchemeSetup_digest(authscheme_entry_t *authscheme) {
+static int init = 0;
+      char * pszNonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
+      char * pszCNonce = "0a4f113b";
+      char * pszUser = "Mufasa";
+      char * pszRealm = "testrealm@host.com";
+      char * pszPass = "Circle Of Life";
+      char * pszAlg = "md5";
+      char szNonceCount[9] = "00000001";
+      char * pszMethod = "GET";
+      char * pszQop = "auth";
+      char * pszURI = "/dir/index.html";
+      HASHHEX HA1;
+      HASHHEX HA2 = "";
+      HASHHEX Response;
+
+      DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce,
+pszCNonce, HA1);
+      DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop,
+       pszMethod, pszURI, HA2, Response);
+      debug(29,1)("Response = %s\n", Response);
+//    fatal("done that thang!\n");
+
+    assert(!authdigest_initialised);
+//    authscheme->parsefunc = storeUfsDirParse;
+//    authscheme->reconfigurefunc = storeUfsDirReconfigure;
+    authscheme->Active            =authenticateDigestActive;
+    if (Config.Program.authenticate){
+    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 (digestauthenticators == NULL)
+                digestauthenticators = helperCreate("digestauthenticator");
+            digestauthenticators->cmdline = Config.Program.authenticate;
+            digestauthenticators->n_to_start = Config.authenticateChildren;
+            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);
+        }
+    }
+}
+
+int
+authenticateDigestActive(){
+    if (authdigest_initialised) 
+        return 1; 
+    else 
+        return 0;
+}
+
+int authenticateDigestcmpUsername(digest_data * u1, digest_data *u2)
+{
+    return strcmp(u1->username,u2->username);
+}
+
+/* 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, *temp_auth;
+    const char * proxy_auth;
+    /* if the password is not ok, do an identity */
+    if (auth_user->flags.credentials_ok!=1)
+        return auth_user;
+
+    /*    get the header. */
+    proxy_auth = httpHeaderGetStr(&request->header, type);
+
+    assert(auth_user->scheme_data != NULL);
+    digest_auth = auth_user->scheme_data;
+
+    /* password was checked and did match */
+    debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n",
+        digest_auth->username);
+    /* see if this is an existing user with a different proxy_auth string */
+    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) {
+            /*
+             * add another link from the new proxy_auth to the
+             * auth_user structure and update the information */
+            assert(proxy_auth_hash == NULL);
+            authenticateProxyAuthCacheAddLink(proxy_auth, usernamehash->auth_user);
+            /* maybe the p/w changed. update in the old structure */
+            temp_auth=usernamehash->auth_user->scheme_data;
+//            xfree(temp_auth->passwd);
+//            temp_auth->passwd = digest_auth->passwd;
+//            digest_auth->passwd = NULL;
+            /* and remove the temporary structure */
+            authenticateAuthUserUnlock(auth_user);
+            authenticateFreeProxyAuthUser(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);
+        }
+    } else {
+        /* store user in hash's */
+        authenticateUserNameCacheAdd(auth_user);
+        authenticateProxyAuthCacheAddLink(proxy_auth, auth_user);
+    }
+    /* auth_user is now linked, we reset these values
+     * after external auth occurs anyway */
+    auth_user->expiretime =  current_time.tv_sec;
+    auth_user->ip_expiretime = squid_curtime;
+    return auth_user;
+}
+
+int authenticateDigestDirection(auth_user_t *auth_user) {
+/* null auth_user is checked for by authenticateDirection */
+    switch (auth_user->flags.credentials_ok) {
+        case 0: /* not checked */
+            return -1;
+        case 1: /* checked & ok */
+            return 0;
+        case 2: /* partway through checking. Invalid for digest */
+            return -2;
+        case 3: /* authentication process failed. */
+            return -2;
+    }
+    return -2;
+}
+
+void
+authenticateDigestFixErrorHeader(auth_user_t *auth_user, HttpReply *rep, http_hdr_type type, request_t * request){
+    digest_nonce_ptr *nonce = authenticateDigestNonceCreate();
+    if (Config.Program.authenticate){
+#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=\"Robs server\", nonce=\"%s\"\n",type,nonce->nonce);
+    httpHeaderPutStrf(&rep->header, type, "Digest realm=\"Robs server\", nonce=\"%s\", qop=\"auth\"",nonce->nonce);
+    }
+}
+
+void
+authenticateDigestFreeUser(auth_user_t *auth_user) {
+    digest_data * digest_auth = auth_user->scheme_data;
+    debug(29,6) ("authenticateDigestFreeUser: Clearing Digest scheme data\n");
+    if (digest_auth->username)
+        xfree(digest_auth->username);
+//    if (digest_auth->passwd)
+//        xfree(digest_auth->passwd);
+    memPoolFree(digest_data_pool, auth_user->scheme_data);
+    auth_user->scheme_data = NULL;
+}
+
+static void
+authenticateDigestHandleReply(void *data, char *reply)
+{
+    authenticateStateData *r = data;
+    auth_user_t *auth_user;
+    int valid;
+    char *t = NULL;
+    debug(29, 5) ("authenticateDigestHandleReply: {%s}\n", reply ? reply : "<NULL>");
+    if (reply) {
+	if ((t = strchr(reply, ' ')))
+	    *t = '\0';
+	if (*reply == '\0')
+	    reply = NULL;
+    }
+    assert(r->auth_user != NULL);
+    assert(r->auth_user->auth_type == AUTH_DIGEST);
+    auth_user=r->auth_user;    
+    if (reply && (strncasecmp(reply, "OK", 2) == 0))
+        auth_user->flags.credentials_ok = 1;
+    else
+        auth_user->flags.credentials_ok = 2;
+    valid = cbdataValid(r->data);
+    cbdataUnlock(r->data);
+    if (valid)
+	r->handler(r->data, NULL);
+#if 0
+    if (valid)
+        r->handler(r->data, reply);
+#endif
+    authenticateStateFree(r);
+}
+
+static void
+authenticateDigestStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "Digest Authenticator Statistics:\n");
+    helperStats(sentry, digestauthenticators);
+}
+
+
+/* authenticateDigestUsername: return a pointer to the username in the */
+char *
+authenticateDigestUsername(auth_user_t *auth_user) {
+    digest_data * digest_auth = auth_user->scheme_data;
+    if (auth_user->auth_type==AUTH_DIGEST)
+            return digest_auth->username;
+    return NULL;
+}
+
+/*
+ * Decode a Digest [Proxy-]Auth string, placing the results in the passed
+ * Auth_user structure.
+ */
+
+static void
+authenticateDigestDecodeAuth(auth_user_t *auth_user, const char * proxy_auth) {
+    char *sent_auth;
+    char *cleartext;
+    String temp;
+    const char *item;
+    const char *p;
+    const char *pos = NULL;
+  
+    int ilen;
+    digest_data * digest_auth;
+    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;
+ 
+    /* trim DIGEST from string */
+    while (!xisspace(*proxy_auth))
+        proxy_auth++;
+
+    /* Trim leading whitespace before decoding */
+    while (xisspace(*proxy_auth))
+        proxy_auth++;
+
+    stringInit(&temp, proxy_auth);
+    while (strListGetItem(&temp, ',', &item,&ilen,&pos))
+    {
+        if ((p = strchr(item,'=')) && (p-item<ilen))
+            ilen = p++ - item;
+        if (!strncmp(item, "username", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            /* quote mark */
+            p++;
+            digest_auth->username=xstrndup(p,strchr(p,'"')+1-p);
+        }
+        else if (!strncmp(item, "realm", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            /* quote mark */
+            p++;
+            digest_auth->realm=xstrndup(p,strchr(p,'"')+1-p);
+        }
+        else if (!strncmp(item, "qop", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            /* quote mark */
+            p++;
+            digest_auth->qop=xstrndup(p,strchr(p,'"')+1-p);
+        }          
+        else if (!strncmp(item, "algorithm", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            /* quote mark */
+            p++;
+            digest_auth->algorithm=xstrndup(p,strchr(p,'"')+1-p);
+        }
+        else if (!strncmp(item, "uri", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            /* quote mark */
+            p++;
+            digest_auth->uri=xstrndup(p,strchr(p,'"')+1-p);
+        }
+        else if (!strncmp(item, "nonce", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            /* quote mark */
+            p++;
+            digest_auth->nonce=xstrndup(p,strchr(p,'"')+1-p);
+        }
+        else if (!strncmp(item, "nc", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            xstrncpy(digest_auth->nc,p,8);
+        }
+        else if (!strncmp(item, "cnonce", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            /* quote mark */
+            p++;
+            digest_auth->cnonce=xstrndup(p,strchr(p,'"')+1-p);
+        }
+        else if (!strncmp(item, "response", ilen))
+        {
+            /* white space */
+            while (xisspace(*p))
+                p++;
+            /* quote mark */
+            p++;
+            digest_auth->response=xstrndup(p,strchr(p,'"')+1-p);
+        }
+    }
+    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 (*cleartext == '\0') {
+        debug(29, 2) ("authenticateDigestDecodeAuth: Disallowing empty password,"
+            "user is '%s'\n", digest_auth->username);
+        auth_user->auth_type = AUTH_BROKEN;
+    }
+    /* special case: we have to free the strings for user and password
+     * if we are not returning AUTH_DIGEST else the UserFree function will
+     * be confused.
+     */
+    if (auth_user->auth_type != AUTH_DIGEST) 
+    {
+        if (digest_auth->username)
+             xfree(digest_auth->username);
+        memPoolFree(digest_data_pool, digest_auth);
+        auth_user->scheme_data = NULL;
+    } else {
+//        digest_auth->passwd = xstrndup(cleartext, USER_IDENT_SZ);
+    }
+    /* we are finished with the proxy_auth */
+//    xfree(auth_user->proxy_auth);
+//    auth_user->proxy_auth = NULL;
+    return;
+}
+
+/* send the initial data to a digest authenticator module */
+static void
+authenticateDigestStart(auth_user_t * auth_user, RH * handler, void *data)
+{
+    authenticateStateData *r = NULL;
+    char buf[8192];
+    digest_data * digest_auth;
+    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->passwd);
+    if (Config.Program.authenticate == NULL) {
+        handler(data, NULL);
+        return;
+    }
+    r = xcalloc(1, sizeof(authenticateStateData));
+    cbdataAdd(r, cbdataXfree, 0);
+    r->handler = handler;
+    cbdataLock(data);
+    r->data = data;
+    r->auth_user = auth_user;
+//    snprintf(buf, 8192, "%s %s\n", digest_auth->username, digest_auth->passwd);
+    helperSubmit(digestauthenticators, buf, authenticateDigestHandleReply, r);
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/src/auth/digest/auth_digest.h	Wed Feb 14 00:47:16 2007
@@ -0,0 +1,55 @@
+/*
+ * auth_digest.h
+ * Internal declarations for the digest auth module
+ */
+
+#ifndef __AUTH_DIGEST_H__
+#define __AUTH_DIGEST_H__
+
+
+/* Generic */
+typedef struct {
+    void *data;
+    auth_user_t *auth_user;
+    RH *handler;
+} authenticateStateData;
+
+
+struct _digest_data {
+    char *username;
+    char * nonce;// = "dcd98b7102dd2f0e8b11d0f600bfb0c093";
+    char * cnonce;// = "0a4f113b";
+    char * realm;// = "testrealm@host.com";
+    char * pszPass;// = "Circle Of Life";
+    char * algorithm;// = "md5";
+    char nc[9];// = "00000001";
+    char * pszMethod;// = "GET";
+    char * qop;// = "auth";
+    char *uri;// = "/dir/index.html";
+    char *response;
+};
+
+typedef struct _digest_data digest_data;
+
+typedef struct _digest_nonce_ptr digest_nonce_ptr;
+
+struct _digest_nonce_ptr {
+    char *nonce;
+    digest_nonce_ptr *next;
+};
+
+
+#if 0
+struct _ntlm_helper_state_t {
+    char *challenge; /* the challenge to use with this helper */
+    int  starve;     /* 0= normal operation. 1=don't hand out any more challenges */
+    int  challengeuses; /* the number of times this challenge has been issued */
+    time_t renewed;
+};
+
+typedef struct _ntlm_helper_state_t ntlm_helper_state_t;
+
+extern MemPool *ntlm_helper_state_pool;
+#endif
+
+#endif
