struct RefCountable_ {
RefCountable_():count_(0) {}
- virtual ~RefCountable_() {}
+ virtual ~RefCountable_() { assert(count_ == 0); }
/* Not private, to allow class hierarchies */
void RefCountReference() const {
#define SQUID_AUTHCONFIG_H
#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"
static AuthUserRequest::Pointer CreateAuthUser(const char *proxy_auth);
static AuthConfig *Find(const char *proxy_auth);
- AuthConfig() {}
+ AuthConfig() : authenticateChildren(20), authenticate(NULL) {}
virtual ~AuthConfig() {}
virtual void parse(AuthConfig *, int, char *) = 0;
/** the http string id */
virtual const char * type() const = 0;
+
+public:
+ HelperChildConfig authenticateChildren;
+ wordlist *authenticate;
};
namespace Auth
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;
+#if USER_REQUEST_LOOP_DEAD
requests.head = requests.tail = NULL;
+#endif
debugs(29, 5, "AuthUser::AuthUser: Initialised auth_user '" << this << "' with refcount '" << references << "'.");
}
-/* Combine two user structs. ONLY to be called from within a scheme
+/**
+ * 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
* data
*/
debugs(29, 5, "authenticateAuthUserMerge auth_user '" << from << "' into auth_user '" << this << "'.");
+#if USER_REQUEST_LOOP_DEAD
dlink_node *link = from->requests.head;
while (link) {
AuthUserRequest::Pointer *auth_user_request = static_cast<AuthUserRequest::Pointer*>(link->data);
+ /* add to our list. replace if already present. */
+ addRequest(*auth_user_request);
+ AuthUserRequest::Pointer aur = *(auth_user_request);
+ aur->user(this);
+ /* remove from other list */
dlink_node *tmplink = link;
link = link->next;
dlinkDelete(tmplink, &from->requests);
- dlinkAddTail(auth_user_request, tmplink, &requests);
- AuthUserRequest::Pointer aur = *(auth_user_request);
- aur->user(this);
}
+#endif /* USER_REQUEST_LOOP_DEAD */
references += from->references;
from->references = 0;
AuthUser::~AuthUser()
{
- 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 ? */
delete usernamehash;
}
+#if USER_REQUEST_LOOP_DEAD
/* remove any outstanding requests */
- link = requests.head;
+ dlink_node *link = requests.head;
while (link) {
debugs(29, 5, "AuthUser::~AuthUser: removing request entry '" << link->data << "'");
AuthUserRequest::Pointer *auth_user_request = static_cast<AuthUserRequest::Pointer*>(link->data);
- tmplink = link;
+ dlink_node *tmplink = link;
link = link->next;
dlinkDelete(tmplink, &requests);
+ tmplink->data = NULL;
dlinkNodeDelete(tmplink);
*auth_user_request = NULL;
}
+#endif /* USER_REQUEST_LOOP_DEAD */
/* free cached acl results */
aclCacheMatchFlush(&proxy_match_cache);
username = auth_user->username();
/* free cached acl results */
aclCacheMatchFlush(&auth_user->proxy_match_cache);
-
}
debugs(29, 3, "AuthUser::CachedACLsReset: Finished.");
}
}
+#if USER_REQUEST_LOOP_DEAD
void
AuthUser::addRequest(AuthUserRequest::Pointer request)
{
- /* lock for the request link */
- /* AYJ: 2009-12-12: WTF? locking the AuthUser because it has a reference to a request? */
- /* seems to me like this once-upon-a-time may have been intended to lock the AuthUserRequest */
+ /* lock for the request link (AKA lock because the request links to us) */
lock();
dlink_node *node = dlinkNodeNew();
dlinkAdd(&request, node, &requests);
}
+
+void
+AuthUser::doneRequest(AuthUserRequest::Pointer request)
+{
+ /* unlink from the auth_user struct */
+ dlink_node *link = requests.head;
+ AuthUserRequest::Pointer *auth_user_request = NULL;
+
+ while (link) {
+ auth_user_request = static_cast<AuthUserRequest::Pointer*>(link->data);
+ if (*auth_user_request == request) {
+ dlink_node *tmplink = link;
+ link = link->next;
+ dlinkDelete(tmplink, &requests);
+ tmplink->data = NULL;
+ dlinkNodeDelete(tmplink);
+ *auth_user_request = NULL;
+ }
+ link = link->next;
+ }
+}
+#endif /* USER_REQUEST_LOOP_DEAD */
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();
virtual ~AuthUser();
_SQUID_INLINE_ char const *username() const;
_SQUID_INLINE_ void username(char const *);
+
+ /* Manage list of IPs using this username */
void clearIp();
void removeIp(IpAddress);
void addIp(IpAddress);
+
+#if USER_REQUEST_LOOP_DEAD
+protected:
+ /* manage list of active authentication requests for this username */
+ /** 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;
+
+ /* AYJ: why? do we need this here? it forms the core of a circular refcount. */
+
+public:
_SQUID_INLINE_ void addRequest(AuthUserRequest::Pointer);
+ _SQUID_INLINE_ void doneRequest(AuthUserRequest::Pointer);
+#endif /* USER_REQUEST_LOOP_DEAD */
void lock();
void unlock();
void addToNameCache();
protected:
- AuthUser (AuthConfig *);
+ AuthUser(AuthConfig *);
private:
- static void cacheCleanup (void *unused);
+ static void cacheCleanup(void *unused);
/**
* DPW 2007-05-08
AuthUserRequest::~AuthUserRequest()
{
- dlink_node *link;
+ assert(RefCountCount()==0);
debugs(29, 5, "AuthUserRequest::~AuthUserRequest: freeing request " << this);
if (user()) {
+#if USER_REQUEST_LOOP_DEAD
/* AYJ: something strange: in order to be deleted this object must not be
* referenced anywhere. Including the AuthUser list of requests.
* I expect the following loop to NEVER find a pointer to this request object.
*/
+ user()->doneRequest(this);
+#endif /* USER_REQUEST_LOOP_DEAD */
- /* unlink from the auth_user struct */
- link = user()->requests.head;
-
- while (link) {
-
- assert( static_cast<AuthUserRequest::Pointer*>(link->data)->getRaw() != this );
-
- if (static_cast<AuthUserRequest::Pointer*>(link->data)->getRaw() == this) {
- dlinkDelete(link, &user()->requests);
- dlinkNodeDelete(link);
- }
- link = link->next;
- }
-
- /* unlock the request structure's lock */
+ /* unlock the request structure's lock and release it */
user()->unlock();
-
user(NULL);
}
}
AuthBasicConfig::AuthBasicConfig() :
- authenticateChildren(20),
- authenticate(NULL),
credentialsTTL( 2*60*60 ),
casesensitive(0),
utf8(0)
return true;
}
+/**
+ * Generate a duplicate of the bad credentials before clearing the working copy.
+ * apparently for logging, but WTF?!
+ */
void
BasicUser::makeLoggingInstance(AuthUserRequest::Pointer auth_user_request)
{
username(NULL);
/* set the auth_user type */
basic_auth->auth_type = AUTH_BROKEN;
+#if USER_REQUEST_LOOP_DEAD
/* link the request to the user */
basic_auth->addRequest(auth_user_request);
+#endif /* USER_REQUEST_LOOP_DEAD */
}
}
/* link the request to the in-cache user */
auth_user_request->user(basic_auth);
+#if USER_REQUEST_LOOP_DEAD
basic_auth->addRequest(auth_user_request);
+#endif /* USER_REQUEST_LOOP_DEAD */
return auth_user_request;
}
typedef class BasicUser basic_data;
-#include "HelperChildConfig.h"
-
/* configuration runtime data */
class AuthBasicConfig : public AuthConfig
virtual void parse(AuthConfig *, int, char *);
virtual void registerWithCacheManager(void);
virtual const char * type() const;
- HelperChildConfig authenticateChildren;
- wordlist *authenticate;
char *basicAuthRealm;
time_t credentialsTTL;
int casesensitive;
MEMPROXY_CLASS(AuthBasicUserRequest);
AuthBasicUserRequest() {};
- virtual ~AuthBasicUserRequest() {};
+ virtual ~AuthBasicUserRequest() { assert(RefCountCount()==0); };
virtual int authenticated() const;
virtual void authenticate(HttpRequest * request, ConnStateData *conn, http_hdr_type type);
static int authdigest_initialised = 0;
static MemAllocator *digest_nonce_pool = NULL;
-CBDATA_TYPE(DigestAuthenticateStateData);
+// CBDATA_TYPE(DigestAuthenticateStateData);
enum http_digest_attr_type {
DIGEST_USERNAME,
safe_free(digestAuthRealm);
}
-AuthDigestConfig::AuthDigestConfig() : authenticateChildren(20), authenticate(NULL)
+AuthDigestConfig::AuthDigestConfig()
{
/* TODO: move into initialisation list */
/* 5 minutes */
/* link the request to the user */
auth_user_request->user(digest_user);
digest_user->lock();
+#if USER_REQUEST_LOOP_DEAD
digest_user->addRequest(auth_user_request);
+#endif
return auth_user_request;
}
digest_user->lock();
digest_request->user(digest_user);
-
+#if USER_REQUEST_LOOP_DEAD
digest_user->addRequest(digest_request);
+#endif
debugs(29, 9, "username = '" << digest_user->username() << "'\nrealm = '" <<
digest_request->realm << "'\nqop = '" << digest_request->qop <<
extern const char *authenticateDigestNonceNonceb64(const digest_nonce_h * nonce);
extern const int authDigestNonceLastRequest(digest_nonce_h * nonce);
-#include "HelperChildConfig.h"
-
/* configuration runtime data */
class AuthDigestConfig : public 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;
*/
AuthDigestUserRequest::~AuthDigestUserRequest()
{
+ assert(RefCountCount()==0);
+
safe_free(nonceb64);
safe_free(cnonce);
safe_free(realm);
}
-AuthNegotiateConfig::AuthNegotiateConfig() : authenticateChildren(20), keep_alive(1), authenticate(NULL)
+AuthNegotiateConfig::AuthNegotiateConfig() : keep_alive(1)
{ }
void
auth_user_request->user(newUser);
auth_user_request->user()->auth_type = AUTH_NEGOTIATE;
+#if USER_REQUEST_LOOP_DEAD
auth_user_request->user()->addRequest(auth_user_request);
+#endif
/* all we have to do is identify that it's Negotiate - the helper does the rest */
debugs(29, 9, "AuthNegotiateConfig::decode: Negotiate authentication");
MEMPROXY_CLASS_INLINE(NegotiateUser);
-#include "HelperChildConfig.h"
-
extern statefulhelper *negotiateauthenticators;
/* configuration runtime data */
virtual void parse(AuthConfig *, int, char *);
virtual void registerWithCacheManager(void);
virtual const char * type() const;
- HelperChildConfig authenticateChildren;
int keep_alive;
- wordlist *authenticate;
};
extern AuthNegotiateConfig negotiateConfig;
AuthNegotiateUserRequest::~AuthNegotiateUserRequest()
{
+ assert(RefCountCount()==0);
safe_free(server_blob);
safe_free(client_blob);
}
-AuthNTLMConfig::AuthNTLMConfig() : authenticateChildren(20), keep_alive(1), authenticate(NULL)
+AuthNTLMConfig::AuthNTLMConfig() : keep_alive(1)
{ }
void
auth_user_request->user(newUser);
auth_user_request->user()->auth_type = AUTH_NTLM;
+#if USER_REQUEST_LOOP_DEAD
auth_user_request->user()->addRequest(auth_user_request);
+#endif
/* all we have to do is identify that it's NTLM - the helper does the rest */
debugs(29, 9, "AuthNTLMConfig::decode: NTLM authentication");
typedef class NTLMUser ntlm_user_t;
-#include "HelperChildConfig.h"
-
/* configuration runtime data */
class AuthNTLMConfig : public 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;
AuthNTLMUserRequest::~AuthNTLMUserRequest()
{
+ assert(RefCountCount()==0);
safe_free(server_blob);
safe_free(client_blob);
if (request->auth_user_request->username())
aLogEntry->cache.authuser = xstrdup(request->auth_user_request->username());
- request->auth_user_request = NULL;
+// WTF?? request->auth_user_request = NULL;
}
}
BasicUser *basic_auth=new BasicUser(AuthConfig::Find("basic"));
basic_auth->username("John");
temp->user(basic_auth);
+#if USER_REQUEST_LOOP_DEAD
basic_auth->addRequest(temp);
+#endif
CPPUNIT_ASSERT_EQUAL(0, strcmp("John", temp->username()));
}
#endif /* HAVE_AUTH_MODULE_BASIC */
DigestUser *duser=new DigestUser(AuthConfig::Find("digest"));
duser->username("John");
temp->user(duser);
+#if USER_REQUEST_LOOP_DEAD
duser->addRequest(temp);
+#endif
CPPUNIT_ASSERT_EQUAL(0, strcmp("John", temp->username()));
}
#endif /* HAVE_AUTH_MODULE_DIGEST */
NTLMUser *nuser=new NTLMUser(AuthConfig::Find("ntlm"));
nuser->username("John");
temp->user(nuser);
+#if USER_REQUEST_LOOP_DEAD
nuser->addRequest(temp);
+#endif
CPPUNIT_ASSERT_EQUAL(0, strcmp("John", temp->username()));
}
#endif /* HAVE_AUTH_MODULE_NTLM */
NegotiateUser *nuser=new NegotiateUser(AuthConfig::Find("negotiate"));
nuser->username("John");
temp->user(nuser);
+#if USER_REQUEST_LOOP_DEAD
nuser->addRequest(temp);
+#endif
CPPUNIT_ASSERT_EQUAL(0, strcmp("John", temp->username()));
}