]>
Commit | Line | Data |
---|---|---|
1d620765 | 1 | |
2 | /* | |
2f44bd34 | 3 | * $Id: authenticate.cc,v 1.51 2003/02/06 09:57:36 robertc Exp $ |
1d620765 | 4 | * |
5 | * DEBUG: section 29 Authenticator | |
e6ccf245 | 6 | * AUTHOR: Robert Collins |
1d620765 | 7 | * |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
1d620765 | 9 | * ---------------------------------------------------------- |
10 | * | |
2b6662ba | 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. | |
1d620765 | 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 | */ | |
35 | ||
94439e4e | 36 | /* The functions in this file handle authentication. |
37 | * They DO NOT perform access control or auditing. | |
38 | * See acl.c for access control and client_side.c for auditing */ | |
1d620765 | 39 | |
94439e4e | 40 | #include "squid.h" |
e6ccf245 | 41 | #include "authenticate.h" |
1d620765 | 42 | |
60d096f4 | 43 | CBDATA_TYPE(auth_user_ip_t); |
44 | ||
94439e4e | 45 | /* |
46 | * | |
47 | * Private Data | |
48 | * | |
49 | */ | |
50 | ||
e6ccf245 | 51 | MemPool *AuthUserRequest::pool = NULL; |
52 | MemPool *AuthUserHashPointer::pool = NULL; | |
53 | MemPool *AuthUser::pool = NULL; | |
54 | /* | |
55 | * memDataInit(MEM_AUTH_USER_T, "auth_user_t", | |
56 | * sizeof(auth_user_t), 0); | |
57 | */ | |
94439e4e | 58 | |
59 | /* Generic Functions */ | |
60 | ||
61 | ||
2d72d4fd | 62 | static int |
94439e4e | 63 | authenticateAuthSchemeConfigured(const char *proxy_auth) |
1d620765 | 64 | { |
94439e4e | 65 | authScheme *scheme; |
66 | int i; | |
e6ccf245 | 67 | for (i = 0; i < Config.authConfiguration.n_configured; i++) { |
68 | scheme = Config.authConfiguration.schemes + i; | |
2d70df72 | 69 | if ((strncasecmp(proxy_auth, scheme->typestr, strlen(scheme->typestr)) == 0) && |
70 | (authscheme_list[scheme->Id].Active())) | |
94439e4e | 71 | return 1; |
c68e9c6b | 72 | } |
94439e4e | 73 | return 0; |
1d620765 | 74 | } |
75 | ||
94439e4e | 76 | int |
77 | authenticateAuthSchemeId(const char *typestr) | |
1d620765 | 78 | { |
94439e4e | 79 | int i = 0; |
80 | for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) { | |
81 | if (strncasecmp(typestr, authscheme_list[i].typestr, strlen(authscheme_list[i].typestr)) == 0) { | |
82 | return i; | |
83 | } | |
84 | } | |
85 | return -1; | |
1d620765 | 86 | } |
87 | ||
94439e4e | 88 | void |
e6ccf245 | 89 | AuthUserRequest::decodeAuth(const char *proxy_auth) |
1d620765 | 90 | { |
94439e4e | 91 | int i = 0; |
92 | assert(proxy_auth != NULL); | |
94439e4e | 93 | debug(29, 9) ("authenticateDecodeAuth: header = '%s'\n", proxy_auth); |
e6ccf245 | 94 | if (!authenticateAuthSchemeConfigured(proxy_auth) || |
95 | (i = authenticateAuthSchemeId(proxy_auth)) == -1) { | |
96 | debug(29, 1) ("AuthUserRequest::decodeAuth: Unsupported or unconfigured proxy-auth scheme, '%s'\n", proxy_auth); | |
97 | return; | |
94439e4e | 98 | } |
e6ccf245 | 99 | assert (i >= 0); |
100 | authscheme_list[i].decodeauth(this, proxy_auth); | |
101 | auth_user->auth_module = i + 1; | |
102 | } | |
103 | ||
104 | size_t | |
105 | AuthUserRequest::refCount () const | |
106 | { | |
107 | return references; | |
108 | } | |
109 | ||
110 | char const * | |
111 | AuthUserRequest::username() const | |
112 | { | |
113 | if (auth_user) | |
114 | return auth_user->username(); | |
115 | else | |
116 | return NULL; | |
117 | } | |
118 | ||
119 | size_t | |
120 | authenticateRequestRefCount (auth_user_request_t *aRequest) | |
121 | { | |
122 | return aRequest->refCount(); | |
1d620765 | 123 | } |
124 | ||
94439e4e | 125 | /* clear any connection related authentication details */ |
126 | void | |
127 | authenticateOnCloseConnection(ConnStateData * conn) | |
128 | { | |
129 | auth_user_request_t *auth_user_request; | |
130 | assert(conn != NULL); | |
131 | if (conn->auth_user_request != NULL) { | |
132 | auth_user_request = conn->auth_user_request; | |
5d146f7d | 133 | /* if the auth type gets reset, the connection shouldn't |
134 | * remain linked to it - the next type might not be conn based | |
135 | */ | |
136 | assert(auth_user_request->auth_user->auth_module); | |
94439e4e | 137 | if (authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection) { |
138 | authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection(conn); | |
139 | } | |
140 | } | |
141 | } | |
1d620765 | 142 | |
94439e4e | 143 | /**** PUBLIC FUNCTIONS (ALL GENERIC!) ****/ |
1d620765 | 144 | |
94439e4e | 145 | /* send the initial data to an authenticator module */ |
1d620765 | 146 | void |
e6ccf245 | 147 | AuthUserRequest::start(RH * handler, void *data) |
1d620765 | 148 | { |
74addf6c | 149 | assert(handler); |
e6ccf245 | 150 | debug(29, 9) ("authenticateStart: auth_user_request '%p'\n", this); |
151 | if (auth_user->auth_module > 0) | |
152 | authscheme_list[auth_user->auth_module - 1].authStart(this, handler, data); | |
94439e4e | 153 | else |
1d620765 | 154 | handler(data, NULL); |
94439e4e | 155 | } |
156 | ||
e6ccf245 | 157 | void |
158 | authenticateStart(auth_user_request_t * auth_user_request, RH * handler, void *data) | |
159 | { | |
160 | assert(auth_user_request); | |
161 | auth_user_request->start (handler, data); | |
162 | } | |
163 | ||
94439e4e | 164 | /* |
165 | * Check a auth_user pointer for validity. Does not check passwords, just data | |
166 | * sensability. Broken or Unknown auth_types are not valid for use... | |
167 | */ | |
168 | ||
169 | int | |
170 | authenticateValidateUser(auth_user_request_t * auth_user_request) | |
171 | { | |
5dae8514 | 172 | debug(29, 9) ("authenticateValidateUser: Validating Auth_user request '%p'.\n", auth_user_request); |
94439e4e | 173 | if (auth_user_request == NULL) { |
174 | debug(29, 4) ("authenticateValidateUser: Auth_user_request was NULL!\n"); | |
175 | return 0; | |
1d620765 | 176 | } |
94439e4e | 177 | if (auth_user_request->auth_user == NULL) { |
178 | debug(29, 4) ("authenticateValidateUser: No associated auth_user structure\n"); | |
179 | return 0; | |
180 | } | |
181 | if (auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) { | |
5dae8514 | 182 | debug(29, 4) ("authenticateValidateUser: Auth_user '%p' uses unknown scheme.\n", auth_user_request->auth_user); |
94439e4e | 183 | return 0; |
184 | } | |
185 | if (auth_user_request->auth_user->auth_type == AUTH_BROKEN) { | |
5dae8514 | 186 | debug(29, 4) ("authenticateValidateUser: Auth_user '%p' is broken for it's scheme.\n", auth_user_request->auth_user); |
94439e4e | 187 | return 0; |
188 | } | |
721b0310 | 189 | if (!auth_user_request->auth_user->scheme_data) { |
190 | debug(29, 4) ("authenticateValidateUser: auth_user '%p' has no scheme data\n", auth_user_request->auth_user); | |
191 | return 0; | |
192 | } | |
94439e4e | 193 | /* any other sanity checks that we need in the future */ |
194 | ||
195 | /* Thus should a module call to something like authValidate */ | |
196 | ||
197 | /* finally return ok */ | |
721b0310 | 198 | debug(29, 5) ("authenticateValidateUser: Validated Auth_user request '%p'.\n", auth_user_request); |
94439e4e | 199 | return 1; |
200 | ||
201 | } | |
202 | ||
e6ccf245 | 203 | void * |
768cb287 | 204 | AuthUser::operator new (size_t byteCount) |
e6ccf245 | 205 | { |
206 | /* derived classes with different sizes must implement their own new */ | |
207 | assert (byteCount == sizeof (AuthUser)); | |
208 | if (!pool) | |
209 | pool = memPoolCreate("Authenticate User Data", sizeof (auth_user_t)); | |
d3b3ab85 | 210 | return memPoolAlloc(pool); |
e6ccf245 | 211 | } |
212 | ||
213 | AuthUser::AuthUser (const char *scheme) : | |
214 | auth_type (AUTH_UNKNOWN), auth_module (authenticateAuthSchemeId(scheme) + 1), | |
215 | usernamehash (NULL), ipcount (0), expiretime (0), references (0), scheme_data (NULL) | |
216 | { | |
217 | proxy_auth_list.head = proxy_auth_list.tail = NULL; | |
218 | proxy_match_cache.head = proxy_match_cache.tail = NULL; | |
219 | ip_list.head = ip_list.tail = NULL; | |
220 | requests.head = requests.tail = NULL; | |
221 | } | |
222 | ||
223 | char const * | |
224 | AuthUser::username () const | |
225 | { | |
226 | if (auth_module <= 0) | |
227 | return NULL; | |
228 | return authscheme_list[auth_module - 1].authUserUsername(this); | |
229 | } | |
230 | ||
94439e4e | 231 | auth_user_t * |
232 | authenticateAuthUserNew(const char *scheme) | |
233 | { | |
e6ccf245 | 234 | return new AuthUser (scheme); |
94439e4e | 235 | } |
236 | ||
e6ccf245 | 237 | void * |
768cb287 | 238 | AuthUserRequest::operator new (size_t byteCount) |
94439e4e | 239 | { |
e6ccf245 | 240 | /* derived classes with different sizes must implement their own new */ |
241 | assert (byteCount == sizeof (AuthUserRequest)); | |
242 | if (!pool) | |
243 | pool = memPoolCreate("Authenticate Request Data", sizeof(auth_user_request_t)); | |
244 | return static_cast<auth_user_request_t *>(memPoolAlloc(pool)); | |
1d620765 | 245 | } |
246 | ||
e6ccf245 | 247 | void |
248 | AuthUserRequest::operator delete (void *address) | |
249 | { | |
250 | memPoolFree(pool, address); | |
251 | } | |
252 | ||
253 | AuthUserRequest::AuthUserRequest():auth_user(NULL), scheme_data (NULL), message(NULL), | |
254 | references (0), lastReply (AUTH_ACL_CANNOT_AUTHENTICATE) | |
255 | { | |
256 | } | |
257 | ||
258 | AuthUserRequest::~AuthUserRequest() | |
1d620765 | 259 | { |
94439e4e | 260 | dlink_node *link; |
e6ccf245 | 261 | debug(29, 5) ("AuthUserRequest::~AuthUserRequest: freeing request %p\n", this); |
262 | assert(references == 0); | |
263 | if (auth_user) { | |
264 | if (scheme_data != NULL) { | |
94439e4e | 265 | /* we MUST know the module */ |
e6ccf245 | 266 | assert(auth_user->auth_module > 0); |
94439e4e | 267 | /* and the module MUST support requestFree if it has created scheme data */ |
e6ccf245 | 268 | assert(authscheme_list[auth_user->auth_module - 1].requestFree != NULL); |
269 | authscheme_list[auth_user->auth_module - 1].requestFree(this); | |
94439e4e | 270 | } |
271 | /* unlink from the auth_user struct */ | |
e6ccf245 | 272 | link = auth_user->requests.head; |
273 | while (link && (link->data != this)) | |
94439e4e | 274 | link = link->next; |
275 | assert(link != NULL); | |
e6ccf245 | 276 | dlinkDelete(link, &auth_user->requests); |
94439e4e | 277 | dlinkNodeDelete(link); |
278 | ||
279 | /* unlock the request structure's lock */ | |
e6ccf245 | 280 | authenticateAuthUserUnlock(auth_user); |
281 | auth_user = NULL; | |
94439e4e | 282 | } else |
e6ccf245 | 283 | assert(scheme_data == NULL); |
284 | safe_free (message); | |
94439e4e | 285 | } |
286 | ||
e6ccf245 | 287 | void |
288 | AuthUserRequest::setDenyMessage (char const *aString) | |
289 | { | |
290 | safe_free (message); | |
291 | message = xstrdup (aString); | |
292 | } | |
293 | ||
294 | char const * | |
295 | AuthUserRequest::getDenyMessage () | |
296 | { | |
297 | return message; | |
298 | } | |
299 | ||
300 | char const * | |
94439e4e | 301 | authenticateAuthUserRequestMessage(auth_user_request_t * auth_user_request) |
302 | { | |
303 | if (auth_user_request) | |
e6ccf245 | 304 | return auth_user_request->getDenyMessage(); |
94439e4e | 305 | return NULL; |
306 | } | |
307 | ||
e6ccf245 | 308 | void |
309 | authenticateSetDenyMessage (auth_user_request_t * auth_user_request, char const *message) | |
310 | { | |
311 | auth_user_request->setDenyMessage (message); | |
312 | } | |
313 | ||
64f904ee | 314 | static void |
94439e4e | 315 | authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr) |
316 | { | |
60d096f4 | 317 | auth_user_ip_t *ipdata, *tempnode; |
318 | auth_user_t *auth_user; | |
319 | char *ip1; | |
d57a7893 | 320 | int found = 0; |
60d096f4 | 321 | CBDATA_INIT_TYPE(auth_user_ip_t); |
322 | if (!auth_user_request->auth_user) | |
323 | return; | |
324 | auth_user = auth_user_request->auth_user; | |
325 | ipdata = (auth_user_ip_t *) auth_user->ip_list.head; | |
d57a7893 | 326 | /* |
327 | * we walk the entire list to prevent the first item in the list | |
328 | * preventing old entries being flushed and locking a user out after | |
329 | * a timeout+reconfigure | |
60d096f4 | 330 | */ |
331 | while (ipdata) { | |
332 | tempnode = (auth_user_ip_t *) ipdata->node.next; | |
333 | /* walk the ip list */ | |
334 | if (ipdata->ipaddr.s_addr == ipaddr.s_addr) { | |
e6ccf245 | 335 | /* This ip has alreadu been seen. */ |
d57a7893 | 336 | found = 1; |
60d096f4 | 337 | /* update IP ttl */ |
338 | ipdata->ip_expiretime = squid_curtime; | |
339 | } else if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) { | |
340 | /* This IP has expired - remove from the seen list */ | |
341 | dlinkDelete(&ipdata->node, &auth_user->ip_list); | |
342 | cbdataFree(ipdata); | |
343 | /* catch incipient underflow */ | |
344 | assert(auth_user->ipcount); | |
345 | auth_user->ipcount--; | |
346 | } | |
347 | ipdata = tempnode; | |
348 | } | |
349 | ||
a51989a0 | 350 | if (found) |
d57a7893 | 351 | return; |
352 | ||
60d096f4 | 353 | /* This ip is not in the seen list */ |
354 | ipdata = cbdataAlloc(auth_user_ip_t); | |
355 | ipdata->ip_expiretime = squid_curtime; | |
356 | ipdata->ipaddr = ipaddr; | |
357 | dlinkAddTail(ipdata, &ipdata->node, &auth_user->ip_list); | |
358 | auth_user->ipcount++; | |
359 | ||
360 | ip1 = xstrdup(inet_ntoa(ipaddr)); | |
e6ccf245 | 361 | debug(29, 2) ("authenticateAuthUserRequestSetIp: user '%s' has been seen at a new IP address (%s)\n ", auth_user->username(), ip1); |
60d096f4 | 362 | safe_free(ip1); |
363 | } | |
364 | ||
365 | void | |
366 | authenticateAuthUserRequestRemoveIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr) | |
367 | { | |
368 | auth_user_ip_t *ipdata; | |
369 | auth_user_t *auth_user; | |
370 | if (!auth_user_request->auth_user) | |
371 | return; | |
372 | auth_user = auth_user_request->auth_user; | |
373 | ipdata = (auth_user_ip_t *) auth_user->ip_list.head; | |
374 | while (ipdata) { | |
375 | /* walk the ip list */ | |
376 | if (ipdata->ipaddr.s_addr == ipaddr.s_addr) { | |
377 | /* remove the node */ | |
378 | dlinkDelete(&ipdata->node, &auth_user->ip_list); | |
379 | cbdataFree(ipdata); | |
380 | /* catch incipient underflow */ | |
381 | assert(auth_user->ipcount); | |
382 | auth_user->ipcount--; | |
383 | return; | |
384 | } | |
385 | ipdata = (auth_user_ip_t *) ipdata->node.next; | |
386 | } | |
387 | ||
94439e4e | 388 | } |
389 | ||
60d096f4 | 390 | static void |
391 | authenticateAuthUserClearIp(auth_user_t * auth_user) | |
392 | { | |
393 | auth_user_ip_t *ipdata, *tempnode; | |
394 | if (!auth_user) | |
395 | return; | |
396 | ipdata = (auth_user_ip_t *) auth_user->ip_list.head; | |
397 | while (ipdata) { | |
398 | tempnode = (auth_user_ip_t *) ipdata->node.next; | |
399 | /* walk the ip list */ | |
400 | dlinkDelete(&ipdata->node, &auth_user->ip_list); | |
401 | cbdataFree(ipdata); | |
402 | /* catch incipient underflow */ | |
403 | assert(auth_user->ipcount); | |
404 | auth_user->ipcount--; | |
405 | ipdata = tempnode; | |
406 | } | |
407 | /* integrity check */ | |
408 | assert(auth_user->ipcount == 0); | |
409 | } | |
410 | ||
411 | ||
412 | void | |
413 | authenticateAuthUserRequestClearIp(auth_user_request_t * auth_user_request) | |
414 | { | |
415 | if (auth_user_request) | |
416 | authenticateAuthUserClearIp(auth_user_request->auth_user); | |
417 | } | |
418 | ||
419 | size_t | |
420 | authenticateAuthUserRequestIPCount(auth_user_request_t * auth_user_request) | |
421 | { | |
422 | assert(auth_user_request); | |
423 | assert(auth_user_request->auth_user); | |
424 | return auth_user_request->auth_user->ipcount; | |
425 | } | |
426 | ||
427 | ||
94439e4e | 428 | /* Get Auth User: Return a filled out auth_user structure for the given |
429 | * Proxy Auth (or Auth) header. It may be a cached Auth User or a new | |
430 | * Unauthenticated structure. The structure is given an inital lock here. | |
431 | */ | |
e6ccf245 | 432 | auth_user_request_t * |
433 | AuthUserRequest::createAuthUser(const char *proxy_auth) | |
94439e4e | 434 | { |
e6ccf245 | 435 | auth_user_request_t *result = new auth_user_request_t; |
94439e4e | 436 | /* and lock for the callers instance */ |
e6ccf245 | 437 | result->lock(); |
60d096f4 | 438 | /* The scheme is allowed to provide a cached auth_user or a new one */ |
e6ccf245 | 439 | result->decodeAuth(proxy_auth); |
440 | return result; | |
94439e4e | 441 | } |
442 | ||
443 | /* | |
444 | * authenticateUserAuthenticated: is this auth_user structure logged in ? | |
445 | */ | |
446 | int | |
447 | authenticateUserAuthenticated(auth_user_request_t * auth_user_request) | |
448 | { | |
6437ac71 | 449 | if (!authenticateValidateUser(auth_user_request)) |
450 | return 0; | |
94439e4e | 451 | if (auth_user_request->auth_user->auth_module > 0) |
452 | return authscheme_list[auth_user_request->auth_user->auth_module - 1].authenticated(auth_user_request); | |
453 | else | |
454 | return 0; | |
455 | } | |
456 | ||
457 | /* | |
60d096f4 | 458 | * authenticateAuthenticateUser: call the module specific code to |
459 | * log this user request in. | |
94439e4e | 460 | * Cache hits may change the auth_user pointer in the structure if needed. |
461 | * This is basically a handle approach. | |
462 | */ | |
60d096f4 | 463 | static void |
94439e4e | 464 | authenticateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type) |
465 | { | |
466 | assert(auth_user_request != NULL); | |
467 | if (auth_user_request->auth_user->auth_module > 0) | |
468 | authscheme_list[auth_user_request->auth_user->auth_module - 1].authAuthenticate(auth_user_request, request, conn, type); | |
469 | } | |
470 | ||
b4504bc8 | 471 | static auth_user_request_t * |
472 | authTryGetUser (auth_user_request_t **auth_user_request, ConnStateData * conn) | |
473 | { | |
474 | if (*auth_user_request) | |
475 | return *auth_user_request; | |
476 | else if (conn) | |
477 | return conn->auth_user_request; | |
478 | else | |
479 | return NULL; | |
480 | } | |
481 | ||
60d096f4 | 482 | /* returns one of |
483 | * AUTH_ACL_CHALLENGE, | |
484 | * AUTH_ACL_HELPER, | |
485 | * AUTH_ACL_CANNOT_AUTHENTICATE, | |
486 | * AUTH_AUTHENTICATED | |
487 | * | |
488 | * How to use: In your proxy-auth dependent acl code, use the following | |
489 | * construct: | |
490 | * int rv; | |
491 | * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED) | |
492 | * return rv; | |
493 | * | |
494 | * when this code is reached, the request/connection is authenticated. | |
495 | * | |
496 | * if you have non-acl code, but want to force authentication, you need a | |
497 | * callback mechanism like the acl testing routines that will send a 40[1|7] to | |
498 | * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with | |
499 | * the authenticateStart routine for rv==AUTH_ACL_HELPER | |
500 | */ | |
501 | auth_acl_t | |
e6ccf245 | 502 | AuthUserRequest::authenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr) |
60d096f4 | 503 | { |
504 | const char *proxy_auth; | |
505 | assert(headertype != 0); | |
0e3be1ea | 506 | |
60d096f4 | 507 | proxy_auth = httpHeaderGetStr(&request->header, headertype); |
508 | ||
60d096f4 | 509 | /* |
510 | * a note on proxy_auth logix here: | |
aa387023 | 511 | * proxy_auth==NULL -> unauthenticated request || already |
512 | * authenticated connection so we test for an authenticated | |
513 | * connection when we recieve no authentication header. | |
60d096f4 | 514 | */ |
b4504bc8 | 515 | if (((proxy_auth == NULL) && (!authenticateUserAuthenticated(authTryGetUser(auth_user_request,conn)))) |
516 | || (conn && conn->auth_type == AUTH_BROKEN)) { | |
60d096f4 | 517 | /* no header or authentication failed/got corrupted - restart */ |
60d096f4 | 518 | debug(28, 4) ("authenticateAuthenticate: broken auth or no proxy_auth header. Requesting auth header.\n"); |
519 | /* something wrong with the AUTH credentials. Force a new attempt */ | |
b4504bc8 | 520 | if (conn) { |
521 | conn->auth_type = AUTH_UNKNOWN; | |
522 | if (conn->auth_user_request) | |
523 | conn->auth_user_request->unlock(); | |
5d146f7d | 524 | conn->auth_user_request = NULL; |
525 | } | |
60d096f4 | 526 | if (*auth_user_request) { |
527 | /* unlock the ACL lock */ | |
e6ccf245 | 528 | (*auth_user_request)->unlock(); |
60d096f4 | 529 | auth_user_request = NULL; |
530 | } | |
531 | return AUTH_ACL_CHALLENGE; | |
532 | } | |
533 | /* | |
534 | * Is this an already authenticated connection with a new auth header? | |
535 | * No check for function required in the if: its compulsory for conn based | |
536 | * auth modules | |
537 | */ | |
b4504bc8 | 538 | if (proxy_auth && conn && conn->auth_user_request && |
60d096f4 | 539 | authenticateUserAuthenticated(conn->auth_user_request) && |
540 | strcmp(proxy_auth, authscheme_list[conn->auth_user_request->auth_user->auth_module - 1].authConnLastHeader(conn->auth_user_request))) { | |
e6ccf245 | 541 | debug(28, 2) ("authenticateAuthenticate: DUPLICATE AUTH - authentication header on already authenticated connection!. AU %p, Current user '%s' proxy_auth %s\n", conn->auth_user_request, conn->auth_user_request->username(), proxy_auth); |
60d096f4 | 542 | /* remove this request struct - the link is already authed and it can't be to |
543 | * reauth. | |
544 | */ | |
545 | ||
546 | /* This should _only_ ever occur on the first pass through | |
547 | * authenticateAuthenticate | |
548 | */ | |
549 | assert(*auth_user_request == NULL); | |
550 | /* unlock the conn lock on the auth_user_request */ | |
e6ccf245 | 551 | conn->auth_user_request->unlock(); |
60d096f4 | 552 | /* mark the conn as non-authed. */ |
553 | conn->auth_user_request = NULL; | |
554 | /* Set the connection auth type */ | |
555 | conn->auth_type = AUTH_UNKNOWN; | |
556 | } | |
557 | /* we have a proxy auth header and as far as we know this connection has | |
558 | * not had bungled connection oriented authentication happen on it. */ | |
559 | debug(28, 9) ("authenticateAuthenticate: header %s.\n", proxy_auth); | |
560 | if (*auth_user_request == NULL) { | |
561 | debug(28, 9) ("authenticateAuthenticate: This is a new checklist test on FD:%d\n", | |
b4504bc8 | 562 | conn ? conn->fd : -1); |
60d096f4 | 563 | if ((!request->auth_user_request) |
b4504bc8 | 564 | && (!conn || conn->auth_type == AUTH_UNKNOWN)) { |
60d096f4 | 565 | /* beginning of a new request check */ |
566 | debug(28, 4) ("authenticateAuthenticate: no connection authentication type\n"); | |
567 | if (!authenticateValidateUser(*auth_user_request = | |
e6ccf245 | 568 | createAuthUser(proxy_auth))) { |
60d096f4 | 569 | /* the decode might have left a username for logging, or a message to |
570 | * the user */ | |
e6ccf245 | 571 | if ((*auth_user_request)->username()) { |
60d096f4 | 572 | /* lock the user for the request structure link */ |
e6ccf245 | 573 | (*auth_user_request)->lock(); |
60d096f4 | 574 | request->auth_user_request = *auth_user_request; |
60d096f4 | 575 | } |
e6ccf245 | 576 | /* unlock the ACL reference granted by ...createAuthUser. */ |
577 | (*auth_user_request)->unlock(); | |
60d096f4 | 578 | *auth_user_request = NULL; |
579 | return AUTH_ACL_CHALLENGE; | |
580 | } | |
e6ccf245 | 581 | /* the user_request comes prelocked for the caller to createAuthUser (us) */ |
60d096f4 | 582 | } else if (request->auth_user_request) { |
583 | *auth_user_request = request->auth_user_request; | |
584 | /* lock the user request for this ACL processing */ | |
e6ccf245 | 585 | (*auth_user_request)->lock(); |
60d096f4 | 586 | } else { |
b4504bc8 | 587 | assert (conn); |
60d096f4 | 588 | if (conn->auth_user_request != NULL) { |
589 | *auth_user_request = conn->auth_user_request; | |
590 | /* lock the user request for this ACL processing */ | |
e6ccf245 | 591 | (*auth_user_request)->lock(); |
60d096f4 | 592 | } else { |
593 | /* failed connection based authentication */ | |
04bd8d25 | 594 | debug(28, 4) ("authenticateAuthenticate: Auth user request %p conn-auth user request %p conn type %d authentication failed.\n", |
60d096f4 | 595 | *auth_user_request, conn->auth_user_request, conn->auth_type); |
e6ccf245 | 596 | (*auth_user_request)->unlock(); |
60d096f4 | 597 | *auth_user_request = NULL; |
598 | return AUTH_ACL_CHALLENGE; | |
599 | } | |
600 | } | |
601 | } | |
602 | if (!authenticateUserAuthenticated(*auth_user_request)) { | |
603 | /* User not logged in. Log them in */ | |
604 | authenticateAuthenticateUser(*auth_user_request, request, | |
605 | conn, headertype); | |
606 | switch (authenticateDirection(*auth_user_request)) { | |
607 | case 1: | |
5d146f7d | 608 | case -2: |
60d096f4 | 609 | /* this ACL check is finished. Unlock. */ |
e6ccf245 | 610 | (*auth_user_request)->unlock(); |
60d096f4 | 611 | *auth_user_request = NULL; |
612 | return AUTH_ACL_CHALLENGE; | |
613 | case -1: | |
614 | /* we are partway through authentication within squid, | |
615 | * the *auth_user_request variables stores the auth_user_request | |
616 | * for the callback to here - Do not Unlock */ | |
617 | return AUTH_ACL_HELPER; | |
60d096f4 | 618 | } |
619 | /* on 0 the authentication is finished - fallthrough */ | |
5d146f7d | 620 | /* See if user authentication failed for some reason */ |
60d096f4 | 621 | if (!authenticateUserAuthenticated(*auth_user_request)) { |
e6ccf245 | 622 | if ((*auth_user_request)->username()) { |
60d096f4 | 623 | if (!request->auth_user_request) { |
624 | /* lock the user for the request structure link */ | |
e6ccf245 | 625 | (*auth_user_request)->lock(); |
60d096f4 | 626 | request->auth_user_request = *auth_user_request; |
627 | } | |
628 | } | |
629 | /* this ACL check is finished. Unlock. */ | |
e6ccf245 | 630 | (*auth_user_request)->unlock(); |
60d096f4 | 631 | *auth_user_request = NULL; |
632 | return AUTH_ACL_CHALLENGE; | |
633 | } | |
634 | } | |
635 | /* copy username to request for logging on client-side */ | |
636 | /* the credentials are correct at this point */ | |
637 | if (!request->auth_user_request) { | |
638 | /* lock the user for the request structure link */ | |
e6ccf245 | 639 | (*auth_user_request)->lock(); |
60d096f4 | 640 | request->auth_user_request = *auth_user_request; |
641 | authenticateAuthUserRequestSetIp(*auth_user_request, src_addr); | |
642 | } | |
643 | /* Unlock the request - we've authenticated it */ | |
e6ccf245 | 644 | (*auth_user_request)->unlock(); |
60d096f4 | 645 | return AUTH_AUTHENTICATED; |
646 | } | |
647 | ||
0e3be1ea | 648 | auth_acl_t |
e6ccf245 | 649 | AuthUserRequest::tryToAuthenticateAndSetAuthUser(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr) |
0e3be1ea | 650 | { |
651 | /* If we have already been called, return the cached value */ | |
b4504bc8 | 652 | auth_user_request_t *t = authTryGetUser (auth_user_request, conn); |
0e3be1ea | 653 | if (t && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE |
654 | && t->lastReply != AUTH_ACL_HELPER) { | |
655 | if (!*auth_user_request) | |
656 | *auth_user_request = t; | |
657 | return t->lastReply; | |
658 | } | |
659 | /* ok, call the actual authenticator routine. */ | |
b4504bc8 | 660 | auth_acl_t result = authenticate(auth_user_request, headertype, request, conn, src_addr); |
661 | t = authTryGetUser (auth_user_request, conn); | |
0e3be1ea | 662 | if (t && result != AUTH_ACL_CANNOT_AUTHENTICATE && |
663 | result != AUTH_ACL_HELPER) | |
664 | t->lastReply = result; | |
665 | return result; | |
666 | } | |
667 | ||
e6ccf245 | 668 | auth_acl_t |
669 | authenticateTryToAuthenticateAndSetAuthUser(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t * request, ConnStateData * conn, struct in_addr src_addr) | |
94439e4e | 670 | { |
e6ccf245 | 671 | return AuthUserRequest::tryToAuthenticateAndSetAuthUser (auth_user_request, headertype,request, conn, src_addr); |
94439e4e | 672 | } |
673 | ||
674 | /* authenticateUserRequestUsername: return a pointer to the username in the */ | |
e6ccf245 | 675 | char const * |
94439e4e | 676 | authenticateUserRequestUsername(auth_user_request_t * auth_user_request) |
677 | { | |
678 | assert(auth_user_request != NULL); | |
e6ccf245 | 679 | return auth_user_request->username(); |
94439e4e | 680 | } |
681 | ||
682 | /* returns | |
683 | * 0: no output needed | |
684 | * 1: send to client | |
685 | * -1: send to helper | |
686 | * -2: authenticate broken in some fashion | |
687 | */ | |
688 | int | |
689 | authenticateDirection(auth_user_request_t * auth_user_request) | |
690 | { | |
691 | if (!auth_user_request) | |
692 | return -2; | |
693 | if (authenticateUserAuthenticated(auth_user_request)) | |
694 | return 0; | |
695 | if (auth_user_request->auth_user->auth_module > 0) | |
696 | return authscheme_list[auth_user_request->auth_user->auth_module - 1].getdirection(auth_user_request); | |
697 | return -2; | |
698 | } | |
699 | ||
700 | int | |
2d72d4fd | 701 | authenticateActiveSchemeCount(void) |
94439e4e | 702 | { |
703 | int i = 0, rv = 0; | |
704 | for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) | |
2d70df72 | 705 | if (authscheme_list[i].configured()) |
94439e4e | 706 | rv++; |
707 | debug(29, 9) ("authenticateActiveSchemeCount: %d active.\n", rv); | |
708 | return rv; | |
709 | } | |
710 | ||
711 | int | |
2d72d4fd | 712 | authenticateSchemeCount(void) |
94439e4e | 713 | { |
714 | int i = 0, rv = 0; | |
715 | for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) | |
716 | rv++; | |
717 | debug(29, 9) ("authenticateSchemeCount: %d active.\n", rv); | |
718 | return rv; | |
719 | } | |
720 | ||
721 | void | |
722 | authenticateSchemeInit(void) | |
723 | { | |
724 | authSchemeSetup(); | |
725 | } | |
726 | ||
727 | void | |
728 | authenticateInit(authConfig * config) | |
729 | { | |
730 | int i; | |
731 | authScheme *scheme; | |
732 | for (i = 0; i < config->n_configured; i++) { | |
5dae8514 | 733 | scheme = config->schemes + i; |
2d70df72 | 734 | if (authscheme_list[scheme->Id].init && authscheme_list[scheme->Id].configured()) { |
5dae8514 | 735 | authscheme_list[scheme->Id].init(scheme); |
94439e4e | 736 | } |
1d620765 | 737 | } |
94439e4e | 738 | if (!proxy_auth_username_cache) |
e6ccf245 | 739 | AuthUser::cacheInit(); |
c623f072 | 740 | } |
741 | ||
1d620765 | 742 | void |
74addf6c | 743 | authenticateShutdown(void) |
1d620765 | 744 | { |
94439e4e | 745 | int i; |
746 | debug(29, 2) ("authenticateShutdown: shutting down auth schemes\n"); | |
c623f072 | 747 | /* free the cache if we are shutting down */ |
748 | if (shutting_down) | |
e6ccf245 | 749 | hashFreeItems(proxy_auth_username_cache, AuthUserHashPointer::removeFromCache); |
c623f072 | 750 | |
94439e4e | 751 | /* find the currently known authscheme types */ |
752 | for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) { | |
753 | if (authscheme_list[i].donefunc != NULL) | |
754 | authscheme_list[i].donefunc(); | |
755 | else | |
756 | debug(29, 2) ("authenticateShutdown: scheme %s has not registered a shutdown function.\n", authscheme_list[i].typestr); | |
2d70df72 | 757 | if (shutting_down) |
912b43b8 | 758 | authscheme_list[i].typestr = NULL; |
94439e4e | 759 | } |
760 | } | |
761 | ||
762 | void | |
e6ccf245 | 763 | AuthUserRequest::addReplyAuthHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated, int internal) |
94439e4e | 764 | /* send the auth types we are configured to support (and have compiled in!) */ |
765 | { | |
e6ccf245 | 766 | http_hdr_type type; |
94439e4e | 767 | switch (rep->sline.status) { |
768 | case HTTP_PROXY_AUTHENTICATION_REQUIRED: | |
769 | /* Proxy authorisation needed */ | |
770 | type = HDR_PROXY_AUTHENTICATE; | |
771 | break; | |
772 | case HTTP_UNAUTHORIZED: | |
773 | /* WWW Authorisation needed */ | |
774 | type = HDR_WWW_AUTHENTICATE; | |
775 | break; | |
776 | default: | |
777 | /* Keep GCC happy */ | |
778 | /* some other HTTP status */ | |
e6ccf245 | 779 | type = HDR_ENUM_END; |
94439e4e | 780 | break; |
781 | } | |
5dae8514 | 782 | debug(29, 9) ("authenticateFixHeader: headertype:%d authuser:%p\n", type, auth_user_request); |
721b0310 | 783 | if (((rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED) |
784 | || (rep->sline.status == HTTP_UNAUTHORIZED)) && internal) | |
94439e4e | 785 | /* this is a authenticate-needed response */ |
786 | { | |
60d096f4 | 787 | if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0) & !authenticateUserAuthenticated(auth_user_request)) |
94439e4e | 788 | authscheme_list[auth_user_request->auth_user->auth_module - 1].authFixHeader(auth_user_request, rep, type, request); |
789 | else { | |
790 | int i; | |
791 | authScheme *scheme; | |
2d70df72 | 792 | /* call each configured & running authscheme */ |
e6ccf245 | 793 | for (i = 0; i < Config.authConfiguration.n_configured; i++) { |
794 | scheme = Config.authConfiguration.schemes + i; | |
94439e4e | 795 | if (authscheme_list[scheme->Id].Active()) |
1b0624e9 | 796 | authscheme_list[scheme->Id].authFixHeader(NULL, rep, type, |
94439e4e | 797 | request); |
798 | else | |
799 | debug(29, 4) ("authenticateFixHeader: Configured scheme %s not Active\n", scheme->typestr); | |
800 | } | |
801 | } | |
802 | } | |
e6ccf245 | 803 | /* |
aa387023 | 804 | * allow protocol specific headers to be _added_ to the existing |
805 | * response - ie digest auth | |
721b0310 | 806 | */ |
94439e4e | 807 | if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0) |
808 | && (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader)) | |
809 | authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader(auth_user_request, rep, accelerated); | |
0e3be1ea | 810 | if (auth_user_request != NULL) |
811 | auth_user_request->lastReply = AUTH_ACL_CANNOT_AUTHENTICATE; | |
94439e4e | 812 | } |
813 | ||
e6ccf245 | 814 | void |
815 | authenticateFixHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated, int internal) | |
816 | { | |
817 | AuthUserRequest::addReplyAuthHeader(rep, auth_user_request, request, accelerated, internal); | |
818 | } | |
819 | ||
820 | ||
94439e4e | 821 | /* call the active auth module and allow it to add a trailer to the request */ |
822 | void | |
823 | authenticateAddTrailer(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated) | |
824 | { | |
825 | if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0) | |
826 | && (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer)) | |
827 | authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer(auth_user_request, rep, accelerated); | |
828 | } | |
829 | ||
830 | void | |
831 | authenticateAuthUserLock(auth_user_t * auth_user) | |
832 | { | |
5dae8514 | 833 | debug(29, 9) ("authenticateAuthUserLock auth_user '%p'.\n", auth_user); |
94439e4e | 834 | assert(auth_user != NULL); |
835 | auth_user->references++; | |
32754419 | 836 | debug(29, 9) ("authenticateAuthUserLock auth_user '%p' now at '%ld'.\n", auth_user, (long int) auth_user->references); |
94439e4e | 837 | } |
838 | ||
839 | void | |
840 | authenticateAuthUserUnlock(auth_user_t * auth_user) | |
841 | { | |
5dae8514 | 842 | debug(29, 9) ("authenticateAuthUserUnlock auth_user '%p'.\n", auth_user); |
94439e4e | 843 | assert(auth_user != NULL); |
844 | if (auth_user->references > 0) { | |
845 | auth_user->references--; | |
846 | } else { | |
5dae8514 | 847 | debug(29, 1) ("Attempt to lower Auth User %p refcount below 0!\n", auth_user); |
94439e4e | 848 | } |
32754419 | 849 | debug(29, 9) ("authenticateAuthUserUnlock auth_user '%p' now at '%ld'.\n", auth_user, (long int) auth_user->references); |
94439e4e | 850 | if (auth_user->references == 0) |
e6ccf245 | 851 | delete auth_user; |
94439e4e | 852 | } |
853 | ||
854 | void | |
e6ccf245 | 855 | AuthUserRequest::lock() |
94439e4e | 856 | { |
e6ccf245 | 857 | debug(29, 9) ("AuthUserRequest::lock: auth_user request '%p'.\n", this); |
858 | assert(this != NULL); | |
859 | ++references; | |
860 | debug(29, 9) ("AuthUserRequest::lock: auth_user request '%p' now at '%ld'.\n", this, (long int) references); | |
94439e4e | 861 | } |
862 | ||
863 | void | |
e6ccf245 | 864 | AuthUserRequest::unlock() |
94439e4e | 865 | { |
e6ccf245 | 866 | debug(29, 9) ("AuthUserRequest::unlock: auth_user request '%p'.\n", this); |
867 | assert(this != NULL); | |
868 | if (references > 0) { | |
869 | --references; | |
94439e4e | 870 | } else { |
e6ccf245 | 871 | debug(29, 1) ("Attempt to lower Auth User request %p refcount below 0!\n", this); |
94439e4e | 872 | } |
e6ccf245 | 873 | debug(29, 9) ("AuthUserRequest::unlock: auth_user_request '%p' now at '%ld'.\n", this, (long int) references); |
874 | if (references == 0) | |
94439e4e | 875 | /* not locked anymore */ |
e6ccf245 | 876 | delete this; |
877 | } | |
878 | ||
879 | void | |
880 | authenticateAuthUserRequestLock(auth_user_request_t * auth_user_request) | |
881 | { | |
882 | auth_user_request->lock(); | |
94439e4e | 883 | } |
884 | ||
e6ccf245 | 885 | void |
886 | authenticateAuthUserRequestUnlock(auth_user_request_t * auth_user_request) | |
887 | { | |
888 | auth_user_request->unlock(); | |
889 | } | |
890 | ||
891 | ||
94439e4e | 892 | int |
893 | authenticateAuthUserInuse(auth_user_t * auth_user) | |
894 | /* returns 0 for not in use */ | |
895 | { | |
896 | assert(auth_user != NULL); | |
897 | return auth_user->references; | |
898 | } | |
899 | ||
e6ccf245 | 900 | /* Combine two user structs. ONLY to be called from within a scheme |
901 | * module. The scheme module is responsible for ensuring that the | |
aa387023 | 902 | * two users _can_ be merged without invalidating all the request |
e6ccf245 | 903 | * scheme data. The scheme is also responsible for merging any user |
aa387023 | 904 | * related scheme data itself. |
905 | */ | |
94439e4e | 906 | void |
e6ccf245 | 907 | AuthUser::absorb (AuthUser *from) |
94439e4e | 908 | { |
94439e4e | 909 | auth_user_request_t *auth_user_request; |
aa387023 | 910 | /* |
911 | * XXX combine two authuser structs. Incomplete: it should merge | |
912 | * in hash references too and ask the module to merge in scheme | |
913 | * data | |
914 | */ | |
e6ccf245 | 915 | debug(29, 5) ("authenticateAuthUserMerge auth_user '%p' into auth_user '%p'.\n", from, this); |
916 | dlink_node *link = from->requests.head; | |
94439e4e | 917 | while (link) { |
e6ccf245 | 918 | auth_user_request = static_cast<auth_user_request_t *>(link->data); |
919 | dlink_node *tmplink = link; | |
94439e4e | 920 | link = link->next; |
921 | dlinkDelete(tmplink, &from->requests); | |
e6ccf245 | 922 | dlinkAddTail(auth_user_request, tmplink, &requests); |
923 | auth_user_request->auth_user = this; | |
94439e4e | 924 | } |
e6ccf245 | 925 | references += from->references; |
94439e4e | 926 | from->references = 0; |
e6ccf245 | 927 | delete from; |
928 | } | |
929 | ||
930 | void | |
931 | authenticateAuthUserMerge(auth_user_t * from, auth_user_t * to) | |
932 | { | |
933 | to->absorb (from); | |
94439e4e | 934 | } |
935 | ||
936 | void | |
e6ccf245 | 937 | AuthUser::operator delete (void *address) |
938 | { | |
939 | memPoolFree(pool, address); | |
940 | } | |
941 | ||
942 | AuthUser::~AuthUser() | |
94439e4e | 943 | { |
94439e4e | 944 | auth_user_request_t *auth_user_request; |
94439e4e | 945 | dlink_node *link, *tmplink; |
e6ccf245 | 946 | debug(29, 5) ("AuthUser::~AuthUser: Freeing auth_user '%p' with refcount '%ld'.\n", this, (long int) references); |
947 | assert(references == 0); | |
94439e4e | 948 | /* were they linked in by username ? */ |
e6ccf245 | 949 | if (usernamehash) { |
950 | assert(usernamehash->user() == this); | |
951 | debug(29, 5) ("AuthUser::~AuthUser: removing usernamehash entry '%p'\n", usernamehash); | |
94439e4e | 952 | hash_remove_link(proxy_auth_username_cache, |
e6ccf245 | 953 | (hash_link *) usernamehash); |
94439e4e | 954 | /* don't free the key as we use the same user string as the auth_user |
955 | * structure */ | |
e6ccf245 | 956 | delete usernamehash; |
94439e4e | 957 | } |
958 | /* remove any outstanding requests */ | |
e6ccf245 | 959 | link = requests.head; |
94439e4e | 960 | while (link) { |
e6ccf245 | 961 | debug(29, 5) ("AuthUser::~AuthUser: removing request entry '%p'\n", link->data); |
962 | auth_user_request = static_cast<auth_user_request_t *>(link->data); | |
94439e4e | 963 | tmplink = link; |
964 | link = link->next; | |
e6ccf245 | 965 | dlinkDelete(tmplink, &requests); |
94439e4e | 966 | dlinkNodeDelete(tmplink); |
e6ccf245 | 967 | delete auth_user_request; |
94439e4e | 968 | } |
969 | /* free cached acl results */ | |
e6ccf245 | 970 | aclCacheMatchFlush(&proxy_match_cache); |
60d096f4 | 971 | /* free seen ip address's */ |
e6ccf245 | 972 | authenticateAuthUserClearIp(this); |
973 | if (scheme_data && auth_module > 0) | |
974 | authscheme_list[auth_module - 1].FreeUser(this); | |
94439e4e | 975 | /* prevent accidental reuse */ |
e6ccf245 | 976 | auth_type = AUTH_UNKNOWN; |
94439e4e | 977 | } |
978 | ||
979 | void | |
e6ccf245 | 980 | AuthUser::cacheInit(void) |
94439e4e | 981 | { |
982 | if (!proxy_auth_username_cache) { | |
983 | /* First time around, 7921 should be big enough */ | |
984 | proxy_auth_username_cache = | |
985 | hash_create((HASHCMP *) strcmp, 7921, hash_string); | |
986 | assert(proxy_auth_username_cache); | |
e6ccf245 | 987 | eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1); |
94439e4e | 988 | } |
989 | } | |
990 | ||
991 | void | |
e6ccf245 | 992 | AuthUser::cacheCleanup(void *datanotused) |
94439e4e | 993 | { |
994 | /* | |
995 | * We walk the hash by username as that is the unique key we use. | |
996 | * For big hashs we could consider stepping through the cache, 100/200 | |
997 | * entries at a time. Lets see how it flys first. | |
998 | */ | |
e6ccf245 | 999 | AuthUserHashPointer *usernamehash; |
94439e4e | 1000 | auth_user_t *auth_user; |
e6ccf245 | 1001 | char const *username = NULL; |
1002 | debug(29, 3) ("AuthUser::cacheCleanup: Cleaning the user cache now\n"); | |
1003 | debug(29, 3) ("AuthUser::cacheCleanup: Current time: %ld\n", (long int) current_time.tv_sec); | |
94439e4e | 1004 | hash_first(proxy_auth_username_cache); |
e6ccf245 | 1005 | while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) { |
1006 | auth_user = usernamehash->user(); | |
1007 | username = auth_user->username(); | |
94439e4e | 1008 | |
1009 | /* if we need to have inpedendent expiry clauses, insert a module call | |
1010 | * here */ | |
e6ccf245 | 1011 | 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); |
94439e4e | 1012 | if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) { |
e6ccf245 | 1013 | debug(29, 5) ("AuthUser::cacheCleanup: Removing user %s from cache due to timeout.\n", username); |
94439e4e | 1014 | /* the minus 1 accounts for the cache lock */ |
2f44bd34 | 1015 | if (!(authenticateAuthUserInuse(auth_user) - 1)) |
1016 | /* we don't warn if we leave the user in the cache, | |
1017 | * because other modules (ie delay pools) may keep | |
1018 | * locks on users, and thats legitimate | |
1019 | */ | |
94439e4e | 1020 | authenticateAuthUserUnlock(auth_user); |
1021 | } | |
1022 | } | |
e6ccf245 | 1023 | debug(29, 3) ("AuthUser::cacheCleanup: Finished cleaning the user cache.\n"); |
1024 | eventAdd("User Cache Maintenance", cacheCleanup, NULL, Config.authenticateGCInterval, 1); | |
94439e4e | 1025 | } |
1026 | ||
1027 | /* | |
1028 | * authenticateUserCacheRestart() cleans all config-dependent data from the | |
1029 | * auth_user cache. It DOES NOT Flush the user cache. | |
1030 | */ | |
1031 | ||
1032 | void | |
2d72d4fd | 1033 | authenticateUserCacheRestart(void) |
94439e4e | 1034 | { |
e6ccf245 | 1035 | AuthUserHashPointer *usernamehash; |
94439e4e | 1036 | auth_user_t *auth_user; |
94439e4e | 1037 | debug(29, 3) ("authenticateUserCacheRestart: Clearing config dependent cache data.\n"); |
1038 | hash_first(proxy_auth_username_cache); | |
e6ccf245 | 1039 | while ((usernamehash = ((AuthUserHashPointer *) hash_next(proxy_auth_username_cache)))) { |
1040 | auth_user = usernamehash->user(); | |
1041 | debug(29, 5) ("authenticateUserCacheRestat: Clearing cache ACL results for user: %s\n", auth_user->username()); | |
94439e4e | 1042 | } |
1043 | ||
1044 | } | |
1045 | ||
1046 | /* | |
1047 | * called to add another auth scheme module | |
1048 | */ | |
1049 | void | |
a2c963ae | 1050 | authSchemeAdd(const char *type, AUTHSSETUP * setup) |
94439e4e | 1051 | { |
1052 | int i; | |
1d1cc61b | 1053 | debug(29, 4) ("authSchemeAdd: adding %s\n", type); |
94439e4e | 1054 | /* find the number of currently known authscheme types */ |
1055 | for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) { | |
1056 | assert(strcmp(authscheme_list[i].typestr, type) != 0); | |
1057 | } | |
1058 | /* add the new type */ | |
e6ccf245 | 1059 | authscheme_list = static_cast<authscheme_entry_t *>(xrealloc(authscheme_list, (i + 2) * sizeof(authscheme_entry_t))); |
8d25251a | 1060 | memset(&authscheme_list[i], 0, sizeof(authscheme_entry_t)); |
94439e4e | 1061 | memset(&authscheme_list[i + 1], 0, sizeof(authscheme_entry_t)); |
1062 | authscheme_list[i].typestr = type; | |
1063 | /* Call the scheme module to set up capabilities and initialize any global data */ | |
1064 | setup(&authscheme_list[i]); | |
1065 | } | |
1066 | ||
e6ccf245 | 1067 | /* _auth_user_hash_pointe */ |
1068 | ||
1069 | void | |
1070 | AuthUserHashPointer::removeFromCache(void *usernamehash_p) | |
1071 | { | |
1072 | AuthUserHashPointer *usernamehash = static_cast<AuthUserHashPointer *>(usernamehash_p); | |
1073 | auth_user_t *auth_user = usernamehash->auth_user; | |
1074 | if ((authenticateAuthUserInuse(auth_user) - 1)) | |
1075 | debug(29, 1) ("AuthUserHashPointer::removeFromCache: entry in use - not freeing\n"); | |
1076 | authenticateAuthUserUnlock(auth_user); | |
1077 | /* TODO: change behaviour - we remove from the auth user list here, and then unlock, and the | |
1078 | * delete ourselves. | |
1079 | */ | |
1080 | } | |
94439e4e | 1081 | |
e6ccf245 | 1082 | void * |
768cb287 | 1083 | AuthUserHashPointer::operator new (size_t byteCount) |
e6ccf245 | 1084 | { |
1085 | assert (byteCount == sizeof (AuthUserHashPointer)); | |
1086 | if (!pool) | |
1087 | pool = memPoolCreate("Auth user hash link", sizeof(AuthUserHashPointer)); | |
1088 | return static_cast<AuthUserHashPointer *>(memPoolAlloc(pool)); | |
1089 | } | |
94439e4e | 1090 | |
94439e4e | 1091 | void |
e6ccf245 | 1092 | AuthUserHashPointer::operator delete (void *address) |
94439e4e | 1093 | { |
e6ccf245 | 1094 | memPoolFree(pool, address); |
1095 | } | |
1096 | ||
1097 | AuthUserHashPointer::AuthUserHashPointer (auth_user_t * anAuth_user): | |
4a8b20e8 | 1098 | auth_user (anAuth_user) |
e6ccf245 | 1099 | { |
4a8b20e8 | 1100 | key = (void *)anAuth_user->username(); |
1101 | next = NULL; | |
e6ccf245 | 1102 | hash_join(proxy_auth_username_cache, (hash_link *) this); |
94439e4e | 1103 | /* lock for presence in the cache */ |
1104 | authenticateAuthUserLock(auth_user); | |
1105 | } | |
e6ccf245 | 1106 | |
1107 | AuthUser * | |
1108 | AuthUserHashPointer::user() const | |
1109 | { | |
1110 | return auth_user; | |
1111 | } | |
1112 | ||
1113 | /* C bindings */ | |
1114 | /* UserNameCacheAdd: add a auth_user structure to the username cache */ | |
1115 | void | |
1116 | authenticateUserNameCacheAdd(auth_user_t * auth_user) | |
1117 | { | |
1118 | auth_user->usernamehash = new AuthUserHashPointer (auth_user); | |
1119 | } | |
1120 | ||
1121 | auth_user_t* | |
1122 | authUserHashPointerUser (auth_user_hash_pointer *aHashEntry) | |
1123 | { | |
1124 | return aHashEntry->user(); | |
1125 | } | |
1126 |