]> git.ipfire.org Git - thirdparty/squid.git/blame - src/authenticate.cc
Major rewrite of proxy authentication to support other schemes than
[thirdparty/squid.git] / src / authenticate.cc
CommitLineData
1d620765 1
2/*
94439e4e 3 * $Id: authenticate.cc,v 1.15 2001/01/07 23:36:37 hno Exp $
1d620765 4 *
5 * DEBUG: section 29 Authenticator
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
efd900cb 15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * 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
1d620765 40
94439e4e 41#include "squid.h"
1d620765 42
43static void
94439e4e 44 authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request);
45
46/*
47 *
48 * Private Data
49 *
50 */
51
52MemPool *auth_user_request_pool = NULL;
53
54/* Generic Functions */
55
56
57int
58authenticateAuthSchemeConfigured(const char *proxy_auth)
1d620765 59{
94439e4e 60 authScheme *scheme;
61 int i;
62 for (i = 0; i < Config.authConfig.n_configured; i++) {
63 scheme = Config.authConfig.schemes + i;
64 if (strncasecmp(proxy_auth, scheme->typestr, strlen(scheme->typestr)) == 0)
65 return 1;
c68e9c6b 66 }
94439e4e 67 return 0;
1d620765 68}
69
94439e4e 70int
71authenticateAuthSchemeId(const char *typestr)
1d620765 72{
94439e4e 73 int i = 0;
74 for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
75 if (strncasecmp(typestr, authscheme_list[i].typestr, strlen(authscheme_list[i].typestr)) == 0) {
76 return i;
77 }
78 }
79 return -1;
1d620765 80}
81
94439e4e 82void
83authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request)
1d620765 84{
94439e4e 85 int i = 0;
86 assert(proxy_auth != NULL);
87 assert(auth_user_request != NULL); /* we need this created for us. */
88 debug(29, 9) ("authenticateDecodeAuth: header = '%s'\n", proxy_auth);
89 if (authenticateAuthSchemeConfigured(proxy_auth)) {
90 /* we're configured to use this scheme - but is it active ? */
91 if ((i = authenticateAuthSchemeId(proxy_auth)) != -1) {
92 authscheme_list[i].decodeauth(auth_user_request, proxy_auth);
93 auth_user_request->auth_user->auth_module = i + 1;
94 return;
95 }
96 }
97 debug(29, 1)
98 ("authenticateDecodeAuth: Unsupported or unconfigured proxy-auth scheme, '%s'\n",
99 proxy_auth);
100 return;
1d620765 101}
102
94439e4e 103/* clear any connection related authentication details */
104void
105authenticateOnCloseConnection(ConnStateData * conn)
106{
107 auth_user_request_t *auth_user_request;
108 assert(conn != NULL);
109 if (conn->auth_user_request != NULL) {
110 auth_user_request = conn->auth_user_request;
111 if (authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection) {
112 authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection(conn);
113 }
114 }
115}
1d620765 116
94439e4e 117/**** PUBLIC FUNCTIONS (ALL GENERIC!) ****/
1d620765 118
94439e4e 119/* send the initial data to an authenticator module */
1d620765 120void
94439e4e 121authenticateStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
1d620765 122{
94439e4e 123 assert(auth_user_request);
74addf6c 124 assert(handler);
94439e4e 125 debug(29, 9) ("authenticateStart: auth_user_request '%d'\n", auth_user_request);
126 if (auth_user_request->auth_user->auth_module > 0)
127 authscheme_list[auth_user_request->auth_user->auth_module - 1].authStart(auth_user_request, handler, data);
128 else
1d620765 129 handler(data, NULL);
94439e4e 130}
131
132/*
133 * Check a auth_user pointer for validity. Does not check passwords, just data
134 * sensability. Broken or Unknown auth_types are not valid for use...
135 */
136
137int
138authenticateValidateUser(auth_user_request_t * auth_user_request)
139{
140 debug(29, 9) ("authenticateValidateUser: Validating Auth_user request '%d'.\n", auth_user_request);
141 if (auth_user_request == NULL) {
142 debug(29, 4) ("authenticateValidateUser: Auth_user_request was NULL!\n");
143 return 0;
1d620765 144 }
94439e4e 145 if (auth_user_request->auth_user == NULL) {
146 debug(29, 4) ("authenticateValidateUser: No associated auth_user structure\n");
147 return 0;
148 }
149 if (auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) {
150 debug(29, 4) ("authenticateValidateUser: Auth_user '%d' uses unknown scheme.\n", auth_user_request->auth_user);
151 return 0;
152 }
153 if (auth_user_request->auth_user->auth_type == AUTH_BROKEN) {
154 debug(29, 4) ("authenticateValidateUser: Auth_user '%d' is broken for it's scheme.\n", auth_user_request->auth_user);
155 return 0;
156 }
157 /* any other sanity checks that we need in the future */
158
159 /* Thus should a module call to something like authValidate */
160
161 /* finally return ok */
162 debug(29, 4) ("authenticateValidateUser: Validated Auth_user request '%d'.\n", auth_user_request);
163 return 1;
164
165}
166
167auth_user_t *
168authenticateAuthUserNew(const char *scheme)
169{
170 auth_user_t *temp_auth;
171 temp_auth = memAllocate(MEM_AUTH_USER_T);
172 assert(temp_auth != NULL);
173 temp_auth->auth_type = AUTH_UNKNOWN;
174 temp_auth->references = 0;
175 temp_auth->auth_module = authenticateAuthSchemeId(scheme) + 1;
176 return temp_auth;
177}
178
179auth_user_request_t *
180authenticateAuthUserRequestNew()
181{
182 auth_user_request_t *temp_request;
183 if (!auth_user_request_pool)
184 auth_user_request_pool = memPoolCreate("Authenticate Request Data", sizeof(auth_user_request_t));
185 temp_request = memPoolAlloc(auth_user_request_pool);
186 assert(temp_request != NULL);
187 temp_request->auth_user = NULL;
188 temp_request->message = NULL;
189 temp_request->scheme_data = NULL;
190 temp_request->references = 0;
191 return temp_request;
1d620765 192}
193
194void
94439e4e 195authenticateAuthUserRequestFree(auth_user_request_t * auth_user_request)
1d620765 196{
94439e4e 197 dlink_node *link;
198 debug(29, 5) ("authenticateAuthUserRequestFree: freeing request %d\n", auth_user_request);
199 if (!auth_user_request)
1d620765 200 return;
94439e4e 201 assert(auth_user_request->references == 0);
202 if (auth_user_request->auth_user) {
203 if (auth_user_request->scheme_data != NULL) {
204 /* we MUST know the module */
205 assert((auth_user_request->auth_user->auth_module > 0));
206 /* and the module MUST support requestFree if it has created scheme data */
207 assert(authscheme_list[auth_user_request->auth_user->auth_module - 1].requestFree != NULL);
208 authscheme_list[auth_user_request->auth_user->auth_module - 1].requestFree(auth_user_request);
209 }
210 /* unlink from the auth_user struct */
211 link = auth_user_request->auth_user->requests.head;
212 while (link && (link->data != auth_user_request))
213 link = link->next;
214 assert(link != NULL);
215 dlinkDelete(link, &auth_user_request->auth_user->requests);
216 dlinkNodeDelete(link);
217
218 /* unlock the request structure's lock */
219 authenticateAuthUserUnlock(auth_user_request->auth_user);
220 auth_user_request->auth_user = NULL;
221 } else
222 assert(auth_user_request->scheme_data == NULL);
223 if (auth_user_request->message)
224 xfree(auth_user_request->message);
225}
226
227char *
228authenticateAuthUserRequestMessage(auth_user_request_t * auth_user_request)
229{
230 if (auth_user_request)
231 return auth_user_request->message;
232 return NULL;
233}
234
235void
236authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr)
237{
238 if (auth_user_request->auth_user)
239 if (!auth_user_request->auth_user->ipaddr.s_addr)
240 auth_user_request->auth_user->ipaddr = ipaddr;
241}
242
243/* Get Auth User: Return a filled out auth_user structure for the given
244 * Proxy Auth (or Auth) header. It may be a cached Auth User or a new
245 * Unauthenticated structure. The structure is given an inital lock here.
246 */
247auth_user_request_t *
248authenticateGetAuthUser(const char *proxy_auth)
249{
250 auth_user_request_t *auth_user_request = authenticateAuthUserRequestNew();
251 /* and lock for the callers instance */
252 authenticateAuthUserRequestLock(auth_user_request);
253 authenticateDecodeAuth(proxy_auth, auth_user_request);
254 return auth_user_request;
255}
256
257/*
258 * authenticateUserAuthenticated: is this auth_user structure logged in ?
259 */
260int
261authenticateUserAuthenticated(auth_user_request_t * auth_user_request)
262{
263 assert(authenticateValidateUser(auth_user_request));
264 if (auth_user_request->auth_user->auth_module > 0)
265 return authscheme_list[auth_user_request->auth_user->auth_module - 1].authenticated(auth_user_request);
266 else
267 return 0;
268}
269
270/*
271 * authenticateAuthenticateUser: log this user request in.
272 * Cache hits may change the auth_user pointer in the structure if needed.
273 * This is basically a handle approach.
274 */
275void
276authenticateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
277{
278 assert(auth_user_request != NULL);
279 if (auth_user_request->auth_user->auth_module > 0)
280 authscheme_list[auth_user_request->auth_user->auth_module - 1].authAuthenticate(auth_user_request, request, conn, type);
281}
282
283/* authenticateUserUsername: return a pointer to the username in the */
284char *
285authenticateUserUsername(auth_user_t * auth_user)
286{
287 if (!auth_user)
288 return NULL;
289 if (auth_user->auth_module > 0)
290 return authscheme_list[auth_user->auth_module - 1].authUserUsername(auth_user);
291 return NULL;
292}
293
294/* authenticateUserRequestUsername: return a pointer to the username in the */
295char *
296authenticateUserRequestUsername(auth_user_request_t * auth_user_request)
297{
298 assert(auth_user_request != NULL);
299 return authenticateUserUsername(auth_user_request->auth_user);
300}
301
302/* returns
303 * 0: no output needed
304 * 1: send to client
305 * -1: send to helper
306 * -2: authenticate broken in some fashion
307 */
308int
309authenticateDirection(auth_user_request_t * auth_user_request)
310{
311 if (!auth_user_request)
312 return -2;
313 if (authenticateUserAuthenticated(auth_user_request))
314 return 0;
315 if (auth_user_request->auth_user->auth_module > 0)
316 return authscheme_list[auth_user_request->auth_user->auth_module - 1].getdirection(auth_user_request);
317 return -2;
318}
319
320int
321authenticateActiveSchemeCount()
322{
323 int i = 0, rv = 0;
324 for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
325 if (authscheme_list[i].Active())
326 rv++;
327 debug(29, 9) ("authenticateActiveSchemeCount: %d active.\n", rv);
328 return rv;
329}
330
331int
332authenticateSchemeCount()
333{
334 int i = 0, rv = 0;
335 for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
336 rv++;
337 debug(29, 9) ("authenticateSchemeCount: %d active.\n", rv);
338 return rv;
339}
340
341void
342authenticateSchemeInit(void)
343{
344 authSchemeSetup();
345}
346
347void
348authenticateInit(authConfig * config)
349{
350 int i;
351 authScheme *scheme;
352 for (i = 0; i < config->n_configured; i++) {
353 if (authscheme_list[i].init) {
354 scheme = config->schemes + i;
355 authscheme_list[i].init(scheme);
356 }
1d620765 357 }
94439e4e 358 if (!proxy_auth_username_cache)
359 authenticateInitUserCache();
1d620765 360}
361
362void
74addf6c 363authenticateShutdown(void)
1d620765 364{
94439e4e 365 int i;
366 debug(29, 2) ("authenticateShutdown: shutting down auth schemes\n");
367 /* find the currently known authscheme types */
368 for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
369 if (authscheme_list[i].donefunc != NULL)
370 authscheme_list[i].donefunc();
371 else
372 debug(29, 2) ("authenticateShutdown: scheme %s has not registered a shutdown function.\n", authscheme_list[i].typestr);
373 authscheme_list[i].typestr = NULL;
374 }
375}
376
377void
378authenticateFixHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated)
379/* send the auth types we are configured to support (and have compiled in!) */
380{
381/* auth_type_t auth_type=err->auth_type;
382 * auth_state_t auth_state=err->auth_state;
383 * char *authchallenge=err->authchallenge;
384 * auth_user_request_t *auth_user_request=err->auth_user_request;
385 */
386 int type = 0;
387 switch (rep->sline.status) {
388 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
389 /* Proxy authorisation needed */
390 type = HDR_PROXY_AUTHENTICATE;
391 break;
392 case HTTP_UNAUTHORIZED:
393 /* WWW Authorisation needed */
394 type = HDR_WWW_AUTHENTICATE;
395 break;
396 default:
397 /* Keep GCC happy */
398 /* some other HTTP status */
399 break;
400 }
401 debug(29, 9) ("authenticateFixHeader: headertype:%d authuser:%d\n", type, auth_user_request);
402 if ((rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
403 || (rep->sline.status == HTTP_UNAUTHORIZED))
404 /* this is a authenticate-needed response */
405 {
406 if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0))
407 authscheme_list[auth_user_request->auth_user->auth_module - 1].authFixHeader(auth_user_request, rep, type, request);
408 else {
409 int i;
410 authScheme *scheme;
411 /* call each configured authscheme */
412 for (i = 0; i < Config.authConfig.n_configured; i++) {
413 scheme = Config.authConfig.schemes + i;
414 if (authscheme_list[scheme->Id].Active())
415 authscheme_list[scheme->Id].authFixHeader(auth_user_request, rep, type,
416 request);
417 else
418 debug(29, 4) ("authenticateFixHeader: Configured scheme %s not Active\n", scheme->typestr);
419 }
420 }
421 }
422 if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
423 && (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader))
424 authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader(auth_user_request, rep, accelerated);
425}
426
427/* call the active auth module and allow it to add a trailer to the request */
428void
429authenticateAddTrailer(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated)
430{
431 if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
432 && (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer))
433 authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer(auth_user_request, rep, accelerated);
434}
435
436void
437authenticateAuthUserLock(auth_user_t * auth_user)
438{
439 debug(29, 9) ("authenticateAuthUserLock auth_user '%d'.\n", auth_user);
440 assert(auth_user != NULL);
441 auth_user->references++;
442 debug(29, 9) ("authenticateAuthUserLock auth_user '%d' now at '%d'.\n", auth_user, auth_user->references);
443}
444
445void
446authenticateAuthUserUnlock(auth_user_t * auth_user)
447{
448 debug(29, 9) ("authenticateAuthUserUnlock auth_user '%d'.\n", auth_user);
449 assert(auth_user != NULL);
450 if (auth_user->references > 0) {
451 auth_user->references--;
452 } else {
453 debug(29, 1) ("Attempt to lower Auth User %d refcount below 0!\n", auth_user);
454 }
455 debug(29, 9) ("authenticateAuthUserUnlock auth_user '%d' now at '%d'.\n", auth_user, auth_user->references);
456 if (auth_user->references == 0)
457 authenticateFreeProxyAuthUser(auth_user);
458}
459
460void
461authenticateAuthUserRequestLock(auth_user_request_t * auth_user_request)
462{
463 debug(29, 9) ("authenticateAuthUserRequestLock auth_user request '%d'.\n", auth_user_request);
464 assert(auth_user_request != NULL);
465 auth_user_request->references++;
466 debug(29, 9) ("authenticateAuthUserRequestLock auth_user request '%d' now at '%d'.\n", auth_user_request, auth_user_request->references);
467}
468
469void
470authenticateAuthUserRequestUnlock(auth_user_request_t * auth_user_request)
471{
472 debug(29, 9) ("authenticateAuthUserRequestUnlock auth_user request '%d'.\n", auth_user_request);
473 assert(auth_user_request != NULL);
474 if (auth_user_request->references > 0) {
475 auth_user_request->references--;
476 } else {
477 debug(29, 1) ("Attempt to lower Auth User request %d refcount below 0!\n", auth_user_request);
478 }
479 debug(29, 9) ("authenticateAuthUserRequestUnlock auth_user_request '%d' now at '%d'.\n", auth_user_request, auth_user_request->references);
480 if (auth_user_request->references == 0) {
481 /* not locked anymore */
482 authenticateAuthUserRequestFree(auth_user_request);
483 }
484}
485
486int
487authenticateAuthUserInuse(auth_user_t * auth_user)
488/* returns 0 for not in use */
489{
490 assert(auth_user != NULL);
491 return auth_user->references;
492}
493
494/* Combine two user structs. ONLY to be called from within a scheme module.
495 * The scheme module is responsible for ensuring that the two users _can_ be merged
496 * without invalidating all the request scheme data.
497 * the scheme is also responsible for merging any user related scheme data itself. */
498void
499authenticateAuthUserMerge(auth_user_t * from, auth_user_t * to)
500{
501 dlink_node *link, *tmplink;
502 auth_user_request_t *auth_user_request;
503/* XXX combine two authuser structs. Incomplete: it should merge in hash references
504 * too and ask the module to merge in scheme data */
505 debug(29, 5) ("authenticateAuthUserMerge auth_user '%d' into auth_user '%d'.\n", from, to);
506 link = from->requests.head;
507 while (link) {
508 auth_user_request = link->data;
509 tmplink = link;
510 link = link->next;
511 dlinkDelete(tmplink, &from->requests);
512 dlinkAddTail(auth_user_request, tmplink, &to->requests);
513 auth_user_request->auth_user = to;
514 }
515 to->references += from->references;
516 from->references = 0;
517 authenticateFreeProxyAuthUser(from);
518}
519
520void
521authenticateFreeProxyAuthUser(void *data)
522{
523 auth_user_t *u = data;
524 auth_user_request_t *auth_user_request;
525#if 0
526 auth_user_hash_pointer *proxy_auth_hash;
527#endif
528 dlink_node *link, *tmplink;
529 assert(data != NULL);
530 debug(29, 5) ("authenticateFreeProxyAuthUser: Freeing auth_user '%d' with refcount '%d'.\n", u, u->references);
531 assert(u->references == 0);
532 /* were they linked in by username ? */
533 if (u->usernamehash) {
534 assert(u->usernamehash->auth_user == u);
535 debug(29, 5) ("authenticateFreeProxyAuthUser: removing usernamehash entry '%d'\n", u->usernamehash);
536 hash_remove_link(proxy_auth_username_cache,
537 (hash_link *) u->usernamehash);
538 /* don't free the key as we use the same user string as the auth_user
539 * structure */
540 memFree(u->usernamehash, MEM_AUTH_USER_HASH);
541 }
542 /* remove any outstanding requests */
543 link = u->requests.head;
544 while (link) {
545 debug(29, 5) ("authenticateFreeProxyAuthUser: removing request entry '%d'\n", link->data);
546 auth_user_request = link->data;
547 tmplink = link;
548 link = link->next;
549 dlinkDelete(tmplink, &u->requests);
550 dlinkNodeDelete(tmplink);
551 authenticateAuthUserRequestFree(auth_user_request);
552 }
553 /* free cached acl results */
554 aclCacheMatchFlush(&u->proxy_match_cache);
555 if (u->scheme_data && u->auth_module > 0)
556 authscheme_list[u->auth_module - 1].FreeUser(u);
557 /* prevent accidental reuse */
558 u->auth_type = AUTH_UNKNOWN;
559 memFree(u, MEM_AUTH_USER_T);
560}
561
562void
563authenticateInitUserCache()
564{
565 if (!proxy_auth_username_cache) {
566 /* First time around, 7921 should be big enough */
567 proxy_auth_username_cache =
568 hash_create((HASHCMP *) strcmp, 7921, hash_string);
569 assert(proxy_auth_username_cache);
570 eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
571 }
572}
573
574void
575authenticateProxyUserCacheCleanup(void *datanotused)
576{
577 /*
578 * We walk the hash by username as that is the unique key we use.
579 * For big hashs we could consider stepping through the cache, 100/200
580 * entries at a time. Lets see how it flys first.
581 */
582 auth_user_hash_pointer *usernamehash;
583 auth_user_t *auth_user;
584 char *username = NULL;
585 debug(29, 3) ("authenticateProxyUserCacheCleanup: Cleaning the user cache now\n");
586 debug(29, 3) ("authenticateProxyUserCacheCleanup: Current time: %d\n", current_time.tv_sec);
587 hash_first(proxy_auth_username_cache);
588 while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
589 auth_user = usernamehash->auth_user;
590 username = authenticateUserUsername(auth_user);
591
592 /* if we need to have inpedendent expiry clauses, insert a module call
593 * here */
594 debug(29, 4) ("authenticateProxyUserCacheCleanup: Cache entry:\n\tType: %d\n\tUsername: %s\n\texpires: %d\n\treferences: %d\n", auth_user->auth_type, username, auth_user->expiretime + Config.authenticateTTL, auth_user->references);
595 if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
596 debug(29, 5) ("authenticateProxyUserCacheCleanup: Removing user %s from cache due to timeout.\n", username);
597 /* the minus 1 accounts for the cache lock */
598 if ((authenticateAuthUserInuse(auth_user) - 1))
599 debug(29, 4) ("authenticateProxyUserCacheCleanup: this cache entry has expired AND has a non-zero ref count.\n");
600 else
601 authenticateAuthUserUnlock(auth_user);
602 }
603 }
604 debug(29, 3) ("authenticateProxyUserCacheCleanup: Finished cleaning the user cache.\n");
605 eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
606}
607
608/*
609 * authenticateUserCacheRestart() cleans all config-dependent data from the
610 * auth_user cache. It DOES NOT Flush the user cache.
611 */
612
613void
614authenticateUserCacheRestart()
615{
616 auth_user_hash_pointer *usernamehash;
617 auth_user_t *auth_user;
618 char *username = NULL;
619 debug(29, 3) ("authenticateUserCacheRestart: Clearing config dependent cache data.\n");
620 hash_first(proxy_auth_username_cache);
621 while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
622 auth_user = usernamehash->auth_user;
623 username = authenticateUserUsername(auth_user);
624 debug(29, 5) ("authenticateUserCacheRestat: Clearing cache ACL results for user: %s\n", username);
625 aclCacheMatchFlush(&auth_user->proxy_match_cache);
626 }
627
628}
629
630/*
631 * called to add another auth scheme module
632 */
633void
634authSchemeAdd(char *type, AUTHSSETUP * setup)
635{
636 int i;
637 /* find the number of currently known authscheme types */
638 for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
639 assert(strcmp(authscheme_list[i].typestr, type) != 0);
640 }
641 /* add the new type */
642 authscheme_list = xrealloc(authscheme_list, (i + 2) * sizeof(authscheme_entry_t));
643 memset(&authscheme_list[i + 1], 0, sizeof(authscheme_entry_t));
644 authscheme_list[i].typestr = type;
645 /* Call the scheme module to set up capabilities and initialize any global data */
646 setup(&authscheme_list[i]);
647}
648
649
650
651/* UserNameCacheAdd: add a auth_user structure to the username cache */
652void
653authenticateUserNameCacheAdd(auth_user_t * auth_user)
654{
655 auth_user_hash_pointer *usernamehash;
656 usernamehash = memAllocate(MEM_AUTH_USER_HASH);
657 usernamehash->key = authenticateUserUsername(auth_user);
658 usernamehash->auth_user = auth_user;
659 hash_join(proxy_auth_username_cache, (hash_link *) usernamehash);
660 auth_user->usernamehash = usernamehash;
661 /* lock for presence in the cache */
662 authenticateAuthUserLock(auth_user);
663}
664
665
666
667/*
668 * check the user for ip changes timeouts
669 * 0 = failed check
670 * 1 = ip requirements are ok.
671 */
672/* TODO:
673 * ip_expire data should be in a struct of it's own - for code reuse */
674int
675authenticateCheckAuthUserIP(struct in_addr request_src_addr, auth_user_request_t * auth_user_request)
676{
677 char *username = authenticateUserRequestUsername(auth_user_request);
678 if (request_src_addr.s_addr == auth_user_request->auth_user->ipaddr.s_addr || auth_user_request->auth_user->ip_expiretime + Config.authenticateIpTTL <= squid_curtime) {
679 /* user has not moved ip or had the ip timeout expire */
680 if ((auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) ||
681 (auth_user_request->auth_user->auth_type == AUTH_BROKEN)) {
682 debug(29, 1) ("authenticateCheckProxyAuthIP: broken or unknown auth type %d.\n", auth_user_request->auth_user->auth_type);
683 return 0;
684 }
685 username = authenticateUserRequestUsername(auth_user_request);
686 /* Update IP ttl */
687 auth_user_request->auth_user->ip_expiretime = squid_curtime;
688 auth_user_request->auth_user->ipaddr = request_src_addr;
689 return 1;
690 } else {
691 char *ip1 = xstrdup(inet_ntoa(auth_user_request->auth_user->ipaddr));
692 char *ip2 = xstrdup(inet_ntoa(request_src_addr));
693 if (Config.onoff.authenticateIpTTLStrict) {
694 debug(29, 1) ("aclMatchProxyAuth: user '%s' tried to use multiple IP addresses! (%s, %s)\n ", username, ip1, ip2);
695 } else {
696 /* Non-strict mode. Reassign ownership to the new IP */
697 auth_user_request->auth_user->ipaddr.s_addr = request_src_addr.s_addr;
698 debug(29, 1) ("aclMatchProxyAuth: user '%s' has changed IP address (%s, %s)\n ", username, ip1, ip2);
699 }
700 safe_free(ip1);
701 safe_free(ip2);
702 /* and deny access */
703 return 0;
704 }
1d620765 705}