]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Merge from trunk
authorAmos Jeffries <squid3@treenet.co.nz>
Thu, 27 May 2010 01:56:23 +0000 (13:56 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Thu, 27 May 2010 01:56:23 +0000 (13:56 +1200)
79 files changed:
include/RefCount.h
src/AuthReg.cc
src/CompositePoolNode.h
src/DelayUser.cc
src/DelayUser.h
src/HttpRequest.cc
src/HttpRequest.h
src/Makefile.am
src/acl/FilledChecklist.cc
src/acl/FilledChecklist.h
src/adaptation/icap/ModXact.cc
src/auth/Acl.cc
src/auth/AclMaxUserIp.cc
src/auth/AclMaxUserIp.h
src/auth/AclProxyAuth.cc
src/auth/AclProxyAuth.h
src/auth/AuthAclState.h [new file with mode: 0644]
src/auth/AuthType.h [new file with mode: 0644]
src/auth/Config.cc
src/auth/Config.h
src/auth/Gadgets.cc
src/auth/Gadgets.h
src/auth/Makefile.am
src/auth/Scheme.cc
src/auth/Scheme.h
src/auth/State.cc [new file with mode: 0644]
src/auth/State.h [new file with mode: 0644]
src/auth/User.cc
src/auth/User.cci
src/auth/User.h
src/auth/UserRequest.cc
src/auth/UserRequest.h
src/auth/basic/auth_basic.cc
src/auth/basic/auth_basic.h
src/auth/basic/basicScheme.cc
src/auth/basic/basicScheme.h
src/auth/basic/basicUserRequest.cc [new file with mode: 0644]
src/auth/basic/basicUserRequest.h [new file with mode: 0644]
src/auth/digest/auth_digest.cc
src/auth/digest/auth_digest.h
src/auth/digest/digestScheme.cc
src/auth/digest/digestScheme.h
src/auth/digest/digestUserRequest.cc [new file with mode: 0644]
src/auth/digest/digestUserRequest.h [new file with mode: 0644]
src/auth/negotiate/auth_negotiate.cc
src/auth/negotiate/auth_negotiate.h
src/auth/negotiate/negotiateScheme.cc
src/auth/negotiate/negotiateScheme.h
src/auth/negotiate/negotiateUserRequest.cc [new file with mode: 0644]
src/auth/negotiate/negotiateUserRequest.h [new file with mode: 0644]
src/auth/ntlm/auth_ntlm.cc
src/auth/ntlm/auth_ntlm.h
src/auth/ntlm/ntlmScheme.cc
src/auth/ntlm/ntlmScheme.h
src/auth/ntlm/ntlmUserRequest.cc [new file with mode: 0644]
src/auth/ntlm/ntlmUserRequest.h [new file with mode: 0644]
src/cache_cf.cc
src/cf.data.pre
src/cf_gen.cc
src/client_side.cc
src/client_side.h
src/client_side_reply.cc
src/client_side_reply.h
src/client_side_request.cc
src/enums.h
src/errorpage.cc
src/errorpage.h
src/external_acl.cc
src/http.cc
src/main.cc
src/peer_userhash.cc
src/protos.h
src/redirect.cc
src/stat.cc
src/structs.h
src/tests/testAuth.cc
src/tests/testAuth.h
src/typedefs.h
test-suite/Makefile.am

index f648fe48cf8d7de65925ffe5267056ce3d3c9674..87341efaa03c5290f563c8a16300219f25847e60 100644 (file)
 
 #include "config.h"
 
+#if REFCOUNT_DEBUG
+#include "Debug.h"
+#endif
+
 #if HAVE_IOSTREAM
 #include <iostream>
 #endif
@@ -114,7 +118,7 @@ private:
 struct RefCountable_ {
     RefCountable_():count_(0) {}
 
-    virtual ~RefCountable_() {}
+    virtual ~RefCountable_() { assert(count_ == 0); }
 
     /* Not private, to allow class hierarchies */
     void RefCountReference() const {
index 6590df16af6927ab5e4265319e54f1cd1264e6b6..2825c949c865b778b798139ed2bd7a1f89e44178 100644 (file)
@@ -1,35 +1,43 @@
-#include "squid.h"
-
+#include "config.h"
+#include "Debug.h"
+#include "protos.h"
 
 #if HAVE_AUTH_MODULE_BASIC
 #include "auth/basic/basicScheme.h"
 #endif
-
-#if HAVE_AUTH_MODULE_NTLM
-#include "auth/ntlm/ntlmScheme.h"
-#endif
-
 #if HAVE_AUTH_MODULE_DIGEST
 #include "auth/digest/digestScheme.h"
 #endif
-
 #if HAVE_AUTH_MODULE_NEGOTIATE
 #include "auth/negotiate/negotiateScheme.h"
 #endif
-
-#if HAVE_AUTH_MODULE_BASIC
-static const char *basic_type = basicScheme::GetInstance().type();
-#endif
-
 #if HAVE_AUTH_MODULE_NTLM
-static const char *ntlm_type = ntlmScheme::GetInstance().type();
+#include "auth/ntlm/ntlmScheme.h"
 #endif
 
+/**
+ * Initialize the authentication modules (if any)
+ * This is required once, before any configuration actions are taken.
+ */
+void
+InitAuthSchemes()
+{
+    debugs(29,1,"Initializing Authentication Schemes ...");
+#if HAVE_AUTH_MODULE_BASIC
+    static const char *basic_type = basicScheme::GetInstance()->type();
+    debugs(29,1,"Initialized Authentication Scheme '" << basic_type << "'");
+#endif
 #if HAVE_AUTH_MODULE_DIGEST
-static const char *digest_type = digestScheme::GetInstance().type();
+    static const char *digest_type = digestScheme::GetInstance()->type();
+    debugs(29,1,"Initialized Authentication Scheme '" << digest_type << "'");
 #endif
-
 #if HAVE_AUTH_MODULE_NEGOTIATE
-static const char *negotiate_type = negotiateScheme::GetInstance().type();
+    static const char *negotiate_type = negotiateScheme::GetInstance()->type();
+    debugs(29,1,"Initialized Authentication Scheme '" << negotiate_type << "'");
 #endif
-
+#if HAVE_AUTH_MODULE_NTLM
+    static const char *ntlm_type = ntlmScheme::GetInstance()->type();
+    debugs(29,1,"Initialized Authentication Scheme '" << ntlm_type << "'");
+#endif
+    debugs(29,1,"Initializing Authentication Schemes Complete.");
+}
index 2fc9a6801bd0ff04246141956c62beefc27551b0..904395de0b54ab4f083db58cf3c88f777a6c8133 100644 (file)
@@ -41,6 +41,7 @@
 
 #if DELAY_POOLS
 #include "squid.h"
+#include "auth/UserRequest.h"
 #include "DelayPools.h"
 #include "DelayIdComposite.h"
 #include "CommRead.h"
@@ -48,8 +49,6 @@
 
 class StoreEntry;
 
-class AuthUserRequest;
-
 /// \ingroup DelayPoolsAPI
 class CompositePoolNode : public RefCountable, public Updateable
 {
@@ -77,7 +76,7 @@ public:
         CompositeSelectionDetails() {}
 
         Ip::Address src_addr;
-        AuthUserRequest *user;
+        AuthUserRequest::Pointer user;
         String tag;
     };
 
index 543a297c5a4f5e6e60ce521e50c43c773bc939e9..7e6e42cc62b824f8af8a6e637f7c235e4191b670 100644 (file)
@@ -180,22 +180,20 @@ DelayUserBucket::operator new(size_t size)
 }
 
 void
-DelayUserBucket::operator delete (void *address)
+DelayUserBucket::operator delete(void *address)
 {
-    DelayPools::MemoryUsed -= sizeof (DelayUserBucket);
-    ::operator delete (address);
+    DelayPools::MemoryUsed -= sizeof(DelayUserBucket);
+    ::operator delete(address);
 }
 
-DelayUserBucket::DelayUserBucket(AuthUser *aUser) : authUser (aUser)
+DelayUserBucket::DelayUserBucket(AuthUser::Pointer aUser) : authUser(aUser)
 {
     debugs(77, 3, "DelayUserBucket::DelayUserBucket");
-
-    authUser->lock();
 }
 
 DelayUserBucket::~DelayUserBucket()
 {
-    authUser->unlock();
+    authUser = NULL;
     debugs(77, 3, "DelayUserBucket::~DelayUserBucket");
 }
 
@@ -203,10 +201,10 @@ void
 DelayUserBucket::stats (StoreEntry *entry) const
 {
     storeAppendPrintf(entry, " %s:", authUser->username());
-    theBucket.stats (entry);
+    theBucket.stats(entry);
 }
 
-DelayUser::Id::Id(DelayUser::Pointer aDelayUser,AuthUser *aUser) : theUser(aDelayUser)
+DelayUser::Id::Id(DelayUser::Pointer aDelayUser, AuthUser::Pointer aUser) : theUser(aDelayUser)
 {
     theBucket = new DelayUserBucket(aUser);
     DelayUserBucket::Pointer const *existing = theUser->buckets.find(theBucket, DelayUserCmp);
index 885389e4d5139e4c5e827c4f032d7240372a9692..7c41f55e9bfb72d2e08bdfff3ac11f28cd923921 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "squid.h"
 #include "auth/Gadgets.h"
+#include "auth/User.h"
 #include "CompositePoolNode.h"
 #include "DelayIdComposite.h"
 #include "DelayBucket.h"
@@ -59,10 +60,10 @@ public:
     void operator delete (void *);
 
     void stats(StoreEntry *)const;
-    DelayUserBucket(AuthUser *);
+    DelayUserBucket(AuthUser::Pointer);
     ~DelayUserBucket();
     DelayBucket theBucket;
-    AuthUser *authUser;
+    AuthUser::Pointer authUser;
 };
 
 /// \ingroup DelayPoolsAPI
@@ -91,7 +92,7 @@ private:
     public:
         void *operator new(size_t);
         void operator delete (void *);
-        Id (RefCount<DelayUser>, AuthUser *);
+        Id(RefCount<DelayUser>, AuthUser::Pointer);
         ~Id();
         virtual int bytesWanted (int min, int max) const;
         virtual void bytesIn(int qty);
index 40ccc86fe9636841965481c4d835010ee1cb395b..a89c2e5a1902acbe22e2063183d313e156d60fc3 100644 (file)
@@ -126,7 +126,7 @@ HttpRequest::clean()
     // points to a pipe that is owned and initiated by another object.
     body_pipe = NULL;
 
-    AUTHUSERREQUESTUNLOCK(auth_user_request, "request");
+    auth_user_request = NULL;
 
     safe_free(canonical);
 
@@ -596,10 +596,7 @@ bool HttpRequest::inheritProperties(const HttpMsg *aMsg)
     // may eventually need cloneNullAdaptationImmune() for that.
     flags = aReq->flags.cloneAdaptationImmune();
 
-    if (aReq->auth_user_request) {
-        auth_user_request = aReq->auth_user_request;
-        AUTHUSERREQUESTLOCK(auth_user_request, "inheritProperties");
-    }
+    auth_user_request = aReq->auth_user_request;
 
     if (aReq->pinned_connection) {
         pinned_connection = cbdataReference(aReq->pinned_connection);
index 27c9600f9daa62bdc387f46fa7f7dae745cda2cc..4e78882aea3a418702b8eb2e3dd98b9ed13666a8 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
@@ -151,7 +150,7 @@ private:
 public:
     Ip::Address host_addr;
 
-    AuthUserRequest *auth_user_request;
+    AuthUserRequest::Pointer auth_user_request;
 
     u_short port;
 
index af7b0ddbf64937ccd88ce4c323ac605b7b32afe6..589a298bb7115e453a538d0a1b9cc996f87f6195 100644 (file)
@@ -154,8 +154,6 @@ noinst_LTLIBRARIES = libsquid.la
 
 # libraries used by many targets
 COMMON_LIBS = \
-       base/libbase.la \
-       libsquid.la \
        auth/libacls.la \
        ident/libident.la \
        acl/libacls.la \
@@ -163,6 +161,8 @@ COMMON_LIBS = \
        acl/libstate.la \
        auth/libauth.la \
        acl/libapi.la \
+       base/libbase.la \
+       libsquid.la \
        ip/libip.la \
        fs/libfs.la
 
@@ -755,7 +755,7 @@ snmp_core.o snmp_agent.o: ../snmplib/libsnmp.a $(top_srcdir)/include/cache_snmp.
 globals.cc: globals.h mk-globals-c.awk
        $(AWK) -f $(srcdir)/mk-globals-c.awk < $(srcdir)/globals.h > $@ || ($(RM) -f $@ && exit 1)
 
-## Generate files containing strng arrays for various enums....
+## Generate files containing string arrays for various enums....
 hier_code.cc: hier_code.h mk-string-arrays.awk
        $(AWK) -f $(srcdir)/mk-string-arrays.awk < $(srcdir)/hier_code.h > $@ || ($(RM) -f $@ && exit 1)
 
@@ -1105,6 +1105,7 @@ tests_testBoilerplate_DEPENDENCIES = \
 
 ## Tests of the CacheManager module.
 tests_testCacheManager_SOURCES = \
+       $(ACL_REGISTRATION_SOURCES) \
        debug.cc \
        HttpRequest.cc \
        HttpRequestMethod.cc \
@@ -1284,6 +1285,7 @@ tests_testDiskIO_DEPENDENCIES = $(top_builddir)/lib/libmiscutil.a \
 
 ## Tests of the Even module.
 tests_testEvent_SOURCES = \
+       $(ACL_REGISTRATION_SOURCES) \
        debug.cc \
        EventLoop.h \
        EventLoop.cc \
@@ -1439,6 +1441,7 @@ tests_testEvent_DEPENDENCIES =  $(top_builddir)/lib/libmiscutil.a \
 
 ## Tests of the EventLoop module.
 tests_testEventLoop_SOURCES = \
+       $(ACL_REGISTRATION_SOURCES) \
        debug.cc \
        EventLoop.h \
        EventLoop.cc \
@@ -1592,6 +1595,7 @@ tests_testEventLoop_DEPENDENCIES =  $(top_builddir)/lib/libmiscutil.a \
        $(SQUID_CPPUNIT_LA)
 
 tests_test_http_range_SOURCES = \
+       $(ACL_REGISTRATION_SOURCES) \
        tests/test_http_range.cc \
        BodyPipe.cc \
        cache_cf.cc \
@@ -1742,6 +1746,7 @@ tests_test_http_range_DEPENDENCIES = \
 
 ## Tests of the HttpRequest module.
 tests_testHttpRequest_SOURCES = \
+       $(ACL_REGISTRATION_SOURCES) \
        debug.cc \
        HttpRequest.cc \
        HttpRequestMethod.cc \
@@ -2113,6 +2118,7 @@ tests_testNull_DEPENDENCIES = \
 ## Tests of the URL module.
 ## TODO: Trim this down once the insanity is over.
 tests_testURL_SOURCES = \
+       $(ACL_REGISTRATION_SOURCES) \
        debug.cc \
        url.cc \
        URLScheme.cc \
index dad2ed501033dd7aad8d2dba2ff54cbd7e24a6ae..72ec05750b18d4e4b4087e509d09915bae44d598 100644 (file)
@@ -8,95 +8,20 @@
 
 CBDATA_CLASS_INIT(ACLFilledChecklist);
 
-#if MOVED
-int
-ACLFilledChecklist::authenticated()
-{
-    http_hdr_type headertype;
-
-    if (NULL == request) {
-        fatal ("requiresRequest SHOULD have been true for this ACL!!");
-        return 0;
-    } else if (request->flags.accelerated) {
-        /* WWW authorization on accelerated requests */
-        headertype = HDR_AUTHORIZATION;
-    } else if (request->flags.intercepted || request->flags.spoof_client_ip) {
-        debugs(28, DBG_IMPORTANT, HERE << " authentication not applicable on intercepted requests.");
-        return -1;
-    } else {
-        /* Proxy authorization on proxy requests */
-        headertype = HDR_PROXY_AUTHORIZATION;
-    }
-
-    /* get authed here */
-    /* Note: this fills in auth_user_request when applicable */
-    /*
-     * DPW 2007-05-08
-     * tryToAuthenticateAndSetAuthUser used to try to lock and
-     * unlock auth_user_request on our behalf, but it was too
-     * ugly and hard to follow.  Now we do our own locking here.
-     *
-     * I'm not sure what tryToAuthenticateAndSetAuthUser does when
-     * auth_user_request is set before calling.  I'm tempted to
-     * unlock and set it to NULL, but it seems safer to save the
-     * pointer before calling and unlock it afterwards.  If the
-     * pointer doesn't change then its a no-op.
-     */
-    AuthUserRequest *old_auth_user_request = auth_user_request;
-    auth_acl_t result = AuthUserRequest::tryToAuthenticateAndSetAuthUser (&auth_user_request, headertype, request, conn(), src_addr);
-    if (auth_user_request)
-        AUTHUSERREQUESTLOCK(auth_user_request, "ACLFilledChecklist");
-    AUTHUSERREQUESTUNLOCK(old_auth_user_request, "old ACLFilledChecklist");
-    switch (result) {
-
-    case AUTH_ACL_CANNOT_AUTHENTICATE:
-        debugs(28, 4, "aclMatchAcl: returning  0 user authenticated but not authorised.");
-        return 0;
-
-    case AUTH_AUTHENTICATED:
-
-        return 1;
-        break;
-
-    case AUTH_ACL_HELPER:
-        debugs(28, 4, "aclMatchAcl: returning 0 sending credentials to helper.");
-        changeState (ProxyAuthLookup::Instance());
-        return 0;
-
-    case AUTH_ACL_CHALLENGE:
-        debugs(28, 4, "aclMatchAcl: returning 0 sending authentication challenge.");
-        changeState (ProxyAuthNeeded::Instance());
-        return 0;
-
-    default:
-        fatal("unexpected authenticateAuthenticate reply\n");
-        return 0;
-    }
-}
-#endif
-
 void
 ACLFilledChecklist::checkCallback(allow_t answer)
 {
-    debugs(28, 5, "ACLFilledChecklist::checkCallback: " << this << " answer=" << answer);
+    debugs(28, 5, HERE << this << " answer=" << answer);
 
     /* During reconfigure, we can end up not finishing call
      * sequences into the auth code */
 
-    if (auth_user_request) {
+    if (auth_user_request != NULL) {
         /* the filled_checklist lock */
-        AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLFilledChecklist");
-
+        auth_user_request = NULL;
         /* it might have been connection based */
-        /*
-         * DPW 2007-05-08
-         * yuck, this make me uncomfortable.  why do this here?
-         * ConnStateData will do its own unlocking.
-         */
-        /* BUG 2827: the connection may also not exist. ie fast ACL tests vs client disconnection. */
         if (conn()) {
-            AUTHUSERREQUESTUNLOCK(conn()->auth_user_request, "conn via ACLFilledChecklist");
-            conn()->auth_type = AUTH_BROKEN;
+            conn()->auth_user_request = NULL;
         }
     }
 
@@ -159,10 +84,6 @@ ACLFilledChecklist::~ACLFilledChecklist()
 
     HTTPMSGUNLOCK(reply);
 
-    // no auth_user_request in builds without any Authentication configured
-    if (auth_user_request)
-        AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLFilledChecklist destructor");
-
     cbdataReferenceDone(conn_);
 
     debugs(28, 4, HERE << "ACLFilledChecklist destroyed " << this);
index fb3b76a27851dee24aa88bccec53b0280fba09e9..2d9f495a0716c4d15b40418acc9b4d2fb524f02b 100644 (file)
@@ -2,8 +2,8 @@
 #define SQUID_ACLFILLED_CHECKLIST_H
 
 #include "acl/Checklist.h"
+#include "auth/UserRequest.h"
 
-class AuthUserRequest;
 class ExternalACLEntry;
 class ConnStateData;
 
@@ -53,7 +53,7 @@ public:
     HttpReply *reply;
 
     char rfc931[USER_IDENT_SZ];
-    AuthUserRequest *auth_user_request;
+    AuthUserRequest::Pointer auth_user_request;
 
 #if SQUID_SNMP
     char *snmp_community;
index dcca69eff235173131a62b9a3d36bf2a9bec0c2f..b024735c3f6ae089b326ea2d9b2773965de0e955 100644 (file)
@@ -1279,12 +1279,11 @@ void Adaptation::Icap::ModXact::makeRequestHeaders(MemBuf &buf)
 
 void Adaptation::Icap::ModXact::makeUsernameHeader(const HttpRequest *request, MemBuf &buf)
 {
-    if (const AuthUserRequest *auth = request->auth_user_request) {
-        if (char const *name = auth->username()) {
-            const char *value = TheConfig.client_username_encode ?
-                                base64_encode(name) : name;
-            buf.Printf("%s: %s\r\n", TheConfig.client_username_header,
-                       value);
+    if (request->auth_user_request != NULL) {
+        char const *name = (request->auth_user_request)->username();
+        if (name) {
+            const char *value = TheConfig.client_username_encode ? base64_encode(name) : name;
+            buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value);
         }
     }
 }
index dddea7d0d4868363a03acef56623206bc58a7dd6..6e43bca198af9181add2a3d9ccbd1ce2686f3919 100644 (file)
@@ -32,25 +32,9 @@ AuthenticateAcl(ACLChecklist *ch)
 
     /* get authed here */
     /* Note: this fills in auth_user_request when applicable */
-    /*
-     * DPW 2007-05-08
-     * tryToAuthenticateAndSetAuthUser used to try to lock and
-     * unlock auth_user_request on our behalf, but it was too
-     * ugly and hard to follow.  Now we do our own locking here.
-     *
-     * I'm not sure what tryToAuthenticateAndSetAuthUser does when
-     * auth_user_request is set before calling.  I'm tempted to
-     * unlock and set it to NULL, but it seems safer to save the
-     * pointer before calling and unlock it afterwards.  If the
-     * pointer doesn't change then its a no-op.
-     */
-    AuthUserRequest *old_auth_user_request = checklist->auth_user_request;
-    const auth_acl_t result = AuthUserRequest::tryToAuthenticateAndSetAuthUser(
+    const AuthAclState result = AuthUserRequest::tryToAuthenticateAndSetAuthUser(
                                   &checklist->auth_user_request, headertype, request,
                                   checklist->conn(), checklist->src_addr);
-    if (checklist->auth_user_request)
-        AUTHUSERREQUESTLOCK(checklist->auth_user_request, "ACLAuth::authenticated");
-    AUTHUSERREQUESTUNLOCK(old_auth_user_request, "old ACLAuth");
     switch (result) {
 
     case AUTH_ACL_CANNOT_AUTHENTICATE:
index c447271b1ab31ae932b6b225a9b8816674dc1d69..20e9d22f545504827ecea69dd49aeb78e30fb5cb 100644 (file)
@@ -112,7 +112,7 @@ ACLMaxUserIP::parse()
  * 1 : Match
  */
 int
-ACLMaxUserIP::match(AuthUserRequest * auth_user_request, Ip::Address const &src_addr)
+ACLMaxUserIP::match(AuthUserRequest::Pointer auth_user_request, Ip::Address const &src_addr)
 {
     /*
      * the logic for flush the ip list when the limit is hit vs keep
@@ -157,7 +157,7 @@ ACLMaxUserIP::match(ACLChecklist *cl)
 
     ti = match(checklist->auth_user_request, checklist->src_addr);
 
-    AUTHUSERREQUESTUNLOCK(checklist->auth_user_request, "ACLChecklist via ACLMaxUserIP");
+    checklist->auth_user_request = NULL;
 
     return ti;
 }
index ad8ade899582310e0dcd1782edeb07706cb9dfa6..35a62feafeb9ef289b56ed7fb0d286de14301a76 100644 (file)
@@ -37,8 +37,7 @@
 
 #include "acl/Acl.h"
 #include "acl/Checklist.h"
-
-class AuthUserRequest;
+#include "auth/UserRequest.h"
 
 /// \ingroup ACLAPI
 class ACLMaxUserIP : public ACL
@@ -69,7 +68,7 @@ private:
     static Prototype RegistryProtoype;
     static ACLMaxUserIP RegistryEntry_;
 
-    int match(AuthUserRequest *, Ip::Address const &);
+    int match(AuthUserRequest::Pointer, Ip::Address const &);
     char const *class_;
     int maximum;
 
index b676957f886a1adb8dd919d91afdb9672b2003ec..38ce3a195b8f013c23739865298140aeb97c48df 100644 (file)
@@ -139,16 +139,12 @@ ProxyAuthLookup::checkForAsync(ACLChecklist *cl)const
     ACLFilledChecklist *checklist = Filled(cl);
 
     checklist->asyncInProgress(true);
-    debugs(28, 3, "ACLChecklist::checkForAsync: checking password via authenticator");
+    debugs(28, 3, HERE << "checking password via authenticator");
 
-    AuthUserRequest *auth_user_request;
     /* make sure someone created auth_user_request for us */
     assert(checklist->auth_user_request != NULL);
-    auth_user_request = checklist->auth_user_request;
-
-    int validated = authenticateValidateUser(auth_user_request);
-    assert(validated);
-    auth_user_request->start(LookupDone, checklist);
+    assert(checklist->auth_user_request->valid());
+    checklist->auth_user_request->start(LookupDone, checklist);
 }
 
 void
@@ -161,15 +157,14 @@ ProxyAuthLookup::LookupDone(void *data, char *result)
     if (result != NULL)
         fatal("AclLookupProxyAuthDone: Old code floating around somewhere.\nMake clean and if that doesn't work, report a bug to the squid developers.\n");
 
-    if (!authenticateValidateUser(checklist->auth_user_request) || checklist->conn() == NULL) {
+    if (checklist->auth_user_request == NULL || !checklist->auth_user_request->valid() || checklist->conn() == NULL) {
         /* credentials could not be checked either way
          * restart the whole process */
         /* OR the connection was closed, there's no way to continue */
-        AUTHUSERREQUESTUNLOCK(checklist->auth_user_request, "ProxyAuthLookup");
+        checklist->auth_user_request = NULL;
 
         if (checklist->conn() != NULL) {
-            AUTHUSERREQUESTUNLOCK(checklist->conn()->auth_user_request, "conn via ProxyAuthLookup");   // DPW discomfort
-            checklist->conn()->auth_type = AUTH_BROKEN;
+            checklist->conn()->auth_user_request = NULL;
         }
     }
 
@@ -201,7 +196,7 @@ int
 ACLProxyAuth::matchForCache(ACLChecklist *cl)
 {
     ACLFilledChecklist *checklist = Filled(cl);
-    assert (checklist->auth_user_request);
+    assert (checklist->auth_user_request != NULL);
     return data->match(checklist->auth_user_request->username());
 }
 
@@ -213,20 +208,11 @@ int
 ACLProxyAuth::matchProxyAuth(ACLChecklist *cl)
 {
     ACLFilledChecklist *checklist = Filled(cl);
-    checkAuthForCaching(checklist);
+    if (!authenticateUserAuthenticated(Filled(checklist)->auth_user_request)) {
+        return 0;
+    }
     /* check to see if we have matched the user-acl before */
-    int result = cacheMatchAcl(&checklist->auth_user_request->user()->
-                               proxy_match_cache, checklist);
-    AUTHUSERREQUESTUNLOCK(checklist->auth_user_request, "ACLChecklist via ACLProxyAuth");
+    int result = cacheMatchAcl(&checklist->auth_user_request->user()->proxy_match_cache, checklist);
+    checklist->auth_user_request = NULL;
     return result;
 }
-
-void
-ACLProxyAuth::checkAuthForCaching(ACLChecklist *checklist)const
-{
-    /* for completeness */
-    /* consistent parameters ? */
-    assert(authenticateUserAuthenticated(Filled(checklist)->auth_user_request));
-    /* this check completed */
-}
-
index 8183d99ba87d3b36984852ff19e7146580efd06e..390fd2a52bbd1098a77bc455450078501f34b85e 100644 (file)
@@ -82,7 +82,7 @@ public:
     virtual bool empty () const;
     virtual bool requiresRequest() const {return true;}
 
-    virtual ACL *clone()const;
+    virtual ACL *clone() const;
     virtual int matchForCache(ACLChecklist *checklist);
 
 private:
@@ -91,7 +91,6 @@ private:
     static Prototype RegexRegistryProtoype;
     static ACLProxyAuth RegexRegistryEntry_;
     int matchProxyAuth(ACLChecklist *);
-    void checkAuthForCaching(ACLChecklist *) const;
     ACLData<char const *> *data;
     char const *type_;
 };
diff --git a/src/auth/AuthAclState.h b/src/auth/AuthAclState.h
new file mode 100644 (file)
index 0000000..10d6390
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _SQUID__SRC_AUTH_AUTHACLSTATE_H
+#define _SQUID__SRC_AUTH_AUTHACLSTATE_H
+
+typedef enum {
+    AUTH_ACL_CHALLENGE = -2,
+    AUTH_ACL_HELPER = -1,
+    AUTH_ACL_CANNOT_AUTHENTICATE = 0,
+    AUTH_AUTHENTICATED = 1
+} AuthAclState;
+
+#endif
diff --git a/src/auth/AuthType.h b/src/auth/AuthType.h
new file mode 100644 (file)
index 0000000..eec96b7
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _SQUID__SRC_AUTH_AUTHTYPE_H
+#define _SQUID__SRC_AUTH_AUTHTYPE_H
+
+typedef enum {
+    AUTH_UNKNOWN,               /* default */
+    AUTH_BASIC,
+    AUTH_NTLM,
+    AUTH_DIGEST,
+    AUTH_NEGOTIATE,
+    AUTH_BROKEN                 /* known type, but broken data */
+} AuthType;
+
+extern const char *AuthType_str[];
+
+#endif
index 0b4beb0862f3c6c31b2656224f6dc68d97e30968..6f0146269694e1564b9221e9e20169c447924416 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
 #include "auth/Config.h"
 #include "auth/UserRequest.h"
 
-/* Get Auth User: Return a filled out auth_user structure for the given
+Auth::authConfig Auth::TheConfig;
+
+/**
+ * Get Auth User: Return a filled out auth_user structure for the given
  * Proxy Auth (or Auth) header. It may be a cached Auth User or a new
  * Unauthenticated structure. The structure is given an inital lock here.
  * It may also be NULL reflecting that no user could be created.
  */
-AuthUserRequest *
+AuthUserRequest::Pointer
 AuthConfig::CreateAuthUser(const char *proxy_auth)
 {
     assert(proxy_auth != NULL);
@@ -55,20 +57,13 @@ AuthConfig::CreateAuthUser(const char *proxy_auth)
         return NULL;
     }
 
-    AuthUserRequest *result = config->decode (proxy_auth);
-
-    /*
-     * DPW 2007-05-08
-     * Do not lock the AuthUserRequest on the caller's behalf.
-     * Callers must manage their own locks.
-     */
-    return result;
+    return config->decode(proxy_auth);
 }
 
 AuthConfig *
 AuthConfig::Find(const char *proxy_auth)
 {
-    for (authConfig::iterator  i = Config.authConfiguration.begin(); i != Config.authConfiguration.end(); ++i)
+    for (Auth::authConfig::iterator  i = Auth::TheConfig.begin(); i != Auth::TheConfig.end(); ++i)
         if (strncasecmp(proxy_auth, (*i)->type(), strlen((*i)->type())) == 0)
             return *i;
 
index bdb553c57d3a4e0b8f113e83491763ffa3bd5ea8..8ea2eca233c39c45f1f330aa9595988525e41a15 100644 (file)
 #ifndef SQUID_AUTHCONFIG_H
 #define SQUID_AUTHCONFIG_H
 
-class AuthUserRequest;
+#include "auth/UserRequest.h"
+#include "HelperChildConfig.h"
+
 class StoreEntry;
 class HttpReply;
 class HttpRequest;
+class wordlist;
 
 /* for http_hdr_type parameters-by-value */
 #include "HttpHeader.h"
@@ -56,10 +59,10 @@ class AuthConfig
 {
 
 public:
-    static AuthUserRequest *CreateAuthUser (const char *proxy_auth);
+    static AuthUserRequest::Pointer CreateAuthUser(const char *proxy_auth);
 
     static AuthConfig *Find(const char *proxy_auth);
-    AuthConfig() {}
+    AuthConfig() : authenticateChildren(20), authenticate(NULL) {}
 
     virtual ~AuthConfig() {}
 
@@ -81,7 +84,7 @@ public:
      \param proxy_auth Login Pattern to parse.
      \retval *         Details needed to authenticate.
      */
-    virtual AuthUserRequest *decode(char const *proxy_auth) = 0;
+    virtual AuthUserRequest::Pointer decode(char const *proxy_auth) = 0;
 
     /**
      * squid is finished with this config, release any unneeded resources.
@@ -102,6 +105,12 @@ public:
      */
     virtual bool configured() const = 0;
 
+    /**
+     * Shutdown just the auth helpers.
+     * For use by log rotate etc. where auth needs to stay running, with the helpers restarted.
+     */
+    virtual void rotateHelpers(void) = 0;
+
     /**
      * Responsible for writing to the StoreEntry the configuration parameters that a user
      * would put in a config file to recreate the running configuration.
@@ -109,7 +118,7 @@ public:
     virtual void dump(StoreEntry *, const char *, AuthConfig *) = 0;
 
     /** add headers as needed when challenging for auth */
-    virtual void fixHeader(AuthUserRequest *, HttpReply *, http_hdr_type, HttpRequest *) = 0;
+    virtual void fixHeader(AuthUserRequest::Pointer, HttpReply *, http_hdr_type, HttpRequest *) = 0;
     /** prepare to handle requests */
     virtual void init(AuthConfig *) = 0;
     /** expose any/all statistics to a CacheManager */
@@ -118,6 +127,19 @@ public:
     virtual void parse(AuthConfig *, int, char *) = 0;
     /** the http string id */
     virtual const char * type() const = 0;
+
+public:
+    HelperChildConfig authenticateChildren;    
+    wordlist *authenticate;
 };
 
+namespace Auth
+{
+
+typedef Vector<AuthConfig *> authConfig;
+
+extern authConfig TheConfig;
+
+}; // namespace Auth
+
 #endif /* SQUID_AUTHCONFIG_H */
index 2bf51f6725cbaeb1a3be1a3c50136273e496cc17..d9a312c4b357b37f9abcd764f29b0acc63e75c91 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
@@ -57,11 +56,11 @@ authenticateActiveSchemeCount(void)
 {
     int rv = 0;
 
-    for (authConfig::iterator i = Config.authConfiguration.begin(); i != Config.authConfiguration.end(); ++i)
+    for (Auth::authConfig::iterator i = Auth::TheConfig.begin(); i != Auth::TheConfig.end(); ++i)
         if ((*i)->configured())
             ++rv;
 
-    debugs(29, 9, "authenticateActiveSchemeCount: " << rv << " active.");
+    debugs(29, 9, HERE << rv << " active.");
 
     return rv;
 }
@@ -69,119 +68,84 @@ authenticateActiveSchemeCount(void)
 int
 authenticateSchemeCount(void)
 {
-    int rv = AuthScheme::Schemes().size();
+    int rv = AuthScheme::GetSchemes().size();
 
-    debugs(29, 9, "authenticateSchemeCount: " << rv << " active.");
+    debugs(29, 9, HERE << rv << " active.");
 
     return rv;
 }
 
 static void
-authenticateRegisterWithCacheManager(authConfig * config)
+authenticateRegisterWithCacheManager(Auth::authConfig * config)
 {
-    for (authConfig::iterator i = config->begin(); i != config->end(); ++i) {
+    for (Auth::authConfig::iterator i = config->begin(); i != config->end(); ++i) {
         AuthConfig *scheme = *i;
         scheme->registerWithCacheManager();
     }
 }
 
 void
-authenticateInit(authConfig * config)
+authenticateInit(Auth::authConfig * config)
 {
-    for (authConfig::iterator i = config->begin(); i != config->end(); ++i) {
-        AuthConfig *scheme = *i;
+    /* Do this first to clear memory and remove dead state on a reconfigure */
+    if (proxy_auth_username_cache)
+        AuthUser::CachedACLsReset();
+
+    /* If we do not have any auth config state to create stop now. */
+    if (!config)
+        return;
 
-        if (scheme->configured())
-            scheme->init(scheme);
+    for (Auth::authConfig::iterator i = config->begin(); i != config->end(); ++i) {
+        AuthConfig *schemeCfg = *i;
+
+        if (schemeCfg->configured())
+            schemeCfg->init(schemeCfg);
     }
 
     if (!proxy_auth_username_cache)
         AuthUser::cacheInit();
-    else
-        AuthUser::CachedACLsReset();
 
-    authenticateRegisterWithCacheManager(&Config.authConfiguration);
+    authenticateRegisterWithCacheManager(config);
 }
 
 void
-authenticateShutdown(void)
-{
-    debugs(29, 2, "authenticateShutdown: shutting down auth schemes");
-    /* free the cache if we are shutting down */
-
-    if (shutting_down) {
-        hashFreeItems(proxy_auth_username_cache, AuthUserHashPointer::removeFromCache);
-        AuthScheme::FreeAll();
-    } else {
-        for (AuthScheme::const_iterator i = AuthScheme::Schemes().begin(); i != AuthScheme::Schemes().end(); ++i)
-            (*i)->done();
-    }
-}
-
-/**
- \retval 0 not in use
- \retval ? in use
- */
-int
-authenticateAuthUserInuse(AuthUser * auth_user)
+authenticateRotate(void)
 {
-    assert(auth_user != NULL);
-    return auth_user->references;
+    for (Auth::authConfig::iterator i = Auth::TheConfig.begin(); i != Auth::TheConfig.end(); ++i)
+        if ((*i)->configured())
+            (*i)->rotateHelpers();
 }
 
 void
-authenticateAuthUserMerge(AuthUser * from, AuthUser * to)
+authenticateReset(void)
 {
-    to->absorb (from);
-}
+    debugs(29, 2, HERE << "Reset authentication State.");
 
-/**
- * Cleans all config-dependent data from the auth_user cache.
- \note It DOES NOT Flush the user cache.
- */
-void
-authenticateUserCacheRestart(void)
-{
-    AuthUserHashPointer *usernamehash;
-    AuthUser *auth_user;
-    debugs(29, 3, HERE << "Clearing config dependent cache data.");
+    /* free all username cache entries */
     hash_first(proxy_auth_username_cache);
-
+    AuthUserHashPointer *usernamehash;
     while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
-        auth_user = usernamehash->user();
-        debugs(29, 5, "authenticateUserCacheRestat: Clearing cache ACL results for user: " << auth_user->username());
+        debugs(29, 5, HERE << "Clearing entry for user: " << usernamehash->user()->username());
+        hash_remove_link(proxy_auth_username_cache, (hash_link *)usernamehash);
+        delete usernamehash;
     }
-}
 
+    /* schedule shutdown of the helpers */
+    authenticateRotate();
 
-void
-AuthUserHashPointer::removeFromCache(void *usernamehash_p)
-{
-    AuthUserHashPointer *usernamehash = static_cast<AuthUserHashPointer *>(usernamehash_p);
-    AuthUser *auth_user = usernamehash->auth_user;
-
-    if ((authenticateAuthUserInuse(auth_user) - 1))
-        debugs(29, 1, "AuthUserHashPointer::removeFromCache: entry in use - not freeing");
-
-    auth_user->unlock();
-
-    /** \todo change behaviour - we remove from the auth user list here, and then unlock, and the
-     * delete ourselves.
-     */
+    /* free current global config details too. */
+    Auth::TheConfig.clean();
 }
 
-AuthUserHashPointer::AuthUserHashPointer(AuthUser * anAuth_user):
+AuthUserHashPointer::AuthUserHashPointer(AuthUser::Pointer anAuth_user):
         auth_user(anAuth_user)
 {
     key = (void *)anAuth_user->username();
     next = NULL;
     hash_join(proxy_auth_username_cache, (hash_link *) this);
-
-    /** lock for presence in the cache */
-    auth_user->lock();
 }
 
-AuthUser *
+AuthUser::Pointer
 AuthUserHashPointer::user() const
 {
     return auth_user;
index 77b08b595645e35a1be661e4c1ad2595c5cf67f2..11de64c42c0c0bf43c017e888d308d2657cdb84f 100644 (file)
 
 #include "hash.h"
 #include "MemPool.h"
-#include "typedefs.h" /* for authConfig */
+#include "auth/Config.h"
+#include "auth/User.h"
 
 class AuthUser;
 
 /**
  \ingroup AuthAPI
  *
- * This is used to link auth_users into the username cache.
+ * This is used to link AuthUsers objects into the username cache.
  * Because some schemes may link in aliases to a user,
  * the link is not part of the AuthUser structure itself.
  *
- \todo Inheritance in a struct? this should be a class.
+ * Code must not hold onto copies of these objects.
+ * They may exist only so long as the AuthUser being referenced
+ * is recorded in the cache. Any caller using hash_remove_link
+ * must then delete the AuthUserHashPointer.
  */
-struct AuthUserHashPointer : public hash_link {
+class AuthUserHashPointer : public hash_link {
     /* first two items must be same as hash_link */
 
 public:
-    static void removeFromCache (void *anAuthUserHashPointer);
     MEMPROXY_CLASS(AuthUserHashPointer);
 
-    AuthUserHashPointer(AuthUser *);
+    AuthUserHashPointer(AuthUser::Pointer);
+    ~AuthUserHashPointer() { auth_user = NULL; };
 
-    AuthUser *user() const;
+    AuthUser::Pointer user() const;
 
 private:
-    AuthUser *auth_user;
+    AuthUser::Pointer auth_user;
 };
 
 MEMPROXY_CLASS_INLINE(AuthUserHashPointer);
@@ -75,19 +79,22 @@ class StoreEntry;
  */
 typedef void AUTHSSTATS(StoreEntry *);
 
-/**
- \ingroup AuthAPI
- * subsumed by the C++ interface
- \todo does 'subsumed' mean deprecated use a C++ API call?
+/// \ingroup AuthAPI
+extern void authenticateInit(Auth::authConfig *);
+
+/** \ingroup AuthAPI
+ * Remove all idle authentication state. Intended for use by reconfigure.
+ *
+ * Removes the username cache contents and global configuration state.
+ * Stops just short of detaching the auth components completely.
+ *
+ * Currently active requests should finish. Howevee new requests will not use
+ * authentication unless something causes the global config to be rebuilt.
+ * Such as a configure load action adding config and re-running authenticateInit().
  */
-extern void authenticateAuthUserMerge(AuthUser *, AuthUser *);
+extern void authenticateReset(void);
 
-/// \ingroup AuthAPI
-extern void authenticateInit(authConfig *);
-/// \ingroup AuthAPI
-extern void authenticateShutdown(void);
-/// \ingroup AuthAPI
-extern int authenticateAuthUserInuse(AuthUser * auth_user);
+extern void authenticateRotate(void);
 
 /// \ingroup AuthAPI
 extern void authenticateFreeProxyAuthUserACLResults(void *data);
@@ -96,8 +103,6 @@ extern int authenticateActiveSchemeCount(void);
 /// \ingroup AuthAPI
 extern int authenticateSchemeCount(void);
 
-/// \ingroup AuthAPI
-extern void authenticateUserCacheRestart(void);
 /// \ingroup AuthAPI
 extern void authenticateOnCloseConnection(ConnStateData * conn);
 
index 9912440df3afc411e8797b45c517f9e447299878..2c0e9eaa5e8f4a82e089c6f7d56bc8c9db2303e9 100644 (file)
@@ -8,17 +8,21 @@ EXTRA_LTLIBRARIES = libbasic.la libdigest.la libntlm.la libnegotiate.la
 
 ## authentication framework; this library is always built
 libauth_la_SOURCES = \
+       AuthType.h \
+       AuthType.cc \
        Config.cc \
        Config.h \
+       Gadgets.cc \
+       Gadgets.h \
        Scheme.cc \
        Scheme.h \
+       State.h \
+       State.cc \
        User.h \
        User.cci \
        User.cc \
        UserRequest.h \
-       UserRequest.cc \
-       Gadgets.cc \
-       Gadgets.h
+       UserRequest.cc
 
 libauth_la_LIBADD = $(AUTH_LIBS_TO_BUILD)
 libauth_la_DEPENDENCIES = $(AUTH_LIBS_TO_BUILD)
@@ -31,32 +35,43 @@ libacls_la_SOURCES = \
        AclMaxUserIp.cc \
        AclMaxUserIp.h \
        AclProxyAuth.cc \
-       AclProxyAuth.h  
-
+       AclProxyAuth.h \
+       AuthAclState.h
 
 libbasic_la_SOURCES = \
        basic/basicScheme.cc \
        basic/basicScheme.h \
        basic/auth_basic.cc \
-       basic/auth_basic.h
+       basic/auth_basic.h \
+       basic/basicUserRequest.cc \
+       basic/basicUserRequest.h
 
 libdigest_la_SOURCES = \
        digest/digestScheme.cc \
        digest/digestScheme.h \
        digest/auth_digest.cc \
-       digest/auth_digest.h
+       digest/auth_digest.h \
+       digest/digestUserRequest.cc \
+       digest/digestUserRequest.h
 
 libntlm_la_SOURCES = \
        ntlm/ntlmScheme.cc \
        ntlm/ntlmScheme.h \
        ntlm/auth_ntlm.cc \
-       ntlm/auth_ntlm.h
+       ntlm/auth_ntlm.h \
+       ntlm/ntlmUserRequest.cc \
+       ntlm/ntlmUserRequest.h
 
 libnegotiate_la_SOURCES = \
        negotiate/negotiateScheme.cc \
        negotiate/negotiateScheme.h \
        negotiate/auth_negotiate.cc \
-       negotiate/auth_negotiate.h
+       negotiate/auth_negotiate.h \
+       negotiate/negotiateUserRequest.cc \
+       negotiate/negotiateUserRequest.h
+
+AuthType.cc: AuthType.h $(top_srcdir)/src/mk-string-arrays.awk
+       $(AWK) -f $(top_srcdir)/src/mk-string-arrays.awk < $(srcdir)/AuthType.h > $@ || (rm -f $@ ; exit 1)
 
 
 TESTS += testHeaders
index 764a7c06194b43622394c30622327eb1e18cbbb5..b476636c18ff0157277888b8712679b2cedaeb30 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
 #include "auth/Gadgets.h"
 #include "auth/Config.h"
 
-Vector<AuthScheme*> *AuthScheme::_Schemes = NULL;
+Vector<AuthScheme::Pointer> *AuthScheme::_Schemes = NULL;
 
 void
-AuthScheme::AddScheme(AuthScheme &instance)
+AuthScheme::AddScheme(AuthScheme::Pointer instance)
 {
     iterator i = GetSchemes().begin();
 
     while (i != GetSchemes().end()) {
-        assert(strcmp((*i)->type(), instance.type()) != 0);
+        assert(strcmp((*i)->type(), instance->type()) != 0);
         ++i;
     }
 
-    GetSchemes().push_back (&instance);
+    GetSchemes().push_back(instance);
 }
 
-AuthScheme *
+AuthScheme::Pointer
 AuthScheme::Find(const char *typestr)
 {
     for (iterator i = GetSchemes().begin(); i != GetSchemes().end(); ++i) {
@@ -62,33 +61,32 @@ AuthScheme::Find(const char *typestr)
             return *i;
     }
 
-    return NULL;
-}
-
-Vector<AuthScheme *> const &
-AuthScheme::Schemes()
-{
-    return GetSchemes();
+    return AuthScheme::Pointer(NULL);
 }
 
-Vector<AuthScheme*> &
+Vector<AuthScheme::Pointer> &
 AuthScheme::GetSchemes()
 {
     if (!_Schemes)
-        _Schemes = new Vector<AuthScheme *>;
+        _Schemes = new Vector<AuthScheme::Pointer>;
 
     return *_Schemes;
 }
 
-/*
- * called when a graceful shutdown is to occur
- * of each scheme module.
+/**
+ * Called when a graceful shutdown is to occur of each scheme module.
+ * On completion the auth components are to be considered deleted.
+ * None will be available globally. Some may remain around for their
+ * currently active connections to close, but only those active
+ * connections will retain pointers to them.
  */
 void
 AuthScheme::FreeAll()
 {
+//    assert(shutting_down);
+
     while (GetSchemes().size()) {
-        AuthScheme *scheme = GetSchemes().back();
+        AuthScheme::Pointer scheme = GetSchemes().back();
         GetSchemes().pop_back();
         scheme->done();
     }
index b7a277ffa3c165d6b64e056a6d4c22388e8c3175..12370ed4af3809e3080eae10cd97c384c6117ef8 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
 #ifndef SQUID_AUTHSCHEME_H
 #define SQUID_AUTHSCHEME_H
 
-#include "squid.h"
+#include "config.h"
 #include "Array.h"
+#include "RefCount.h"
+
+class AuthConfig;
 
 /**
  \defgroup AuthSchemeAPI       Authentication Scheme API
  */
 
 /**
- \ingroup AuthAPI
- \ingroup AuthSchemeAPI
- \par
\ingroup AuthAPI
\ingroup AuthSchemeAPI
\par
  * I represent an authentication scheme. For now my children
- * store both the scheme metadata, and the scheme configuration.
- \par
+ * store the scheme metadata.
\par
  * Should we need multiple configs of a single scheme,
  * a new class AuthConfiguration should be made, and the
  * config specific calls on AuthScheme moved to it.
  */
-class AuthScheme
+class AuthScheme : public RefCountable
 {
+public:
+    typedef RefCount<AuthScheme> Pointer;
+    typedef Vector<AuthScheme::Pointer>::iterator iterator;
+    typedef Vector<AuthScheme::Pointer>::const_iterator const_iterator;
 
 public:
-    static void AddScheme(AuthScheme &);
+    AuthScheme() : initialised (false) {};
+    virtual ~AuthScheme() {};
+
+    static void AddScheme(AuthScheme::Pointer);
+
+    /**
+     * Final termination of all authentication components.
+     * To be used only on shutdown. All global pointers are released.
+     * After this all schemes will appear completely unsupported
+     * until a call to InitAuthModules().
+     * Release the Auth::TheConfig handles instead to disable authentication
+     * without terminiating all support.
+     */
     static void FreeAll();
-    static Vector<AuthScheme*> const &Schemes();
-    static AuthScheme *Find(const char *);
-    typedef Vector<AuthScheme*>::iterator iterator;
-    typedef Vector<AuthScheme*>::const_iterator const_iterator;
-    AuthScheme() : initialised (false) {}
 
-    virtual ~AuthScheme() {}
+    /**
+     * Locate an authentication scheme component by Name.
+     */
+    static AuthScheme::Pointer Find(const char *);
 
     /* per scheme methods */
     virtual char const *type () const = 0;
     virtual void done() = 0;
     virtual AuthConfig *createConfig() = 0;
+
     // Not implemented
     AuthScheme(AuthScheme const &);
     AuthScheme &operator=(AuthScheme const&);
 
+    static Vector<AuthScheme::Pointer> &GetSchemes();
+
 protected:
     bool initialised;
 
 private:
-    static Vector<AuthScheme*> &GetSchemes();
-    static Vector<AuthScheme*> *_Schemes;
+    static Vector<AuthScheme::Pointer> *_Schemes;
 };
 
 #endif /* SQUID_AUTHSCHEME_H */
diff --git a/src/auth/State.cc b/src/auth/State.cc
new file mode 100644 (file)
index 0000000..375bd23
--- /dev/null
@@ -0,0 +1,11 @@
+#include "config.h"
+#include "auth/State.h"
+
+CBDATA_GLOBAL_TYPE(authenticateStateData);
+
+void
+authenticateStateFree(authenticateStateData * r)
+{
+    r->auth_user_request = NULL;
+    cbdataFree(r);
+}
diff --git a/src/auth/State.h b/src/auth/State.h
new file mode 100644 (file)
index 0000000..cd19e72
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __AUTH_AUTHENTICATE_STATE_T__
+#define __AUTH_AUTHENTICATE_STATE_T__
+
+#include "auth/UserRequest.h"
+
+/**
+ * CBDATA state for NTLM, Negotiate, and Digest stateful authentication.
+ */
+typedef struct {
+    void *data;
+    AuthUserRequest::Pointer auth_user_request;
+    RH *handler;
+} authenticateStateData;
+
+extern CBDATA_GLOBAL_TYPE(authenticateStateData);
+
+extern void authenticateStateFree(authenticateStateData * r);
+
+#endif /* __AUTH_AUTHENTICATE_STATE_T__ */
index c95ab0db75933b11a49205e01525a86e1b5dccff..1dc586902b957c5306a2835294775e1e7b8322a4 100644 (file)
 #include "acl/Gadgets.h"
 #include "event.h"
 #include "SquidTime.h"
+#include "Store.h"
 
 #if !_USE_INLINE_
 #include "auth/User.cci"
 #endif
 
 // This should be converted into a pooled type. Does not need to be cbdata
-CBDATA_TYPE(auth_user_ip_t);
+CBDATA_TYPE(AuthUserIP);
 
-AuthUser::AuthUser (AuthConfig *aConfig) :
-        auth_type (AUTH_UNKNOWN), config(aConfig),
-        usernamehash (NULL), ipcount (0), expiretime (0), references (0), username_(NULL)
+time_t AuthUser::last_discard = 0;
+
+char *CredentialsState_str[] = { "Unchecked", "Ok", "Pending", "Handshake", "Failed" };
+
+
+AuthUser::AuthUser(AuthConfig *aConfig) :
+        auth_type(AUTH_UNKNOWN),
+        config(aConfig),
+        ipcount(0),
+        expiretime(0),
+       credentials_state(Unchecked),
+        username_(NULL)
 {
     proxy_auth_list.head = proxy_auth_list.tail = NULL;
     proxy_match_cache.head = proxy_match_cache.tail = NULL;
     ip_list.head = ip_list.tail = NULL;
-    requests.head = requests.tail = NULL;
-    debugs(29, 5, "AuthUser::AuthUser: Initialised auth_user '" << this << "' with refcount '" << references << "'.");
+    debugs(29, 5, "AuthUser::AuthUser: Initialised auth_user '" << this << "'.");
+}
+
+AuthUser::CredentialsState
+AuthUser::credentials() const
+{
+    return credentials_state;
 }
 
-/* Combine two user structs. ONLY to be called from within a scheme
+void
+AuthUser::credentials(CredentialsState newCreds)
+{
+    credentials_state = newCreds;
+}
+
+
+/**
+ * Combine two user structs. ONLY to be called from within a scheme
  * module. The scheme module is responsible for ensuring that the
  * two users _can_ be merged without invalidating all the request
  * scheme data. The scheme is also responsible for merging any user
  * related scheme data itself.
  */
 void
-AuthUser::absorb (AuthUser *from)
+AuthUser::absorb(AuthUser::Pointer from)
 {
-    AuthUserRequest *auth_user_request;
+
+    /* RefCount children CANNOT be merged like this. The external AuthUser::Pointer's cannot be changed. */
+
+    /* check that we only have the two references:
+     * 1) our function scope
+     * 2) the parsing function scope)
+     */
+    assert(from->RefCountCount() == 2);
+
     /*
-     * XXX combine two authuser structs. Incomplete: it should merge
-     * in hash references too and ask the module to merge in scheme
-     * data
+     * XXX Incomplete: it should merge in hash references too and ask the module to merge in scheme data
+     *  dlink_list proxy_auth_list;
+     *  dlink_list proxy_match_cache;
      */
+
     debugs(29, 5, "authenticateAuthUserMerge auth_user '" << from << "' into auth_user '" << this << "'.");
-    dlink_node *link = from->requests.head;
-
-    while (link) {
-        auth_user_request = static_cast<AuthUserRequest *>(link->data);
-        dlink_node *tmplink = link;
-        link = link->next;
-        dlinkDelete(tmplink, &from->requests);
-        dlinkAddTail(auth_user_request, tmplink, &requests);
-        auth_user_request->user(this);
-    }
 
-    references += from->references;
-    from->references = 0;
-    delete from;
+    /* absorb the list of IP address sources (for max_user_ip controls) */
+    AuthUserIP *new_ipdata;
+    while (from->ip_list.head != NULL) {
+        new_ipdata = static_cast<AuthUserIP *>(from->ip_list.head->data);
+
+        /* If this IP has expired - ignore the expensive merge actions. */
+        if (new_ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) {
+            /* This IP has expired - remove from the source list */
+            dlinkDelete(&new_ipdata->node, &(from->ip_list));
+            cbdataFree(new_ipdata);
+            /* catch incipient underflow */
+            from->ipcount--;
+        } else {
+            /* add to our list. replace if already present. */
+            AuthUserIP *ipdata = static_cast<AuthUserIP *>(ip_list.head->data);
+            bool found = false;
+            while (ipdata) {
+                AuthUserIP *tempnode = static_cast<AuthUserIP *>(ipdata->node.next->data);
+
+                if (ipdata->ipaddr == new_ipdata->ipaddr) {
+                    /* This IP has already been seen. */
+                    found = true;
+                    /* update IP ttl and stop searching. */
+                    ipdata->ip_expiretime = max(ipdata->ip_expiretime, new_ipdata->ip_expiretime);
+                    break;
+                } else if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) {
+                    /* This IP has expired - cleanup the destination list */
+                    dlinkDelete(&ipdata->node, &ip_list);
+                    cbdataFree(ipdata);
+                    /* catch incipient underflow */
+                    assert(ipcount);
+                    ipcount--;
+                }
+
+                ipdata = tempnode;
+            }
+
+            if (!found) {
+                /* This ip is not in the seen list. Add it. */
+                dlinkAddTail(&new_ipdata->node, &ipdata->node, &ip_list);
+                ipcount++;
+                /* remove from the source list */
+                dlinkDelete(&new_ipdata->node, &(from->ip_list));
+                from->ipcount--;
+            }
+        }
+    }
 }
 
 AuthUser::~AuthUser()
 {
-    AuthUserRequest *auth_user_request;
-    dlink_node *link, *tmplink;
-    debugs(29, 5, "AuthUser::~AuthUser: Freeing auth_user '" << this << "' with refcount '" << references << "'.");
-    assert(references == 0);
-    /* were they linked in by username ? */
-
-    if (usernamehash) {
-        assert(usernamehash->user() == this);
-        debugs(29, 5, "AuthUser::~AuthUser: removing usernamehash entry '" << usernamehash << "'");
-        hash_remove_link(proxy_auth_username_cache,
-                         (hash_link *) usernamehash);
-        /* don't free the key as we use the same user string as the auth_user
-         * structure */
-        delete usernamehash;
-    }
-
-    /* remove any outstanding requests */
-    link = requests.head;
-
-    while (link) {
-        debugs(29, 5, "AuthUser::~AuthUser: removing request entry '" << link->data << "'");
-        auth_user_request = static_cast<AuthUserRequest *>(link->data);
-        tmplink = link;
-        link = link->next;
-        dlinkDelete(tmplink, &requests);
-        dlinkNodeDelete(tmplink);
-        delete auth_user_request;
-    }
+    debugs(29, 5, "AuthUser::~AuthUser: Freeing auth_user '" << this << "'.");
+    assert(RefCountCount() == 0);
 
     /* free cached acl results */
     aclCacheMatchFlush(&proxy_match_cache);
@@ -142,10 +182,10 @@ AuthUser::cacheInit(void)
 {
     if (!proxy_auth_username_cache) {
         /* First time around, 7921 should be big enough */
-        proxy_auth_username_cache =
-            hash_create((HASHCMP *) strcmp, 7921, hash_string);
+        proxy_auth_username_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
         assert(proxy_auth_username_cache);
         eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
+        last_discard = squid_curtime;
     }
 }
 
@@ -153,21 +193,17 @@ void
 AuthUser::CachedACLsReset()
 {
     /*
-     * We walk the hash by username as that is the unique key we use.
      * This must complete all at once, because we are ensuring correctness.
      */
     AuthUserHashPointer *usernamehash;
-    AuthUser *auth_user;
-    char const *username = NULL;
+    AuthUser::Pointer auth_user;
     debugs(29, 3, "AuthUser::CachedACLsReset: Flushing the ACL caches for all users.");
     hash_first(proxy_auth_username_cache);
 
     while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
         auth_user = usernamehash->user();
-        username = auth_user->username();
         /* free cached acl results */
         aclCacheMatchFlush(&auth_user->proxy_match_cache);
-
     }
 
     debugs(29, 3, "AuthUser::CachedACLsReset: Finished.");
@@ -182,7 +218,7 @@ AuthUser::cacheCleanup(void *datanotused)
      * entries at a time. Lets see how it flys first.
      */
     AuthUserHashPointer *usernamehash;
-    AuthUser *auth_user;
+    AuthUser::Pointer auth_user;
     char const *username = NULL;
     debugs(29, 3, "AuthUser::cacheCleanup: Cleaning the user cache now");
     debugs(29, 3, "AuthUser::cacheCleanup: Current time: " << current_time.tv_sec);
@@ -192,40 +228,40 @@ AuthUser::cacheCleanup(void *datanotused)
         auth_user = usernamehash->user();
         username = auth_user->username();
 
-        /* if we need to have inpedendent expiry clauses, insert a module call
+        /* if we need to have indedendent expiry clauses, insert a module call
          * here */
         debugs(29, 4, "AuthUser::cacheCleanup: Cache entry:\n\tType: " <<
                auth_user->auth_type << "\n\tUsername: " << username <<
                "\n\texpires: " <<
                (long int) (auth_user->expiretime + Config.authenticateTTL) <<
-               "\n\treferences: " << (long int) auth_user->references);
+               "\n\treferences: " << (long int) auth_user->RefCountCount());
 
         if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
             debugs(29, 5, "AuthUser::cacheCleanup: Removing user " << username << " from cache due to timeout.");
-            /* the minus 1 accounts for the cache lock */
-
-            if (!(authenticateAuthUserInuse(auth_user) - 1))
-                /* we don't warn if we leave the user in the cache,
-                 * because other modules (ie delay pools) may keep
-                 * locks on users, and thats legitimate
-                 */
-                auth_user->unlock();
+
+            /* Old credentials are always removed. Existing users must hold their own
+             * AuthUser::Pointer to the credentials. Cache exists only for finding
+             * and re-using current valid credentials.
+             */
+            hash_remove_link(proxy_auth_username_cache, usernamehash);
+            delete usernamehash;
         }
     }
 
     debugs(29, 3, "AuthUser::cacheCleanup: Finished cleaning the user cache.");
     eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
+    last_discard = squid_curtime;
 }
 
 void
 AuthUser::clearIp()
 {
-    auth_user_ip_t *ipdata, *tempnode;
+    AuthUserIP *ipdata, *tempnode;
 
-    ipdata = (auth_user_ip_t *) ip_list.head;
+    ipdata = (AuthUserIP *) ip_list.head;
 
     while (ipdata) {
-        tempnode = (auth_user_ip_t *) ipdata->node.next;
+        tempnode = (AuthUserIP *) ipdata->node.next;
         /* walk the ip list */
         dlinkDelete(&ipdata->node, &ip_list);
         cbdataFree(ipdata);
@@ -242,7 +278,7 @@ AuthUser::clearIp()
 void
 AuthUser::removeIp(Ip::Address ipaddr)
 {
-    auth_user_ip_t *ipdata = (auth_user_ip_t *) ip_list.head;
+    AuthUserIP *ipdata = (AuthUserIP *) ip_list.head;
 
     while (ipdata) {
         /* walk the ip list */
@@ -257,7 +293,7 @@ AuthUser::removeIp(Ip::Address ipaddr)
             return;
         }
 
-        ipdata = (auth_user_ip_t *) ipdata->node.next;
+        ipdata = (AuthUserIP *) ipdata->node.next;
     }
 
 }
@@ -265,10 +301,10 @@ AuthUser::removeIp(Ip::Address ipaddr)
 void
 AuthUser::addIp(Ip::Address ipaddr)
 {
-    auth_user_ip_t *ipdata = (auth_user_ip_t *) ip_list.head;
+    AuthUserIP *ipdata = (AuthUserIP *) ip_list.head;
     int found = 0;
 
-    CBDATA_INIT_TYPE(auth_user_ip_t);
+    CBDATA_INIT_TYPE(AuthUserIP);
 
     /*
      * we walk the entire list to prevent the first item in the list
@@ -276,7 +312,7 @@ AuthUser::addIp(Ip::Address ipaddr)
      * a timeout+reconfigure
      */
     while (ipdata) {
-        auth_user_ip_t *tempnode = (auth_user_ip_t *) ipdata->node.next;
+        AuthUserIP *tempnode = (AuthUserIP *) ipdata->node.next;
         /* walk the ip list */
 
         if (ipdata->ipaddr == ipaddr) {
@@ -300,7 +336,7 @@ AuthUser::addIp(Ip::Address ipaddr)
         return;
 
     /* This ip is not in the seen list */
-    ipdata = cbdataAlloc(auth_user_ip_t);
+    ipdata = cbdataAlloc(AuthUserIP);
 
     ipdata->ip_expiretime = squid_curtime;
 
@@ -313,37 +349,47 @@ AuthUser::addIp(Ip::Address ipaddr)
     debugs(29, 2, "authenticateAuthUserAddIp: user '" << username() << "' has been seen at a new IP address (" << ipaddr << ")");
 }
 
-
+/**
+ * Add the AuthUser structure to the username cache.
+ */
 void
-AuthUser::lock()
+AuthUser::addToNameCache()
 {
-    debugs(29, 9, "authenticateAuthUserLock auth_user '" << this << "'.");
-    assert(this != NULL);
-    references++;
-    debugs(29, 9, "authenticateAuthUserLock auth_user '" << this << "' now at '" << references << "'.");
+    /* AuthUserHashPointer will self-register with the username cache */
+    new AuthUserHashPointer(this);
 }
 
+/**
+ * Dump the username cache statictics for viewing...
+ */
 void
-AuthUser::unlock()
+AuthUser::UsernameCacheStats(StoreEntry *output)
 {
-    debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "'.");
-    assert(this != NULL);
+    AuthUserHashPointer *usernamehash;
 
-    if (references > 0) {
-        references--;
-    } else {
-        debugs(29, 1, "Attempt to lower Auth User " << this << " refcount below 0!");
-    }
+    /* overview of username cache */
+    storeAppendPrintf(output, "Cached Usernames: %d of %d\n", proxy_auth_username_cache->count, proxy_auth_username_cache->size);
+    storeAppendPrintf(output, "Next Garbage Collection in %d seconds.\n", static_cast<int32_t>(last_discard + Config.authenticateGCInterval - squid_curtime));
 
-    debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "' now at '" << references << "'.");
+    /* cache dump column titles */
+    storeAppendPrintf(output, "\n%-15s %-9s %-9s %-9s %s\n",
+                      "Type",
+                      "State",
+                      "Check TTL",
+                      "Cache TTL",
+                      "Username");
+    storeAppendPrintf(output, "--------------- --------- --------- --------- ------------------------------\n");
 
-    if (references == 0)
-        delete this;
-}
-
-/* addToNameCache: add a auth_user structure to the username cache */
-void
-AuthUser::addToNameCache()
-{
-    usernamehash = new AuthUserHashPointer (this);
+    hash_first(proxy_auth_username_cache);
+    while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
+        AuthUser::Pointer auth_user = usernamehash->user();
+
+        storeAppendPrintf(output, "%-15s %-9s %-9d %-9d %s\n",
+                          AuthType_str[auth_user->auth_type],
+                          CredentialsState_str[auth_user->credentials()],
+                          auth_user->ttl(),
+                          static_cast<int32_t>(auth_user->expiretime - squid_curtime + Config.authenticateTTL),
+                          auth_user->username()
+                          );
+    }
 }
index 38ce96511f8966960785bb752671a87aa0903d26..f7d31b38450c70a3dfca460cd41490542b2d7d10 100644 (file)
@@ -47,7 +47,7 @@ AuthUser::username () const
 }
 
 void
-AuthUser::username(char const*aString)
+AuthUser::username(char const *aString)
 {
     if (aString) {
         assert(!username_);
@@ -56,14 +56,3 @@ AuthUser::username(char const*aString)
         safe_free(username_);
     }
 }
-
-void
-AuthUser::addRequest(AuthUserRequest *request)
-{
-    /* lock for the request link */
-
-    lock();
-    dlink_node *node = dlinkNodeNew();
-
-    dlinkAdd(request, node, &requests);
-}
index 84a233dc9b8bdae7980281a65f3bc7a31673273e..1a56933590126c95e0b4cb20f4b84fd8c1c337e6 100644 (file)
 #ifndef SQUID_AUTHUSER_H
 #define SQUID_AUTHUSER_H
 
-class AuthUserRequest;
+#include "auth/AuthType.h"
+#include "dlink.h"
+#include "ip/Address.h"
+#include "RefCount.h"
+
 class AuthConfig;
 class AuthUserHashPointer;
-
-/* for auth_type_t */
-#include "enums.h"
-
-#include "ip/Address.h"
-#include "dlink.h"
+class StoreEntry;
 
 /**
  *  \ingroup AuthAPI
@@ -52,53 +51,71 @@ class AuthUserHashPointer;
  * structure is the cached ACL match results. This structure, is private to
  * the authentication framework.
  */
-class AuthUser
+class AuthUser : public RefCountable
 {
-
 public:
+    typedef RefCount<AuthUser> Pointer;
+
     /* extra fields for proxy_auth */
     /* auth_type and auth_module are deprecated. Do Not add new users of these fields.
      * Aim to remove shortly
      */
     /** \deprecated this determines what scheme owns the user data. */
-    auth_type_t auth_type;
+    AuthType auth_type;
     /** the config for this user */
     AuthConfig *config;
-    /** we only have one username associated with a given auth_user struct */
-    AuthUserHashPointer *usernamehash;
     /** we may have many proxy-authenticate strings that decode to the same user */
     dlink_list proxy_auth_list;
     dlink_list proxy_match_cache;
     size_t ipcount;
     long expiretime;
-    /** how many references are outstanding to this instance */
-    size_t references;
-    /** the auth_user_request structures that link to this. Yes it could be a splaytree
-     * but how many requests will a single username have in parallel? */
-    dlink_list requests;
 
     static void cacheInit();
     static void CachedACLsReset();
 
-    void absorb(AuthUser *from);
+    void absorb(AuthUser::Pointer from);
     virtual ~AuthUser();
     _SQUID_INLINE_ char const *username() const;
     _SQUID_INLINE_ void username(char const *);
+
+    /**
+     * How long these credentials are still valid for.
+     * Negative numbers means already expired.
+     */
+    virtual int32_t ttl() const = 0;
+
+    /* Manage list of IPs using this username */
     void clearIp();
     void removeIp(Ip::Address);
     void addIp(Ip::Address);
-    _SQUID_INLINE_ void addRequest(AuthUserRequest *);
-
-    void lock();
-    void unlock();
 
     void addToNameCache();
+    static void UsernameCacheStats(StoreEntry * output);
+
+    enum CredentialsState { Unchecked, Ok, Pending, Handshake, Failed };
+    CredentialsState credentials() const;
+    void credentials(CredentialsState);
+
+private:
+    /**
+     * The current state these credentials are in:
+     *   Unchecked
+     *   Authenticated
+     *   Pending helper result
+     *   Handshake happening in stateful auth.
+     *   Failed auth
+     */
+    CredentialsState credentials_state;
 
 protected:
-    AuthUser (AuthConfig *);
+    AuthUser(AuthConfig *);
 
 private:
-    static void cacheCleanup (void *unused);
+    /**
+     * Garbage Collection for the username cache.
+     */
+    static void cacheCleanup(void *unused);
+    static time_t last_discard; /// Time of last username cache garbage collection.
 
     /**
      * DPW 2007-05-08
@@ -111,6 +128,8 @@ private:
     dlink_list ip_list;
 };
 
+extern char *CredentialsState_str[];
+
 #if _USE_INLINE_
 #include "auth/User.cci"
 #endif
index f936e1016f560b68aea60b0720aa8c05d93fd5e1..608574a015bcdd0573a1aadf359a8695de32ab61 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
 
 /* Generic Functions */
 
-size_t
-AuthUserRequest::refCount () const
-{
-    return references;
-}
-
 char const *
 AuthUserRequest::username() const
 {
-    if (user())
+    if (user() != NULL)
         return user()->username();
     else
         return NULL;
 }
 
-size_t
-authenticateRequestRefCount (AuthUserRequest *aRequest)
-{
-    return aRequest->refCount();
-}
-
 /**** PUBLIC FUNCTIONS (ALL GENERIC!)  ****/
 
 /* send the initial data to an authenticator module */
@@ -82,49 +69,36 @@ void
 AuthUserRequest::start(RH * handler, void *data)
 {
     assert(handler);
+    assert(data);
     debugs(29, 9, "authenticateStart: auth_user_request '" << this << "'");
     module_start(handler, data);
 }
 
-/*
- * Check a auth_user pointer for validity. Does not check passwords, just data
- * sensability. Broken or Unknown auth_types are not valid for use...
- */
-
-int
-authenticateValidateUser(AuthUserRequest * auth_user_request)
+bool
+AuthUserRequest::valid() const
 {
-    debugs(29, 9, "authenticateValidateUser: Validating Auth_user request '" << auth_user_request << "'.");
-
-    if (auth_user_request == NULL) {
-        debugs(29, 4, "authenticateValidateUser: Auth_user_request was NULL!");
-        return 0;
-    }
+    debugs(29, 9, HERE << "Validating AuthUserRequest '" << this << "'.");
 
-    if (auth_user_request->user() == NULL) {
-        debugs(29, 4, "authenticateValidateUser: No associated auth_user structure");
-        return 0;
+    if (user() == NULL) {
+        debugs(29, 4, HERE << "No associated AuthUser data");
+        return false;
     }
 
-    if (auth_user_request->user()->auth_type == AUTH_UNKNOWN) {
-        debugs(29, 4, "authenticateValidateUser: Auth_user '" << auth_user_request->user() << "' uses unknown scheme.");
-        return 0;
+    if (user()->auth_type == AUTH_UNKNOWN) {
+        debugs(29, 4, HERE << "AuthUser '" << user() << "' uses unknown scheme.");
+        return false;
     }
 
-    if (auth_user_request->user()->auth_type == AUTH_BROKEN) {
-        debugs(29, 4, "authenticateValidateUser: Auth_user '" << auth_user_request->user() << "' is broken for it's scheme.");
-        return 0;
+    if (user()->auth_type == AUTH_BROKEN) {
+        debugs(29, 4, HERE << "AuthUser '" << user() << "' is broken for it's scheme.");
+        return false;
     }
 
     /* any other sanity checks that we need in the future */
 
-    /* Thus should a module call to something like authValidate */
-
     /* finally return ok */
-    debugs(29, 5, "authenticateValidateUser: Validated Auth_user request '" << auth_user_request << "'.");
-
-    return 1;
-
+    debugs(29, 5, HERE << "Validated. AuthUserRequest '" << this << "'.");
+    return true;
 }
 
 void *
@@ -140,51 +114,36 @@ AuthUserRequest::operator delete (void *address)
     fatal ("AuthUserRequest child failed to override operator delete\n");
 }
 
-AuthUserRequest::AuthUserRequest():_auth_user(NULL), message(NULL),
-        references (0), lastReply (AUTH_ACL_CANNOT_AUTHENTICATE)
+AuthUserRequest::AuthUserRequest():
+        _auth_user(NULL),
+        message(NULL),
+        lastReply(AUTH_ACL_CANNOT_AUTHENTICATE)
 {
-    debugs(29, 5, "AuthUserRequest::AuthUserRequest: initialised request " <<
-           this);
+    debugs(29, 5, "AuthUserRequest::AuthUserRequest: initialised request " << this);
 }
 
 AuthUserRequest::~AuthUserRequest()
 {
-    dlink_node *link;
-    debugs(29, 5, "AuthUserRequest::~AuthUserRequest: freeing request " <<
-           this);
-    assert(references == 0);
-
-    if (user()) {
-        /* unlink from the auth_user struct */
-        link = user()->requests.head;
-
-        while (link && (link->data != this))
-            link = link->next;
-
-        assert(link != NULL);
-
-        dlinkDelete(link, &user()->requests);
-
-        dlinkNodeDelete(link);
-
-        /* unlock the request structure's lock */
-        user()->unlock();
+    assert(RefCountCount()==0);
+    debugs(29, 5, "AuthUserRequest::~AuthUserRequest: freeing request " << this);
 
+    if (user() != NULL) {
+        /* release our references to the user credentials */
         user(NULL);
     }
 
-    safe_free (message);
+    safe_free(message);
 }
 
 void
-AuthUserRequest::setDenyMessage (char const *aString)
+AuthUserRequest::setDenyMessage(char const *aString)
 {
-    safe_free (message);
-    message = xstrdup (aString);
+    safe_free(message);
+    message = xstrdup(aString);
 }
 
 char const *
-AuthUserRequest::getDenyMessage ()
+AuthUserRequest::getDenyMessage()
 {
     return message;
 }
@@ -200,9 +159,9 @@ AuthUserRequest::denyMessage(char const * const default_message)
 }
 
 static void
-authenticateAuthUserRequestSetIp(AuthUserRequest * auth_user_request, Ip::Address &ipaddr)
+authenticateAuthUserRequestSetIp(AuthUserRequest::Pointer auth_user_request, Ip::Address &ipaddr)
 {
-    AuthUser *auth_user = auth_user_request->user();
+    AuthUser::Pointer auth_user = auth_user_request->user();
 
     if (!auth_user)
         return;
@@ -211,9 +170,9 @@ authenticateAuthUserRequestSetIp(AuthUserRequest * auth_user_request, Ip::Addres
 }
 
 void
-authenticateAuthUserRequestRemoveIp(AuthUserRequest * auth_user_request, Ip::Address const &ipaddr)
+authenticateAuthUserRequestRemoveIp(AuthUserRequest::Pointer auth_user_request, Ip::Address const &ipaddr)
 {
-    AuthUser *auth_user = auth_user_request->user();
+    AuthUser::Pointer auth_user = auth_user_request->user();
 
     if (!auth_user)
         return;
@@ -222,17 +181,17 @@ authenticateAuthUserRequestRemoveIp(AuthUserRequest * auth_user_request, Ip::Add
 }
 
 void
-authenticateAuthUserRequestClearIp(AuthUserRequest * auth_user_request)
+authenticateAuthUserRequestClearIp(AuthUserRequest::Pointer auth_user_request)
 {
-    if (auth_user_request)
+    if (auth_user_request != NULL)
         auth_user_request->user()->clearIp();
 }
 
 int
-authenticateAuthUserRequestIPCount(AuthUserRequest * auth_user_request)
+authenticateAuthUserRequestIPCount(AuthUserRequest::Pointer auth_user_request)
 {
-    assert(auth_user_request);
-    assert(auth_user_request->user());
+    assert(auth_user_request != NULL);
+    assert(auth_user_request->user() != NULL);
     return auth_user_request->user()->ipcount;
 }
 
@@ -241,9 +200,9 @@ authenticateAuthUserRequestIPCount(AuthUserRequest * auth_user_request)
  * authenticateUserAuthenticated: is this auth_user structure logged in ?
  */
 int
-authenticateUserAuthenticated(AuthUserRequest * auth_user_request)
+authenticateUserAuthenticated(AuthUserRequest::Pointer auth_user_request)
 {
-    if (!authenticateValidateUser(auth_user_request))
+    if (auth_user_request == NULL || !auth_user_request->valid())
         return 0;
 
     return auth_user_request->authenticated();
@@ -286,19 +245,19 @@ AuthUserRequest::connLastHeader()
  * This is basically a handle approach.
  */
 static void
-authenticateAuthenticateUser(AuthUserRequest * auth_user_request, HttpRequest * request, ConnStateData * conn, http_hdr_type type)
+authenticateAuthenticateUser(AuthUserRequest::Pointer auth_user_request, HttpRequest * request, ConnStateData * conn, http_hdr_type type)
 {
-    assert(auth_user_request != NULL);
+    assert(auth_user_request.getRaw() != NULL);
 
     auth_user_request->authenticate(request, conn, type);
 }
 
-static AuthUserRequest *
-authTryGetUser (AuthUserRequest **auth_user_request, ConnStateData * conn, HttpRequest * request)
+static AuthUserRequest::Pointer
+authTryGetUser(AuthUserRequest::Pointer auth_user_request, ConnStateData * conn, HttpRequest * request)
 {
-    if (*auth_user_request)
-        return *auth_user_request;
-    else if (request != NULL && request->auth_user_request)
+    if (auth_user_request != NULL)
+        return auth_user_request;
+    else if (request != NULL && request->auth_user_request != NULL)
         return request->auth_user_request;
     else if (conn != NULL)
         return conn->auth_user_request;
@@ -327,8 +286,8 @@ authTryGetUser (AuthUserRequest **auth_user_request, ConnStateData * conn, HttpR
  *
  * Caller is responsible for locking and unlocking their *auth_user_request!
  */
-auth_acl_t
-AuthUserRequest::authenticate(AuthUserRequest ** auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr)
+AuthAclState
+AuthUserRequest::authenticate(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr)
 {
     const char *proxy_auth;
     assert(headertype != 0);
@@ -342,15 +301,16 @@ AuthUserRequest::authenticate(AuthUserRequest ** auth_user_request, http_hdr_typ
      * connection when we recieve no authentication header.
      */
 
-    if (((proxy_auth == NULL) && (!authenticateUserAuthenticated(authTryGetUser(auth_user_request,conn,request))))
-            || (conn != NULL  && conn->auth_type == AUTH_BROKEN)) {
+    /* a) can we find other credentials to use? and b) are they logged in already? */
+    if (proxy_auth == NULL && !authenticateUserAuthenticated(authTryGetUser(*auth_user_request,conn,request))) {
         /* no header or authentication failed/got corrupted - restart */
-        debugs(29, 4, "authenticateAuthenticate: broken auth or no proxy_auth header. Requesting auth header.");
+        debugs(29, 4, HERE << "No Proxy-Auth header and no working alternative. Requesting auth header.");
+
         /* something wrong with the AUTH credentials. Force a new attempt */
 
+        /* connection auth we must reset on auth errors */
         if (conn != NULL) {
-            conn->auth_type = AUTH_UNKNOWN;
-            AUTHUSERREQUESTUNLOCK(conn->auth_user_request, "conn");
+            conn->auth_user_request = NULL;
         }
 
         *auth_user_request = NULL;
@@ -362,84 +322,75 @@ AuthUserRequest::authenticate(AuthUserRequest ** auth_user_request, http_hdr_typ
      * No check for function required in the if: its compulsory for conn based
      * auth modules
      */
-    if (proxy_auth && conn != NULL && conn->auth_user_request &&
+    if (proxy_auth && conn != NULL && conn->auth_user_request != NULL &&
             authenticateUserAuthenticated(conn->auth_user_request) &&
             conn->auth_user_request->connLastHeader() != NULL &&
             strcmp(proxy_auth, conn->auth_user_request->connLastHeader())) {
-        debugs(29, 2, "authenticateAuthenticate: DUPLICATE AUTH - authentication header on already authenticated connection!. AU " <<
+        debugs(29, 2, "WARNING: DUPLICATE AUTH - authentication header on already authenticated connection!. AU " <<
                conn->auth_user_request << ", Current user '" <<
                conn->auth_user_request->username() << "' proxy_auth " <<
                proxy_auth);
 
-        /* remove this request struct - the link is already authed and it can't be to
-         * reauth.
-         */
+        /* remove this request struct - the link is already authed and it can't be to reauth. */
 
         /* This should _only_ ever occur on the first pass through
          * authenticateAuthenticate
          */
         assert(*auth_user_request == NULL);
-        AUTHUSERREQUESTUNLOCK(conn->auth_user_request, "conn");
-        /* Set the connection auth type */
-        conn->auth_type = AUTH_UNKNOWN;
+        conn->auth_user_request = NULL;
     }
 
     /* we have a proxy auth header and as far as we know this connection has
      * not had bungled connection oriented authentication happen on it. */
-    debugs(29, 9, "authenticateAuthenticate: header " << (proxy_auth ? proxy_auth : "-") << ".");
+    debugs(29, 9, HERE << "header " << (proxy_auth ? proxy_auth : "-") << ".");
 
     if (*auth_user_request == NULL) {
-        debugs(29, 9, "authenticateAuthenticate: This is a new checklist test on FD:" << (conn != NULL ? conn->fd : -1)  );
+        debugs(29, 9, HERE << "This is a new checklist test on FD:" << (conn != NULL ? conn->fd : -1)  );
 
-        if (proxy_auth && !request->auth_user_request && conn != NULL && conn->auth_user_request) {
+        if (proxy_auth && request->auth_user_request == NULL && conn != NULL && conn->auth_user_request != NULL) {
             AuthConfig * scheme = AuthConfig::Find(proxy_auth);
 
-            if (!conn->auth_user_request->user() || conn->auth_user_request->user()->config != scheme) {
-                debugs(29, 1, "authenticateAuthenticate: Unexpected change of authentication scheme from '" <<
+            if (conn->auth_user_request->user() == NULL || conn->auth_user_request->user()->config != scheme) {
+                debugs(29, 1, "WARNING: Unexpected change of authentication scheme from '" <<
                        conn->auth_user_request->user()->config->type() <<
                        "' to '" << proxy_auth << "' (client " <<
                        src_addr << ")");
 
-                AUTHUSERREQUESTUNLOCK(conn->auth_user_request, "conn");
-                conn->auth_type = AUTH_UNKNOWN;
+                conn->auth_user_request = NULL;
             }
         }
 
-        if ((!request->auth_user_request)
-                && (conn == NULL || conn->auth_type == AUTH_UNKNOWN)) {
+        if (request->auth_user_request == NULL && (conn == NULL || conn->auth_user_request == NULL)) {
             /* beginning of a new request check */
-            debugs(29, 4, "authenticateAuthenticate: no connection authentication type");
+            debugs(29, 4, HERE << "No connection authentication type");
 
             *auth_user_request = AuthConfig::CreateAuthUser(proxy_auth);
-            if (!authenticateValidateUser(*auth_user_request)) {
-                if (*auth_user_request == NULL)
-                    return AUTH_ACL_CHALLENGE;
-
+            if (*auth_user_request == NULL)
+                return AUTH_ACL_CHALLENGE;
+            else if (!(*auth_user_request)->valid()) {
                 /* the decode might have left a username for logging, or a message to
                  * the user */
 
                 if ((*auth_user_request)->username()) {
                     request->auth_user_request = *auth_user_request;
-                    AUTHUSERREQUESTLOCK(request->auth_user_request, "request");
                 }
 
                 *auth_user_request = NULL;
                 return AUTH_ACL_CHALLENGE;
             }
 
-            /* the user_request comes prelocked for the caller to createAuthUser (us) */
-        } else if (request->auth_user_request) {
+        } else if (request->auth_user_request != NULL) {
             *auth_user_request = request->auth_user_request;
         } else {
             assert (conn != NULL);
-            if (conn->auth_user_request) {
+            if (conn->auth_user_request != NULL) {
                 *auth_user_request = conn->auth_user_request;
             } else {
                 /* failed connection based authentication */
-                debugs(29, 4, "authenticateAuthenticate: Auth user request " <<
+                debugs(29, 4, HERE << "Auth user request " <<
                        *auth_user_request << " conn-auth user request " <<
                        conn->auth_user_request << " conn type " <<
-                       conn->auth_type << " authentication failed.");
+                       conn->auth_user_request->user()->auth_type << " authentication failed.");
 
                 *auth_user_request = NULL;
                 return AUTH_ACL_CHALLENGE;
@@ -449,16 +400,14 @@ AuthUserRequest::authenticate(AuthUserRequest ** auth_user_request, http_hdr_typ
 
     if (!authenticateUserAuthenticated(*auth_user_request)) {
         /* User not logged in. Log them in */
-        authenticateAuthenticateUser(*auth_user_request, request,
-                                     conn, headertype);
+        authenticateAuthenticateUser(*auth_user_request, request, conn, headertype);
 
         switch (authenticateDirection(*auth_user_request)) {
 
         case 1:
 
-            if (NULL == request->auth_user_request) {
+            if (request->auth_user_request == NULL) {
                 request->auth_user_request = *auth_user_request;
-                AUTHUSERREQUESTLOCK(request->auth_user_request, "request");
             }
 
             /* fallthrough to -2 */
@@ -481,7 +430,6 @@ AuthUserRequest::authenticate(AuthUserRequest ** auth_user_request, http_hdr_typ
             if ((*auth_user_request)->username()) {
                 if (!request->auth_user_request) {
                     request->auth_user_request = *auth_user_request;
-                    AUTHUSERREQUESTLOCK(request->auth_user_request, "request");
                 }
             }
 
@@ -492,41 +440,36 @@ AuthUserRequest::authenticate(AuthUserRequest ** auth_user_request, http_hdr_typ
 
     /* copy username to request for logging on client-side */
     /* the credentials are correct at this point */
-    if (NULL == request->auth_user_request) {
+    if (request->auth_user_request == NULL) {
         request->auth_user_request = *auth_user_request;
-        AUTHUSERREQUESTLOCK(request->auth_user_request, "request");
         authenticateAuthUserRequestSetIp(*auth_user_request, src_addr);
     }
 
     return AUTH_AUTHENTICATED;
 }
 
-auth_acl_t
-
-AuthUserRequest::tryToAuthenticateAndSetAuthUser(AuthUserRequest ** auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr)
+AuthAclState
+AuthUserRequest::tryToAuthenticateAndSetAuthUser(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr)
 {
     /* If we have already been called, return the cached value */
-    AuthUserRequest *t = authTryGetUser (auth_user_request, conn, request);
+    AuthUserRequest::Pointer t = authTryGetUser(*auth_user_request, conn, request);
 
-    if (t && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE
-            && t->lastReply != AUTH_ACL_HELPER) {
-        if (!*auth_user_request)
+    if (t != NULL && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE && t->lastReply != AUTH_ACL_HELPER) {
+        if (*auth_user_request == NULL)
             *auth_user_request = t;
 
-        if (!request->auth_user_request && t->lastReply == AUTH_AUTHENTICATED) {
+        if (request->auth_user_request == NULL && t->lastReply == AUTH_AUTHENTICATED) {
             request->auth_user_request = t;
-            AUTHUSERREQUESTLOCK(request->auth_user_request, "request");
         }
         return t->lastReply;
     }
 
     /* ok, call the actual authenticator routine. */
-    auth_acl_t result = authenticate(auth_user_request, headertype, request, conn, src_addr);
+    AuthAclState result = authenticate(auth_user_request, headertype, request, conn, src_addr);
 
-    t = authTryGetUser (auth_user_request, conn, request);
+    t = authTryGetUser(*auth_user_request, conn, request);
 
-    if (t && result != AUTH_ACL_CANNOT_AUTHENTICATE &&
-            result != AUTH_ACL_HELPER)
+    if (t != NULL && result != AUTH_ACL_CANNOT_AUTHENTICATE && result != AUTH_ACL_HELPER)
         t->lastReply = result;
 
     return result;
@@ -539,16 +482,16 @@ AuthUserRequest::tryToAuthenticateAndSetAuthUser(AuthUserRequest ** auth_user_re
  * -2: authenticate broken in some fashion
  */
 int
-authenticateDirection(AuthUserRequest * auth_user_request)
+authenticateDirection(AuthUserRequest::Pointer auth_user_request)
 {
-    if (!auth_user_request)
+    if (auth_user_request == NULL || auth_user_request->user() == NULL)
         return -2;
 
     return auth_user_request->direction();
 }
 
 void
-AuthUserRequest::addReplyAuthHeader(HttpReply * rep, AuthUserRequest * auth_user_request, HttpRequest * request, int accelerated, int internal)
+AuthUserRequest::addReplyAuthHeader(HttpReply * rep, AuthUserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal)
 /* send the auth types we are configured to support (and have compiled in!) */
 {
     http_hdr_type type;
@@ -585,7 +528,7 @@ AuthUserRequest::addReplyAuthHeader(HttpReply * rep, AuthUserRequest * auth_user
         else {
             /* call each configured & running authscheme */
 
-            for (authConfig::iterator  i = Config.authConfiguration.begin(); i != Config.authConfiguration.end(); ++i) {
+            for (Auth::authConfig::iterator  i = Auth::TheConfig.begin(); i != Auth::TheConfig.end(); ++i) {
                 AuthConfig *scheme = *i;
 
                 if (scheme->active())
@@ -609,7 +552,7 @@ AuthUserRequest::addReplyAuthHeader(HttpReply * rep, AuthUserRequest * auth_user
 }
 
 void
-authenticateFixHeader(HttpReply * rep, AuthUserRequest * auth_user_request, HttpRequest * request, int accelerated, int internal)
+authenticateFixHeader(HttpReply * rep, AuthUserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal)
 {
     AuthUserRequest::addReplyAuthHeader(rep, auth_user_request, request, accelerated, internal);
 }
@@ -617,41 +560,13 @@ authenticateFixHeader(HttpReply * rep, AuthUserRequest * auth_user_request, Http
 
 /* call the active auth module and allow it to add a trailer to the request */
 void
-authenticateAddTrailer(HttpReply * rep, AuthUserRequest * auth_user_request, HttpRequest * request, int accelerated)
+authenticateAddTrailer(HttpReply * rep, AuthUserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated)
 {
     if (auth_user_request != NULL)
         auth_user_request->addTrailer(rep, accelerated);
 }
 
-void
-
-AuthUserRequest::_lock()
-{
-    assert(this);
-    debugs(29, 9, "AuthUserRequest::lock: auth_user request '" << this << " " << references << "->" << references+1);
-    ++references;
-}
-
-void
-AuthUserRequest::_unlock()
-{
-    assert(this != NULL);
-
-    if (references > 0) {
-        debugs(29, 9, "AuthUserRequest::unlock: auth_user request '" << this << " " << references << "->" << references-1);
-        --references;
-    } else {
-        debugs(29, 1, "Attempt to lower Auth User request " << this << " refcount below 0!");
-    }
-
-    if (references == 0) {
-        debugs(29, 9, "AuthUserRequest::unlock: deleting auth_user_request '" << this << "'.");
-        /* not locked anymore */
-        delete this;
-    }
-}
-
-AuthScheme *
+AuthScheme::Pointer
 AuthUserRequest::scheme() const
 {
     /* TODO: this should be overriden by the child and be essentially a no-op */
index a08066626e76d112778c5a0c9df3cdccce58c792..c86d9cf00cca9fead95ab7bc7cd1578dac608654 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
 #ifndef SQUID_AUTHUSERREQUEST_H
 #define SQUID_AUTHUSERREQUEST_H
 
-#include "client_side.h"
-
-class AuthUser;
+#include "auth/AuthAclState.h"
+#include "auth/Scheme.h"
+#include "auth/User.h"
+#include "dlink.h"
+#include "ip/Address.h"
+#include "typedefs.h"
+#include "HttpHeader.h"
 
 class ConnStateData;
+class HttpReply;
+class HttpRequest;
 
-class AuthScheme;
-
-struct AuthUserIP {
+/// \ingroup AuthAPI
+class AuthUserIP
+{
+public:
     dlink_node node;
     /* IP addr this user authenticated from */
 
@@ -55,9 +61,14 @@ struct AuthUserIP {
 /**
  \ingroup AuthAPI
  * This is a short lived structure is the visible aspect of the authentication framework.
+ *
+ * It and its children hold the state data while processing authentication for a client request.
+ * The AuthenticationStateData object is merely a CBDATA wrapper for one of these.
  */
-class AuthUserRequest
+class AuthUserRequest : public RefCountable
 {
+public:
+    typedef RefCount<AuthUserRequest> Pointer;
 
 public:
     /**
@@ -65,7 +76,7 @@ public:
      * it has request specific data, and links to user specific data
      * the user
      */
-    AuthUser *_auth_user;
+    AuthUser::Pointer _auth_user;
 
     /**
      *  Used by squid to determine what the next step in performing authentication for a given scheme is.
@@ -86,6 +97,19 @@ public:
      \retval false     Timeouts on cached credentials have occurred or for any reason the credentials are not valid.
      */
     virtual int authenticated() const = 0;
+
+    /**
+     * Check a auth_user pointer for validity.
+     * Does not check passwords, just data sensability. Broken or Unknown auth_types are not valid for use...
+     *
+     * \retval false    User credentials are missing.
+     * \retval false    User credentials use an unknown scheme type.
+     * \retval false    User credentials are broken for their scheme.
+     *
+     * \retval true    User credentials exist and may be able to authenticate.
+     */
+    bool valid() const;
+
     virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type) = 0;
     /* template method */
     virtual int module_direction() = 0;
@@ -102,14 +126,14 @@ public:
      */
     virtual void module_start(RH *handler, void *data) = 0;
 
-    virtual AuthUser *user() {return _auth_user;}
+    virtual AuthUser::Pointer user() {return _auth_user;}
 
-    virtual const AuthUser *user() const {return _auth_user;}
+    virtual const AuthUser::Pointer user() const {return _auth_user;}
 
-    virtual void user(AuthUser *aUser) {_auth_user=aUser;}
+    virtual void user(AuthUser::Pointer aUser) {_auth_user=aUser;}
 
-    static auth_acl_t tryToAuthenticateAndSetAuthUser(AuthUserRequest **, http_hdr_type, HttpRequest *, ConnStateData *, Ip::Address &);
-    static void addReplyAuthHeader(HttpReply * rep, AuthUserRequest * auth_user_request, HttpRequest * request, int accelerated, int internal);
+    static AuthAclState tryToAuthenticateAndSetAuthUser(AuthUserRequest::Pointer *, http_hdr_type, HttpRequest *, ConnStateData *, Ip::Address &);
+    static void addReplyAuthHeader(HttpReply * rep, AuthUserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal);
 
     AuthUserRequest();
 
@@ -126,10 +150,6 @@ public:
     /** Possibly overrideable in future */
     char const * getDenyMessage();
 
-    size_t refCount() const;
-    void _lock();            /**< \note please use AUTHUSERREQUESTLOCK()   */
-    void _unlock();          /**< \note please use AUTHUSERREQUESTUNLOCK() */
-
     /**
      * Squid does not make assumptions about where the username is stored.
      * This function must return a pointer to a NULL terminated string to be used in logging the request.
@@ -140,64 +160,45 @@ public:
      */
     char const *username() const;
 
-    AuthScheme *scheme() const;
+    AuthScheme::Pointer scheme() const;
 
     virtual const char * connLastHeader();
 
 private:
 
-    static auth_acl_t authenticate(AuthUserRequest ** auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr);
+    static AuthAclState authenticate(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr);
 
     /** return a message on the 407 error pages */
     char *message;
 
-    /** how many 'processes' are working on this data */
-    size_t references;
-
     /**
      * We only attempt authentication once per http request. This
      * is to allow multiple auth acl references from different _access areas
      * when using connection based authentication
      */
-    auth_acl_t lastReply;
+    AuthAclState lastReply;
 };
 
 /* AuthUserRequest */
 
-/**
- \ingroup AuthAPI
- \deprecated Use AuthUserRequest::refCount() instead.
- */
-extern size_t authenticateRequestRefCount (AuthUserRequest *);
-
 /// \ingroup AuthAPI
-extern void authenticateFixHeader(HttpReply *, AuthUserRequest *, HttpRequest *, int, int);
+extern void authenticateFixHeader(HttpReply *, AuthUserRequest::Pointer, HttpRequest *, int, int);
 /// \ingroup AuthAPI
-extern void authenticateAddTrailer(HttpReply *, AuthUserRequest *, HttpRequest *, int);
+extern void authenticateAddTrailer(HttpReply *, AuthUserRequest::Pointer, HttpRequest *, int);
 
 /// \ingroup AuthAPI
-extern void authenticateAuthUserRequestRemoveIp(AuthUserRequest *, Ip::Address const &);
+extern void authenticateAuthUserRequestRemoveIp(AuthUserRequest::Pointer, Ip::Address const &);
 /// \ingroup AuthAPI
-extern void authenticateAuthUserRequestClearIp(AuthUserRequest *);
+extern void authenticateAuthUserRequestClearIp(AuthUserRequest::Pointer);
 /// \ingroup AuthAPI
-extern int authenticateAuthUserRequestIPCount(AuthUserRequest *);
+extern int authenticateAuthUserRequestIPCount(AuthUserRequest::Pointer);
 /// \ingroup AuthAPI
 /// \deprecated Use AuthUserRequest::direction() instead.
-extern int authenticateDirection(AuthUserRequest *);
+extern int authenticateDirection(AuthUserRequest::Pointer);
 
 /// \ingroup AuthAPI
 /// See AuthUserRequest::authenticated()
-extern int authenticateUserAuthenticated(AuthUserRequest *);
-/// \ingroup AuthAPI
-extern int authenticateValidateUser(AuthUserRequest *);
-
-/// \todo Drop dead code? or make a debugging option.
-#if 0
-#define AUTHUSERREQUESTUNLOCK(a,b) if(a){(a)->_unlock();debugs(0,0,HERE << "auth_user_request " << a << " was unlocked for " << b); (a)=NULL;}
-#define AUTHUSERREQUESTLOCK(a,b) { (a)->_lock(); debugs(0,0,HERE << "auth_user_request " << a << " was locked for " << b); }
-#endif
-#define AUTHUSERREQUESTUNLOCK(a,b) if(a){(a)->_unlock();(a)=NULL;}
-#define AUTHUSERREQUESTLOCK(a,b) (a)->_lock()
+extern int authenticateUserAuthenticated(AuthUserRequest::Pointer);
 
 
 #endif /* SQUID_AUTHUSERREQUEST_H */
index da99ba2e5232a6aa4819107d4d82c9dc2a073125..135c1c215748bcf3a4428c99a8522f8abbfd22fb 100644 (file)
 
 
 #include "squid.h"
-#include "auth_basic.h"
+#include "auth/basic/auth_basic.h"
+#include "auth/basic/basicScheme.h"
+#include "auth/basic/basicUserRequest.h"
 #include "auth/Gadgets.h"
+#include "auth/State.h"
 #include "CacheManager.h"
 #include "Store.h"
 #include "HttpReply.h"
-#include "basicScheme.h"
 #include "rfc1738.h"
 #include "wordlist.h"
 #include "SquidTime.h"
 
-static void
-authenticateStateFree(AuthenticateStateData * r)
-{
-    cbdataFree(r);
-}
-
 /* Basic Scheme */
-
 static HLPCB authenticateBasicHandleReply;
 static AUTHSSTATS authenticateBasicStats;
 
 static helper *basicauthenticators = NULL;
 
-static AuthBasicConfig basicConfig;
-
 static int authbasic_initialised = 0;
 
 
@@ -74,27 +67,6 @@ static int authbasic_initialised = 0;
 
 /* internal functions */
 
-/* TODO: move to basicScheme.cc - after all per request and user functions are moved out */
-void
-basicScheme::done()
-{
-    /* TODO: this should be a Config call. */
-
-    if (basicauthenticators)
-        helperShutdown(basicauthenticators);
-
-    authbasic_initialised = 0;
-
-    if (!shutting_down)
-        return;
-
-    delete basicauthenticators;
-    basicauthenticators = NULL;
-
-    /* XXX Reinstate auth shutdown for dynamic schemes? */
-    debugs(29, DBG_CRITICAL, HERE << "Basic authentication Shutdown.");
-}
-
 bool
 AuthBasicConfig::active() const
 {
@@ -117,20 +89,25 @@ AuthBasicConfig::configured() const
 const char *
 AuthBasicConfig::type() const
 {
-    return basicScheme::GetInstance().type();
+    return basicScheme::GetInstance()->type();
 }
 
-AuthBasicUserRequest::AuthBasicUserRequest() : _theUser(NULL)
-{}
+int32_t
+BasicUser::ttl() const
+{
+    if (credentials() != Ok && credentials() != Pending)
+        return -1; // TTL is obsolete NOW.
 
-AuthBasicUserRequest::~AuthBasicUserRequest()
-{}
+    int32_t basic_ttl = expiretime - squid_curtime + static_cast<AuthBasicConfig*>(config)->credentialsTTL;
+    int32_t global_ttl = static_cast<int32_t>(expiretime - squid_curtime + Config.authenticateTTL);
 
+    return min(basic_ttl, global_ttl);
+}
 
 bool
 BasicUser::authenticated() const
 {
-    if ((flags.credentials_ok == 1) && (credentials_checkedtime + basicConfig.credentialsTTL > squid_curtime))
+    if ((credentials() == Ok) && (expiretime + static_cast<AuthBasicConfig*>(config)->credentialsTTL > squid_curtime))
         return true;
 
     debugs(29, 4, "User not authenticated or credentials need rechecking.");
@@ -138,89 +115,39 @@ BasicUser::authenticated() const
     return false;
 }
 
-int
-AuthBasicUserRequest::authenticated() const
-{
-    BasicUser const *basic_auth = dynamic_cast<BasicUser const *>(user());
-
-    if (basic_auth && basic_auth->authenticated())
-        return 1;
-
-    return 0;
-}
-
-/* log a basic user in
- */
 void
-AuthBasicUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type)
+AuthBasicConfig::fixHeader(AuthUserRequest::Pointer auth_user_request, HttpReply *rep, http_hdr_type hdrType, HttpRequest * request)
 {
-    assert(user() != NULL);
-
-    basic_data *basic_auth = dynamic_cast<BasicUser *>(user());
-
-    /* if the password is not ok, do an identity */
-
-    if (!basic_auth || basic_auth->flags.credentials_ok != 1)
-        return;
-
-    /* are we about to recheck the credentials externally? */
-    if ((basic_auth->credentials_checkedtime + basicConfig.credentialsTTL) <= squid_curtime) {
-        debugs(29, 4, "authBasicAuthenticate: credentials expired - rechecking");
-        return;
+    if (authenticate) {
+        debugs(29, 9, HERE << "Sending type:" << hdrType << " header: 'Basic realm=\"" << basicAuthRealm << "\"'");
+        httpHeaderPutStrf(&rep->header, hdrType, "Basic realm=\"%s\"", basicAuthRealm);
     }
-
-    /* we have been through the external helper, and the credentials haven't expired */
-    debugs(29, 9, "authenticateBasicAuthenticateuser: user '" << basic_auth->username() << "' authenticated");
-
-    /* Decode now takes care of finding the AuthUser struct in the cache */
-    /* after external auth occurs anyway */
-    basic_auth->expiretime = current_time.tv_sec;
-
-    return;
 }
 
-int
-AuthBasicUserRequest::module_direction()
+void
+AuthBasicConfig::rotateHelpers()
 {
-    /* null auth_user is checked for by authenticateDirection */
-    basic_data *basic_auth = dynamic_cast<BasicUser *>(user());
-    assert (basic_auth);
-
-    switch (basic_auth->flags.credentials_ok) {
-
-    case 0:                    /* not checked */
-        return -1;
-
-    case 1:                    /* checked & ok */
-
-        if (basic_auth->credentials_checkedtime + basicConfig.credentialsTTL <= squid_curtime)
-            return -1;
-
-        return 0;
-
-    case 2:                    /* paused while waiting for a username:password check on another request */
-        return -1;
-
-    case 3:                    /* authentication process failed. */
-        return 0;
+    /* schedule closure of existing helpers */
+    if (basicauthenticators) {
+        helperShutdown(basicauthenticators);
     }
 
-    return -2;
+    /* NP: dynamic helper restart will ensure they start up again as needed. */
 }
 
+/** shutdown the auth helpers and free any allocated configuration details */
 void
-AuthBasicConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *rep, http_hdr_type hdrType, HttpRequest * request)
+AuthBasicConfig::done()
 {
-    if (authenticate) {
-        debugs(29, 9, HERE << "Sending type:" << hdrType << " header: 'Basic realm=\"" << basicAuthRealm << "\"'");
-        httpHeaderPutStrf(&rep->header, hdrType, "Basic realm=\"%s\"", basicAuthRealm);
+    authbasic_initialised = 0;
+
+    if (basicauthenticators) {
+        helperShutdown(basicauthenticators);
     }
-}
 
-/* free any allocated configuration details */
-void
-AuthBasicConfig::done()
-{
+    delete basicauthenticators;
+    basicauthenticators = NULL;
+
     if (authenticate)
         wordlistDestroy(&authenticate);
 
@@ -237,7 +164,7 @@ BasicUser::~BasicUser()
 static void
 authenticateBasicHandleReply(void *data, char *reply)
 {
-    AuthenticateStateData *r = static_cast<AuthenticateStateData *>(data);
+    authenticateStateData *r = static_cast<authenticateStateData *>(data);
     BasicAuthQueueNode *tmpnode;
     char *t = NULL;
     void *cbdata;
@@ -253,20 +180,23 @@ authenticateBasicHandleReply(void *data, char *reply)
 
     assert(r->auth_user_request != NULL);
     assert(r->auth_user_request->user()->auth_type == AUTH_BASIC);
-    basic_data *basic_auth = dynamic_cast<basic_data *>(r->auth_user_request->user());
+
+    /* this is okay since we only play with the BasicUser child fields below
+     * and dont pass the pointer itself anywhere */
+    BasicUser *basic_auth = dynamic_cast<BasicUser *>(r->auth_user_request->user().getRaw());
 
     assert(basic_auth != NULL);
 
     if (reply && (strncasecmp(reply, "OK", 2) == 0))
-        basic_auth->flags.credentials_ok = 1;
+        basic_auth->credentials(AuthUser::Ok);
     else {
-        basic_auth->flags.credentials_ok = 3;
+        basic_auth->credentials(AuthUser::Failed);
 
         if (t && *t)
             r->auth_user_request->setDenyMessage(t);
     }
 
-    basic_auth->credentials_checkedtime = squid_curtime;
+    basic_auth->expiretime = squid_curtime;
 
     if (cbdataReferenceValidDone(r->data, &cbdata))
         r->handler(cbdata, NULL);
@@ -306,10 +236,11 @@ AuthBasicConfig::dump(StoreEntry * entry, const char *name, AuthConfig * scheme)
     storeAppendPrintf(entry, "%s basic casesensitive %s\n", name, casesensitive ? "on" : "off");
 }
 
-AuthBasicConfig::AuthBasicConfig() : authenticateChildren(20)
+AuthBasicConfig::AuthBasicConfig() :
+        credentialsTTL( 2*60*60 ),
+        casesensitive(0),
+        utf8(0)
 {
-    /* TODO: move into initialisation list */
-    credentialsTTL = 2 * 60 * 60;      /* two hours */
     basicAuthRealm = xstrdup("Squid proxy-caching web server");
 }
 
@@ -349,9 +280,7 @@ authenticateBasicStats(StoreEntry * sentry)
     helperStats(sentry, basicauthenticators, "Basic Authenticator Statistics");
 }
 
-CBDATA_TYPE(AuthenticateStateData);
-
-static AuthUser *
+static AuthUser::Pointer
 authBasicAuthUserFindUsername(const char *username)
 {
     AuthUserHashPointer *usernamehash;
@@ -376,10 +305,14 @@ BasicUser::deleteSelf() const
     delete this;
 }
 
-BasicUser::BasicUser(AuthConfig *aConfig) : AuthUser (aConfig) , passwd (NULL), credentials_checkedtime(0), auth_queue(NULL), cleartext (NULL), currentRequest (NULL), httpAuthHeader (NULL)
-{
-    flags.credentials_ok = 0;
-}
+BasicUser::BasicUser(AuthConfig *aConfig) :
+        AuthUser(aConfig),
+        passwd(NULL),
+        auth_queue(NULL),
+        cleartext(NULL),
+        currentRequest(NULL),
+        httpAuthHeader(NULL)
+{}
 
 bool
 BasicUser::decodeCleartext()
@@ -430,7 +363,7 @@ BasicUser::extractUsername()
         *seperator = ':';
     }
 
-    if (!basicConfig.casesensitive)
+    if (!static_cast<AuthBasicConfig*>(config)->casesensitive)
         Tolower((char *)username());
 }
 
@@ -456,15 +389,18 @@ BasicUser::extractPassword()
 }
 
 void
-BasicUser::decode(char const *proxy_auth, AuthUserRequest *auth_user_request)
+BasicUser::decode(char const *proxy_auth, AuthUserRequest::Pointer auth_user_request)
 {
     currentRequest = auth_user_request;
     httpAuthHeader = proxy_auth;
-    if (decodeCleartext ()) {
+    if (decodeCleartext()) {
         extractUsername();
         extractPassword();
     }
-    currentRequest = NULL;
+    currentRequest = NULL; // AYJ: why ?? we have only just filled it with data!
+    // so that we dont have circular UserRequest->User->UseRequest loops persisting outside the auth decode sequence????
+
+    // okay we dont need the original buffer string any more.
     httpAuthHeader = NULL;
 }
 
@@ -478,64 +414,44 @@ BasicUser::valid() const
     return true;
 }
 
+/**
+ * Generate a duplicate of the bad credentials before clearing the working copy.
+ */
 void
-BasicUser::makeLoggingInstance(AuthBasicUserRequest *auth_user_request)
+BasicUser::makeLoggingInstance(AuthUserRequest::Pointer auth_user_request)
 {
     if (username()) {
         /* log the username */
         debugs(29, 9, HERE << "Creating new user for logging '" << username() << "'");
         /* new scheme data */
-        BasicUser *basic_auth = new BasicUser(& basicConfig);
+        AuthUser::Pointer basic_auth = dynamic_cast<AuthUser*>(new BasicUser(config));
         auth_user_request->user(basic_auth);
         /* save the credentials */
         basic_auth->username(username());
         username(NULL);
         /* set the auth_user type */
         basic_auth->auth_type = AUTH_BROKEN;
-        /* link the request to the user */
-        basic_auth->addRequest(auth_user_request);
     }
 }
 
-AuthUser *
-BasicUser::makeCachedFrom()
-{
-    /* the user doesn't exist in the username cache yet */
-    debugs(29, 9, HERE << "Creating new user '" << username() << "'");
-    BasicUser *basic_user = new BasicUser(&basicConfig);
-    /* save the credentials */
-    basic_user->username(username());
-    username(NULL);
-    basic_user->passwd = passwd;
-    passwd = NULL;
-    /* set the auth_user type */
-    basic_user->auth_type = AUTH_BASIC;
-    /* current time for timeouts */
-    basic_user->expiretime = current_time.tv_sec;
-
-    /* this basic_user struct is the 'lucky one' to get added to the username cache */
-    /* the requests after this link to the basic_user */
-    /* store user in hash */
-    basic_user->addToNameCache();
-    return basic_user;
-}
-
 void
 BasicUser::updateCached(BasicUser *from)
 {
-    debugs(29, 9, HERE << "Found user '" << from->username() << "' in the user cache as '" << this << "'");
+    debugs(29, 9, HERE << "Found user '" << from->username() << "' already in the user cache as '" << this << "'");
+
+    assert(strcmp(from->username(), username()) == 0);
 
     if (strcmp(from->passwd, passwd)) {
         debugs(29, 4, HERE << "new password found. Updating in user master record and resetting auth state to unchecked");
-        flags.credentials_ok = 0;
+        credentials(Unchecked);
         xfree(passwd);
         passwd = from->passwd;
         from->passwd = NULL;
     }
 
-    if (flags.credentials_ok == 3) {
+    if (credentials() == Failed) {
         debugs(29, 4, HERE << "last attempt to authenticate this user failed, resetting auth state to unchecked");
-        flags.credentials_ok = 0;
+        credentials(Unchecked);
     }
 }
 
@@ -546,56 +462,66 @@ BasicUser::updateCached(BasicUser *from)
  * "cannot decode credentials". Use the message field to return a
  * descriptive message to the user.
  */
-AuthUserRequest *
+AuthUserRequest::Pointer
 AuthBasicConfig::decode(char const *proxy_auth)
 {
-    AuthBasicUserRequest *auth_user_request = new AuthBasicUserRequest();
+    AuthUserRequest::Pointer auth_user_request = dynamic_cast<AuthUserRequest*>(new AuthBasicUserRequest);
     /* decode the username */
     /* trim BASIC from string */
 
     while (xisgraph(*proxy_auth))
         proxy_auth++;
 
-    BasicUser *basic_auth, local_basic(&basicConfig);
+    /* decoder copy. maybe temporary. maybe added to hash if none already existing. */
+    BasicUser *local_basic = new BasicUser(this);
 
     /* Trim leading whitespace before decoding */
     while (xisspace(*proxy_auth))
         proxy_auth++;
 
-    local_basic.decode(proxy_auth, auth_user_request);
+    local_basic->decode(proxy_auth, auth_user_request);
 
-    if (!local_basic.valid()) {
-        local_basic.makeLoggingInstance(auth_user_request);
+    if (!local_basic->valid()) {
+        local_basic->makeLoggingInstance(auth_user_request);
         return auth_user_request;
     }
 
-    /* now lookup and see if we have a matching auth_user structure in
-     * memory. */
+    /* now lookup and see if we have a matching auth_user structure in memory. */
+    AuthUser::Pointer auth_user;
+
+    if ((auth_user = authBasicAuthUserFindUsername(local_basic->username())) == NULL) {
+        /* the user doesn't exist in the username cache yet */
+        /* save the credentials */
+        debugs(29, 9, HERE << "Creating new user '" << local_basic->username() << "'");
+        /* set the auth_user type */
+        local_basic->auth_type = AUTH_BASIC;
+        /* current time for timeouts */
+        local_basic->expiretime = current_time.tv_sec;
 
-    AuthUser *auth_user;
+        /* this basic_user struct is the 'lucky one' to get added to the username cache */
+        /* the requests after this link to the basic_user */
+        /* store user in hash */
+        local_basic->addToNameCache();
 
-    if ((auth_user = authBasicAuthUserFindUsername(local_basic.username())) == NULL) {
-        auth_user = local_basic.makeCachedFrom();
-        basic_auth = dynamic_cast<BasicUser *>(auth_user);
-        assert (basic_auth);
+        auth_user = dynamic_cast<AuthUser*>(local_basic);
+        assert(auth_user != NULL);
     } else {
-        basic_auth = dynamic_cast<BasicUser *>(auth_user);
-        assert (basic_auth);
-        basic_auth->updateCached (&local_basic);
+        /* replace the current cached password with the new one */
+        BasicUser *basic_auth = dynamic_cast<BasicUser *>(auth_user.getRaw());
+        assert(basic_auth);
+        basic_auth->updateCached(local_basic);
+        auth_user = basic_auth;
     }
 
     /* link the request to the in-cache user */
-    auth_user_request->user(basic_auth);
-
-    basic_auth->addRequest(auth_user_request);
-
+    auth_user_request->user(auth_user);
     return auth_user_request;
 }
 
 /** Initialize helpers and the like for this auth scheme. Called AFTER parsing the
  * config file */
 void
-AuthBasicConfig::init(AuthConfig * scheme)
+AuthBasicConfig::init(AuthConfig * schemeCfg)
 {
     if (authenticate) {
         authbasic_initialised = 1;
@@ -611,7 +537,7 @@ AuthBasicConfig::init(AuthConfig * scheme)
 
         helperOpenServers(basicauthenticators);
 
-        CBDATA_INIT_TYPE(AuthenticateStateData);
+        CBDATA_INIT_TYPE(authenticateStateData);
     }
 }
 
@@ -625,10 +551,10 @@ AuthBasicConfig::registerWithCacheManager(void)
 }
 
 void
-BasicUser::queueRequest(AuthUserRequest * auth_user_request, RH * handler, void *data)
+BasicUser::queueRequest(AuthUserRequest::Pointer auth_user_request, RH * handler, void *data)
 {
     BasicAuthQueueNode *node;
-    node = static_cast<BasicAuthQueueNode *>(xmalloc(sizeof(BasicAuthQueueNode)));
+    node = static_cast<BasicAuthQueueNode *>(xcalloc(1, sizeof(BasicAuthQueueNode)));
     assert(node);
     /* save the details */
     node->next = auth_queue;
@@ -638,44 +564,19 @@ BasicUser::queueRequest(AuthUserRequest * auth_user_request, RH * handler, void
     node->data = cbdataReference(data);
 }
 
-/* send the initial data to a basic authenticator module */
 void
-AuthBasicUserRequest::module_start(RH * handler, void *data)
+BasicUser::submitRequest(AuthUserRequest::Pointer auth_user_request, RH * handler, void *data)
 {
-    basic_data *basic_auth;
-    assert(user()->auth_type == AUTH_BASIC);
-    basic_auth = dynamic_cast<basic_data *>(user());
-    assert(basic_auth != NULL);
-    debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'");
-
-    if (basicConfig.authenticate == NULL) {
-        handler(data, NULL);
-        return;
-    }
-
-    /* check to see if the auth_user already has a request outstanding */
-    if (basic_auth->flags.credentials_ok == 2) {
-        /* there is a request with the same credentials already being verified */
-        basic_auth->queueRequest(this, handler, data);
-        return;
-    }
-
-    basic_auth->submitRequest (this, handler, data);
-}
-
-void
-BasicUser::submitRequest(AuthUserRequest * auth_user_request, RH * handler, void *data)
-{
-    /* mark the user as haveing verification in progress */
-    flags.credentials_ok = 2;
-    AuthenticateStateData *r = NULL;
+    /* mark the user as having verification in progress */
+    credentials(Pending);
+    authenticateStateData *r = NULL;
     char buf[8192];
     char user[1024], pass[1024];
-    r = cbdataAlloc(AuthenticateStateData);
+    r = cbdataAlloc(authenticateStateData);
     r->handler = handler;
     r->data = cbdataReference(data);
     r->auth_user_request = auth_user_request;
-    if (basicConfig.utf8) {
+    if (static_cast<AuthBasicConfig*>(config)->utf8) {
         latin1_to_utf8(user, sizeof(user), username());
         latin1_to_utf8(pass, sizeof(pass), passwd);
         xstrncpy(user, rfc1738_escape(user), sizeof(user));
@@ -687,9 +588,3 @@ BasicUser::submitRequest(AuthUserRequest * auth_user_request, RH * handler, void
     snprintf(buf, sizeof(buf), "%s %s\n", user, pass);
     helperSubmit(basicauthenticators, buf, authenticateBasicHandleReply, r);
 }
-
-AuthConfig *
-basicScheme::createConfig()
-{
-    return &basicConfig;
-}
index 2728cf4f90c85a247f781e28387e8a9824a1201e..fef4b9ffa31ce8ffd649dfb52795607dd60b7379 100644 (file)
@@ -5,6 +5,7 @@
 
 #ifndef __AUTH_BASIC_H__
 #define __AUTH_BASIC_H__
+
 #include "auth/Gadgets.h"
 #include "auth/User.h"
 #include "auth/UserRequest.h"
 
 #define DefaultAuthenticateChildrenMax  32     /* 32 processes */
 
-/* Generic */
-
-class AuthenticateStateData
-{
-
-public:
-    void *data;
-    AuthUserRequest *auth_user_request;
-    RH *handler;
-};
-
-/* queue of auth requests waiting for verification to occur */
-
+/** queue of auth requests waiting for verification to occur */
 class BasicAuthQueueNode
 {
 
 public:
     BasicAuthQueueNode *next;
-    AuthUserRequest *auth_user_request;
+    AuthUserRequest::Pointer auth_user_request;
     RH *handler;
     void *data;
 };
 
-class AuthBasicUserRequest;
-
 class BasicUser : public AuthUser
 {
 
@@ -48,23 +35,20 @@ public:
     BasicUser(AuthConfig *);
     ~BasicUser();
     bool authenticated() const;
-    void queueRequest(AuthUserRequest * auth_user_request, RH * handler, void *data);
-    void submitRequest (AuthUserRequest * auth_user_request, RH * handler, void *data);
-    void decode(char const *credentials, AuthUserRequest *);
+    void queueRequest(AuthUserRequest::Pointer auth_user_request, RH * handler, void *data);
+    void submitRequest(AuthUserRequest::Pointer auth_user_request, RH * handler, void *data);
+    void decode(char const *credentials, AuthUserRequest::Pointer);
     char *getCleartext() {return cleartext;}
 
     bool valid() const;
-    void makeLoggingInstance(AuthBasicUserRequest *auth_user_request);
-    AuthUser * makeCachedFrom();
+    void makeLoggingInstance(AuthUserRequest::Pointer auth_user_request);
+
+    /** Update the cached password for a username. */
     void updateCached(BasicUser *from);
-    char *passwd;
-    time_t credentials_checkedtime;
+    virtual int32_t ttl() const;
 
-    struct {
+    char *passwd;
 
-unsigned int credentials_ok:
-        2;     /*0=unchecked,1=ok,2=failed */
-    } flags;
     BasicAuthQueueNode *auth_queue;
 
 private:
@@ -72,43 +56,12 @@ private:
     void extractUsername();
     void extractPassword();
     char *cleartext;
-    AuthUserRequest *currentRequest;
+    AuthUserRequest::Pointer currentRequest;
     char const *httpAuthHeader;
 };
 
 MEMPROXY_CLASS_INLINE(BasicUser);
 
-typedef class BasicUser basic_data;
-
-/* follows the http request around */
-
-class AuthBasicUserRequest : public AuthUserRequest
-{
-
-public:
-    MEMPROXY_CLASS(AuthBasicUserRequest);
-
-    AuthBasicUserRequest();
-    virtual ~AuthBasicUserRequest();
-
-    virtual int authenticated() const;
-    virtual void authenticate(HttpRequest * request, ConnStateData *conn, http_hdr_type type);
-    virtual int module_direction();
-    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<BasicUser *>(aUser);}
-
-private:
-    BasicUser *_theUser;
-};
-
-MEMPROXY_CLASS_INLINE(AuthBasicUserRequest);
-
-#include "HelperChildConfig.h"
-
 /* configuration runtime data */
 
 class AuthBasicConfig : public AuthConfig
@@ -119,20 +72,19 @@ public:
     ~AuthBasicConfig();
     virtual bool active() const;
     virtual bool configured() const;
-    virtual AuthUserRequest *decode(char const *proxy_auth);
+    virtual AuthUserRequest::Pointer decode(char const *proxy_auth);
     virtual void done();
+    virtual void rotateHelpers();
     virtual void dump(StoreEntry *, const char *, AuthConfig *);
-    virtual void fixHeader(AuthUserRequest *, HttpReply *, http_hdr_type, HttpRequest *);
+    virtual void fixHeader(AuthUserRequest::Pointer, HttpReply *, http_hdr_type, HttpRequest *);
     virtual void init(AuthConfig *);
     virtual void parse(AuthConfig *, int, char *);
     virtual void registerWithCacheManager(void);
     virtual const char * type() const;
-    HelperChildConfig authenticateChildren;
     char *basicAuthRealm;
-    wordlist *authenticate;
     time_t credentialsTTL;
     int casesensitive;
     int utf8;
 };
 
-#endif
+#endif /* __AUTH_BASIC_H__ */
index 86a7911f8ce0ee93cd9706621a1cfd7a5ae74bc7..f818e65919d399d4a8001bbd124541986fdf3321 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
  *
  */
 
-#include "basicScheme.h"
+#include "config.h"
+#include "auth/basic/basicScheme.h"
+#include "helper.h"
+
+/* for AuthConfig */
+#include "auth/basic/auth_basic.h"
+
+AuthScheme::Pointer basicScheme::_instance = NULL;
 
-AuthScheme &
+AuthScheme::Pointer
 basicScheme::GetInstance()
 {
-    if (_instance == NULL)
+    if (_instance == NULL) {
         _instance = new basicScheme();
-    return *_instance;
-}
-
-basicScheme::basicScheme()
-{
-    AddScheme(*this);
+        AddScheme(_instance);
+    }
+    return _instance;
 }
 
 char const *
@@ -52,4 +55,18 @@ basicScheme::type () const
     return "basic";
 }
 
-basicScheme *basicScheme::_instance = NULL;
+void
+basicScheme::done()
+{
+    /* clear the global handle to this scheme. */
+    _instance = NULL;
+
+    debugs(29, DBG_CRITICAL, HERE << "Basic authentication Schema Detached.");
+}
+
+AuthConfig *
+basicScheme::createConfig()
+{
+    AuthBasicConfig *newCfg = new AuthBasicConfig;
+    return dynamic_cast<AuthConfig*>(newCfg);
+}
index 98e2092460726c79cd1d58b887109c4243914fee..4bb12e3d773105147e0857d64d0913295825a7e4 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
@@ -35,6 +34,7 @@
 #define SQUID_BASICSCHEME_H
 
 #include "auth/Scheme.h"
+#include "auth/basic/auth_basic.h"
 
 /// \ingroup AuthAPI
 /// \ingroup AuthSchemeAPI
@@ -42,8 +42,8 @@ class basicScheme : public AuthScheme
 {
 
 public:
-    static AuthScheme &GetInstance();
-    basicScheme();
+    static AuthScheme::Pointer GetInstance();
+    basicScheme() {};
     virtual ~basicScheme() {}
 
     /* per scheme */
@@ -55,7 +55,8 @@ public:
     basicScheme &operator=(basicScheme const &);
 
 private:
-    static basicScheme *_instance;
+    static AuthScheme::Pointer _instance;
+//    AuthBasicConfig basicConfig;
 };
 
 #endif /* SQUID_BASICSCHEME_H */
diff --git a/src/auth/basic/basicUserRequest.cc b/src/auth/basic/basicUserRequest.cc
new file mode 100644 (file)
index 0000000..f3f45f7
--- /dev/null
@@ -0,0 +1,95 @@
+#include "config.h"
+#include "auth/basic/basicUserRequest.h"
+#include "SquidTime.h"
+
+#include "auth/basic/auth_basic.h"
+
+int
+AuthBasicUserRequest::authenticated() const
+{
+    BasicUser const *basic_auth = dynamic_cast<BasicUser const *>(user().getRaw());
+
+    if (basic_auth && basic_auth->authenticated())
+        return 1;
+
+    return 0;
+}
+
+/* log a basic user in
+ */
+void
+AuthBasicUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type)
+{
+    assert(user() != NULL);
+
+    /* if the password is not ok, do an identity */
+    if (!user() || user()->credentials() != AuthUser::Ok)
+        return;
+
+    /* are we about to recheck the credentials externally? */
+    if ((user()->expiretime + static_cast<AuthBasicConfig*>(AuthConfig::Find("basic"))->credentialsTTL) <= squid_curtime) {
+        debugs(29, 4, HERE << "credentials expired - rechecking");
+        return;
+    }
+
+    /* we have been through the external helper, and the credentials haven't expired */
+    debugs(29, 9, HERE << "user '" << user()->username() << "' authenticated");
+
+    /* Decode now takes care of finding the AuthUser struct in the cache */
+    /* after external auth occurs anyway */
+    user()->expiretime = current_time.tv_sec;
+
+    return;
+}
+
+int
+AuthBasicUserRequest::module_direction()
+{
+    /* null auth_user is checked for by authenticateDirection */
+    if (user()->auth_type != AUTH_BASIC)
+        return -2;
+
+    switch (user()->credentials()) {
+
+    case AuthUser::Unchecked:
+    case AuthUser::Pending:
+        return -1;
+
+    case AuthUser::Ok:
+        if (user()->expiretime + static_cast<AuthBasicConfig*>(AuthConfig::Find("basic"))->credentialsTTL <= squid_curtime)
+            return -1;
+        return 0;
+
+    case AuthUser::Failed:
+        return 0;
+
+    default:
+        return -2;
+    }
+}
+
+/* send the initial data to a basic authenticator module */
+void
+AuthBasicUserRequest::module_start(RH * handler, void *data)
+{
+    assert(user()->auth_type == AUTH_BASIC);
+    BasicUser *basic_auth = dynamic_cast<BasicUser *>(user().getRaw());
+    assert(basic_auth != NULL);
+    debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'");
+
+    if (static_cast<AuthBasicConfig*>(AuthConfig::Find("basic"))->authenticate == NULL) {
+        debugs(29, DBG_CRITICAL, "ERROR: No Basic authentication program configured.");
+        handler(data, NULL);
+        return;
+    }
+
+    /* check to see if the auth_user already has a request outstanding */
+    if (user()->credentials() == AuthUser::Pending) {
+        /* there is a request with the same credentials already being verified */
+        basic_auth->queueRequest(this, handler, data);
+        return;
+    }
+
+    basic_auth->submitRequest(this, handler, data);
+}
+
diff --git a/src/auth/basic/basicUserRequest.h b/src/auth/basic/basicUserRequest.h
new file mode 100644 (file)
index 0000000..fabd599
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _SQUID_SRC_AUTH_BASIC_USERREQUEST_H
+#define _SQUID_SRC_AUTH_BASIC_USERREQUEST_H
+
+#include "MemPool.h"
+#include "auth/UserRequest.h"
+
+class ConnStateData;
+class HttpRequest;
+
+/* follows the http request around */
+
+class AuthBasicUserRequest : public AuthUserRequest
+{
+
+public:
+    MEMPROXY_CLASS(AuthBasicUserRequest);
+
+    AuthBasicUserRequest() {};
+    virtual ~AuthBasicUserRequest() { assert(RefCountCount()==0); };
+
+    virtual int authenticated() const;
+    virtual void authenticate(HttpRequest * request, ConnStateData *conn, http_hdr_type type);
+    virtual int module_direction();
+    virtual void module_start(RH *, void *);
+};
+
+MEMPROXY_CLASS_INLINE(AuthBasicUserRequest);
+
+#endif /* _SQUID_SRC_AUTH_BASIC_USERREQUEST_H */
index b4d4a4c0ff7dcd39aad5fca792f5636b30175b19..aa0845145fb0710b8a4b4f9ee72bbefcea579357 100644 (file)
@@ -39,7 +39,7 @@
 
 #include "squid.h"
 #include "rfc2617.h"
-#include "auth_digest.h"
+#include "auth/digest/auth_digest.h"
 #include "auth/Gadgets.h"
 #include "event.h"
 #include "CacheManager.h"
 #include "wordlist.h"
 #include "SquidTime.h"
 /* TODO don't include this */
-#include "digestScheme.h"
+#include "auth/digest/digestScheme.h"
+#include "auth/digest/digestUserRequest.h"
 
 /* Digest Scheme */
 
-static HLPCB authenticateDigestHandleReply;
 static AUTHSSTATS authenticateDigestStats;
 
-static helper *digestauthenticators = NULL;
+helper *digestauthenticators = NULL;
 
 static hash_table *digest_nonce_cache;
 
-static AuthDigestConfig digestConfig;
-
 static int authdigest_initialised = 0;
 static MemAllocator *digest_nonce_pool = NULL;
 
-CBDATA_TYPE(DigestAuthenticateStateData);
+// CBDATA_TYPE(DigestAuthenticateStateData);
 
 enum http_digest_attr_type {
     DIGEST_USERNAME,
@@ -107,13 +105,9 @@ static void authenticateDigestNonceDelete(digest_nonce_h * nonce);
 static void authenticateDigestNonceSetup(void);
 static void authenticateDigestNonceShutdown(void);
 static void authenticateDigestNonceReconfigure(void);
-static const char *authenticateDigestNonceNonceb64(digest_nonce_h * nonce);
-static int authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9]);
 static int authDigestNonceIsStale(digest_nonce_h * nonce);
 static void authDigestNonceEncode(digest_nonce_h * nonce);
-static int authDigestNonceLastRequest(digest_nonce_h * nonce);
 static void authDigestNonceLink(digest_nonce_h * nonce);
-static void authDigestNonceUnlink(digest_nonce_h * nonce);
 #if NOT_USED
 static int authDigestNonceLinks(digest_nonce_h * nonce);
 #endif
@@ -233,7 +227,7 @@ authenticateDigestNonceSetup(void)
     if (!digest_nonce_cache) {
         digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
         assert(digest_nonce_cache);
-        eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig.nonceGCInterval, 1);
+        eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->nonceGCInterval, 1);
     }
 }
 
@@ -300,8 +294,8 @@ authenticateDigestNonceCacheCleanup(void *data)
 
     debugs(29, 3, "authenticateDigestNonceCacheCleanup: Finished cleaning the nonce cache.");
 
-    if (digestConfig.active())
-        eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, digestConfig.nonceGCInterval, 1);
+    if (static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->active())
+        eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->nonceGCInterval, 1);
 }
 
 static void
@@ -324,7 +318,7 @@ authDigestNonceLinks(digest_nonce_h * nonce)
 
 #endif
 
-static void
+void
 authDigestNonceUnlink(digest_nonce_h * nonce)
 {
     assert(nonce != NULL);
@@ -341,8 +335,8 @@ authDigestNonceUnlink(digest_nonce_h * nonce)
         authenticateDigestNonceDelete(nonce);
 }
 
-static const char *
-authenticateDigestNonceNonceb64(digest_nonce_h * nonce)
+const char *
+authenticateDigestNonceNonceb64(const digest_nonce_h * nonce)
 {
     if (!nonce)
         return NULL;
@@ -370,7 +364,7 @@ authenticateDigestNonceFindNonce(const char *nonceb64)
     return nonce;
 }
 
-static int
+int
 authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9])
 {
     unsigned long intnc;
@@ -388,12 +382,12 @@ authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9])
     }
 
     /* is the nonce-count ok ? */
-    if (!digestConfig.CheckNonceCount) {
+    if (!static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->CheckNonceCount) {
         nonce->nc++;
         return -1;              /* forced OK by configuration */
     }
 
-    if ((digestConfig.NonceStrictness && intnc != nonce->nc + 1) ||
+    if ((static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->NonceStrictness && intnc != nonce->nc + 1) ||
             intnc < nonce->nc + 1) {
         debugs(29, 4, "authDigestNonceIsValid: Nonce count doesn't match");
         nonce->flags.valid = 0;
@@ -418,10 +412,10 @@ authDigestNonceIsStale(digest_nonce_h * nonce)
         return -1;
 
     /* has it's max duration expired? */
-    if (nonce->noncedata.creationtime + digestConfig.noncemaxduration < current_time.tv_sec) {
+    if (nonce->noncedata.creationtime + static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->noncemaxduration < current_time.tv_sec) {
         debugs(29, 4, "authDigestNonceIsStale: Nonce is too old. " <<
                nonce->noncedata.creationtime << " " <<
-               digestConfig.noncemaxduration << " " <<
+               static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->noncemaxduration << " " <<
                current_time.tv_sec);
 
         nonce->flags.valid = 0;
@@ -434,7 +428,7 @@ authDigestNonceIsStale(digest_nonce_h * nonce)
         return -1;
     }
 
-    if (nonce->nc > digestConfig.noncemaxuses) {
+    if (nonce->nc > static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->noncemaxuses) {
         debugs(29, 4, "authDigestNoncelastRequest: Nonce count over user limit");
         nonce->flags.valid = 0;
         return -1;
@@ -444,8 +438,11 @@ authDigestNonceIsStale(digest_nonce_h * nonce)
     return 0;
 }
 
-/* return -1 if the digest will be stale on the next request */
-static int
+/**
+ * \retval  0    the digest is not stale yet
+ * \retval -1    the digest will be stale on the next request
+ */
+const int
 authDigestNonceLastRequest(digest_nonce_h * nonce)
 {
     if (!nonce)
@@ -456,7 +453,7 @@ authDigestNonceLastRequest(digest_nonce_h * nonce)
         return -1;
     }
 
-    if (nonce->nc >= digestConfig.noncemaxuses - 1) {
+    if (nonce->nc >= static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->noncemaxuses - 1) {
         debugs(29, 4, "authDigestNoncelastRequest: Nonce count about to hit user limit");
         return -1;
     }
@@ -483,46 +480,36 @@ authDigestNoncePurge(digest_nonce_h * nonce)
 }
 
 /* USER related functions */
-static AuthUser *
+static AuthUser::Pointer
 authDigestUserFindUsername(const char *username)
 {
     AuthUserHashPointer *usernamehash;
-    AuthUser *auth_user;
     debugs(29, 9, HERE << "Looking for user '" << username << "'");
 
     if (username && (usernamehash = static_cast < auth_user_hash_pointer * >(hash_lookup(proxy_auth_username_cache, username)))) {
-        while ((usernamehash->user()->auth_type != AUTH_DIGEST) &&
-                (usernamehash->next))
-            usernamehash = static_cast < auth_user_hash_pointer * >(usernamehash->next);
-
-        auth_user = NULL;
+        while ((usernamehash->user()->auth_type != AUTH_DIGEST) && (usernamehash->next))
+            usernamehash = static_cast<AuthUserHashPointer *>(usernamehash->next);
 
         if (usernamehash->user()->auth_type == AUTH_DIGEST) {
-            auth_user = usernamehash->user();
+            return usernamehash->user();
         }
-
-        return auth_user;
     }
 
     return NULL;
 }
 
-static void
-authDigestUserShutdown(void)
+void
+AuthDigestConfig::rotateHelpers()
 {
-    /** \todo Future work: the auth framework could flush it's cache */
-    AuthUserHashPointer *usernamehash;
-    AuthUser *auth_user;
-    hash_first(proxy_auth_username_cache);
-
-    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
-        auth_user = usernamehash->user();
-
-        if (strcmp(auth_user->config->type(), "digest") == 0)
-            auth_user->unlock();
+    /* schedule closure of existing helpers */
+    if (digestauthenticators) {
+        helperShutdown(digestauthenticators);
     }
+
+    /* NP: dynamic helper restart will ensure they start up again as needed. */
 }
 
+
 /** delete the digest request structure. Does NOT delete related structures */
 void
 digestScheme::done()
@@ -547,9 +534,12 @@ digestScheme::done()
     delete digestauthenticators;
     digestauthenticators = NULL;
 
-    authDigestUserShutdown();
+    PurgeCredentialsCache();
     authenticateDigestNonceShutdown();
     debugs(29, 2, "authenticateDigestDone: Digest authentication shut down.");
+
+    /* clear the global handle to this scheme. */
+    _instance = NULL;
 }
 
 void
@@ -589,231 +579,18 @@ AuthDigestConfig::configured() const
     return false;
 }
 
-int
-AuthDigestUserRequest::authenticated() const
-{
-    if (credentials() == Ok)
-        return 1;
-
-    return 0;
-}
-
-/** log a digest user in
- */
-void
-AuthDigestUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type)
-{
-    AuthUser *auth_user;
-    AuthDigestUserRequest *digest_request;
-    digest_user_h *digest_user;
-
-    HASHHEX SESSIONKEY;
-    HASHHEX HA2 = "";
-    HASHHEX Response;
-
-    assert(authUser() != NULL);
-    auth_user = authUser();
-
-    digest_user = dynamic_cast < digest_user_h * >(auth_user);
-
-    assert(digest_user != NULL);
-
-    /* if the check has corrupted the user, just return */
-
-    if (credentials() == Failed) {
-        return;
-    }
-
-    digest_request = this;
-
-    /* do we have the HA1 */
-
-    if (!digest_user->HA1created) {
-        credentials(Pending);
-        return;
-    }
-
-    if (digest_request->nonce == NULL) {
-        /* this isn't a nonce we issued */
-        credentials(Failed);
-        return;
-    }
-
-    DigestCalcHA1(digest_request->algorithm, NULL, NULL, NULL,
-                  authenticateDigestNonceNonceb64(digest_request->nonce),
-                  digest_request->cnonce,
-                  digest_user->HA1, SESSIONKEY);
-    DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
-                       digest_request->nc, digest_request->cnonce, digest_request->qop,
-                       RequestMethodStr(request->method), digest_request->uri, HA2, Response);
-
-    debugs(29, 9, "\nResponse = '" << digest_request->response << "'\nsquid is = '" << Response << "'");
-
-    if (strcasecmp(digest_request->response, Response) != 0) {
-        if (!digest_request->flags.helper_queried) {
-            /* Query the helper in case the password has changed */
-            digest_request->flags.helper_queried = 1;
-            digest_request->credentials_ok = Pending;
-            return;
-        }
-
-        if (digestConfig.PostWorkaround && request->method != METHOD_GET) {
-            /* Ugly workaround for certain very broken browsers using the
-             * wrong method to calculate the request-digest on POST request.
-             * This should be deleted once Digest authentication becomes more
-             * widespread and such broken browsers no longer are commonly
-             * used.
-             */
-            DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
-                               digest_request->nc, digest_request->cnonce, digest_request->qop,
-                               RequestMethodStr(METHOD_GET), digest_request->uri, HA2, Response);
-
-            if (strcasecmp(digest_request->response, Response)) {
-                credentials(Failed);
-                digest_request->flags.invalid_password = 1;
-                digest_request->setDenyMessage("Incorrect password");
-                return;
-            } else {
-                const char *useragent = request->header.getStr(HDR_USER_AGENT);
-
-                static Ip::Address last_broken_addr;
-                static int seen_broken_client = 0;
-
-                if (!seen_broken_client) {
-                    last_broken_addr.SetNoAddr();
-                    seen_broken_client = 1;
-                }
-
-                if (last_broken_addr != request->client_addr) {
-                    debugs(29, 1, "\nDigest POST bug detected from " <<
-                           request->client_addr << " using '" <<
-                           (useragent ? useragent : "-") <<
-                           "'. Please upgrade browser. See Bug #630 for details.");
-
-                    last_broken_addr = request->client_addr;
-                }
-            }
-        } else {
-            credentials(Failed);
-            digest_request->flags.invalid_password = 1;
-            digest_request->setDenyMessage("Incorrect password");
-            return;
-        }
-
-        /* check for stale nonce */
-        if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) {
-            debugs(29, 3, "authenticateDigestAuthenticateuser: user '" << digest_user->username() << "' validated OK but nonce stale");
-            credentials(Failed);
-            digest_request->setDenyMessage("Stale nonce");
-            return;
-        }
-    }
-
-    credentials(Ok);
-
-    /* password was checked and did match */
-    debugs(29, 4, "authenticateDigestAuthenticateuser: user '" << digest_user->username() << "' validated OK");
-
-    /* auth_user is now linked, we reset these values
-     * after external auth occurs anyway */
-    auth_user->expiretime = current_time.tv_sec;
-    return;
-}
-
-int
-AuthDigestUserRequest::module_direction()
-{
-    switch (credentials()) {
-
-    case Unchecked:
-        return -1;
-
-    case Ok:
-
-        return 0;
-
-    case Pending:
-        return -1;
-
-    case Failed:
-
-        /* send new challenge */
-        return 1;
-    }
-
-    return -2;
-}
-
-/* add the [proxy]authorisation header */
-void
-AuthDigestUserRequest::addHeader(HttpReply * rep, int accel)
-{
-    http_hdr_type type;
-
-    /* don't add to authentication error pages */
-
-    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
-            || (accel && rep->sline.status == HTTP_UNAUTHORIZED))
-        return;
-
-    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
-
-#if WAITING_FOR_TE
-    /* test for http/1.1 transfer chunked encoding */
-    if (chunkedtest)
-        return;
-
-#endif
-
-    if ((digestConfig.authenticate) && authDigestNonceLastRequest(nonce)) {
-        flags.authinfo_sent = 1;
-        debugs(29, 9, "authDigestAddHead: Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
-        httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nonce));
-    }
-}
-
-#if WAITING_FOR_TE
-/* add the [proxy]authorisation header */
-void
-AuthDigestUserRequest::addTrailer(HttpReply * rep, int accel)
-{
-    int type;
-
-    if (!auth_user_request)
-        return;
-
-
-    /* has the header already been send? */
-    if (flags.authinfo_sent)
-        return;
-
-    /* don't add to authentication error pages */
-    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
-            || (accel && rep->sline.status == HTTP_UNAUTHORIZED))
-        return;
-
-    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
-
-    if ((digestConfig.authenticate) && authDigestNonceLastRequest(nonce)) {
-        debugs(29, 9, "authDigestAddTrailer: Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
-        httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nonce));
-    }
-}
-
-#endif
-
 /* add the [www-|Proxy-]authenticate header on a 407 or 401 reply */
 void
-AuthDigestConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *rep, http_hdr_type hdrType, HttpRequest * request)
+AuthDigestConfig::fixHeader(AuthUserRequest::Pointer auth_user_request, HttpReply *rep, http_hdr_type hdrType, HttpRequest * request)
 {
     if (!authenticate)
         return;
 
     int stale = 0;
 
-    if (auth_user_request) {
+    if (auth_user_request != NULL) {
         AuthDigestUserRequest *digest_request;
-        digest_request = dynamic_cast < AuthDigestUserRequest * >(auth_user_request);
+        digest_request = dynamic_cast<AuthDigestUserRequest*>(auth_user_request.getRaw());
         assert (digest_request != NULL);
 
         stale = !digest_request->flags.invalid_password;
@@ -833,7 +610,6 @@ AuthDigestConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *rep,
 
 DigestUser::~DigestUser()
 {
-
     dlink_node *link, *tmplink;
     link = nonces.head;
 
@@ -847,53 +623,30 @@ DigestUser::~DigestUser()
     }
 }
 
-static void
-authenticateDigestHandleReply(void *data, char *reply)
+int32_t
+DigestUser::ttl() const
 {
-    DigestAuthenticateStateData *replyData = static_cast < DigestAuthenticateStateData * >(data);
-    AuthUserRequest *auth_user_request;
-    AuthDigestUserRequest *digest_request;
-    digest_user_h *digest_user;
-    char *t = NULL;
-    void *cbdata;
-    debugs(29, 9, "authenticateDigestHandleReply: {" << (reply ? reply : "<NULL>") << "}");
-
-    if (reply) {
-        if ((t = strchr(reply, ' ')))
-            *t++ = '\0';
-
-        if (*reply == '\0' || *reply == '\n')
-            reply = NULL;
-    }
+    int32_t global_ttl = static_cast<int32_t>(expiretime - squid_curtime + Config.authenticateTTL);
 
-    assert(replyData->auth_user_request != NULL);
-    auth_user_request = replyData->auth_user_request;
-    digest_request = dynamic_cast < AuthDigestUserRequest * >(auth_user_request);
-    assert(digest_request);
-
-    digest_user = dynamic_cast < digest_user_h * >(auth_user_request->user());
-    assert(digest_user != NULL);
-
-    if (reply && (strncasecmp(reply, "ERR", 3) == 0)) {
-        digest_request->credentials(AuthDigestUserRequest::Failed);
-        digest_request->flags.invalid_password = 1;
+    /* find the longest lasting nonce. */
+    int32_t latest_nonce = -1;
+    dlink_node *link = nonces.head;
+    while (link) {
+        digest_nonce_h *nonce = static_cast<digest_nonce_h *>(link->data);
+        if (nonce->flags.valid && nonce->noncedata.creationtime > latest_nonce)
+            latest_nonce = nonce->noncedata.creationtime;
 
-        if (t && *t)
-            digest_request->setDenyMessage(t);
-    } else if (reply) {
-        CvtBin(reply, digest_user->HA1);
-        digest_user->HA1created = 1;
+        link = link->next;
     }
+    if (latest_nonce == -1)
+        return min(-1, global_ttl);
 
-    if (cbdataReferenceValidDone(replyData->data, &cbdata))
-        replyData->handler(cbdata, NULL);
+    int32_t nonce_ttl = latest_nonce - current_time.tv_sec + static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->noncemaxduration;
 
-    //we know replyData->auth_user_request != NULL, or we'd have asserted
-    AUTHUSERREQUESTUNLOCK(replyData->auth_user_request, "replyData");
-
-    cbdataFree(replyData);
+    return min(nonce_ttl, global_ttl);
 }
 
+
 /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
  * config file */
 void
@@ -915,7 +668,7 @@ AuthDigestConfig::init(AuthConfig * scheme)
 
         helperOpenServers(digestauthenticators);
 
-        CBDATA_INIT_TYPE(DigestAuthenticateStateData);
+        CBDATA_INIT_TYPE(authenticateStateData);
     }
 }
 
@@ -938,7 +691,7 @@ AuthDigestConfig::done()
     safe_free(digestAuthRealm);
 }
 
-AuthDigestConfig::AuthDigestConfig() : authenticateChildren(20)
+AuthDigestConfig::AuthDigestConfig()
 {
     /* TODO: move into initialisation list */
     /* 5 minutes */
@@ -989,7 +742,7 @@ AuthDigestConfig::parse(AuthConfig * scheme, int n_configured, char *param_str)
 const char *
 AuthDigestConfig::type() const
 {
-    return digestScheme::GetInstance().type();
+    return digestScheme::GetInstance()->type();
 }
 
 
@@ -1004,7 +757,7 @@ authenticateDigestStats(StoreEntry * sentry)
 static void
 authDigestNonceUserUnlink(digest_nonce_h * nonce)
 {
-    digest_user_h *digest_user;
+    DigestUser *digest_user;
     dlink_node *link, *tmplink;
 
     if (!nonce)
@@ -1044,7 +797,7 @@ static void
 authDigestUserLinkNonce(DigestUser * user, digest_nonce_h * nonce)
 {
     dlink_node *node;
-    digest_user_h *digest_user;
+    DigestUser *digest_user;
 
     if (!user || !nonce)
         return;
@@ -1075,22 +828,20 @@ authDigestUserLinkNonce(DigestUser * user, digest_nonce_h * nonce)
 }
 
 /* setup the necessary info to log the username */
-static AuthUserRequest *
-authDigestLogUsername(char *username, AuthDigestUserRequest *auth_user_request)
+static AuthUserRequest::Pointer
+authDigestLogUsername(char *username, AuthUserRequest::Pointer auth_user_request)
 {
     assert(auth_user_request != NULL);
 
     /* log the username */
     debugs(29, 9, "authDigestLogUsername: Creating new user for logging '" << username << "'");
-    digest_user_h *digest_user = new DigestUser(&digestConfig);
+    AuthUser::Pointer digest_user = new DigestUser(static_cast<AuthDigestConfig*>(AuthConfig::Find("digest")));
     /* save the credentials */
     digest_user->username(username);
     /* set the auth_user type */
     digest_user->auth_type = AUTH_BROKEN;
     /* link the request to the user */
-    auth_user_request->authUser(digest_user);
     auth_user_request->user(digest_user);
-    digest_user->addRequest (auth_user_request);
     return auth_user_request;
 }
 
@@ -1098,7 +849,7 @@ authDigestLogUsername(char *username, AuthDigestUserRequest *auth_user_request)
  * Decode a Digest [Proxy-]Auth string, placing the results in the passed
  * Auth_user structure.
  */
-AuthUserRequest *
+AuthUserRequest::Pointer
 AuthDigestConfig::decode(char const *proxy_auth)
 {
     const char *item;
@@ -1318,7 +1069,7 @@ AuthDigestConfig::decode(char const *proxy_auth)
     if (!nonce) {
         /* we couldn't find a matching nonce! */
         debugs(29, 2, "authenticateDigestDecode: Unexpected or invalid nonce received");
-        digest_request->credentials(AuthDigestUserRequest::Failed);
+        digest_request->user()->credentials(AuthUser::Failed);
         return authDigestLogUsername(username, digest_request);
     }
 
@@ -1337,14 +1088,14 @@ AuthDigestConfig::decode(char const *proxy_auth)
     /* we don't send or parse opaques. Ok so we're flexable ... */
 
     /* find the user */
-    digest_user_h *digest_user;
+    DigestUser *digest_user;
 
-    AuthUser *auth_user;
+    AuthUser::Pointer auth_user;
 
     if ((auth_user = authDigestUserFindUsername(username)) == NULL) {
         /* the user doesn't exist in the username cache yet */
         debugs(29, 9, "authDigestDecodeAuth: Creating new digest user '" << username << "'");
-        digest_user = new DigestUser (&digestConfig);
+        digest_user = new DigestUser(this);
         /* auth_user is a parent */
         auth_user = digest_user;
         /* save the username */
@@ -1364,19 +1115,14 @@ AuthDigestConfig::decode(char const *proxy_auth)
         authDigestUserLinkNonce(digest_user, nonce);
     } else {
         debugs(29, 9, "authDigestDecodeAuth: Found user '" << username << "' in the user cache as '" << auth_user << "'");
-        digest_user = static_cast < digest_user_h * >(auth_user);
+        digest_user = static_cast<DigestUser *>(auth_user.getRaw());
         xfree(username);
     }
 
     /*link the request and the user */
     assert(digest_request != NULL);
 
-    digest_request->authUser (digest_user);
-
     digest_request->user(digest_user);
-
-    digest_user->addRequest (digest_request);
-
     debugs(29, 9, "username = '" << digest_user->username() << "'\nrealm = '" <<
            digest_request->realm << "'\nqop = '" << digest_request->qop <<
            "'\nalgorithm = '" << digest_request->algorithm << "'\nuri = '" <<
@@ -1388,95 +1134,5 @@ AuthDigestConfig::decode(char const *proxy_auth)
     return digest_request;
 }
 
-/* send the initial data to a digest authenticator module */
-void
-AuthDigestUserRequest::module_start(RH * handler, void *data)
-{
-    DigestAuthenticateStateData *r = NULL;
-    char buf[8192];
-    digest_user_h *digest_user;
-    assert(user()->auth_type == AUTH_DIGEST);
-    digest_user = dynamic_cast < digest_user_h * >(user());
-    assert(digest_user != NULL);
-    debugs(29, 9, "authenticateStart: '\"" << digest_user->username() << "\":\"" << realm << "\"'");
-
-    if (digestConfig.authenticate == NULL) {
-        handler(data, NULL);
-        return;
-    }
-
-    r = cbdataAlloc(DigestAuthenticateStateData);
-    r->handler = handler;
-    r->data = cbdataReference(data);
-    r->auth_user_request = this;
-    AUTHUSERREQUESTLOCK(r->auth_user_request, "r");
-    if (digestConfig.utf8) {
-        char userstr[1024];
-        latin1_to_utf8(userstr, sizeof(userstr), digest_user->username());
-        snprintf(buf, 8192, "\"%s\":\"%s\"\n", userstr, realm);
-    } else {
-        snprintf(buf, 8192, "\"%s\":\"%s\"\n", digest_user->username(), realm);
-    }
-
-    helperSubmit(digestauthenticators, buf, authenticateDigestHandleReply, r);
-}
-
-DigestUser::DigestUser (AuthConfig *aConfig) : AuthUser (aConfig), HA1created (0)
+DigestUser::DigestUser(AuthConfig *aConfig) : AuthUser(aConfig), HA1created (0)
 {}
-
-AuthUser *
-AuthDigestUserRequest::authUser() const
-{
-    return const_cast<AuthUser *>(user());
-}
-
-void
-AuthDigestUserRequest::authUser(AuthUser *aUser)
-{
-    assert(!authUser());
-    user(aUser);
-    user()->lock();
-}
-
-AuthDigestUserRequest::CredentialsState
-AuthDigestUserRequest::credentials() const
-{
-    return credentials_ok;
-}
-
-void
-AuthDigestUserRequest::credentials(CredentialsState newCreds)
-{
-    credentials_ok = newCreds;
-}
-
-AuthDigestUserRequest::AuthDigestUserRequest() : nonceb64(NULL) ,cnonce(NULL) ,realm(NULL),
-        pszPass(NULL) ,algorithm(NULL) ,pszMethod(NULL),
-        qop(NULL) ,uri(NULL) ,response(NULL),
-        nonce(NULL), _theUser (NULL) ,
-        credentials_ok (Unchecked)
-{}
-
-/** delete the digest request structure. Does NOT delete related structures */
-AuthDigestUserRequest::~AuthDigestUserRequest()
-{
-    safe_free (nonceb64);
-    safe_free (cnonce);
-    safe_free (realm);
-    safe_free (pszPass);
-    safe_free (algorithm);
-    safe_free (pszMethod);
-    safe_free (qop);
-    safe_free (uri);
-    safe_free (response);
-
-    if (nonce)
-        authDigestNonceUnlink(nonce);
-}
-
-AuthConfig *
-digestScheme::createConfig()
-{
-    return &digestConfig;
-}
-
index feb25fd36b58f1d7474eba8fc2e883c005ccec0b..de67901043edec8773b547f24a2313e0ff577352 100644 (file)
@@ -5,24 +5,17 @@
 
 #ifndef __AUTH_DIGEST_H__
 #define __AUTH_DIGEST_H__
-#include "rfc2617.h"
+
+#include "auth/Config.h"
 #include "auth/Gadgets.h"
+#include "auth/State.h"
 #include "auth/User.h"
 #include "auth/UserRequest.h"
-#include "auth/Config.h"
 #include "helper.h"
+#include "rfc2617.h"
 
 /* Generic */
 
-class DigestAuthenticateStateData
-{
-
-public:
-    void *data;
-    AuthUserRequest *auth_user_request;
-    RH *handler;
-};
-
 typedef struct _digest_nonce_data digest_nonce_data;
 
 typedef struct _digest_nonce_h digest_nonce_h;
@@ -36,6 +29,9 @@ public:
     DigestUser(AuthConfig *);
     ~DigestUser();
     int authenticated() const;
+
+    virtual int32_t ttl() const;
+
     HASH HA1;
     int HA1created;
 
@@ -46,66 +42,6 @@ public:
 
 MEMPROXY_CLASS_INLINE(DigestUser);
 
-typedef class DigestUser digest_user_h;
-
-/* the digest_request structure is what follows the http_request around */
-
-class AuthDigestUserRequest : public AuthUserRequest
-{
-
-public:
-    enum CredentialsState {Unchecked, Ok, Pending, Failed};
-    MEMPROXY_CLASS(AuthDigestUserRequest);
-
-    AuthDigestUserRequest();
-    virtual ~AuthDigestUserRequest();
-
-    virtual int authenticated() const;
-    virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type);
-    virtual int module_direction();
-    virtual void addHeader(HttpReply * rep, int accel);
-#if WAITING_FOR_TE
-
-    virtual void addTrailer(HttpReply * rep, int accel);
-#endif
-
-    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<DigestUser *>(aUser);}
-
-    CredentialsState credentials() const;
-    void credentials(CredentialsState);
-
-    void authUser(AuthUser *);
-    AuthUser *authUser() const;
-
-    char *nonceb64;            /* "dcd98b7102dd2f0e8b11d0f600bfb0c093" */
-    char *cnonce;              /* "0a4f113b" */
-    char *realm;               /* = "testrealm@host.com" */
-    char *pszPass;             /* = "Circle Of Life" */
-    char *algorithm;           /* = "md5" */
-    char nc[9];                        /* = "00000001" */
-    char *pszMethod;           /* = "GET" */
-    char *qop;                 /* = "auth" */
-    char *uri;                 /* = "/dir/index.html" */
-    char *response;
-
-    struct {
-        unsigned int authinfo_sent:1;
-        unsigned int invalid_password:1;
-        unsigned int helper_queried:1;
-    } flags;
-    digest_nonce_h *nonce;
-
-private:
-    DigestUser *_theUser;
-    CredentialsState credentials_ok;
-};
-
-MEMPROXY_CLASS_INLINE(AuthDigestUserRequest);
 
 /* data to be encoded into the nonce's b64 representation */
 
@@ -134,7 +70,10 @@ struct _digest_nonce_h : public hash_link {
     } flags;
 };
 
-#include "HelperChildConfig.h"
+extern void authDigestNonceUnlink(digest_nonce_h * nonce);
+extern int authDigestNonceIsValid(digest_nonce_h * nonce, char nc[9]);
+extern const char *authenticateDigestNonceNonceb64(const digest_nonce_h * nonce);
+extern const int authDigestNonceLastRequest(digest_nonce_h * nonce);
 
 /* configuration runtime data */
 
@@ -145,17 +84,16 @@ public:
     AuthDigestConfig();
     virtual bool active() const;
     virtual bool configured() const;
-    virtual AuthUserRequest *decode(char const *proxy_auth);
+    virtual AuthUserRequest::Pointer decode(char const *proxy_auth);
     virtual void done();
+    virtual void rotateHelpers();
     virtual void dump(StoreEntry *, const char *, AuthConfig *);
-    virtual void fixHeader(AuthUserRequest *, HttpReply *, http_hdr_type, HttpRequest *);
+    virtual void fixHeader(AuthUserRequest::Pointer, HttpReply *, http_hdr_type, HttpRequest *);
     virtual void init(AuthConfig *);
     virtual void parse(AuthConfig *, int, char *);
     virtual void registerWithCacheManager(void);
     virtual const char * type() const;
-    HelperChildConfig authenticateChildren;
     char *digestAuthRealm;
-    wordlist *authenticate;
     time_t nonceGCInterval;
     time_t noncemaxduration;
     unsigned int noncemaxuses;
@@ -170,4 +108,6 @@ typedef class AuthDigestConfig auth_digest_config;
 /* strings */
 #define QOP_AUTH "auth"
 
+extern helper *digestauthenticators;
+
 #endif
index 649cd6136a564066573f483148e8f0c62b3ac0e3..f823107baf51e9ac2468d116834f0066135c9b3a 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
  *
  */
 
-#include "digestScheme.h"
+#include "config.h"
+#include "auth/digest/digestScheme.h"
+#include "helper.h"
 
-AuthScheme &
+AuthScheme::Pointer
 digestScheme::GetInstance()
 {
-    if (_instance == NULL)
+    if (_instance == NULL) {
         _instance = new digestScheme();
-    return *_instance;
-}
-
-digestScheme::digestScheme()
-{
-    AddScheme(*this);
+        AddScheme(_instance);
+    }
+    return _instance;
 }
 
 char const *
@@ -52,4 +50,28 @@ digestScheme::type () const
     return "digest";
 }
 
-digestScheme *digestScheme::_instance = NULL;
+AuthScheme::Pointer digestScheme::_instance = NULL;
+
+AuthConfig *
+digestScheme::createConfig()
+{
+    AuthDigestConfig *digestCfg = new AuthDigestConfig;
+    return dynamic_cast<AuthConfig*>(digestCfg);
+}
+
+void
+digestScheme::PurgeCredentialsCache(void)
+{
+    AuthUserHashPointer *usernamehash;
+    AuthUser::Pointer auth_user;
+    hash_first(proxy_auth_username_cache);
+
+    while ((usernamehash = static_cast<AuthUserHashPointer *>(hash_next(proxy_auth_username_cache)) )) {
+        auth_user = usernamehash->user();
+
+        if (strcmp(auth_user->config->type(), "digest") == 0) {
+            hash_remove_link(proxy_auth_username_cache, static_cast<hash_link*>(usernamehash));
+            delete usernamehash;
+        }
+    }
+}
index 5d534eb6d53d549f2251f1ba38e934eac4e47b9f..1d7652574b26ef55ee231ae97045b5acfb00db50 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
@@ -35,6 +34,7 @@
 #define SQUID_DIGESTSCHEME_H
 
 #include "auth/Scheme.h"
+#include "auth/digest/auth_digest.h"
 
 /// \ingroup AuthSchemeAPI
 /// \ingroup AuthAPI
@@ -42,20 +42,28 @@ class digestScheme : public AuthScheme
 {
 
 public:
-    static AuthScheme &GetInstance();
-    digestScheme();
+    static AuthScheme::Pointer GetInstance();
+    digestScheme() {};
     virtual ~digestScheme() {}
 
     /* per scheme */
     virtual char const *type () const;
     virtual void done();
     virtual AuthConfig *createConfig();
+
     /* Not implemented */
     digestScheme (digestScheme const &);
     digestScheme &operator=(digestScheme const &);
 
 private:
-    static digestScheme *_instance;
+    static AuthScheme::Pointer _instance;
+
+    /**
+     * Remove all cached user credentials from circulation.
+     * Intended for use during shutdown procedure.
+     * After calling this all newly received credentials must be re-authenticated.
+     */
+    static void PurgeCredentialsCache(void);
 };
 
 #endif /* SQUID_DIGESTSCHEME_H */
diff --git a/src/auth/digest/digestUserRequest.cc b/src/auth/digest/digestUserRequest.cc
new file mode 100644 (file)
index 0000000..f51b7ea
--- /dev/null
@@ -0,0 +1,321 @@
+#include "config.h"
+#include "auth/digest/auth_digest.h"
+#include "auth/digest/digestUserRequest.h"
+#include "auth/State.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "SquidTime.h"
+
+AuthDigestUserRequest::AuthDigestUserRequest() :
+        nonceb64(NULL),
+        cnonce(NULL),
+        realm(NULL),
+        pszPass(NULL),
+        algorithm(NULL),
+        pszMethod(NULL),
+        qop(NULL),
+        uri(NULL),
+        response(NULL),
+        nonce(NULL)
+{}
+
+/**
+ * Delete the digest request structure.
+ * Does NOT delete related AuthUser structures
+ */
+AuthDigestUserRequest::~AuthDigestUserRequest()
+{
+    assert(RefCountCount()==0);
+
+    safe_free(nonceb64);
+    safe_free(cnonce);
+    safe_free(realm);
+    safe_free(pszPass);
+    safe_free(algorithm);
+    safe_free(pszMethod);
+    safe_free(qop);
+    safe_free(uri);
+    safe_free(response);
+
+    if (nonce)
+        authDigestNonceUnlink(nonce);
+}
+
+int
+AuthDigestUserRequest::authenticated() const
+{
+    if (user() != NULL && user()->credentials() == AuthUser::Ok)
+        return 1;
+
+    return 0;
+}
+
+/** log a digest user in
+ */
+void
+AuthDigestUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type)
+{
+    HASHHEX SESSIONKEY;
+    HASHHEX HA2 = "";
+    HASHHEX Response;
+
+    /* if the check has corrupted the user, just return */
+    if (user() == NULL || user()->credentials() == AuthUser::Failed) {
+        return;
+    }
+
+    AuthUser::Pointer auth_user = user();
+
+    DigestUser *digest_user = dynamic_cast<DigestUser*>(auth_user.getRaw());
+    assert(digest_user != NULL);
+
+    AuthDigestUserRequest *digest_request = this;
+
+    /* do we have the HA1 */
+    if (!digest_user->HA1created) {
+        auth_user->credentials(AuthUser::Pending);
+        return;
+    }
+
+    if (digest_request->nonce == NULL) {
+        /* this isn't a nonce we issued */
+        auth_user->credentials(AuthUser::Failed);
+        return;
+    }
+
+    DigestCalcHA1(digest_request->algorithm, NULL, NULL, NULL,
+                  authenticateDigestNonceNonceb64(digest_request->nonce),
+                  digest_request->cnonce,
+                  digest_user->HA1, SESSIONKEY);
+    DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
+                       digest_request->nc, digest_request->cnonce, digest_request->qop,
+                       RequestMethodStr(request->method), digest_request->uri, HA2, Response);
+
+    debugs(29, 9, "\nResponse = '" << digest_request->response << "'\nsquid is = '" << Response << "'");
+
+    if (strcasecmp(digest_request->response, Response) != 0) {
+        if (!digest_request->flags.helper_queried) {
+            /* Query the helper in case the password has changed */
+            digest_request->flags.helper_queried = 1;
+            auth_user->credentials(AuthUser::Pending);
+            return;
+        }
+
+       if (static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->PostWorkaround && request->method != METHOD_GET) {
+            /* Ugly workaround for certain very broken browsers using the
+             * wrong method to calculate the request-digest on POST request.
+             * This should be deleted once Digest authentication becomes more
+             * widespread and such broken browsers no longer are commonly
+             * used.
+             */
+            DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
+                               digest_request->nc, digest_request->cnonce, digest_request->qop,
+                               RequestMethodStr(METHOD_GET), digest_request->uri, HA2, Response);
+
+            if (strcasecmp(digest_request->response, Response)) {
+                auth_user->credentials(AuthUser::Failed);
+                digest_request->flags.invalid_password = 1;
+                digest_request->setDenyMessage("Incorrect password");
+                return;
+            } else {
+                const char *useragent = request->header.getStr(HDR_USER_AGENT);
+
+                static Ip::Address last_broken_addr;
+                static int seen_broken_client = 0;
+
+                if (!seen_broken_client) {
+                    last_broken_addr.SetNoAddr();
+                    seen_broken_client = 1;
+                }
+
+                if (last_broken_addr != request->client_addr) {
+                    debugs(29, 1, "\nDigest POST bug detected from " <<
+                           request->client_addr << " using '" <<
+                           (useragent ? useragent : "-") <<
+                           "'. Please upgrade browser. See Bug #630 for details.");
+
+                    last_broken_addr = request->client_addr;
+                }
+            }
+        } else {
+            auth_user->credentials(AuthUser::Failed);
+            digest_request->flags.invalid_password = 1;
+            digest_request->setDenyMessage("Incorrect password");
+            return;
+        }
+
+        /* check for stale nonce */
+        if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) {
+            debugs(29, 3, "authenticateDigestAuthenticateuser: user '" << auth_user->username() << "' validated OK but nonce stale");
+            auth_user->credentials(AuthUser::Failed);
+            digest_request->setDenyMessage("Stale nonce");
+            return;
+        }
+    }
+
+    auth_user->credentials(AuthUser::Ok);
+
+    /* password was checked and did match */
+    debugs(29, 4, "authenticateDigestAuthenticateuser: user '" << auth_user->username() << "' validated OK");
+
+    /* auth_user is now linked, we reset these values
+     * after external auth occurs anyway */
+    auth_user->expiretime = current_time.tv_sec;
+    return;
+}
+
+int
+AuthDigestUserRequest::module_direction()
+{
+    if (user()->auth_type != AUTH_DIGEST)
+        return -2;
+
+    switch (user()->credentials()) {
+
+    case AuthUser::Ok:
+        return 0;
+
+    case AuthUser::Failed:
+        /* send new challenge */
+        return 1;
+
+    case AuthUser::Unchecked:
+    case AuthUser::Pending:
+        return -1;
+
+    default:
+        return -2;
+    }
+}
+
+/* add the [proxy]authorisation header */
+void
+AuthDigestUserRequest::addHeader(HttpReply * rep, int accel)
+{
+    http_hdr_type type;
+
+    /* don't add to authentication error pages */
+
+    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
+            || (accel && rep->sline.status == HTTP_UNAUTHORIZED))
+        return;
+
+    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
+
+#if WAITING_FOR_TE
+    /* test for http/1.1 transfer chunked encoding */
+    if (chunkedtest)
+        return;
+#endif
+
+    if ((static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->authenticate) && authDigestNonceLastRequest(nonce)) {
+        flags.authinfo_sent = 1;
+        debugs(29, 9, "authDigestAddHead: Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
+        httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nonce));
+    }
+}
+
+#if WAITING_FOR_TE
+/** add the [proxy]authorisation header */
+void
+AuthDigestUserRequest::addTrailer(HttpReply * rep, int accel)
+{
+    int type;
+
+    if (!auth_user_request)
+        return;
+
+    /* has the header already been send? */
+    if (flags.authinfo_sent)
+        return;
+
+    /* don't add to authentication error pages */
+    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
+            || (accel && rep->sline.status == HTTP_UNAUTHORIZED))
+        return;
+
+    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
+
+    if ((static_cast<AuthDigestConfig*>(digestScheme::GetInstance()->getConfig())->authenticate) && authDigestNonceLastRequest(nonce)) {
+        debugs(29, 9, "authDigestAddTrailer: Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
+        httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nonce));
+    }
+}
+#endif
+
+/* send the initial data to a digest authenticator module */
+void
+AuthDigestUserRequest::module_start(RH * handler, void *data)
+{
+    authenticateStateData *r = NULL;
+    char buf[8192];
+
+    assert(user() != NULL && user()->auth_type == AUTH_DIGEST);
+    debugs(29, 9, "authenticateStart: '\"" << user()->username() << "\":\"" << realm << "\"'");
+
+    if (static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->authenticate == NULL) {
+        debugs(29, DBG_CRITICAL, "ERROR: No Digest authentication program configured.");
+        handler(data, NULL);
+        return;
+    }
+
+    r = cbdataAlloc(authenticateStateData);
+    r->handler = handler;
+    r->data = cbdataReference(data);
+    r->auth_user_request = static_cast<AuthUserRequest*>(this);
+    if (static_cast<AuthDigestConfig*>(AuthConfig::Find("digest"))->utf8) {
+        char userstr[1024];
+        latin1_to_utf8(userstr, sizeof(userstr), user()->username());
+        snprintf(buf, 8192, "\"%s\":\"%s\"\n", userstr, realm);
+    } else {
+        snprintf(buf, 8192, "\"%s\":\"%s\"\n", user()->username(), realm);
+    }
+
+    helperSubmit(digestauthenticators, buf, AuthDigestUserRequest::HandleReply, r);
+}
+
+void
+AuthDigestUserRequest::HandleReply(void *data, char *reply)
+{
+    authenticateStateData *replyData = static_cast < authenticateStateData * >(data);
+    char *t = NULL;
+    void *cbdata;
+    debugs(29, 9, HERE << "{" << (reply ? reply : "<NULL>") << "}");
+
+    if (reply) {
+        if ((t = strchr(reply, ' ')))
+            *t++ = '\0';
+
+        if (*reply == '\0' || *reply == '\n')
+            reply = NULL;
+    }
+
+    assert(replyData->auth_user_request != NULL);
+    AuthUserRequest::Pointer auth_user_request = replyData->auth_user_request;
+
+    if (reply && (strncasecmp(reply, "ERR", 3) == 0)) {
+        /* allow this because the digest_request pointer is purely local */
+        AuthDigestUserRequest *digest_request = dynamic_cast<AuthDigestUserRequest *>(auth_user_request.getRaw());
+        assert(digest_request);
+
+        digest_request->user()->credentials(AuthUser::Failed);
+        digest_request->flags.invalid_password = 1;
+
+        if (t && *t)
+            digest_request->setDenyMessage(t);
+    } else if (reply) {
+        /* allow this because the digest_request pointer is purely local */
+        DigestUser *digest_user = dynamic_cast<DigestUser *>(auth_user_request->user().getRaw());
+        assert(digest_user != NULL);
+
+        CvtBin(reply, digest_user->HA1);
+        digest_user->HA1created = 1;
+    }
+
+    if (cbdataReferenceValidDone(replyData->data, &cbdata))
+        replyData->handler(cbdata, NULL);
+
+    replyData->auth_user_request = NULL;
+
+    cbdataFree(replyData);
+}
diff --git a/src/auth/digest/digestUserRequest.h b/src/auth/digest/digestUserRequest.h
new file mode 100644 (file)
index 0000000..6c706bf
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef _SQUID_SRC_AUTH_DIGEST_USERREQUEST_H
+#define _SQUID_SRC_AUTH_DIGEST_USERREQUEST_H
+
+#include "auth/UserRequest.h"
+#include "auth/digest/auth_digest.h"
+#include "MemPool.h"
+
+class ConnStateData;
+class HttpReply;
+class HttpRequest;
+
+/**
+ * The AuthDigestUserRequest structure is what follows the http_request around
+ */
+class AuthDigestUserRequest : public AuthUserRequest
+{
+
+public:
+    MEMPROXY_CLASS(AuthDigestUserRequest);
+
+    AuthDigestUserRequest();
+    virtual ~AuthDigestUserRequest();
+
+    virtual int authenticated() const;
+    virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type);
+    virtual int module_direction();
+    virtual void addHeader(HttpReply * rep, int accel);
+#if WAITING_FOR_TE
+
+    virtual void addTrailer(HttpReply * rep, int accel);
+#endif
+
+    virtual void module_start(RH *, void *);
+
+    char *nonceb64;             /* "dcd98b7102dd2f0e8b11d0f600bfb0c093" */
+    char *cnonce;               /* "0a4f113b" */
+    char *realm;                /* = "testrealm@host.com" */
+    char *pszPass;              /* = "Circle Of Life" */
+    char *algorithm;            /* = "md5" */
+    char nc[9];                 /* = "00000001" */
+    char *pszMethod;            /* = "GET" */
+    char *qop;                  /* = "auth" */
+    char *uri;                  /* = "/dir/index.html" */
+    char *response;
+
+    struct {
+        unsigned int authinfo_sent:1;
+        unsigned int invalid_password:1;
+        unsigned int helper_queried:1;
+    } flags;
+    digest_nonce_h *nonce;
+
+private:
+    static HLPCB HandleReply;
+};
+
+MEMPROXY_CLASS_INLINE(AuthDigestUserRequest);
+
+#endif /* _SQUID_SRC_AUTH_DIGEST_USERREQUEST_H */
index d41e0feacdc4f0df3efaf45b2243b710d6378892..b3fe433b5a3786cb5283c83b43f2ccb9237be6fe 100644 (file)
@@ -38,8 +38,9 @@
 
 
 #include "squid.h"
-#include "auth_negotiate.h"
+#include "auth/negotiate/auth_negotiate.h"
 #include "auth/Gadgets.h"
+#include "auth/State.h"
 #include "CacheManager.h"
 #include "Store.h"
 #include "client_side.h"
@@ -47,7 +48,8 @@
 #include "HttpRequest.h"
 #include "SquidTime.h"
 /** \todo remove this include */
-#include "negotiateScheme.h"
+#include "auth/negotiate/negotiateScheme.h"
+#include "auth/negotiate/negotiateUserRequest.h"
 #include "wordlist.h"
 
 /**
  \ingroup AuthNegotiateAPI
  */
 
-/**
- * Maximum length (buffer size) for token strings.
- */
-// AYJ: must match re-definition in helpers/negotiate_auth/squid_kerb_auth/squid_kerb_auth.c
-#define MAX_AUTHTOKEN_LEN   32768
-
-
-/// \ingroup AuthNegotiateInternal
-static void
-authenticateStateFree(authenticateStateData * r)
-{
-    AUTHUSERREQUESTUNLOCK(r->auth_user_request, "r");
-    cbdataFree(r);
-}
-
 /* Negotiate Scheme */
-static HLPSCB authenticateNegotiateHandleReply;
 static AUTHSSTATS authenticateNegotiateStats;
 
 /// \ingroup AuthNegotiateInternal
-static statefulhelper *negotiateauthenticators = NULL;
-
-CBDATA_TYPE(authenticateStateData);
+statefulhelper *negotiateauthenticators = NULL;
 
 /// \ingroup AuthNegotiateInternal
 static int authnegotiate_initialised = 0;
 
 /// \ingroup AuthNegotiateInternal
-static auth_negotiate_config negotiateConfig;
+AuthNegotiateConfig negotiateConfig;
 
 /// \ingroup AuthNegotiateInternal
 static hash_table *proxy_auth_cache = NULL;
@@ -94,35 +78,36 @@ static hash_table *proxy_auth_cache = NULL;
  *
  */
 
-/**
- \ingroup AuthNegotiateInternal
- \todo move to negotiateScheme.cc
- */
 void
-negotiateScheme::done()
+AuthNegotiateConfig::rotateHelpers()
 {
-    /* TODO: this should be a Config call. */
-    debugs(29, 2, "negotiateScheme::done: shutting down Negotiate authentication.");
-
-    if (negotiateauthenticators)
+    /* schedule closure of existing helpers */
+    if (negotiateauthenticators) {
         helperStatefulShutdown(negotiateauthenticators);
+    }
+
+    /* NP: dynamic helper restart will ensure they start up again as needed. */
+}
 
+void
+AuthNegotiateConfig::done()
+{
     authnegotiate_initialised = 0;
 
+    if (negotiateauthenticators) {
+        helperStatefulShutdown(negotiateauthenticators);
+    }
+
     if (!shutting_down)
         return;
 
     delete negotiateauthenticators;
     negotiateauthenticators = NULL;
 
-    debugs(29, 2, "negotiateScheme::done: Negotiate authentication Shutdown.");
-}
-
-void
-AuthNegotiateConfig::done()
-{
     if (authenticate)
         wordlistDestroy(&authenticate);
+
+    debugs(29, 2, "negotiateScheme::done: Negotiate authentication Shutdown.");
 }
 
 void
@@ -142,7 +127,7 @@ AuthNegotiateConfig::dump(StoreEntry * entry, const char *name, AuthConfig * sch
 
 }
 
-AuthNegotiateConfig::AuthNegotiateConfig() : authenticateChildren(20), keep_alive(1)
+AuthNegotiateConfig::AuthNegotiateConfig() : keep_alive(1)
 { }
 
 void
@@ -178,7 +163,7 @@ AuthNegotiateConfig::parse(AuthConfig * scheme, int n_configured, char *param_st
 const char *
 AuthNegotiateConfig::type() const
 {
-    return negotiateScheme::GetInstance().type();
+    return negotiateScheme::GetInstance()->type();
 }
 
 /**
@@ -240,66 +225,9 @@ AuthNegotiateConfig::configured() const
 }
 
 /* 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:
-        debugs(29, 1, "AuthNegotiateUserRequest::direction: called before Negotiate Authenticate for request " << this << "!. Report a bug to squid-dev.");
-        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_DONE:
-        return 0; /* do nothing */
-
-    case AUTHENTICATE_STATE_INITIAL:
-        debugs(29, 1, "AuthNegotiateUserRequest::direction: Unexpected AUTHENTICATE_STATE_INITIAL");
-        return -2;
-    }
-
-    return -2;
-}
-
-/* add the [proxy]authorisation header */
 void
-AuthNegotiateUserRequest::addHeader(HttpReply * rep, int accel)
-{
-    http_hdr_type type;
-
-    if (!server_blob)
-        return;
-
-    /* don't add to authentication error pages */
-
-    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
-            || (accel && rep->sline.status == HTTP_UNAUTHORIZED))
-        return;
-
-    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
-
-    httpHeaderPutStrf(&rep->header, type, "Negotiate %s", server_blob);
-
-    safe_free(server_blob);
-}
-
-void
-AuthNegotiateConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *rep, http_hdr_type reqType, HttpRequest * request)
+AuthNegotiateConfig::fixHeader(AuthUserRequest::Pointer auth_user_request, HttpReply *rep, http_hdr_type reqType, HttpRequest * request)
 {
     AuthNegotiateUserRequest *negotiate_request;
 
@@ -321,24 +249,22 @@ AuthNegotiateConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *re
             request->flags.proxy_keepalive = 0;
         }
     } else {
-        negotiate_request = dynamic_cast<AuthNegotiateUserRequest *>(auth_user_request);
-
+        negotiate_request = dynamic_cast<AuthNegotiateUserRequest *>(auth_user_request.getRaw());
         assert(negotiate_request != NULL);
 
-        switch (negotiate_request->auth_state) {
+        switch (negotiate_request->user()->credentials()) {
 
-        case AUTHENTICATE_STATE_FAILED:
+        case AuthUser::Failed:
             /* here it makes sense to drop the connection, as auth is
              * tied to it, even if MAYBE the client could handle it - Kinkie */
             rep->header.delByName("keep-alive");
             request->flags.proxy_keepalive = 0;
             /* fall through */
 
-        case AUTHENTICATE_STATE_DONE:
+        case AuthUser::Ok:
             /* Special case: authentication finished OK but disallowed by ACL.
              * Need to start over to give the client another chance.
              */
-
             if (negotiate_request->server_blob) {
                 debugs(29, 9, "authenticateNegotiateFixErrorHeader: Sending type:" << reqType << " header: 'Negotiate " << negotiate_request->server_blob << "'");
                 httpHeaderPutStrf(&rep->header, reqType, "Negotiate %s", negotiate_request->server_blob);
@@ -347,26 +273,24 @@ AuthNegotiateConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *re
                 debugs(29, 9, "authenticateNegotiateFixErrorHeader: Connection authenticated");
                 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
             }
-
             break;
 
-        case AUTHENTICATE_STATE_NONE:
+        case AuthUser::Unchecked:
             /* semantic change: do not drop the connection.
              * 2.5 implementation used to keep it open - Kinkie */
             debugs(29, 9, "AuthNegotiateConfig::fixHeader: Sending type:" << reqType << " header: 'Negotiate'");
             httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
             break;
 
-        case AUTHENTICATE_STATE_IN_PROGRESS:
+        case AuthUser::Handshake:
             /* we're waiting for a response from the client. Pass it the blob */
             debugs(29, 9, "AuthNegotiateConfig::fixHeader: Sending type:" << reqType << " header: 'Negotiate " << negotiate_request->server_blob << "'");
             httpHeaderPutStrf(&rep->header, reqType, "Negotiate %s", negotiate_request->server_blob);
             safe_free(negotiate_request->server_blob);
             break;
 
-
         default:
-            debugs(29, 0, "AuthNegotiateConfig::fixHeader: state " << negotiate_request->auth_state << ".");
+            debugs(29, DBG_CRITICAL, "AuthNegotiateConfig::fixHeader: state " << negotiate_request->user()->credentials() << ".");
             fatal("unexpected state in AuthenticateNegotiateFixErrorHeader.\n");
         }
     }
@@ -377,167 +301,10 @@ NegotiateUser::~NegotiateUser()
     debugs(29, 5, "NegotiateUser::~NegotiateUser: doing nothing to clearNegotiate scheme data for '" << this << "'");
 }
 
-static void
-authenticateNegotiateHandleReply(void *data, void *lastserver, char *reply)
+int32_t
+NegotiateUser::ttl() const
 {
-    authenticateStateData *r = static_cast<authenticateStateData *>(data);
-
-    int valid;
-    char *blob, *arg = NULL;
-
-    AuthUserRequest *auth_user_request;
-    AuthUser *auth_user;
-    NegotiateUser *negotiate_user;
-    AuthNegotiateUserRequest *negotiate_request;
-
-    debugs(29, 8, "authenticateNegotiateHandleReply: helper: '" << lastserver << "' sent us '" << (reply ? reply : "<NULL>") << "'");
-    valid = cbdataReferenceValid(r->data);
-
-    if (!valid) {
-        debugs(29, 1, "authenticateNegotiateHandleReply: invalid callback data. helper '" << lastserver << "'.");
-        cbdataReferenceDone(r->data);
-        authenticateStateFree(r);
-        return;
-    }
-
-    if (!reply) {
-        debugs(29, 1, "authenticateNegotiateHandleReply: Helper '" << lastserver << "' crashed!.");
-        reply = (char *)"BH Internal error";
-    }
-
-    auth_user_request = r->auth_user_request;
-    assert(auth_user_request != NULL);
-    negotiate_request = dynamic_cast<AuthNegotiateUserRequest *>(auth_user_request);
-
-    assert(negotiate_request != NULL);
-    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<negotiate_user_t *>(auth_user_request->user());
-
-    assert(negotiate_user != NULL);
-
-    if (negotiate_request->authserver == NULL)
-        negotiate_request->authserver = static_cast<helper_stateful_server*>(lastserver);
-    else
-        assert(negotiate_request->authserver == lastserver);
-
-    /* seperate out the useful data */
-    blob = strchr(reply, ' ');
-
-    if (blob) {
-        blob++;
-        arg = strchr(blob + 1, ' ');
-    } else {
-        arg = NULL;
-    }
-
-    if (strncasecmp(reply, "TT ", 3) == 0) {
-        /* we have been given a blob to send to the client */
-        if (arg)
-            *arg++ = '\0';
-        safe_free(negotiate_request->server_blob);
-        negotiate_request->request->flags.must_keepalive = 1;
-        if (negotiate_request->request->flags.proxy_keepalive) {
-            negotiate_request->server_blob = xstrdup(blob);
-            negotiate_request->auth_state = AUTHENTICATE_STATE_IN_PROGRESS;
-            auth_user_request->denyMessage("Authentication in progress");
-            debugs(29, 4, "authenticateNegotiateHandleReply: Need to challenge the client with a server blob '" << blob << "'");
-        } else {
-            negotiate_request->auth_state = AUTHENTICATE_STATE_FAILED;
-            auth_user_request->denyMessage("NTLM authentication requires a persistent connection");
-        }
-    } else if (strncasecmp(reply, "AF ", 3) == 0 && arg != 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);
-
-        negotiate_request->releaseAuthServer();
-
-        negotiate_request->auth_state = AUTHENTICATE_STATE_DONE;
-
-        debugs(29, 4, "authenticateNegotiateHandleReply: Successfully validated user via Negotiate. Username '" << blob << "'");
-
-        /* connection is authenticated */
-        debugs(29, 4, "AuthNegotiateUserRequest::authenticate: authenticated user " << negotiate_user->username());
-        /* see if this is an existing user with a different proxy_auth
-         * string */
-        AuthUserHashPointer *usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, negotiate_user->username()));
-        AuthUser *local_auth_user = negotiate_request->user();
-        while (usernamehash && (usernamehash->user()->auth_type != AUTH_NEGOTIATE || strcmp(usernamehash->user()->username(), negotiate_user->username()) != 0))
-            usernamehash = static_cast<AuthUserHashPointer *>(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();
-            negotiate_request->_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;
-        negotiate_request->releaseAuthServer();
-        negotiate_request->auth_state = AUTHENTICATE_STATE_DONE;
-
-    } else if (strncasecmp(reply, "NA ", 3) == 0 && arg != 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);
-
-        negotiate_request->releaseAuthServer();
-
-        debugs(29, 4, "authenticateNegotiateHandleReply: Failed validating user via Negotiate. Error returned '" << 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);
-        negotiate_request->releaseAuthServer();
-        debugs(29, 1, "authenticateNegotiateHandleReply: Error validating user via Negotiate. Error returned '" << reply << "'");
-    } else {
-        /* protocol error */
-        fatalf("authenticateNegotiateHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
-    }
-
-    if (negotiate_request->request) {
-        HTTPMSGUNLOCK(negotiate_request->request);
-        negotiate_request->request = NULL;
-    }
-    r->handler(r->data, NULL);
-    cbdataReferenceDone(r->data);
-    authenticateStateFree(r);
+    return -1; // Negotiate cannot be cached.
 }
 
 static void
@@ -546,273 +313,32 @@ authenticateNegotiateStats(StoreEntry * sentry)
     helperStatefulStats(sentry, negotiateauthenticators, "Negotiate Authenticator Statistics");
 }
 
-
-/** send the initial data to a stateful negotiate authenticator module */
-void
-AuthNegotiateUserRequest::module_start(RH * handler, void *data)
-{
-    authenticateStateData *r = NULL;
-    static char buf[MAX_AUTHTOKEN_LEN];
-    negotiate_user_t *negotiate_user;
-    AuthUser *auth_user = user();
-
-    assert(data);
-    assert(handler);
-    assert(auth_user);
-    assert(auth_user->auth_type == AUTH_NEGOTIATE);
-
-    negotiate_user = dynamic_cast<negotiate_user_t *>(user());
-
-    debugs(29, 8, "AuthNegotiateUserRequest::module_start: auth state is '" << auth_state << "'");
-
-    if (negotiateConfig.authenticate == NULL) {
-        debugs(29, 0, "AuthNegotiateUserRequest::module_start: no Negotiate program specified.");
-        handler(data, NULL);
-        return;
-    }
-
-    r = cbdataAlloc(authenticateStateData);
-    r->handler = handler;
-    r->data = cbdataReference(data);
-    r->auth_user_request = this;
-    AUTHUSERREQUESTLOCK(r->auth_user_request, "r");
-
-    if (auth_state == AUTHENTICATE_STATE_INITIAL) {
-        snprintf(buf, MAX_AUTHTOKEN_LEN, "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
-    } else {
-        snprintf(buf, MAX_AUTHTOKEN_LEN, "KK %s\n", client_blob);
-    }
-
-    waiting = 1;
-
-    safe_free(client_blob);
-    helperStatefulSubmit(negotiateauthenticators, buf, authenticateNegotiateHandleReply, r, authserver);
-}
-
-/**
- * Atomic action: properly release the Negotiate auth helpers which may have been reserved
- * for this request connections use.
- */
-void
-AuthNegotiateUserRequest::releaseAuthServer()
-{
-    if (authserver) {
-        debugs(29, 6, HERE << "releasing Negotiate auth server '" << authserver << "'");
-        helperStatefulReleaseServer(authserver);
-        authserver = NULL;
-    } else
-        debugs(29, 6, HERE << "No Negotiate auth server to release.");
-}
-
-/* clear any connection related authentication details */
-void
-AuthNegotiateUserRequest::onConnectionClose(ConnStateData *conn)
-{
-    assert(conn != NULL);
-
-    debugs(29, 8, "AuthNegotiateUserRequest::onConnectionClose: closing connection '" << conn << "' (this is '" << this << "')");
-
-    if (conn->auth_user_request == NULL) {
-        debugs(29, 8, "AuthNegotiateUserRequest::onConnectionClose: no auth_user_request");
-        return;
-    }
-
-    releaseAuthServer();
-
-    /* unlock the connection based lock */
-    debugs(29, 9, "AuthNegotiateUserRequest::onConnectionClose: Unlocking auth_user from the connection '" << conn << "'.");
-
-    AUTHUSERREQUESTUNLOCK(conn->auth_user_request, "conn");
-}
-
 /*
  * Decode a Negotiate [Proxy-]Auth string, placing the results in the passed
  * Auth_user structure.
  */
-AuthUserRequest *
+AuthUserRequest::Pointer
 AuthNegotiateConfig::decode(char const *proxy_auth)
 {
     NegotiateUser *newUser = new NegotiateUser(&negotiateConfig);
-    AuthNegotiateUserRequest *auth_user_request = new AuthNegotiateUserRequest ();
+    AuthUserRequest *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 */
     debugs(29, 9, "AuthNegotiateConfig::decode: Negotiate authentication");
     return auth_user_request;
 }
 
-int
-AuthNegotiateUserRequest::authenticated() const
-{
-    if (auth_state == AUTHENTICATE_STATE_DONE) {
-        debugs(29, 9, "AuthNegotiateUserRequest::authenticated: user authenticated.");
-        return 1;
-    }
-
-    debugs(29, 9, "AuthNegotiateUserRequest::authenticated: user not fully authenticated.");
-
-    return 0;
-}
-
-void
-AuthNegotiateUserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, http_hdr_type type)
-{
-    const char *proxy_auth, *blob;
-
-    /** \todo rename this!! */
-    AuthUser *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<negotiate_user_t *>(local_auth_user);
-    assert (this);
-
-    /** Check that we are in the client side, where we can generate
-     * auth challenges */
-
-    if (conn == NULL) {
-        auth_state = AUTHENTICATE_STATE_FAILED;
-        debugs(29, 1, "AuthNegotiateUserRequest::authenticate: attempt to perform authentication without a connection!");
-        return;
-    }
-
-    if (waiting) {
-        debugs(29, 1, "AuthNegotiateUserRequest::authenticate: waiting for helper reply!");
-        return;
-    }
-
-    if (server_blob) {
-        debugs(29, 2, "AuthNegotiateUserRequest::authenticate: need to challenge client '" << server_blob << "'!");
-        return;
-    }
-
-    /* get header */
-    proxy_auth = aRequest->header.getStr(type);
-
-    /* locate second word */
-    blob = proxy_auth;
-
-    if (blob) {
-        while (xisspace(*blob) && *blob)
-            blob++;
-
-        while (!xisspace(*blob) && *blob)
-            blob++;
-
-        while (xisspace(*blob) && *blob)
-            blob++;
-    }
-
-    switch (auth_state) {
-
-    case AUTHENTICATE_STATE_NONE:
-        /* we've received a negotiate request. pass to a helper */
-        debugs(29, 9, "AuthNegotiateUserRequest::authenticate: auth state negotiate none. Received blob: '" << proxy_auth << "'");
-        auth_state = AUTHENTICATE_STATE_INITIAL;
-        safe_free(client_blob);
-        client_blob=xstrdup(blob);
-        conn->auth_type = AUTH_NEGOTIATE;
-        assert(conn->auth_user_request == NULL);
-        conn->auth_user_request = this;
-        AUTHUSERREQUESTLOCK(conn->auth_user_request, "conn");
-        request = aRequest;
-        HTTPMSGLOCK(request);
-        return;
-
-        break;
-
-    case AUTHENTICATE_STATE_INITIAL:
-        debugs(29, 1, "AuthNegotiateUserRequest::authenticate: need to ask helper");
-
-        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);
-
-        if (request)
-            HTTPMSGUNLOCK(request);
-        request = aRequest;
-        HTTPMSGLOCK(request);
-        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 */
-        debugs(29, 9, "AuthNegotiateUserRequest::authenticate: auth state negotiate failed. " << 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;
-    request=NULL;
-}
-
-AuthNegotiateUserRequest::~AuthNegotiateUserRequest()
-{
-    safe_free(server_blob);
-    safe_free(client_blob);
-
-    if (authserver != NULL) {
-        debugs(29, 9, "AuthNegotiateUserRequest::~AuthNegotiateUserRequest: releasing server '" << authserver << "'");
-        helperStatefulReleaseServer(authserver);
-        authserver = NULL;
-    }
-    if (request) {
-        HTTPMSGUNLOCK(request);
-        request = NULL;
-    }
-}
-
 void
 NegotiateUser::deleteSelf() const
 {
     delete this;
 }
 
-NegotiateUser::NegotiateUser (AuthConfig *aConfig) : AuthUser (aConfig)
+NegotiateUser::NegotiateUser(AuthConfig *aConfig) : AuthUser (aConfig)
 {
     proxy_auth_list.head = proxy_auth_list.tail = NULL;
 }
-
-AuthConfig *
-negotiateScheme::createConfig()
-{
-    return &negotiateConfig;
-}
-
-const char *
-AuthNegotiateUserRequest::connLastHeader()
-{
-    return NULL;
-}
-
index 74bd5a48d26ee7d648df5f5130dda623ce4eb3b8..f5d414b0f31b5ef177b9ab65eb42f6fca31c71a0 100644 (file)
@@ -5,10 +5,12 @@
 
 #ifndef __AUTH_NEGOTIATE_H__
 #define __AUTH_NEGOTIATE_H__
+
+#include "auth/Config.h"
 #include "auth/Gadgets.h"
+#include "auth/State.h"
 #include "auth/User.h"
 #include "auth/UserRequest.h"
-#include "auth/Config.h"
 #include "helper.h"
 
 /**
 /// \ingroup AuthNegotiateAPI
 #define DefaultAuthenticateChildrenMax  32     /* 32 processes */
 
-#ifndef __AUTH_AUTHENTICATE_STATE_T__
-#define __AUTH_AUTHENTICATE_STATE_T__
-
-/// \ingroup AuthNegotiateAPI
-typedef enum {
-    AUTHENTICATE_STATE_NONE,
-    AUTHENTICATE_STATE_INITIAL,
-    AUTHENTICATE_STATE_IN_PROGRESS,
-    AUTHENTICATE_STATE_DONE,
-    AUTHENTICATE_STATE_FAILED
-} auth_state_t;                 /* connection level auth state */
-
-/* Generic */
-
-/// \ingroup AuthNegotiateAPI
-typedef struct {
-    void *data;
-    AuthUserRequest *auth_user_request;
-    RH *handler;
-} authenticateStateData;
-#endif
-
 /// \ingroup AuthNegotiateAPI
 class NegotiateUser : public AuthUser
 {
 
 public:
     MEMPROXY_CLASS(NegotiateUser);
-    virtual void deleteSelf() const;
     NegotiateUser(AuthConfig *);
     ~NegotiateUser();
+    virtual void deleteSelf() const;
+    virtual int32_t ttl() const;
+
     dlink_list proxy_auth_list;
 };
 
 MEMPROXY_CLASS_INLINE(NegotiateUser);
 
-/// \ingroup AuthNegotiateAPI
-typedef class NegotiateUser negotiate_user_t;
-
-/// \ingroup AuthNegotiateAPI
-class AuthNegotiateUserRequest : public AuthUserRequest
-{
-
-public:
-    MEMPROXY_CLASS(AuthNegotiateUserRequest);
-
-    AuthNegotiateUserRequest();
-    virtual ~AuthNegotiateUserRequest();
-    virtual int authenticated() const;
-    virtual void authenticate(HttpRequest * request, ConnStateData * 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 addHeader(HttpReply * rep, int accel);
-
-    virtual void user (AuthUser *aUser) {_theUser=dynamic_cast<NegotiateUser *>(aUser);}
-
-    virtual const char * connLastHeader();
-
-    /*we need to store the helper server between requests */
-    helper_stateful_server *authserver;
-    void releaseAuthServer(void); ///< Release the authserver helper server properly.
-
-    /* what connection is this associated with */
-    /* ConnStateData * 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;
-
-    /* need access to the request flags to mess around on pconn failure */
-    HttpRequest *request;
-
-private:
-    /* the user */
-    NegotiateUser * _theUser;
-};
-
-MEMPROXY_CLASS_INLINE(AuthNegotiateUserRequest);
-
-#include "HelperChildConfig.h"
+extern statefulhelper *negotiateauthenticators;
 
 /* configuration runtime data */
 
@@ -122,20 +49,18 @@ public:
     AuthNegotiateConfig();
     virtual bool active() const;
     virtual bool configured() const;
-    virtual AuthUserRequest *decode(char const *proxy_auth);
+    virtual AuthUserRequest::Pointer decode(char const *proxy_auth);
     virtual void done();
+    virtual void rotateHelpers();
     virtual void dump(StoreEntry *, const char *, AuthConfig *);
-    virtual void fixHeader(AuthUserRequest *, HttpReply *, http_hdr_type, HttpRequest *);
+    virtual void fixHeader(AuthUserRequest::Pointer, HttpReply *, http_hdr_type, HttpRequest *);
     virtual void init(AuthConfig *);
     virtual void parse(AuthConfig *, int, char *);
     virtual void registerWithCacheManager(void);
     virtual const char * type() const;
-    HelperChildConfig authenticateChildren;
     int keep_alive;
-    wordlist *authenticate;
 };
 
-/// \ingroup AuthNegotiateAPI
-typedef class AuthNegotiateConfig auth_negotiate_config;
+extern AuthNegotiateConfig negotiateConfig;
 
 #endif
index 499375effaa5a78c84ec297b720a29e43224ca6a..411415a2fe71d0d9718a34a86b0ae6be1fde7b21 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
  *
  */
 
-#include "negotiateScheme.h"
+#include "config.h"
+#include "auth/negotiate/negotiateScheme.h"
+#include "helper.h"
 
-AuthScheme &
+AuthScheme::Pointer
 negotiateScheme::GetInstance()
 {
-    if (_instance == NULL)
+    if (_instance == NULL) {
         _instance = new negotiateScheme();
-    return *_instance;
-}
-
-negotiateScheme::negotiateScheme()
-{
-    AddScheme(*this);
+        AddScheme(_instance);
+    }
+    return _instance;
 }
 
 char const *
@@ -52,4 +50,24 @@ negotiateScheme::type () const
     return "negotiate";
 }
 
-negotiateScheme *negotiateScheme::_instance = NULL;
+AuthScheme::Pointer negotiateScheme::_instance = NULL;
+
+/**
+ \ingroup AuthNegotiateInternal
+ \todo move to negotiateScheme.cc
+ */
+void
+negotiateScheme::done()
+{
+    /* clear the global handle to this scheme. */
+    _instance = NULL;
+
+    debugs(29, 2, "negotiateScheme::done: Negotiate authentication Shutdown.");
+}
+
+AuthConfig *
+negotiateScheme::createConfig()
+{
+    AuthNegotiateConfig *negotiateCfg = new AuthNegotiateConfig;
+    return dynamic_cast<AuthConfig*>(negotiateCfg);
+}
index bde9a5976989e830db4750958cfb0e73427ad5d8..89ad24495b35407dd9047c15905d7f79cde6640f 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
@@ -35,6 +34,7 @@
 #define SQUID_NEGOTIATESCHEME_H
 
 #include "auth/Scheme.h"
+#include "auth/negotiate/auth_negotiate.h"
 
 /// \ingroup AuthSchemeAPI
 /// \ingroup AuthAPI
@@ -42,20 +42,21 @@ class negotiateScheme : public AuthScheme
 {
 
 public:
-    static AuthScheme &GetInstance();
-    negotiateScheme();
+    static AuthScheme::Pointer 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;
+    static AuthScheme::Pointer _instance;
 };
 
 #endif /* SQUID_negotiateSCHEME_H */
diff --git a/src/auth/negotiate/negotiateUserRequest.cc b/src/auth/negotiate/negotiateUserRequest.cc
new file mode 100644 (file)
index 0000000..e9e0863
--- /dev/null
@@ -0,0 +1,404 @@
+#include "config.h"
+#include "auth/negotiate/auth_negotiate.h"
+#include "auth/negotiate/negotiateUserRequest.h"
+#include "auth/User.h"
+#include "helper.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "SquidTime.h"
+
+/**
+ * Maximum length (buffer size) for token strings.
+ */
+// AYJ: must match re-definition in helpers/negotiate_auth/kerberos/negotiate_kerb_auth.cc
+#define MAX_AUTHTOKEN_LEN   32768
+
+AuthNegotiateUserRequest::AuthNegotiateUserRequest()
+{
+    waiting=0;
+    client_blob=0;
+    server_blob=0;
+    authserver=NULL;
+    request=NULL;
+}
+
+AuthNegotiateUserRequest::~AuthNegotiateUserRequest()
+{
+    assert(RefCountCount()==0);
+    safe_free(server_blob);
+    safe_free(client_blob);
+
+    if (authserver != NULL) {
+        debugs(29, 9, HERE << "releasing server '" << authserver << "'");
+        helperStatefulReleaseServer(authserver);
+        authserver = NULL;
+    }
+    if (request) {
+        HTTPMSGUNLOCK(request);
+        request = NULL;
+    }
+}
+
+const char *
+AuthNegotiateUserRequest::connLastHeader()
+{
+    return NULL;
+}
+
+int
+AuthNegotiateUserRequest::authenticated() const
+{
+    if (user() != NULL && user()->credentials() == AuthUser::Ok) {
+        debugs(29, 9, HERE << "user authenticated.");
+        return 1;
+    }
+
+    debugs(29, 9, HERE << "user not fully authenticated.");
+    return 0;
+}
+
+/* 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 */
+
+    if (user()->auth_type != AUTH_NEGOTIATE)
+        return -2;
+
+    switch (user()->credentials()) {
+
+    case AuthUser::Handshake:
+        assert(server_blob);
+        return 1; /* send to client */
+
+    case AuthUser::Ok:
+        return 0; /* do nothing */
+
+    case AuthUser::Failed:
+        return -2;
+
+    default:
+        debugs(29, DBG_IMPORTANT, "WARNING: Negotiate Authentication in unexpected state: " << user()->credentials());
+        return -2;
+    }
+}
+
+/* add the [proxy]authorisation header */
+void
+AuthNegotiateUserRequest::addHeader(HttpReply * rep, int accel)
+{
+    http_hdr_type type;
+
+    if (!server_blob)
+        return;
+
+    /* don't add to authentication error pages */
+    if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
+            || (accel && rep->sline.status == HTTP_UNAUTHORIZED))
+        return;
+
+    type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
+    httpHeaderPutStrf(&rep->header, type, "Negotiate %s", server_blob);
+
+    safe_free(server_blob);
+}
+
+/** send the initial data to a stateful negotiate authenticator module */
+void
+AuthNegotiateUserRequest::module_start(RH * handler, void *data)
+{
+    static char buf[MAX_AUTHTOKEN_LEN];
+
+    assert(data);
+    assert(handler);
+
+    assert(user() != NULL);
+    assert(user()->auth_type == AUTH_NEGOTIATE);
+
+    debugs(29, 8, HERE << "auth state is '" << user()->credentials() << "'");
+
+    if (static_cast<AuthNegotiateConfig*>(AuthConfig::Find("negotiate"))->authenticate == NULL) {
+        debugs(29, DBG_CRITICAL, "ERROR: No Negotiate authentication program configured.");
+        handler(data, NULL);
+        return;
+    }
+
+    authenticateStateData *r = cbdataAlloc(authenticateStateData);
+    r->handler = handler;
+    r->data = cbdataReference(data);
+    r->auth_user_request = this;
+
+    if (user()->credentials() == AuthUser::Pending) {
+        snprintf(buf, MAX_AUTHTOKEN_LEN, "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
+    } else {
+        snprintf(buf, MAX_AUTHTOKEN_LEN, "KK %s\n", client_blob);
+    }
+
+    waiting = 1;
+
+    safe_free(client_blob);
+    helperStatefulSubmit(negotiateauthenticators, buf, AuthNegotiateUserRequest::HandleReply, r, authserver);
+}
+
+/**
+ * Atomic action: properly release the Negotiate auth helpers which may have been reserved
+ * for this request connections use.
+ */
+void
+AuthNegotiateUserRequest::releaseAuthServer()
+{
+    if (authserver) {
+        debugs(29, 6, HERE << "releasing Negotiate auth server '" << authserver << "'");
+        helperStatefulReleaseServer(authserver);
+        authserver = NULL;
+    } else
+        debugs(29, 6, HERE << "No Negotiate auth server to release.");
+}
+
+/* clear any connection related authentication details */
+void
+AuthNegotiateUserRequest::onConnectionClose(ConnStateData *conn)
+{
+    assert(conn != NULL);
+
+    debugs(29, 8, "AuthNegotiateUserRequest::onConnectionClose: closing connection '" << conn << "' (this is '" << this << "')");
+
+    if (conn->auth_user_request == NULL) {
+        debugs(29, 8, "AuthNegotiateUserRequest::onConnectionClose: no auth_user_request");
+        return;
+    }
+
+    releaseAuthServer();
+
+    /* unlock the connection based lock */
+    debugs(29, 9, "AuthNegotiateUserRequest::onConnectionClose: Unlocking auth_user from the connection '" << conn << "'.");
+
+    conn->auth_user_request = NULL;
+}
+
+void
+AuthNegotiateUserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, http_hdr_type type)
+{
+    assert (this);
+
+    /** Check that we are in the client side, where we can generate auth challenges */
+    if (conn == NULL) {
+        user()->credentials(AuthUser::Failed);
+        debugs(29, DBG_IMPORTANT, "WARNING: Negotiate Authentication attempt to perform authentication without a connection!");
+        return;
+    }
+
+    if (waiting) {
+        debugs(29, DBG_IMPORTANT, "WARNING: Negotiate Authentication waiting for helper reply!");
+        return;
+    }
+
+    if (server_blob) {
+        debugs(29, 2, HERE << "need to challenge client '" << server_blob << "'!");
+        return;
+    }
+
+    /* get header */
+    const char *proxy_auth = aRequest->header.getStr(type);
+
+    /* locate second word */
+    const char *blob = proxy_auth;
+
+    if (blob) {
+        while (xisspace(*blob) && *blob)
+            blob++;
+
+        while (!xisspace(*blob) && *blob)
+            blob++;
+
+        while (xisspace(*blob) && *blob)
+            blob++;
+    }
+
+    switch (user()->credentials()) {
+
+    case AuthUser::Unchecked:
+        /* we've received a negotiate request. pass to a helper */
+        debugs(29, 9, HERE << "auth state negotiate none. Received blob: '" << proxy_auth << "'");
+        user()->credentials(AuthUser::Pending);
+        safe_free(client_blob);
+        client_blob=xstrdup(blob);
+        assert(conn->auth_user_request == NULL);
+        conn->auth_user_request = this;
+        request = aRequest;
+        HTTPMSGLOCK(request);
+        break;
+
+    case AuthUser::Pending:
+        debugs(29, 1, HERE << "need to ask helper");
+        break;
+
+    case AuthUser::Handshake:
+        /* we should have received a blob from the client. Hand it off to
+         * some helper */
+        safe_free(client_blob);
+        client_blob = xstrdup(blob);
+        if (request)
+            HTTPMSGUNLOCK(request);
+        request = aRequest;
+        HTTPMSGLOCK(request);
+        break;
+
+    case AuthUser::Ok:
+        fatal("AuthNegotiateUserRequest::authenticate: unexpected auth state DONE! Report a bug to the squid developers.\n");
+        break;
+
+    case AuthUser::Failed:
+        /* we've failed somewhere in authentication */
+        debugs(29, 9, HERE << "auth state negotiate failed. " << proxy_auth);
+        break;
+   }
+
+    return;
+}
+
+void
+AuthNegotiateUserRequest::HandleReply(void *data, void *lastserver, char *reply)
+{
+    authenticateStateData *r = static_cast<authenticateStateData *>(data);
+
+    int valid;
+    char *blob, *arg = NULL;
+
+    debugs(29, 8, HERE << "helper: '" << lastserver << "' sent us '" << (reply ? reply : "<NULL>") << "'");
+    valid = cbdataReferenceValid(r->data);
+
+    if (!valid) {
+        debugs(29, DBG_IMPORTANT, "ERROR: Negotiate Authentication invalid callback data. helper '" << lastserver << "'.");
+        cbdataReferenceDone(r->data);
+        authenticateStateFree(r);
+        return;
+   }
+
+    if (!reply) {
+        debugs(29, DBG_IMPORTANT, "ERROR: Negotiate Authentication Helper '" << lastserver << "' crashed!.");
+        reply = (char *)"BH Internal error";
+    }
+
+    AuthUserRequest::Pointer auth_user_request = r->auth_user_request;
+    assert(auth_user_request != NULL);
+
+    AuthNegotiateUserRequest *negotiate_request = dynamic_cast<AuthNegotiateUserRequest *>(auth_user_request.getRaw());
+    assert(negotiate_request != NULL);
+
+    assert(negotiate_request->waiting);
+    negotiate_request->waiting = 0;
+    safe_free(negotiate_request->client_blob);
+
+    assert(auth_user_request->user() != NULL);
+    assert(auth_user_request->user()->auth_type == AUTH_NEGOTIATE);
+
+    if (negotiate_request->authserver == NULL)
+        negotiate_request->authserver = static_cast<helper_stateful_server*>(lastserver);
+    else
+        assert(negotiate_request->authserver == lastserver);
+
+    /* seperate out the useful data */
+    blob = strchr(reply, ' ');
+
+    if (blob) {
+        blob++;
+        arg = strchr(blob + 1, ' ');
+    } else {
+        arg = NULL;
+    }
+
+    if (strncasecmp(reply, "TT ", 3) == 0) {
+        /* we have been given a blob to send to the client */
+        if (arg)
+            *arg++ = '\0';
+        safe_free(negotiate_request->server_blob);
+        negotiate_request->request->flags.must_keepalive = 1;
+        if (negotiate_request->request->flags.proxy_keepalive) {
+            negotiate_request->server_blob = xstrdup(blob);
+            auth_user_request->user()->credentials(AuthUser::Handshake);
+            auth_user_request->denyMessage("Authentication in progress");
+            debugs(29, 4, HERE << "Need to challenge the client with a server blob '" << blob << "'");
+        } else {
+            auth_user_request->user()->credentials(AuthUser::Failed);
+            auth_user_request->denyMessage("NTLM authentication requires a persistent connection");
+        }
+    } else if (strncasecmp(reply, "AF ", 3) == 0 && arg != NULL) {
+        /* we're finished, release the helper */
+
+        if (arg)
+            *arg++ = '\0';
+
+        auth_user_request->user()->username(arg);
+        auth_user_request->denyMessage("Login successful");
+        safe_free(negotiate_request->server_blob);
+        negotiate_request->server_blob = xstrdup(blob);
+        negotiate_request->releaseAuthServer();
+        auth_user_request->user()->credentials(AuthUser::Ok);
+        debugs(29, 4, HERE << "Successfully validated user via Negotiate. Username '" << blob << "'");
+
+        /* connection is authenticated */
+        debugs(29, 4, HERE << "authenticated user " << auth_user_request->user()->username());
+        /* see if this is an existing user with a different proxy_auth
+         * string */
+        AuthUserHashPointer *usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, auth_user_request->user()->username()));
+        AuthUser::Pointer local_auth_user = negotiate_request->user();
+        while (usernamehash && (usernamehash->user()->auth_type != AUTH_NEGOTIATE || strcmp(usernamehash->user()->username(), auth_user_request->user()->username()) != 0))
+            usernamehash = static_cast<AuthUserHashPointer *>(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 after merging as
+             * much of it new state into the existing one as possible */
+            usernamehash->user()->absorb(local_auth_user);
+            local_auth_user = usernamehash->user();
+            /* from here on we are working with the original cached credentials. */
+            negotiate_request->_auth_user = local_auth_user;
+        } else {
+            /* store user in hash's */
+            local_auth_user->addToNameCache();
+        }
+        /* 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;
+        negotiate_request->releaseAuthServer();
+        negotiate_request->user()->credentials(AuthUser::Ok);
+
+    } else if (strncasecmp(reply, "NA ", 3) == 0 && arg != NULL) {
+        /* authentication failure (wrong password, etc.) */
+
+        if (arg)
+            *arg++ = '\0';
+
+        auth_user_request->denyMessage(arg);
+        negotiate_request->user()->credentials(AuthUser::Failed);
+        safe_free(negotiate_request->server_blob);
+        negotiate_request->server_blob = xstrdup(blob);
+        negotiate_request->releaseAuthServer();
+        debugs(29, 4, HERE << "Failed validating user via Negotiate. Error returned '" << 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);
+        auth_user_request->user()->credentials(AuthUser::Failed);
+        safe_free(negotiate_request->server_blob);
+        negotiate_request->releaseAuthServer();
+        debugs(29, DBG_IMPORTANT, "ERROR: Negotiate Authentication validating user. Error returned '" << reply << "'");
+    } else {
+        /* protocol error */
+        fatalf("authenticateNegotiateHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
+    }
+
+    negotiate_request->request = NULL;
+    r->handler(r->data, NULL);
+    cbdataReferenceDone(r->data);
+    authenticateStateFree(r);
+}
+
diff --git a/src/auth/negotiate/negotiateUserRequest.h b/src/auth/negotiate/negotiateUserRequest.h
new file mode 100644 (file)
index 0000000..657f4b5
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _SQUID_SRC_AUTH_NEGOTIATE_USERREQUEST_H
+#define _SQUID_SRC_AUTH_NEGOTIATE_USERREQUEST_H
+
+#include "auth/UserRequest.h"
+#include "helper.h"
+#include "MemPool.h"
+
+class ConnStateData;
+class HttpReply;
+class HttpRequest;
+struct helper_stateful_server;
+
+/// \ingroup AuthNegotiateAPI
+class AuthNegotiateUserRequest : public AuthUserRequest
+{
+
+public:
+    MEMPROXY_CLASS(AuthNegotiateUserRequest);
+
+    AuthNegotiateUserRequest();
+    virtual ~AuthNegotiateUserRequest();
+    virtual int authenticated() const;
+    virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type);
+    virtual int module_direction();
+    virtual void onConnectionClose(ConnStateData *);
+    virtual void module_start(RH *, void *);
+
+    virtual void addHeader(HttpReply * rep, int accel);
+
+    virtual const char * connLastHeader();
+
+    /* we need to store the helper server between requests */
+    helper_stateful_server *authserver;
+    void releaseAuthServer(void); ///< Release the authserver helper server properly.
+
+    /* what connection is this associated with */
+    /* ConnStateData * conn;*/
+
+    /* 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;
+
+    /* need access to the request flags to mess around on pconn failure */
+    HttpRequest *request;
+
+private:
+    static HLPSCB HandleReply;
+};
+
+MEMPROXY_CLASS_INLINE(AuthNegotiateUserRequest);
+
+#endif /* _SQUID_SRC_AUTH_NEGOTIATE_USERREQUEST_H */
index 2546362da1b8d1689dc3f4b44b590c4958a4ba80..500bcf05d39c429ea6a9ec79e624b2c3745b7416 100644 (file)
 
 
 #include "squid.h"
-#include "auth_ntlm.h"
 #include "auth/Gadgets.h"
+#include "auth/ntlm/auth_ntlm.h"
+#include "auth/ntlm/ntlmScheme.h"
+#include "auth/ntlm/ntlmUserRequest.h"
+#include "auth/State.h"
 #include "CacheManager.h"
 #include "Store.h"
 #include "client_side.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
-/* TODO remove this include */
-#include "ntlmScheme.h"
 #include "wordlist.h"
 #include "SquidTime.h"
 
-
-static void
-authenticateStateFree(authenticateStateData * r)
-{
-    AUTHUSERREQUESTUNLOCK(r->auth_user_request, "r");
-    cbdataFree(r);
-}
-
 /* NTLM Scheme */
-static HLPSCB authenticateNTLMHandleReply;
 static AUTHSSTATS authenticateNTLMStats;
 
-static statefulhelper *ntlmauthenticators = NULL;
-
-CBDATA_TYPE(authenticateStateData);
-
+statefulhelper *ntlmauthenticators = NULL;
 static int authntlm_initialised = 0;
 
-static auth_ntlm_config ntlmConfig;
-
 static hash_table *proxy_auth_cache = NULL;
 
 /*
@@ -78,33 +65,37 @@ static hash_table *proxy_auth_cache = NULL;
  *
  */
 
-/* move to ntlmScheme.cc */
 void
-ntlmScheme::done()
+AuthNTLMConfig::rotateHelpers()
 {
-    /* TODO: this should be a Config call. */
-    debugs(29, 2, "ntlmScheme::done: shutting down NTLM authentication.");
-
-    if (ntlmauthenticators)
+    /* schedule closure of existing helpers */
+    if (ntlmauthenticators) {
         helperStatefulShutdown(ntlmauthenticators);
+    }
 
+    /* NP: dynamic helper restart will ensure they start up again as needed. */
+}
+
+/* free any allocated configuration details */
+void
+AuthNTLMConfig::done()
+{
     authntlm_initialised = 0;
 
+    if (ntlmauthenticators) {
+        helperStatefulShutdown(ntlmauthenticators);
+    }
+
     if (!shutting_down)
         return;
 
     delete ntlmauthenticators;
     ntlmauthenticators = NULL;
 
-    debugs(29, 2, "ntlmScheme::done: NTLM authentication Shutdown.");
-}
-
-/* free any allocated configuration details */
-void
-AuthNTLMConfig::done()
-{
     if (authenticate)
         wordlistDestroy(&authenticate);
+
+    debugs(29, 2, "ntlmScheme::done: NTLM authentication Shutdown.");
 }
 
 void
@@ -124,7 +115,7 @@ AuthNTLMConfig::dump(StoreEntry * entry, const char *name, AuthConfig * scheme)
 
 }
 
-AuthNTLMConfig::AuthNTLMConfig() : authenticateChildren(20), keep_alive(1)
+AuthNTLMConfig::AuthNTLMConfig() : keep_alive(1)
 { }
 
 void
@@ -160,7 +151,7 @@ AuthNTLMConfig::parse(AuthConfig * scheme, int n_configured, char *param_str)
 const char *
 AuthNTLMConfig::type() const
 {
-    return ntlmScheme::GetInstance().type();
+    return ntlmScheme::GetInstance()->type();
 }
 
 /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
@@ -220,47 +211,10 @@ AuthNTLMConfig::configured() const
 }
 
 /* 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:
-        debugs(29, 1, "AuthNTLMUserRequest::direction: called before NTLM Authenticate for request " << this << "!. Report a bug to squid-dev.");
-        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_DONE:
-        return 0; /* do nothing */
-
-    case AUTHENTICATE_STATE_INITIAL:
-        debugs(29, 1, "AuthNTLMUserRequest::direction: Unexpected AUTHENTICATE_STATE_INITIAL");
-        return -2;
-    }
-
-    return -2;
-}
 
 void
-AuthNTLMConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *rep, http_hdr_type hdrType, HttpRequest * request)
+AuthNTLMConfig::fixHeader(AuthUserRequest::Pointer auth_user_request, HttpReply *rep, http_hdr_type hdrType, HttpRequest * request)
 {
-    AuthNTLMUserRequest *ntlm_request;
-
     if (!authenticate)
         return;
 
@@ -278,41 +232,39 @@ AuthNTLMConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *rep, ht
             request->flags.proxy_keepalive = 0;
         }
     } else {
-        ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request);
-
+        AuthNTLMUserRequest *ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request.getRaw());
         assert(ntlm_request != NULL);
 
-        switch (ntlm_request->auth_state) {
+        switch (ntlm_request->user()->credentials()) {
 
-        case AUTHENTICATE_STATE_FAILED:
+        case AuthUser::Failed:
             /* here it makes sense to drop the connection, as auth is
              * tied to it, even if MAYBE the client could handle it - Kinkie */
             request->flags.proxy_keepalive = 0;
             /* fall through */
 
-        case AUTHENTICATE_STATE_DONE:
+        case AuthUser::Ok:
             /* 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:
+        case AuthUser::Unchecked:
             /* semantic change: do not drop the connection.
              * 2.5 implementation used to keep it open - Kinkie */
             debugs(29, 9, "AuthNTLMConfig::fixHeader: Sending type:" << hdrType << " header: 'NTLM'");
             httpHeaderPutStrf(&rep->header, hdrType, "NTLM");
             break;
 
-        case AUTHENTICATE_STATE_IN_PROGRESS:
+        case AuthUser::Handshake:
             /* we're waiting for a response from the client. Pass it the blob */
             debugs(29, 9, "AuthNTLMConfig::fixHeader: Sending type:" << hdrType << " header: 'NTLM " << ntlm_request->server_blob << "'");
             httpHeaderPutStrf(&rep->header, hdrType, "NTLM %s", ntlm_request->server_blob);
             safe_free(ntlm_request->server_blob);
             break;
 
-
         default:
-            debugs(29, 0, "AuthNTLMConfig::fixHeader: state " << ntlm_request->auth_state << ".");
+            debugs(29, DBG_CRITICAL, "AuthNTLMConfig::fixHeader: state " << ntlm_request->user()->credentials() << ".");
             fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n");
         }
     }
@@ -323,391 +275,38 @@ NTLMUser::~NTLMUser()
     debugs(29, 5, "NTLMUser::~NTLMUser: doing nothing to clearNTLM scheme data for '" << this << "'");
 }
 
-static void
-authenticateNTLMHandleReply(void *data, void *lastserver, char *reply)
+int32_t
+NTLMUser::ttl() const
 {
-    authenticateStateData *r = static_cast<authenticateStateData *>(data);
-
-    int valid;
-    char *blob;
-
-    AuthUserRequest *auth_user_request;
-    AuthUser *auth_user;
-    NTLMUser *ntlm_user;
-    AuthNTLMUserRequest *ntlm_request;
-
-    debugs(29, 8, "authenticateNTLMHandleReply: helper: '" << lastserver << "' sent us '" << (reply ? reply : "<NULL>") << "'");
-    valid = cbdataReferenceValid(r->data);
-
-    if (!valid) {
-        debugs(29, 1, "authenticateNTLMHandleReply: invalid callback data. helper '" << lastserver << "'.");
-        cbdataReferenceDone(r->data);
-        authenticateStateFree(r);
-        return;
-    }
-
-    if (!reply) {
-        debugs(29, 1, "authenticateNTLMHandleReply: Helper '" << lastserver << "' crashed!.");
-        reply = (char *)"BH Internal error";
-    }
-
-    auth_user_request = r->auth_user_request;
-    assert(auth_user_request != NULL);
-    ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request);
-
-    assert(ntlm_request != NULL);
-    assert(ntlm_request->waiting);
-    ntlm_request->waiting = 0;
-    safe_free(ntlm_request->client_blob);
-
-    auth_user = ntlm_request->user();
-    assert(auth_user != NULL);
-    assert(auth_user->auth_type == AUTH_NTLM);
-    ntlm_user = dynamic_cast<ntlm_user_t *>(auth_user_request->user());
-
-    assert(ntlm_user != NULL);
-
-    if (ntlm_request->authserver == NULL)
-        ntlm_request->authserver = static_cast<helper_stateful_server*>(lastserver);
-    else
-        assert(ntlm_request->authserver == lastserver);
-
-    /* seperate out the useful data */
-    blob = strchr(reply, ' ');
-
-    if (blob)
-        blob++;
-
-    if (strncasecmp(reply, "TT ", 3) == 0) {
-        /* we have been given a blob to send to the client */
-        safe_free(ntlm_request->server_blob);
-        ntlm_request->request->flags.must_keepalive = 1;
-        if (ntlm_request->request->flags.proxy_keepalive) {
-            ntlm_request->server_blob = xstrdup(blob);
-            ntlm_request->auth_state = AUTHENTICATE_STATE_IN_PROGRESS;
-            auth_user_request->denyMessage("Authentication in progress");
-            debugs(29, 4, "authenticateNTLMHandleReply: Need to challenge the client with a server blob '" << blob << "'");
-        } else {
-            ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
-            auth_user_request->denyMessage("NTLM authentication requires a persistent connection");
-        }
-    } else if (strncasecmp(reply, "AF ", 3) == 0) {
-        /* we're finished, release the helper */
-        ntlm_user->username(blob);
-        auth_user_request->denyMessage("Login successful");
-        safe_free(ntlm_request->server_blob);
-
-        debugs(29, 4, "authenticateNTLMHandleReply: Successfully validated user via NTLM. Username '" << blob << "'");
-        /* connection is authenticated */
-        debugs(29, 4, "AuthNTLMUserRequest::authenticate: authenticated user " << ntlm_user->username());
-        /* see if this is an existing user with a different proxy_auth
-         * string */
-        auth_user_hash_pointer *usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, ntlm_user->username()));
-        AuthUser *local_auth_user = ntlm_request->user();
-        while (usernamehash && (usernamehash->user()->auth_type != AUTH_NTLM || strcmp(usernamehash->user()->username(), ntlm_user->username()) != 0))
-            usernamehash = static_cast<AuthUserHashPointer *>(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();
-            ntlm_request->_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;
-        ntlm_request->releaseAuthServer();
-        ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
-    } else if (strncasecmp(reply, "NA ", 3) == 0) {
-        /* authentication failure (wrong password, etc.) */
-        auth_user_request->denyMessage(blob);
-        ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
-        safe_free(ntlm_request->server_blob);
-        ntlm_request->releaseAuthServer();
-        debugs(29, 4, "authenticateNTLMHandleReply: Failed validating user via NTLM. Error returned '" << 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. */
-        auth_user_request->denyMessage(blob);
-        ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
-        safe_free(ntlm_request->server_blob);
-        ntlm_request->releaseAuthServer();
-        debugs(29, 1, "authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '" << reply << "'");
-    } else {
-        /* protocol error */
-        fatalf("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
-    }
-
-    if (ntlm_request->request) {
-        HTTPMSGUNLOCK(ntlm_request->request);
-        ntlm_request->request = NULL;
-    }
-    r->handler(r->data, NULL);
-    cbdataReferenceDone(r->data);
-    authenticateStateFree(r);
+    return -1; // NTLM credentials cannot be cached.
 }
 
+
 static void
 authenticateNTLMStats(StoreEntry * sentry)
 {
     helperStatefulStats(sentry, ntlmauthenticators, "NTLM Authenticator Statistics");
 }
 
-
-/* send the initial data to a stateful ntlm authenticator module */
-void
-AuthNTLMUserRequest::module_start(RH * handler, void *data)
-{
-    authenticateStateData *r = NULL;
-    static char buf[8192];
-    ntlm_user_t *ntlm_user;
-    AuthUser *auth_user = user();
-
-    assert(data);
-    assert(handler);
-    assert(auth_user);
-    assert(auth_user->auth_type == AUTH_NTLM);
-
-    ntlm_user = dynamic_cast<ntlm_user_t *>(user());
-
-    debugs(29, 8, "AuthNTLMUserRequest::module_start: auth state is '" << auth_state << "'");
-
-    if (ntlmConfig.authenticate == NULL) {
-        debugs(29, 0, "AuthNTLMUserRequest::module_start: no NTLM program specified.");
-        handler(data, NULL);
-        return;
-    }
-
-    r = cbdataAlloc(authenticateStateData);
-    r->handler = handler;
-    r->data = cbdataReference(data);
-    r->auth_user_request = this;
-    AUTHUSERREQUESTLOCK(r->auth_user_request, "r");
-
-    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(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, authserver);
-}
-
-/**
- * Atomic action: properly release the NTLM auth helpers which may have been reserved
- * for this request connections use.
- */
-void
-AuthNTLMUserRequest::releaseAuthServer()
-{
-    if (authserver) {
-        debugs(29, 6, HERE << "releasing NTLM auth server '" << authserver << "'");
-        helperStatefulReleaseServer(authserver);
-        authserver = NULL;
-    } else
-        debugs(29, 6, HERE << "No NTLM auth server to release.");
-}
-
-/* clear any connection related authentication details */
-void
-AuthNTLMUserRequest::onConnectionClose(ConnStateData *conn)
-{
-    assert(conn != NULL);
-
-    debugs(29, 8, "AuthNTLMUserRequest::onConnectionClose: closing connection '" << conn << "' (this is '" << this << "')");
-
-    if (conn->auth_user_request == NULL) {
-        debugs(29, 8, "AuthNTLMUserRequest::onConnectionClose: no auth_user_request");
-        return;
-    }
-
-    // unlock / un-reserve the helpers
-    releaseAuthServer();
-
-    /* unlock the connection based lock */
-    debugs(29, 9, "AuthNTLMUserRequest::onConnectionClose: Unlocking auth_user from the connection '" << conn << "'.");
-
-    AUTHUSERREQUESTUNLOCK(conn->auth_user_request, "conn");
-}
-
 /*
  * Decode a NTLM [Proxy-]Auth string, placing the results in the passed
  * Auth_user structure.
  */
-AuthUserRequest *
+AuthUserRequest::Pointer
 AuthNTLMConfig::decode(char const *proxy_auth)
 {
-    NTLMUser *newUser = new NTLMUser(&ntlmConfig);
-    AuthNTLMUserRequest *auth_user_request = new AuthNTLMUserRequest ();
+    NTLMUser *newUser = new NTLMUser(AuthConfig::Find("ntlm"));
+    AuthUserRequest::Pointer auth_user_request = new AuthNTLMUserRequest();
     assert(auth_user_request->user() == NULL);
+
     auth_user_request->user(newUser);
     auth_user_request->user()->auth_type = AUTH_NTLM;
-    auth_user_request->user()->addRequest(auth_user_request);
 
     /* all we have to do is identify that it's NTLM - the helper does the rest */
     debugs(29, 9, "AuthNTLMConfig::decode: NTLM authentication");
     return auth_user_request;
 }
 
-int
-AuthNTLMUserRequest::authenticated() const
-{
-    if (auth_state == AUTHENTICATE_STATE_DONE) {
-        debugs(29, 9, "AuthNTLMUserRequest::authenticated: user authenticated.");
-        return 1;
-    }
-
-    debugs(29, 9, "AuthNTLMUserRequest::authenticated: user not fully authenticated.");
-
-    return 0;
-}
-
-void
-AuthNTLMUserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, http_hdr_type type)
-{
-    const char *proxy_auth, *blob;
-
-    /* TODO: rename this!! */
-    AuthUser *local_auth_user;
-    ntlm_user_t *ntlm_user;
-
-    local_auth_user = user();
-    assert(local_auth_user);
-    assert(local_auth_user->auth_type == AUTH_NTLM);
-    ntlm_user = dynamic_cast<ntlm_user_t *>(local_auth_user);
-    assert (this);
-
-    /* Check that we are in the client side, where we can generate
-     * auth challenges */
-
-    if (conn == NULL || !cbdataReferenceValid(conn)) {
-        auth_state = AUTHENTICATE_STATE_FAILED;
-        debugs(29, 1, "AuthNTLMUserRequest::authenticate: attempt to perform authentication without a connection!");
-        return;
-    }
-
-    if (waiting) {
-        debugs(29, 1, "AuthNTLMUserRequest::authenticate: waiting for helper reply!");
-        return;
-    }
-
-    if (server_blob) {
-        debugs(29, 2, "AuthNTLMUserRequest::authenticate: need to challenge client '" << server_blob << "'!");
-        return;
-    }
-
-    /* get header */
-    proxy_auth = aRequest->header.getStr(type);
-
-    /* locate second word */
-    blob = proxy_auth;
-
-    /* if proxy_auth is actually NULL, we'd better not manipulate it. */
-    if (blob) {
-        while (xisspace(*blob) && *blob)
-            blob++;
-
-        while (!xisspace(*blob) && *blob)
-            blob++;
-
-        while (xisspace(*blob) && *blob)
-            blob++;
-    }
-
-    switch (auth_state) {
-
-    case AUTHENTICATE_STATE_NONE:
-        /* we've received a ntlm request. pass to a helper */
-        debugs(29, 9, "AuthNTLMUserRequest::authenticate: auth state ntlm none. Received blob: '" << proxy_auth << "'");
-        auth_state = AUTHENTICATE_STATE_INITIAL;
-        safe_free(client_blob);
-        client_blob=xstrdup(blob);
-        conn->auth_type = AUTH_NTLM;
-        assert(conn->auth_user_request == NULL);
-        conn->auth_user_request = this;
-        AUTHUSERREQUESTLOCK(conn->auth_user_request, "conn");
-        request = aRequest;
-        HTTPMSGLOCK(request);
-        return;
-
-        break;
-
-    case AUTHENTICATE_STATE_INITIAL:
-        debugs(29, 1, "AuthNTLMUserRequest::authenticate: need to ask helper");
-
-        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);
-
-        if (request)
-            HTTPMSGUNLOCK(request);
-        request = aRequest;
-        HTTPMSGLOCK(request);
-        return;
-
-        break;
-
-    case AUTHENTICATE_STATE_DONE:
-        fatal("AuthNTLMUserRequest::authenticate: unexpect auth state DONE! Report a bug to the squid developers.\n");
-
-        break;
-
-    case AUTHENTICATE_STATE_FAILED:
-        /* we've failed somewhere in authentication */
-        debugs(29, 9, "AuthNTLMUserRequest::authenticate: auth state ntlm failed. " << proxy_auth);
-
-        return;
-
-        break;
-    }
-
-    return;
-}
-
-AuthNTLMUserRequest::AuthNTLMUserRequest() :
-        /*conn(NULL),*/ auth_state(AUTHENTICATE_STATE_NONE),
-        _theUser(NULL)
-{
-    waiting=0;
-    client_blob=0;
-    server_blob=0;
-    authserver=NULL;
-    request = NULL;
-}
-
-AuthNTLMUserRequest::~AuthNTLMUserRequest()
-{
-    safe_free(server_blob);
-    safe_free(client_blob);
-
-    releaseAuthServer();
-
-    if (request) {
-        HTTPMSGUNLOCK(request);
-        request = NULL;
-    }
-}
-
 void
 NTLMUser::deleteSelf() const
 {
@@ -718,15 +317,3 @@ NTLMUser::NTLMUser (AuthConfig *aConfig) : AuthUser (aConfig)
 {
     proxy_auth_list.head = proxy_auth_list.tail = NULL;
 }
-
-AuthConfig *
-ntlmScheme::createConfig()
-{
-    return &ntlmConfig;
-}
-
-const char *
-AuthNTLMUserRequest::connLastHeader()
-{
-    return NULL;
-}
index 5e43c9140b4480df71595dcdd7c90b6ca07a2c35..2a2514e5e1ddb00ea957c946e7c276c82c76f700 100644 (file)
 
 #define DefaultAuthenticateChildrenMax  32     /* 32 processes */
 
-#ifndef __AUTH_AUTHENTICATE_STATE_T__
-#define __AUTH_AUTHENTICATE_STATE_T__
-typedef enum {
-    AUTHENTICATE_STATE_NONE,
-    AUTHENTICATE_STATE_INITIAL,
-    AUTHENTICATE_STATE_IN_PROGRESS,
-    AUTHENTICATE_STATE_DONE,
-    AUTHENTICATE_STATE_FAILED
-} auth_state_t;                 /* connection level auth state */
-
-/* Generic */
-
-typedef struct {
-    void *data;
-    AuthUserRequest *auth_user_request;
-    RH *handler;
-} authenticateStateData;
-#endif
-
 class NTLMUser : public AuthUser
 {
 
 public:
     MEMPROXY_CLASS(NTLMUser);
-    virtual void deleteSelf() const;
     NTLMUser(AuthConfig *);
     ~NTLMUser();
+
+    virtual void deleteSelf() const;
+    virtual int32_t ttl() const;
+
     dlink_list proxy_auth_list;
 };
 
@@ -47,57 +31,6 @@ MEMPROXY_CLASS_INLINE(NTLMUser);
 
 typedef class NTLMUser ntlm_user_t;
 
-class AuthNTLMUserRequest : public AuthUserRequest
-{
-
-public:
-    MEMPROXY_CLASS(AuthNTLMUserRequest);
-
-    AuthNTLMUserRequest();
-    virtual ~AuthNTLMUserRequest();
-    virtual int authenticated() const;
-    virtual void authenticate(HttpRequest * request, ConnStateData * 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<NTLMUser *>(aUser);}
-
-    virtual const char * connLastHeader();
-
-    /* we need to store the helper server between requests */
-    helper_stateful_server *authserver;
-    void releaseAuthServer(void); ///< Release authserver NTLM helpers properly when finished or abandoning.
-
-    /* what connection is this associated with */
-//    ConnStateData * 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;
-
-    /* need access to the request flags to mess around on pconn failure */
-    HttpRequest *request;
-
-private:
-    /* the user */
-    NTLMUser * _theUser;
-};
-
-MEMPROXY_CLASS_INLINE(AuthNTLMUserRequest);
-
-#include "HelperChildConfig.h"
-
 /* configuration runtime data */
 
 class AuthNTLMConfig : public AuthConfig
@@ -107,19 +40,20 @@ public:
     AuthNTLMConfig();
     virtual bool active() const;
     virtual bool configured() const;
-    virtual AuthUserRequest *decode(char const *proxy_auth);
+    virtual AuthUserRequest::Pointer decode(char const *proxy_auth);
     virtual void done();
+    virtual void rotateHelpers();
     virtual void dump(StoreEntry *, const char *, AuthConfig *);
-    virtual void fixHeader(AuthUserRequest *, HttpReply *, http_hdr_type, HttpRequest *);
+    virtual void fixHeader(AuthUserRequest::Pointer, HttpReply *, http_hdr_type, HttpRequest *);
     virtual void init(AuthConfig *);
     virtual void parse(AuthConfig *, int, char *);
     virtual void registerWithCacheManager(void);
     virtual const char * type() const;
-    HelperChildConfig authenticateChildren;
     int keep_alive;
-    wordlist *authenticate;
 };
 
 typedef class AuthNTLMConfig auth_ntlm_config;
 
+extern statefulhelper *ntlmauthenticators;
+
 #endif
index 8f5f74c2a1d574fbe00cabf0946c386222af5dc7..e6dee80e2c94fe54ce2af5a83a5147a6ba1c42ba 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
  *
  */
 
-#include "ntlmScheme.h"
+#include "config.h"
+#include "auth/ntlm/auth_ntlm.h"
+#include "auth/ntlm/ntlmScheme.h"
+#include "helper.h"
 
-AuthScheme &
+AuthScheme::Pointer
 ntlmScheme::GetInstance()
 {
-    if (_instance == NULL)
+    if (_instance == NULL) {
         _instance = new ntlmScheme();
-    return *_instance;
-}
-
-ntlmScheme::ntlmScheme()
-{
-    AddScheme(*this);
+        AddScheme(_instance);
+    }
+    return _instance;
 }
 
 char const *
@@ -52,4 +51,20 @@ ntlmScheme::type () const
     return "ntlm";
 }
 
-ntlmScheme *ntlmScheme::_instance = NULL;
+AuthScheme::Pointer ntlmScheme::_instance = NULL;
+
+void
+ntlmScheme::done()
+{
+    /* clear the global handle to this scheme. */
+    _instance = NULL;
+
+    debugs(29, 2, "ntlmScheme::done: NTLM authentication Shutdown.");
+}
+
+AuthConfig *
+ntlmScheme::createConfig()
+{
+    auth_ntlm_config *ntlmCfg = new auth_ntlm_config;
+    return dynamic_cast<AuthConfig*>(ntlmCfg);
+}
index f9b037c9a4187c6fa6919b94400f1df5c6c6e1ab..e48bf82d4c6e3721942c8cd4deb4f6573de88f74 100644 (file)
@@ -35,6 +35,7 @@
 #define SQUID_NTLMSCHEME_H
 
 #include "auth/Scheme.h"
+#include "auth/ntlm/auth_ntlm.h"
 
 /// \ingroup AuthSchemeAPI
 /// \ingroup AuthAPI
@@ -42,20 +43,25 @@ class ntlmScheme : public AuthScheme
 {
 
 public:
-    static AuthScheme &GetInstance();
-    ntlmScheme();
+    static AuthScheme::Pointer GetInstance();
+    ntlmScheme() {};
     virtual ~ntlmScheme() {};
 
     /* per scheme */
     virtual char const *type () const;
     virtual void done();
     virtual AuthConfig *createConfig();
+
     /* Not implemented */
     ntlmScheme (ntlmScheme const &);
     ntlmScheme &operator=(ntlmScheme const &);
 
 private:
-    static ntlmScheme *_instance;
+    /**
+     * Main instance of this authentication Scheme.
+     * NULL when the scheme is not being used.
+     */
+    static AuthScheme::Pointer _instance;
 };
 
 #endif /* SQUID_ntlmSCHEME_H */
diff --git a/src/auth/ntlm/ntlmUserRequest.cc b/src/auth/ntlm/ntlmUserRequest.cc
new file mode 100644 (file)
index 0000000..cf0776b
--- /dev/null
@@ -0,0 +1,358 @@
+#include "config.h"
+#include "auth/ntlm/ntlmUserRequest.h"
+#include "auth/ntlm/auth_ntlm.h"
+#include "auth/State.h"
+#include "cbdata.h"
+#include "HttpRequest.h"
+#include "SquidTime.h"
+
+/* state wrapper functions */
+
+AuthNTLMUserRequest::AuthNTLMUserRequest()
+{
+    waiting=0;
+    client_blob=0;
+    server_blob=0;
+    authserver=NULL;
+    request = NULL;
+}
+
+AuthNTLMUserRequest::~AuthNTLMUserRequest()
+{
+    assert(RefCountCount()==0);
+    safe_free(server_blob);
+    safe_free(client_blob);
+
+    releaseAuthServer();
+
+    if (request) {
+        HTTPMSGUNLOCK(request);
+        request = NULL;
+    }
+}
+
+const char *
+AuthNTLMUserRequest::connLastHeader()
+{
+    return NULL;
+}
+
+/* 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 */
+
+    if (user()->auth_type != AUTH_NTLM)
+        return -2;
+
+    switch (user()->credentials()) {
+
+    case AuthUser::Handshake:
+        assert(server_blob);
+        return 1; /* send to client */
+
+    case AuthUser::Ok:
+        return 0; /* do nothing */
+
+    case AuthUser::Failed:
+        return -2;
+
+    default:
+        debugs(29, DBG_IMPORTANT, "WARNING: NTLM Authentication in unexpected state: " << user()->credentials());
+        return -2;
+    }
+}
+
+/* send the initial data to a stateful ntlm authenticator module */
+void
+AuthNTLMUserRequest::module_start(RH * handler, void *data)
+{
+    authenticateStateData *r = NULL;
+    static char buf[8192];
+
+    assert(data);
+    assert(handler);
+
+    debugs(29, 8, HERE << "credentials state is '" << user()->credentials() << "'");
+
+    if (static_cast<AuthNTLMConfig*>(AuthConfig::Find("ntlm"))->authenticate == NULL) {
+        debugs(29, DBG_CRITICAL, "ERROR: NTLM Start: no NTLM program configured.");
+        handler(data, NULL);
+       return;
+    }
+
+    r = cbdataAlloc(authenticateStateData);
+    r->handler = handler;
+    r->data = cbdataReference(data);
+    r->auth_user_request = this;
+
+    if (user()->credentials() == AuthUser::Pending) {
+        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(ntlmauthenticators, buf, AuthNTLMUserRequest::HandleReply, r, authserver);
+}
+
+/**
+ * Atomic action: properly release the NTLM auth helpers which may have been reserved
+ * for this request connections use.
+ */
+void
+AuthNTLMUserRequest::releaseAuthServer()
+{
+    if (authserver) {
+        debugs(29, 6, HERE << "releasing NTLM auth server '" << authserver << "'");
+        helperStatefulReleaseServer(authserver);
+        authserver = NULL;
+    } else
+        debugs(29, 6, HERE << "No NTLM auth server to release.");
+}
+
+void
+AuthNTLMUserRequest::onConnectionClose(ConnStateData *conn)
+{
+    assert(conn != NULL);
+
+    debugs(29, 8, "AuthNTLMUserRequest::onConnectionClose: closing connection '" << conn << "' (this is '" << this << "')");
+
+    if (conn->auth_user_request == NULL) {
+        debugs(29, 8, "AuthNTLMUserRequest::onConnectionClose: no auth_user_request");
+        return;
+    }
+
+    // unlock / un-reserve the helpers
+    releaseAuthServer();
+
+    /* unlock the connection based lock */
+    debugs(29, 9, "AuthNTLMUserRequest::onConnectionClose: Unlocking auth_user from the connection '" << conn << "'.");
+
+    conn->auth_user_request = NULL;
+}
+
+int
+AuthNTLMUserRequest::authenticated() const
+{
+    if (user()->credentials() == AuthUser::Ok) {
+        debugs(29, 9, "AuthNTLMUserRequest::authenticated: user authenticated.");
+        return 1;
+    }
+
+    debugs(29, 9, "AuthNTLMUserRequest::authenticated: user not fully authenticated.");
+
+    return 0;
+}
+
+void
+AuthNTLMUserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, http_hdr_type type)
+{
+    const char *proxy_auth, *blob;
+
+    assert(this);
+
+    /* Check that we are in the client side, where we can generate
+     * auth challenges */
+
+    if (conn == NULL || !cbdataReferenceValid(conn)) {
+        user()->credentials(AuthUser::Failed);
+        debugs(29, 1, "AuthNTLMUserRequest::authenticate: attempt to perform authentication without a connection!");
+        return;
+    }
+
+    if (waiting) {
+        debugs(29, 1, "AuthNTLMUserRequest::authenticate: waiting for helper reply!");
+        return;
+    }
+
+    if (server_blob) {
+        debugs(29, 2, "AuthNTLMUserRequest::authenticate: need to challenge client '" << server_blob << "'!");
+        return;
+    }
+
+    /* get header */
+    proxy_auth = aRequest->header.getStr(type);
+
+    /* locate second word */
+    blob = proxy_auth;
+
+    /* if proxy_auth is actually NULL, we'd better not manipulate it. */
+    if (blob) {
+        while (xisspace(*blob) && *blob)
+            blob++;
+
+        while (!xisspace(*blob) && *blob)
+            blob++;
+
+        while (xisspace(*blob) && *blob)
+            blob++;
+    }
+
+    switch (user()->credentials()) {
+
+    case AuthUser::Unchecked:
+        /* we've received a ntlm request. pass to a helper */
+        debugs(29, 9, "AuthNTLMUserRequest::authenticate: auth state ntlm none. Received blob: '" << proxy_auth << "'");
+        user()->credentials(AuthUser::Pending);
+        safe_free(client_blob);
+        client_blob=xstrdup(blob);
+        assert(conn->auth_user_request == NULL);
+        conn->auth_user_request = this;
+        request = aRequest;
+        HTTPMSGLOCK(request);
+        break;
+
+    case AuthUser::Pending:
+        debugs(29, 1, "AuthNTLMUserRequest::authenticate: need to ask helper");
+        break;
+
+    case AuthUser::Handshake:
+        /* we should have received a blob from the client. Hand it off to
+         * some helper */
+        safe_free(client_blob);
+        client_blob = xstrdup (blob);
+
+        if (request)
+            HTTPMSGUNLOCK(request);
+        request = aRequest;
+        HTTPMSGLOCK(request);
+        break;
+
+    case AuthUser::Ok:
+        fatal("AuthNTLMUserRequest::authenticate: unexpect auth state DONE! Report a bug to the squid developers.\n");
+        break;
+
+    case AuthUser::Failed:
+        /* we've failed somewhere in authentication */
+        debugs(29, 9, "AuthNTLMUserRequest::authenticate: auth state ntlm failed. " << proxy_auth);
+        break;
+    }
+}
+
+void
+AuthNTLMUserRequest::HandleReply(void *data, void *lastserver, char *reply)
+{
+    authenticateStateData *r = static_cast<authenticateStateData *>(data);
+
+    int valid;
+    char *blob;
+
+    debugs(29, 8, "authenticateNTLMHandleReply: helper: '" << lastserver << "' sent us '" << (reply ? reply : "<NULL>") << "'");
+    valid = cbdataReferenceValid(r->data);
+
+    if (!valid) {
+        debugs(29, 1, "authenticateNTLMHandleReply: invalid callback data. helper '" << lastserver << "'.");
+        cbdataReferenceDone(r->data);
+        authenticateStateFree(r);
+        return;
+    }
+
+    if (!reply) {
+        debugs(29, 1, "authenticateNTLMHandleReply: Helper '" << lastserver << "' crashed!.");
+        reply = (char *)"BH Internal error";
+    }
+
+    AuthUserRequest::Pointer auth_user_request = r->auth_user_request;
+    assert(auth_user_request != NULL);
+
+    AuthNTLMUserRequest *ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request.getRaw());
+    assert(ntlm_request != NULL);
+    assert(ntlm_request->waiting);
+    assert(ntlm_request->user() != NULL);
+    assert(ntlm_request->user()->auth_type == AUTH_NTLM);
+
+    ntlm_request->waiting = 0;
+    safe_free(ntlm_request->client_blob);
+
+    if (ntlm_request->authserver == NULL)
+        ntlm_request->authserver = static_cast<helper_stateful_server*>(lastserver);
+    else
+        assert(ntlm_request->authserver == lastserver);
+
+    /* seperate out the useful data */
+    blob = strchr(reply, ' ');
+    if (blob)
+        blob++;
+
+    if (strncasecmp(reply, "TT ", 3) == 0) {
+        /* we have been given a blob to send to the client */
+        safe_free(ntlm_request->server_blob);
+        ntlm_request->request->flags.must_keepalive = 1;
+        if (ntlm_request->request->flags.proxy_keepalive) {
+            ntlm_request->server_blob = xstrdup(blob);
+            ntlm_request->user()->credentials(AuthUser::Handshake);
+            auth_user_request->denyMessage("Authentication in progress");
+            debugs(29, 4, "authenticateNTLMHandleReply: Need to challenge the client with a server blob '" << blob << "'");
+        } else {
+            ntlm_request->user()->credentials(AuthUser::Failed);
+            auth_user_request->denyMessage("NTLM authentication requires a persistent connection");
+        }
+    } else if (strncasecmp(reply, "AF ", 3) == 0) {
+        /* we're finished, release the helper */
+        auth_user_request->user()->username(blob);
+        auth_user_request->denyMessage("Login successful");
+        safe_free(ntlm_request->server_blob);
+
+        debugs(29, 4, "authenticateNTLMHandleReply: Successfully validated user via NTLM. Username '" << blob << "'");
+        /* connection is authenticated */
+        debugs(29, 4, "AuthNTLMUserRequest::authenticate: authenticated user " << auth_user_request->user()->username());
+        /* see if this is an existing user with a different proxy_auth
+         * string */
+        auth_user_hash_pointer *usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, auth_user_request->user()->username()));
+        AuthUser::Pointer local_auth_user = ntlm_request->user();
+        while (usernamehash && (usernamehash->user()->auth_type != AUTH_NTLM || strcmp(usernamehash->user()->username(), auth_user_request->user()->username()) != 0))
+            usernamehash = static_cast<AuthUserHashPointer *>(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);
+            local_auth_user = usernamehash->user();
+            ntlm_request->_auth_user = local_auth_user;
+        } else {
+            /* store user in hash's */
+            local_auth_user->addToNameCache();
+        }
+        /* 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;
+        ntlm_request->releaseAuthServer();
+        local_auth_user->credentials(AuthUser::Ok);
+    } else if (strncasecmp(reply, "NA ", 3) == 0) {
+        /* authentication failure (wrong password, etc.) */
+        auth_user_request->denyMessage(blob);
+        ntlm_request->user()->credentials(AuthUser::Failed);
+        safe_free(ntlm_request->server_blob);
+        ntlm_request->releaseAuthServer();
+        debugs(29, 4, "authenticateNTLMHandleReply: Failed validating user via NTLM. Error returned '" << 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. */
+        auth_user_request->denyMessage(blob);
+        auth_user_request->user()->credentials(AuthUser::Failed);
+        safe_free(ntlm_request->server_blob);
+        ntlm_request->releaseAuthServer();
+        debugs(29, 1, "authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '" << reply << "'");
+    } else {
+        /* protocol error */
+        fatalf("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
+    }
+
+    if (ntlm_request->request) {
+        HTTPMSGUNLOCK(ntlm_request->request);
+        ntlm_request->request = NULL;
+    }
+    r->handler(r->data, NULL);
+    cbdataReferenceDone(r->data);
+    authenticateStateFree(r);
+}
diff --git a/src/auth/ntlm/ntlmUserRequest.h b/src/auth/ntlm/ntlmUserRequest.h
new file mode 100644 (file)
index 0000000..189cdcc
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef _SQUID_SRC_AUTH_NTLM_USERREQUEST_H
+#define _SQUID_SRC_AUTH_NTLM_USERREQUEST_H
+
+#include "auth/UserRequest.h"
+#include "auth/ntlm/auth_ntlm.h"
+#include "MemPool.h"
+
+class ConnStateData;
+class HttpReply;
+class HttpRequest;
+struct helper_stateful_server;
+
+class AuthNTLMUserRequest : public AuthUserRequest
+{
+
+public:
+    MEMPROXY_CLASS(AuthNTLMUserRequest);
+
+    AuthNTLMUserRequest();
+    virtual ~AuthNTLMUserRequest();
+    virtual int authenticated() const;
+    virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type);
+    virtual int module_direction();
+    virtual void onConnectionClose(ConnStateData *);
+    virtual void module_start(RH *, void *);
+
+    virtual const char * connLastHeader();
+
+    /* we need to store the helper server between requests */
+    helper_stateful_server *authserver;
+    void releaseAuthServer(void); ///< Release authserver NTLM helpers properly when finished or abandoning.
+
+    /* what connection is this associated with */
+//    ConnStateData * conn;
+
+    /* 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;
+
+    /* need access to the request flags to mess around on pconn failure */
+    HttpRequest *request;
+
+private:
+    static HLPSCB HandleReply;
+};
+
+MEMPROXY_CLASS_INLINE(AuthNTLMUserRequest);
+
+#endif /* _SQUID_SRC_AUTH_NTLM_USERREQUEST_H */
index 0f4788c25ba5b1c7776f4c1bf49990406233212e..1bb1ea226cce595d130fa784259e54e2f95a8ce6 100644 (file)
@@ -398,6 +398,8 @@ parseConfigFile(const char *file_name)
     int err_count = 0;
     CacheManager *manager=CacheManager::GetInstance();
 
+    debugs(5, 4, HERE);
+
     configFreeMemory();
 
     ACLMethodData::ThePurgeCount = 0;
@@ -1436,7 +1438,7 @@ check_null_string(char *s)
 }
 
 static void
-parse_authparam(authConfig * config)
+parse_authparam(Auth::authConfig * config)
 {
     char *type_str;
     char *param_str;
@@ -1447,38 +1449,43 @@ parse_authparam(authConfig * config)
     if ((param_str = strtok(NULL, w_space)) == NULL)
         self_destruct();
 
-    /* find a configuration for the scheme */
-    AuthConfig *scheme = AuthConfig::Find (type_str);
+    /* find a configuration for the scheme in the currently parsed configs... */
+    AuthConfig *schemeCfg = AuthConfig::Find(type_str);
 
-    if (scheme == NULL) {
-        /* Create a configuration */
-        AuthScheme *theScheme;
+    if (schemeCfg == NULL) {
+        /* Create a configuration based on the scheme info */
+        AuthScheme::Pointer theScheme = AuthScheme::Find(type_str);
 
-        if ((theScheme = AuthScheme::Find(type_str)) == NULL) {
-            debugs(3, 0, "Parsing Config File: Unknown authentication scheme '" << type_str << "'.");
-            return;
+        if (theScheme == NULL) {
+            debugs(3, DBG_CRITICAL, "Parsing Config File: Unknown authentication scheme '" << type_str << "'.");
+            self_destruct();
         }
 
         config->push_back(theScheme->createConfig());
-        scheme = config->back();
-        assert (scheme);
+        schemeCfg = AuthConfig::Find(type_str);
+        if (schemeCfg == NULL) {
+            debugs(3, DBG_CRITICAL, "Parsing Config File: Corruption configuring authentication scheme '" << type_str << "'.");
+            self_destruct();
+        }
     }
 
-    scheme->parse(scheme, config->size(), param_str);
+    schemeCfg->parse(schemeCfg, config->size(), param_str);
 }
 
 static void
-free_authparam(authConfig * cfg)
+free_authparam(Auth::authConfig * cfg)
 {
-    AuthConfig *scheme;
-    /* DON'T FREE THESE FOR RECONFIGURE */
-
-    if (reconfiguring)
-        return;
+    /* Wipe the Auth globals and Detach/Destruct component config + state. */
+    cfg->clean();
 
+    /* remove our pointers to the probably-dead sub-configs */
     while (cfg->size()) {
-        scheme = cfg->pop_back();
-        scheme->done();
+        cfg->pop_back();
+    }
+
+    /* on reconfigure initialize new auth schemes for the new config. */
+    if(reconfiguring) {
+        InitAuthSchemes();
     }
 }
 
index d173d6556f0a08fec9ae8e8c7457038424205b0a..539325f0f4d77838b1ff5aa379b8e48d533e807c 100644 (file)
@@ -66,7 +66,7 @@ COMMENT_END
 
 NAME: auth_param
 TYPE: authparam
-LOC: Config.authConfiguration
+LOC: Auth::TheConfig
 DEFAULT: none
 DOC_START
        This is used to define parameters for the various authentication
index 794f57e93b9c1214c0cfeef40af1fb44b81ea1ea..c287d0ba9736a832a19225d4f3b7646ab0d59642 100644 (file)
@@ -711,6 +711,7 @@ gen_dump(Entry * head, FILE * fp)
             "static void\n"
             "dump_config(StoreEntry *entry)\n"
             "{\n"
+            "    debugs(5, 4, HERE);\n"
            );
 
     for (entry = head; entry != NULL; entry = entry->next) {
@@ -745,6 +746,7 @@ gen_free(Entry * head, FILE * fp)
             "static void\n"
             "free_all(void)\n"
             "{\n"
+            "    debugs(5, 4, HERE);\n"
            );
 
     for (entry = head; entry != NULL; entry = entry->next) {
index 6059e220088f2a44114b450158c295c4cfebb7d0..a5391ee42b21f31e0dde8b2330f3904fae7a6638 100644 (file)
@@ -499,13 +499,12 @@ prepareLogWithRequestDetails(HttpRequest * request, AccessLogEntry * aLogEntry)
         aLogEntry->cache.requestSize += request->content_length;
     aLogEntry->cache.extuser = request->extacl_user.termedBuf();
 
-    if (request->auth_user_request) {
+    if (request->auth_user_request != NULL) {
 
         if (request->auth_user_request->username())
-            aLogEntry->cache.authuser =
-                xstrdup(request->auth_user_request->username());
+            aLogEntry->cache.authuser = xstrdup(request->auth_user_request->username());
 
-        AUTHUSERREQUESTUNLOCK(request->auth_user_request, "request via clientPrepareLogWithRequestDetails");
+// WTF??        request->auth_user_request = NULL;
     }
 }
 
@@ -691,8 +690,6 @@ ConnStateData::~ConnStateData()
     if (!flags.swanSang)
         debugs(33, 1, "BUG: ConnStateData was not destroyed properly; FD " << fd);
 
-    AUTHUSERREQUESTUNLOCK(auth_user_request, "~conn");
-
     cbdataReferenceDone(port);
 
     if (bodyPipe != NULL)
index 4162562ab3d7a981a7b1da583d4eccb7c2b628a7..32aafc9f67e6fa1d61720b598a9ebc4712c1a860 100644 (file)
@@ -33,6 +33,7 @@
 #ifndef SQUID_CLIENTSIDE_H
 #define SQUID_CLIENTSIDE_H
 
+#include "auth/UserRequest.h"
 #include "base/AsyncJob.h"
 #include "BodyPipe.h"
 #include "comm.h"
 #include "StoreIOBuffer.h"
 
 class ConnStateData;
-
 class ClientHttpRequest;
-
 class clientStreamNode;
-
-class AuthUserRequest;
-
 class ChunkedCodingParser;
 class HttpParser;
 
@@ -174,16 +170,10 @@ public:
     int64_t bodySizeLeft();
 
     /**
-     * Is this connection based authentication? if so what type it
-     * is.
-     */
-    auth_type_t auth_type;
-
-    /**
-     * note this is ONLY connection based because NTLM is against HTTP spec.
+     * note this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
      * the user details for connection based authentication
      */
-    AuthUserRequest *auth_user_request;
+    AuthUserRequest::Pointer auth_user_request;
 
     /**
      * used by the owner of the connection, opaque otherwise
index 6962571c1318c5edd52d2b3ee1352fd3214fbda4..7e60fb5192250807ed3615d5844d42add28f42a2 100644 (file)
@@ -96,10 +96,9 @@ void
 clientReplyContext::setReplyToError(
     err_type err, http_status status, const HttpRequestMethod& method, char const *uri,
     Ip::Address &addr, HttpRequest * failedrequest, const char *unparsedrequest,
-    AuthUserRequest * auth_user_request)
+    AuthUserRequest::Pointer auth_user_request)
 {
-    ErrorState *errstate =
-        clientBuildError(err, status, uri, addr, failedrequest);
+    ErrorState *errstate = clientBuildError(err, status, uri, addr, failedrequest);
 
     if (unparsedrequest)
         errstate->request_hdrs = xstrdup(unparsedrequest);
@@ -112,10 +111,7 @@ clientReplyContext::setReplyToError(
 
     createStoreEntry(method, request_flags());
 
-    if (auth_user_request) {
-        errstate->auth_user_request = auth_user_request;
-        AUTHUSERREQUESTLOCK(errstate->auth_user_request, "errstate");
-    }
+    errstate->auth_user_request = auth_user_request;
 
     assert(errstate->callback_data == NULL);
     errorAppendEntry(http->storeEntry(), errstate);
@@ -1355,9 +1351,8 @@ clientReplyContext::buildReplyHeader()
          * responses
          */
         authenticateFixHeader(reply, request->auth_user_request, request, 0, 1);
-    } else if (request->auth_user_request)
-        authenticateFixHeader(reply, request->auth_user_request, request,
-                              http->flags.accel, 0);
+    } else if (request->auth_user_request != NULL)
+        authenticateFixHeader(reply, request->auth_user_request, request, http->flags.accel, 0);
 
     /* Append X-Cache */
     httpHeaderPutStrf(hdr, HDR_X_CACHE, "%s from %s",
index 60ca4d84945e738d730fc61d1bd652de2b6a2859..e141b84c3f5590e86fdfd5fc0f0f613b23bfbc75 100644 (file)
@@ -72,7 +72,7 @@ public:
     int storeOKTransferDone() const;
     int storeNotOKTransferDone() const;
 
-    void setReplyToError(err_type, http_status, const HttpRequestMethod&, char const *, Ip::Address &, HttpRequest *, const char *, AuthUserRequest *);
+    void setReplyToError(err_type, http_status, const HttpRequestMethod&, char const *, Ip::Address &, HttpRequest *, const char *, AuthUserRequest::Pointer);
     void createStoreEntry(const HttpRequestMethod& m, request_flags flags);
     void removeStoreReference(store_client ** scp, StoreEntry ** ep);
     void removeClientStoreReference(store_client **scp, ClientHttpRequest *http);
index b2a3d27a8577bb9b46f7c3903f1f4e08b74f16cd..26093dda969adccc1496d3a7550b5defb7f7f876 100644 (file)
@@ -623,7 +623,7 @@ ClientRequestContext::clientAccessCheckDone(int answer)
                                     http->getConn() != NULL ? http->getConn()->peer : tmpnoaddr,
                                     http->request,
                                     NULL,
-                                    http->getConn() != NULL && http->getConn()->auth_user_request ?
+                                    http->getConn() != NULL && http->getConn()->auth_user_request != NULL ?
                                     http->getConn()->auth_user_request : http->request->auth_user_request);
 
         node = (clientStreamNode *)http->client_stream.tail->data;
@@ -1038,11 +1038,7 @@ ClientRequestContext::clientRedirectDone(char *result)
         new_request->my_addr = old_request->my_addr;
         new_request->flags = old_request->flags;
         new_request->flags.redirected = 1;
-
-        if (old_request->auth_user_request) {
-            new_request->auth_user_request = old_request->auth_user_request;
-            AUTHUSERREQUESTLOCK(new_request->auth_user_request, "new request");
-        }
+        new_request->auth_user_request = old_request->auth_user_request;
 
         if (old_request->body_pipe != NULL) {
             new_request->body_pipe = old_request->body_pipe;
@@ -1524,7 +1520,7 @@ ClientHttpRequest::handleAdaptationFailure(bool bypassable)
     repContext->setReplyToError(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
                                 request->method, NULL,
                                 (c != NULL ? c->peer : noAddr), request, NULL,
-                                (c != NULL && c->auth_user_request ?
+                                (c != NULL && c->auth_user_request != NULL ?
                                  c->auth_user_request : request->auth_user_request));
 
     node = (clientStreamNode *)client_stream.tail->data;
index d7aa6f8b0ac4ee25438ca96f0cec66e142a737fb..15d563b49cd1b88e37286ce07a13f48b8f86f6e4 100644 (file)
@@ -199,22 +199,6 @@ typedef enum {
     STREAM_FAILED
 } clientStream_status_t;
 
-typedef enum {
-    AUTH_ACL_CHALLENGE = -2,
-    AUTH_ACL_HELPER = -1,
-    AUTH_ACL_CANNOT_AUTHENTICATE = 0,
-    AUTH_AUTHENTICATED = 1
-} auth_acl_t;
-
-typedef enum {
-    AUTH_UNKNOWN,              /* default */
-    AUTH_BASIC,
-    AUTH_NTLM,
-    AUTH_DIGEST,
-    AUTH_NEGOTIATE,
-    AUTH_BROKEN                        /* known type, but broken data */
-} auth_type_t;
-
 /* stateful helper callback response codes */
 typedef enum {
     S_HELPER_UNKNOWN,
index 30b165fb772bd20f15a61631b78b93c201a0f6e4..b8c11db5f95a921843af676bacdef57225706274 100644 (file)
@@ -500,7 +500,7 @@ errorStateFree(ErrorState * err)
     wordlistDestroy(&err->ftp.server_msg);
     safe_free(err->ftp.request);
     safe_free(err->ftp.reply);
-    AUTHUSERREQUESTUNLOCK(err->auth_user_request, "errstate");
+    err->auth_user_request = NULL;
     safe_free(err->err_msg);
 #if USE_ERR_LOCALES
     if (err->err_language != Config.errorDefaultLanguage)
@@ -608,7 +608,7 @@ ErrorState::Convert(char token, bool url_presentable)
     switch (token) {
 
     case 'a':
-        if (request && request->auth_user_request)
+        if (request && request->auth_user_request != NULL)
             p = request->auth_user_request->username();
         if (!p)
             p = "-";
index b7099e0b7755746d19651161130e7f5b698a4ecf..4c6a89303edf092f9f5ef7286961df6a9e9a9c6a 100644 (file)
@@ -35,6 +35,7 @@
 #define   SQUID_ERRORPAGE_H
 
 #include "squid.h"
+#include "auth/UserRequest.h"
 #include "cbdata.h"
 #include "ip/Address.h"
 
@@ -78,7 +79,6 @@
  \endverbatim
  */
 
-class AuthUserRequest;
 class HttpReply;
 class MemBuf;
 
@@ -127,7 +127,7 @@ public:
     int page_id;
     char *err_language;
     http_status httpStatus;
-    AuthUserRequest *auth_user_request;
+    AuthUserRequest::Pointer auth_user_request;
     HttpRequest *request;
     char *url;
     int xerrno;
index 598a2b2359ce789b5a5f158e6e48e0b3f4ba57f8..ebaa4300e5e770aa1ec79931c464d36da42047b4 100644 (file)
@@ -121,6 +121,12 @@ public:
 
     dlink_list queue;
 
+    /**
+     * Configuration flag. May only be altered by the configuration parser.
+     *
+     * Indicates that all uses of this external_acl_type helper require authentication
+     * details to be processed. If none are available its a fail match.
+     */
     bool require_auth;
 
     enum {
@@ -741,18 +747,17 @@ aclMatchExternal(external_acl_data *acl, ACLFilledChecklist *ch)
         if (acl->def->require_auth) {
             int ti;
             /* Make sure the user is authenticated */
+            debugs(82, 3, "aclMatchExternal: " << acl->def->name << " check user authenticated.");
 
             if ((ti = AuthenticateAcl(ch)) != 1) {
                 debugs(82, 2, "aclMatchExternal: " << acl->def->name << " user not authenticated (" << ti << ")");
                 return ti;
             }
+            debugs(82, 3, "aclMatchExternal: " << acl->def->name << " user is authenticated.");
         }
 
         key = makeExternalAclKey(ch, acl);
 
-        if (acl->def->require_auth)
-            AUTHUSERREQUESTUNLOCK(ch->auth_user_request, "ACLChecklist via aclMatchExternal");
-
         if (!key) {
             /* Not sufficient data to process */
             return -1;
@@ -869,7 +874,7 @@ makeExternalAclKey(ACLFilledChecklist * ch, external_acl_data * acl_data)
         switch (format->type) {
 
         case _external_acl_format::EXT_ACL_LOGIN:
-            assert (ch->auth_user_request);
+            assert (ch->auth_user_request != NULL);
             str = ch->auth_user_request->username();
             break;
 #if USE_IDENT
@@ -1282,6 +1287,7 @@ ACLExternal::ExternalAclLookup(ACLChecklist *checklist, ACLExternal * me, EAH *
     if (acl->def->require_auth) {
         int ti;
         /* Make sure the user is authenticated */
+        debugs(82, 3, "aclMatchExternal: " << acl->def->name << " check user authenticated.");
 
         if ((ti = AuthenticateAcl(ch)) != 1) {
             debugs(82, 1, "externalAclLookup: " << acl->def->name <<
@@ -1289,6 +1295,7 @@ ACLExternal::ExternalAclLookup(ACLChecklist *checklist, ACLExternal * me, EAH *
             callback(callback_data, NULL);
             return;
         }
+        debugs(82, 3, "aclMatchExternal: " << acl->def->name << " user is authenticated.");
     }
 
     const char *key = makeExternalAclKey(ch, acl);
index fe67c9a5fca4f199e0f70bb8ef359d99d16194ab..2420d6219048504c92672b203edd53637de044a0 100644 (file)
@@ -1530,7 +1530,7 @@ httpFixupAuthentication(HttpRequest * request, HttpRequest * orig_request, const
 
         if (orig_request->extacl_user.size())
             username = orig_request->extacl_user.termedBuf();
-        else if (orig_request->auth_user_request)
+        else if (orig_request->auth_user_request != NULL)
             username = orig_request->auth_user_request->username();
 
         snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
index cc20480c0c79e8dd453bcf8f3f45f54946546cc2..8d7d8e51f4f4a64aa639857a029764ee2e063fff 100644 (file)
@@ -212,7 +212,12 @@ SignalEngine::doShutdown(time_t wait)
     WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
 #endif
 
+    /* run the closure code which can be shared with reconfigure */
     serverConnectionsClose();
+
+    /* detach the auth components (only do this on full shutdown) */
+    AuthScheme::FreeAll();
+
     eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
 }
 
@@ -693,7 +698,7 @@ mainReconfigureStart(void)
 #endif
 
     redirectShutdown();
-    authenticateShutdown();
+    authenticateReset();
     externalAclShutdown();
     storeDirCloseSwapLogs();
     storeLogClose();
@@ -731,7 +736,6 @@ mainReconfigureFinish(void *)
     setEffectiveUser();
     _db_init(Debug::cache_log, Debug::debugOptions);
     ipcache_restart();         /* clear stuck entries */
-    authenticateUserCacheRestart();    /* clear stuck ACL entries */
     fqdncache_restart();       /* sigh, fqdncache too */
     parseEtcHosts();
     errorInitialize();         /* reload error pages */
@@ -769,7 +773,7 @@ mainReconfigureFinish(void *)
 #endif
 
     redirectInit();
-    authenticateInit(&Config.authConfiguration);
+    authenticateInit(&Auth::TheConfig);
     externalAclInit();
 #if USE_WCCP
 
@@ -811,7 +815,7 @@ mainRotate(void)
     dnsShutdown();
 #endif
     redirectShutdown();
-    authenticateShutdown();
+    authenticateRotate();
     externalAclShutdown();
 
     _db_rotate_log();          /* cache.log */
@@ -832,7 +836,7 @@ mainRotate(void)
     dnsInit();
 #endif
     redirectInit();
-    authenticateInit(&Config.authConfiguration);
+    authenticateInit(&Auth::TheConfig);
     externalAclInit();
 }
 
@@ -965,7 +969,7 @@ mainInitialize(void)
 
     redirectInit();
 
-    authenticateInit(&Config.authConfiguration);
+    authenticateInit(&Auth::TheConfig);
 
     externalAclInit();
 
@@ -1281,6 +1285,8 @@ SquidMain(int argc, char **argv)
         /* we may want the parsing process to set this up in the future */
         Store::Root(new StoreController);
 
+        InitAuthSchemes();      /* required for config parsing */
+
         parse_err = parseConfigFile(ConfigFile);
 
         Mem::Report();
@@ -1735,7 +1741,7 @@ SquidShutdown()
     DelayPools::FreePools();
 #endif
 
-    authenticateShutdown();
+    authenticateReset();
 #if USE_WIN32_SERVICE
 
     WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
index 5d4255ff0cf03eafed3dab1d8cbe09b927e9e792..b966336c4a659b84a717950d987516de6a342e95 100644 (file)
@@ -180,7 +180,7 @@ peerUserHashSelectParent(HttpRequest * request)
     if (n_userhash_peers == 0)
         return NULL;
 
-    if (request->auth_user_request)
+    if (request->auth_user_request != NULL)
         key = request->auth_user_request->username();
 
     if (!key)
index 9fac2805abecef2c7d6c1e57b59013bab14d31d4..23c2c0d68399f67e9ab2e2e2bb5708bea11c6348 100644 (file)
@@ -789,4 +789,8 @@ class external_acl;
             /* upstream proxy authentication */
             SQUIDCEXTERN char *peer_proxy_negotiate_auth(char *principal_name, char *proxy);
 #endif
+
+/* call to ensure the auth component schemes exist. */
+SQUIDCEXTERN void InitAuthSchemes(void);
+
 #endif /* SQUID_PROTOS_H */
index 6d43e4b6dfb10ccf572da506f440ab1663ab241f..43c884a9bb5637d86114429cac39332de87b5e95 100644 (file)
@@ -136,7 +136,7 @@ redirectStart(ClientHttpRequest * http, RH * handler, void *data)
         r->client_addr.SetNoAddr();
     r->client_ident = NULL;
 
-    if (http->request->auth_user_request)
+    if (http->request->auth_user_request != NULL)
         r->client_ident = http->request->auth_user_request->username();
     else if (http->request->extacl_user.defined()) {
         r->client_ident = http->request->extacl_user.termedBuf();
index 44dde166213a7e16ad3b7b52dcf4c11d841233c5..b92abc3f8ab49191566b63292fb29435f97aaa3e 100644 (file)
@@ -1040,6 +1040,9 @@ statRegisterWithCacheManager(void)
     manager->registerAction("active_requests",
                             "Client-side Active Requests",
                             statClientRequests, 0, 1);
+    manager->registerAction("username_cache",
+                            "Active Cached Usernames",
+                            AuthUser::UsernameCacheStats, 0, 1);
 #if DEBUG_OPENFD
     manager->registerAction("openfd_objects", "Objects with Swapout files open",
                             statOpenfdObj, 0, 0);
@@ -1653,7 +1656,7 @@ statClientRequests(StoreEntry * s)
                           (int) http->start_time.tv_usec,
                           tvSubDsec(http->start_time, current_time));
 
-        if (http->request->auth_user_request)
+        if (http->request->auth_user_request != NULL)
             p = http->request->auth_user_request->username();
         else if (http->request->extacl_user.defined()) {
             p = http->request->extacl_user.termedBuf();
index b8ddec90bf4ebc754bb424ad4e13ac60405e76fa..258a4dfbc8578609244574aeaf5f027ab4c8623c 100644 (file)
@@ -486,7 +486,6 @@ struct SquidConfig {
 #endif
     } accessList;
     acl_deny_info_list *denyInfoList;
-    authConfig authConfiguration;
 
     struct {
         size_t list_width;
index a6089e1e5d5d636e1ef8c448e5c3a0d20488f795..056bc14ba0f8a4d21d114ec670ac52bf23d2f072 100644 (file)
@@ -59,22 +59,22 @@ static
 AuthConfig *
 getConfig(char const *type_str)
 {
-    Vector<AuthConfig *> &config = Config.authConfiguration;
+    Auth::authConfig &config = Auth::TheConfig;
     /* find a configuration for the scheme */
-    AuthConfig *scheme = AuthConfig::Find (type_str);
+    AuthConfig *scheme = AuthConfig::Find(type_str);
 
     if (scheme == NULL) {
         /* Create a configuration */
-        AuthScheme *theScheme;
+        AuthScheme::Pointer theScheme = AuthScheme::Find(type_str);
 
-        if ((theScheme = AuthScheme::Find(type_str)) == NULL) {
+        if (theScheme == NULL) {
             return NULL;
             //fatalf("Unknown authentication scheme '%s'.\n", type_str);
         }
 
         config.push_back(theScheme->createConfig());
         scheme = config.back();
-        assert (scheme);
+        assert(scheme);
     }
 
     return scheme;
@@ -84,7 +84,7 @@ static
 void
 setup_scheme(AuthConfig *scheme, char const **params, unsigned param_count)
 {
-    Vector<AuthConfig *> &config = Config.authConfiguration;
+    Auth::authConfig &config = Auth::TheConfig;
 
     for (unsigned position=0; position < param_count; position++) {
         char *param_str=xstrdup(params[position]);
@@ -104,7 +104,7 @@ fake_auth_setup()
 
     Mem::Init();
 
-    Vector<AuthConfig *> &config = Config.authConfiguration;
+    Auth::authConfig &config = Auth::TheConfig;
 
     char const *digest_parms[]= {"program /home/robertc/install/squid/libexec/digest_pw_auth /home/robertc/install/squid/etc/digest.pwd",
                                  "realm foo"
@@ -155,8 +155,8 @@ testAuthConfig::create()
     Debug::Levels[29]=9;
     fake_auth_setup();
 
-    for (AuthScheme::const_iterator i = AuthScheme::Schemes().begin(); i != AuthScheme::Schemes().end(); ++i) {
-        AuthUserRequest *authRequest = AuthConfig::CreateAuthUser(find_proxy_auth((*i)->type()));
+    for (AuthScheme::iterator i = AuthScheme::GetSchemes().begin(); i != AuthScheme::GetSchemes().end(); ++i) {
+        AuthUserRequest::Pointer authRequest = AuthConfig::CreateAuthUser(find_proxy_auth((*i)->type()));
         CPPUNIT_ASSERT(authRequest != NULL);
     }
 }
@@ -174,15 +174,16 @@ testAuthUserRequest::scheme()
     Debug::Levels[29]=9;
     fake_auth_setup();
 
-    for (AuthScheme::const_iterator i = AuthScheme::Schemes().begin(); i != AuthScheme::Schemes().end(); ++i) {
+    for (AuthScheme::iterator i = AuthScheme::GetSchemes().begin(); i != AuthScheme::GetSchemes().end(); ++i) {
         // create a user request
         // check its scheme matches *i
-        AuthUserRequest *authRequest = AuthConfig::CreateAuthUser(find_proxy_auth((*i)->type()));
+        AuthUserRequest::Pointer authRequest = AuthConfig::CreateAuthUser(find_proxy_auth((*i)->type()));
         CPPUNIT_ASSERT_EQUAL(authRequest->scheme(), *i);
     }
 }
 
 #if HAVE_AUTH_MODULE_BASIC
+#include "auth/basic/basicUserRequest.h"
 #include "auth/basic/auth_basic.h"
 /* AuthBasicUserRequest::AuthBasicUserRequest works
  */
@@ -197,14 +198,11 @@ testAuthBasicUserRequest::construction()
 void
 testAuthBasicUserRequest::username()
 {
-    AuthBasicUserRequest();
-    AuthBasicUserRequest *temp=new AuthBasicUserRequest();
+    AuthUserRequest::Pointer temp = new AuthBasicUserRequest();
     BasicUser *basic_auth=new BasicUser(AuthConfig::Find("basic"));
     basic_auth->username("John");
     temp->user(basic_auth);
-    basic_auth->addRequest(temp);
     CPPUNIT_ASSERT_EQUAL(0, strcmp("John", temp->username()));
-    delete temp;
 }
 #endif /* HAVE_AUTH_MODULE_BASIC */
 
@@ -223,14 +221,11 @@ testAuthDigestUserRequest::construction()
 void
 testAuthDigestUserRequest::username()
 {
-    AuthDigestUserRequest();
-    AuthDigestUserRequest *temp=new AuthDigestUserRequest();
-    DigestUser *user=new DigestUser(AuthConfig::Find("digest"));
-    user->username("John");
-    temp->user(user);
-    user->addRequest(temp);
+    AuthUserRequest::Pointer temp = new AuthDigestUserRequest();
+    DigestUser *duser=new DigestUser(AuthConfig::Find("digest"));
+    duser->username("John");
+    temp->user(duser);
     CPPUNIT_ASSERT_EQUAL(0, strcmp("John", temp->username()));
-    delete temp;
 }
 #endif /* HAVE_AUTH_MODULE_DIGEST */
 
@@ -249,14 +244,11 @@ testAuthNTLMUserRequest::construction()
 void
 testAuthNTLMUserRequest::username()
 {
-    AuthNTLMUserRequest();
-    AuthNTLMUserRequest *temp=new AuthNTLMUserRequest();
-    NTLMUser *user=new NTLMUser(AuthConfig::Find("ntlm"));
-    user->username("John");
-    temp->user(user);
-    user->addRequest(temp);
+    AuthUserRequest::Pointer temp = new AuthNTLMUserRequest();
+    NTLMUser *nuser=new NTLMUser(AuthConfig::Find("ntlm"));
+    nuser->username("John");
+    temp->user(nuser);
     CPPUNIT_ASSERT_EQUAL(0, strcmp("John", temp->username()));
-    delete temp;
 }
 #endif /* HAVE_AUTH_MODULE_NTLM */
 
@@ -275,14 +267,11 @@ testAuthNegotiateUserRequest::construction()
 void
 testAuthNegotiateUserRequest::username()
 {
-    AuthNegotiateUserRequest();
-    AuthNegotiateUserRequest *temp=new AuthNegotiateUserRequest();
-    NegotiateUser *user=new NegotiateUser(AuthConfig::Find("negotiate"));
-    user->username("John");
-    temp->user(user);
-    user->addRequest(temp);
+    AuthUserRequest::Pointer temp = new AuthNegotiateUserRequest();
+    NegotiateUser *nuser=new NegotiateUser(AuthConfig::Find("negotiate"));
+    nuser->username("John");
+    temp->user(nuser);
     CPPUNIT_ASSERT_EQUAL(0, strcmp("John", temp->username()));
-    delete temp;
 }
 
 #endif /* HAVE_AUTH_MODULE_NEGOTIATE */
index 44086e760a1494b6d0cb78d965be4039a41fbd35..dfd442f483d2f81b6c15d1b32fb5a173087d2a8f 100644 (file)
@@ -48,6 +48,7 @@ protected:
 };
 
 #if HAVE_AUTH_MODULE_BASIC
+#include "auth/basic/basicUserRequest.h"
 class testAuthBasicUserRequest : public CPPUNIT_NS::TestFixture
 {
     CPPUNIT_TEST_SUITE( testAuthBasicUserRequest );
@@ -64,6 +65,7 @@ protected:
 #endif
 
 #if HAVE_AUTH_MODULE_DIGEST
+#include "auth/digest/digestUserRequest.h"
 class testAuthDigestUserRequest : public CPPUNIT_NS::TestFixture
 {
     CPPUNIT_TEST_SUITE( testAuthDigestUserRequest );
@@ -80,6 +82,7 @@ protected:
 #endif
 
 #if HAVE_AUTH_MODULE_NTLM
+#include "auth/ntlm/ntlmUserRequest.h"
 class testAuthNTLMUserRequest : public CPPUNIT_NS::TestFixture
 {
     CPPUNIT_TEST_SUITE( testAuthNTLMUserRequest );
@@ -96,6 +99,7 @@ protected:
 #endif
 
 #if HAVE_AUTH_MODULE_NEGOTIATE
+#include "auth/negotiate/negotiateUserRequest.h"
 class testAuthNegotiateUserRequest : public CPPUNIT_NS::TestFixture
 {
     CPPUNIT_TEST_SUITE( testAuthNegotiateUserRequest );
index b316c47a42d960849bb184c1a59c76980255c18c..73034c75e7ed7cb6de8955f5eccd7a0a1deebdb1 100644 (file)
@@ -54,10 +54,6 @@ typedef struct {
 /// \deprecated Use AuthUserHashPointer instead.
 typedef struct AuthUserHashPointer auth_user_hash_pointer;
 
-/// \ingroup AuthAPI
-/// \deprecated Use AuthUserIP instead.
-typedef struct AuthUserIP auth_user_ip_t;
-
 /* temporary: once Config is fully hidden, this shouldn't be needed */
 #include "Array.h"
 
index 513aea4c4f49ffca0644c2f9ff4878a44db3380b..00f427974cd87e09f1577d619a05851229db63af 100644 (file)
@@ -67,7 +67,7 @@ mem_hdr_test_SOURCES = mem_hdr_test.cc $(DEBUG_SOURCE)
 mem_hdr_test_LDADD = $(top_builddir)/src/stmem.o \
                     $(top_builddir)/src/mem_node.o $(LDADD)
 MemPoolTest_SOURCES = MemPoolTest.cc
-refcount_SOURCES = refcount.cc
+refcount_SOURCES = refcount.cc  $(DEBUG_SOURCE)
 
 splay_SOURCES = splay.cc