]> git.ipfire.org Git - thirdparty/squid.git/blame - src/AuthUser.cc
Fixed buffer overflow bug in whois.cc.
[thirdparty/squid.git] / src / AuthUser.cc
CommitLineData
f5691f9c 1
2/*
bf8fe701 3 * $Id: AuthUser.cc,v 1.4 2007/04/28 22:26:37 hno Exp $
f5691f9c 4 *
5 * DEBUG: section 29 Authenticator
6 * AUTHOR: Robert Collins
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
19 *
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.
24 *
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.
29 *
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.
33 *
34 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
35 */
36
37#include "squid.h"
38#include "AuthUser.h"
39#include "AuthUserRequest.h"
40#include "AuthConfig.h"
41#include "authenticate.h"
42#include "ACL.h"
a553a5a3 43#include "event.h"
4c19ba24 44#include "SquidTime.h"
f5691f9c 45
46#ifndef _USE_INLINE_
47#include "AuthUser.cci"
48#endif
49
4c19ba24 50// This should be converted into a pooled type. Does not need to be cbdata
51CBDATA_TYPE(auth_user_ip_t);
52
f5691f9c 53AuthUser::AuthUser (AuthConfig *aConfig) :
54 auth_type (AUTH_UNKNOWN), config(aConfig),
55 usernamehash (NULL), ipcount (0), expiretime (0), references (0), username_(NULL)
56{
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;
bf8fe701 61 debugs(29, 5, "AuthUser::AuthUser: Initialised auth_user '" << this << "' with refcount '" << (long int) references << "'.");
f5691f9c 62}
63
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.
69 */
70void
71AuthUser::absorb (AuthUser *from)
72{
73 auth_user_request_t *auth_user_request;
74 /*
75 * XXX combine two authuser structs. Incomplete: it should merge
76 * in hash references too and ask the module to merge in scheme
77 * data
78 */
bf8fe701 79 debugs(29, 5, "authenticateAuthUserMerge auth_user '" << from << "' into auth_user '" << this << "'.");
f5691f9c 80 dlink_node *link = from->requests.head;
81
82 while (link) {
83 auth_user_request = static_cast<auth_user_request_t *>(link->data);
84 dlink_node *tmplink = link;
85 link = link->next;
86 dlinkDelete(tmplink, &from->requests);
87 dlinkAddTail(auth_user_request, tmplink, &requests);
88 auth_user_request->user(this);
89 }
90
91 references += from->references;
92 from->references = 0;
93 delete from;
94}
95
96AuthUser::~AuthUser()
97{
98 auth_user_request_t *auth_user_request;
99 dlink_node *link, *tmplink;
bf8fe701 100 debugs(29, 5, "AuthUser::~AuthUser: Freeing auth_user '" << this << "' with refcount '" << (long int) references << "'.");
f5691f9c 101 assert(references == 0);
102 /* were they linked in by username ? */
103
104 if (usernamehash) {
105 assert(usernamehash->user() == this);
bf8fe701 106 debugs(29, 5, "AuthUser::~AuthUser: removing usernamehash entry '" << usernamehash << "'");
f5691f9c 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
110 * structure */
111 delete usernamehash;
112 }
113
114 /* remove any outstanding requests */
115 link = requests.head;
116
117 while (link) {
bf8fe701 118 debugs(29, 5, "AuthUser::~AuthUser: removing request entry '" << link->data << "'");
f5691f9c 119 auth_user_request = static_cast<auth_user_request_t *>(link->data);
120 tmplink = link;
121 link = link->next;
122 dlinkDelete(tmplink, &requests);
123 dlinkNodeDelete(tmplink);
124 delete auth_user_request;
125 }
126
127 /* free cached acl results */
128 aclCacheMatchFlush(&proxy_match_cache);
129
130 /* free seen ip address's */
131 clearIp();
132
133 if (username())
134 xfree((char *)username());
135
136 /* prevent accidental reuse */
137 auth_type = AUTH_UNKNOWN;
138}
139
140void
141AuthUser::cacheInit(void)
142{
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);
149 }
150}
151
152void
153AuthUser::CachedACLsReset()
154{
155 /*
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.
158 */
159 AuthUserHashPointer *usernamehash;
160 auth_user_t *auth_user;
161 char const *username = NULL;
bf8fe701 162 debugs(29, 3, "AuthUser::CachedACLsReset: Flushing the ACL caches for all users.");
f5691f9c 163 hash_first(proxy_auth_username_cache);
164
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);
170
171 }
172
bf8fe701 173 debugs(29, 3, "AuthUser::CachedACLsReset: Finished.");
f5691f9c 174}
175
176void
177AuthUser::cacheCleanup(void *datanotused)
178{
179 /*
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.
183 */
184 AuthUserHashPointer *usernamehash;
185 auth_user_t *auth_user;
186 char const *username = NULL;
bf8fe701 187 debugs(29, 3, "AuthUser::cacheCleanup: Cleaning the user cache now");
188 debugs(29, 3, "AuthUser::cacheCleanup: Current time: " << (long int) current_time.tv_sec);
f5691f9c 189 hash_first(proxy_auth_username_cache);
190
191 while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
192 auth_user = usernamehash->user();
193 username = auth_user->username();
194
195 /* if we need to have inpedendent expiry clauses, insert a module call
196 * here */
bf8fe701 197 debugs(29, 4, "AuthUser::cacheCleanup: Cache entry:\n\tType: " <<
198 auth_user->auth_type << "\n\tUsername: " << username <<
199 "\n\texpires: " <<
200 (long int) (auth_user->expiretime + Config.authenticateTTL) <<
201 "\n\treferences: " << (long int) auth_user->references);
f5691f9c 202
203 if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
bf8fe701 204 debugs(29, 5, "AuthUser::cacheCleanup: Removing user " << username << " from cache due to timeout.");
f5691f9c 205 /* the minus 1 accounts for the cache lock */
206
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
211 */
212 auth_user->unlock();
213 }
214 }
215
bf8fe701 216 debugs(29, 3, "AuthUser::cacheCleanup: Finished cleaning the user cache.");
f5691f9c 217 eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
218}
219
220void
221AuthUser::clearIp()
222{
223 auth_user_ip_t *ipdata, *tempnode;
224
225 ipdata = (auth_user_ip_t *) ip_list.head;
226
227 while (ipdata) {
228 tempnode = (auth_user_ip_t *) ipdata->node.next;
229 /* walk the ip list */
230 dlinkDelete(&ipdata->node, &ip_list);
231 cbdataFree(ipdata);
232 /* catch incipient underflow */
233 assert(ipcount);
234 ipcount--;
235 ipdata = tempnode;
236 }
237
238 /* integrity check */
239 assert(ipcount == 0);
240}
241
242void
4c19ba24 243AuthUser::removeIp(struct IN_ADDR ipaddr)
244{
245 auth_user_ip_t *ipdata = (auth_user_ip_t *) ip_list.head;
246
247 while (ipdata)
248 {
249 /* walk the ip list */
250
251 if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
252 /* remove the node */
253 dlinkDelete(&ipdata->node, &ip_list);
254 cbdataFree(ipdata);
255 /* catch incipient underflow */
256 assert(ipcount);
257 ipcount--;
258 return;
259 }
260
261 ipdata = (auth_user_ip_t *) ipdata->node.next;
262 }
263
264}
265
266void
267AuthUser::addIp(struct IN_ADDR ipaddr)
268{
269 auth_user_ip_t *ipdata = (auth_user_ip_t *) ip_list.head;
270 char *ip1;
271 int found = 0;
272
273 CBDATA_INIT_TYPE(auth_user_ip_t);
274
275 /*
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
279 */
280 while (ipdata)
281 {
282 auth_user_ip_t *tempnode = (auth_user_ip_t *) ipdata->node.next;
283 /* walk the ip list */
f5691f9c 284
4c19ba24 285 if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
286 /* This ip has alreadu been seen. */
287 found = 1;
288 /* update IP ttl */
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);
293 cbdataFree(ipdata);
294 /* catch incipient underflow */
295 assert(ipcount);
296 ipcount--;
297 }
298
299 ipdata = tempnode;
300 }
301
302 if (found)
303 return;
304
305 /* This ip is not in the seen list */
306 ipdata = cbdataAlloc(auth_user_ip_t);
307
308 ipdata->ip_expiretime = squid_curtime;
309
310 ipdata->ipaddr = ipaddr;
311
312 dlinkAddTail(ipdata, &ipdata->node, &ip_list);
313
314 ipcount++;
315
316 ip1 = xstrdup(inet_ntoa(ipaddr));
317
bf8fe701 318 debugs(29, 2, "authenticateAuthUserAddIp: user '" << username() << "' has been seen at a new IP address (" << ip1 << ")");
4c19ba24 319
320 safe_free(ip1);
321}
322
323
324void
f5691f9c 325AuthUser::lock()
326{
bf8fe701 327 debugs(29, 9, "authenticateAuthUserLock auth_user '" << this << "'.");
f5691f9c 328 assert(this != NULL);
329 references++;
bf8fe701 330 debugs(29, 9, "authenticateAuthUserLock auth_user '" << this << "' now at '" << (long int) references << "'.");
f5691f9c 331}
332
333void
334AuthUser::unlock()
335{
bf8fe701 336 debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "'.");
f5691f9c 337 assert(this != NULL);
338
339 if (references > 0) {
340 references--;
341 } else {
bf8fe701 342 debugs(29, 1, "Attempt to lower Auth User " << this << " refcount below 0!");
f5691f9c 343 }
344
bf8fe701 345 debugs(29, 9, "authenticateAuthUserUnlock auth_user '" << this << "' now at '" << (long int) references << "'.");
f5691f9c 346
347 if (references == 0)
348 delete this;
349}
350
351/* addToNameCache: add a auth_user structure to the username cache */
352void
353AuthUser::addToNameCache()
354{
355 usernamehash = new AuthUserHashPointer (this);
356}