]> git.ipfire.org Git - thirdparty/squid.git/blame - src/AuthUser.cc
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / src / AuthUser.cc
CommitLineData
f5691f9c 1/*
262a0e14 2 * $Id$
f5691f9c 3 *
4 * DEBUG: section 29 Authenticator
5 * AUTHOR: Robert Collins
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
26ac0430 23 *
f5691f9c 24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
26ac0430 28 *
f5691f9c 29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
34 */
35
36#include "squid.h"
37#include "AuthUser.h"
38#include "AuthUserRequest.h"
39#include "AuthConfig.h"
40#include "authenticate.h"
41#include "ACL.h"
a553a5a3 42#include "event.h"
4c19ba24 43#include "SquidTime.h"
f5691f9c 44
45#ifndef _USE_INLINE_
46#include "AuthUser.cci"
47#endif
48
4c19ba24 49// This should be converted into a pooled type. Does not need to be cbdata
50CBDATA_TYPE(auth_user_ip_t);
51
f5691f9c 52AuthUser::AuthUser (AuthConfig *aConfig) :
53 auth_type (AUTH_UNKNOWN), config(aConfig),
54 usernamehash (NULL), ipcount (0), expiretime (0), references (0), username_(NULL)
55{
56 proxy_auth_list.head = proxy_auth_list.tail = NULL;
57 proxy_match_cache.head = proxy_match_cache.tail = NULL;
58 ip_list.head = ip_list.tail = NULL;
59 requests.head = requests.tail = NULL;
4a7a3d56 60 debugs(29, 5, "AuthUser::AuthUser: Initialised auth_user '" << this << "' with refcount '" << references << "'.");
f5691f9c 61}
62
63/* Combine two user structs. ONLY to be called from within a scheme
64 * module. The scheme module is responsible for ensuring that the
65 * two users _can_ be merged without invalidating all the request
66 * scheme data. The scheme is also responsible for merging any user
67 * related scheme data itself.
68 */
69void
70AuthUser::absorb (AuthUser *from)
71{
76f142cd 72 AuthUserRequest *auth_user_request;
f5691f9c 73 /*
74 * XXX combine two authuser structs. Incomplete: it should merge
75 * in hash references too and ask the module to merge in scheme
76 * data
77 */
bf8fe701 78 debugs(29, 5, "authenticateAuthUserMerge auth_user '" << from << "' into auth_user '" << this << "'.");
f5691f9c 79 dlink_node *link = from->requests.head;
80
81 while (link) {
76f142cd 82 auth_user_request = static_cast<AuthUserRequest *>(link->data);
f5691f9c 83 dlink_node *tmplink = link;
84 link = link->next;
85 dlinkDelete(tmplink, &from->requests);
86 dlinkAddTail(auth_user_request, tmplink, &requests);
87 auth_user_request->user(this);
88 }
89
90 references += from->references;
91 from->references = 0;
92 delete from;
93}
94
95AuthUser::~AuthUser()
96{
76f142cd 97 AuthUserRequest *auth_user_request;
f5691f9c 98 dlink_node *link, *tmplink;
4a7a3d56 99 debugs(29, 5, "AuthUser::~AuthUser: Freeing auth_user '" << this << "' with refcount '" << references << "'.");
f5691f9c 100 assert(references == 0);
101 /* were they linked in by username ? */
102
103 if (usernamehash) {
104 assert(usernamehash->user() == this);
bf8fe701 105 debugs(29, 5, "AuthUser::~AuthUser: removing usernamehash entry '" << usernamehash << "'");
f5691f9c 106 hash_remove_link(proxy_auth_username_cache,
107 (hash_link *) usernamehash);
108 /* don't free the key as we use the same user string as the auth_user
109 * structure */
110 delete usernamehash;
111 }
112
113 /* remove any outstanding requests */
114 link = requests.head;
115
116 while (link) {
bf8fe701 117 debugs(29, 5, "AuthUser::~AuthUser: removing request entry '" << link->data << "'");
76f142cd 118 auth_user_request = static_cast<AuthUserRequest *>(link->data);
f5691f9c 119 tmplink = link;
120 link = link->next;
121 dlinkDelete(tmplink, &requests);
122 dlinkNodeDelete(tmplink);
123 delete auth_user_request;
124 }
125
126 /* free cached acl results */
127 aclCacheMatchFlush(&proxy_match_cache);
128
129 /* free seen ip address's */
130 clearIp();
131
3f5f1a01 132 if (username_)
133 xfree((char*)username_);
f5691f9c 134
135 /* prevent accidental reuse */
136 auth_type = AUTH_UNKNOWN;
137}
138
139void
140AuthUser::cacheInit(void)
141{
142 if (!proxy_auth_username_cache) {
143 /* First time around, 7921 should be big enough */
144 proxy_auth_username_cache =
30abd221 145 hash_create((HASHCMP *) strcmp, 7921, hash_string);
f5691f9c 146 assert(proxy_auth_username_cache);
147 eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
148 }
149}
150
151void
152AuthUser::CachedACLsReset()
153{
154 /*
155 * We walk the hash by username as that is the unique key we use.
156 * This must complete all at once, because we are ensuring correctness.
157 */
158 AuthUserHashPointer *usernamehash;
e1f7507e 159 AuthUser *auth_user;
f5691f9c 160 char const *username = NULL;
bf8fe701 161 debugs(29, 3, "AuthUser::CachedACLsReset: Flushing the ACL caches for all users.");
f5691f9c 162 hash_first(proxy_auth_username_cache);
163
164 while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
165 auth_user = usernamehash->user();
166 username = auth_user->username();
167 /* free cached acl results */
168 aclCacheMatchFlush(&auth_user->proxy_match_cache);
169
170 }
171
bf8fe701 172 debugs(29, 3, "AuthUser::CachedACLsReset: Finished.");
f5691f9c 173}
174
175void
176AuthUser::cacheCleanup(void *datanotused)
177{
178 /*
179 * We walk the hash by username as that is the unique key we use.
180 * For big hashs we could consider stepping through the cache, 100/200
181 * entries at a time. Lets see how it flys first.
182 */
183 AuthUserHashPointer *usernamehash;
e1f7507e 184 AuthUser *auth_user;
f5691f9c 185 char const *username = NULL;
bf8fe701 186 debugs(29, 3, "AuthUser::cacheCleanup: Cleaning the user cache now");
4a7a3d56 187 debugs(29, 3, "AuthUser::cacheCleanup: Current time: " << current_time.tv_sec);
f5691f9c 188 hash_first(proxy_auth_username_cache);
189
190 while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
191 auth_user = usernamehash->user();
192 username = auth_user->username();
193
194 /* if we need to have inpedendent expiry clauses, insert a module call
195 * here */
bf8fe701 196 debugs(29, 4, "AuthUser::cacheCleanup: Cache entry:\n\tType: " <<
197 auth_user->auth_type << "\n\tUsername: " << username <<
198 "\n\texpires: " <<
199 (long int) (auth_user->expiretime + Config.authenticateTTL) <<
200 "\n\treferences: " << (long int) auth_user->references);
f5691f9c 201
202 if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
bf8fe701 203 debugs(29, 5, "AuthUser::cacheCleanup: Removing user " << username << " from cache due to timeout.");
f5691f9c 204 /* the minus 1 accounts for the cache lock */
205
206 if (!(authenticateAuthUserInuse(auth_user) - 1))
207 /* we don't warn if we leave the user in the cache,
208 * because other modules (ie delay pools) may keep
209 * locks on users, and thats legitimate
210 */
211 auth_user->unlock();
212 }
213 }
214
bf8fe701 215 debugs(29, 3, "AuthUser::cacheCleanup: Finished cleaning the user cache.");
f5691f9c 216 eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
217}
218
219void
220AuthUser::clearIp()
221{
222 auth_user_ip_t *ipdata, *tempnode;
223
224 ipdata = (auth_user_ip_t *) ip_list.head;
225
226 while (ipdata) {
227 tempnode = (auth_user_ip_t *) ipdata->node.next;
228 /* walk the ip list */
229 dlinkDelete(&ipdata->node, &ip_list);
230 cbdataFree(ipdata);
231 /* catch incipient underflow */
232 assert(ipcount);
233 ipcount--;
234 ipdata = tempnode;
235 }
236
237 /* integrity check */
238 assert(ipcount == 0);
239}
240
241void
ad61a2b4 242AuthUser::removeIp(IpAddress ipaddr)
4c19ba24 243{
244 auth_user_ip_t *ipdata = (auth_user_ip_t *) ip_list.head;
245
26ac0430 246 while (ipdata) {
4c19ba24 247 /* walk the ip list */
248
cc192b50 249 if (ipdata->ipaddr == ipaddr) {
4c19ba24 250 /* remove the node */
251 dlinkDelete(&ipdata->node, &ip_list);
252 cbdataFree(ipdata);
253 /* catch incipient underflow */
254 assert(ipcount);
255 ipcount--;
256 return;
257 }
258
259 ipdata = (auth_user_ip_t *) ipdata->node.next;
260 }
261
262}
263
264void
ad61a2b4 265AuthUser::addIp(IpAddress ipaddr)
4c19ba24 266{
267 auth_user_ip_t *ipdata = (auth_user_ip_t *) ip_list.head;
4c19ba24 268 int found = 0;
269
270 CBDATA_INIT_TYPE(auth_user_ip_t);
271
272 /*
273 * we walk the entire list to prevent the first item in the list
274 * preventing old entries being flushed and locking a user out after
275 * a timeout+reconfigure
276 */
26ac0430 277 while (ipdata) {
4c19ba24 278 auth_user_ip_t *tempnode = (auth_user_ip_t *) ipdata->node.next;
279 /* walk the ip list */
f5691f9c 280
cc192b50 281 if (ipdata->ipaddr == ipaddr) {
282 /* This ip has already been seen. */
4c19ba24 283 found = 1;
284 /* update IP ttl */
285 ipdata->ip_expiretime = squid_curtime;
286 } else if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) {
287 /* This IP has expired - remove from the seen list */
288 dlinkDelete(&ipdata->node, &ip_list);
289 cbdataFree(ipdata);
290 /* catch incipient underflow */
291 assert(ipcount);
292 ipcount--;
293 }
294
295 ipdata = tempnode;
296 }
297
298 if (found)
299 return;
300
301 /* This ip is not in the seen list */
302 ipdata = cbdataAlloc(auth_user_ip_t);
303
304 ipdata->ip_expiretime = squid_curtime;
305
306 ipdata->ipaddr = ipaddr;
307
308 dlinkAddTail(ipdata, &ipdata->node, &ip_list);
309
310 ipcount++;
311
cc192b50 312 debugs(29, 2, "authenticateAuthUserAddIp: user '" << username() << "' has been seen at a new IP address (" << ipaddr << ")");
4c19ba24 313}
314
315
316void
f5691f9c 317AuthUser::lock()
318{
bf8fe701 319 debugs(29, 9, "authenticateAuthUserLock auth_user '" << this << "'.");
f5691f9c 320 assert(this != NULL);
321 references++;
4a7a3d56 322 debugs(29, 9, "authenticateAuthUserLock auth_user '" << this << "' now at '" << references << "'.");
f5691f9c 323}
324
325void
326AuthUser::unlock()
327{
bf8fe701 328 debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "'.");
f5691f9c 329 assert(this != NULL);
330
331 if (references > 0) {
332 references--;
333 } else {
bf8fe701 334 debugs(29, 1, "Attempt to lower Auth User " << this << " refcount below 0!");
f5691f9c 335 }
336
4a7a3d56 337 debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "' now at '" << references << "'.");
f5691f9c 338
339 if (references == 0)
340 delete this;
341}
342
343/* addToNameCache: add a auth_user structure to the username cache */
344void
345AuthUser::addToNameCache()
346{
347 usernamehash = new AuthUserHashPointer (this);
348}