]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/UserRequest.cc
Resolve assert in cacheCleanup
[thirdparty/squid.git] / src / auth / UserRequest.cc
CommitLineData
f5691f9c 1/*
262a0e14 2 * $Id$
f5691f9c 3 *
4 * DO NOT MODIFY NEXT 2 LINES:
5 * arch-tag: 6803fde1-d5a2-4c29-9034-1c0c9f650eb4
6 *
7 * DEBUG: section 29 Authenticator
8 * AUTHOR: Robert Collins
9 *
10 * SQUID Web Proxy Cache http://www.squid-cache.org/
11 * ----------------------------------------------------------
12 *
13 * Squid is the result of efforts by numerous individuals from
14 * the Internet community; see the CONTRIBUTORS file for full
15 * details. Many organizations have provided support for Squid's
16 * development; see the SPONSORS file for full details. Squid is
17 * Copyrighted (C) 2001 by the Regents of the University of
18 * California; see the COPYRIGHT file for full details. Squid
19 * incorporates software developed and/or copyrighted by other
20 * sources; see the CREDITS file for full details.
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26ac0430 26 *
f5691f9c 27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
26ac0430 31 *
f5691f9c 32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
35 *
36 */
37
38/* The functions in this file handle authentication.
39 * They DO NOT perform access control or auditing.
40 * See acl.c for access control and client_side.c for auditing */
41
42#include "squid.h"
2d2b0bb7
AR
43#include "auth/UserRequest.h"
44#include "auth/User.h"
3ad63615
AR
45/*#include "auth/Gadgets.h"
46#include "acl/Acl.h"
f5691f9c 47#include "client_side.h"
48*/
2d2b0bb7
AR
49#include "auth/Config.h"
50#include "auth/Scheme.h"
f5691f9c 51#include "HttpReply.h"
52#include "HttpRequest.h"
f5691f9c 53
54/* Generic Functions */
55
f5691f9c 56char const *
57AuthUserRequest::username() const
58{
56a49fda 59 if (user() != NULL)
f5691f9c 60 return user()->username();
61 else
62 return NULL;
63}
64
f5691f9c 65/**** PUBLIC FUNCTIONS (ALL GENERIC!) ****/
66
67/* send the initial data to an authenticator module */
68void
69AuthUserRequest::start(RH * handler, void *data)
70{
71 assert(handler);
bf8fe701 72 debugs(29, 9, "authenticateStart: auth_user_request '" << this << "'");
f5691f9c 73 module_start(handler, data);
74}
75
76/*
77 * Check a auth_user pointer for validity. Does not check passwords, just data
78 * sensability. Broken or Unknown auth_types are not valid for use...
79 */
80
81int
a33a428a 82authenticateValidateUser(AuthUserRequest::Pointer auth_user_request)
f5691f9c 83{
bf8fe701 84 debugs(29, 9, "authenticateValidateUser: Validating Auth_user request '" << auth_user_request << "'.");
f5691f9c 85
a33a428a 86 if (auth_user_request.getRaw() == NULL) {
bf8fe701 87 debugs(29, 4, "authenticateValidateUser: Auth_user_request was NULL!");
f5691f9c 88 return 0;
89 }
90
91 if (auth_user_request->user() == NULL) {
bf8fe701 92 debugs(29, 4, "authenticateValidateUser: No associated auth_user structure");
f5691f9c 93 return 0;
94 }
95
96 if (auth_user_request->user()->auth_type == AUTH_UNKNOWN) {
bf8fe701 97 debugs(29, 4, "authenticateValidateUser: Auth_user '" << auth_user_request->user() << "' uses unknown scheme.");
f5691f9c 98 return 0;
99 }
100
101 if (auth_user_request->user()->auth_type == AUTH_BROKEN) {
bf8fe701 102 debugs(29, 4, "authenticateValidateUser: Auth_user '" << auth_user_request->user() << "' is broken for it's scheme.");
f5691f9c 103 return 0;
104 }
105
106 /* any other sanity checks that we need in the future */
107
108 /* Thus should a module call to something like authValidate */
109
110 /* finally return ok */
bf8fe701 111 debugs(29, 5, "authenticateValidateUser: Validated Auth_user request '" << auth_user_request << "'.");
f5691f9c 112
113 return 1;
114
115}
116
117void *
118AuthUserRequest::operator new (size_t byteCount)
119{
120 fatal ("AuthUserRequest not directly allocatable\n");
121 return (void *)1;
122}
123
124void
125AuthUserRequest::operator delete (void *address)
126{
127 fatal ("AuthUserRequest child failed to override operator delete\n");
128}
129
130AuthUserRequest::AuthUserRequest():_auth_user(NULL), message(NULL),
a33a428a 131 lastReply (AUTH_ACL_CANNOT_AUTHENTICATE)
f5691f9c 132{
a33a428a 133 debugs(29, 5, "AuthUserRequest::AuthUserRequest: initialised request " << this);
f5691f9c 134}
135
136AuthUserRequest::~AuthUserRequest()
137{
ea0695f2 138 assert(RefCountCount()==0);
a33a428a 139 debugs(29, 5, "AuthUserRequest::~AuthUserRequest: freeing request " << this);
f5691f9c 140
56a49fda 141 if (user() != NULL) {
ea0695f2 142#if USER_REQUEST_LOOP_DEAD
edda1244
AJ
143 /* AYJ: something strange: in order to be deleted this object must not be
144 * referenced anywhere. Including the AuthUser list of requests.
145 * I expect the following loop to NEVER find a pointer to this request object.
146 */
ea0695f2
AJ
147 user()->doneRequest(this);
148#endif /* USER_REQUEST_LOOP_DEAD */
edda1244 149
56a49fda 150 /* release our references to the user credentials */
f5691f9c 151 user(NULL);
152 }
153
56a49fda 154 safe_free(message);
f5691f9c 155}
156
157void
56a49fda 158AuthUserRequest::setDenyMessage(char const *aString)
f5691f9c 159{
56a49fda
AJ
160 safe_free(message);
161 message = xstrdup(aString);
f5691f9c 162}
163
164char const *
56a49fda 165AuthUserRequest::getDenyMessage()
f5691f9c 166{
167 return message;
168}
169
170char const *
171AuthUserRequest::denyMessage(char const * const default_message)
172{
173 if (this == NULL || getDenyMessage() == NULL) {
174 return default_message;
175 }
176
177 return getDenyMessage();
178}
179
180static void
a33a428a 181authenticateAuthUserRequestSetIp(AuthUserRequest::Pointer auth_user_request, IpAddress &ipaddr)
f5691f9c 182{
56a49fda 183 AuthUser::Pointer auth_user = auth_user_request->user();
f5691f9c 184
4c19ba24 185 if (!auth_user)
f5691f9c 186 return;
187
4c19ba24 188 auth_user->addIp(ipaddr);
f5691f9c 189}
190
191void
a33a428a 192authenticateAuthUserRequestRemoveIp(AuthUserRequest::Pointer auth_user_request, IpAddress const &ipaddr)
f5691f9c 193{
56a49fda 194 AuthUser::Pointer auth_user = auth_user_request->user();
f5691f9c 195
4c19ba24 196 if (!auth_user)
f5691f9c 197 return;
198
4c19ba24 199 auth_user->removeIp(ipaddr);
f5691f9c 200}
201
202void
a33a428a 203authenticateAuthUserRequestClearIp(AuthUserRequest::Pointer auth_user_request)
f5691f9c 204{
a33a428a 205 if (auth_user_request != NULL)
f5691f9c 206 auth_user_request->user()->clearIp();
207}
208
4b0f5de8 209int
a33a428a 210authenticateAuthUserRequestIPCount(AuthUserRequest::Pointer auth_user_request)
f5691f9c 211{
a33a428a 212 assert(auth_user_request != NULL);
56a49fda 213 assert(auth_user_request->user() != NULL);
f5691f9c 214 return auth_user_request->user()->ipcount;
215}
216
217
218/*
219 * authenticateUserAuthenticated: is this auth_user structure logged in ?
220 */
221int
a33a428a 222authenticateUserAuthenticated(AuthUserRequest::Pointer auth_user_request)
f5691f9c 223{
224 if (!authenticateValidateUser(auth_user_request))
225 return 0;
226
227 return auth_user_request->authenticated();
228}
229
230int
231AuthUserRequest::direction()
232{
233 if (authenticateUserAuthenticated(this))
234 return 0;
235
236 return module_direction();
237
238 return -2;
239}
240
241void
242AuthUserRequest::addHeader(HttpReply * rep, int accelerated)
243{}
244
245void
246AuthUserRequest::addTrailer(HttpReply * rep, int accelerated)
247{}
248
249void
250AuthUserRequest::onConnectionClose(ConnStateData *)
251{}
252
253const char *
254AuthUserRequest::connLastHeader()
255{
256 fatal("AuthUserRequest::connLastHeader should always be overridden by conn based auth schemes");
257 return NULL;
258}
259
260/*
26ac0430 261 * authenticateAuthenticateUser: call the module specific code to
f5691f9c 262 * log this user request in.
263 * Cache hits may change the auth_user pointer in the structure if needed.
264 * This is basically a handle approach.
265 */
266static void
a33a428a 267authenticateAuthenticateUser(AuthUserRequest::Pointer auth_user_request, HttpRequest * request, ConnStateData * conn, http_hdr_type type)
f5691f9c 268{
a33a428a 269 assert(auth_user_request.getRaw() != NULL);
f5691f9c 270
271 auth_user_request->authenticate(request, conn, type);
272}
273
a33a428a
AJ
274static AuthUserRequest::Pointer
275authTryGetUser(AuthUserRequest::Pointer auth_user_request, ConnStateData * conn, HttpRequest * request)
f5691f9c 276{
a33a428a
AJ
277 if (auth_user_request != NULL)
278 return auth_user_request;
279 else if (request != NULL && request->auth_user_request != NULL)
f5691f9c 280 return request->auth_user_request;
4d3a24ca 281 else if (conn != NULL)
f5691f9c 282 return conn->auth_user_request;
283 else
284 return NULL;
285}
286
287/* returns one of
288 * AUTH_ACL_CHALLENGE,
289 * AUTH_ACL_HELPER,
290 * AUTH_ACL_CANNOT_AUTHENTICATE,
291 * AUTH_AUTHENTICATED
292 *
26ac0430 293 * How to use: In your proxy-auth dependent acl code, use the following
f5691f9c 294 * construct:
295 * int rv;
296 * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED)
297 * return rv;
26ac0430 298 *
f5691f9c 299 * when this code is reached, the request/connection is authenticated.
300 *
26ac0430 301 * if you have non-acl code, but want to force authentication, you need a
f5691f9c 302 * callback mechanism like the acl testing routines that will send a 40[1|7] to
26ac0430 303 * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with
f5691f9c 304 * the authenticateStart routine for rv==AUTH_ACL_HELPER
4f0ef8e8 305 *
306 * Caller is responsible for locking and unlocking their *auth_user_request!
f5691f9c 307 */
56a49fda 308AuthAclState
a33a428a 309AuthUserRequest::authenticate(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, IpAddress &src_addr)
f5691f9c 310{
311 const char *proxy_auth;
312 assert(headertype != 0);
313
a9925b40 314 proxy_auth = request->header.getStr(headertype);
f5691f9c 315
316 /*
317 * a note on proxy_auth logix here:
318 * proxy_auth==NULL -> unauthenticated request || already
319 * authenticated connection so we test for an authenticated
320 * connection when we recieve no authentication header.
321 */
322
a33a428a 323 if (((proxy_auth == NULL) && (!authenticateUserAuthenticated(authTryGetUser(*auth_user_request,conn,request))))
26ac0430 324 || (conn != NULL && conn->auth_type == AUTH_BROKEN)) {
f5691f9c 325 /* no header or authentication failed/got corrupted - restart */
bf8fe701 326 debugs(29, 4, "authenticateAuthenticate: broken auth or no proxy_auth header. Requesting auth header.");
f5691f9c 327 /* something wrong with the AUTH credentials. Force a new attempt */
328
4d3a24ca 329 if (conn != NULL) {
f5691f9c 330 conn->auth_type = AUTH_UNKNOWN;
a33a428a 331 conn->auth_user_request = NULL;
f5691f9c 332 }
333
26ac0430 334 *auth_user_request = NULL;
f5691f9c 335 return AUTH_ACL_CHALLENGE;
336 }
337
338 /*
339 * Is this an already authenticated connection with a new auth header?
26ac0430 340 * No check for function required in the if: its compulsory for conn based
f5691f9c 341 * auth modules
342 */
a33a428a 343 if (proxy_auth && conn != NULL && conn->auth_user_request != NULL &&
f5691f9c 344 authenticateUserAuthenticated(conn->auth_user_request) &&
6bf4f823 345 conn->auth_user_request->connLastHeader() != NULL &&
26ac0430 346 strcmp(proxy_auth, conn->auth_user_request->connLastHeader())) {
bf8fe701 347 debugs(29, 2, "authenticateAuthenticate: DUPLICATE AUTH - authentication header on already authenticated connection!. AU " <<
348 conn->auth_user_request << ", Current user '" <<
349 conn->auth_user_request->username() << "' proxy_auth " <<
350 proxy_auth);
351
f5691f9c 352 /* remove this request struct - the link is already authed and it can't be to
353 * reauth.
354 */
355
356 /* This should _only_ ever occur on the first pass through
26ac0430 357 * authenticateAuthenticate
f5691f9c 358 */
359 assert(*auth_user_request == NULL);
a33a428a 360 conn->auth_user_request = NULL;
f5691f9c 361 /* Set the connection auth type */
362 conn->auth_type = AUTH_UNKNOWN;
363 }
364
365 /* we have a proxy auth header and as far as we know this connection has
366 * not had bungled connection oriented authentication happen on it. */
bf8fe701 367 debugs(29, 9, "authenticateAuthenticate: header " << (proxy_auth ? proxy_auth : "-") << ".");
f5691f9c 368
26ac0430 369 if (*auth_user_request == NULL) {
bf8fe701 370 debugs(29, 9, "authenticateAuthenticate: This is a new checklist test on FD:" << (conn != NULL ? conn->fd : -1) );
f5691f9c 371
a33a428a 372 if (proxy_auth && request->auth_user_request == NULL && conn != NULL && conn->auth_user_request != NULL) {
6bf4f823 373 AuthConfig * scheme = AuthConfig::Find(proxy_auth);
638b2ce3 374
6bf4f823 375 if (!conn->auth_user_request->user() || conn->auth_user_request->user()->config != scheme) {
bf8fe701 376 debugs(29, 1, "authenticateAuthenticate: Unexpected change of authentication scheme from '" <<
377 conn->auth_user_request->user()->config->type() <<
378 "' to '" << proxy_auth << "' (client " <<
cc192b50 379 src_addr << ")");
bf8fe701 380
a33a428a 381 conn->auth_user_request = NULL;
638b2ce3 382 conn->auth_type = AUTH_UNKNOWN;
383 }
384 }
385
f5691f9c 386 if ((!request->auth_user_request)
4d3a24ca 387 && (conn == NULL || conn->auth_type == AUTH_UNKNOWN)) {
f5691f9c 388 /* beginning of a new request check */
bf8fe701 389 debugs(29, 4, "authenticateAuthenticate: no connection authentication type");
f5691f9c 390
26ac0430 391 *auth_user_request = AuthConfig::CreateAuthUser(proxy_auth);
4f0ef8e8 392 if (!authenticateValidateUser(*auth_user_request)) {
f5691f9c 393 if (*auth_user_request == NULL)
394 return AUTH_ACL_CHALLENGE;
395
396 /* the decode might have left a username for logging, or a message to
397 * the user */
398
399 if ((*auth_user_request)->username()) {
f5691f9c 400 request->auth_user_request = *auth_user_request;
401 }
402
f5691f9c 403 *auth_user_request = NULL;
f5691f9c 404 return AUTH_ACL_CHALLENGE;
405 }
406
407 /* the user_request comes prelocked for the caller to createAuthUser (us) */
a33a428a 408 } else if (request->auth_user_request != NULL) {
f5691f9c 409 *auth_user_request = request->auth_user_request;
f5691f9c 410 } else {
4d3a24ca 411 assert (conn != NULL);
a33a428a 412 if (conn->auth_user_request != NULL) {
f5691f9c 413 *auth_user_request = conn->auth_user_request;
f5691f9c 414 } else {
415 /* failed connection based authentication */
bf8fe701 416 debugs(29, 4, "authenticateAuthenticate: Auth user request " <<
417 *auth_user_request << " conn-auth user request " <<
418 conn->auth_user_request << " conn type " <<
419 conn->auth_type << " authentication failed.");
420
f5691f9c 421 *auth_user_request = NULL;
422 return AUTH_ACL_CHALLENGE;
423 }
424 }
425 }
426
26ac0430 427 if (!authenticateUserAuthenticated(*auth_user_request)) {
f5691f9c 428 /* User not logged in. Log them in */
a33a428a 429 authenticateAuthenticateUser(*auth_user_request, request, conn, headertype);
f5691f9c 430
431 switch (authenticateDirection(*auth_user_request)) {
432
433 case 1:
434
a33a428a 435 if (request->auth_user_request == NULL) {
f5691f9c 436 request->auth_user_request = *auth_user_request;
437 }
438
439 /* fallthrough to -2 */
440
441 case -2:
4f0ef8e8 442 /* this ACL check is finished. */
f5691f9c 443 *auth_user_request = NULL;
f5691f9c 444 return AUTH_ACL_CHALLENGE;
445
446 case -1:
447 /* we are partway through authentication within squid,
448 * the *auth_user_request variables stores the auth_user_request
449 * for the callback to here - Do not Unlock */
450 return AUTH_ACL_HELPER;
451 }
452
453 /* on 0 the authentication is finished - fallthrough */
454 /* See if user authentication failed for some reason */
455 if (!authenticateUserAuthenticated(*auth_user_request)) {
456 if ((*auth_user_request)->username()) {
457 if (!request->auth_user_request) {
f5691f9c 458 request->auth_user_request = *auth_user_request;
459 }
460 }
461
f5691f9c 462 *auth_user_request = NULL;
f5691f9c 463 return AUTH_ACL_CHALLENGE;
464 }
465 }
466
467 /* copy username to request for logging on client-side */
468 /* the credentials are correct at this point */
a33a428a 469 if (request->auth_user_request == NULL) {
f5691f9c 470 request->auth_user_request = *auth_user_request;
f5691f9c 471 authenticateAuthUserRequestSetIp(*auth_user_request, src_addr);
472 }
473
f5691f9c 474 return AUTH_AUTHENTICATED;
475}
476
56a49fda 477AuthAclState
a33a428a 478AuthUserRequest::tryToAuthenticateAndSetAuthUser(AuthUserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, IpAddress &src_addr)
f5691f9c 479{
480 /* If we have already been called, return the cached value */
a33a428a 481 AuthUserRequest::Pointer t = authTryGetUser(*auth_user_request, conn, request);
f5691f9c 482
a33a428a
AJ
483 if (t != NULL && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE && t->lastReply != AUTH_ACL_HELPER) {
484 if (*auth_user_request == NULL)
f5691f9c 485 *auth_user_request = t;
486
a33a428a 487 if (request->auth_user_request == NULL && t->lastReply == AUTH_AUTHENTICATED) {
26ac0430 488 request->auth_user_request = t;
26ac0430 489 }
f5691f9c 490 return t->lastReply;
491 }
492
493 /* ok, call the actual authenticator routine. */
56a49fda 494 AuthAclState result = authenticate(auth_user_request, headertype, request, conn, src_addr);
f5691f9c 495
a33a428a 496 t = authTryGetUser(*auth_user_request, conn, request);
f5691f9c 497
a33a428a 498 if (t != NULL && result != AUTH_ACL_CANNOT_AUTHENTICATE && result != AUTH_ACL_HELPER)
f5691f9c 499 t->lastReply = result;
500
501 return result;
502}
503
504/* returns
505 * 0: no output needed
506 * 1: send to client
507 * -1: send to helper
508 * -2: authenticate broken in some fashion
509 */
510int
a33a428a 511authenticateDirection(AuthUserRequest::Pointer auth_user_request)
f5691f9c 512{
a33a428a 513 if (auth_user_request == NULL)
f5691f9c 514 return -2;
515
516 return auth_user_request->direction();
517}
518
519void
a33a428a 520AuthUserRequest::addReplyAuthHeader(HttpReply * rep, AuthUserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal)
f5691f9c 521/* send the auth types we are configured to support (and have compiled in!) */
522{
523 http_hdr_type type;
524
26ac0430 525 switch (rep->sline.status) {
f5691f9c 526
527 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
528 /* Proxy authorisation needed */
529 type = HDR_PROXY_AUTHENTICATE;
530 break;
531
532 case HTTP_UNAUTHORIZED:
533 /* WWW Authorisation needed */
534 type = HDR_WWW_AUTHENTICATE;
535 break;
536
537 default:
538 /* Keep GCC happy */
539 /* some other HTTP status */
540 type = HDR_ENUM_END;
541 break;
542 }
543
bf8fe701 544 debugs(29, 9, "authenticateFixHeader: headertype:" << type << " authuser:" << auth_user_request);
f5691f9c 545
546 if (((rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
547 || (rep->sline.status == HTTP_UNAUTHORIZED)) && internal)
548 /* this is a authenticate-needed response */
549 {
550
8d3b341e 551 if ((auth_user_request != NULL) && authenticateDirection(auth_user_request) == 1)
f5691f9c 552 /* scheme specific */
553 auth_user_request->user()->config->fixHeader(auth_user_request, rep, type, request);
26ac0430 554 else {
f5691f9c 555 /* call each configured & running authscheme */
556
5817ee13 557 for (Auth::authConfig::iterator i = Auth::TheConfig.begin(); i != Auth::TheConfig.end(); ++i) {
f5691f9c 558 AuthConfig *scheme = *i;
559
560 if (scheme->active())
561 scheme->fixHeader(NULL, rep, type, request);
562 else
bf8fe701 563 debugs(29, 4, "authenticateFixHeader: Configured scheme " << scheme->type() << " not Active");
f5691f9c 564 }
565 }
566
567 }
568 /*
569 * allow protocol specific headers to be _added_ to the existing
570 * response - ie digest auth
571 */
572
26ac0430 573 if (auth_user_request != NULL) {
f5691f9c 574 auth_user_request->addHeader(rep, accelerated);
26ac0430
AJ
575 if (auth_user_request->lastReply != AUTH_AUTHENTICATED)
576 auth_user_request->lastReply = AUTH_ACL_CANNOT_AUTHENTICATE;
f5691f9c 577 }
578}
579
580void
a33a428a 581authenticateFixHeader(HttpReply * rep, AuthUserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal)
f5691f9c 582{
583 AuthUserRequest::addReplyAuthHeader(rep, auth_user_request, request, accelerated, internal);
584}
585
586
587/* call the active auth module and allow it to add a trailer to the request */
588void
a33a428a 589authenticateAddTrailer(HttpReply * rep, AuthUserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated)
f5691f9c 590{
591 if (auth_user_request != NULL)
592 auth_user_request->addTrailer(rep, accelerated);
593}
594
5817ee13 595AuthScheme::Pointer
f5691f9c 596AuthUserRequest::scheme() const
597{
598 /* TODO: this should be overriden by the child and be essentially a no-op */
599 return AuthScheme::Find(user()->config->type());
600}