squid-2426

Version:

2.6.STABLE21

Symptom (Failure):
Squid mistakenly refuses client’s authentication. The user provided correct username/password, but Squid does not grant him/her authentication.

Bug link:

http://bugs.squid-cache.org/show_bug.cgi?id=2426

Background:

Squid in this case is used as an enterprise proxy. Users within the enterprise network can only access the internet via a Squid server. The squid server will also authenticate users by talking to an Active Directory server.

There are mainly two relevant functions in this whole process:

authenticateNegotiateStart: to prepare the authentication and send the security token to AD server.

authenticateNegotiateHandleReply: once the AD server authenticated the user, send the reply back.

These two functions will call other callee functions for different functionalities.

Diagram:

          Squid:                                                                              AD

authenticateNegotiateStart ----------------- token ------------------>

                                                                                            authenticate

authenticateNegotiateHandleReply  ←------ reply -----------------------

How it is diagnosed:

This failure is not reproducible due to privacy concerns (requires user password) and environmental set-up complexity (squid is used together with Microsoft AD server).

So we rely on source analysis.

Root Cause:

The kerberos Token was truncated when copying with snprintf. The kerberos token has a larger size than the allocated length (8192), but is truncated to 8192 by snprintf, thus result in a wrong value.

/* prepare the authentication and send the security token to AD server. */

authenticateNegotiateStart(auth_user_request_t * auth_user_request, RH *
handler, void *data)
{
    authenticateStateData *r = NULL;

     /* buf holds the security token. */
-    char buf[8192];
+    char buf[32768];
    char *sent_string = NULL;
    negotiate_user_t *negotiate_user;
    negotiate_request_t *negotiate_request;
@@ -606,9 +606,9 @@
    r->auth_user_request = auth_user_request;
    authenticateAuthUserRequestLock(r->auth_user_request);

     /* When the security token is longer than 8192, snprintf

        will truncate this buffer and send to the AD server, resulting

        in a denial of access response from the AD server.

        The fix is to simply increase the buffer length. */
    if (negotiate_request->auth_state == AUTHENTICATE_STATE_INITIAL) {
- snprintf(buf, 8192, "YR %s\n", sent_string);
+ snprintf(buf, 32768, "YR %s\n", sent_string);
    } else {
- snprintf(buf, 8192, "KK %s\n", sent_string);
+ snprintf(buf, 32768, "KK %s\n", sent_string);
    }

Is there any log message?

No.

Can Errlog anticipate?

Yes. Library ‘snprintf’ return value: not even checked!

snprintf man page: If the output was truncated due to this limit then the return value is the number of characters (not including the trailing '\0') which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated. -- if snprintf returns larger than 8192, then it meant truncation occurred!

- snprintf(buf, 8192, "YR %s\n", sent_string);

+ (_retval = snprintf(buf, 8192, "YR %s\n", sent_string), (_retval >= 8192) ? elog(“snprintf truncated the input string...”) : NULL, _retval);