3
* $Id: AuthUser.cc,v 1.9 2007/05/29 13:31:36 amosjeffries Exp $
5
* DEBUG: section 29 Authenticator
6
* AUTHOR: Robert Collins
8
* SQUID Web Proxy Cache http://www.squid-cache.org/
9
* ----------------------------------------------------------
11
* Squid is the result of efforts by numerous individuals from
12
* the Internet community; see the CONTRIBUTORS file for full
13
* details. Many organizations have provided support for Squid's
14
* development; see the SPONSORS file for full details. Squid is
15
* Copyrighted (C) 2001 by the Regents of the University of
16
* California; see the COPYRIGHT file for full details. Squid
17
* incorporates software developed and/or copyrighted by other
18
* sources; see the CREDITS file for full details.
20
* This program is free software; you can redistribute it and/or modify
21
* it under the terms of the GNU General Public License as published by
22
* the Free Software Foundation; either version 2 of the License, or
23
* (at your option) any later version.
25
* This program is distributed in the hope that it will be useful,
26
* but WITHOUT ANY WARRANTY; without even the implied warranty of
27
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
* GNU General Public License for more details.
30
* You should have received a copy of the GNU General Public License
31
* along with this program; if not, write to the Free Software
32
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34
* Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
39
#include "AuthUserRequest.h"
40
#include "AuthConfig.h"
41
#include "authenticate.h"
44
#include "SquidTime.h"
47
#include "AuthUser.cci"
50
// This should be converted into a pooled type. Does not need to be cbdata
51
CBDATA_TYPE(auth_user_ip_t);
53
AuthUser::AuthUser (AuthConfig *aConfig) :
54
auth_type (AUTH_UNKNOWN), config(aConfig),
55
usernamehash (NULL), ipcount (0), expiretime (0), references (0), username_(NULL)
57
proxy_auth_list.head = proxy_auth_list.tail = NULL;
58
proxy_match_cache.head = proxy_match_cache.tail = NULL;
59
ip_list.head = ip_list.tail = NULL;
60
requests.head = requests.tail = NULL;
61
debugs(29, 5, "AuthUser::AuthUser: Initialised auth_user '" << this << "' with refcount '" << references << "'.");
64
/* Combine two user structs. ONLY to be called from within a scheme
65
* module. The scheme module is responsible for ensuring that the
66
* two users _can_ be merged without invalidating all the request
67
* scheme data. The scheme is also responsible for merging any user
68
* related scheme data itself.
71
AuthUser::absorb (AuthUser *from)
73
AuthUserRequest *auth_user_request;
75
* XXX combine two authuser structs. Incomplete: it should merge
76
* in hash references too and ask the module to merge in scheme
79
debugs(29, 5, "authenticateAuthUserMerge auth_user '" << from << "' into auth_user '" << this << "'.");
80
dlink_node *link = from->requests.head;
83
auth_user_request = static_cast<AuthUserRequest *>(link->data);
84
dlink_node *tmplink = link;
86
dlinkDelete(tmplink, &from->requests);
87
dlinkAddTail(auth_user_request, tmplink, &requests);
88
auth_user_request->user(this);
91
references += from->references;
98
AuthUserRequest *auth_user_request;
99
dlink_node *link, *tmplink;
100
debugs(29, 5, "AuthUser::~AuthUser: Freeing auth_user '" << this << "' with refcount '" << references << "'.");
101
assert(references == 0);
102
/* were they linked in by username ? */
105
assert(usernamehash->user() == this);
106
debugs(29, 5, "AuthUser::~AuthUser: removing usernamehash entry '" << usernamehash << "'");
107
hash_remove_link(proxy_auth_username_cache,
108
(hash_link *) usernamehash);
109
/* don't free the key as we use the same user string as the auth_user
114
/* remove any outstanding requests */
115
link = requests.head;
118
debugs(29, 5, "AuthUser::~AuthUser: removing request entry '" << link->data << "'");
119
auth_user_request = static_cast<AuthUserRequest *>(link->data);
122
dlinkDelete(tmplink, &requests);
123
dlinkNodeDelete(tmplink);
124
delete auth_user_request;
127
/* free cached acl results */
128
aclCacheMatchFlush(&proxy_match_cache);
130
/* free seen ip address's */
134
xfree((char*)username_);
136
/* prevent accidental reuse */
137
auth_type = AUTH_UNKNOWN;
141
AuthUser::cacheInit(void)
143
if (!proxy_auth_username_cache) {
144
/* First time around, 7921 should be big enough */
145
proxy_auth_username_cache =
146
hash_create((HASHCMP *) strcmp, 7921, hash_string);
147
assert(proxy_auth_username_cache);
148
eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
153
AuthUser::CachedACLsReset()
156
* We walk the hash by username as that is the unique key we use.
157
* This must complete all at once, because we are ensuring correctness.
159
AuthUserHashPointer *usernamehash;
160
auth_user_t *auth_user;
161
char const *username = NULL;
162
debugs(29, 3, "AuthUser::CachedACLsReset: Flushing the ACL caches for all users.");
163
hash_first(proxy_auth_username_cache);
165
while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
166
auth_user = usernamehash->user();
167
username = auth_user->username();
168
/* free cached acl results */
169
aclCacheMatchFlush(&auth_user->proxy_match_cache);
173
debugs(29, 3, "AuthUser::CachedACLsReset: Finished.");
177
AuthUser::cacheCleanup(void *datanotused)
180
* We walk the hash by username as that is the unique key we use.
181
* For big hashs we could consider stepping through the cache, 100/200
182
* entries at a time. Lets see how it flys first.
184
AuthUserHashPointer *usernamehash;
185
auth_user_t *auth_user;
186
char const *username = NULL;
187
debugs(29, 3, "AuthUser::cacheCleanup: Cleaning the user cache now");
188
debugs(29, 3, "AuthUser::cacheCleanup: Current time: " << current_time.tv_sec);
189
hash_first(proxy_auth_username_cache);
191
while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
192
auth_user = usernamehash->user();
193
username = auth_user->username();
195
/* if we need to have inpedendent expiry clauses, insert a module call
197
debugs(29, 4, "AuthUser::cacheCleanup: Cache entry:\n\tType: " <<
198
auth_user->auth_type << "\n\tUsername: " << username <<
200
(long int) (auth_user->expiretime + Config.authenticateTTL) <<
201
"\n\treferences: " << (long int) auth_user->references);
203
if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
204
debugs(29, 5, "AuthUser::cacheCleanup: Removing user " << username << " from cache due to timeout.");
205
/* the minus 1 accounts for the cache lock */
207
if (!(authenticateAuthUserInuse(auth_user) - 1))
208
/* we don't warn if we leave the user in the cache,
209
* because other modules (ie delay pools) may keep
210
* locks on users, and thats legitimate
216
debugs(29, 3, "AuthUser::cacheCleanup: Finished cleaning the user cache.");
217
eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
223
auth_user_ip_t *ipdata, *tempnode;
225
ipdata = (auth_user_ip_t *) ip_list.head;
228
tempnode = (auth_user_ip_t *) ipdata->node.next;
229
/* walk the ip list */
230
dlinkDelete(&ipdata->node, &ip_list);
232
/* catch incipient underflow */
238
/* integrity check */
239
assert(ipcount == 0);
243
AuthUser::removeIp(struct IN_ADDR ipaddr)
245
auth_user_ip_t *ipdata = (auth_user_ip_t *) ip_list.head;
249
/* walk the ip list */
251
if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
252
/* remove the node */
253
dlinkDelete(&ipdata->node, &ip_list);
255
/* catch incipient underflow */
261
ipdata = (auth_user_ip_t *) ipdata->node.next;
267
AuthUser::addIp(struct IN_ADDR ipaddr)
269
auth_user_ip_t *ipdata = (auth_user_ip_t *) ip_list.head;
273
CBDATA_INIT_TYPE(auth_user_ip_t);
276
* we walk the entire list to prevent the first item in the list
277
* preventing old entries being flushed and locking a user out after
278
* a timeout+reconfigure
282
auth_user_ip_t *tempnode = (auth_user_ip_t *) ipdata->node.next;
283
/* walk the ip list */
285
if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
286
/* This ip has alreadu been seen. */
289
ipdata->ip_expiretime = squid_curtime;
290
} else if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) {
291
/* This IP has expired - remove from the seen list */
292
dlinkDelete(&ipdata->node, &ip_list);
294
/* catch incipient underflow */
305
/* This ip is not in the seen list */
306
ipdata = cbdataAlloc(auth_user_ip_t);
308
ipdata->ip_expiretime = squid_curtime;
310
ipdata->ipaddr = ipaddr;
312
dlinkAddTail(ipdata, &ipdata->node, &ip_list);
316
ip1 = xstrdup(inet_ntoa(ipaddr));
318
debugs(29, 2, "authenticateAuthUserAddIp: user '" << username() << "' has been seen at a new IP address (" << ip1 << ")");
327
debugs(29, 9, "authenticateAuthUserLock auth_user '" << this << "'.");
328
assert(this != NULL);
330
debugs(29, 9, "authenticateAuthUserLock auth_user '" << this << "' now at '" << references << "'.");
336
debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "'.");
337
assert(this != NULL);
339
if (references > 0) {
342
debugs(29, 1, "Attempt to lower Auth User " << this << " refcount below 0!");
345
debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "' now at '" << references << "'.");
351
/* addToNameCache: add a auth_user structure to the username cache */
353
AuthUser::addToNameCache()
355
usernamehash = new AuthUserHashPointer (this);