--------------------- PatchSet 1965 Date: 2005/10/22 18:30:58 Author: hno Branch: negotiate Tag: (none) Log: Import of the Squid-3 Negotiate branch from baz Members: configure.in:1.81->1.81.2.1 src/ACL.h:1.13->1.13.6.1 src/ACLARP.cc:1.13->1.13.6.1 src/ACLChecklist.cc:1.26->1.26.2.1 src/AuthUser.h:1.1->1.1.14.1 src/AuthUserRequest.cc:1.7->1.7.2.1 src/AuthUserRequest.h:1.5->1.5.6.1 src/Makefile.am:1.64->1.64.2.1 src/acl.cc:1.25->1.25.6.1 src/cache_cf.cc:1.55->1.55.2.1 src/cf.data.pre:1.87->1.87.2.1 src/client_side.cc:1.81->1.81.2.1 src/client_side_reply.cc:1.65->1.65.2.1 src/enums.h:1.25->1.25.2.1 src/helper.cc:1.19->1.19.2.1 src/auth/Makefile.am:1.5->1.5.2.1 src/auth/negotiate/auth_negotiate.cc:1.1->1.1.2.1 src/auth/negotiate/auth_negotiate.h:1.1->1.1.2.1 src/auth/negotiate/negotiateScheme.cc:1.1->1.1.2.1 src/auth/negotiate/negotiateScheme.h:1.1->1.1.2.1 src/auth/ntlm/auth_ntlm.cc:1.22->1.22.2.1 src/auth/ntlm/auth_ntlm.h:1.8->1.8.12.1 Index: squid3/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid3/configure.in,v retrieving revision 1.81 retrieving revision 1.81.2.1 diff -u -r1.81 -r1.81.2.1 --- squid3/configure.in 17 Oct 2005 02:13:07 -0000 1.81 +++ squid3/configure.in 22 Oct 2005 18:30:58 -0000 1.81.2.1 @@ -3,7 +3,7 @@ dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.81 2005/10/17 02:13:07 squidadm Exp $ +dnl $Id: configure.in,v 1.81.2.1 2005/10/22 18:30:58 hno Exp $ dnl dnl dnl @@ -13,7 +13,7 @@ AC_CONFIG_AUX_DIR(cfgaux) AM_INIT_AUTOMAKE(squid, 3.0-PRE3-CVS) AM_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.81 $)dnl +AC_REVISION($Revision: 1.81.2.1 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -1249,7 +1249,7 @@ esac ], [ if test -z "$AUTH_MODULES"; then - AUTH_MODULES="basic digest ntlm" + AUTH_MODULES="ntlm basic digest negotiate" fi ]) if test -n "$AUTH_MODULES"; then Index: squid3/src/ACL.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ACL.h,v retrieving revision 1.13 retrieving revision 1.13.6.1 diff -u -r1.13 -r1.13.6.1 --- squid3/src/ACL.h 6 May 2005 02:14:57 -0000 1.13 +++ squid3/src/ACL.h 22 Oct 2005 18:30:58 -0000 1.13.6.1 @@ -1,6 +1,6 @@ /* - * $Id: ACL.h,v 1.13 2005/05/06 02:14:57 squidadm Exp $ + * $Id: ACL.h,v 1.13.6.1 2005/10/22 18:30:58 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -76,7 +76,6 @@ virtual bool requiresRequest() const; virtual bool requiresReply() const; virtual int match(ACLChecklist * checklist) = 0; - virtual wordlist *dumpGeneric() const; virtual wordlist *dump() const = 0; virtual bool empty () const = 0; virtual bool valid () const; Index: squid3/src/ACLARP.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ACLARP.cc,v retrieving revision 1.13 retrieving revision 1.13.6.1 diff -u -r1.13 -r1.13.6.1 --- squid3/src/ACLARP.cc 9 May 2005 02:14:08 -0000 1.13 +++ squid3/src/ACLARP.cc 22 Oct 2005 18:30:58 -0000 1.13.6.1 @@ -1,5 +1,5 @@ /* - * $Id: ACLARP.cc,v 1.13 2005/05/09 02:14:08 squidadm Exp $ + * $Id: ACLARP.cc,v 1.13.6.1 2005/10/22 18:30:58 hno Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -605,7 +605,7 @@ #else - WRITE ME; +#error "ARP type ACL not supported on this operating system." #endif /* Index: squid3/src/ACLChecklist.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ACLChecklist.cc,v retrieving revision 1.26 retrieving revision 1.26.2.1 diff -u -r1.26 -r1.26.2.1 --- squid3/src/ACLChecklist.cc 17 Oct 2005 02:13:08 -0000 1.26 +++ squid3/src/ACLChecklist.cc 22 Oct 2005 18:30:58 -0000 1.26.2.1 @@ -1,5 +1,5 @@ /* - * $Id: ACLChecklist.cc,v 1.26 2005/10/17 02:13:08 squidadm Exp $ + * $Id: ACLChecklist.cc,v 1.26.2.1 2005/10/22 18:30:58 hno Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -61,7 +61,7 @@ } /* get authed here */ - /* Note: this fills in auth_user_request when applicable (auth incomplete)*/ + /* Note: this fills in auth_user_request when applicable */ switch (AuthUserRequest::tryToAuthenticateAndSetAuthUser (&auth_user_request, headertype, request, conn(), src_addr)) { case AUTH_ACL_CANNOT_AUTHENTICATE: @@ -221,6 +221,18 @@ PF *callback_; void *cbdata_; debug(28, 3) ("ACLChecklist::checkCallback: %p answer=%d\n", this, answer); + /* During reconfigure, we can end up not finishing call + * sequences into the auth code */ + + if (auth_user_request) { + /* the checklist lock */ + auth_user_request->unlock(); + /* it might have been connection based */ + assert(conn().getRaw() != NULL); + conn()->auth_user_request = NULL; + conn()->auth_type = AUTH_BROKEN; + auth_user_request = NULL; + } callback_ = callback; callback = NULL; @@ -311,21 +323,6 @@ if (extacl_entry) cbdataReferenceDone(extacl_entry); - /* During reconfigure or if authentication is used in aclCheckFast without - * first being authenticated in http_access we can end up not finishing call - * sequences into the auth code. In such case we must make sure to forget - * the authentication state completely - */ - if (auth_user_request) { - /* the checklist lock */ - auth_user_request->unlock(); - /* it might have been connection based */ - assert(conn().getRaw() != NULL); - conn()->auth_user_request = NULL; - conn()->auth_type = AUTH_BROKEN; - auth_user_request = NULL; - } - if (request) requestUnlink(request); Index: squid3/src/AuthUser.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/AuthUser.h,v retrieving revision 1.1 retrieving revision 1.1.14.1 diff -u -r1.1 -r1.1.14.1 --- squid3/src/AuthUser.h 31 Aug 2004 02:14:26 -0000 1.1 +++ squid3/src/AuthUser.h 22 Oct 2005 18:30:58 -0000 1.1.14.1 @@ -1,6 +1,6 @@ /* - * $Id: AuthUser.h,v 1.1 2004/08/31 02:14:26 squidadm Exp $ + * $Id: AuthUser.h,v 1.1.14.1 2005/10/22 18:30:58 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -62,7 +62,6 @@ * but how many requests will a single username have in parallel? */ dlink_list requests; -public: static void cacheInit (); static void CachedACLsReset(); Index: squid3/src/AuthUserRequest.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/AuthUserRequest.cc,v retrieving revision 1.7 retrieving revision 1.7.2.1 diff -u -r1.7 -r1.7.2.1 --- squid3/src/AuthUserRequest.cc 17 Oct 2005 02:13:08 -0000 1.7 +++ squid3/src/AuthUserRequest.cc 22 Oct 2005 18:30:58 -0000 1.7.2.1 @@ -1,6 +1,6 @@ /* - * $Id: AuthUserRequest.cc,v 1.7 2005/10/17 02:13:08 squidadm Exp $ + * $Id: AuthUserRequest.cc,v 1.7.2.1 2005/10/22 18:30:58 hno Exp $ * * DO NOT MODIFY NEXT 2 LINES: * arch-tag: 6803fde1-d5a2-4c29-9034-1c0c9f650eb4 @@ -449,6 +449,7 @@ */ if (proxy_auth && conn.getRaw() != NULL && conn->auth_user_request && authenticateUserAuthenticated(conn->auth_user_request) && + conn->auth_user_request->connLastHeader() != NULL && strcmp(proxy_auth, conn->auth_user_request->connLastHeader())) { debug(28, 2) ("authenticateAuthenticate: DUPLICATE AUTH - authentication header on already authenticated connection!. AU %p, Current user '%s' proxy_auth %s\n", conn->auth_user_request, conn->auth_user_request->username(), proxy_auth); @@ -636,23 +637,9 @@ if (t && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE && t->lastReply != AUTH_ACL_HELPER) { - if (!*auth_user_request) { + if (!*auth_user_request) *auth_user_request = t; - (*auth_user_request)->lock() - - ; - //TODO: check if needed. If there's a leak, it is not - } - - if (!request->auth_user_request) { - request->auth_user_request=t; - - request->auth_user_request->lock() - - ; - } - return t->lastReply; } @@ -765,16 +752,15 @@ AuthUserRequest::lock() { - debug(29, 9) ("AuthUserRequest::lock: auth_user request '%p'.\n", this); - assert(this != NULL); + debug(29, 9) ("AuthUserRequest::lock: auth_user request '%p' (%ld references).\n", this, (long int) references); + assert(this); ++references; - debug(29, 9) ("AuthUserRequest::lock: auth_user request '%p' now at '%ld'.\n", this, (long int) references); } void AuthUserRequest::unlock() { - debug(29, 9) ("AuthUserRequest::unlock: auth_user request '%p'.\n", this); + debug(29, 9) ("AuthUserRequest::unlock: auth_user request '%p' (%ld references) .\n", this, (long int) references); assert(this != NULL); if (references > 0) { @@ -783,11 +769,11 @@ debug(29, 1) ("Attempt to lower Auth User request %p refcount below 0!\n", this); } - debug(29, 9) ("AuthUserRequest::unlock: auth_user_request '%p' now at '%ld'.\n", this, (long int) references); - - if (references == 0) + if (references == 0) { + debug(29, 9) ("AuthUserRequest::unlock: deleting auth_user_request '%p'.\n", this); /* not locked anymore */ delete this; + } } AuthScheme * Index: squid3/src/AuthUserRequest.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/AuthUserRequest.h,v retrieving revision 1.5 retrieving revision 1.5.6.1 diff -u -r1.5 -r1.5.6.1 --- squid3/src/AuthUserRequest.h 6 May 2005 02:14:58 -0000 1.5 +++ squid3/src/AuthUserRequest.h 22 Oct 2005 18:30:58 -0000 1.5.6.1 @@ -1,6 +1,6 @@ /* - * $Id: AuthUserRequest.h,v 1.5 2005/05/06 02:14:58 squidadm Exp $ + * $Id: AuthUserRequest.h,v 1.5.6.1 2005/10/22 18:30:58 hno Exp $ * * DO NOT MODIFY NEXT 2 LINES: * arch-tag: 674533af-8b21-4641-b71a-74c4639072a0 @@ -70,7 +70,6 @@ virtual void addHeader(HttpReply * rep, int accel); virtual void addTrailer(HttpReply * rep, int accel); virtual void onConnectionClose(ConnStateData *); - virtual const char *connLastHeader(); /* template method */ virtual void module_start(RH *, void *) = 0; virtual AuthUser *user() {return _auth_user;} @@ -79,8 +78,6 @@ virtual void user (AuthUser *aUser) {_auth_user=aUser;} -public: - static auth_acl_t tryToAuthenticateAndSetAuthUser(auth_user_request_t **, http_hdr_type, HttpRequest *, ConnStateData::Pointer, struct IN_ADDR); static void addReplyAuthHeader(HttpReply * rep, auth_user_request_t * auth_user_request, HttpRequest * request, int accelerated, int internal); @@ -96,18 +93,17 @@ void setDenyMessage (char const *); char const * getDenyMessage (); - size_t refCount() const; - void lock () - - ; + void lock (); void unlock (); char const *username() const; AuthScheme *scheme() const; + virtual const char * connLastHeader(); + private: static auth_acl_t authenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData::Pointer conn, struct IN_ADDR src_addr); Index: squid3/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Makefile.am,v retrieving revision 1.64 retrieving revision 1.64.2.1 diff -u -r1.64 -r1.64.2.1 --- squid3/src/Makefile.am 17 Oct 2005 02:13:08 -0000 1.64 +++ squid3/src/Makefile.am 22 Oct 2005 18:30:58 -0000 1.64.2.1 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.64 2005/10/17 02:13:08 squidadm Exp $ +# $Id: Makefile.am,v 1.64.2.1 2005/10/22 18:30:58 hno Exp $ # # Uncomment and customize the following to suit your needs: # @@ -229,7 +229,9 @@ auth/digest/digestScheme.cc \ auth/digest/digestScheme.h \ auth/ntlm/ntlmScheme.cc \ - auth/ntlm/ntlmScheme.h + auth/ntlm/ntlmScheme.h \ + auth/negotiate/negotiateScheme.cc \ + auth/negotiate/negotiateScheme.h EXTRA_squid_SOURCES = \ $(all_FSMODULES) \ Index: squid3/src/acl.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/acl.cc,v retrieving revision 1.25 retrieving revision 1.25.6.1 diff -u -r1.25 -r1.25.6.1 --- squid3/src/acl.cc 6 May 2005 02:14:58 -0000 1.25 +++ squid3/src/acl.cc 22 Oct 2005 18:30:58 -0000 1.25.6.1 @@ -1,5 +1,5 @@ /* - * $Id: acl.cc,v 1.25 2005/05/06 02:14:58 squidadm Exp $ + * $Id: acl.cc,v 1.25.6.1 2005/10/22 18:30:58 hno Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -56,11 +56,13 @@ ACL::FindByName(const char *name) { ACL *a; + debug(28, 9) ("ACL::FindByName '%s'\n",name); for (a = Config.aclList; a; a = a->next) if (!strcasecmp(a->name, name)) return a; + debug(28,9) ("ACL::FindByName found no match\n"); return NULL; } @@ -173,20 +175,29 @@ acl_deny_info_list *A = NULL; acl_name_list *L = NULL; + debug(28,9)("aclGetDenyInfoPage: got called for %s\n",name); + A = *head; - if (NULL == *head) /* empty list */ + if (NULL == *head) { /* empty list */ + debug(28,9)("aclGetDenyInfoPage: called for an empty list\n"); return ERR_NONE; + } while (A) { L = A->acl_list; - if (NULL == L) /* empty list should never happen, but in case */ + if (NULL == L) { /* empty list should never happen, but in case */ + debug(28,3)("aclGetDenyInfoPage: " + "WARNING, unexpected codepath taken\n"); continue; + } while (L) { - if (!strcmp(name, L->name)) + if (!strcmp(name, L->name)) { + debug(28,8)("aclGetDenyInfoPage: match on %s\n",name); return A->err_page_id; + } L = L->next; } @@ -194,6 +205,7 @@ A = A->next; } + debug(28,8)("aclGetDenyInfoPage: no match\n"); return ERR_NONE; } @@ -201,14 +213,18 @@ int aclIsProxyAuth(const char *name) { + debug(28,5)("aclIsProxyAuth: called for %s\n",name); if (NULL == name) return false; ACL *a; - if ((a = ACL::FindByName(name))) + if ((a = ACL::FindByName(name))) { + debug(28,5)("aclIsProxyAuth: returning %d\n",a->isProxyAuth()); return a->isProxyAuth(); + } + debug(28,3)("aclIsProxyAuth: WARNING, called for nonexistent ACL\n"); return false; } @@ -240,7 +256,7 @@ /* first expect a page name */ if ((t = strtok(NULL, w_space)) == NULL) { - debug(28, 0) ("%s line %d: %s\n", + debug(28, 0) ("aclParseDenyInfoLine: %s line %d: %s\n", cfg_filename, config_lineno, config_input_line); debug(28, 0) ("aclParseDenyInfoLine: missing 'error page' parameter.\n"); return; @@ -261,7 +277,7 @@ } if (A->acl_list == NULL) { - debug(28, 0) ("%s line %d: %s\n", + debug(28, 0) ("aclParseDenyInfoLine: %s line %d: %s\n", cfg_filename, config_lineno, config_input_line); debug(28, 0) ("aclParseDenyInfoLine: deny_info line contains no ACL's, skipping\n"); memFree(A, MEM_ACL_DENY_INFO_LIST); @@ -285,7 +301,7 @@ /* first expect either 'allow' or 'deny' */ if ((t = strtok(NULL, w_space)) == NULL) { - debug(28, 0) ("%s line %d: %s\n", + debug(28, 0) ("aclParseAccessLine: %s line %d: %s\n", cfg_filename, config_lineno, config_input_line); debug(28, 0) ("aclParseAccessLine: missing 'allow' or 'deny'.\n"); return; @@ -298,7 +314,7 @@ else if (!strcmp(t, "deny")) A->allow = ACCESS_DENIED; else { - debug(28, 0) ("%s line %d: %s\n", + debug(28, 0) ("aclParseAccessLine: %s line %d: %s\n", cfg_filename, config_lineno, config_input_line); debug(28, 0) ("aclParseAccessLine: expecting 'allow' or 'deny', got '%s'.\n", t); delete A; @@ -388,8 +404,9 @@ * checked we check it and cache the result. This function is a template * method to support caching of multiple acl types. * Note that caching of time based acl's is not - * wise in long lived caches (i.e. the auth_user proxy match cache. + * wise in long lived caches (i.e. the auth_user proxy match cache) * RBC + * TODO: does a dlink_list perform well enough? Kinkie */ int ACL::cacheMatchAcl(dlink_list * cache, ACLChecklist *checklist) @@ -402,7 +419,7 @@ auth_match = (acl_proxy_auth_match_cache *)link->data; if (auth_match->acl_data == this) { - debug(28, 4) ("ACL::cacheMatchAcl: cache hit on acl '%p'\n", this); + debug(28, 4) ("ACL::cacheMatchAcl: cache hit on acl '%s' (%p)\n", name, this); return auth_match->matchrv; } @@ -414,6 +431,7 @@ auth_match->matchrv = matchForCache (checklist); auth_match->acl_data = this; dlinkAddTail(auth_match, &auth_match->link, cache); + debug(28,4)("ACL::cacheMatchAcl: miss for '%s'. Adding result %d\n",name,auth_match->matchrv); return auth_match->matchrv; } @@ -424,6 +442,7 @@ dlink_node *link, *tmplink; link = cache->head; + debug(28,8)("aclCacheMatchFlush called for cache %p\n",cache); while (link) { auth_match = (acl_proxy_auth_match_cache *)link->data; tmplink = link; @@ -448,20 +467,25 @@ int ACL::checklistMatches(ACLChecklist *checklist) { + int rv; if (NULL == checklist->request && requiresRequest()) { - debug(28, 1) ("WARNING: '%s' ACL is used but there is no" - " HTTP request -- not matching.\n", name); + debug(28, 1) ( "ACL::checklistMatches " + "WARNING: '%s' ACL is used but there is no" + " HTTP request -- not matching.\n", name); return 0; } if (NULL == checklist->reply && requiresReply()) { - debug(28, 1) ("WARNING: '%s' ACL is used but there is no" - " HTTP reply -- not matching.\n", name); + debug(28, 1) ( "ACL::checklistMatches " + "WARNING: '%s' ACL is used but there is no" + " HTTP reply -- not matching.\n", name); return 0; } - debug(28, 3) ("aclMatchAcl: checking '%s'\n", cfgline); - return match(checklist); + debug(28, 3) ("ACL::checklistMatches: checking '%s'\n", name); + rv= match(checklist); + debug(28,3) ("ACL::ChecklistMatches: result for '%s' is %d\n",name,rv); + return rv; } bool @@ -473,9 +497,11 @@ op ? null_string : "!", _acl->name); if (_acl->checklistMatches(checklist) != op) { + debug(28,4)("ACLList::matches: result is false\n"); return false; } + debug(28,4)("ACLList::matches: result is true\n"); return true; } @@ -489,6 +515,8 @@ { ACL *next = NULL; + debug(28,8)("aclDestroyACLs: invoked\n"); + for (ACL *a = *head; a; a = next) { next = a->next; delete a; @@ -499,7 +527,7 @@ ACL::~ACL() { - debug(28, 3) ("aclDestroyAcls: '%s'\n", cfgline); + debug(28, 3) ("ACL::~ACL: '%s'\n", cfgline); safe_free(cfgline); } @@ -507,6 +535,7 @@ aclDestroyAclList(acl_list ** head) { acl_list *l; + debug(28,8)("aclDestroyAclList: invoked\n"); for (l = *head; l; l = *head) { *head = l->next; @@ -542,6 +571,8 @@ acl_name_list *l = NULL; acl_name_list *l_next = NULL; + debug(28,8)("aclDestroyDenyInfoList: invoked\n"); + for (a = *list; a; a = a_next) { for (l = a->acl_list; l; l = l_next) { l_next = l->next; @@ -556,13 +587,6 @@ *list = NULL; } -wordlist * -ACL::dumpGeneric () const -{ - debug(28, 3) ("ACL::dumpGeneric: %s type %s\n", name, typeString()); - return dump(); -} - /* * This function traverses all ACL elements referenced * by an access list (presumably 'http_access'). If @@ -583,18 +607,24 @@ acl_access const *a = this; acl_list *b; + debug(28,6)("acl_access::containsPURGE: invoked for '%s'\n",cfgline); for (; a; a = a->next) { for (b = a->aclList; b; b = b->next) { ACLStrategised *tempAcl = dynamic_cast *>(b->_acl); - if (!tempAcl) + if (!tempAcl) { + debug(28,7)("acl_access::containsPURGE: can't create tempAcl\n"); continue; + } - if (tempAcl->match(METHOD_PURGE)) + if (tempAcl->match(METHOD_PURGE)) { + debug(28,6)("acl_access::containsPURGE: returning true\n"); return true; + } } } + debug(28,6)("acl_access::containsPURGE: returning false\n"); return false; } @@ -630,10 +660,14 @@ bool ACL::Prototype::Registered(char const *aType) { + debug(28,7)("ACL::Prototype::Registered: invoked for type %s\n",aType); for (iterator i = Registry->begin(); i != Registry->end(); ++i) - if (!strcmp (aType, (*i)->typeString)) + if (!strcmp (aType, (*i)->typeString)) { + debug(28,7)("ACL::Prototype::Registered: yes\n"); return true; + } + debug(28,7)("ACL::Prototype::Registered: no\n"); return false; } @@ -661,10 +695,12 @@ ACL * ACL::Prototype::Factory (char const *typeToClone) { + debug(28,4)("ACL::Prototype::Factory: cloning an object for type '%s'\n",typeToClone); for (iterator i = Registry->begin(); i != Registry->end(); ++i) if (!strcmp (typeToClone, (*i)->typeString)) return (*i)->prototype->clone(); + debug(28,4)("ACL::Prototype::Factory: cloning failed, no type '%s' available\n",typeToClone); return NULL; } Index: squid3/src/cache_cf.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/cache_cf.cc,v retrieving revision 1.55 retrieving revision 1.55.2.1 diff -u -r1.55 -r1.55.2.1 --- squid3/src/cache_cf.cc 3 Oct 2005 02:12:59 -0000 1.55 +++ squid3/src/cache_cf.cc 22 Oct 2005 18:30:58 -0000 1.55.2.1 @@ -1,6 +1,6 @@ /* - * $Id: cache_cf.cc,v 1.55 2005/10/03 02:12:59 squidadm Exp $ + * $Id: cache_cf.cc,v 1.55.2.1 2005/10/22 18:30:58 hno Exp $ * * DEBUG: section 3 Configuration File Parsing * AUTHOR: Harvest Derived @@ -813,7 +813,7 @@ name, ae->name, ae->typeString()); - v = w = ae->dumpGeneric(); + v = w = ae->dump(); while (v != NULL) { debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key); Index: squid3/src/cf.data.pre =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/cf.data.pre,v retrieving revision 1.87 retrieving revision 1.87.2.1 diff -u -r1.87 -r1.87.2.1 --- squid3/src/cf.data.pre 17 Oct 2005 02:13:09 -0000 1.87 +++ squid3/src/cf.data.pre 22 Oct 2005 18:30:58 -0000 1.87.2.1 @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.87 2005/10/17 02:13:09 squidadm Exp $ +# $Id: cf.data.pre,v 1.87.2.1 2005/10/22 18:30:58 hno Exp $ # # # SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -1887,32 +1887,43 @@ 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 means use the challenge only once. (disable challenge - caching) See max_ntlm_challenge_lifetime for more information. - 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 + === Options for configuring the NEGOTIATE auth-scheme follow === + + "program" cmdline + Specify the command for the external Negotiate authenticator. + This protocol is used in Microsoft Active-Directory enabled setups with + the Microsoft Internet Explorer or Mozilla Firefox browsers. + Its main purpose is to exchange credentials with the Squid proxy + using the Kerberos mechanisms. + If you use a Negotiate authenticator, make sure you have at least one acl + of type proxy_auth active. By default, the ntlm authenticator_program + is not used. + The only supported program for this role is the ntlm_auth + program distributed as part of Samba, version 3 or later. + + auth_param ntlm program @DEFAULT_PREFIX@/bin/ntlm_auth --helper-protocol=gss-spnego + + "children" numberofchildren + The number of authenticator processes to spawn (no default). + If you start too few Squid will have to wait for them to + process a backlog of credential verifications, slowing it + down. When crendential verifications are done via a (slow) + network you are likely to need lots of authenticator + processes. + auth_param ntlm children 5 NOCOMMENT_START #Recommended minimum configuration: +#auth_param ntlm program +#auth_param ntlm children 5 +#auth_param negotiate program +#auth_param negotiate children 5 #auth_param digest program #auth_param digest children 5 #auth_param digest realm Squid proxy-caching web server #auth_param digest nonce_garbage_interval 5 minutes #auth_param digest nonce_max_duration 30 minutes #auth_param digest nonce_max_count 50 -#auth_param ntlm program -#auth_param ntlm children 5 -#auth_param ntlm max_challenge_reuses 0 -#auth_param ntlm max_challenge_lifetime 2 minutes #auth_param basic program auth_param basic children 5 auth_param basic realm Squid proxy-caching web server Index: squid3/src/client_side.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/client_side.cc,v retrieving revision 1.81 retrieving revision 1.81.2.1 diff -u -r1.81 -r1.81.2.1 --- squid3/src/client_side.cc 18 Sep 2005 02:12:40 -0000 1.81 +++ squid3/src/client_side.cc 22 Oct 2005 18:30:58 -0000 1.81.2.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side.cc,v 1.81 2005/09/18 02:12:40 squidadm Exp $ + * $Id: client_side.cc,v 1.81.2.1 2005/10/22 18:30:58 hno Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -598,8 +598,11 @@ assert(areAllContextsForThisConnection()); freeAllContexts(); - if (auth_user_request != NULL) + if (auth_user_request != NULL) { + debug(33,4)("ConnStateData::close: freeing auth_user_request '%p' (this is '%p')\n", + auth_user_request,this); auth_user_request->onConnectionClose(this); + } } bool Index: squid3/src/client_side_reply.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/client_side_reply.cc,v retrieving revision 1.65 retrieving revision 1.65.2.1 diff -u -r1.65 -r1.65.2.1 --- squid3/src/client_side_reply.cc 16 Sep 2005 02:12:42 -0000 1.65 +++ squid3/src/client_side_reply.cc 22 Oct 2005 18:30:58 -0000 1.65.2.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side_reply.cc,v 1.65 2005/09/16 02:12:42 squidadm Exp $ + * $Id: client_side_reply.cc,v 1.65.2.1 2005/10/22 18:30:58 hno Exp $ * * DEBUG: section 88 Client-side Reply Routines * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c) @@ -1833,11 +1833,7 @@ acl_size_t *l = Config.ReplyBodySize; ACLChecklist *ch; - if (http->logType == LOG_TCP_DENIED) - return; - ch = clientAclChecklistCreate(NULL, http); - ch->reply = reply; for (l = Config.ReplyBodySize; l; l = l -> next) { Index: squid3/src/enums.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/enums.h,v retrieving revision 1.25 retrieving revision 1.25.2.1 diff -u -r1.25 -r1.25.2.1 --- squid3/src/enums.h 29 Aug 2005 02:13:04 -0000 1.25 +++ squid3/src/enums.h 22 Oct 2005 18:30:59 -0000 1.25.2.1 @@ -1,6 +1,6 @@ /* - * $Id: enums.h,v 1.25 2005/08/29 02:13:04 squidadm Exp $ + * $Id: enums.h,v 1.25.2.1 2005/10/22 18:30:59 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -511,6 +511,7 @@ AUTH_BASIC, AUTH_NTLM, AUTH_DIGEST, + AUTH_NEGOTIATE, AUTH_BROKEN /* known type, but broken data */ } auth_type_t; Index: squid3/src/helper.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/helper.cc,v retrieving revision 1.19 retrieving revision 1.19.2.1 diff -u -r1.19 -r1.19.2.1 --- squid3/src/helper.cc 18 Sep 2005 02:12:40 -0000 1.19 +++ squid3/src/helper.cc 22 Oct 2005 18:30:59 -0000 1.19.2.1 @@ -1,6 +1,6 @@ /* - * $Id: helper.cc,v 1.19 2005/09/18 02:12:40 squidadm Exp $ + * $Id: helper.cc,v 1.19.2.1 2005/10/22 18:30:59 hno Exp $ * * DEBUG: section 84 Helper process maintenance * AUTHOR: Harvest Derived? @@ -935,6 +935,8 @@ char *msg = srv->rbuf; int i = 0; debug(84, 3) ("helperHandleRead: end of reply found\n"); + if (t > srv->rbuf && t[-1] == '\r') + t[-1] = '\0'; *t++ = '\0'; if (hlp->concurrency) { @@ -1029,6 +1031,8 @@ if ((t = strchr(srv->rbuf, '\n'))) { /* end of reply found */ debug(84, 3) ("helperStatefulHandleRead: end of reply found\n"); + if (t > srv->rbuf && t[-1] == '\r') + t[-1] = '\0'; *t = '\0'; if (cbdataReferenceValid(r->data)) { Index: squid3/src/auth/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/auth/Makefile.am,v retrieving revision 1.5 retrieving revision 1.5.2.1 diff -u -r1.5 -r1.5.2.1 --- squid3/src/auth/Makefile.am 21 Aug 2005 02:13:14 -0000 1.5 +++ squid3/src/auth/Makefile.am 22 Oct 2005 18:30:59 -0000 1.5.2.1 @@ -1,6 +1,6 @@ # Makefile for authentication modules in the Squid Object Cache server # -# $Id: Makefile.am,v 1.5 2005/08/21 02:13:14 squidadm Exp $ +# $Id: Makefile.am,v 1.5.2.1 2005/10/22 18:30:59 hno Exp $ # AUTOMAKE_OPTIONS = subdir-objects AM_CFLAGS = @SQUID_CFLAGS@ @@ -9,12 +9,13 @@ ##DIST_SUBDIRS = basic digest ntlm ##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.cc basic/auth_basic.h libdigest_a_SOURCES = digest/auth_digest.cc digest/auth_digest.h libntlm_a_SOURCES = ntlm/auth_ntlm.cc ntlm/auth_ntlm.h +libnegotiate_a_SOURCES = negotiate/auth_negotiate.cc negotiate/auth_negotiate.h negotiate/negotiateScheme.cc negotiate/negotiateScheme.h INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_srcdir)/src --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/src/auth/negotiate/auth_negotiate.cc Wed Feb 14 13:35:24 2007 @@ -0,0 +1,735 @@ + +/* + * $Id: auth_negotiate.cc,v 1.1.2.1 2005/10/22 18:30:59 hno Exp $ + * + * DEBUG: section 29 Negotiate Authenticator + * AUTHOR: Robert Collins, Henrik Nordstrom, Francesco Chemolli + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +/* The functions in this file handle authentication. + * They DO NOT perform access control or auditing. + * See acl.c for access control and client_side.c for auditing */ + + +#include "squid.h" +#include "auth_negotiate.h" +#include "authenticate.h" +#include "Store.h" +#include "client_side.h" +#include "HttpReply.h" +#include "HttpRequest.h" +/* TODO remove this include */ +#include "negotiateScheme.h" + +static void +authenticateNegotiateReleaseServer(auth_user_request_t * auth_user_request); + + +static void +authenticateStateFree(authenticateStateData * r) +{ + cbdataFree(r); +} + +/* Negotiate Scheme */ +static HLPSCB authenticateNegotiateHandleReply; +static AUTHSSTATS authenticateNegotiateStats; + +static statefulhelper *negotiateauthenticators = NULL; + +CBDATA_TYPE(authenticateStateData); + +static int authnegotiate_initialised = 0; + +//static MemAllocatorProxy *negotiate_user_hash_pool = NULL; + +static auth_negotiate_config negotiateConfig; + +static hash_table *proxy_auth_cache = NULL; + +/* + * + * Private Functions + * + */ + +/* move to negotiateScheme.cc */ +void +negotiateScheme::done() +{ + /* TODO: this should be a Config call. */ + debug(29, 2) ("negotiateScheme::done: shutting down Negotiate authentication.\n"); + + if (negotiateauthenticators) + helperStatefulShutdown(negotiateauthenticators); + + authnegotiate_initialised = 0; + + if (!shutting_down) + return; + + if (negotiateauthenticators) + helperStatefulFree(negotiateauthenticators); + + negotiateauthenticators = NULL; + + debug(29, 2) ("negotiateScheme::done: Negotiate authentication Shutdown.\n"); +} + +/* free any allocated configuration details */ +void +AuthNegotiateConfig::done() +{ + if (authenticate) + wordlistDestroy(&authenticate); +} + +void +AuthNegotiateConfig::dump(StoreEntry * entry, const char *name, AuthConfig * scheme) +{ + wordlist *list = authenticate; + storeAppendPrintf(entry, "%s %s", name, "negotiate"); + + while (list != NULL) { + storeAppendPrintf(entry, " %s", list->key); + list = list->next; + } + + storeAppendPrintf(entry, "\n%s negotiate children %d\n", + name, authenticateChildren); + +} + +AuthNegotiateConfig::AuthNegotiateConfig() : authenticateChildren(5) +{ } + +void +AuthNegotiateConfig::parse(AuthConfig * scheme, int n_configured, char *param_str) +{ + if (strcasecmp(param_str, "program") == 0) { + if (authenticate) + wordlistDestroy(&authenticate); + + parse_wordlist(&authenticate); + + requirePathnameExists("authparam negotiate program", authenticate->key); + } else if (strcasecmp(param_str, "children") == 0) { + parse_int(&authenticateChildren); + } else { + debug(28, 0) ("AuthNegotiateConfig::parse: unrecognised negotiate auth scheme parameter '%s'\n", param_str); + } + + /* + * disable client side request pipelining. There is a race with + * Negotiate when the client sends a second request on an Negotiate + * connection before the authenticate challenge is sent. With + * this patch, the client may fail to authenticate, but squid's + * state will be preserved. Caveats: this should be a post-parse + * test, but that can wait for the modular parser to be integrated. + */ + if (authenticate) + Config.onoff.pipeline_prefetch = 0; +} + +const char * +AuthNegotiateConfig::type() const +{ + return negotiateScheme::GetInstance().type(); +} + +/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the + * config file */ +void +AuthNegotiateConfig::init(AuthConfig * scheme) +{ + static unsigned char negotiate_was_already_initialised = 0; + + if (authenticate) { +#if PLACEHOLDER + if (!negotiate_user_hash_pool) + negotiate_user_hash_pool = new MemAllocatorProxy("Negotiate Header Hash Data", sizeof(struct ProxyAuthCachePointer)); +#endif + + authnegotiate_initialised = 1; + + if (negotiateauthenticators == NULL) + negotiateauthenticators = helperStatefulCreate("negotiateauthenticator"); + + if (!proxy_auth_cache) + proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string); + + assert(proxy_auth_cache); + + negotiateauthenticators->cmdline = authenticate; + + negotiateauthenticators->n_to_start = authenticateChildren; + + negotiateauthenticators->ipc_type = IPC_STREAM; + + helperStatefulOpenServers(negotiateauthenticators); + + if (!negotiate_was_already_initialised) { + cachemgrRegister("negotiateauthenticator", + "Negotiate User Authenticator Stats", + authenticateNegotiateStats, 0, 1); + negotiate_was_already_initialised++; + } + + CBDATA_INIT_TYPE(authenticateStateData); + } +} + +bool +AuthNegotiateConfig::active() const +{ + return authnegotiate_initialised == 1; +} + +bool +AuthNegotiateConfig::configured() const +{ + if ((authenticate != NULL) && (authenticateChildren != 0)) { + debug(29, 9) ("AuthNegotiateConfig::configured: returning configured\n"); + return true; + } + + debug(29, 9) ("AuthNegotiateConfig::configured: returning unconfigured\n"); + return false; +} + +/* Negotiate Scheme */ +/* See AuthUserRequest.cc::authenticateDirection for return values */ +int +AuthNegotiateUserRequest::module_direction() +{ + /* null auth_user is checked for by authenticateDirection */ + + if (waiting || client_blob) + return -1; /* need helper response to continue */ + switch (auth_state) { + + /* no progress at all. */ + + case AUTHENTICATE_STATE_NONE: + debug(29, 1) ("AuthNegotiateUserRequest::direction: called before Negotiate Authenticate for request %p!. Report a bug to squid-dev.\n",this); + return -2; /* error */ + + case AUTHENTICATE_STATE_FAILED: + return -2; /* error */ + + + case AUTHENTICATE_STATE_IN_PROGRESS: + assert(server_blob); + return 1; /* send to client */ + + case AUTHENTICATE_STATE_FINISHED: + return 0; /* do nothing */ + + case AUTHENTICATE_STATE_DONE: + return 0; /* do nothing */ + + case AUTHENTICATE_STATE_INITIAL: + debug(29, 1) ("AuthNegotiateUserRequest::direction: Unexpected AUTHENTICATE_STATE_INITIAL\n"); + return -2; + } + + return -2; +} + +void +AuthNegotiateConfig::fixHeader(auth_user_request_t *auth_user_request, HttpReply *rep, http_hdr_type type, HttpRequest * request) +{ + AuthNegotiateUserRequest *negotiate_request; + + if (!authenticate) + return; + + /* New request, no user details */ + if (auth_user_request == NULL) { + debug(29, 9) ("AuthNegotiateConfig::fixHeader: Sending type:%d header: 'NEGOTIATE'\n", type); + httpHeaderPutStrf(&rep->header, type, "NEGOTIATE"); +#if PROBABLY_NOT_NEEDED + /* drop the connection */ + httpHeaderDelByName(&rep->header, "keep-alive"); + /* Negotiate 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; +#endif /* PROBABLY_NOT_NEEDED */ + } else { + negotiate_request = dynamic_cast(auth_user_request); + + switch (negotiate_request->auth_state) { + + case AUTHENTICATE_STATE_FAILED: + /* here it makes sense to drop the connection, as auth is + * tied to it, even if MAYBE the client could handle it - Kinkie */ + httpHeaderDelByName(&rep->header, "keep-alive"); + request->flags.proxy_keepalive = 0; + /* fall through */ + + case AUTHENTICATE_STATE_FINISHED: + /* Special case: authentication finished OK but disallowed by ACL. + * Need to start over to give the client another chance. + */ + /* fall through */ + + case AUTHENTICATE_STATE_NONE: + /* semantic change: do not drop the connection. + * 2.5 implementation used to keep it open - Kinkie */ + debug(29, 9) ("AuthNegotiateConfig::fixHeader: Sending type:%d header: 'NEGOTIATE'\n", type); + httpHeaderPutStrf(&rep->header, type, "NEGOTIATE"); + break; + + case AUTHENTICATE_STATE_IN_PROGRESS: + /* we're waiting for a response from the client. Pass it the blob */ + debug(29, 9) ("AuthNegotiateConfig::fixHeader: Sending type:%d header: 'Negotiate %s'\n", type, negotiate_request->server_blob); + httpHeaderPutStrf(&rep->header, type, "NEGOTIATE %s", negotiate_request->server_blob); + safe_free(negotiate_request->server_blob); + break; + + + default: + debug(29, 0) ("AuthNegotiateConfig::fixHeader: state %d.\n", negotiate_request->auth_state); + fatal("unexpected state in AuthenticateNegotiateFixErrorHeader.\n"); + } + } +} + +NegotiateUser::~NegotiateUser() +{ + debug(29, 5) ("NegotiateUser::~NegotiateUser: doing nothing to clearNEGOTIATE scheme data for '%p'\n",this); +} + +static stateful_helper_callback_t +authenticateNegotiateHandleReply(void *data, void *lastserver, char *reply) +{ + authenticateStateData *r = static_cast(data); + + int valid; + stateful_helper_callback_t result = S_HELPER_UNKNOWN; + char *blob, *arg = NULL; + + auth_user_request_t *auth_user_request; + AuthUser *auth_user; + NegotiateUser *negotiate_user; + AuthNegotiateUserRequest *negotiate_request; + + debug(29, 8) ("authenticateNegotiateHandleReply: helper: '%p' sent us '%s'\n", lastserver, reply ? reply : ""); + valid = cbdataReferenceValid(data); + + if (!valid) { + debug(29, 1) ("authenticateNegotiateHandleReply: invalid callback data. Releasing helper '%p'.\n", lastserver); + cbdataReferenceDone(r->data); + authenticateStateFree(r); + debug(29, 9) ("authenticateNegotiateHandleReply: telling stateful helper : %d\n", S_HELPER_RELEASE); + return S_HELPER_RELEASE; + } + + if (!reply) { + /* + * TODO: this occurs when a helper crashes. We should clean + * up that helpers resources and queued requests. + */ + fatal("authenticateNegotiateHandleReply: called with no result string\n"); + } + + auth_user_request = r->auth_user_request; + assert(auth_user_request != NULL); + negotiate_request = dynamic_cast(auth_user_request); + + assert(negotiate_request->waiting); + negotiate_request->waiting = 0; + safe_free(negotiate_request->client_blob); + + auth_user = negotiate_request->user(); + assert(auth_user != NULL); + assert(auth_user->auth_type == AUTH_NEGOTIATE); + negotiate_user = dynamic_cast(auth_user_request->user()); + + if (negotiate_request->authserver == NULL) + negotiate_request->authserver = static_cast(lastserver); + else + assert(negotiate_request->authserver == lastserver); + + /* seperate out the useful data */ + blob = strchr(reply, ' '); + while (xisspace(*blob)) { // trim leading spaces in blob + blob++; + arg = strchr(blob + 1, ' '); + } + + if (strncasecmp(reply, "TT ", 3) == 0 && blob != NULL) { + /* we have been given a blob to send to the client */ + if (arg) + *arg++ = '\0'; + safe_free(negotiate_request->server_blob); + negotiate_request->server_blob = xstrdup(blob); + negotiate_request->auth_state = AUTHENTICATE_STATE_IN_PROGRESS; + auth_user_request->denyMessage("Authenication in progress"); + debug(29, 4) ("authenticateNegotiateHandleReply: Need to challenge the client with a server blob '%s'\n", blob); + result = S_HELPER_RESERVE; + } else if (strncasecmp(reply, "AF ", 3) == 0 && blob != NULL) { + /* we're finished, release the helper */ + if (arg) + *arg++ = '\0'; + negotiate_user->username(arg); + auth_user_request->denyMessage("Login successful"); + safe_free(negotiate_request->server_blob); + negotiate_request->server_blob = xstrdup(blob); + authenticateNegotiateReleaseServer(negotiate_request); + negotiate_request->auth_state = AUTHENTICATE_STATE_FINISHED; + + result = S_HELPER_RELEASE; + debug(29, 4) ("authenticateNegotiateHandleReply: Successfully validated user via NEGOTIATE. Username '%s'\n", blob); + } else if (strncasecmp(reply, "NA ", 3) == 0 && blob != NULL) { + /* authentication failure (wrong password, etc.) */ + if (arg) + *arg++ = '\0'; + auth_user_request->denyMessage(arg); + negotiate_request->auth_state = AUTHENTICATE_STATE_FAILED; + safe_free(negotiate_request->server_blob); + negotiate_request->server_blob = xstrdup(blob); + authenticateNegotiateReleaseServer(negotiate_request); + result = S_HELPER_RELEASE; + debug(29, 4) ("authenticateNegotiateHandleReply: Failed validating user via NEGOTIATE. 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 NEGOTIATE start. + * If after a KK deny the user's request w/ 407 and mark the helper as + * Needing YR. */ + auth_user_request->denyMessage(blob); + negotiate_request->auth_state = AUTHENTICATE_STATE_FAILED; + safe_free(negotiate_request->server_blob); + authenticateNegotiateReleaseServer(negotiate_request); + result = S_HELPER_RELEASE; + debug(29, 1) ("authenticateNegotiateHandleReply: Error validating user via NEGOTIATE. Error returned '%s'\n", reply); + } else { + /* protocol error */ + fatalf("authenticateNegotiateHandleReply: *** Unsupported helper response ***, '%s'\n", reply); + } + + r->handler(r->data, NULL); + cbdataReferenceDone(r->data); + authenticateStateFree(r); + debug(29, 9) ("authenticateNegotiateHandleReply: telling stateful helper : %d\n", result); + return result; +} + +static void +authenticateNegotiateStats(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "NEGOTIATE Authenticator Statistics:\n"); + helperStatefulStats(sentry, negotiateauthenticators); +} + + +/* send the initial data to a stateful negotiate authenticator module */ +void +AuthNegotiateUserRequest::module_start(RH * handler, void *data) +{ + authenticateStateData *r = NULL; + static char buf[8192]; + negotiate_user_t *negotiate_user; + auth_user_t *auth_user = user(); + + assert(data); + assert(handler); + assert(auth_user); + assert(auth_user->auth_type == AUTH_NEGOTIATE); + + negotiate_user = dynamic_cast(user()); + + debug(29, 8) ("AuthNegotiateUserRequest::module_start: auth state is '%d'\n", auth_state); + + if (negotiateConfig.authenticate == NULL) { + debug(29, 0) ("AuthNegotiateUserRequest::module_start: no NEGOTIATE program specified."); + handler(data, NULL); + return; + } + + r = cbdataAlloc(authenticateStateData); + r->handler = handler; + cbdataReference(data); + r->data = data; + r->auth_user_request = this; + lock(); + if (auth_state == AUTHENTICATE_STATE_INITIAL) { + snprintf(buf, 8192, "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here? + } else { + snprintf(buf, 8192, "KK %s\n", client_blob); + } + waiting = 1; + + safe_free(client_blob); + helperStatefulSubmit(negotiateauthenticators, buf, authenticateNegotiateHandleReply, r, authserver); +} + +/* clear the NEGOTIATE helper of being reserved for future requests */ +static void +authenticateNegotiateReleaseServer(auth_user_request_t * auth_user_request) +{ + AuthNegotiateUserRequest *negotiate_request; + assert(auth_user_request->user()->auth_type == AUTH_NEGOTIATE); + negotiate_request = dynamic_cast< AuthNegotiateUserRequest *>(auth_user_request); + debug(29, 9) ("authenticateNegotiateReleaseServer: releasing server '%p'\n", negotiate_request->authserver); + /* is it possible for the server to be NULL? hno seems to think so. + * Let's see what happens, might segfault in helperStatefulReleaseServer + * if it does. I leave it like this not to cover possibly problematic + * code-paths. Kinkie */ + helperStatefulReleaseServer(negotiate_request->authserver); + negotiate_request->authserver = NULL; +} + +/* clear any connection related authentication details */ +void +AuthNegotiateUserRequest::onConnectionClose(ConnStateData *connection) +{ + assert(connection != NULL); + + debug(29,8)("AuthNegotiateUserRequest::onConnectionClose: closing connection '%p' (this is '%p')\n",connection,this); + if (connection->auth_user_request == NULL) { + debug(29,8)("AuthNegotiateUserRequest::onConnectionClose: no auth_user_request\n"); + return; + } + + if (authserver != NULL) + authenticateNegotiateReleaseServer(this); + + /* unlock the connection based lock */ + debug(29, 9) ("AuthNegotiateUserRequest::onConnectionClose: Unlocking auth_user from the connection '%p'.\n",connection); + + /* This still breaks the abstraction, but is at least read only now. + * If needed, this could be ignored, as the conn deletion will also unlock + * the auth user request. + */ + unlock(); + + connection->auth_user_request = NULL; +} + +/* + * Decode a NEGOTIATE [Proxy-]Auth string, placing the results in the passed + * Auth_user structure. + */ +AuthUserRequest * +AuthNegotiateConfig::decode(char const *proxy_auth) +{ + NegotiateUser *newUser = new NegotiateUser(&negotiateConfig); + AuthNegotiateUserRequest *auth_user_request = new AuthNegotiateUserRequest (); + assert(auth_user_request->user() == NULL); + auth_user_request->user(newUser); + auth_user_request->user()->auth_type = AUTH_NEGOTIATE; + auth_user_request->user()->addRequest(auth_user_request); + + /* all we have to do is identify that it's NEGOTIATE - the helper does the rest */ + debug(29, 9) ("AuthNegotiateConfig::decode: NEGOTIATE authentication\n"); + return auth_user_request; +} + +int +AuthNegotiateUserRequest::authenticated() const +{ + if (auth_state == AUTHENTICATE_STATE_FINISHED) { + debug(29, 9) ("AuthNegotiateUserRequest::authenticated: user authenticated.\n"); + return 1; + } + + debug(29, 9) ("AuthNegotiateUserRequest::authenticated: user not fully authenticated.\n"); + + return 0; +} + +void +AuthNegotiateUserRequest::authenticate(HttpRequest * request, ConnStateData::Pointer conn, http_hdr_type type) +{ + const char *proxy_auth, *blob; + + //ProxyAuthCachePointer *proxy_auth_hash = NULL; + auth_user_hash_pointer *usernamehash; + + /* TODO: rename this!! */ + auth_user_t *local_auth_user; + negotiate_user_t *negotiate_user; + + local_auth_user = user(); + assert(local_auth_user); + assert(local_auth_user->auth_type == AUTH_NEGOTIATE); + negotiate_user = dynamic_cast(local_auth_user); + assert (this); + + /* Check that we are in the client side, where we can generate + * auth challenges */ + + if (conn.getRaw() == NULL) { + auth_state = AUTHENTICATE_STATE_FAILED; + debug(29, 1) ("AuthNegotiateUserRequest::authenticate: attempt to perform authentication without a connection!\n"); + return; + } + + if (waiting) { + debug(29, 1) ("AuthNegotiateUserRequest::authenticate: waiting for helper reply!\n"); + return; + } + + if (server_blob) { + debug(29,2)("AuthNegotiateUserRequest::authenticate: need to challenge client '%s'!\n", server_blob); + return; + } + + /* get header */ + proxy_auth = httpHeaderGetStr(&request->header, type); + + if (strncasecmp("NEGOTIATE ",proxy_auth,5) != 0) { + fatal("AuthNegotiateUserRequest::authenticate: incorrect scheme in auth header\n"); + /* TODO: more fault tolerance.. reset the auth scheme here */ + } + blob = proxy_auth + 10; + + while (xisspace(*blob)) // trim leading spaces in blob + blob++; + + switch (auth_state) { + + case AUTHENTICATE_STATE_NONE: + /* we've recieved a negotiate request. pass to a helper */ + debug(29, 9) ("AuthNegotiateUserRequest::authenticate: auth state negotiate none. Received blob: '%s'\n", proxy_auth); + auth_state = AUTHENTICATE_STATE_INITIAL; + safe_free(client_blob); + client_blob=xstrdup(blob); + conn->auth_type = AUTH_NEGOTIATE; + conn->auth_user_request = this; + conn = conn; + lock(); + return; + break; + + case AUTHENTICATE_STATE_INITIAL: + debug(29,1)("AuthNegotiateUserRequest::authenticate: need to ask helper\n"); + return; + break; + + + case AUTHENTICATE_STATE_IN_PROGRESS: + /* we should have received a blob from the client. Hand it off to + * some helper */ + safe_free(client_blob); + client_blob = xstrdup (blob); + return; + break; + + case AUTHENTICATE_STATE_FINISHED: + /* connection is authenticated */ + debug(29, 4) ("AuthNegotiateUserRequest::authenticate: authenticated user %s\n", negotiate_user->username()); + /* see if this is an existing user with a different proxy_auth + * string */ + usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, negotiate_user->username())); + while (usernamehash && (usernamehash->user()->auth_type != AUTH_NEGOTIATE || strcmp(usernamehash->user()->username(), negotiate_user->username()) != 0)) + usernamehash = static_cast(usernamehash->next); + if (usernamehash) { + /* we can't seamlessly recheck the username due to the + * challenge-response nature of the protocol. + * Just free the temporary auth_user */ + usernamehash->user()->absorb(local_auth_user); + //authenticateAuthUserMerge(local_auth_user, usernamehash->user()); + local_auth_user = usernamehash->user(); + _auth_user = local_auth_user; + } else { + /* store user in hash's */ + local_auth_user->addToNameCache(); + // authenticateUserNameCacheAdd(local_auth_user); + } + /* set these to now because this is either a new login from an + * existing user or a new user */ + local_auth_user->expiretime = current_time.tv_sec; + authenticateNegotiateReleaseServer(this); + auth_state = AUTHENTICATE_STATE_DONE; + return; + break; + + case AUTHENTICATE_STATE_DONE: + fatal("AuthNegotiateUserRequest::authenticate: unexpect auth state DONE! Report a bug to the squid developers.\n"); + break; + + case AUTHENTICATE_STATE_FAILED: + /* we've failed somewhere in authentication */ + debug(29, 9) ("AuthNegotiateUserRequest::authenticate: auth state negotiate failed. %s\n", proxy_auth); + return; + break; + } + + return; +} + +AuthNegotiateUserRequest::AuthNegotiateUserRequest() : + conn(NULL), auth_state(AUTHENTICATE_STATE_NONE), + _theUser(NULL) +{ + waiting=0; + client_blob=0; + server_blob=0; + authserver=NULL; +} + +AuthNegotiateUserRequest::~AuthNegotiateUserRequest() +{ + safe_free(server_blob); + safe_free(client_blob); + + if (authserver != NULL) { + debug(29, 9) ("AuthNegotiateUserRequest::~AuthNegotiateUserRequest: releasing server '%p'\n", authserver); + helperStatefulReleaseServer(authserver); + authserver = NULL; + } +} + +void +NegotiateUser::deleteSelf() const +{ + delete this; +} + +NegotiateUser::NegotiateUser (AuthConfig *config) : AuthUser (config) +{ + proxy_auth_list.head = proxy_auth_list.tail = NULL; +} + +AuthConfig * +negotiateScheme::createConfig() +{ + return &negotiateConfig; +} + +const char * +AuthNegotiateUserRequest::connLastHeader() +{ + return NULL; +} + --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/src/auth/negotiate/auth_negotiate.h Wed Feb 14 13:35:24 2007 @@ -0,0 +1,116 @@ +/* + * auth_negotiate.h + * Internal declarations for the negotiate auth module + */ + +#ifndef __AUTH_NEGOTIATE_H__ +#define __AUTH_NEGOTIATE_H__ +#include "authenticate.h" +#include "AuthUser.h" +#include "AuthUserRequest.h" +#include "AuthConfig.h" + +#define DefaultAuthenticateChildrenMax 32 /* 32 processes */ + +typedef enum { + AUTHENTICATE_STATE_NONE, + AUTHENTICATE_STATE_INITIAL, + AUTHENTICATE_STATE_IN_PROGRESS, + AUTHENTICATE_STATE_FINISHED, + AUTHENTICATE_STATE_DONE, + AUTHENTICATE_STATE_FAILED +} auth_state_t; /* connection level auth state */ + +/* Generic */ + +typedef struct +{ + void *data; + auth_user_request_t *auth_user_request; + RH *handler; +} + +authenticateStateData; + +class NegotiateUser : public AuthUser +{ + +public: + MEMPROXY_CLASS(NegotiateUser); + virtual void deleteSelf() const; + NegotiateUser(AuthConfig *); + ~NegotiateUser(); + dlink_list proxy_auth_list; +}; + +MEMPROXY_CLASS_INLINE(NegotiateUser) + +typedef class NegotiateUser negotiate_user_t; + +class AuthNegotiateUserRequest : public AuthUserRequest +{ + +public: + MEMPROXY_CLASS(AuthNegotiateUserRequest); + + AuthNegotiateUserRequest(); + virtual ~AuthNegotiateUserRequest(); + virtual int authenticated() const; + virtual void authenticate(HttpRequest * request, ConnStateData::Pointer conn, http_hdr_type type); + virtual int module_direction(); + virtual void onConnectionClose(ConnStateData *); + virtual void module_start(RH *, void *); + virtual AuthUser *user() {return _theUser;} + + virtual const AuthUser *user() const {return _theUser;} + + virtual void user (AuthUser *aUser) {_theUser=dynamic_cast(aUser);} + + virtual const char * connLastHeader(); + + /*we need to store the helper server between requests */ + helper_stateful_server *authserver; + /* what connection is this associated with */ + ConnStateData::Pointer conn; + + /* how far through the authentication process are we? */ + auth_state_t auth_state; + + /* our current blob to pass to the client */ + char *server_blob; + /* our current blob to pass to the server */ + char *client_blob; + + /* currently waiting for helper response */ + unsigned char waiting; + +private: + /* the user */ + NegotiateUser * _theUser; +}; + +MEMPROXY_CLASS_INLINE(AuthNegotiateUserRequest) + +/* configuration runtime data */ + +class AuthNegotiateConfig : public AuthConfig +{ + +public: + AuthNegotiateConfig::AuthNegotiateConfig(); + virtual bool active() const; + virtual bool configured() const; + virtual AuthUserRequest *decode(char const *proxy_auth); + virtual void done(); + virtual void dump(StoreEntry *, const char *, AuthConfig *); + virtual void fixHeader(auth_user_request_t *, HttpReply *, http_hdr_type, HttpRequest *); + virtual void init(AuthConfig *); + virtual void parse(AuthConfig *, int, char *); + virtual const char * type() const; + int authenticateChildren; + wordlist *authenticate; +}; + +typedef class AuthNegotiateConfig auth_negotiate_config; + +#endif --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/src/auth/negotiate/negotiateScheme.cc Wed Feb 14 13:35:24 2007 @@ -0,0 +1,53 @@ + +/* + * $Id: negotiateScheme.cc,v 1.1.2.1 2005/10/22 18:30:59 hno Exp $ + * + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "negotiateScheme.h" + +AuthScheme & +negotiateScheme::GetInstance() +{ + return _instance; +} + +negotiateScheme::negotiateScheme() +{ + AddScheme(*this); +} + +char const * +negotiateScheme::type () const +{ + return "negotiate"; +} + +negotiateScheme negotiateScheme::_instance; --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/src/auth/negotiate/negotiateScheme.h Wed Feb 14 13:35:24 2007 @@ -0,0 +1,59 @@ + +/* + * $Id: negotiateScheme.h,v 1.1.2.1 2005/10/22 18:30:59 hno Exp $ + * + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#ifndef SQUID_NEGOTIATESCHEME_H +#define SQUID_NEGOTIATESCHEME_H + +#include "AuthScheme.h" + +class negotiateScheme : public AuthScheme +{ + +public: + static AuthScheme &GetInstance(); + negotiateScheme(); + virtual ~negotiateScheme(){}; + + /* per scheme */ + virtual char const *type () const; + virtual void done(); + virtual AuthConfig *createConfig(); + /* Not implemented */ + negotiateScheme (negotiateScheme const &); + negotiateScheme &operator=(negotiateScheme const &); + +private: + static negotiateScheme _instance; +}; + +#endif /* SQUID_negotiateSCHEME_H */ Index: squid3/src/auth/ntlm/auth_ntlm.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/auth/ntlm/auth_ntlm.cc,v retrieving revision 1.22 retrieving revision 1.22.2.1 diff -u -r1.22 -r1.22.2.1 --- squid3/src/auth/ntlm/auth_ntlm.cc 17 Oct 2005 02:13:09 -0000 1.22 +++ squid3/src/auth/ntlm/auth_ntlm.cc 22 Oct 2005 18:30:59 -0000 1.22.2.1 @@ -1,6 +1,6 @@ /* - * $Id: auth_ntlm.cc,v 1.22 2005/10/17 02:13:09 squidadm Exp $ + * $Id: auth_ntlm.cc,v 1.22.2.1 2005/10/22 18:30:59 hno Exp $ * * DEBUG: section 29 NTLM Authenticator * AUTHOR: Robert Collins @@ -49,30 +49,26 @@ #include "ntlmScheme.h" static void +authenticateNTLMReleaseServer(auth_user_request_t * auth_user_request); + + +static void authenticateStateFree(authenticateStateData * r) { - r->auth_user_request->unlock(); - r->auth_user_request = NULL; cbdataFree(r); } /* NTLM Scheme */ static HLPSCB authenticateNTLMHandleReply; -static HLPSCB authenticateNTLMHandleplaceholder; static AUTHSSTATS authenticateNTLMStats; -/* helper callbacks to handle per server state data */ -static HLPSAVAIL authenticateNTLMHelperServerAvailable; -static HLPSONEQ authenticateNTLMHelperServerOnEmpty; - static statefulhelper *ntlmauthenticators = NULL; CBDATA_TYPE(authenticateStateData); static int authntlm_initialised = 0; -static MemAllocatorProxy *ntlm_helper_state_pool = NULL; -static MemAllocatorProxy *ntlm_user_hash_pool = NULL; +//static MemAllocatorProxy *ntlm_user_hash_pool = NULL; static auth_ntlm_config ntlmConfig; @@ -89,7 +85,7 @@ ntlmScheme::done() { /* TODO: this should be a Config call. */ - debug(29, 2) ("authNTLMDone: shutting down NTLM authentication.\n"); + debug(29, 2) ("ntlmScheme::done: shutting down NTLM authentication.\n"); if (ntlmauthenticators) helperStatefulShutdown(ntlmauthenticators); @@ -104,21 +100,7 @@ ntlmauthenticators = NULL; -#if DEBUGSHUTDOWN - - if (ntlm_helper_state_pool) { - delete ntlm_helper_state_pool; - ntlm_helper_state_pool = NULL; - } - - /* Removed for some reason.. - if (ntlm_user_pool) { - delete ntlm_user_pool;ntlm_user_pool = NULL; - } - */ - -#endif - debug(29, 2) ("authNTLMDone: NTLM authentication Shutdown.\n"); + debug(29, 2) ("ntlmScheme::done: NTLM authentication Shutdown.\n"); } /* free any allocated configuration details */ @@ -140,10 +122,8 @@ 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", - name, "ntlm", authenticateChildren, - name, "ntlm", challengeuses, - name, "ntlm", (int) challengelifetime); + storeAppendPrintf(entry, "\n%s ntlm children %d\n", + name, authenticateChildren); } @@ -151,8 +131,6 @@ { /* TODO Move into initialisation list */ authenticateChildren = 5; - challengeuses = 0; - challengelifetime = 60; } void @@ -167,12 +145,8 @@ requirePathnameExists("authparam ntlm program", authenticate->key); } else if (strcasecmp(param_str, "children") == 0) { parse_int(&authenticateChildren); - } else if (strcasecmp(param_str, "max_challenge_reuses") == 0) { - parse_int(&challengeuses); - } else if (strcasecmp(param_str, "max_challenge_lifetime") == 0) { - parse_time_t(&challengelifetime); } else { - debug(28, 0) ("unrecognised ntlm auth scheme parameter '%s'\n", param_str); + debug(28, 0) ("AuthNTLMConfig::parse: unrecognised ntlm auth scheme parameter '%s'\n", param_str); } /* @@ -198,15 +172,13 @@ void AuthNTLMConfig::init(AuthConfig * scheme) { - static int ntlminit = 0; + static unsigned char ntlm_was_already_initialised = 0; if (authenticate) { - if (!ntlm_helper_state_pool) - ntlm_helper_state_pool = new MemAllocatorProxy("NTLM Helper State data", sizeof(ntlm_helper_state_t)); - +#if PLACEHOLDER if (!ntlm_user_hash_pool) - ntlm_user_hash_pool = new MemAllocatorProxy("NTLM Header Hash Data", sizeof(struct ProxyAuthCachePointer)); +#endif authntlm_initialised = 1; @@ -224,27 +196,13 @@ ntlmauthenticators->ipc_type = IPC_STREAM; - ntlmauthenticators->datapool = ntlm_helper_state_pool; - - ntlmauthenticators->IsAvailable = authenticateNTLMHelperServerAvailable; - - ntlmauthenticators->OnEmptyQueue = authenticateNTLMHelperServerOnEmpty; - 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) { + if (!ntlm_was_already_initialised) { cachemgrRegister("ntlmauthenticator", "NTLM User Authenticator Stats", authenticateNTLMStats, 0, 1); - ntlminit++; + ntlm_was_already_initialised++; } CBDATA_INIT_TYPE(authenticateStateData); @@ -260,50 +218,49 @@ bool AuthNTLMConfig::configured() const { - if ((authenticate != NULL) && (authenticateChildren != 0) && (challengeuses > -1) && (challengelifetime > -1)) { - debug(29, 9) ("authNTLMConfigured: returning configured\n"); + if ((authenticate != NULL) && (authenticateChildren != 0)) { + debug(29, 9) ("AuthNTLMConfig::configured: returning configured\n"); return true; } - debug(29, 9) ("authNTLMConfigured: returning unconfigured\n"); + debug(29, 9) ("AuthNTLMConfig::configured: returning unconfigured\n"); return false; } /* NTLM Scheme */ +/* See AuthUserRequest.cc::authenticateDirection for return values */ int AuthNTLMUserRequest::module_direction() { /* null auth_user is checked for by authenticateDirection */ + if (waiting || client_blob) + return -1; /* need helper response to continue */ switch (auth_state) { /* no progress at all. */ case AUTHENTICATE_STATE_NONE: - debug(29, 1) ("AuthNTLMUserRequest::direction: called before NTLM Authenticate!. Report a bug to squid-dev.\n"); - /* fall thru */ + debug(29, 1) ("AuthNTLMUserRequest::direction: called before NTLM Authenticate for request %p!. Report a bug to squid-dev.\n",this); + return -2; /* error */ case AUTHENTICATE_STATE_FAILED: - return -2; + return -2; /* error */ - /* send to helper */ case AUTHENTICATE_STATE_NEGOTIATE: + assert(server_blob); + return 1; /* send to client */ - /*send to helper */ - - case AUTHENTICATE_STATE_RESPONSE: - return -1; - - /* send to client */ - - case AUTHENTICATE_STATE_CHALLENGE: - return 1; - - /* do nothing.. */ + case AUTHENTICATE_STATE_FINISHED: + return 0; /* do nothing */ case AUTHENTICATE_STATE_DONE: - return 0; + return 0; /* do nothing */ + + case AUTHENTICATE_STATE_INITIAL: + debug(29, 1) ("AuthNTLMUserRequest::direction: Unexpected AUTHENTICATE_STATE_INITIAL\n"); + return -2; } return -2; @@ -869,45 +826,40 @@ AuthNTLMUserRequest *ntlm_request; assert(auth_user_request->user()->auth_type == AUTH_NTLM); ntlm_request = dynamic_cast< AuthNTLMUserRequest *>(auth_user_request); - assert (ntlm_request); debug(29, 9) ("authenticateNTLMReleaseServer: releasing server '%p'\n", ntlm_request->authserver); + /* is it possible for the server to be NULL? hno seems to think so. + * Let's see what happens, might segfault in helperStatefulReleaseServer + * if it does. I leave it like this not to cover possibly problematic + * code-paths. Kinkie */ helperStatefulReleaseServer(ntlm_request->authserver); ntlm_request->authserver = NULL; } /* clear any connection related authentication details */ void -AuthNTLMUserRequest::onConnectionClose(ConnStateData *conn) +AuthNTLMUserRequest::onConnectionClose(ConnStateData *connection) { - assert(conn != NULL); + assert(connection != NULL); - if (conn->auth_user_request != NULL) { - assert (conn->auth_user_request == this); - assert(this->conn == conn); - - if (authserver != NULL && authserver_deferred) - authenticateNTLMReleaseServer(this); + debug(29,8)("AuthNTLMUserRequest::onConnectionClose: closing connection '%p' (this is '%p')\n",connection,this); + if (connection->auth_user_request == NULL) { + debug(29,8)("AuthNTLMUserRequest::onConnectionClose: no auth_user_request\n"); + return; + } - /* unlock the connection based lock */ - debug(29, 9) ("authenticateNTLMOnCloseConnection: Unlocking auth_user from the connection.\n"); + if (authserver != NULL) + authenticateNTLMReleaseServer(this); - /* This still breaks the abstraction, but is at least read only now. - * If needed, this could be ignored, as the conn deletion will also unlock - * the auth user request. - */ - this->unlock(); + /* unlock the connection based lock */ + debug(29, 9) ("AuthNTLMUserRequest::onConnectionClose: Unlocking auth_user from the connection '%p'.\n",connection); - conn->auth_user_request = NULL; - } -} + /* This still breaks the abstraction, but is at least read only now. + * If needed, this could be ignored, as the conn deletion will also unlock + * the auth user request. + */ + unlock(); -/* NTLMLastHeader: return a pointer to the last header used in authenticating - * the request/conneciton - */ -const char * -AuthNTLMUserRequest::connLastHeader() -{ - return ntlmauthenticate; + connection->auth_user_request = NULL; } /* @@ -925,54 +877,19 @@ auth_user_request->user()->addRequest(auth_user_request); /* all we have to do is identify that it's NTLM - the helper does the rest */ - debug(29, 9) ("authenticateDecodeNTLMAuth: NTLM authentication\n"); + debug(29, 9) ("AuthNTLMConfig::decode: NTLM authentication\n"); return auth_user_request; } -static int -authenticateNTLMcmpUsername(ntlm_user_t * u1, ntlm_user_t * u2) -{ - 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 - */ -static void -authenticateProxyAuthCacheAddLink(const char *key, auth_user_t * auth_user) -{ - - struct ProxyAuthCachePointer *proxy_auth_hash; - dlink_node *node; - ntlm_user_t *ntlm_user; - ntlm_user = dynamic_cast(auth_user); - node = ntlm_user->proxy_auth_list.head; - /* prevent duplicates */ - - while (node) { - - if (!strcmp(key, (char const *)((struct ProxyAuthCachePointer *) node->data)->key)) - return; - - node = node->next; - } - - proxy_auth_hash = static_cast(ntlm_user_hash_pool->alloc()); - proxy_auth_hash->key = xstrdup(key); - proxy_auth_hash->auth_user = auth_user; - dlinkAddTail(proxy_auth_hash, &proxy_auth_hash->link, &ntlm_user->proxy_auth_list); - hash_join(proxy_auth_cache, (hash_link *) proxy_auth_hash); -} - int AuthNTLMUserRequest::authenticated() const { - if (auth_state == AUTHENTICATE_STATE_DONE) + if (auth_state == AUTHENTICATE_STATE_FINISHED) { + debug(29, 9) ("AuthNTLMUserRequest::authenticated: user authenticated.\n"); return 1; + } - debug(29, 9) ("User not fully authenticated.\n"); + debug(29, 9) ("AuthNTLMUserRequest::authenticated: user not fully authenticated.\n"); return 0; } @@ -1186,3 +1103,9 @@ return &ntlmConfig; } +const char * +AuthNTLMUserRequest::connLastHeader() +{ + return NULL; +} + Index: squid3/src/auth/ntlm/auth_ntlm.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/auth/ntlm/auth_ntlm.h,v retrieving revision 1.8 retrieving revision 1.8.12.1 diff -u -r1.8 -r1.8.12.1 --- squid3/src/auth/ntlm/auth_ntlm.h 31 Aug 2004 02:14:29 -0000 1.8 +++ squid3/src/auth/ntlm/auth_ntlm.h 22 Oct 2005 18:30:59 -0000 1.8.12.1 @@ -14,9 +14,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 */ @@ -59,7 +59,6 @@ virtual void authenticate(HttpRequest * request, ConnStateData::Pointer conn, http_hdr_type type); virtual int module_direction(); virtual void onConnectionClose(ConnStateData *); - virtual const char *connLastHeader(); virtual void module_start(RH *, void *); virtual AuthUser *user() {return _theUser;} @@ -67,21 +66,24 @@ virtual void user (AuthUser *aUser) {_theUser=dynamic_cast(aUser);} - /* 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 */ + virtual const char * connLastHeader(); + + /*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; /* what connection is this associated with */ ConnStateData::Pointer conn; + /* how far through the authentication process are we? */ + auth_state_t auth_state; + + /* our current blob to pass to the client */ + char *server_blob; + /* our current blob to pass to the server */ + char *client_blob; + + /* currently waiting for helper response */ + unsigned char waiting; + private: /* the user */ NTLMUser * _theUser; @@ -89,14 +91,6 @@ MEMPROXY_CLASS_INLINE(AuthNTLMUserRequest) -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; -}; - /* configuration runtime data */ class AuthNTLMConfig : public AuthConfig @@ -115,19 +109,8 @@ virtual const char * type() const; int authenticateChildren; wordlist *authenticate; - int challengeuses; - time_t challengelifetime; }; -struct ProxyAuthCachePointer : public hash_link -{ - dlink_node link; - /* other hash entries that point to the same auth_user */ - auth_user_t *auth_user; -}; - -typedef struct _ntlm_helper_state_t ntlm_helper_state_t; - typedef class AuthNTLMConfig auth_ntlm_config; #endif