--------------------- 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 : ""); @@ -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; };