]> git.ipfire.org Git - thirdparty/squid.git/blame - src/authenticate.cc
Bootstrapped
[thirdparty/squid.git] / src / authenticate.cc
CommitLineData
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 43CBDATA_TYPE(auth_user_ip_t);
44
94439e4e 45/*
46 *
47 * Private Data
48 *
49 */
50
e6ccf245 51MemPool *AuthUserRequest::pool = NULL;
52MemPool *AuthUserHashPointer::pool = NULL;
53MemPool *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 62static int
94439e4e 63authenticateAuthSchemeConfigured(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 76int
77authenticateAuthSchemeId(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 88void
e6ccf245 89AuthUserRequest::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
104size_t
105AuthUserRequest::refCount () const
106{
107 return references;
108}
109
110char const *
111AuthUserRequest::username() const
112{
113 if (auth_user)
114 return auth_user->username();
115 else
116 return NULL;
117}
118
119size_t
120authenticateRequestRefCount (auth_user_request_t *aRequest)
121{
122 return aRequest->refCount();
1d620765 123}
124
94439e4e 125/* clear any connection related authentication details */
126void
127authenticateOnCloseConnection(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 146void
e6ccf245 147AuthUserRequest::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 157void
158authenticateStart(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
169int
170authenticateValidateUser(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 203void *
768cb287 204AuthUser::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
213AuthUser::AuthUser (const char *scheme) :
214auth_type (AUTH_UNKNOWN), auth_module (authenticateAuthSchemeId(scheme) + 1),
215usernamehash (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
223char const *
224AuthUser::username () const
225{
226 if (auth_module <= 0)
227 return NULL;
228 return authscheme_list[auth_module - 1].authUserUsername(this);
229}
230
94439e4e 231auth_user_t *
232authenticateAuthUserNew(const char *scheme)
233{
e6ccf245 234 return new AuthUser (scheme);
94439e4e 235}
236
e6ccf245 237void *
768cb287 238AuthUserRequest::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 247void
248AuthUserRequest::operator delete (void *address)
249{
250 memPoolFree(pool, address);
251}
252
253AuthUserRequest::AuthUserRequest():auth_user(NULL), scheme_data (NULL), message(NULL),
254 references (0), lastReply (AUTH_ACL_CANNOT_AUTHENTICATE)
255{
256}
257
258AuthUserRequest::~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 287void
288AuthUserRequest::setDenyMessage (char const *aString)
289{
290 safe_free (message);
291 message = xstrdup (aString);
292}
293
294char const *
295AuthUserRequest::getDenyMessage ()
296{
297 return message;
298}
299
300char const *
94439e4e 301authenticateAuthUserRequestMessage(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 308void
309authenticateSetDenyMessage (auth_user_request_t * auth_user_request, char const *message)
310{
311 auth_user_request->setDenyMessage (message);
312}
313
64f904ee 314static void
94439e4e 315authenticateAuthUserRequestSetIp(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
365void
366authenticateAuthUserRequestRemoveIp(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 390static void
391authenticateAuthUserClearIp(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
412void
413authenticateAuthUserRequestClearIp(auth_user_request_t * auth_user_request)
414{
415 if (auth_user_request)
416 authenticateAuthUserClearIp(auth_user_request->auth_user);
417}
418
419size_t
420authenticateAuthUserRequestIPCount(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 432auth_user_request_t *
433AuthUserRequest::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 */
446int
447authenticateUserAuthenticated(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 463static void
94439e4e 464authenticateAuthenticateUser(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 471static auth_user_request_t *
472authTryGetUser (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 */
501auth_acl_t
e6ccf245 502AuthUserRequest::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 648auth_acl_t
e6ccf245 649AuthUserRequest::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 668auth_acl_t
669authenticateTryToAuthenticateAndSetAuthUser(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 675char const *
94439e4e 676authenticateUserRequestUsername(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 */
688int
689authenticateDirection(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
700int
2d72d4fd 701authenticateActiveSchemeCount(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
711int
2d72d4fd 712authenticateSchemeCount(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
721void
722authenticateSchemeInit(void)
723{
724 authSchemeSetup();
725}
726
727void
728authenticateInit(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 742void
74addf6c 743authenticateShutdown(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
762void
e6ccf245 763AuthUserRequest::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 814void
815authenticateFixHeader(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 */
822void
823authenticateAddTrailer(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
830void
831authenticateAuthUserLock(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
839void
840authenticateAuthUserUnlock(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
854void
e6ccf245 855AuthUserRequest::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
863void
e6ccf245 864AuthUserRequest::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
879void
880authenticateAuthUserRequestLock(auth_user_request_t * auth_user_request)
881{
882 auth_user_request->lock();
94439e4e 883}
884
e6ccf245 885void
886authenticateAuthUserRequestUnlock(auth_user_request_t * auth_user_request)
887{
888 auth_user_request->unlock();
889}
890
891
94439e4e 892int
893authenticateAuthUserInuse(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 906void
e6ccf245 907AuthUser::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
930void
931authenticateAuthUserMerge(auth_user_t * from, auth_user_t * to)
932{
933 to->absorb (from);
94439e4e 934}
935
936void
e6ccf245 937AuthUser::operator delete (void *address)
938{
939 memPoolFree(pool, address);
940}
941
942AuthUser::~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
979void
e6ccf245 980AuthUser::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
991void
e6ccf245 992AuthUser::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
1032void
2d72d4fd 1033authenticateUserCacheRestart(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 */
1049void
a2c963ae 1050authSchemeAdd(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
1069void
1070AuthUserHashPointer::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 1082void *
768cb287 1083AuthUserHashPointer::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 1091void
e6ccf245 1092AuthUserHashPointer::operator delete (void *address)
94439e4e 1093{
e6ccf245 1094 memPoolFree(pool, address);
1095}
1096
1097AuthUserHashPointer::AuthUserHashPointer (auth_user_t * anAuth_user):
4a8b20e8 1098auth_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
1107AuthUser *
1108AuthUserHashPointer::user() const
1109{
1110 return auth_user;
1111}
1112
1113/* C bindings */
1114/* UserNameCacheAdd: add a auth_user structure to the username cache */
1115void
1116authenticateUserNameCacheAdd(auth_user_t * auth_user)
1117{
1118 auth_user->usernamehash = new AuthUserHashPointer (auth_user);
1119}
1120
1121auth_user_t*
1122authUserHashPointerUser (auth_user_hash_pointer *aHashEntry)
1123{
1124 return aHashEntry->user();
1125}
1126