--------------------- PatchSet 7078 Date: 2005/10/08 09:13:11 Author: serassio Branch: negotiate-nt-2_5 Tag: (none) Log: Imported negotiate-2_5.patch Members: configure.in:1.42.2.5.4.81->1.42.2.5.4.81.2.1 src/authenticate.c:1.23.2.1.4.14->1.23.2.1.4.14.2.1 src/cf.data.pre:1.49.2.5.4.80->1.49.2.5.4.80.2.1 src/enums.h:1.29.6.17->1.29.6.17.2.1 src/auth/Makefile.am:1.2.40.1->1.2.40.1.2.1 src/auth/ntlm/auth_ntlm.c:1.18.2.1.4.24->1.18.2.1.4.24.2.1 src/auth/ntlm/auth_ntlm.h:1.8.10.4->1.8.10.4.2.1 Index: squid/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid/configure.in,v retrieving revision 1.42.2.5.4.81 retrieving revision 1.42.2.5.4.81.2.1 diff -u -r1.42.2.5.4.81 -r1.42.2.5.4.81.2.1 --- squid/configure.in 1 Oct 2005 08:36:48 -0000 1.42.2.5.4.81 +++ squid/configure.in 8 Oct 2005 09:13:11 -0000 1.42.2.5.4.81.2.1 @@ -3,15 +3,15 @@ dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.42.2.5.4.81 2005/10/01 08:36:48 serassio Exp $ +dnl $Id: configure.in,v 1.42.2.5.4.81.2.1 2005/10/08 09:13:11 serassio Exp $ dnl dnl dnl AC_INIT(src/main.c) AC_CONFIG_AUX_DIR(cfgaux) -AM_INIT_AUTOMAKE(squid, 2.5.STABLE11-NT-CVS) +AM_INIT_AUTOMAKE(squid, 2.5.STABLE11-NEGOTIATE-NT-CVS) AM_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.42.2.5.4.81 $)dnl +AC_REVISION($Revision: 1.42.2.5.4.81.2.1 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -2633,6 +2633,7 @@ src/auth/basic/Makefile \ src/auth/digest/Makefile \ src/auth/ntlm/Makefile \ + src/auth/negotiate/Makefile \ contrib/Makefile \ snmplib/Makefile \ icons/Makefile \ Index: squid/src/authenticate.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/authenticate.c,v retrieving revision 1.23.2.1.4.14 retrieving revision 1.23.2.1.4.14.2.1 diff -u -r1.23.2.1.4.14 -r1.23.2.1.4.14.2.1 --- squid/src/authenticate.c 19 Sep 2005 16:23:07 -0000 1.23.2.1.4.14 +++ squid/src/authenticate.c 8 Oct 2005 09:13:11 -0000 1.23.2.1.4.14.2.1 @@ -1,6 +1,6 @@ /* - * $Id: authenticate.c,v 1.23.2.1.4.14 2005/09/19 16:23:07 serassio Exp $ + * $Id: authenticate.c,v 1.23.2.1.4.14.2.1 2005/10/08 09:13:11 serassio Exp $ * * DEBUG: section 29 Authenticator * AUTHOR: Duane Wessels @@ -763,11 +763,16 @@ /* call each configured & running authscheme */ for (i = 0; i < Config.authConfig.n_configured; i++) { scheme = Config.authConfig.schemes + i; - if (authscheme_list[scheme->Id].Active()) - authscheme_list[scheme->Id].authFixHeader(NULL, rep, type, - request); - else + if (authscheme_list[scheme->Id].Active()) { + if (auth_user_request && scheme->Id == auth_user_request->auth_user->auth_module - 1) + authscheme_list[scheme->Id].authFixHeader( + auth_user_request, rep, type, request); + else + authscheme_list[scheme->Id].authFixHeader( + NULL, rep, type, request); + } else { debug(29, 4) ("authenticateFixHeader: Configured scheme %s not Active\n", scheme->typestr); + } } } } Index: squid/src/cf.data.pre =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cf.data.pre,v retrieving revision 1.49.2.5.4.80 retrieving revision 1.49.2.5.4.80.2.1 diff -u -r1.49.2.5.4.80 -r1.49.2.5.4.80.2.1 --- squid/src/cf.data.pre 1 Oct 2005 08:36:48 -0000 1.49.2.5.4.80 +++ squid/src/cf.data.pre 8 Oct 2005 09:13:11 -0000 1.49.2.5.4.80.2.1 @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.49.2.5.4.80 2005/10/01 08:36:48 serassio Exp $ +# $Id: cf.data.pre,v 1.49.2.5.4.80.2.1 2005/10/08 09:13:11 serassio Exp $ # # # SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -1460,20 +1460,6 @@ lots of authenticator processes. auth_param ntlm children 5 - "max_challenge_reuses" number - The maximum number of times a challenge given by a ntlm authentication - helper can be reused. Increasing this number increases your exposure - to replay attacks on your network. 0 (the default) means use the - challenge is used only once. See also the max_ntlm_challenge_lifetime - directive if enabling challenge reuses. - auth_param ntlm max_challenge_reuses 0 - - "max_challenge_lifetime" timespan - The maximum time period a ntlm challenge is reused over. The - actual period will be the minimum of this time AND the number of - reused challenges. - auth_param ntlm max_challenge_lifetime 2 minutes - "use_ntlm_negotiate" on|off Enables support for NTLM NEGOTIATE packet exchanges with the helper. The configured ntlm authenticator must be able to handle NTLM @@ -1493,6 +1479,37 @@ max_challenge_lifetime parameters and set them to 0. auth_param ntlm use_ntlm_negotiate off + "keep_alive" on|off + This option enables the use of keep-alive on the initial + authentication request. It has been reported some versions of MSIE + have problems if this is enabled, but performance will be increased + if enabled. + + auth_param ntlm keep_alive off + + === Negotiate scheme options follow === + + "program" cmdline + Specify the command for the external SPNEGO authenticator. Such a + program participates in the SPNEGO exchanges between Squid and the + client and reads commands according to the Squid ntlmssp helper + protocol. See helpers/ntlm_auth/ for details. Recommended SPNEGO + authenticator is ntlm_auth from Samba-3.X. + + By default, the Negotiate authentication scheme is not used unless a + program is specified. + + auth_param negotiate program /path/to/samba/bin/ntlm_auth --helper-protocol=gss-spnego + + "keep_alive" on|off + If you experience problems with PUT/POST requests when using the + Negotiate authentication scheme then you can try setting this to + off. This will cause Squid to forcibly close the connection on + the initial requests where the browser asks which schemes are + supported by the proxy. + + auth_param negotiate keep_alive on + NOCOMMENT_START #Recommended minimum configuration: #auth_param digest program Index: squid/src/enums.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/enums.h,v retrieving revision 1.29.6.17 retrieving revision 1.29.6.17.2.1 diff -u -r1.29.6.17 -r1.29.6.17.2.1 --- squid/src/enums.h 20 Sep 2005 10:07:27 -0000 1.29.6.17 +++ squid/src/enums.h 8 Oct 2005 09:13:11 -0000 1.29.6.17.2.1 @@ -1,6 +1,6 @@ /* - * $Id: enums.h,v 1.29.6.17 2005/09/20 10:07:27 serassio Exp $ + * $Id: enums.h,v 1.29.6.17.2.1 2005/10/08 09:13:11 serassio Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -533,6 +533,7 @@ AUTH_BASIC, AUTH_NTLM, AUTH_DIGEST, + AUTH_NEGOTIATE, AUTH_BROKEN /* known type, but broken data */ } auth_type_t; Index: squid/src/auth/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/src/auth/Makefile.am,v retrieving revision 1.2.40.1 retrieving revision 1.2.40.1.2.1 diff -u -r1.2.40.1 -r1.2.40.1.2.1 --- squid/src/auth/Makefile.am 27 Oct 2002 10:46:15 -0000 1.2.40.1 +++ squid/src/auth/Makefile.am 8 Oct 2005 09:13:11 -0000 1.2.40.1.2.1 @@ -4,15 +4,16 @@ # AUTOMAKE_OPTIONS = subdir-objects -DIST_SUBDIRS = basic digest ntlm +DIST_SUBDIRS = basic digest ntlm negotiate SUBDIRS = @AUTH_MODULES@ -EXTRA_LIBRARIES = libbasic.a libdigest.a libntlm.a +EXTRA_LIBRARIES = libbasic.a libdigest.a libntlm.a libnegotiate.a noinst_LIBRARIES = @AUTH_LIBS@ libbasic_a_SOURCES = basic/auth_basic.c basic/auth_basic.h libdigest_a_SOURCES = digest/auth_digest.c digest/auth_digest.h libntlm_a_SOURCES = ntlm/auth_ntlm.c ntlm/auth_ntlm.h +libnegotiate_a_SOURCES = negotiate/auth_negotiate.c negotiate/auth_negotiate.h if ENABLE_WIN32SPECIFIC INCLUDES = -I. -I$(top_srcdir)/port/win32/include -I$(top_srcdir)/include \ Index: squid/src/auth/ntlm/auth_ntlm.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/auth/ntlm/auth_ntlm.c,v retrieving revision 1.18.2.1.4.24 retrieving revision 1.18.2.1.4.24.2.1 diff -u -r1.18.2.1.4.24 -r1.18.2.1.4.24.2.1 --- squid/src/auth/ntlm/auth_ntlm.c 21 Sep 2005 08:39:52 -0000 1.18.2.1.4.24 +++ squid/src/auth/ntlm/auth_ntlm.c 8 Oct 2005 09:13:11 -0000 1.18.2.1.4.24.2.1 @@ -53,7 +53,6 @@ /* NTLM Scheme */ static HLPSCB authenticateNTLMHandleReply; -static HLPSCB authenticateNTLMHandleplaceholder; static AUTHSACTIVE authenticateNTLMActive; static AUTHSAUTHED authNTLMAuthenticated; static AUTHSAUTHUSER authenticateNTLMAuthenticateUser; @@ -66,7 +65,6 @@ static AUTHSFREECONFIG authNTLMFreeConfig; static AUTHSINIT authNTLMInit; static AUTHSONCLOSEC authenticateNTLMOnCloseConnection; -static AUTHSCONNLASTHEADER NTLMLastHeader; static AUTHSUSERNAME authenticateNTLMUsername; static AUTHSREQFREE authNTLMAURequestFree; static AUTHSPARSE authNTLMParse; @@ -74,24 +72,16 @@ static AUTHSSTATS authenticateNTLMStats; static AUTHSSHUTDOWN authNTLMDone; -/* helper callbacks to handle per server state data */ -static HLPSAVAIL authenticateNTLMHelperServerAvailable; -static HLPSRESET authenticateNTLMHelperServerReset; - static statefulhelper *ntlmauthenticators = NULL; CBDATA_TYPE(authenticateStateData); static int authntlm_initialised = 0; -static MemPool *ntlm_helper_state_pool = NULL; static MemPool *ntlm_user_pool = NULL; static MemPool *ntlm_request_pool = NULL; -static MemPool *ntlm_challenge_pool = NULL; static auth_ntlm_config *ntlmConfig = NULL; -static hash_table *ntlm_challenge_cache = NULL; - static void authenticateNTLMReleaseServer(ntlm_request_t * ntlm_request); /* * @@ -111,11 +101,6 @@ if (ntlmauthenticators) helperStatefulFree(ntlmauthenticators); ntlmauthenticators = NULL; - if (ntlm_helper_state_pool) { - assert(memPoolInUseCount(ntlm_helper_state_pool) == 0); - memPoolDestroy(ntlm_helper_state_pool); - ntlm_helper_state_pool = NULL; - } if (ntlm_request_pool) { assert(memPoolInUseCount(ntlm_request_pool) == 0); memPoolDestroy(ntlm_request_pool); @@ -138,8 +123,8 @@ assert(ntlmConfig == scheme->scheme_data); if (ntlmConfig->authenticate) wordlistDestroy(&ntlmConfig->authenticate); - xfree(ntlmConfig); - ntlmConfig = NULL; + safe_free(ntlmConfig); + scheme->scheme_data = NULL; } static void @@ -147,17 +132,15 @@ { auth_ntlm_config *config = scheme->scheme_data; wordlist *list = config->authenticate; - storeAppendPrintf(entry, "%s %s", name, "ntlm"); + storeAppendPrintf(entry, "%s %s program", name, "ntlm"); while (list != NULL) { storeAppendPrintf(entry, " %s", list->key); list = list->next; } - storeAppendPrintf(entry, "\n%s %s children %d\n%s %s max_challenge_reuses %d\n%s %s max_challenge_lifetime %d seconds\n%s %s use_ntlm_negotiate %s\n", - name, "ntlm", config->authenticateChildren, - name, "ntlm", config->challengeuses, - name, "ntlm", (int) config->challengelifetime, - name, "ntlm", config->use_ntlm_negotiate ? "on" : "off"); - + storeAppendPrintf(entry, "\n"); + storeAppendPrintf(entry, "%s %s children %d\n", name, "ntlm", config->authenticateChildren); + storeAppendPrintf(entry, "%s %s keep_alive %s\n", name, "ntlm", config->keep_alive ? "on" : "off"); + storeAppendPrintf(entry, "%s %s use_ntlm_negotiate %s\n", name, "ntlm", config->use_ntlm_negotiate ? "on" : "off"); } static void @@ -170,9 +153,6 @@ memset(scheme->scheme_data, 0, sizeof(auth_ntlm_config)); ntlmConfig = scheme->scheme_data; ntlmConfig->authenticateChildren = 5; - ntlmConfig->challengeuses = 0; - ntlmConfig->challengelifetime = 60; - ntlmConfig->use_ntlm_negotiate = 0; } ntlmConfig = scheme->scheme_data; if (strcasecmp(param_str, "program") == 0) { @@ -182,10 +162,8 @@ requirePathnameExists("authparam ntlm program", ntlmConfig->authenticate->key); } else if (strcasecmp(param_str, "children") == 0) { parse_int(&ntlmConfig->authenticateChildren); - } else if (strcasecmp(param_str, "max_challenge_reuses") == 0) { - parse_int(&ntlmConfig->challengeuses); - } else if (strcasecmp(param_str, "max_challenge_lifetime") == 0) { - parse_time_t(&ntlmConfig->challengelifetime); + } else if (strcasecmp(param_str, "keep_alive") == 0) { + parse_onoff(&ntlmConfig->keep_alive); } else if (strcasecmp(param_str, "use_ntlm_negotiate") == 0) { parse_onoff(&ntlmConfig->use_ntlm_negotiate); } else { @@ -216,7 +194,6 @@ 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 @@ -237,21 +214,6 @@ debug(28, 1) ("pipeline prefetching incompatile with NTLM authentication. Disabling pipeline_prefetch\n"); Config.onoff.pipeline_prefetch = 0; } - if (ntlmConfig->use_ntlm_negotiate && ntlmConfig->challengeuses > 0) { - debug(28, 1) ("challenge reuses incompatible with use_ntlm_negotiate. Disabling challenge reuse\n"); - ntlmConfig->challengeuses = 0; - } - /* Native Windows helpers don't allow Challenge reuse even when - * running without NTLM NEGOTIATE packet support. - */ -#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) - if (ntlmConfig->challengeuses > 0) { - debug(28, 1) ("challenge reuses incompatible with Windows platform. Disabling challenge reuse\n"); - ntlmConfig->challengeuses = 0; - } -#endif - if (!ntlm_helper_state_pool) - ntlm_helper_state_pool = memPoolCreate("NTLM Helper State data", sizeof(ntlm_helper_state_t)); if (!ntlm_user_pool) ntlm_user_pool = memPoolCreate("NTLM Scheme User Data", sizeof(ntlm_user_t)); if (!ntlm_request_pool) @@ -259,27 +221,10 @@ authntlm_initialised = 1; if (ntlmauthenticators == NULL) ntlmauthenticators = helperStatefulCreate("ntlmauthenticator"); - if (ntlmConfig->challengeuses) { - if (!ntlm_challenge_cache) - ntlm_challenge_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string); - if (!ntlm_challenge_pool) - ntlm_challenge_pool = memPoolCreate("NTLM Challenge Cache", sizeof(ntlm_challenge_hash_pointer)); - } ntlmauthenticators->cmdline = ntlmConfig->authenticate; ntlmauthenticators->n_to_start = ntlmConfig->authenticateChildren; ntlmauthenticators->ipc_type = IPC_TCP_SOCKET; - ntlmauthenticators->datapool = ntlm_helper_state_pool; - ntlmauthenticators->IsAvailable = authenticateNTLMHelperServerAvailable; - ntlmauthenticators->Reset = authenticateNTLMHelperServerReset; helperStatefulOpenServers(ntlmauthenticators); - /* - * 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) { cachemgrRegister("ntlmauthenticator", "NTLM User Authenticator Stats", @@ -300,12 +245,20 @@ static int authNTLMConfigured() { - if ((ntlmConfig != NULL) && (ntlmConfig->authenticate != NULL) && (ntlmConfig->authenticateChildren != 0) && (ntlmConfig->challengeuses > -1) && (ntlmConfig->challengelifetime > -1)) { - debug(29, 9) ("authNTLMConfigured: returning configured\n"); - return 1; + if (ntlmConfig == NULL) { + debug(29, 9) ("authNTLMConfigured: not configured\n"); + return 0; } - debug(29, 9) ("authNTLMConfigured: returning unconfigured\n"); - return 0; + if (ntlmConfig->authenticate == NULL) { + debug(29, 9) ("authNTLMConfigured: no helper\n"); + return 0; + } + if (ntlmConfig->authenticateChildren == 0) { + debug(29, 9) ("authNTLMConfigured: no helper children\n"); + return 0; + } + debug(29, 9) ("authNTLMConfigured: returning configured\n"); + return 1; } /* NTLM Scheme */ @@ -315,19 +268,23 @@ { ntlm_request_t *ntlm_request = auth_user_request->scheme_data; /* null auth_user is checked for by authenticateDirection */ + if (ntlm_request->waiting || ntlm_request->client_blob) + return -1; /* Need helper response to continue */ switch (ntlm_request->auth_state) { case AUTHENTICATE_STATE_NONE: /* no progress at all. */ debug(29, 1) ("authenticateNTLMDirection: called before NTLM Authenticate!. Report a bug to squid-dev. au %p\n", auth_user_request); - /* fall thru */ - case AUTHENTICATE_STATE_FAILED: return -2; - case AUTHENTICATE_STATE_NEGOTIATE: /* send to helper */ - case AUTHENTICATE_STATE_RESPONSE: /*send to helper */ - return -1; - case AUTHENTICATE_STATE_CHALLENGE: /* send to client */ + case AUTHENTICATE_STATE_NEGOTIATE: /* send to client */ + assert(ntlm_request->server_blob); return 1; + case AUTHENTICATE_STATE_FAILED: + return -2; + case AUTHENTICATE_STATE_FINISHED: /* do nothing.. */ case AUTHENTICATE_STATE_DONE: /* do nothing.. */ return 0; + case AUTHENTICATE_STATE_INITIAL: + debug(29, 1) ("authenticateNTLMDirection: Unexpected AUTHENTICATE_STATE_INITIAL\n"); + return -2; } return -2; } @@ -343,41 +300,45 @@ ntlm_request_t *ntlm_request; if (!request->flags.proxy_keepalive) return; - if (ntlmConfig->authenticate) { - /* New request, no user details */ - if (auth_user_request == NULL) { - debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type); - httpHeaderPutStrf(&rep->header, type, "NTLM"); + if (!ntlmConfig->authenticate) + return; + /* New request, no user details */ + if (auth_user_request == NULL) { + debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type); + httpHeaderPutStrf(&rep->header, type, "NTLM"); + if (!ntlmConfig->keep_alive) { /* drop the connection */ httpHeaderDelByName(&rep->header, "keep-alive"); - /* NTLM has problems if the initial connection is not dropped - * I haven't checked the RFC compliance of this hack - RBCollins */ request->flags.proxy_keepalive = 0; - } else { - ntlm_request = auth_user_request->scheme_data; - switch (ntlm_request->auth_state) { - case AUTHENTICATE_STATE_NONE: - case AUTHENTICATE_STATE_FAILED: - debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type); - httpHeaderPutStrf(&rep->header, type, "NTLM"); - /* drop the connection */ - httpHeaderDelByName(&rep->header, "keep-alive"); - /* NTLM has problems if the initial connection is not dropped - * I haven't checked the RFC compliance of this hack - RBCollins */ - request->flags.proxy_keepalive = 0; - break; - case AUTHENTICATE_STATE_CHALLENGE: - /* we are 'waiting' for a response */ - /* pass the challenge to the client */ - debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM %s'\n", type, ntlm_request->authchallenge); - httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->authchallenge); - request->flags.must_keepalive = 1; - break; - default: - debug(29, 0) ("authenticateNTLMFixErrorHeader: state %d.\n", ntlm_request->auth_state); - fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n"); - } } + return; + } + ntlm_request = auth_user_request->scheme_data; + switch (ntlm_request->auth_state) { + case AUTHENTICATE_STATE_NONE: + case AUTHENTICATE_STATE_FAILED: + debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type); + httpHeaderPutStrf(&rep->header, type, "NTLM"); + /* drop the connection */ + httpHeaderDelByName(&rep->header, "keep-alive"); + request->flags.proxy_keepalive = 0; + break; + case AUTHENTICATE_STATE_NEGOTIATE: + /* we are 'waiting' for a response from the client */ + /* pass the blob to the client */ + debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM %s'\n", type, ntlm_request->server_blob); + httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->server_blob); + safe_free(ntlm_request->server_blob); + request->flags.must_keepalive = 1; + break; + case AUTHENTICATE_STATE_FINISHED: + /* Special case when authentication finished, but not allowed by ACL */ + debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n", type); + httpHeaderPutStrf(&rep->header, type, "NTLM"); + break; + default: + debug(29, 0) ("authenticateNTLMFixErrorHeader: state %d.\n", ntlm_request->auth_state); + fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n"); } } @@ -386,12 +347,8 @@ { if (!ntlm_request) return; - if (ntlm_request->ntlmnegotiate) - xfree(ntlm_request->ntlmnegotiate); - if (ntlm_request->authchallenge) - xfree(ntlm_request->authchallenge); - if (ntlm_request->ntlmauthenticate) - xfree(ntlm_request->ntlmauthenticate); + safe_free(ntlm_request->server_blob); + safe_free(ntlm_request->client_blob); if (ntlm_request->authserver != NULL) { debug(29, 9) ("authenticateNTLMRequestFree: releasing server '%p'\n", ntlm_request->authserver); authenticateNTLMReleaseServer(ntlm_request); @@ -407,20 +364,13 @@ auth_user_request->scheme_data = NULL; } -static void authenticateNTLMChallengeCacheRemoveLink(ntlm_challenge_hash_pointer * challenge_hash); - static void authenticateNTLMFreeUser(auth_user_t * auth_user) { ntlm_user_t *ntlm_user = auth_user->scheme_data; debug(29, 5) ("authenticateNTLMFreeUser: Clearing NTLM scheme data\n"); - if (ntlm_user->username) - xfree(ntlm_user->username); - /* were they linked in by one or more proxy-authenticate headers */ - while (ntlm_user->challenge_list.head) { - authenticateNTLMChallengeCacheRemoveLink(ntlm_user->challenge_list.head->data); - } + safe_free(ntlm_user->username); memPoolFree(ntlm_user_pool, ntlm_user); auth_user->scheme_data = NULL; } @@ -430,60 +380,23 @@ authenticateNTLMReleaseServer(ntlm_request_t * ntlm_request) { helper_stateful_server *server = ntlm_request->authserver; + if (!server) + return; debug(29, 9) ("authenticateNTLMReleaseServer: releasing server '%p'\n", server); ntlm_request->authserver = NULL; - if (!ntlmConfig->challengeuses) { - ntlm_helper_state_t *helperstate = helperStatefulServerGetData(server); - helperstate->starve = 1; - } - helperStatefulReleaseServer(server); -} - -/* clear the NTLM helper of being reserved for future requests */ -static void -authenticateNTLMResetServer(ntlm_request_t * ntlm_request) -{ - helper_stateful_server *server = ntlm_request->authserver; - ntlm_helper_state_t *helperstate = helperStatefulServerGetData(server); - debug(29, 9) ("authenticateNTLMResetServer: releasing server '%p'\n", server); - ntlm_request->authserver = NULL; - helperstate->starve = 1; helperStatefulReleaseServer(server); } static void -authenticateNTLMHandleplaceholder(void *data, void *srv, char *reply) -{ - authenticateStateData *r = data; - int valid; - /* we should only be called for placeholder requests - which have no reply string */ - assert(reply == NULL); - assert(r->auth_user_request); - /* standard callback stuff */ - valid = cbdataValid(r->data); - if (!valid) { - debug(29, 2) ("AuthenticateNTLMHandlePlacheholder: invalid callback data.\n"); - helperStatefulReleaseServer(srv); - return; - } - /* call authenticateNTLMStart to retry this request */ - debug(29, 9) ("authenticateNTLMHandleplaceholder: calling authenticateNTLMStart\n"); - helperStatefulReleaseServer(srv); - authenticateNTLMStart(r->auth_user_request, r->handler, r->data); - cbdataUnlock(r->data); - authenticateStateFree(r); -} - -static void authenticateNTLMHandleReply(void *data, void *srv, char *reply) { authenticateStateData *r = data; - ntlm_helper_state_t *helperstate; int valid; auth_user_request_t *auth_user_request; auth_user_t *auth_user; ntlm_user_t *ntlm_user; ntlm_request_t *ntlm_request; + char *blob; debug(29, 9) ("authenticateNTLMHandleReply: Helper: '%p' {%s}\n", srv, reply ? reply : ""); valid = cbdataValid(r->data); if (!valid) { @@ -499,107 +412,63 @@ */ fatal("authenticateNTLMHandleReply: called with no result string\n"); } - assert(r->auth_user_request != NULL); - assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM); + auth_user_request = r->auth_user_request; + ntlm_request = auth_user_request->scheme_data; assert(ntlm_request != NULL); - if (!ntlm_request->authserver) + + assert(ntlm_request->waiting); + ntlm_request->waiting = 0; + safe_free(ntlm_request->client_blob); + + auth_user = auth_user_request->auth_user; + assert(auth_user != NULL); + assert(auth_user->auth_type == AUTH_NEGOTIATE); + ntlm_user = auth_user_request->auth_user->scheme_data; + + if (ntlm_request->authserver == NULL) ntlm_request->authserver = srv; else assert(ntlm_request->authserver == srv); /* seperate out the useful data */ - if (strncasecmp(reply, "TT ", 3) == 0) { - reply += 3; - /* we have been given a Challenge */ - /* we should check we weren't given an empty challenge */ - /* copy the challenge to the state data */ - helperstate = helperStatefulServerGetData(srv); - if (helperstate == NULL) - fatal("lost NTLM helper state! quitting\n"); - helperstate->challenge = xstrdup(reply); - helperstate->renewed = squid_curtime; - /* and we satisfy the request that happended on the refresh boundary */ - /* note this code is now in two places FIXME */ - assert(ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE); - ntlm_request->authchallenge = xstrdup(reply); - helperstate->challengeuses = 1; - } else if (strncasecmp(reply, "AF ", 3) == 0) { + blob = strchr(reply, ' '); + + if (strncasecmp(reply, "TT ", 3) == 0 && blob != NULL) { + /* we have been given a blob to send to the client */ + safe_free(ntlm_request->server_blob); + ntlm_request->server_blob = xstrdup(blob); + ntlm_request->auth_state = AUTHENTICATE_STATE_NEGOTIATE; + safe_free(auth_user_request->message); + auth_user_request->message = xstrdup("Authenication in progress"); + debug(29, 4) ("authenticateNTLMHandleReply: Need to challenge the client with a server blob '%s'\n", blob); + } else if (strncasecmp(reply, "AF ", 3) == 0 && blob != NULL) { /* we're finished, release the helper */ - reply += 3; - auth_user = auth_user_request->auth_user; - ntlm_user = auth_user_request->auth_user->scheme_data; - assert(ntlm_user != NULL); - /* we only expect OK when finishing the handshake */ - assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE); - ntlm_user->username = xstrdup(reply); -#ifdef NTLM_FAIL_OPEN - } else if (strncasecmp(reply, "LD ", 3) == 0) { - /* This is a variant of BH, which rather than deny access - * allows the user through. The helper is starved and then refreshed - * via YR, all pending authentications are likely to fail also. - * It is meant for those helpers which occasionally fail for - * no reason at all (casus belli, NTLMSSP helper on NT domain, - * failing about 1 auth out of 1k. - * The code is a merge from the BH case with snippets of the AF - * case */ - /* AF code: mark user as authenticated */ - reply += 3; - auth_user = auth_user_request->auth_user; - ntlm_user = auth_user_request->auth_user->scheme_data; - assert(ntlm_user != NULL); - /* we only expect LD when finishing the handshake */ - assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE); - ntlm_user->username = xstrdup(reply); - /* BH code: mark helper as broken */ - authenticateNTLMResetServer(ntlm_request); - debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply); -#endif - } else if (strncasecmp(reply, "NA ", 3) == 0) { - /* todo: action of Negotiate state on error */ - ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED; - authenticateNTLMResetServer(ntlm_request); - debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply); - reply += 3; + safe_free(ntlm_user->username); + ntlm_user->username = xstrdup(blob); safe_free(auth_user_request->message); - if (*reply) - auth_user_request->message = xstrdup(reply); + auth_user_request->message = xstrdup("Login successful"); + debug(29, 4) ("authenticateNTLMHandleReply: Successfully validated user via NTLM. Username '%s'\n", blob); + authenticateNTLMReleaseServer(ntlm_request); + ntlm_request->auth_state = AUTHENTICATE_STATE_FINISHED; + } else if (strncasecmp(reply, "NA ", 3) == 0 && blob != NULL) { + safe_free(auth_user_request->message); + auth_user_request->message = xstrdup(blob); + ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED; + authenticateNTLMReleaseServer(ntlm_request); + debug(29, 4) ("authenticateNTLMHandleReply: Failed validating user via NTLM. Error returned '%s'\n", blob); } else if (strncasecmp(reply, "BH ", 3) == 0) { /* TODO kick off a refresh process. This can occur after a YR or after * a KK. If after a YR release the helper and resubmit the request via * Authenticate NTLM start. * If after a KK deny the user's request w/ 407 and mark the helper as * Needing YR. */ - assert(r->auth_user_request != NULL); - assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM); - auth_user_request = r->auth_user_request; - auth_user = auth_user_request->auth_user; - assert(auth_user != NULL); - ntlm_user = auth_user->scheme_data; - ntlm_request = auth_user_request->scheme_data; - assert((ntlm_user != NULL) && (ntlm_request != NULL)); - authenticateNTLMResetServer(ntlm_request); - if (ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE) { - /* The helper broke on YR. It automatically - * resets */ - debug(29, 1) ("authenticateNTLMHandleReply: Error obtaining challenge from helper: %p. Error returned '%s'\n", srv, reply); - /* resubmit the request. This helper is currently busy, so we will get - * a different one. Our auth state stays the same */ - authenticateNTLMStart(auth_user_request, r->handler, r->data); - /* don't call the callback */ - cbdataUnlock(r->data); - authenticateStateFree(r); - return; - } else { - /* the helper broke on a KK */ - debug(29, 1) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply); - ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED; - reply += 3; - safe_free(auth_user_request->message); - if (*reply) - auth_user_request->message = xstrdup(reply); - } + auth_user_request->message = xstrdup(reply); + ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED; + safe_free(ntlm_request->server_blob); + authenticateNTLMReleaseServer(ntlm_request); + debug(29, 1) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply); } else { fatalf("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply); } @@ -615,48 +484,11 @@ helperStatefulStats(sentry, ntlmauthenticators); } -/* is a particular challenge still valid ? */ -static int -authenticateNTLMValidChallenge(ntlm_helper_state_t * helperstate) -{ - debug(29, 9) ("authenticateNTLMValidChallenge: Challenge is %s\n", helperstate->challenge ? "Valid" : "Invalid"); - if (helperstate->challenge == NULL) - return 0; - return 1; -} - -/* does our policy call for changing the challenge now? */ -static int -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 - * requests have been satisfied */ - if (!helperstate->renewed) { - /* first use, no challenge has been set. Without this check, it will - * loop forever */ - debug(29, 5) ("authenticateNTLMChangeChallenge_p: first use\n"); - return 0; - } - if (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_p: Challenge exceeded max lifetime by %d seconds\n", (int) (squid_curtime - (helperstate->renewed + ntlmConfig->challengelifetime))); - return 1; - } - debug(29, 9) ("Challenge is to be reused\n"); - return 0; -} - /* send the initial data to a stateful ntlm authenticator module */ static void authenticateNTLMStart(auth_user_request_t * auth_user_request, RH * handler, void *data) { authenticateStateData *r = NULL; - helper_stateful_server *server; - ntlm_helper_state_t *helperstate; char buf[8192]; char *sent_string = NULL; ntlm_user_t *ntlm_user; @@ -671,26 +503,9 @@ assert(ntlm_request); assert(handler); assert(data); - assert(auth_user->auth_type == AUTH_NTLM); + assert(auth_user->auth_type == AUTH_NEGOTIATE); debug(29, 9) ("authenticateNTLMStart: auth state '%d'\n", ntlm_request->auth_state); - switch (ntlm_request->auth_state) { - case AUTHENTICATE_STATE_NEGOTIATE: - sent_string = ntlm_request->ntlmnegotiate; - break; - case AUTHENTICATE_STATE_RESPONSE: - sent_string = ntlm_request->ntlmauthenticate; - assert(ntlm_request->authserver); - debug(29, 9) ("authenticateNTLMStart: Asking NTLMauthenticator '%p'.\n", ntlm_request->authserver); - break; - default: - fatal("Invalid authenticate state for NTLMStart"); - } - - while (xisgraph(*sent_string)) /*trim NTLM */ - sent_string++; - - while (xisspace(*sent_string)) /*trim leading spaces */ - sent_string++; + sent_string = ntlm_request->client_blob; debug(29, 9) ("authenticateNTLMStart: state '%d'\n", ntlm_request->auth_state); debug(29, 9) ("authenticateNTLMStart: '%s'\n", sent_string); @@ -699,120 +514,25 @@ handler(data, NULL); return; } - /* 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) { - case AUTHENTICATE_STATE_NEGOTIATE: - /* - * 1: get a helper server - * 2: does it have a challenge? - * 3: tell it to get a challenge, or give ntlmauthdone the challenge - */ - server = helperStatefulGetServer(ntlmauthenticators); - helperstate = server ? helperStatefulServerGetData(server) : NULL; - if (ntlmConfig->challengeuses) { - while ((server != NULL) && authenticateNTLMChangeChallenge_p(helperstate)) { - /* flag this helper for challenge changing */ - helperstate->starve = 1; - helperStatefulReleaseServer(server); - /* Get another server */ - server = helperStatefulGetServer(ntlmauthenticators); - helperstate = server ? helperStatefulServerGetData(server) : NULL; - } - } - ntlm_request->authserver = server; - /* tell the log what helper we have been given */ - if (server == NULL) - debug(29, 9) ("authenticateNTLMStart: unable to get a ntlm helper... Queuing as a placeholder request.\n"); - else - debug(29, 9) ("authenticateNTLMStart: helper '%p' assigned\n", server); - /* server and valid challenge? */ - if ((server == NULL) || ntlmConfig->challengeuses == 0 || !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; - authenticateAuthUserRequestLock(r->auth_user_request); - if (server == NULL && ntlmConfig->challengeuses) { - helperStatefulSubmit(ntlmauthenticators, NULL, authenticateNTLMHandleplaceholder, r, NULL); - } else { - /* Server with invalid challenge */ - - if (ntlmConfig->use_ntlm_negotiate) { - snprintf(buf, 8192, "YR %s\n", sent_string); - } else { - snprintf(buf, 8192, "YR\n"); - } - helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver); - } - } else { - if (!ntlmConfig->challengeuses) - debug(29, 0) ("authenticateNTLMStart: Reused challenge in server %p even if challenge reuse is disabled!", server); - /* (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 = xstrdup(helperstate->challenge); - handler(data, NULL); - } - - break; - case AUTHENTICATE_STATE_RESPONSE: - r = cbdataAlloc(authenticateStateData); - r->handler = handler; - cbdataLock(data); - r->data = data; - r->auth_user_request = auth_user_request; - authenticateAuthUserRequestLock(r->auth_user_request); + /* Send blob to helper */ + r = cbdataAlloc(authenticateStateData); + r->handler = handler; + cbdataLock(data); + r->data = data; + r->auth_user_request = auth_user_request; + authenticateAuthUserRequestLock(r->auth_user_request); + if (ntlm_request->auth_state == AUTHENTICATE_STATE_INITIAL) { + if (ntlmConfig->use_ntlm_negotiate) + snprintf(buf, 8192, "YR %s\n", sent_string); + else + snprintf(buf, 8192, "YR\n"); + } else { snprintf(buf, 8192, "KK %s\n", sent_string); - helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver); - debug(29, 9) ("authenticateNTLMstart: finished\n"); - break; - default: - fatal("Invalid authenticate state for NTLMStart"); - } -} - -/* callback used by stateful helper routines */ -static int -authenticateNTLMHelperServerAvailable(void *data) -{ - ntlm_helper_state_t *statedata = data; - if (statedata != NULL) { - if (statedata->starve) { - debug(29, 4) ("authenticateNTLMHelperServerAvailable: starving - returning 0\n"); - return 0; - } else { - debug(29, 4) ("authenticateNTLMHelperServerAvailable: not starving - returning 1\n"); - return 1; - } - } - debug(29, 4) ("authenticateNTLMHelperServerAvailable: no state data - returning 0\n"); - return 0; -} - -static void -authenticateNTLMHelperServerReset(void *data) -{ - ntlm_helper_state_t *statedata = data; - if (statedata == NULL) - return; - if (statedata->starve) { - /* we have been starving the helper */ - debug(29, 9) ("authenticateNTLMHelperServerReset: resetting challenge details\n"); - statedata->starve = 0; - statedata->challengeuses = 0; - statedata->renewed = 0; - xfree(statedata->challenge); - statedata->challenge = NULL; - while (statedata->user_list.head) { - authenticateNTLMChallengeCacheRemoveLink(statedata->user_list.head->data); - } } + ntlm_request->waiting = 1; + safe_free(ntlm_request->client_blob); + helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authserver); } /* clear any connection related authentication details */ @@ -850,22 +570,8 @@ return NULL; } -/* NTLMLastHeader: return a pointer to the last header used in authenticating - * the request/conneciton - */ -static 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 - * Auth_user structure. + * Called on the initial request only, to set things up for later processing */ static void @@ -874,7 +580,7 @@ dlink_node *node; assert(auth_user_request->auth_user == NULL); auth_user_request->auth_user = authenticateAuthUserNew("ntlm"); - auth_user_request->auth_user->auth_type = AUTH_NTLM; + auth_user_request->auth_user->auth_type = AUTH_NEGOTIATE; 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)); @@ -883,7 +589,8 @@ node = dlinkNodeNew(); dlinkAdd(auth_user_request, node, &auth_user_request->auth_user->requests); - /* all we have to do is identify that it's NTLM - the helper does the rest */ + /* the helper does the rest, with data collected in + * authenticateNTLMAuthenticateUser */ debug(29, 9) ("authenticateDecodeNTLMAuth: NTLM authentication\n"); return; } @@ -895,47 +602,11 @@ } -/* 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 - */ -static void -authenticateNTLMChallengeCacheAddLink(const char *key, auth_user_t * auth_user, helper_stateful_server * auth_server) -{ - ntlm_challenge_hash_pointer *challenge_hash; - ntlm_user_t *ntlm_user; - ntlm_helper_state_t *helperstate = helperStatefulServerGetData(auth_server); - ntlm_user = auth_user->scheme_data; - /* prevent duplicates */ - if (hash_lookup(ntlm_challenge_cache, key)) - return; - challenge_hash = memPoolAlloc(ntlm_challenge_pool); - challenge_hash->key = xstrdup(key); - challenge_hash->user.auth_user = auth_user; - dlinkAddTail(challenge_hash, &challenge_hash->user.link, &ntlm_user->challenge_list); - challenge_hash->challenge.authserver = auth_server; - dlinkAddTail(challenge_hash, &challenge_hash->challenge.link, &helperstate->user_list); - hash_join(ntlm_challenge_cache, (hash_link *) challenge_hash); -} - -static void -authenticateNTLMChallengeCacheRemoveLink(ntlm_challenge_hash_pointer * challenge_hash) -{ - ntlm_user_t *ntlm_user = challenge_hash->user.auth_user->scheme_data; - ntlm_helper_state_t *helperstate = helperStatefulServerGetData(challenge_hash->challenge.authserver); - hash_remove_link(ntlm_challenge_cache, (hash_link *) challenge_hash); - dlinkDelete(&challenge_hash->user.link, &ntlm_user->challenge_list); - dlinkDelete(&challenge_hash->challenge.link, &helperstate->user_list); - xfree(challenge_hash->key); - memPoolFree(ntlm_challenge_pool, challenge_hash); -} - - static int authNTLMAuthenticated(auth_user_request_t * auth_user_request) { ntlm_request_t *ntlm_request = auth_user_request->scheme_data; - if (ntlm_request->auth_state == AUTHENTICATE_STATE_DONE) + if (ntlm_request->auth_state == AUTHENTICATE_STATE_FINISHED) return 1; debug(29, 9) ("User not fully authenticated.\n"); return 0; @@ -944,19 +615,15 @@ static void authenticateNTLMAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type) { - const char *proxy_auth; + const char *proxy_auth, *blob; auth_user_hash_pointer *usernamehash; - ntlm_challenge_hash_pointer *challenge_hash = NULL; auth_user_t *auth_user; ntlm_request_t *ntlm_request; ntlm_user_t *ntlm_user; - LOCAL_ARRAY(char, ntlmhash, NTLM_CHALLENGE_SZ * 2); - /* get header */ - proxy_auth = httpHeaderGetStr(&request->header, type); auth_user = auth_user_request->auth_user; assert(auth_user); - assert(auth_user->auth_type == AUTH_NTLM); + assert(auth_user->auth_type == AUTH_NEGOTIATE); assert(auth_user->scheme_data != NULL); assert(auth_user_request->scheme_data != NULL); ntlm_user = auth_user->scheme_data; @@ -968,13 +635,33 @@ debug(29, 1) ("authenticateNTLMAuthenticateUser: attempt to perform authentication without a connection!\n"); return; } + if (ntlm_request->waiting) { + debug(29, 1) ("authenticateNTLMAuthenticateUser: waiting for helper reply!\n"); + return; + } + if (ntlm_request->server_blob) { + debug(29, 2) ("authenticateNTLMAuthenticateUser: need to challenge client '%s'!\n", ntlm_request->server_blob); + return; + } + + /* get header */ + proxy_auth = httpHeaderGetStr(&request->header, type); + if (strncasecmp("NTLM ", proxy_auth, 5) != 0) { + fatal("Incorrect scheme in auth header\n"); + /* TODO: more fault tolerance.. reset the auth scheme here */ + } + blob = proxy_auth + 5; + while (xisspace(*blob)) /*trim leading spaces */ + blob++; + switch (ntlm_request->auth_state) { case AUTHENTICATE_STATE_NONE: - /* we've recieved a negotiate request. pass to a helper */ + /* we've recieved a ntlm request. pass to a helper */ debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state ntlm none. %s\n", proxy_auth); - ntlm_request->auth_state = AUTHENTICATE_STATE_NEGOTIATE; - ntlm_request->ntlmnegotiate = xstrdup(proxy_auth); - conn->auth_type = AUTH_NTLM; + ntlm_request->auth_state = AUTHENTICATE_STATE_INITIAL; + safe_free(ntlm_request->client_blob); + ntlm_request->client_blob = xstrdup(blob); + conn->auth_type = AUTH_NEGOTIATE; conn->auth_user_request = auth_user_request; ntlm_request->conn = conn; /* and lock for the connection duration */ @@ -982,68 +669,24 @@ authenticateAuthUserRequestLock(auth_user_request); return; break; - case AUTHENTICATE_STATE_NEGOTIATE: - ntlm_request->auth_state = AUTHENTICATE_STATE_CHALLENGE; - /* We _MUST_ have the auth challenge by now */ - assert(ntlm_request->authchallenge); + case AUTHENTICATE_STATE_INITIAL: + debug(29, 1) ("authenticateNTLMAuthenticateUser: need to ask helper!\n"); return; break; - case AUTHENTICATE_STATE_CHALLENGE: - /* we should have recieved a NTLM challenge. pass it to the same + case AUTHENTICATE_STATE_NEGOTIATE: + /* we should have recieved a blob from the clien. pass it to the same * helper process */ debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state challenge with header %s.\n", proxy_auth); /* do a cache lookup here. If it matches it's a successful ntlm * challenge - release the helper and use the existing auth_user * details. */ - ntlm_request->ntlmauthenticate = xstrdup(proxy_auth); - /* normal case with challenge reuses disabled */ - if (ntlmConfig->challengeuses == 0) { - /* verify with the ntlm helper */ - ntlm_request->auth_state = AUTHENTICATE_STATE_RESPONSE; - return; - } - /* cache entries have authenticateauthheaderchallengestring */ - snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s", - ntlm_request->ntlmauthenticate, - ntlm_request->authchallenge); - /* see if we already know this user's authenticate */ - debug(29, 9) ("aclMatchProxyAuth: cache lookup with key '%s'\n", ntlmhash); - assert(ntlm_challenge_cache != NULL); - challenge_hash = hash_lookup(ntlm_challenge_cache, ntlmhash); - if (!challenge_hash) { /* not in the hash table */ - debug(29, 4) ("authenticateNTLMAuthenticateUser: proxy-auth cache miss.\n"); - ntlm_request->auth_state = AUTHENTICATE_STATE_RESPONSE; - /* verify with the ntlm helper */ - } else { - debug(29, 4) ("authenticateNTLMAuthenticateUser: ntlm proxy-auth cache hit\n"); - /* throw away the temporary entry */ - ntlm_request->authserver_deferred = 0; - authenticateNTLMReleaseServer(ntlm_request); - authenticateAuthUserMerge(auth_user, challenge_hash->user.auth_user); - auth_user = challenge_hash->user.auth_user; - auth_user_request->auth_user = auth_user; - ntlm_request->auth_state = AUTHENTICATE_STATE_DONE; - /* we found one */ - debug(29, 9) ("found matching cache entry\n"); - assert(auth_user->auth_type == AUTH_NTLM); - /* get the existing entries details */ - ntlm_user = auth_user->scheme_data; - debug(29, 9) ("Username to be used is %s\n", ntlm_user->username); - /* on ntlm auth we do not unlock the auth_user until the - * connection is dropped. Thank MS for this quirk */ - auth_user->expiretime = current_time.tv_sec; - } + safe_free(ntlm_request->client_blob); + ntlm_request->client_blob = xstrdup(blob); return; break; - case AUTHENTICATE_STATE_RESPONSE: - /* auth-challenge pair cache miss. We've just got the response from the helper */ - /*add to cache and let them through */ - ntlm_request->auth_state = AUTHENTICATE_STATE_DONE; + case AUTHENTICATE_STATE_FINISHED: /* this connection is authenticated */ - debug(29, 4) ("authenticated\nch %s\nauth %s\nauthuser %s\n", - ntlm_request->authchallenge, - ntlm_request->ntlmauthenticate, - ntlm_user->username); + debug(29, 4) ("authenticated user %s\n", ntlm_user->username); /* see if this is an existing user with a different proxy_auth * string */ usernamehash = hash_lookup(proxy_auth_username_cache, ntlm_user->username); @@ -1062,17 +705,11 @@ /* store user in hash's */ authenticateUserNameCacheAdd(auth_user); } - if (ntlmConfig->challengeuses) { - /* cache entries have authenticateauthheaderchallengestring */ - snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s", - ntlm_request->ntlmauthenticate, - ntlm_request->authchallenge); - authenticateNTLMChallengeCacheAddLink(ntlmhash, auth_user, ntlm_request->authserver); - } /* set these to now because this is either a new login from an * existing user or a new user */ auth_user->expiretime = current_time.tv_sec; authenticateNTLMReleaseServer(ntlm_request); + ntlm_request->auth_state = AUTHENTICATE_STATE_DONE; return; case AUTHENTICATE_STATE_DONE: fatal("authenticateNTLMAuthenticateUser: unexpect auth state DONE! Report a bug to the squid developers.\n"); Index: squid/src/auth/ntlm/auth_ntlm.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/auth/ntlm/auth_ntlm.h,v retrieving revision 1.8.10.4 retrieving revision 1.8.10.4.2.1 diff -u -r1.8.10.4 -r1.8.10.4.2.1 --- squid/src/auth/ntlm/auth_ntlm.h 22 Feb 2005 12:59:28 -0000 1.8.10.4 +++ squid/src/auth/ntlm/auth_ntlm.h 8 Oct 2005 09:13:11 -0000 1.8.10.4.2.1 @@ -10,9 +10,9 @@ typedef enum { AUTHENTICATE_STATE_NONE, + AUTHENTICATE_STATE_INITIAL, AUTHENTICATE_STATE_NEGOTIATE, - AUTHENTICATE_STATE_CHALLENGE, - AUTHENTICATE_STATE_RESPONSE, + AUTHENTICATE_STATE_FINISHED, AUTHENTICATE_STATE_DONE, AUTHENTICATE_STATE_FAILED } auth_state_t; /* connection level auth state */ @@ -27,62 +27,33 @@ struct _ntlm_user { /* what username did this connection get? */ char *username; - dlink_list challenge_list; }; -struct _ntlm_challenge_hash_pointer { - /* first two items must be same as hash_link */ - char *key; - auth_user_hash_pointer *next; - struct { - auth_user_t *auth_user; - dlink_node link; /* other hash entries that point to the same auth_user */ - } user; - struct { - helper_stateful_server *authserver; - dlink_node link; /* other hash entries that point to the same challenge */ - } challenge; -}; - - struct _ntlm_request { - /* what negotiate string did the client use? */ - char *ntlmnegotiate; - /* what challenge did we give the client? */ - char *authchallenge; - /* what authenticate string did we get? */ - char *ntlmauthenticate; - /*we need to store the NTLM server between requests */ + /*we need to store the helper server between requests */ 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; + /* currently waiting for helper response */ + int waiting; /* what connection is this associated with */ ConnStateData *conn; -}; - -struct _ntlm_helper_state_t { - char *challenge; /* the challenge to use with this helper */ - int starve; /* 0= normal operation. 1=don't hand out any more challenges */ - int challengeuses; /* the number of times this challenge has been issued */ - time_t renewed; - dlink_list user_list; /* ntlm_challenge_hash_pointer list referring to this challenge */ + /* our current blob to pass to the client */ + char *server_blob; + /* our current blob to pass to the server */ + char *client_blob; }; /* configuration runtime data */ struct _auth_ntlm_config { int authenticateChildren; - wordlist *authenticate; - int challengeuses; - time_t challengelifetime; + int keep_alive; int use_ntlm_negotiate; + wordlist *authenticate; }; typedef struct _ntlm_user ntlm_user_t; typedef struct _ntlm_request ntlm_request_t; -typedef struct _ntlm_helper_state_t ntlm_helper_state_t; typedef struct _auth_ntlm_config auth_ntlm_config; -typedef struct _ntlm_challenge_hash_pointer ntlm_challenge_hash_pointer; #endif