From 56a49fdac1f359076dcb2adb7b71bdc7b51f991e Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Sun, 11 Apr 2010 21:02:42 +1200 Subject: [PATCH] RefCount AuthUser and children Also adds CacheMgr "username_cache" display page to view the currently cached usernames and how long their TTLs are for. --- src/DelayUser.cc | 16 +- src/DelayUser.h | 7 +- src/Makefile.am | 7 +- src/acl/FilledChecklist.cc | 2 +- src/auth/Acl.cc | 2 +- src/auth/AuthAclState.h | 11 ++ src/auth/AuthType.h | 15 ++ src/auth/Gadgets.cc | 40 +---- src/auth/Gadgets.h | 18 +- src/auth/Makefile.am | 19 ++- src/auth/User.cc | 181 ++++++++++++++------- src/auth/User.cci | 2 +- src/auth/User.h | 35 ++-- src/auth/UserRequest.cc | 29 ++-- src/auth/UserRequest.h | 23 +-- src/auth/basic/auth_basic.cc | 77 ++++++--- src/auth/basic/auth_basic.h | 15 +- src/auth/basic/basicUserRequest.cc | 11 +- src/auth/digest/auth_digest.cc | 73 ++++----- src/auth/digest/auth_digest.h | 5 +- src/auth/digest/digestScheme.cc | 17 ++ src/auth/digest/digestScheme.h | 7 + src/auth/digest/digestUserRequest.cc | 53 +++--- src/auth/enums.h | 20 --- src/auth/negotiate/auth_negotiate.cc | 7 + src/auth/negotiate/auth_negotiate.h | 4 +- src/auth/negotiate/negotiateUserRequest.cc | 51 ++---- src/auth/negotiate/negotiateUserRequest.h | 2 - src/auth/ntlm/auth_ntlm.cc | 7 + src/auth/ntlm/auth_ntlm.h | 5 +- src/auth/ntlm/ntlmUserRequest.cc | 48 ++---- src/client_side.h | 3 +- src/stat.cc | 3 + src/typedefs.h | 4 - 34 files changed, 445 insertions(+), 374 deletions(-) create mode 100644 src/auth/AuthAclState.h create mode 100644 src/auth/AuthType.h delete mode 100644 src/auth/enums.h diff --git a/src/DelayUser.cc b/src/DelayUser.cc index 543a297c5a..7e6e42cc62 100644 --- a/src/DelayUser.cc +++ b/src/DelayUser.cc @@ -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); diff --git a/src/DelayUser.h b/src/DelayUser.h index 885389e4d5..7c41f55e9b 100644 --- a/src/DelayUser.h +++ b/src/DelayUser.h @@ -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, AuthUser *); + Id(RefCount, AuthUser::Pointer); ~Id(); virtual int bytesWanted (int min, int max) const; virtual void bytesIn(int qty); diff --git a/src/Makefile.am b/src/Makefile.am index 0def622313..88f93ab971 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 > $@ -## 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 > $@ @@ -981,6 +981,7 @@ tests_testAuth_SOURCES = \ ConfigParser.cc \ HelperChildConfig.h \ HelperChildConfig.cc \ + ip/stubQosConfig.cc \ tests/stub_acl.cc tests/stub_cache_cf.cc \ tests/stub_helper.cc cbdata.cc String.cc \ tests/stub_store.cc HttpHeaderTools.cc HttpHeader.cc mem.cc ClientInfo.h \ diff --git a/src/acl/FilledChecklist.cc b/src/acl/FilledChecklist.cc index f59e5f1aea..92f3ba772d 100644 --- a/src/acl/FilledChecklist.cc +++ b/src/acl/FilledChecklist.cc @@ -30,7 +30,7 @@ ACLFilledChecklist::authenticated() /* get authed here */ /* Note: this fills in auth_user_request when applicable */ - auth_acl_t result = AuthUserRequest::tryToAuthenticateAndSetAuthUser(&auth_user_request, headertype, request, conn(), src_addr); + AuthAclState result = AuthUserRequest::tryToAuthenticateAndSetAuthUser(&auth_user_request, headertype, request, conn(), src_addr); switch (result) { case AUTH_ACL_CANNOT_AUTHENTICATE: diff --git a/src/auth/Acl.cc b/src/auth/Acl.cc index 6952fbc76d..6e43bca198 100644 --- a/src/auth/Acl.cc +++ b/src/auth/Acl.cc @@ -32,7 +32,7 @@ AuthenticateAcl(ACLChecklist *ch) /* get authed here */ /* Note: this fills in auth_user_request when applicable */ - const auth_acl_t result = AuthUserRequest::tryToAuthenticateAndSetAuthUser( + const AuthAclState result = AuthUserRequest::tryToAuthenticateAndSetAuthUser( &checklist->auth_user_request, headertype, request, checklist->conn(), checklist->src_addr); switch (result) { diff --git a/src/auth/AuthAclState.h b/src/auth/AuthAclState.h new file mode 100644 index 0000000000..10d639014e --- /dev/null +++ b/src/auth/AuthAclState.h @@ -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 index 0000000000..eec96b77f5 --- /dev/null +++ b/src/auth/AuthType.h @@ -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 diff --git a/src/auth/Gadgets.cc b/src/auth/Gadgets.cc index 2748630ab3..424b2b3e63 100644 --- a/src/auth/Gadgets.cc +++ b/src/auth/Gadgets.cc @@ -120,23 +120,6 @@ authenticateShutdown(void) } } -/** - \retval 0 not in use - \retval ? in use - */ -int -authenticateAuthUserInuse(AuthUser * auth_user) -{ - assert(auth_user != NULL); - return auth_user->references; -} - -void -authenticateAuthUserMerge(AuthUser * from, AuthUser * to) -{ - to->absorb (from); -} - /** * Cleans all config-dependent data from the auth_user cache. \note It DOES NOT Flush the user cache. @@ -145,7 +128,7 @@ void authenticateUserCacheRestart(void) { AuthUserHashPointer *usernamehash; - AuthUser *auth_user; + AuthUser::Pointer auth_user; debugs(29, 3, HERE << "Clearing config dependent cache data."); hash_first(proxy_auth_username_cache); @@ -155,35 +138,24 @@ authenticateUserCacheRestart(void) } } - +// TODO: remove this wrapper. inline the actions. void AuthUserHashPointer::removeFromCache(void *usernamehash_p) { AuthUserHashPointer *usernamehash = static_cast(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. - */ + hash_remove_link(proxy_auth_username_cache, (hash_link *)usernamehash); + delete usernamehash; } -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; diff --git a/src/auth/Gadgets.h b/src/auth/Gadgets.h index 2e94fc2f0d..96da2c09a8 100644 --- a/src/auth/Gadgets.h +++ b/src/auth/Gadgets.h @@ -36,6 +36,7 @@ #include "hash.h" #include "MemPool.h" #include "auth/Config.h" +#include "auth/User.h" class AuthUser; @@ -52,15 +53,15 @@ struct AuthUserHashPointer : public hash_link { /* first two items must be same as hash_link */ public: - static void removeFromCache (void *anAuthUserHashPointer); + static void removeFromCache(void *anAuthUserHashPointer); MEMPROXY_CLASS(AuthUserHashPointer); - AuthUserHashPointer(AuthUser *); + AuthUserHashPointer(AuthUser::Pointer ); - AuthUser *user() const; + AuthUser::Pointer user() const; private: - AuthUser *auth_user; + AuthUser::Pointer auth_user; }; MEMPROXY_CLASS_INLINE(AuthUserHashPointer); @@ -75,19 +76,10 @@ class StoreEntry; */ typedef void AUTHSSTATS(StoreEntry *); -/** - \ingroup AuthAPI - * subsumed by the C++ interface - \todo does 'subsumed' mean deprecated use a C++ API call? - */ -extern void authenticateAuthUserMerge(AuthUser *, AuthUser *); - /// \ingroup AuthAPI extern void authenticateInit(Auth::authConfig *); /// \ingroup AuthAPI extern void authenticateShutdown(void); -/// \ingroup AuthAPI -extern int authenticateAuthUserInuse(AuthUser * auth_user); /// \ingroup AuthAPI extern void authenticateFreeProxyAuthUserACLResults(void *data); diff --git a/src/auth/Makefile.am b/src/auth/Makefile.am index becf34eba6..470ece2779 100644 --- a/src/auth/Makefile.am +++ b/src/auth/Makefile.am @@ -8,20 +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 \ - enums.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 \ - State.h \ - State.cc + UserRequest.cc libauth_la_LIBADD = $(AUTH_LIBS_TO_BUILD) libauth_la_DEPENDENCIES = $(AUTH_LIBS_TO_BUILD) @@ -34,7 +35,8 @@ libacls_la_SOURCES = \ AclMaxUserIp.cc \ AclMaxUserIp.h \ AclProxyAuth.cc \ - AclProxyAuth.h + AclProxyAuth.h \ + AuthAclState.h libbasic_la_SOURCES = \ basic/basicScheme.cc \ @@ -68,6 +70,9 @@ libnegotiate_la_SOURCES = \ 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 > $@ + TESTS += testHeaders diff --git a/src/auth/User.cc b/src/auth/User.cc index cceb296ad7..0b1a8d8e2a 100644 --- a/src/auth/User.cc +++ b/src/auth/User.cc @@ -42,17 +42,22 @@ #include "acl/Gadgets.h" #include "event.h" #include "SquidTime.h" +#include "Store.h" #ifndef _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); - -AuthUser::AuthUser (AuthConfig *aConfig) : - auth_type (AUTH_UNKNOWN), config(aConfig), - usernamehash (NULL), ipcount (0), expiretime (0), references (0), username_(NULL) +CBDATA_TYPE(AuthUserIP); + +AuthUser::AuthUser(AuthConfig *aConfig) : + auth_type(AUTH_UNKNOWN), + config(aConfig), + usernamehash(NULL), + ipcount(0), + expiretime(0), + username_(NULL) { proxy_auth_list.head = proxy_auth_list.tail = NULL; proxy_match_cache.head = proxy_match_cache.tail = NULL; @@ -60,7 +65,7 @@ AuthUser::AuthUser (AuthConfig *aConfig) : #if USER_REQUEST_LOOP_DEAD requests.head = requests.tail = NULL; #endif - debugs(29, 5, "AuthUser::AuthUser: Initialised auth_user '" << this << "' with refcount '" << references << "'."); + debugs(29, 5, "AuthUser::AuthUser: Initialised auth_user '" << this << "'."); } /** @@ -71,13 +76,23 @@ AuthUser::AuthUser (AuthConfig *aConfig) : * related scheme data itself. */ void -AuthUser::absorb(AuthUser *from) +AuthUser::absorb(AuthUser::Pointer from) { + + /* 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 << "'."); #if USER_REQUEST_LOOP_DEAD dlink_node *link = from->requests.head; @@ -95,15 +110,60 @@ AuthUser::absorb(AuthUser *from) } #endif /* USER_REQUEST_LOOP_DEAD */ - 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(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(ip_list.head->data); + bool found = false; + while (ipdata) { + AuthUserIP *tempnode = static_cast(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() { - debugs(29, 5, "AuthUser::~AuthUser: Freeing auth_user '" << this << "' with refcount '" << references << "'."); - assert(references == 0); + debugs(29, 5, "AuthUser::~AuthUser: Freeing auth_user '" << this << "'."); + assert(RefCountCount() == 0); + /* were they linked in by username ? */ if (usernamehash) { @@ -150,8 +210,7 @@ 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); } @@ -165,7 +224,7 @@ AuthUser::CachedACLsReset() * This must complete all at once, because we are ensuring correctness. */ AuthUserHashPointer *usernamehash; - AuthUser *auth_user; + AuthUser::Pointer auth_user; char const *username = NULL; debugs(29, 3, "AuthUser::CachedACLsReset: Flushing the ACL caches for all users."); hash_first(proxy_auth_username_cache); @@ -189,7 +248,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); @@ -205,18 +264,17 @@ AuthUser::cacheCleanup(void *datanotused) 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; } } @@ -227,12 +285,12 @@ AuthUser::cacheCleanup(void *datanotused) 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); @@ -249,7 +307,7 @@ AuthUser::clearIp() void AuthUser::removeIp(IpAddress 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 */ @@ -264,7 +322,7 @@ AuthUser::removeIp(IpAddress ipaddr) return; } - ipdata = (auth_user_ip_t *) ipdata->node.next; + ipdata = (AuthUserIP *) ipdata->node.next; } } @@ -272,10 +330,10 @@ AuthUser::removeIp(IpAddress ipaddr) void AuthUser::addIp(IpAddress 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 @@ -283,7 +341,7 @@ AuthUser::addIp(IpAddress 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) { @@ -307,7 +365,7 @@ AuthUser::addIp(IpAddress ipaddr) return; /* This ip is not in the seen list */ - ipdata = cbdataAlloc(auth_user_ip_t); + ipdata = cbdataAlloc(AuthUserIP); ipdata->ip_expiretime = squid_curtime; @@ -320,37 +378,40 @@ AuthUser::addIp(IpAddress ipaddr) debugs(29, 2, "authenticateAuthUserAddIp: user '" << username() << "' has been seen at a new IP address (" << ipaddr << ")"); } - +/* addToNameCache: add a auth_user 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 << "'."); + usernamehash = 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); - debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "' now at '" << references << "'."); + /* cache dump column titles */ + storeAppendPrintf(output, "Authentication cached Usernames:\n"); + storeAppendPrintf(output, "%-15s %-9s %s\n", + "Type", + "TTL", + "Username"); + storeAppendPrintf(output, "--------------- --------- ------------------------------\n"); - if (references == 0) - delete this; -} + hash_first(proxy_auth_username_cache); + while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) { + AuthUser::Pointer auth_user = usernamehash->user(); -/* addToNameCache: add a auth_user structure to the username cache */ -void -AuthUser::addToNameCache() -{ - usernamehash = new AuthUserHashPointer (this); + storeAppendPrintf(output, "%-15s %-9d %s\n", + AuthType_str[auth_user->auth_type], + auth_user->ttl(), + auth_user->username() + ); + } } diff --git a/src/auth/User.cci b/src/auth/User.cci index 91c7988b51..35e4074a8b 100644 --- a/src/auth/User.cci +++ b/src/auth/User.cci @@ -47,7 +47,7 @@ AuthUser::username () const } void -AuthUser::username(char const*aString) +AuthUser::username(char const *aString) { if (aString) { assert(!username_); diff --git a/src/auth/User.h b/src/auth/User.h index ccad09a4a6..72ebdffe61 100644 --- a/src/auth/User.h +++ b/src/auth/User.h @@ -34,16 +34,18 @@ #ifndef SQUID_AUTHUSER_H #define SQUID_AUTHUSER_H +#if USER_REQUEST_LOOP_DEAD #include "auth/UserRequest.h" +#endif + +#include "auth/AuthType.h" +#include "dlink.h" +#include "ip/IpAddress.h" +#include "RefCount.h" class AuthConfig; class AuthUserHashPointer; - -/* for auth_type_t */ -#include "enums.h" - -#include "ip/IpAddress.h" -#include "dlink.h" +class StoreEntry; /** * \ingroup AuthAPI @@ -53,16 +55,17 @@ 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 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 */ @@ -72,17 +75,21 @@ public: dlink_list proxy_match_cache; size_t ipcount; long expiretime; - /** how many references are outstanding to this instance */ - size_t references; 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(IpAddress); @@ -102,10 +109,8 @@ public: _SQUID_INLINE_ void doneRequest(AuthUserRequest::Pointer); #endif /* USER_REQUEST_LOOP_DEAD */ - void lock(); - void unlock(); - void addToNameCache(); + static void UsernameCacheStats(StoreEntry * output); protected: AuthUser(AuthConfig *); diff --git a/src/auth/UserRequest.cc b/src/auth/UserRequest.cc index 493ae4a048..63525d4185 100644 --- a/src/auth/UserRequest.cc +++ b/src/auth/UserRequest.cc @@ -56,7 +56,7 @@ char const * AuthUserRequest::username() const { - if (user()) + if (user() != NULL) return user()->username(); else return NULL; @@ -138,7 +138,7 @@ AuthUserRequest::~AuthUserRequest() assert(RefCountCount()==0); debugs(29, 5, "AuthUserRequest::~AuthUserRequest: freeing request " << this); - if (user()) { + if (user() != NULL) { #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. @@ -147,23 +147,22 @@ AuthUserRequest::~AuthUserRequest() user()->doneRequest(this); #endif /* USER_REQUEST_LOOP_DEAD */ - /* unlock the request structure's lock and release it */ - user()->unlock(); + /* 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; } @@ -181,7 +180,7 @@ AuthUserRequest::denyMessage(char const * const default_message) static void authenticateAuthUserRequestSetIp(AuthUserRequest::Pointer auth_user_request, IpAddress &ipaddr) { - AuthUser *auth_user = auth_user_request->user(); + AuthUser::Pointer auth_user = auth_user_request->user(); if (!auth_user) return; @@ -192,7 +191,7 @@ authenticateAuthUserRequestSetIp(AuthUserRequest::Pointer auth_user_request, IpA void authenticateAuthUserRequestRemoveIp(AuthUserRequest::Pointer auth_user_request, IpAddress const &ipaddr) { - AuthUser *auth_user = auth_user_request->user(); + AuthUser::Pointer auth_user = auth_user_request->user(); if (!auth_user) return; @@ -211,7 +210,7 @@ int authenticateAuthUserRequestIPCount(AuthUserRequest::Pointer auth_user_request) { assert(auth_user_request != NULL); - assert(auth_user_request->user()); + assert(auth_user_request->user() != NULL); return auth_user_request->user()->ipcount; } @@ -306,7 +305,7 @@ authTryGetUser(AuthUserRequest::Pointer auth_user_request, ConnStateData * conn, * * Caller is responsible for locking and unlocking their *auth_user_request! */ -auth_acl_t +AuthAclState AuthUserRequest::authenticate(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, IpAddress &src_addr) { const char *proxy_auth; @@ -475,7 +474,7 @@ AuthUserRequest::authenticate(AuthUserRequest::Pointer * auth_user_request, http return AUTH_AUTHENTICATED; } -auth_acl_t +AuthAclState AuthUserRequest::tryToAuthenticateAndSetAuthUser(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, IpAddress &src_addr) { /* If we have already been called, return the cached value */ @@ -492,7 +491,7 @@ AuthUserRequest::tryToAuthenticateAndSetAuthUser(AuthUserRequest::Pointer * auth } /* 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); diff --git a/src/auth/UserRequest.h b/src/auth/UserRequest.h index d95c2b5a31..cfc6a945ac 100644 --- a/src/auth/UserRequest.h +++ b/src/auth/UserRequest.h @@ -35,19 +35,22 @@ #ifndef SQUID_AUTHUSERREQUEST_H #define SQUID_AUTHUSERREQUEST_H -#include "auth/enums.h" +#include "auth/AuthAclState.h" #include "auth/Scheme.h" +#include "auth/User.h" #include "dlink.h" #include "ip/IpAddress.h" #include "typedefs.h" #include "HttpHeader.h" -class AuthUser; class ConnStateData; class HttpReply; class HttpRequest; -struct AuthUserIP { +/// \ingroup AuthAPI +class AuthUserIP +{ +public: dlink_node node; /* IP addr this user authenticated from */ @@ -73,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. @@ -110,13 +113,13 @@ 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::Pointer *, http_hdr_type, HttpRequest *, ConnStateData *, IpAddress &); + static AuthAclState tryToAuthenticateAndSetAuthUser(AuthUserRequest::Pointer *, http_hdr_type, HttpRequest *, ConnStateData *, IpAddress &); static void addReplyAuthHeader(HttpReply * rep, AuthUserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal); AuthUserRequest(); @@ -150,7 +153,7 @@ public: private: - static auth_acl_t authenticate(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, IpAddress &src_addr); + static AuthAclState authenticate(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, IpAddress &src_addr); /** return a message on the 407 error pages */ char *message; @@ -160,7 +163,7 @@ private: * is to allow multiple auth acl references from different _access areas * when using connection based authentication */ - auth_acl_t lastReply; + AuthAclState lastReply; }; /* AuthUserRequest */ diff --git a/src/auth/basic/auth_basic.cc b/src/auth/basic/auth_basic.cc index d73c952c13..a16f3fa7ea 100644 --- a/src/auth/basic/auth_basic.cc +++ b/src/auth/basic/auth_basic.cc @@ -92,6 +92,18 @@ AuthBasicConfig::type() const return basicScheme::GetInstance()->type(); } +int32_t +BasicUser::ttl() const +{ + if (flags.credentials_ok != 1) + return -1; // TTL is obsolete NOW. + + int32_t basic_ttl = credentials_checkedtime - squid_curtime + static_cast(config)->credentialsTTL; + int32_t global_ttl = static_cast(expiretime - squid_curtime + Config.authenticateTTL); + + return min(basic_ttl, global_ttl); +} + bool BasicUser::authenticated() const @@ -158,7 +170,10 @@ 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(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(r->auth_user_request->user().getRaw()); assert(basic_auth != NULL); @@ -255,7 +270,7 @@ authenticateBasicStats(StoreEntry * sentry) helperStats(sentry, basicauthenticators, "Basic Authenticator Statistics"); } -static AuthUser * +static AuthUser::Pointer authBasicAuthUserFindUsername(const char *username) { AuthUserHashPointer *usernamehash; @@ -280,7 +295,7 @@ 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) +BasicUser::BasicUser(AuthConfig *aConfig) : AuthUser(aConfig) , passwd (NULL), credentials_checkedtime(0), auth_queue(NULL), cleartext(NULL), currentRequest(NULL), httpAuthHeader(NULL) { flags.credentials_ok = 0; } @@ -387,7 +402,6 @@ BasicUser::valid() const /** * 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) @@ -396,7 +410,7 @@ BasicUser::makeLoggingInstance(AuthUserRequest::Pointer auth_user_request) /* log the username */ debugs(29, 9, HERE << "Creating new user for logging '" << username() << "'"); /* new scheme data */ - BasicUser *basic_auth = new BasicUser(config); + AuthUser::Pointer basic_auth = dynamic_cast(new BasicUser(config)); auth_user_request->user(basic_auth); /* save the credentials */ basic_auth->username(username()); @@ -410,7 +424,9 @@ BasicUser::makeLoggingInstance(AuthUserRequest::Pointer auth_user_request) } } -AuthUser * +#if 0 +/* TODO: instead of duplicating into the cache why not just add a ::Pointer to ourselves there? */ +AuthUser::Pointer BasicUser::makeCachedFrom() { /* the user doesn't exist in the username cache yet */ @@ -430,13 +446,18 @@ BasicUser::makeCachedFrom() /* the requests after this link to the basic_user */ /* store user in hash */ basic_user->addToNameCache(); - return basic_user; + + AuthUser::Pointer auth_user = dynamic_cast(basic_user); + return auth_user; } +#endif 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"); @@ -469,35 +490,49 @@ AuthBasicConfig::decode(char const *proxy_auth) while (xisgraph(*proxy_auth)) proxy_auth++; - BasicUser *basic_auth, local_basic(this); + /* 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. */ - AuthUser *auth_user = NULL; + 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; + + /* 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) { - /* TODO: optimize. make "local_basic" the object we will store. dont allocate, duplicate, discard. */ - auth_user = local_basic.makeCachedFrom(); - basic_auth = dynamic_cast(auth_user); - assert (basic_auth); + auth_user = dynamic_cast(local_basic); + assert(auth_user != NULL); } else { - basic_auth = dynamic_cast(auth_user); + /* replace the current cached password with the new one */ + BasicUser *basic_auth = dynamic_cast(auth_user.getRaw()); assert(basic_auth); - basic_auth->updateCached(&local_basic); + basic_auth->updateCached(local_basic); + auth_user = basic_auth; } /* link the request to the in-cache user */ - auth_user_request->user(basic_auth); + auth_user_request->user(auth_user); #if USER_REQUEST_LOOP_DEAD basic_auth->addRequest(auth_user_request); #endif /* USER_REQUEST_LOOP_DEAD */ diff --git a/src/auth/basic/auth_basic.h b/src/auth/basic/auth_basic.h index e9f12d0089..6b506c1281 100644 --- a/src/auth/basic/auth_basic.h +++ b/src/auth/basic/auth_basic.h @@ -42,15 +42,18 @@ public: bool valid() const; void makeLoggingInstance(AuthUserRequest::Pointer auth_user_request); - AuthUser * makeCachedFrom(); +#if 0 + AuthUser::Pointer makeCachedFrom(); +#endif + /** Update the cached password for a username. */ void updateCached(BasicUser *from); + virtual int32_t ttl() const; + char *passwd; time_t credentials_checkedtime; struct { - -unsigned int credentials_ok: - 2; /*0=unchecked,1=ok,2=failed */ + unsigned int credentials_ok:2; /* 0=unchecked, 1=ok, 2=failed */ } flags; BasicAuthQueueNode *auth_queue; @@ -65,8 +68,6 @@ private: MEMPROXY_CLASS_INLINE(BasicUser); -typedef class BasicUser basic_data; - /* configuration runtime data */ class AuthBasicConfig : public AuthConfig @@ -91,4 +92,4 @@ public: int utf8; }; -#endif +#endif /* __AUTH_BASIC_H__ */ diff --git a/src/auth/basic/basicUserRequest.cc b/src/auth/basic/basicUserRequest.cc index dc45db4cd6..f8829dcf54 100644 --- a/src/auth/basic/basicUserRequest.cc +++ b/src/auth/basic/basicUserRequest.cc @@ -7,7 +7,7 @@ int AuthBasicUserRequest::authenticated() const { - BasicUser const *basic_auth = dynamic_cast(user()); + BasicUser const *basic_auth = dynamic_cast(user().getRaw()); if (basic_auth && basic_auth->authenticated()) return 1; @@ -22,7 +22,7 @@ AuthBasicUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, { assert(user() != NULL); - basic_data *basic_auth = dynamic_cast(user()); + BasicUser *basic_auth = dynamic_cast(user().getRaw()); /* if the password is not ok, do an identity */ @@ -49,7 +49,7 @@ int AuthBasicUserRequest::module_direction() { /* null auth_user is checked for by authenticateDirection */ - basic_data *basic_auth = dynamic_cast(user()); + BasicUser const *basic_auth = dynamic_cast(user().getRaw()); assert (basic_auth); switch (basic_auth->flags.credentials_ok) { @@ -78,9 +78,8 @@ AuthBasicUserRequest::module_direction() void AuthBasicUserRequest::module_start(RH * handler, void *data) { - basic_data *basic_auth; assert(user()->auth_type == AUTH_BASIC); - basic_auth = dynamic_cast(user()); + BasicUser *basic_auth = dynamic_cast(user().getRaw()); assert(basic_auth != NULL); debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'"); @@ -96,6 +95,6 @@ AuthBasicUserRequest::module_start(RH * handler, void *data) return; } - basic_auth->submitRequest (this, handler, data); + basic_auth->submitRequest(this, handler, data); } diff --git a/src/auth/digest/auth_digest.cc b/src/auth/digest/auth_digest.cc index bf5a6d963c..4c0c8d8fe6 100644 --- a/src/auth/digest/auth_digest.cc +++ b/src/auth/digest/auth_digest.cc @@ -480,46 +480,24 @@ 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(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) -{ - /** \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(); - } -} - /** delete the digest request structure. Does NOT delete related structures */ void digestScheme::done() @@ -544,7 +522,7 @@ digestScheme::done() delete digestauthenticators; digestauthenticators = NULL; - authDigestUserShutdown(); + PurgeCredentialsCache(); authenticateDigestNonceShutdown(); debugs(29, 2, "authenticateDigestDone: Digest authentication shut down."); @@ -620,7 +598,6 @@ AuthDigestConfig::fixHeader(AuthUserRequest::Pointer auth_user_request, HttpRepl DigestUser::~DigestUser() { - dlink_node *link, *tmplink; link = nonces.head; @@ -634,6 +611,30 @@ DigestUser::~DigestUser() } } +int32_t +DigestUser::ttl() const +{ + int32_t global_ttl = static_cast(expiretime - squid_curtime + Config.authenticateTTL); + + /* find the longest lasting nonce. */ + int32_t latest_nonce = -1; + dlink_node *link = nonces.head; + while (link) { + digest_nonce_h *nonce = static_cast(link->data); + if (nonce->flags.valid && nonce->noncedata.creationtime > latest_nonce) + latest_nonce = nonce->noncedata.creationtime; + + link = link->next; + } + if (latest_nonce == -1) + return min(-1, global_ttl); + + int32_t nonce_ttl = latest_nonce - current_time.tv_sec + static_cast(AuthConfig::Find("digest"))->noncemaxduration; + + return min(nonce_ttl, global_ttl); +} + + /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the * config file */ void @@ -744,7 +745,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) @@ -784,7 +785,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; @@ -822,14 +823,13 @@ authDigestLogUsername(char *username, AuthUserRequest::Pointer auth_user_request /* log the username */ debugs(29, 9, "authDigestLogUsername: Creating new user for logging '" << username << "'"); - digest_user_h *digest_user = new DigestUser(static_cast(AuthConfig::Find("digest"))); + AuthUser::Pointer digest_user = new DigestUser(static_cast(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->user(digest_user); - digest_user->lock(); #if USER_REQUEST_LOOP_DEAD digest_user->addRequest(auth_user_request); #endif @@ -1079,9 +1079,9 @@ 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 */ @@ -1106,14 +1106,13 @@ 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(auth_user.getRaw()); xfree(username); } /*link the request and the user */ assert(digest_request != NULL); - digest_user->lock(); digest_request->user(digest_user); #if USER_REQUEST_LOOP_DEAD digest_user->addRequest(digest_request); @@ -1130,5 +1129,5 @@ AuthDigestConfig::decode(char const *proxy_auth) return digest_request; } -DigestUser::DigestUser (AuthConfig *aConfig) : AuthUser (aConfig), HA1created (0) +DigestUser::DigestUser(AuthConfig *aConfig) : AuthUser(aConfig), HA1created (0) {} diff --git a/src/auth/digest/auth_digest.h b/src/auth/digest/auth_digest.h index dfbe62ae6a..a37e4bfd55 100644 --- a/src/auth/digest/auth_digest.h +++ b/src/auth/digest/auth_digest.h @@ -29,6 +29,9 @@ public: DigestUser(AuthConfig *); ~DigestUser(); int authenticated() const; + + virtual int32_t ttl() const; + HASH HA1; int HA1created; @@ -39,8 +42,6 @@ public: MEMPROXY_CLASS_INLINE(DigestUser); -typedef class DigestUser digest_user_h; - /* data to be encoded into the nonce's b64 representation */ diff --git a/src/auth/digest/digestScheme.cc b/src/auth/digest/digestScheme.cc index 2d4053cf19..f823107baf 100644 --- a/src/auth/digest/digestScheme.cc +++ b/src/auth/digest/digestScheme.cc @@ -58,3 +58,20 @@ digestScheme::createConfig() AuthDigestConfig *digestCfg = new AuthDigestConfig; return dynamic_cast(digestCfg); } + +void +digestScheme::PurgeCredentialsCache(void) +{ + AuthUserHashPointer *usernamehash; + AuthUser::Pointer auth_user; + hash_first(proxy_auth_username_cache); + + while ((usernamehash = static_cast(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(usernamehash)); + delete usernamehash; + } + } +} diff --git a/src/auth/digest/digestScheme.h b/src/auth/digest/digestScheme.h index 2d12f547e0..1d7652574b 100644 --- a/src/auth/digest/digestScheme.h +++ b/src/auth/digest/digestScheme.h @@ -57,6 +57,13 @@ public: private: 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 index 3fd996c475..3c953b427b 100644 --- a/src/auth/digest/digestUserRequest.cc +++ b/src/auth/digest/digestUserRequest.cc @@ -68,29 +68,24 @@ AuthDigestUserRequest::authenticated() const void AuthDigestUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type) { - AuthDigestUserRequest *digest_request; - digest_user_h *digest_user; - HASHHEX SESSIONKEY; HASHHEX HA2 = ""; HASHHEX Response; - assert(authUser() != NULL); - AuthUser *auth_user = user(); - - digest_user = dynamic_cast(auth_user); - assert(digest_user != NULL); - /* if the check has corrupted the user, just return */ - if (credentials() == Failed) { return; } - digest_request = this; + assert(user() != NULL); + AuthUser::Pointer auth_user = user(); - /* do we have the HA1 */ + DigestUser *digest_user = dynamic_cast(auth_user.getRaw()); + assert(digest_user != NULL); + AuthDigestUserRequest *digest_request = this; + + /* do we have the HA1 */ if (!digest_user->HA1created) { credentials(Pending); return; @@ -165,7 +160,7 @@ AuthDigestUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, /* 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"); + debugs(29, 3, "authenticateDigestAuthenticateuser: user '" << auth_user->username() << "' validated OK but nonce stale"); credentials(Failed); digest_request->setDenyMessage("Stale nonce"); return; @@ -175,7 +170,7 @@ AuthDigestUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, credentials(Ok); /* password was checked and did match */ - debugs(29, 4, "authenticateDigestAuthenticateuser: user '" << digest_user->username() << "' validated OK"); + debugs(29, 4, "authenticateDigestAuthenticateuser: user '" << auth_user->username() << "' validated OK"); /* auth_user is now linked, we reset these values * after external auth occurs anyway */ @@ -265,11 +260,14 @@ AuthDigestUserRequest::module_start(RH * handler, void *data) { authenticateStateData *r = NULL; char buf[8192]; - digest_user_h *digest_user; - assert(user()->auth_type == AUTH_DIGEST); - digest_user = dynamic_cast(user()); + + assert(user() != NULL && user()->auth_type == AUTH_DIGEST); +#if 0 + DigestUser *digest_user = dynamic_cast(user().getRaw()); assert(digest_user != NULL); - debugs(29, 9, "authenticateStart: '\"" << digest_user->username() << "\":\"" << realm << "\"'"); +#endif + + debugs(29, 9, "authenticateStart: '\"" << user()->username() << "\":\"" << realm << "\"'"); if (static_cast(AuthConfig::Find("digest"))->authenticate == NULL) { handler(data, NULL); @@ -282,10 +280,10 @@ AuthDigestUserRequest::module_start(RH * handler, void *data) r->auth_user_request = static_cast(this); if (static_cast(AuthConfig::Find("digest"))->utf8) { char userstr[1024]; - latin1_to_utf8(userstr, sizeof(userstr), digest_user->username()); + latin1_to_utf8(userstr, sizeof(userstr), user()->username()); snprintf(buf, 8192, "\"%s\":\"%s\"\n", userstr, realm); } else { - snprintf(buf, 8192, "\"%s\":\"%s\"\n", digest_user->username(), realm); + snprintf(buf, 8192, "\"%s\":\"%s\"\n", user()->username(), realm); } helperSubmit(digestauthenticators, buf, AuthDigestUserRequest::HandleReply, r); @@ -310,20 +308,21 @@ AuthDigestUserRequest::HandleReply(void *data, char *reply) assert(replyData->auth_user_request != NULL); AuthUserRequest::Pointer auth_user_request = replyData->auth_user_request; - /* AYJ: 2009-12-12: allow this because the digest_request pointer is purely local */ - AuthDigestUserRequest *digest_request = dynamic_cast < AuthDigestUserRequest * >(auth_user_request.getRaw()); - assert(digest_request); - - digest_user_h *digest_user = dynamic_cast < digest_user_h * >(auth_user_request->user()); - assert(digest_user != NULL); - if (reply && (strncasecmp(reply, "ERR", 3) == 0)) { + /* allow this because the digest_request pointer is purely local */ + AuthDigestUserRequest *digest_request = dynamic_cast(auth_user_request.getRaw()); + assert(digest_request); + digest_request->credentials(AuthDigestUserRequest::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(auth_user_request->user().getRaw()); + assert(digest_user != NULL); + CvtBin(reply, digest_user->HA1); digest_user->HA1created = 1; } diff --git a/src/auth/enums.h b/src/auth/enums.h deleted file mode 100644 index 058fd68d05..0000000000 --- a/src/auth/enums.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _SQUID__SRC_AUTH_ENUMS_H -#define _SQUID__SRC_AUTH_ENUMS_H - -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; - -#endif diff --git a/src/auth/negotiate/auth_negotiate.cc b/src/auth/negotiate/auth_negotiate.cc index 6e9a6ff630..a1bbaf47aa 100644 --- a/src/auth/negotiate/auth_negotiate.cc +++ b/src/auth/negotiate/auth_negotiate.cc @@ -293,6 +293,13 @@ NegotiateUser::~NegotiateUser() debugs(29, 5, "NegotiateUser::~NegotiateUser: doing nothing to clearNegotiate scheme data for '" << this << "'"); } +int32_t +NegotiateUser::ttl() const +{ + return -1; // Negotiate canot be cached. +} + + static void authenticateNegotiateStats(StoreEntry * sentry) { diff --git a/src/auth/negotiate/auth_negotiate.h b/src/auth/negotiate/auth_negotiate.h index d0cdd31038..baa1bf1211 100644 --- a/src/auth/negotiate/auth_negotiate.h +++ b/src/auth/negotiate/auth_negotiate.h @@ -27,9 +27,11 @@ 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; }; diff --git a/src/auth/negotiate/negotiateUserRequest.cc b/src/auth/negotiate/negotiateUserRequest.cc index dbf4511131..68a1a8d4dd 100644 --- a/src/auth/negotiate/negotiateUserRequest.cc +++ b/src/auth/negotiate/negotiateUserRequest.cc @@ -119,15 +119,12 @@ AuthNegotiateUserRequest::module_start(RH * handler, void *data) { authenticateStateData *r = NULL; static char buf[MAX_AUTHTOKEN_LEN]; - NegotiateUser *negotiate_user; - AuthUser *auth_user = user(); assert(data); assert(handler); - assert(auth_user); - assert(auth_user->auth_type == AUTH_NEGOTIATE); - negotiate_user = dynamic_cast(user()); + assert(user() != NULL); + assert(user()->auth_type == AUTH_NEGOTIATE); debugs(29, 8, HERE << "auth state is '" << auth_state << "'"); @@ -193,16 +190,6 @@ AuthNegotiateUserRequest::onConnectionClose(ConnStateData *conn) void AuthNegotiateUserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, http_hdr_type type) { - const char *proxy_auth, *blob; - - /** \todo rename this!! */ - AuthUser *local_auth_user; - NegotiateUser *negotiate_user; - - local_auth_user = user(); - assert(local_auth_user); - assert(local_auth_user->auth_type == AUTH_NEGOTIATE); - negotiate_user = dynamic_cast(local_auth_user); assert (this); /** Check that we are in the client side, where we can generate auth challenges */ @@ -223,10 +210,10 @@ AuthNegotiateUserRequest::authenticate(HttpRequest * aRequest, ConnStateData * c } /* get header */ - proxy_auth = aRequest->header.getStr(type); + const char *proxy_auth = aRequest->header.getStr(type); /* locate second word */ - blob = proxy_auth; + const char *blob = proxy_auth; if (blob) { while (xisspace(*blob) && *blob) @@ -291,10 +278,6 @@ AuthNegotiateUserRequest::HandleReply(void *data, void *lastserver, char *reply) int valid; char *blob, *arg = NULL; - AuthUser *auth_user; - NegotiateUser *negotiate_user; - AuthNegotiateUserRequest *negotiate_request; - debugs(29, 8, HERE << "helper: '" << lastserver << "' sent us '" << (reply ? reply : "") << "'"); valid = cbdataReferenceValid(r->data); @@ -313,19 +296,15 @@ AuthNegotiateUserRequest::HandleReply(void *data, void *lastserver, char *reply) AuthUserRequest::Pointer auth_user_request = r->auth_user_request; assert(auth_user_request != NULL); - negotiate_request = dynamic_cast(auth_user_request.getRaw()); + AuthNegotiateUserRequest *negotiate_request = dynamic_cast(auth_user_request.getRaw()); assert(negotiate_request != NULL); assert(negotiate_request->waiting); negotiate_request->waiting = 0; safe_free(negotiate_request->client_blob); - auth_user = auth_user_request->user(); - assert(auth_user != NULL); - assert(auth_user->auth_type == AUTH_NEGOTIATE); - - negotiate_user = dynamic_cast(auth_user_request->user()); - assert(negotiate_user != NULL); + 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(lastserver); @@ -363,7 +342,7 @@ AuthNegotiateUserRequest::HandleReply(void *data, void *lastserver, char *reply) if (arg) *arg++ = '\0'; - negotiate_user->username(arg); + auth_user_request->user()->username(arg); auth_user_request->denyMessage("Login successful"); safe_free(negotiate_request->server_blob); negotiate_request->server_blob = xstrdup(blob); @@ -372,25 +351,25 @@ AuthNegotiateUserRequest::HandleReply(void *data, void *lastserver, char *reply) debugs(29, 4, HERE << "Successfully validated user via Negotiate. Username '" << blob << "'"); /* connection is authenticated */ - debugs(29, 4, HERE << "authenticated user " << negotiate_user->username()); + 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(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)) + AuthUserHashPointer *usernamehash = static_cast(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(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 */ + * 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); - //authenticateAuthUserMerge(local_auth_user, usernamehash->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(); - // authenticateUserNameCacheAdd(local_auth_user); } /* set these to now because this is either a new login from an * existing user or a new user */ diff --git a/src/auth/negotiate/negotiateUserRequest.h b/src/auth/negotiate/negotiateUserRequest.h index 5f98035965..e068ccf566 100644 --- a/src/auth/negotiate/negotiateUserRequest.h +++ b/src/auth/negotiate/negotiateUserRequest.h @@ -6,8 +6,6 @@ #include "helper.h" #include "MemPool.h" -// #include "typedefs.h" - class ConnStateData; class HttpReply; class HttpRequest; diff --git a/src/auth/ntlm/auth_ntlm.cc b/src/auth/ntlm/auth_ntlm.cc index dbc1515e29..333942403d 100644 --- a/src/auth/ntlm/auth_ntlm.cc +++ b/src/auth/ntlm/auth_ntlm.cc @@ -264,6 +264,13 @@ NTLMUser::~NTLMUser() debugs(29, 5, "NTLMUser::~NTLMUser: doing nothing to clearNTLM scheme data for '" << this << "'"); } +int32_t +NTLMUser::ttl() const +{ + return -1; // NTLM credentials cannot be cached. +} + + static void authenticateNTLMStats(StoreEntry * sentry) { diff --git a/src/auth/ntlm/auth_ntlm.h b/src/auth/ntlm/auth_ntlm.h index d61eece5e1..0a4e016390 100644 --- a/src/auth/ntlm/auth_ntlm.h +++ b/src/auth/ntlm/auth_ntlm.h @@ -18,9 +18,12 @@ 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; }; diff --git a/src/auth/ntlm/ntlmUserRequest.cc b/src/auth/ntlm/ntlmUserRequest.cc index 0e41ccf7a8..6f0e107fc1 100644 --- a/src/auth/ntlm/ntlmUserRequest.cc +++ b/src/auth/ntlm/ntlmUserRequest.cc @@ -79,15 +79,9 @@ 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(user()); debugs(29, 8, "AuthNTLMUserRequest::module_start: auth state is '" << auth_state << "'"); @@ -168,15 +162,7 @@ AuthNTLMUserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, { 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(local_auth_user); - assert (this); + assert(this); /* Check that we are in the client side, where we can generate * auth challenges */ @@ -265,11 +251,6 @@ AuthNTLMUserRequest::HandleReply(void *data, void *lastserver, char *reply) int valid; char *blob; - AuthUser *auth_user; - NTLMUser *ntlm_user; - AuthUserRequest::Pointer auth_user_request; - AuthNTLMUserRequest *ntlm_request; - debugs(29, 8, "authenticateNTLMHandleReply: helper: '" << lastserver << "' sent us '" << (reply ? reply : "") << "'"); valid = cbdataReferenceValid(r->data); @@ -285,22 +266,18 @@ AuthNTLMUserRequest::HandleReply(void *data, void *lastserver, char *reply) reply = (char *)"BH Internal error"; } - auth_user_request = r->auth_user_request; + AuthUserRequest::Pointer auth_user_request = r->auth_user_request; assert(auth_user_request != NULL); - ntlm_request = dynamic_cast(auth_user_request.getRaw()); + AuthNTLMUserRequest *ntlm_request = dynamic_cast(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); - auth_user = ntlm_request->user(); - assert(auth_user != NULL); - assert(auth_user->auth_type == AUTH_NTLM); - ntlm_user = dynamic_cast(auth_user_request->user()); - - assert(ntlm_user != NULL); - if (ntlm_request->authserver == NULL) ntlm_request->authserver = static_cast(lastserver); else @@ -308,7 +285,6 @@ AuthNTLMUserRequest::HandleReply(void *data, void *lastserver, char *reply) /* seperate out the useful data */ blob = strchr(reply, ' '); - if (blob) blob++; @@ -327,31 +303,29 @@ AuthNTLMUserRequest::HandleReply(void *data, void *lastserver, char *reply) } } else if (strncasecmp(reply, "AF ", 3) == 0) { /* we're finished, release the helper */ - ntlm_user->username(blob); + 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 " << ntlm_user->username()); + 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(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)) + auth_user_hash_pointer *usernamehash = static_cast(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(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 */ diff --git a/src/client_side.h b/src/client_side.h index 6dda0f3cb1..2e68d9cb42 100644 --- a/src/client_side.h +++ b/src/client_side.h @@ -33,6 +33,7 @@ #ifndef SQUID_CLIENTSIDE_H #define SQUID_CLIENTSIDE_H +#include "auth/AuthType.h" #include "auth/UserRequest.h" #include "base/AsyncJob.h" #include "BodyPipe.h" @@ -174,7 +175,7 @@ public: * Is this connection based authentication? if so what type it * is. */ - auth_type_t auth_type; + AuthType auth_type; /** * note this is ONLY connection based because NTLM is against HTTP spec. diff --git a/src/stat.cc b/src/stat.cc index dd909d9caf..1a9562e233 100644 --- a/src/stat.cc +++ b/src/stat.cc @@ -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); diff --git a/src/typedefs.h b/src/typedefs.h index b316c47a42..73034c75e7 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -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" -- 2.39.5