1 Index: squid/src/cf.data.pre
2 diff -c squid/src/cf.data.pre:1.245.2.41 squid/src/cf.data.pre:1.245.2.42
3 *** squid/src/cf.data.pre:1.245.2.41 Sat Apr 26 18:33:17 2003
4 --- squid/src/cf.data.pre Sun May 18 15:49:19 2003
9 "nonce_strictness" on|off
10 ! Determines if squid requires increment-by-1 behaviour for
11 ! nonce counts (on - the default), or strictly incrementing
12 ! (off - for use when useragents generate nonce counts that
13 ! occasionally miss 1 (ie, 1,2,4,6)).
15 === NTLM scheme options follow ===
20 "nonce_strictness" on|off
21 ! Determines if squid requires strict increment-by-1 behaviour
22 ! for nonce counts, or just incrementing (off - for use when
23 ! useragents generate nonce counts that occasionally miss 1
24 ! (ie, 1,2,4,6)). Default off.
26 ! "check_nonce_count" on|off
27 ! This directive if set to off can disable the nonce count check
28 ! completely to work around buggy digest qop implementations in
29 ! certain mainstream browser versions. Default on to check the
30 ! nonce count to protect from authentication replay attacks.
32 ! "post_workaround" on|off
33 ! This is a workaround to certain buggy browsers who sends
34 ! an incorrect request digest in POST requests when reusing
35 ! the same nonce as aquired earlier on a GET request.
37 === NTLM scheme options follow ===
39 Index: squid/src/authenticate.c
40 diff -c squid/src/authenticate.c:1.36.2.9 squid/src/authenticate.c:1.36.2.10
41 *** squid/src/authenticate.c:1.36.2.9 Sun May 11 15:44:31 2003
42 --- squid/src/authenticate.c Sun May 18 15:49:19 2003
47 switch (authenticateDirection(*auth_user_request)) {
49 + if (!request->auth_user_request) {
50 + /* lock the user for the request structure link */
51 + authenticateAuthUserRequestLock(*auth_user_request);
52 + request->auth_user_request = *auth_user_request;
54 + /* fallthrough to -2 */
56 /* this ACL check is finished. Unlock. */
57 authenticateAuthUserRequestUnlock(*auth_user_request);
58 Index: squid/src/auth/digest/auth_digest.h
59 diff -c squid/src/auth/digest/auth_digest.h:1.5.2.2 squid/src/auth/digest/auth_digest.h:1.5.2.3
60 *** squid/src/auth/digest/auth_digest.h:1.5.2.2 Thu Feb 27 01:19:24 2003
61 --- squid/src/auth/digest/auth_digest.h Sun May 18 15:49:20 2003
66 unsigned int authinfo_sent:1;
67 ! unsigned int credentials_ok:2; /*0=unchecked,1=ok,2=failed */
69 digest_nonce_h *nonce;
74 unsigned int authinfo_sent:1;
75 ! unsigned int credentials_ok:2; /*0=unchecked,1=ok,2=helper,3=failed */
76 ! unsigned int nonce_stale:1;
78 digest_nonce_h *nonce;
83 time_t noncemaxduration;
86 + int CheckNonceCount;
90 typedef struct _auth_digest_config auth_digest_config;
91 Index: squid/src/auth/digest/auth_digest.c
92 diff -c squid/src/auth/digest/auth_digest.c:1.10.2.5 squid/src/auth/digest/auth_digest.c:1.10.2.6
93 *** squid/src/auth/digest/auth_digest.c:1.10.2.5 Thu Feb 27 01:19:24 2003
94 --- squid/src/auth/digest/auth_digest.c Sun May 18 15:49:20 2003
99 intnc = strtol(nc, NULL, 16);
100 if ((digestConfig->NonceStrictness && intnc != nonce->nc + 1) ||
101 intnc < nonce->nc + 1) {
102 debug(29, 4) ("authDigestNonceIsValid: Nonce count doesn't match\n");
103 nonce->flags.valid = 0;
106 - /* has it already been invalidated ? */
107 - if (!nonce->flags.valid) {
108 - debug(29, 4) ("authDigestNonceIsValid: Nonce already invalidated\n");
112 /* increment the nonce count - we've already checked that intnc is a
113 * valid representation for us, so we don't need the test here.
117 intnc = strtol(nc, NULL, 16);
118 + /* has it already been invalidated ? */
119 + if (!nonce->flags.valid) {
120 + debug(29, 4) ("authDigestNonceIsValid: Nonce already invalidated\n");
123 + /* is the nonce-count ok ? */
124 + if (!digestConfig->CheckNonceCount) {
126 + return -1; /* forced OK by configuration */
128 if ((digestConfig->NonceStrictness && intnc != nonce->nc + 1) ||
129 intnc < nonce->nc + 1) {
130 debug(29, 4) ("authDigestNonceIsValid: Nonce count doesn't match\n");
131 nonce->flags.valid = 0;
135 /* increment the nonce count - we've already checked that intnc is a
136 * valid representation for us, so we don't need the test here.
139 "squid is = '%s'\n", digest_request->response, Response);
141 if (strcasecmp(digest_request->response, Response)) {
142 digest_request->flags.credentials_ok = 3;
145 - digest_request->flags.credentials_ok = 1;
146 /* password was checked and did match */
147 debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n",
148 digest_user->username);
151 "squid is = '%s'\n", digest_request->response, Response);
153 if (strcasecmp(digest_request->response, Response)) {
154 + if (digestConfig->PostWorkaround && request->method != METHOD_GET) {
155 + /* Ugly workaround for certain very broken browsers using the
156 + * wrong method to calculate the request-digest on POST request.
157 + * This should be deleted once Digest authentication becomes more
158 + * widespread and such broken browsers no longer are commonly
161 + DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
162 + digest_request->nc, digest_request->cnonce, digest_request->qop,
163 + RequestMethodStr[METHOD_GET], digest_request->uri, HA2, Response);
164 + if (strcasecmp(digest_request->response, Response)) {
165 + digest_request->flags.credentials_ok = 3;
168 + const char *useragent = httpHeaderGetStr(&request->header, HDR_USER_AGENT);
169 + static struct in_addr last_broken_addr =
171 + if (memcmp(&last_broken_addr, &request->client_addr, sizeof(last_broken_addr)) != 0) {
172 + debug(29, 1) ("\nDigest POST bug detected from %s using '%s'. Please upgrade browser. See Bug #630 for details.\n", inet_ntoa(request->client_addr), useragent ? useragent : "-");
173 + last_broken_addr = request->client_addr;
177 + digest_request->flags.credentials_ok = 3;
181 + /* check for stale nonce */
182 + if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) {
183 + debug(29, 3) ("authenticateDigestAuthenticateuser: user '%s' validated OK but nonce stale\n",
184 + digest_user->username);
185 + digest_request->flags.nonce_stale = 1;
186 digest_request->flags.credentials_ok = 3;
189 /* password was checked and did match */
190 + digest_request->flags.credentials_ok = 1;
192 debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n",
193 digest_user->username);
197 case 0: /* not checked */
199 case 1: /* checked & ok */
200 - if (authDigestNonceIsStale(digest_request->nonce))
201 - /* send stale response to the client agent */
204 case 2: /* partway through checking. */
206 case 3: /* authentication process failed. */
211 case 0: /* not checked */
213 case 1: /* checked & ok */
215 case 2: /* partway through checking. */
217 case 3: /* authentication process failed. */
218 + if (digest_request->flags.nonce_stale)
219 + /* nonce is stale, send new challenge */
226 digest_request_h *digest_request;
228 digest_nonce_h *nonce = authenticateDigestNonceNew();
229 ! if (auth_user_request && auth_user_request->scheme_data && authDigestAuthenticated(auth_user_request)) {
230 digest_request = auth_user_request->scheme_data;
231 ! stale = authDigestNonceIsStale(digest_request->nonce);
233 if (digestConfig->authenticate) {
234 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");
236 digest_request_h *digest_request;
238 digest_nonce_h *nonce = authenticateDigestNonceNew();
239 ! if (auth_user_request && auth_user_request->scheme_data) {
240 digest_request = auth_user_request->scheme_data;
241 ! stale = digest_request->flags.nonce_stale;
243 if (digestConfig->authenticate) {
244 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");
247 digestConfig->noncemaxduration = 30 * 60;
249 digestConfig->noncemaxuses = 50;
250 ! /* strict nonce count behaviour */
251 ! digestConfig->NonceStrictness = 1;
253 digestConfig = scheme->scheme_data;
254 if (strcasecmp(param_str, "program") == 0) {
256 digestConfig->noncemaxduration = 30 * 60;
258 digestConfig->noncemaxuses = 50;
259 ! /* Not strict nonce count behaviour */
260 ! digestConfig->NonceStrictness = 0;
261 ! /* Verify nonce count */
262 ! digestConfig->CheckNonceCount = 1;
264 digestConfig = scheme->scheme_data;
265 if (strcasecmp(param_str, "program") == 0) {
269 parse_int(&digestConfig->noncemaxuses);
270 } else if (strcasecmp(param_str, "nonce_strictness") == 0) {
271 parse_onoff(&digestConfig->NonceStrictness);
272 + } else if (strcasecmp(param_str, "check_nonce_count") == 0) {
273 + parse_onoff(&digestConfig->CheckNonceCount);
274 + } else if (strcasecmp(param_str, "post_workaround") == 0) {
275 + parse_onoff(&digestConfig->PostWorkaround);
277 debug(28, 0) ("unrecognised digest auth scheme parameter '%s'\n", param_str);
283 nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64);
284 ! if ((nonce == NULL) || !(authDigestNonceIsValid(nonce, digest_request->nc))) {
285 /* we couldn't find a matching nonce! */
286 debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce recieved\n");
287 authDigestLogUsername(auth_user_request, username);
291 nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64);
293 /* we couldn't find a matching nonce! */
294 debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce recieved\n");
295 authDigestLogUsername(auth_user_request, username);