]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ACLChecklist.cc
Incremental merge from rproxy
[thirdparty/squid.git] / src / ACLChecklist.cc
CommitLineData
225b7b10 1/*
66e818e8 2 * $Id: ACLChecklist.cc,v 1.2 2003/02/14 11:56:51 robertc Exp $
225b7b10 3 *
4 * DEBUG: section 28 Access Control
5 * AUTHOR: Duane Wessels
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
34 */
35
36#include "squid.h"
37#include "ACLChecklist.h"
38/* TODO: trim this ! */
39#include "splay.h"
40#include "HttpRequest.h"
41#include "authenticate.h"
42#include "fde.h"
43#include "ACLProxyAuth.h"
44#if USE_IDENT
45#include "ACLIdent.h"
46#endif
47#include "ACLUserData.h"
48
49int
50ACLChecklist::authenticated()
51{
52 http_hdr_type headertype;
53 if (NULL == request) {
54 fatal ("requiresRequest SHOULD have been true for this ACL!!");
66e818e8 55 return 0;
225b7b10 56 } else if (!request->flags.accelerated) {
57 /* Proxy authorization on proxy requests */
58 headertype = HDR_PROXY_AUTHORIZATION;
59 } else if (request->flags.internal) {
60 /* WWW authorization on accelerated internal requests */
61 headertype = HDR_AUTHORIZATION;
62 } else {
63#if AUTH_ON_ACCELERATION
64 /* WWW authorization on accelerated requests */
65 headertype = HDR_AUTHORIZATION;
66#else
67 debug(28, 1) ("ACHChecklist::authenticated: authentication not applicable on accelerated requests.\n");
68 return -1;
69#endif
70 }
71 /* get authed here */
72 /* Note: this fills in auth_user_request when applicable */
73 switch (authenticateTryToAuthenticateAndSetAuthUser(&auth_user_request, headertype, request, conn(), src_addr)) {
74 case AUTH_ACL_CANNOT_AUTHENTICATE:
75 debug(28, 4) ("aclMatchAcl: returning 0 user authenticated but not authorised.\n");
76 return 0;
77 case AUTH_AUTHENTICATED:
78 return 1;
79 break;
80 case AUTH_ACL_HELPER:
81 debug(28, 4) ("aclMatchAcl: returning 0 sending credentials to helper.\n");
82 changeState (ProxyAuthLookup::Instance());
83 return 0;
84 case AUTH_ACL_CHALLENGE:
85 debug(28, 4) ("aclMatchAcl: returning 0 sending authentication challenge.\n");
86 changeState (ProxyAuthNeeded::Instance());
87 return 0;
88 default:
89 fatal("unexpected authenticateAuthenticate reply\n");
90 return 0;
91 }
92}
93
94allow_t const &
95ACLChecklist::currentAnswer() const
96{
97 return allow_;
98}
99
100void
101ACLChecklist::currentAnswer(allow_t const newAnswer)
102{
103 allow_ = newAnswer;
104}
105
106void
107ACLChecklist::check()
108{
109 /* deny if no rules present */
110 currentAnswer(ACCESS_DENIED);
111 /* NOTE: This holds a cbdata reference to the current access_list
112 * entry, not the whole list.
113 */
114 while (accessList != NULL) {
115 /*
116 * If the _acl_access is no longer valid (i.e. its been
117 * freed because of a reconfigure), then bail on this
118 * access check. For now, return ACCESS_DENIED.
119 */
120 if (!cbdataReferenceValid(accessList)) {
121 cbdataReferenceDone(accessList);
122 break;
123 }
124
125 checkAccessList();
126 if (asyncInProgress())
127 return;
128
129 if (finished()) {
130 /*
131 * We are done. Either the request
132 * is allowed, denied, requires authentication.
133 */
134 debug(28, 3) ("ACLChecklist::check: match found, returning %d\n", currentAnswer());
135 cbdataReferenceDone(accessList); /* A */
136 checkCallback(currentAnswer());
137 /* From here on in, this may be invalid */
138 return;
139 }
140 /*
141 * Reference the next access entry
142 */
143 const acl_access *A = accessList;
144 accessList = cbdataReference(accessList->next);
145 cbdataReferenceDone(A);
146 }
147 /* dropped off the end of the list */
148 debug(28, 3) ("ACLChecklist::check: NO match found, returning %d\n",
149 currentAnswer() != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED);
150 checkCallback(currentAnswer() != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED);
151}
152
153bool
154ACLChecklist::asyncInProgress() const
155{
156 return async_;
157}
158
159void
160ACLChecklist::asyncInProgress(bool const newAsync)
161{
162 assert (!finished());
163 async_ = newAsync;
164 debug (28,3)("ACLChecklist::asyncInProgress: async set to %d\n",async_);
165}
166
167bool
168ACLChecklist::finished() const
169{
170 return finished_;
171}
172
173void
174ACLChecklist::markFinished()
175{
176 assert (!finished());
177 finished_ = true;
178 debug (28,3)("checklist processing finished\n");
179}
180
181void
182ACLChecklist::checkAccessList()
183{
184 debug(28, 3) ("ACLChecklist::checkAccessList: checking '%s'\n", accessList->cfgline);
185 /* what is our result on a match? */
186 currentAnswer(accessList->allow);
187 /* does the current AND clause match */
188 bool match = matchAclList(accessList->aclList);
189 if (match)
190 markFinished();
191 /* Should be else, but keep the exact same flow as before */
192 checkForAsync();
193}
194
195void
196ACLChecklist::checkForAsync()
197{
198 /* check for async lookups needed. */
199 if (asyncState() != NullState::Instance()) {
200 /* If a state object is here, use it.
201 * When all cases are converted, the if goes away and it
202 * becomes unconditional.
203 * RBC 02 2003
204 */
205 asyncState()->checkForAsync(this);
206 } else if (state[ACL_DST_ASN] == ACL_LOOKUP_NEEDED) {
207 state[ACL_DST_ASN] = ACL_LOOKUP_PENDING;
208 ipcache_nbgethostbyname(request->host,
209 aclLookupDstIPforASNDone, this);
210 asyncInProgress(true);
211 } else if (state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NEEDED) {
212 state[ACL_SRC_DOMAIN] = ACL_LOOKUP_PENDING;
213 fqdncache_nbgethostbyaddr(src_addr,
214 aclLookupSrcFQDNDone, this);
215 asyncInProgress(true);
216 } else if (state[ACL_DST_DOMAIN] == ACL_LOOKUP_NEEDED) {
217 ipcache_addrs *ia;
218 ia = ipcacheCheckNumeric(request->host);
219 if (ia == NULL) {
220 state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
221 } else {
222 dst_addr = ia->in_addrs[0];
223 state[ACL_DST_DOMAIN] = ACL_LOOKUP_PENDING;
224 fqdncache_nbgethostbyaddr(dst_addr,
225 aclLookupDstFQDNDone, this);
226 }
227 asyncInProgress(true);
228#if USE_IDENT
229 } else if (state[ACL_IDENT] == ACL_LOOKUP_NEEDED) {
230 debug(28, 3) ("ACLChecklist::checkForAsync: Doing ident lookup\n");
231 if (conn() && cbdataReferenceValid(conn())) {
232 identStart(&conn()->me, &conn()->peer,
233 aclLookupIdentDone, this);
234 state[ACL_IDENT] = ACL_LOOKUP_PENDING;
235 } else {
236 debug(28, 1) ("ACLChecklist::checkForAsync: Can't start ident lookup. No client connection\n");
237 currentAnswer(ACCESS_DENIED);
238 markFinished();
239 return;
240 }
241 asyncInProgress(true);
242#endif
243 }
244}
245
246void
247ACLChecklist::checkCallback(allow_t answer)
248{
249 PF *callback_;
250 void *cbdata_;
251 debug(28, 3) ("ACLChecklist::checkCallback: answer=%d\n", answer);
252 /* During reconfigure, we can end up not finishing call
253 * sequences into the auth code */
254 if (auth_user_request) {
255 /* the checklist lock */
256 authenticateAuthUserRequestUnlock(auth_user_request);
257 /* it might have been connection based */
258 assert(conn());
259 conn()->auth_user_request = NULL;
260 conn()->auth_type = AUTH_BROKEN;
261 auth_user_request = NULL;
262 }
263 callback_ = callback;
264 callback = NULL;
265 if (cbdataReferenceValidDone(callback_data, &cbdata_))
266 callback_(answer, cbdata_);
267 delete this;
268}
269bool
270ACLChecklist::matchAclList(const acl_list * head)
271{
272 PROF_start(aclMatchAclList);
273 const acl_list *node = head;
274 while (node) {
275 if (!node->matches(this)) {
276 debug(28, 3) ("aclmatchAclList: returning false (AND list entry failed to match)\n");
277 PROF_stop(aclMatchAclList);
278 return false;
279 }
280 node = node->next;
281 }
282 debug(28, 3) ("aclmatchAclList: returning true (AND list satisfied)\n");
283 PROF_stop(aclMatchAclList);
284 return true;
285}
286
287CBDATA_CLASS_INIT(ACLChecklist);
288
289void *
290ACLChecklist::operator new (size_t size)
291{
292 assert (size == sizeof(ACLChecklist));
293 CBDATA_INIT_TYPE(ACLChecklist);
294 ACLChecklist *result = cbdataAlloc(ACLChecklist);
295 /* Mark result as being owned - we want the refcounter to do the delete
296 * call */
297 cbdataReference(result);
298 return result;
299}
300
301void
302ACLChecklist::operator delete (void *address)
303{
304 ACLChecklist *t = static_cast<ACLChecklist *>(address);
305 cbdataFree(address);
306 /* And allow the memory to be freed */
307 cbdataReferenceDone (t);
308}
309
310void
311ACLChecklist::deleteSelf() const
312{
313 delete this;
314}
315
316ACLChecklist::ACLChecklist() : accessList (NULL), my_port (0), request (NULL),
317 reply (NULL),
318 auth_user_request (NULL)
319#if SQUID_SNMP
320 ,snmp_community(NULL)
321#endif
322 , callback (NULL),
323 callback_data (NULL),
324 extacl_entry (NULL),
325 conn_(NULL),
326 async_(false),
327 finished_(false),
328 allow_(ACCESS_DENIED),
329 state_(NullState::Instance())
330{
331 memset (&src_addr, '\0', sizeof (struct in_addr));
332 memset (&dst_addr, '\0', sizeof (struct in_addr));
333 memset (&my_addr, '\0', sizeof (struct in_addr));
334 rfc931[0] = '\0';
335 memset (&state, '\0', sizeof (state));
336}
337
338ACLChecklist::~ACLChecklist()
339{
340 assert (!asyncInProgress());
341 if (extacl_entry)
342 cbdataReferenceDone(extacl_entry);
343 if (request)
344 requestUnlink(request);
345 request = NULL;
346 cbdataReferenceDone(conn_);
347 cbdataReferenceDone(accessList);
348}
349
350
351ConnStateData *
352ACLChecklist::conn()
353{
354 return conn_;
355}
356
357void
358ACLChecklist::conn(ConnStateData *aConn)
359{
360 assert (conn() == NULL);
361 conn_ = aConn;
362}
363
364void
365ACLChecklist::AsyncState::changeState (ACLChecklist *checklist, AsyncState *newState) const
366{
367 checklist->changeState(newState);
368}
369
370ACLChecklist::NullState *
371ACLChecklist::NullState::Instance()
372{
373 return &_instance;
374}
375
376void
377ACLChecklist::NullState::checkForAsync(ACLChecklist *) const
378{
379}
380
381ACLChecklist::NullState ACLChecklist::NullState::_instance;
382
383void
384ACLChecklist::changeState (AsyncState *newState)
385{
386 /* only change from null to active and back again,
387 * not active to active.
388 * relax this once conversion to states is complete
389 * RBC 02 2003
390 */
391 assert (state_ == NullState::Instance() || newState == NullState::Instance());
392 state_ = newState;
393}
394
395ACLChecklist::AsyncState *
396ACLChecklist::asyncState() const
397{
398 return state_;
399}
400
401void
402ACLChecklist::nonBlockingCheck(PF * callback_, void *callback_data_)
403{
404 callback = callback_;
405 callback_data = cbdataReference(callback_data_);
406 check();
407}
408