--------------------- PatchSet 2703 Date: 2001/08/02 13:42:36 Author: rbcollins Branch: auth_rewrite Tag: (none) Log: merge code updates from NTLM Members: src/acl.c:1.1.1.3.12.26.2.52->1.1.1.3.12.26.2.53 src/authenticate.c:1.1.1.3.12.17.2.43->1.1.1.3.12.17.2.44 src/client_side.c:1.1.1.3.4.1.2.30.2.33->1.1.1.3.4.1.2.30.2.34 src/helper.c:1.1.1.3.12.13.2.16->1.1.1.3.12.13.2.17 src/protos.h:1.1.1.3.12.17.2.35->1.1.1.3.12.17.2.36 src/structs.h:1.1.1.3.4.1.2.26.2.40->1.1.1.3.4.1.2.26.2.41 src/typedefs.h:1.1.1.3.12.13.2.32->1.1.1.3.12.13.2.33 src/auth/basic/auth_basic.c:1.1.2.40->1.1.2.41 src/auth/digest/auth_digest.c:1.1.20.5->1.1.20.6 src/auth/ntlm/auth_ntlm.c:1.1.2.42->1.1.2.43 src/auth/ntlm/auth_ntlm.h:1.1.2.9->1.1.2.10 Index: squid/src/acl.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/acl.c,v retrieving revision 1.1.1.3.12.26.2.52 retrieving revision 1.1.1.3.12.26.2.53 diff -u -r1.1.1.3.12.26.2.52 -r1.1.1.3.12.26.2.53 --- squid/src/acl.c 31 Jul 2001 10:29:22 -0000 1.1.1.3.12.26.2.52 +++ squid/src/acl.c 2 Aug 2001 13:42:36 -0000 1.1.1.3.12.26.2.53 @@ -1,6 +1,6 @@ /* - * $Id: acl.c,v 1.1.1.3.12.26.2.52 2001/07/31 10:29:22 rbcollins Exp $ + * $Id: acl.c,v 1.1.1.3.12.26.2.53 2001/08/02 13:42:36 rbcollins Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -1182,189 +1182,6 @@ } } - - /* THIS IS FOR BUGFIXING BELOW... ***** - * Is this an already authenticated connection with a new auth header? - * FIXME: This breaks the abstraction model. Even if it is just for bug hunting - * It's really really ugly. - */ - #include "auth/ntlm/auth_ntlm.h" - -/* returns one of - * AUTH_ACL_CHALLENGE, - * AUTH_ACL_HELPER, - * AUTH_ACL_CANNOT_AUTHENTICATE, - * AUTH_AUTHENTICATED - * - * How to use: In your proxy-auth dependent acl code, use the following - * construct: - * int rv; - * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED) - * return rv; - * - * when this code is reached, the request/connection is authenticated. - * - * if you have non-acl code, but want to force authentication, you need a - * callback mechanism like the acl testing routines that will send a 40[1|7] to - * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with - * the authenticateStart routine for rv==AUTH_ACL_HELPER - */ -static auth_acl_t -AuthenticateAuthenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t *request, ConnStateData *conn, struct in_addr src_addr) -{ - const char * proxy_auth; - assert(headertype != 0); - proxy_auth = httpHeaderGetStr(&request->header, headertype); - - if (conn == NULL) { - debug(28, 1) ("aclMatchProxyAuth: no connection data, cannot process authentication\n"); - /* - * deny access: clientreadrequest requires conn data, and it is always - * compiled in so we should have it too. - */ - return AUTH_ACL_CANNOT_AUTHENTICATE; - } - - /* - * a note on proxy_auth logix here: - * proxy_auth==NULL -> unauthenticated request || already authenticated connection - * so we test for an authenticated connection when we recieve no authentication - * header. - */ - if (((proxy_auth == NULL) && (!authenticateUserAuthenticated(*auth_user_request ? *auth_user_request : conn->auth_user_request))) - || (conn->auth_type == AUTH_BROKEN)) { - /* no header or authentication failed/got corrupted - restart */ - conn->auth_type = AUTH_UNKNOWN; - debug(28, 4) ("aclMatchProxyAuth: broken auth or no proxy_auth header. Requesting auth header.\n"); - /* something wrong with the AUTH credentials. Force a new attempt */ - conn->auth_user_request = NULL; - if (*auth_user_request) { - /* unlock the ACL lock */ - authenticateAuthUserRequestUnlock(*auth_user_request); - auth_user_request = NULL; - } - return AUTH_ACL_CHALLENGE; - } - - /* - * Is this an already authenticated connection with a new auth header? - * FIXME: This breaks the abstraction model. Even if it is just for bug hunting - * It's really really ugly. - */ - if (proxy_auth && conn->auth_user_request && - authenticateUserAuthenticated(conn->auth_user_request) - && strcmp(proxy_auth, ((ntlm_request_t *)(conn->auth_user_request->scheme_data))->ntlmauthenticate)) { - debug(28,1) ("aclMatchProxyAuth: DUPLICATE AUTH - authentication header on already authenticated connection!. Current user '%s' proxy_auth %s, authenticate request %s\n", authenticateUserRequestUsername(conn->auth_user_request), proxy_auth, ((ntlm_request_t *)(conn->auth_user_request->scheme_data))->ntlmauthenticate); - /* remove this request struct - the link is already authed and it can't be to - * reauth. - */ - - /* This should _only_ ever occur on the first pass through aclMatchProxyAuth */ - assert(*auth_user_request == NULL); - /* unlock the conn lock on the auth_user_request */ - authenticateAuthUserRequestUnlock(conn->auth_user_request); - /* mark the conn as non-authed. */ - conn->auth_user_request=NULL; - /* Set the connection auth type */ - conn->auth_type = AUTH_UNKNOWN; - } - - /* we have a proxy auth header and as far as we know this connection has - * not had bungled connection oriented authentication happen on it. */ - debug(28, 9) ("aclMatchProxyAuth: header %s.\n", proxy_auth); - if (*auth_user_request == NULL) { - debug(28, 9) ("aclMatchProxyAuth: This is a new checklist test on FD:%d\n", - conn->fd); - if ((!request->auth_user_request) - && (conn->auth_type == AUTH_UNKNOWN)) { - /* beginning of a new request check */ - debug(28, 4) ("aclMatchProxyAuth: no connection authentication type\n"); - if (!authenticateValidateUser(*auth_user_request = - authenticateGetAuthUser(proxy_auth))) { - /* the decode might have left a username for logging, or a message to - * the user */ - if (authenticateUserRequestUsername(*auth_user_request)) { - /* lock the user for the request structure link */ - authenticateAuthUserRequestLock(*auth_user_request); - request->auth_user_request = *auth_user_request; - /* unlock the ACL reference. */ - authenticateAuthUserRequestUnlock(*auth_user_request); - } - return AUTH_ACL_CHALLENGE; - } - /* the user_request comes prelocked for the caller to GetAuthUser (us) */ - } else if (request->auth_user_request) { - *auth_user_request = request->auth_user_request; - /* lock the user request for this ACL processing */ - authenticateAuthUserRequestLock(*auth_user_request); - } else { - if (conn->auth_user_request != NULL) { - *auth_user_request = conn->auth_user_request; - /* lock the user request for this ACL processing */ - authenticateAuthUserRequestLock(*auth_user_request); - } else { - /* failed connection based authentication */ - debug(28, 4) ("aclMatchProxyAuth: Auth user request %d conn-auth user request %d conn type %d authentication failed.\n", - *auth_user_request, conn->auth_user_request, conn->auth_type); - authenticateAuthUserRequestUnlock(*auth_user_request); - *auth_user_request=NULL; - return AUTH_ACL_CHALLENGE; - } - } - } - - if (!authenticateUserAuthenticated(*auth_user_request)) { - /* User not logged in. Log them in */ - authenticateAuthenticateUser(*auth_user_request, request, - conn, headertype); - switch (authenticateDirection(*auth_user_request)) { - case 1: - /* this ACL check is finished. Unlock. */ - authenticateAuthUserRequestUnlock(*auth_user_request); - *auth_user_request=NULL; - return AUTH_ACL_CHALLENGE; - case -1: - /* we are partway through authentication within squid, - * the *auth_user_request variables stores the auth_user_request - * for the callback to here - Do not Unlock */ - return AUTH_ACL_HELPER; - case -2: - /* this ACL check is finished. Unlock. */ - authenticateAuthUserRequestUnlock(*auth_user_request); - *auth_user_request=NULL; - return AUTH_ACL_CHALLENGE; - } - /* on 0 the authentication is finished - fallthrough */ - /* See of user authentication failed for some reason */ - if (!authenticateUserAuthenticated(*auth_user_request)) { - if ((authenticateUserRequestUsername(*auth_user_request))) { - if (!request->auth_user_request) { - /* lock the user for the request structure link */ - authenticateAuthUserRequestLock(*auth_user_request); - request->auth_user_request = *auth_user_request; - } - } - /* this ACL check is finished. Unlock. */ - authenticateAuthUserRequestUnlock(*auth_user_request); - *auth_user_request=NULL; - return AUTH_ACL_CHALLENGE; - } - } - - /* copy username to request for logging on client-side */ - /* the credentials are correct at this point */ - if (!request->auth_user_request) { - /* lock the user for the request structure link */ - authenticateAuthUserRequestLock(*auth_user_request); - request->auth_user_request = *auth_user_request; - authenticateAuthUserRequestSetIp(*auth_user_request, src_addr); - } - - /* Unlock the request - we've authenticated it */ - authenticateAuthUserRequestUnlock(*auth_user_request); - return AUTH_AUTHENTICATED; -} - /* aclMatchProxyAuth can return four exit codes: * 0 : Authorisation for this ACL failed. (Did not match) * 1 : Authorisation OK. (Matched) @@ -1771,7 +1588,7 @@ #endif } /* get authed here */ - if ((ti = AuthenticateAuthenticate(&checklist->auth_user_request, headertype, checklist->request, checklist->conn, checklist->src_addr)) != AUTH_AUTHENTICATED) { + if ((ti = authenticateAuthenticate(&checklist->auth_user_request, headertype, checklist->request, checklist->conn, checklist->src_addr)) != AUTH_AUTHENTICATED) { switch (ti) { case 0: /* Authenticated but not Authorised for this ACL */ Index: squid/src/authenticate.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/authenticate.c,v retrieving revision 1.1.1.3.12.17.2.43 retrieving revision 1.1.1.3.12.17.2.44 diff -u -r1.1.1.3.12.17.2.43 -r1.1.1.3.12.17.2.44 --- squid/src/authenticate.c 31 Jul 2001 10:29:23 -0000 1.1.1.3.12.17.2.43 +++ squid/src/authenticate.c 2 Aug 2001 13:42:36 -0000 1.1.1.3.12.17.2.44 @@ -1,6 +1,6 @@ /* - * $Id: authenticate.c,v 1.1.1.3.12.17.2.43 2001/07/31 10:29:23 rbcollins Exp $ + * $Id: authenticate.c,v 1.1.1.3.12.17.2.44 2001/08/02 13:42:36 rbcollins Exp $ * * DEBUG: section 29 Authenticator * AUTHOR: Duane Wessels @@ -407,11 +407,12 @@ } /* - * authenticateAuthenticateUser: log this user request in. + * authenticateAuthenticateUser: call the module specific code to + * log this user request in. * Cache hits may change the auth_user pointer in the structure if needed. * This is basically a handle approach. */ -void +static void authenticateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type) { assert(auth_user_request != NULL); @@ -419,6 +420,182 @@ authscheme_list[auth_user_request->auth_user->auth_module - 1].authAuthenticate(auth_user_request, request, conn, type); } +/* returns one of + * AUTH_ACL_CHALLENGE, + * AUTH_ACL_HELPER, + * AUTH_ACL_CANNOT_AUTHENTICATE, + * AUTH_AUTHENTICATED + * + * How to use: In your proxy-auth dependent acl code, use the following + * construct: + * int rv; + * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED) + * return rv; + * + * when this code is reached, the request/connection is authenticated. + * + * if you have non-acl code, but want to force authentication, you need a + * callback mechanism like the acl testing routines that will send a 40[1|7] to + * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with + * the authenticateStart routine for rv==AUTH_ACL_HELPER + */ +auth_acl_t +authenticateAuthenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t *request, ConnStateData *conn, struct in_addr src_addr) +{ + const char * proxy_auth; + assert(headertype != 0); + proxy_auth = httpHeaderGetStr(&request->header, headertype); + + if (conn == NULL) { + debug(28, 1) ("aclMatchProxyAuth: no connection data, cannot process authentication\n"); + /* + * deny access: clientreadrequest requires conn data, and it is always + * compiled in so we should have it too. + */ + return AUTH_ACL_CANNOT_AUTHENTICATE; + } + + /* + * a note on proxy_auth logix here: + * proxy_auth==NULL -> unauthenticated request || already authenticated connection + * so we test for an authenticated connection when we recieve no authentication + * header. + */ + if (((proxy_auth == NULL) && (!authenticateUserAuthenticated(*auth_user_request ? *auth_user_request : conn->auth_user_request))) + || (conn->auth_type == AUTH_BROKEN)) { + /* no header or authentication failed/got corrupted - restart */ + conn->auth_type = AUTH_UNKNOWN; + debug(28, 4) ("aclMatchProxyAuth: broken auth or no proxy_auth header. Requesting auth header.\n"); + /* something wrong with the AUTH credentials. Force a new attempt */ + conn->auth_user_request = NULL; + if (*auth_user_request) { + /* unlock the ACL lock */ + authenticateAuthUserRequestUnlock(*auth_user_request); + auth_user_request = NULL; + } + return AUTH_ACL_CHALLENGE; + } + + /* + * Is this an already authenticated connection with a new auth header? + * No check for function required in the if: its compulsory for conn based + * auth modules + */ + if (proxy_auth && conn->auth_user_request && + authenticateUserAuthenticated(conn->auth_user_request) && + strcmp(proxy_auth, authscheme_list[conn->auth_user_request->auth_user->auth_module - 1].authConnLastHeader(conn->auth_user_request))) { + debug(28,1) ("aclMatchProxyAuth: DUPLICATE AUTH - authentication header on already authenticated connection!. Current user '%s' proxy_auth %s\n", authenticateUserRequestUsername(conn->auth_user_request), proxy_auth); + /* remove this request struct - the link is already authed and it can't be to + * reauth. + */ + + /* This should _only_ ever occur on the first pass through aclMatchProxyAuth */ + assert(*auth_user_request == NULL); + /* unlock the conn lock on the auth_user_request */ + authenticateAuthUserRequestUnlock(conn->auth_user_request); + /* mark the conn as non-authed. */ + conn->auth_user_request=NULL; + /* Set the connection auth type */ + conn->auth_type = AUTH_UNKNOWN; + } + + /* we have a proxy auth header and as far as we know this connection has + * not had bungled connection oriented authentication happen on it. */ + debug(28, 9) ("aclMatchProxyAuth: header %s.\n", proxy_auth); + if (*auth_user_request == NULL) { + debug(28, 9) ("aclMatchProxyAuth: This is a new checklist test on FD:%d\n", + conn->fd); + if ((!request->auth_user_request) + && (conn->auth_type == AUTH_UNKNOWN)) { + /* beginning of a new request check */ + debug(28, 4) ("aclMatchProxyAuth: no connection authentication type\n"); + if (!authenticateValidateUser(*auth_user_request = + authenticateGetAuthUser(proxy_auth))) { + /* the decode might have left a username for logging, or a message to + * the user */ + if (authenticateUserRequestUsername(*auth_user_request)) { + /* lock the user for the request structure link */ + authenticateAuthUserRequestLock(*auth_user_request); + request->auth_user_request = *auth_user_request; + /* unlock the ACL reference. */ + authenticateAuthUserRequestUnlock(*auth_user_request); + } + return AUTH_ACL_CHALLENGE; + } + /* the user_request comes prelocked for the caller to GetAuthUser (us) */ + } else if (request->auth_user_request) { + *auth_user_request = request->auth_user_request; + /* lock the user request for this ACL processing */ + authenticateAuthUserRequestLock(*auth_user_request); + } else { + if (conn->auth_user_request != NULL) { + *auth_user_request = conn->auth_user_request; + /* lock the user request for this ACL processing */ + authenticateAuthUserRequestLock(*auth_user_request); + } else { + /* failed connection based authentication */ + debug(28, 4) ("aclMatchProxyAuth: Auth user request %d conn-auth user request %d conn type %d authentication failed.\n", + *auth_user_request, conn->auth_user_request, conn->auth_type); + authenticateAuthUserRequestUnlock(*auth_user_request); + *auth_user_request=NULL; + return AUTH_ACL_CHALLENGE; + } + } + } + + if (!authenticateUserAuthenticated(*auth_user_request)) { + /* User not logged in. Log them in */ + authenticateAuthenticateUser(*auth_user_request, request, + conn, headertype); + switch (authenticateDirection(*auth_user_request)) { + case 1: + /* this ACL check is finished. Unlock. */ + authenticateAuthUserRequestUnlock(*auth_user_request); + *auth_user_request=NULL; + return AUTH_ACL_CHALLENGE; + case -1: + /* we are partway through authentication within squid, + * the *auth_user_request variables stores the auth_user_request + * for the callback to here - Do not Unlock */ + return AUTH_ACL_HELPER; + case -2: + /* this ACL check is finished. Unlock. */ + authenticateAuthUserRequestUnlock(*auth_user_request); + *auth_user_request=NULL; + return AUTH_ACL_CHALLENGE; + } + /* on 0 the authentication is finished - fallthrough */ + /* See of user authentication failed for some reason */ + if (!authenticateUserAuthenticated(*auth_user_request)) { + if ((authenticateUserRequestUsername(*auth_user_request))) { + if (!request->auth_user_request) { + /* lock the user for the request structure link */ + authenticateAuthUserRequestLock(*auth_user_request); + request->auth_user_request = *auth_user_request; + } + } + /* this ACL check is finished. Unlock. */ + authenticateAuthUserRequestUnlock(*auth_user_request); + *auth_user_request=NULL; + return AUTH_ACL_CHALLENGE; + } + } + + /* copy username to request for logging on client-side */ + /* the credentials are correct at this point */ + if (!request->auth_user_request) { + /* lock the user for the request structure link */ + authenticateAuthUserRequestLock(*auth_user_request); + request->auth_user_request = *auth_user_request; + authenticateAuthUserRequestSetIp(*auth_user_request, src_addr); + } + + /* Unlock the request - we've authenticated it */ + authenticateAuthUserRequestUnlock(*auth_user_request); + return AUTH_AUTHENTICATED; +} + + /* authenticateUserUsername: return a pointer to the username in the */ char * authenticateUserUsername(auth_user_t * auth_user) Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.1.1.3.4.1.2.30.2.33 retrieving revision 1.1.1.3.4.1.2.30.2.34 diff -u -r1.1.1.3.4.1.2.30.2.33 -r1.1.1.3.4.1.2.30.2.34 --- squid/src/client_side.c 31 Jul 2001 10:29:23 -0000 1.1.1.3.4.1.2.30.2.33 +++ squid/src/client_side.c 2 Aug 2001 13:42:36 -0000 1.1.1.3.4.1.2.30.2.34 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.1.1.3.4.1.2.30.2.33 2001/07/31 10:29:23 rbcollins Exp $ + * $Id: client_side.c,v 1.1.1.3.4.1.2.30.2.34 2001/08/02 13:42:36 rbcollins Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -258,32 +258,20 @@ if (page_id == ERR_NONE) page_id = ERR_CACHE_ACCESS_DENIED; } else { -#ifdef KINKIES_407_HACK /* return a 407 */ - status = HTTP_PROXY_AUTHENTICATION_REQUIRED; - if (page_id == ERR_NONE) - page_id = ERR_CACHE_ACCESS_DENIED; -#else /* return a 403 */ status = HTTP_FORBIDDEN; if (page_id == ERR_NONE) page_id = ERR_ACCESS_DENIED; -#endif } err = errorCon(page_id, status); err->request = requestLink(http->request); err->src_addr = http->conn->peer.sin_addr; -#ifdef KINKIES_407_HACK - if (answer == ACCESS_REQ_PROXY_AUTH) { /* second part, by Kinkie */ -#endif - if (http->conn->auth_user_request) - err->auth_user_request = http->conn->auth_user_request; - else if (http->request->auth_user_request) - err->auth_user_request = http->request->auth_user_request; - /* lock for the error state */ - if (err->auth_user_request) - authenticateAuthUserRequestLock(err->auth_user_request); -#ifdef KINKIES_407_HACK - } -#endif + if (http->conn->auth_user_request) + err->auth_user_request = http->conn->auth_user_request; + else if (http->request->auth_user_request) + err->auth_user_request = http->request->auth_user_request; + /* lock for the error state */ + if (err->auth_user_request) + authenticateAuthUserRequestLock(err->auth_user_request); err->callback_data = NULL; errorAppendEntry(http->entry, err); } Index: squid/src/helper.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/helper.c,v retrieving revision 1.1.1.3.12.13.2.16 retrieving revision 1.1.1.3.12.13.2.17 diff -u -r1.1.1.3.12.13.2.16 -r1.1.1.3.12.13.2.17 --- squid/src/helper.c 16 Jul 2001 21:44:17 -0000 1.1.1.3.12.13.2.16 +++ squid/src/helper.c 2 Aug 2001 13:42:37 -0000 1.1.1.3.12.13.2.17 @@ -1,6 +1,6 @@ /* - * $Id: helper.c,v 1.1.1.3.12.13.2.16 2001/07/16 21:44:17 rbcollins Exp $ + * $Id: helper.c,v 1.1.1.3.12.13.2.17 2001/08/02 13:42:37 rbcollins Exp $ * * DEBUG: section 29 Helper process maintenance * AUTHOR: Harvest Derived? @@ -183,6 +183,10 @@ srv->flags.alive = 1; srv->flags.reserved = S_HELPER_FREE; srv->deferred_requests = 0; + srv->stats.deferbyfunc = 0; + srv->stats.deferbycb = 0; + srv->stats.submits = 0; + srv->stats.releases = 0; srv->index = k; srv->rfd = rfd; srv->wfd = wfd; @@ -260,8 +264,19 @@ cbdataLock(r->data); if ((buf != NULL) && lastserver) { debug(29, 5) ("StatefulSubmit with lastserver %d\n", lastserver); - if (lastserver->flags.reserved != S_HELPER_RESERVED) + /* the queue doesn't count for this assert because queued requests + * have already gone through here and been tested. + * It's legal to have deferred_requests == 0 and queue entries + * and status of S_HELPEER_DEFERRED. + * BUT: It's not legal to submit a new request w/lastserver in + * that state. + */ + assert (!(lastserver->deferred_requests == 0 && + lastserver->flags.reserved == S_HELPER_DEFERRED)); + if (lastserver->flags.reserved != S_HELPER_RESERVED) { + lastserver->stats.submits++; lastserver->deferred_requests--; + } if (!(lastserver->request)) { debug(29, 5) ("StatefulSubmit dispatching\n"); helperStatefulDispatch(lastserver, r); @@ -314,8 +329,20 @@ debug(29, 1) ("helperStatefulDefer: None available.\n"); return NULL; } + /* consistency check: + * when the deferred count is 0, + * submits + releases == deferbyfunc + deferbycb + * Or in english, when there are no deferred requests, the amount + * we have submitted to the queue or cancelled must equal the amount + * we have said we wanted to be able to submit or cancel + */ + if (rv->deferred_requests == 0) + assert (rv->stats.submits + rv->stats.releases == + rv->stats.deferbyfunc + rv->stats.deferbycb); + rv->flags.reserved = S_HELPER_DEFERRED; rv->deferred_requests++; + rv->stats.deferbyfunc++; return rv; } @@ -337,7 +364,6 @@ helperStatefulRequestFree(r); srv->request = NULL; } - debug(29, 1) ("helperStatefulReset reset helper %s #%d\n", hlp->id_name, srv->index + 1); srv->flags.busy = 0; if (srv->queue.head) { srv->flags.reserved = S_HELPER_DEFERRED; @@ -354,8 +380,11 @@ helperStatefulReleaseServer(helper_stateful_server * srv) /*decrease the number of 'waiting' clients that set the helper to be DEFERRED */ { - if (srv->deferred_requests > 0) + srv->stats.releases++; + if (srv->flags.reserved == S_HELPER_DEFERRED) { + assert (srv->deferred_requests); srv->deferred_requests--; + } if (!(srv->deferred_requests) && (srv->flags.reserved == S_HELPER_DEFERRED) && !(srv->queue.head)) { srv->flags.reserved = S_HELPER_FREE; if ((srv->parent->OnEmptyQueue != NULL) && (srv->data)) @@ -747,7 +776,7 @@ fatal("helperStatefulHandleRead: either a non-state aware callback was give to the stateful helper routines, or an uninitialised callback response was recieved.\n"); break; case S_HELPER_RELEASE: /* helper finished with */ - if (!srv->queue.head) { + if (!srv->deferred_requests && !srv->queue.head) { srv->flags.reserved = S_HELPER_FREE; if ((srv->parent->OnEmptyQueue != NULL) && (srv->data)) srv->parent->OnEmptyQueue(srv->data); @@ -759,6 +788,7 @@ break; case S_HELPER_RESERVE: /* 'pin' this helper for the caller */ if (!srv->queue.head) { + assert (srv->deferred_requests == 0); srv->flags.reserved = S_HELPER_RESERVED; debug(29, 5) ("StatefulHandleRead: reserving %s #%d\n", hlp->id_name, srv->index + 1); } else { @@ -771,6 +801,7 @@ */ srv->flags.reserved = S_HELPER_DEFERRED; srv->deferred_requests++; + srv->stats.deferbycb++; debug(29, 5) ("StatefulHandleRead: reserving %s #%d for deferred requests.\n", hlp->id_name, srv->index + 1); break; default: Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.1.1.3.12.17.2.35 retrieving revision 1.1.1.3.12.17.2.36 diff -u -r1.1.1.3.12.17.2.35 -r1.1.1.3.12.17.2.36 --- squid/src/protos.h 31 Jul 2001 10:29:23 -0000 1.1.1.3.12.17.2.35 +++ squid/src/protos.h 2 Aug 2001 13:42:37 -0000 1.1.1.3.12.17.2.36 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.1.1.3.12.17.2.35 2001/07/31 10:29:23 rbcollins Exp $ + * $Id: protos.h,v 1.1.1.3.12.17.2.36 2001/08/02 13:42:37 rbcollins Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -738,7 +738,7 @@ extern void authenticateFixHeader(HttpReply *, auth_user_request_t *, request_t *, int, int); extern void authenticateAddTrailer(HttpReply *, auth_user_request_t *, request_t *, int); extern auth_user_request_t *authenticateGetAuthUser(const char *proxy_auth); -extern void authenticateAuthenticateUser(auth_user_request_t *, request_t *, ConnStateData *, http_hdr_type); +extern auth_acl_t authenticateAuthenticate(auth_user_request_t **, http_hdr_type, request_t *, ConnStateData *, struct in_addr); extern void authenticateAuthUserUnlock(auth_user_t * auth_user); extern void authenticateAuthUserLock(auth_user_t * auth_user); extern void authenticateAuthUserRequestUnlock(auth_user_request_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.40 retrieving revision 1.1.1.3.4.1.2.26.2.41 diff -u -r1.1.1.3.4.1.2.26.2.40 -r1.1.1.3.4.1.2.26.2.41 --- squid/src/structs.h 31 Jul 2001 10:29:23 -0000 1.1.1.3.4.1.2.26.2.40 +++ squid/src/structs.h 2 Aug 2001 13:42:37 -0000 1.1.1.3.4.1.2.26.2.41 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.1.1.3.4.1.2.26.2.40 2001/07/31 10:29:23 rbcollins Exp $ + * $Id: structs.h,v 1.1.1.3.4.1.2.26.2.41 2001/08/02 13:42:37 rbcollins Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -158,6 +158,7 @@ AUTHSFREECONFIG *freeconfig; AUTHSUSERNAME *authUserUsername; AUTHSONCLOSEC *oncloseconnection; /*optional */ + AUTHSCONNLASTHEADER *authConnLastHeader; AUTHSDECODE *decodeauth; AUTHSDIRECTION *getdirection; AUTHSPARSE *parse; @@ -2051,6 +2052,10 @@ } flags; struct { int uses; + int submits; + int releases; + int deferbyfunc; + int deferbycb; } stats; size_t deferred_requests; /* current number of deferred requests */ void *data; /* State data used by the calling routines */ Index: squid/src/typedefs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.1.1.3.12.13.2.32 retrieving revision 1.1.1.3.12.13.2.33 diff -u -r1.1.1.3.12.13.2.32 -r1.1.1.3.12.13.2.33 --- squid/src/typedefs.h 31 Jul 2001 10:29:23 -0000 1.1.1.3.12.13.2.32 +++ squid/src/typedefs.h 2 Aug 2001 13:42:37 -0000 1.1.1.3.12.13.2.33 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.1.1.3.12.13.2.32 2001/07/31 10:29:23 rbcollins Exp $ + * $Id: typedefs.h,v 1.1.1.3.12.13.2.33 2001/08/02 13:42:37 rbcollins Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -315,6 +315,7 @@ typedef void AUTHSSHUTDOWN(void); typedef void AUTHSSTART(auth_user_request_t *, RH *, void *); typedef void AUTHSSTATS(StoreEntry *); +typedef const char * AUTHSCONNLASTHEADER(auth_user_request_t *); /* append/vprintf's for Packer */ typedef void (*append_f) (void *, const char *buf, int size); Index: squid/src/auth/basic/auth_basic.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/auth/basic/auth_basic.c,v retrieving revision 1.1.2.40 retrieving revision 1.1.2.41 diff -u -r1.1.2.40 -r1.1.2.41 --- squid/src/auth/basic/auth_basic.c 31 Jul 2001 10:29:23 -0000 1.1.2.40 +++ squid/src/auth/basic/auth_basic.c 2 Aug 2001 13:42:37 -0000 1.1.2.41 @@ -1,4 +1,4 @@ - + /* * $Id$ * @@ -104,6 +104,7 @@ authscheme->oncloseconnection = NULL; authscheme->decodeauth = authenticateBasicDecodeAuth; authscheme->donefunc = authBasicDone; + authscheme->authConnLastHeader = NULL; } /* internal functions */ 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.20.5 retrieving revision 1.1.20.6 diff -u -r1.1.20.5 -r1.1.20.6 --- squid/src/auth/digest/auth_digest.c 31 Jul 2001 10:29:24 -0000 1.1.20.5 +++ squid/src/auth/digest/auth_digest.c 2 Aug 2001 13:42:37 -0000 1.1.20.6 @@ -456,7 +456,8 @@ hash_first(proxy_auth_username_cache); while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) { auth_user = usernamehash->auth_user; - if (strcmp(authscheme_list[auth_user->auth_module - 1].typestr, "digest") == 0) + if (authscheme_list[auth_user->auth_module - 1].typestr && + strcmp(authscheme_list[auth_user->auth_module - 1].typestr, "digest") == 0) /* it's digest */ authenticateAuthUserUnlock(auth_user); } @@ -597,6 +598,7 @@ authscheme->decodeauth = authenticateDigestDecodeAuth; authscheme->donefunc = authDigestDone; authscheme->requestFree = authDigestAURequestFree; + authscheme->authConnLastHeader = NULL; } int Index: squid/src/auth/ntlm/auth_ntlm.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/auth/ntlm/auth_ntlm.c,v retrieving revision 1.1.2.42 retrieving revision 1.1.2.43 diff -u -r1.1.2.42 -r1.1.2.43 --- squid/src/auth/ntlm/auth_ntlm.c 31 Jul 2001 10:29:24 -0000 1.1.2.42 +++ squid/src/auth/ntlm/auth_ntlm.c 2 Aug 2001 13:42:37 -0000 1.1.2.43 @@ -62,6 +62,7 @@ static AUTHSFREECONFIG authNTLMFreeConfig; static AUTHSINIT authNTLMInit; static AUTHSONCLOSEC authenticateNTLMOnCloseConnection; +static AUTHSCONNLASTHEADER NTLMLastHeader; static AUTHSUSERNAME authenticateNTLMUsername; static AUTHSREQFREE authNTLMAURequestFree; static AUTHSPARSE authNTLMParse; @@ -74,6 +75,7 @@ static HLPSONEQ authenticateNTLMHelperServerOnEmpty; static statefulhelper *ntlmauthenticators = NULL; +static wordlist *ntlmprevauthline = NULL; CBDATA_TYPE(authenticateStateData); @@ -92,17 +94,38 @@ * */ +static int +wordliststrcmp (wordlist *a, wordlist *b) +{ + int i; + while (a && b) { + if ((i = strcmp(a->key, b->key))) + return i; + a = a->next; + b = b->next; + } + if (a && ! b) + return -1; + if (b && ! a) + return 1; + return 0; +} + void authNTLMDone(void) { debug(29, 2) ("authNTLMDone: shutting down NTLM authentication.\n"); +#if 0 if (ntlmauthenticators) helperStatefulShutdown(ntlmauthenticators); +#endif authntlm_initialised = 0; if (!shutting_down) return; - if (ntlmauthenticators) + if (ntlmauthenticators) { + helperStatefulShutdown(ntlmauthenticators); helperStatefulFree(ntlmauthenticators); + } ntlmauthenticators = NULL; if (ntlm_helper_state_pool) { assert(memPoolInUseCount(ntlm_helper_state_pool) == 0); @@ -215,6 +238,7 @@ authscheme->decodeauth = authenticateDecodeNTLMAuth; authscheme->donefunc = authNTLMDone; authscheme->oncloseconnection = authenticateNTLMOnCloseConnection; + authscheme->authConnLastHeader = NTLMLastHeader; } /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the @@ -242,7 +266,13 @@ ntlmauthenticators->datapool = ntlm_helper_state_pool; ntlmauthenticators->IsAvailable = authenticateNTLMHelperServerAvailable; ntlmauthenticators->OnEmptyQueue = authenticateNTLMHelperServerOnEmpty; - helperStatefulOpenServers(ntlmauthenticators); + if (wordliststrcmp(ntlmprevauthline, ntlmConfig->authenticate)) { + helperStatefulShutdown(ntlmauthenticators); + helperStatefulOpenServers(ntlmauthenticators); + if (ntlmprevauthline) + wordlistDestroy (&ntlmprevauthline); + ntlmprevauthline = wordlistDup (ntlmConfig->authenticate); + } /* TODO: In here send the initial YR to preinitialise the challenge cache */ /* Think about this... currently we ask when the challenge is needed. Better? */ if (!ntlminit) { @@ -330,11 +360,6 @@ debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM %s'\n", type, ntlm_request->authchallenge); httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->authchallenge); break; -#ifdef KINKIES_407_HACK - case AUTHENTICATE_STATE_DONE: /* HACK by Kinkie */ - /* nothing */ - break; -#endif /* KINKIES_407_HACK */ default: debug(29, 0) ("authenticateNTLMFixErrorHeader: state %d.\n", ntlm_request->auth_state); fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n"); @@ -403,6 +428,10 @@ assert(r->auth_user_request); /* standard callback stuff */ valid = cbdataValid(r->data); + if (!valid) { + debug(29, 1) ("AuthenticateNTLMHandlePlacheholder: invalid callback data.\n"); + return result; + } /* call authenticateNTLMStart to retry this request */ debug(29, 9) ("authenticateNTLMHandleplaceholder: calling authenticateNTLMStart\n"); authenticateNTLMStart(r->auth_user_request, r->handler, r->data); @@ -435,7 +464,7 @@ /* copy the challenge to the state data */ helperstate = helperStatefulServerGetData(lastserver); if (helperstate == NULL) - fatal("lost NTLm helper state! quitting\n"); + fatal("lost NTLM helper state! quitting\n"); helperstate->challenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5); helperstate->challengeuses = 0; helperstate->renewed = squid_curtime; @@ -447,6 +476,8 @@ ntlm_request = auth_user_request->scheme_data; assert(ntlm_request != NULL); result = S_HELPER_DEFER; + /* reserve the server for future authentication */ + ntlm_request->authserver_deferred = 1; debug(29, 9) ("authenticateNTLMHandleReply: helper '%d'\n", lastserver); assert(ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE); ntlm_request->authserver = lastserver; @@ -609,7 +640,7 @@ /* does our policy call for changing the challenge now? */ int -authenticateNTLMChangeChallenge(ntlm_helper_state_t * helperstate) +authenticateNTLMChangeChallenge_p(ntlm_helper_state_t * helperstate) { /* don't check for invalid challenges just for expiry choices */ /* this is needed because we have to starve the helper until all old @@ -617,15 +648,15 @@ if (!helperstate->renewed) { /* first use, no challenge has been set. Without this check, it will * loop forever */ - debug(29, 5) ("authenticateNTLMChangeChallenge: first use\n"); + debug(29, 5) ("authenticateNTLMChangeChallenge_p: first use\n"); return 0; } if (helperstate->challengeuses > ntlmConfig->challengeuses) { - debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge uses (%d) exceeded max uses (%d)\n", helperstate->challengeuses, ntlmConfig->challengeuses); + debug(29, 4) ("authenticateNTLMChangeChallenge_p: Challenge uses (%d) exceeded max uses (%d)\n", helperstate->challengeuses, ntlmConfig->challengeuses); return 1; } if (helperstate->renewed + ntlmConfig->challengelifetime < squid_curtime) { - debug(29, 4) ("authenticateNTLMChangeChallenge: Challenge exceeded max lifetime by %d seconds\n", squid_curtime - (helperstate->renewed + ntlmConfig->challengelifetime)); + debug(29, 4) ("authenticateNTLMChangeChallenge_p: Challenge exceeded max lifetime by %d seconds\n", squid_curtime - (helperstate->renewed + ntlmConfig->challengelifetime)); return 1; } debug(29, 9) ("Challenge is to be reused\n"); @@ -681,16 +712,6 @@ handler(data, NULL); return; } -#ifdef NTLMHELPPROTOCOLV2 - r = cbdataAlloc(authenticateStateData); - r->handler = handler; - cbdataLock(data); - r->data = data; - r->auth_user_request = auth_user_request; - snprintf(buf, 8192, "%s\n", sent_string); - helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver); - debug(29, 9) ("authenticateNTLMstart: finished\n"); -#else /* this is ugly TODO: move the challenge generation routines to their own function and * tidy the logic up to make use of the efficiency we now have */ switch (ntlm_request->auth_state) { @@ -702,11 +723,12 @@ */ server = helperStatefulDefer(ntlmauthenticators); helperstate = server ? helperStatefulServerGetData(server) : NULL; - while ((server != NULL) && authenticateNTLMChangeChallenge(helperstate)) { + while ((server != NULL) && authenticateNTLMChangeChallenge_p(helperstate)) { /* flag this helper for challenge changing */ helperstate->starve = 1; /* and release the deferred request */ helperStatefulReleaseServer(server); + /* Get another deferrable server */ server = helperStatefulDefer(ntlmauthenticators); if (server != NULL) helperstate = helperStatefulServerGetData(server); @@ -717,26 +739,32 @@ ntlm_request->authserver = server; /* tell the log what helper we have been given */ debug(29, 9) ("authenticateNTLMStart: helper '%d' assigned\n", server); - /* valid challenge? */ + /* server and valid challenge? */ if ((server == NULL) || !authenticateNTLMValidChallenge(helperstate)) { + /* No server, or server with invalid challenge */ r = cbdataAlloc(authenticateStateData); r->handler = handler; cbdataLock(data); r->data = data; r->auth_user_request = auth_user_request; if (server == NULL) { - helperStatefulSubmit(ntlmauthenticators, NULL, authenticateNTLMHandleplaceholder, r, ntlm_request->authserver); + helperStatefulSubmit(ntlmauthenticators, NULL, authenticateNTLMHandleplaceholder, r, NULL); } else { + /* Server with invalid challenge */ snprintf(buf, 8192, "YR\n"); helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver); } } else { - /* we have a valid challenge */ + /* (server != NULL and we have a valid challenge) */ /* TODO: turn the below into a function and call from here and handlereply */ /* increment the challenge uses */ helperstate->challengeuses++; /* assign the challenge */ ntlm_request->authchallenge = xstrndup(helperstate->challenge, NTLM_CHALLENGE_SZ + 5); + /* we're not actually submitting a request, so we need to release the helper should + * the connection close unexpectedly + */ + ntlm_request->authserver_deferred = 1; handler(data, NULL); } @@ -748,13 +776,14 @@ r->data = data; r->auth_user_request = auth_user_request; snprintf(buf, 8192, "KK %s\n", sent_string); + /* getting rid of deferred request status */ + ntlm_request->authserver_deferred = 0; helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver); debug(29, 9) ("authenticateNTLMstart: finished\n"); break; default: fatal("Invalid authenticate state for NTLMStart"); } -#endif } /* callback used by stateful helper routines */ @@ -815,7 +844,7 @@ if (conn->auth_user_request != NULL) { assert(conn->auth_user_request->scheme_data != NULL); ntlm_request = conn->auth_user_request->scheme_data; - if (ntlm_request->authserver != NULL) + if (ntlm_request->authserver != NULL && ntlm_request->authserver_deferred) authenticateNTLMReleaseServer(conn->auth_user_request); /* unlock the connection based lock */ debug(29, 9) ("authenticateNTLMOnCloseConnection: Unlocking auth_user from the connection.\n"); @@ -834,6 +863,18 @@ return NULL; } +/* NTLMLastHeader: return a pointer to the last header used in authenticating + * the request/conneciton + */ +const char * +NTLMLastHeader(auth_user_request_t * auth_user_request) +{ + ntlm_request_t *ntlm_request; + assert(auth_user_request != NULL); + assert(auth_user_request->scheme_data != NULL); + ntlm_request = auth_user_request->scheme_data; + return ntlm_request->ntlmauthenticate; +} /* * Decode an NTLM [Proxy-]Auth string, placing the results in the passed @@ -849,6 +890,7 @@ auth_user_request->auth_user->auth_type = AUTH_NTLM; auth_user_request->auth_user->scheme_data = memPoolAlloc(ntlm_user_pool); auth_user_request->scheme_data = memPoolAlloc(ntlm_request_pool); + memset (auth_user_request->scheme_data, '\0', sizeof (ntlm_request_t)); /* lock for the auth_user_request link */ authenticateAuthUserLock(auth_user_request->auth_user); node = dlinkNodeNew(); @@ -865,15 +907,28 @@ return strcmp(u1->username, u2->username); } + +/* there is a known race where a single client recieves the same challenge + * and sends the same response to squid on a single select cycle. + * Check for this and if found ignore the new link + */ void authenticateProxyAuthCacheAddLink(const char *key, auth_user_t * auth_user) { auth_user_hash_pointer *proxy_auth_hash; + dlink_node *node; ntlm_user_t *ntlm_user; + ntlm_user = auth_user->scheme_data; + node = ntlm_user->proxy_auth_list.head; + /* prevent duplicates */ + while (node) { + if (!strcmp(key, ((auth_user_hash_pointer *)node->data)->key)) + return; + node=node->next; + } proxy_auth_hash = memAllocate(MEM_AUTH_USER_HASH); proxy_auth_hash->key = xstrdup(key); proxy_auth_hash->auth_user = auth_user; - ntlm_user = auth_user->scheme_data; dlinkAddTail(proxy_auth_hash, &proxy_auth_hash->link, &ntlm_user->proxy_auth_list); hash_join(proxy_auth_cache, (hash_link *) proxy_auth_hash); } @@ -927,6 +982,8 @@ break; case AUTHENTICATE_STATE_NEGOTIATE: ntlm_request->auth_state = AUTHENTICATE_STATE_CHALLENGE; + /* We _MUST_ have the auth challenge by now */ + assert(ntlm_request->authchallenge); return; break; case AUTHENTICATE_STATE_CHALLENGE: Index: squid/src/auth/ntlm/auth_ntlm.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/auth/ntlm/auth_ntlm.h,v retrieving revision 1.1.2.9 retrieving revision 1.1.2.10 diff -u -r1.1.2.9 -r1.1.2.10 --- squid/src/auth/ntlm/auth_ntlm.h 31 Jul 2001 10:29:24 -0000 1.1.2.9 +++ squid/src/auth/ntlm/auth_ntlm.h 2 Aug 2001 13:42:37 -0000 1.1.2.10 @@ -32,6 +32,8 @@ helper_stateful_server *authserver; /* how far through the authentication process are we? */ auth_state_t auth_state; + /* have we got the helper-server in a deferred state? */ + int authserver_deferred; }; struct _ntlm_helper_state_t {