--------------------- PatchSet 11863 Date: 2008/01/02 17:07:26 Author: hno Branch: SQUID_2_6 Tag: (none) Log: MFC: Digest authentication fixes - digest auth related memory corruption - Random authenticaiton failures when using Digest authentication The stale= propery of the Digest responses sent by Squid indicated far too often that the nonce was not stale. Contrary to what the RFC recommends we should only say that the nonce is not stale when it is a valid nonce but the response did not compute (invalid user or password). In all other situations we should say that the nonce is stale even if we haven't validated the response. Members: lib/rfc2617.c:1.8->1.8.2.1 src/auth/digest/auth_digest.c:1.21.2.1->1.21.2.2 src/auth/digest/auth_digest.h:1.8->1.8.2.1 Index: squid/lib/rfc2617.c =================================================================== RCS file: /cvsroot/squid/squid/lib/rfc2617.c,v retrieving revision 1.8 retrieving revision 1.8.2.1 diff -u -r1.8 -r1.8.2.1 --- squid/lib/rfc2617.c 13 Jan 2007 16:06:42 -0000 1.8 +++ squid/lib/rfc2617.c 2 Jan 2008 17:07:26 -0000 1.8.2.1 @@ -13,7 +13,7 @@ /* - * $Id: rfc2617.c,v 1.8 2007/01/13 16:06:42 hno Exp $ + * $Id: rfc2617.c,v 1.8.2.1 2008/01/02 17:07:26 hno Exp $ * * DEBUG: * AUTHOR: RFC 2617 & Robert Collins @@ -94,7 +94,7 @@ else Bin[i / 2] |= n; } - for (; i <= HASHHEXLEN; i++) { + for (i = i / 2; i < HASHLEN; i++) { Bin[i] = '\0'; } } Index: squid/src/auth/digest/auth_digest.c =================================================================== RCS file: /cvsroot/squid/squid/src/auth/digest/auth_digest.c,v retrieving revision 1.21.2.1 retrieving revision 1.21.2.2 diff -u -r1.21.2.1 -r1.21.2.2 --- squid/src/auth/digest/auth_digest.c 31 Aug 2007 14:08:53 -0000 1.21.2.1 +++ squid/src/auth/digest/auth_digest.c 2 Jan 2008 17:07:26 -0000 1.21.2.2 @@ -1,6 +1,6 @@ /* - * $Id: auth_digest.c,v 1.21.2.1 2007/08/31 14:08:53 hno Exp $ + * $Id: auth_digest.c,v 1.21.2.2 2008/01/02 17:07:26 hno Exp $ * * DEBUG: section 29 Authenticator * AUTHOR: Robert Collins @@ -741,6 +741,7 @@ } } else { digest_request->flags.credentials_ok = 3; + digest_request->flags.invalid_password = 1; safe_free(auth_user_request->message); auth_user_request->message = xstrdup("Incorrect password"); return; @@ -750,7 +751,6 @@ if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) { debug(29, 3) ("authenticateDigestAuthenticateuser: user '%s' validated OK but nonce stale\n", digest_user->username); - digest_request->flags.nonce_stale = 1; digest_request->flags.credentials_ok = 3; safe_free(auth_user_request->message); auth_user_request->message = xstrdup("Stale nonce"); @@ -781,11 +781,8 @@ return 0; case 2: /* partway through checking. */ return -1; - case 3: /* authentication process failed. */ - if (digest_request->flags.nonce_stale) - /* nonce is stale, send new challenge */ - return 1; - return -2; + case 3: /* authentication process failed. Challenge. */ + return 1; } return -2; } @@ -855,7 +852,7 @@ digest_nonce_h *nonce = authenticateDigestNonceNew(); if (auth_user_request && auth_user_request->scheme_data) { digest_request = auth_user_request->scheme_data; - stale = digest_request->flags.nonce_stale; + stale = !digest_request->flags.invalid_password; } if (digestConfig->authenticate) { debug(29, 9) ("authenticateFixHeader: Sending type:%d header: 'Digest realm=\"%s\", nonce=\"%s\", qop=\"%s\", stale=%s\n", type, digestConfig->digestAuthRealm, authenticateDigestNonceNonceb64(nonce), QOP_AUTH, stale ? "true" : "false"); @@ -911,6 +908,7 @@ digest_user = auth_user_request->auth_user->scheme_data; if (reply && (strncasecmp(reply, "ERR", 3) == 0)) { digest_request->flags.credentials_ok = 3; + digest_request->flags.invalid_password = 1; safe_free(auth_user_request->message); if (t && *t) auth_user_request->message = xstrdup(t); @@ -1273,10 +1271,7 @@ /* we couldn't find a matching nonce! */ debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce received\n"); authDigestLogUsername(auth_user_request, username); - - /* we don't need the scheme specific data anymore */ - authDigestRequestDelete(digest_request); - auth_user_request->scheme_data = NULL; + auth_user_request->scheme_data = digest_request; return; } digest_request->nonce = nonce; @@ -1284,7 +1279,7 @@ /* check the qop is what we expected. Note that for compatability with * RFC 2069 we should support a missing qop. Tough. */ - if (!digest_request->qop || strcmp(digest_request->qop, QOP_AUTH)) { + if (digest_request->qop && strcmp(digest_request->qop, QOP_AUTH) != 0) { /* we received a qop option we didn't send */ debug(29, 4) ("authenticateDigestDecode: Invalid qop option received\n"); authDigestLogUsername(auth_user_request, username); Index: squid/src/auth/digest/auth_digest.h =================================================================== RCS file: /cvsroot/squid/squid/src/auth/digest/auth_digest.h,v retrieving revision 1.8 retrieving revision 1.8.2.1 diff -u -r1.8 -r1.8.2.1 --- squid/src/auth/digest/auth_digest.h 8 Jul 2006 13:26:26 -0000 1.8 +++ squid/src/auth/digest/auth_digest.h 2 Jan 2008 17:07:26 -0000 1.8.2.1 @@ -43,7 +43,7 @@ struct { unsigned int authinfo_sent:1; unsigned int credentials_ok:2; /*0=unchecked,1=ok,2=helper,3=failed */ - unsigned int nonce_stale:1; + unsigned int invalid_password:1; unsigned int helper_queried:1; } flags; digest_nonce_h *nonce;