]> git.ipfire.org Git - thirdparty/squid.git/blame - src/AuthUser.cc
Bug #1792: max_user_ip not working with ntlm_auth
[thirdparty/squid.git] / src / AuthUser.cc
CommitLineData
f5691f9c 1
2/*
a553a5a3 3 * $Id: AuthUser.cc,v 1.2 2006/08/07 02:28:22 robertc 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"
f5691f9c 44
45#ifndef _USE_INLINE_
46#include "AuthUser.cci"
47#endif
48
49AuthUser::AuthUser (AuthConfig *aConfig) :
50 auth_type (AUTH_UNKNOWN), config(aConfig),
51 usernamehash (NULL), ipcount (0), expiretime (0), references (0), username_(NULL)
52{
53 proxy_auth_list.head = proxy_auth_list.tail = NULL;
54 proxy_match_cache.head = proxy_match_cache.tail = NULL;
55 ip_list.head = ip_list.tail = NULL;
56 requests.head = requests.tail = NULL;
57 debug(29, 5) ("AuthUser::AuthUser: Initialised auth_user '%p' with refcount '%ld'.\n", this, (long int) references);
58}
59
60/* Combine two user structs. ONLY to be called from within a scheme
61 * module. The scheme module is responsible for ensuring that the
62 * two users _can_ be merged without invalidating all the request
63 * scheme data. The scheme is also responsible for merging any user
64 * related scheme data itself.
65 */
66void
67AuthUser::absorb (AuthUser *from)
68{
69 auth_user_request_t *auth_user_request;
70 /*
71 * XXX combine two authuser structs. Incomplete: it should merge
72 * in hash references too and ask the module to merge in scheme
73 * data
74 */
75 debug(29, 5) ("authenticateAuthUserMerge auth_user '%p' into auth_user '%p'.\n", from, this);
76 dlink_node *link = from->requests.head;
77
78 while (link) {
79 auth_user_request = static_cast<auth_user_request_t *>(link->data);
80 dlink_node *tmplink = link;
81 link = link->next;
82 dlinkDelete(tmplink, &from->requests);
83 dlinkAddTail(auth_user_request, tmplink, &requests);
84 auth_user_request->user(this);
85 }
86
87 references += from->references;
88 from->references = 0;
89 delete from;
90}
91
92AuthUser::~AuthUser()
93{
94 auth_user_request_t *auth_user_request;
95 dlink_node *link, *tmplink;
96 debug(29, 5) ("AuthUser::~AuthUser: Freeing auth_user '%p' with refcount '%ld'.\n", this, (long int) references);
97 assert(references == 0);
98 /* were they linked in by username ? */
99
100 if (usernamehash) {
101 assert(usernamehash->user() == this);
102 debug(29, 5) ("AuthUser::~AuthUser: removing usernamehash entry '%p'\n", usernamehash);
103 hash_remove_link(proxy_auth_username_cache,
104 (hash_link *) usernamehash);
105 /* don't free the key as we use the same user string as the auth_user
106 * structure */
107 delete usernamehash;
108 }
109
110 /* remove any outstanding requests */
111 link = requests.head;
112
113 while (link) {
114 debug(29, 5) ("AuthUser::~AuthUser: removing request entry '%p'\n", link->data);
115 auth_user_request = static_cast<auth_user_request_t *>(link->data);
116 tmplink = link;
117 link = link->next;
118 dlinkDelete(tmplink, &requests);
119 dlinkNodeDelete(tmplink);
120 delete auth_user_request;
121 }
122
123 /* free cached acl results */
124 aclCacheMatchFlush(&proxy_match_cache);
125
126 /* free seen ip address's */
127 clearIp();
128
129 if (username())
130 xfree((char *)username());
131
132 /* prevent accidental reuse */
133 auth_type = AUTH_UNKNOWN;
134}
135
136void
137AuthUser::cacheInit(void)
138{
139 if (!proxy_auth_username_cache) {
140 /* First time around, 7921 should be big enough */
141 proxy_auth_username_cache =
142 hash_create((HASHCMP *) strcmp, 7921, hash_string);
143 assert(proxy_auth_username_cache);
144 eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
145 }
146}
147
148void
149AuthUser::CachedACLsReset()
150{
151 /*
152 * We walk the hash by username as that is the unique key we use.
153 * This must complete all at once, because we are ensuring correctness.
154 */
155 AuthUserHashPointer *usernamehash;
156 auth_user_t *auth_user;
157 char const *username = NULL;
158 debug(29, 3) ("AuthUser::CachedACLsReset: Flushing the ACL caches for all users.\n");
159 hash_first(proxy_auth_username_cache);
160
161 while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
162 auth_user = usernamehash->user();
163 username = auth_user->username();
164 /* free cached acl results */
165 aclCacheMatchFlush(&auth_user->proxy_match_cache);
166
167 }
168
169 debug(29, 3) ("AuthUser::CachedACLsReset: Finished.\n");
170}
171
172void
173AuthUser::cacheCleanup(void *datanotused)
174{
175 /*
176 * We walk the hash by username as that is the unique key we use.
177 * For big hashs we could consider stepping through the cache, 100/200
178 * entries at a time. Lets see how it flys first.
179 */
180 AuthUserHashPointer *usernamehash;
181 auth_user_t *auth_user;
182 char const *username = NULL;
183 debug(29, 3) ("AuthUser::cacheCleanup: Cleaning the user cache now\n");
184 debug(29, 3) ("AuthUser::cacheCleanup: Current time: %ld\n", (long int) current_time.tv_sec);
185 hash_first(proxy_auth_username_cache);
186
187 while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) {
188 auth_user = usernamehash->user();
189 username = auth_user->username();
190
191 /* if we need to have inpedendent expiry clauses, insert a module call
192 * here */
193 debug(29, 4) ("AuthUser::cacheCleanup: Cache entry:\n\tType: %d\n\tUsername: %s\n\texpires: %ld\n\treferences: %ld\n", auth_user->auth_type, username, (long int) (auth_user->expiretime + Config.authenticateTTL), (long int) auth_user->references);
194
195 if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
196 debug(29, 5) ("AuthUser::cacheCleanup: Removing user %s from cache due to timeout.\n", username);
197 /* the minus 1 accounts for the cache lock */
198
199 if (!(authenticateAuthUserInuse(auth_user) - 1))
200 /* we don't warn if we leave the user in the cache,
201 * because other modules (ie delay pools) may keep
202 * locks on users, and thats legitimate
203 */
204 auth_user->unlock();
205 }
206 }
207
208 debug(29, 3) ("AuthUser::cacheCleanup: Finished cleaning the user cache.\n");
209 eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1);
210}
211
212void
213AuthUser::clearIp()
214{
215 auth_user_ip_t *ipdata, *tempnode;
216
217 ipdata = (auth_user_ip_t *) ip_list.head;
218
219 while (ipdata) {
220 tempnode = (auth_user_ip_t *) ipdata->node.next;
221 /* walk the ip list */
222 dlinkDelete(&ipdata->node, &ip_list);
223 cbdataFree(ipdata);
224 /* catch incipient underflow */
225 assert(ipcount);
226 ipcount--;
227 ipdata = tempnode;
228 }
229
230 /* integrity check */
231 assert(ipcount == 0);
232}
233
234void
235
236AuthUser::lock()
237{
238 debug(29, 9) ("authenticateAuthUserLock auth_user '%p'.\n", this);
239 assert(this != NULL);
240 references++;
241 debug(29, 9) ("authenticateAuthUserLock auth_user '%p' now at '%ld'.\n", this, (long int) references);
242}
243
244void
245AuthUser::unlock()
246{
247 debug(29, 9) ("authenticateAuthUserUnlock auth_user '%p'.\n", this);
248 assert(this != NULL);
249
250 if (references > 0) {
251 references--;
252 } else {
253 debug(29, 1) ("Attempt to lower Auth User %p refcount below 0!\n", this);
254 }
255
256 debug(29, 9) ("authenticateAuthUserUnlock auth_user '%p' now at '%ld'.\n", this, (long int) references);
257
258 if (references == 0)
259 delete this;
260}
261
262/* addToNameCache: add a auth_user structure to the username cache */
263void
264AuthUser::addToNameCache()
265{
266 usernamehash = new AuthUserHashPointer (this);
267}