]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl.cc
Summary: Fix non delay pool compiles.
[thirdparty/squid.git] / src / acl.cc
CommitLineData
8213067d 1/*
4fb35c3c 2 * $Id: acl.cc,v 1.297 2003/01/28 01:29:33 robertc Exp $
30a4f2a8 3 *
4 * DEBUG: section 28 Access Control
5 * AUTHOR: Duane Wessels
6 *
2b6662ba 7 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 8 * ----------------------------------------------------------
30a4f2a8 9 *
2b6662ba 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.
30a4f2a8 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
cbdec147 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 32 *
8213067d 33 */
7dd57fa2 34
35#include "squid.h"
4fb35c3c 36#include "ACLChecklist.h"
f32789f4 37#include "splay.h"
528b2c61 38#include "HttpRequest.h"
e6ccf245 39#include "authenticate.h"
ecb04c8c 40#include "fde.h"
f32789f4 41
9bea1d5b 42static void aclParseDomainList(void *curlist);
43static void aclParseUserList(void **current);
44static void aclParseIpList(void *curlist);
45static void aclParseIntlist(void *curlist);
2d72d4fd 46#if SQUID_SNMP
9bea1d5b 47static void aclParseWordList(void *curlist);
2d72d4fd 48#endif
9bea1d5b 49static void aclParseProtoList(void *curlist);
50static void aclParseMethodList(void *curlist);
51static void aclParseTimeSpec(void *curlist);
52static void aclParseIntRange(void *curlist);
9bea1d5b 53static void aclDestroyTimeList(acl_time_data * data);
54static void aclDestroyIntRange(intrange *);
4fb35c3c 55static void aclLookupProxyAuthStart(ACLChecklist * checklist);
9bea1d5b 56static void aclLookupProxyAuthDone(void *data, char *result);
57static struct _acl *aclFindByName(const char *name);
4fb35c3c 58static int aclMatchAcl(struct _acl *, ACLChecklist *);
9bea1d5b 59static int aclMatchTime(acl_time_data * data, time_t when);
e6ccf245 60static int aclMatchUser(void *proxyauth_acl, char const *user);
9bea1d5b 61static int aclMatchIp(void *dataptr, struct in_addr c);
62static int aclMatchDomainList(void *dataptr, const char *);
63static int aclMatchIntegerRange(intrange * data, int i);
9e160ce2 64#if SQUID_SNMP
9bea1d5b 65static int aclMatchWordList(wordlist *, const char *);
9e160ce2 66#endif
9bea1d5b 67static void aclParseUserMaxIP(void *data);
68static void aclDestroyUserMaxIP(void *data);
69static wordlist *aclDumpUserMaxIP(void *data);
70static int aclMatchUserMaxIP(void *, auth_user_request_t *, struct in_addr);
71static squid_acl aclStrToType(const char *s);
72static int decode_addr(const char *, struct in_addr *, struct in_addr *);
4fb35c3c 73static void aclCheck(ACLChecklist * checklist);
3898f57f 74#if USE_IDENT
05832ae1 75static IDCB aclLookupIdentDone;
3898f57f 76#endif
b69f7771 77static IPH aclLookupDstIPDone;
53ad48e6 78static IPH aclLookupDstIPforASNDone;
348b2031 79static FQDNH aclLookupSrcFQDNDone;
80static FQDNH aclLookupDstFQDNDone;
d9572179 81static EAH aclLookupExternalDone;
9bea1d5b 82static wordlist *aclDumpIpList(void *);
83static wordlist *aclDumpDomainList(void *data);
84static wordlist *aclDumpTimeSpecList(acl_time_data *);
85static wordlist *aclDumpRegexList(relist * data);
86static wordlist *aclDumpIntlistList(intlist * data);
87static wordlist *aclDumpIntRangeList(intrange * data);
88static wordlist *aclDumpProtoList(intlist * data);
89static wordlist *aclDumpMethodList(intlist * data);
96da6e88 90static SPLAYCMP aclIpAddrNetworkCompare;
f084f6af 91static SPLAYCMP aclIpNetworkCompare;
92static SPLAYCMP aclHostDomainCompare;
93static SPLAYCMP aclDomainCompare;
94static SPLAYWALKEE aclDumpIpListWalkee;
95static SPLAYWALKEE aclDumpDomainListWalkee;
c68e9c6b 96static SPLAYFREE aclFreeIpData;
f32789f4 97
23351cb2 98#if USE_ARP_ACL
9bea1d5b 99static void aclParseArpList(void *curlist);
100static int decode_eth(const char *asc, char *eth);
101static int aclMatchArp(void *dataptr, struct in_addr c);
102static wordlist *aclDumpArpList(void *);
f084f6af 103static SPLAYCMP aclArpCompare;
bd0c865a 104static SPLAYWALKEE aclDumpArpListWalkee;
23351cb2 105#endif
e6ccf245 106static int aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data, char const *MatchParam);
a7ad6e4e 107#if USE_SSL
108static void aclParseCertList(void *curlist);
4fb35c3c 109static int aclMatchUserCert(void *data, ACLChecklist *);
110static int aclMatchCACert(void *data, ACLChecklist *);
a7ad6e4e 111static wordlist *aclDumpCertList(void *data);
112static void aclDestroyCertList(void *data);
113#endif
23351cb2 114
8203a132 115static squid_acl
9bea1d5b 116aclStrToType(const char *s)
117{
118 if (!strcmp(s, "src"))
119 return ACL_SRC_IP;
120 if (!strcmp(s, "dst"))
121 return ACL_DST_IP;
122 if (!strcmp(s, "myip"))
123 return ACL_MY_IP;
124 if (!strcmp(s, "domain"))
125 return ACL_DST_DOMAIN;
126 if (!strcmp(s, "dstdomain"))
127 return ACL_DST_DOMAIN;
128 if (!strcmp(s, "srcdomain"))
129 return ACL_SRC_DOMAIN;
130 if (!strcmp(s, "dstdom_regex"))
131 return ACL_DST_DOM_REGEX;
132 if (!strcmp(s, "srcdom_regex"))
133 return ACL_SRC_DOM_REGEX;
134 if (!strcmp(s, "time"))
135 return ACL_TIME;
136 if (!strcmp(s, "pattern"))
137 return ACL_URLPATH_REGEX;
138 if (!strcmp(s, "urlpath_regex"))
139 return ACL_URLPATH_REGEX;
140 if (!strcmp(s, "url_regex"))
141 return ACL_URL_REGEX;
142 if (!strcmp(s, "port"))
143 return ACL_URL_PORT;
144 if (!strcmp(s, "myport"))
145 return ACL_MY_PORT;
146 if (!strcmp(s, "maxconn"))
147 return ACL_MAXCONN;
3898f57f 148#if USE_IDENT
9bea1d5b 149 if (!strcmp(s, "ident"))
150 return ACL_IDENT;
151 if (!strcmp(s, "ident_regex"))
152 return ACL_IDENT_REGEX;
3898f57f 153#endif
9bea1d5b 154 if (!strncmp(s, "proto", 5))
155 return ACL_PROTO;
156 if (!strcmp(s, "method"))
157 return ACL_METHOD;
158 if (!strcmp(s, "browser"))
159 return ACL_BROWSER;
fc659d9d 160 if (!strcmp(s, "referer_regex"))
161 return ACL_REFERER_REGEX;
9bea1d5b 162 if (!strcmp(s, "proxy_auth"))
163 return ACL_PROXY_AUTH;
164 if (!strcmp(s, "proxy_auth_regex"))
165 return ACL_PROXY_AUTH_REGEX;
166 if (!strcmp(s, "src_as"))
167 return ACL_SRC_ASN;
168 if (!strcmp(s, "dst_as"))
169 return ACL_DST_ASN;
dba79ac5 170#if SQUID_SNMP
9bea1d5b 171 if (!strcmp(s, "snmp_community"))
172 return ACL_SNMP_COMMUNITY;
dba79ac5 173#endif
6b5fbfee 174#if SRC_RTT_NOT_YET_FINISHED
9bea1d5b 175 if (!strcmp(s, "src_rtt"))
176 return ACL_NETDB_SRC_RTT;
6b5fbfee 177#endif
66c75c41 178#if USE_ARP_ACL
9bea1d5b 179 if (!strcmp(s, "arp"))
180 return ACL_SRC_ARP;
66c75c41 181#endif
9bea1d5b 182 if (!strcmp(s, "req_mime_type"))
183 return ACL_REQ_MIME_TYPE;
184 if (!strcmp(s, "rep_mime_type"))
185 return ACL_REP_MIME_TYPE;
186 if (!strcmp(s, "max_user_ip"))
187 return ACL_MAX_USER_IP;
d9572179 188 if (!strcmp(s, "external"))
189 return ACL_EXTERNAL;
a7ad6e4e 190#if USE_SSL
191 if (!strcmp(s, "user_cert"))
192 return ACL_USER_CERT;
193 if (!strcmp(s, "ca_cert"))
194 return ACL_CA_CERT;
195#endif
9bea1d5b 196 return ACL_NONE;
7dd57fa2 197}
198
56b63fa1 199const char *
9bea1d5b 200aclTypeToStr(squid_acl type)
201{
202 if (type == ACL_SRC_IP)
203 return "src";
204 if (type == ACL_DST_IP)
205 return "dst";
206 if (type == ACL_MY_IP)
207 return "myip";
208 if (type == ACL_DST_DOMAIN)
209 return "dstdomain";
210 if (type == ACL_SRC_DOMAIN)
211 return "srcdomain";
212 if (type == ACL_DST_DOM_REGEX)
213 return "dstdom_regex";
214 if (type == ACL_SRC_DOM_REGEX)
215 return "srcdom_regex";
216 if (type == ACL_TIME)
217 return "time";
218 if (type == ACL_URLPATH_REGEX)
219 return "urlpath_regex";
220 if (type == ACL_URL_REGEX)
221 return "url_regex";
222 if (type == ACL_URL_PORT)
223 return "port";
224 if (type == ACL_MY_PORT)
225 return "myport";
226 if (type == ACL_MAXCONN)
227 return "maxconn";
3898f57f 228#if USE_IDENT
9bea1d5b 229 if (type == ACL_IDENT)
230 return "ident";
231 if (type == ACL_IDENT_REGEX)
232 return "ident_regex";
3898f57f 233#endif
9bea1d5b 234 if (type == ACL_PROTO)
235 return "proto";
236 if (type == ACL_METHOD)
237 return "method";
238 if (type == ACL_BROWSER)
239 return "browser";
fc659d9d 240 if (type == ACL_REFERER_REGEX)
241 return "referer_regex";
9bea1d5b 242 if (type == ACL_PROXY_AUTH)
243 return "proxy_auth";
244 if (type == ACL_PROXY_AUTH_REGEX)
245 return "proxy_auth_regex";
246 if (type == ACL_SRC_ASN)
247 return "src_as";
248 if (type == ACL_DST_ASN)
249 return "dst_as";
dba79ac5 250#if SQUID_SNMP
9bea1d5b 251 if (type == ACL_SNMP_COMMUNITY)
252 return "snmp_community";
dba79ac5 253#endif
6b5fbfee 254#if SRC_RTT_NOT_YET_FINISHED
9bea1d5b 255 if (type == ACL_NETDB_SRC_RTT)
256 return "src_rtt";
6b5fbfee 257#endif
56b63fa1 258#if USE_ARP_ACL
9bea1d5b 259 if (type == ACL_SRC_ARP)
260 return "arp";
56b63fa1 261#endif
9bea1d5b 262 if (type == ACL_REQ_MIME_TYPE)
263 return "req_mime_type";
264 if (type == ACL_REP_MIME_TYPE)
265 return "rep_mime_type";
266 if (type == ACL_MAX_USER_IP)
267 return "max_user_ip";
d9572179 268 if (type == ACL_EXTERNAL)
269 return "external";
a7ad6e4e 270#if USE_SSL
271 if (type == ACL_USER_CERT)
272 return "user_cert";
273 if (type == ACL_CA_CERT)
274 return "ca_cert";
275#endif
9bea1d5b 276 return "ERROR";
56b63fa1 277}
278
1cfdbcf0 279static acl *
9bea1d5b 280aclFindByName(const char *name)
7dd57fa2 281{
9bea1d5b 282 acl *a;
283 for (a = Config.aclList; a; a = a->next)
284 if (!strcasecmp(a->name, name))
285 return a;
286 return NULL;
7dd57fa2 287}
288
fda94b88 289static void
9bea1d5b 290aclParseIntlist(void *curlist)
7dd57fa2 291{
9bea1d5b 292 intlist **Tail;
293 intlist *q = NULL;
294 char *t = NULL;
e6ccf245 295 for (Tail = (intlist **)curlist; *Tail; Tail = &((*Tail)->next));
9bea1d5b 296 while ((t = strtokFile())) {
e6ccf245 297 q = (intlist *)memAllocate(MEM_INTLIST);
9bea1d5b 298 q->i = atoi(t);
299 *(Tail) = q;
300 Tail = &q->next;
7dd57fa2 301 }
7dd57fa2 302}
303
8f663d72 304static void
9bea1d5b 305aclParseIntRange(void *curlist)
306{
307 intrange **Tail;
308 intrange *q = NULL;
309 char *t = NULL;
e6ccf245 310 for (Tail = (intrange **)curlist; *Tail; Tail = &((*Tail)->next));
9bea1d5b 311 while ((t = strtokFile())) {
e6ccf245 312 q = (intrange *)xcalloc(1, sizeof(intrange));
9bea1d5b 313 q->i = atoi(t);
314 t = strchr(t, '-');
315 if (t && *(++t))
316 q->j = atoi(t);
317 else
318 q->j = q->i;
319 *(Tail) = q;
320 Tail = &q->next;
8f663d72 321 }
322}
323
fda94b88 324static void
9bea1d5b 325aclParseProtoList(void *curlist)
7dd57fa2 326{
9bea1d5b 327 intlist **Tail;
328 intlist *q = NULL;
329 char *t = NULL;
c193c972 330 protocol_t protocol;
e6ccf245 331 for (Tail = (intlist **)curlist; *Tail; Tail = &((*Tail)->next));
9bea1d5b 332 while ((t = strtokFile())) {
c193c972 333 protocol = urlParseProtocol(t);
e6ccf245 334 q = (intlist *)memAllocate(MEM_INTLIST);
c193c972 335 q->i = (int) protocol;
9bea1d5b 336 *(Tail) = q;
337 Tail = &q->next;
7dd57fa2 338 }
7dd57fa2 339}
92a6f4b1 340
fda94b88 341static void
9bea1d5b 342aclParseMethodList(void *curlist)
92a6f4b1 343{
9bea1d5b 344 intlist **Tail;
345 intlist *q = NULL;
346 char *t = NULL;
e6ccf245 347 for (Tail = (intlist **)curlist; *Tail; Tail = &((*Tail)->next));
9bea1d5b 348 while ((t = strtokFile())) {
e6ccf245 349 q = (intlist *)memAllocate(MEM_INTLIST);
9bea1d5b 350 q->i = (int) urlParseMethod(t);
351 *(Tail) = q;
352 Tail = &q->next;
92a6f4b1 353 }
92a6f4b1 354}
355
06e6d12a 356/*
357 * Decode a ascii representation (asc) of a IP adress, and place
30a4f2a8 358 * adress and netmask information in addr and mask.
06e6d12a 359 * This function should NOT be called if 'asc' is a hostname!
30a4f2a8 360 */
8203a132 361static int
9bea1d5b 362decode_addr(const char *asc, struct in_addr *addr, struct in_addr *mask)
7dd57fa2 363{
a9245686 364 u_int32_t a;
9bea1d5b 365 int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
30a4f2a8 366
9bea1d5b 367 switch (sscanf(asc, "%d.%d.%d.%d", &a1, &a2, &a3, &a4)) {
30a4f2a8 368 case 4: /* a dotted quad */
9bea1d5b 369 if (!safe_inet_addr(asc, addr)) {
370 debug(28, 0) ("decode_addr: unsafe IP address: '%s'\n", asc);
371 fatal("decode_addr: unsafe IP address");
30a4f2a8 372 }
9bea1d5b 373 break;
30a4f2a8 374 case 1: /* a significant bits value for a mask */
9bea1d5b 375 if (a1 >= 0 && a1 < 33) {
376 addr->s_addr = a1 ? htonl(0xfffffffful << (32 - a1)) : 0;
377 break;
30a4f2a8 378 }
379 default:
9bea1d5b 380 debug(28, 0) ("decode_addr: Invalid IP address '%s'\n", asc);
381 return 0; /* This is not valid address */
30a4f2a8 382 }
383
9bea1d5b 384 if (mask != NULL) { /* mask == NULL if called to decode a netmask */
30a4f2a8 385
9bea1d5b 386 /* Guess netmask */
a9245686 387 a = (u_int32_t) ntohl(addr->s_addr);
9bea1d5b 388 if (!(a & 0xFFFFFFFFul))
389 mask->s_addr = htonl(0x00000000ul);
390 else if (!(a & 0x00FFFFFF))
391 mask->s_addr = htonl(0xFF000000ul);
392 else if (!(a & 0x0000FFFF))
393 mask->s_addr = htonl(0xFFFF0000ul);
394 else if (!(a & 0x000000FF))
395 mask->s_addr = htonl(0xFFFFFF00ul);
396 else
397 mask->s_addr = htonl(0xFFFFFFFFul);
30a4f2a8 398 }
9bea1d5b 399 return 1;
30a4f2a8 400}
401
75e5a32e 402
403#define SCAN_ACL1 "%[0123456789.]-%[0123456789.]/%[0123456789.]"
588b63e8 404#define SCAN_ACL2 "%[0123456789.]-%[0123456789.]%c"
75e5a32e 405#define SCAN_ACL3 "%[0123456789.]/%[0123456789.]"
20a4484e 406#define SCAN_ACL4 "%[0123456789.]%c"
75e5a32e 407
56b63fa1 408static acl_ip_data *
9bea1d5b 409aclParseIpData(const char *t)
410{
411 LOCAL_ARRAY(char, addr1, 256);
412 LOCAL_ARRAY(char, addr2, 256);
413 LOCAL_ARRAY(char, mask, 256);
e6ccf245 414 acl_ip_data *q = (acl_ip_data *)memAllocate(MEM_ACL_IP_DATA);
9bea1d5b 415 acl_ip_data *r;
416 acl_ip_data **Q;
417 struct hostent *hp;
418 char **x;
419 char c;
420 debug(28, 5) ("aclParseIpData: %s\n", t);
421 if (!strcasecmp(t, "all")) {
422 q->addr1.s_addr = 0;
423 q->addr2.s_addr = 0;
424 q->mask.s_addr = 0;
425 return q;
426 }
427 if (sscanf(t, SCAN_ACL1, addr1, addr2, mask) == 3) {
428 (void) 0;
429 } else if (sscanf(t, SCAN_ACL2, addr1, addr2, &c) == 2) {
430 mask[0] = '\0';
431 } else if (sscanf(t, SCAN_ACL3, addr1, mask) == 2) {
432 addr2[0] = '\0';
433 } else if (sscanf(t, SCAN_ACL4, addr1, &c) == 1) {
434 addr2[0] = '\0';
435 mask[0] = '\0';
436 } else if (sscanf(t, "%[^/]/%s", addr1, mask) == 2) {
437 addr2[0] = '\0';
438 } else if (sscanf(t, "%s", addr1) == 1) {
439 /*
440 * Note, must use plain gethostbyname() here because at startup
441 * ipcache hasn't been initialized
442 */
443 if ((hp = gethostbyname(addr1)) == NULL) {
444 debug(28, 0) ("aclParseIpData: Bad host/IP: '%s'\n", t);
445 safe_free(q);
446 return NULL;
447 }
448 Q = &q;
449 for (x = hp->h_addr_list; x != NULL && *x != NULL; x++) {
450 if ((r = *Q) == NULL)
e6ccf245 451 r = *Q = (acl_ip_data *)memAllocate(MEM_ACL_IP_DATA);
9bea1d5b 452 xmemcpy(&r->addr1.s_addr, *x, sizeof(r->addr1.s_addr));
453 r->addr2.s_addr = 0;
454 r->mask.s_addr = no_addr.s_addr; /* 255.255.255.255 */
455 Q = &r->next;
456 debug(28, 3) ("%s --> %s\n", addr1, inet_ntoa(r->addr1));
457 }
458 return q;
459 } else {
460 debug(28, 0) ("aclParseIpData: Bad host/IP: '%s'\n", t);
461 safe_free(q);
462 return NULL;
463 }
464 /* Decode addr1 */
465 if (!decode_addr(addr1, &q->addr1, &q->mask)) {
466 debug(28, 0) ("%s line %d: %s\n",
467 cfg_filename, config_lineno, config_input_line);
468 debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown first address '%s'\n", addr1);
469 safe_free(q);
470 return NULL;
471 }
472 /* Decode addr2 */
473 if (*addr2 && !decode_addr(addr2, &q->addr2, &q->mask)) {
474 debug(28, 0) ("%s line %d: %s\n",
475 cfg_filename, config_lineno, config_input_line);
476 debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown second address '%s'\n", addr2);
477 safe_free(q);
478 return NULL;
479 }
480 /* Decode mask */
481 if (*mask && !decode_addr(mask, &q->mask, NULL)) {
482 debug(28, 0) ("%s line %d: %s\n",
483 cfg_filename, config_lineno, config_input_line);
484 debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown netmask '%s'\n", mask);
485 safe_free(q);
486 return NULL;
487 }
488 if ((q->addr1.s_addr & q->mask.s_addr) != q->addr1.s_addr ||
489 (q->addr2.s_addr & q->mask.s_addr) != q->addr2.s_addr)
490 debug(28, 0) ("aclParseIpData: WARNING: Netmask masks away part of the specified IP in '%s'\n", t);
491 q->addr1.s_addr &= q->mask.s_addr;
492 q->addr2.s_addr &= q->mask.s_addr;
493 /* 1.2.3.4/255.255.255.0 --> 1.2.3.0 */
494 return q;
dfc52ac5 495}
30a4f2a8 496
f32789f4 497/******************/
498/* aclParseIpList */
499/******************/
8bad0cc5 500
fda94b88 501static void
9bea1d5b 502aclParseIpList(void *curlist)
503{
504 char *t = NULL;
e6ccf245 505 splayNode **Top = (splayNode **)curlist;
9bea1d5b 506 acl_ip_data *q = NULL;
507 while ((t = strtokFile())) {
508 q = aclParseIpData(t);
509 while (q != NULL) {
510 *Top = splay_insert(q, *Top, aclIpNetworkCompare);
511 q = q->next;
06e6d12a 512 }
b1ef1220 513 }
8bad0cc5 514}
515
fda94b88 516static void
9bea1d5b 517aclParseTimeSpec(void *curlist)
518{
519 acl_time_data *q = NULL;
520 acl_time_data **Tail;
521 int h1, m1, h2, m2;
522 char *t = NULL;
e6ccf245 523 for (Tail = (acl_time_data **)curlist; *Tail; Tail = &((*Tail)->next));
524 q = (acl_time_data *)memAllocate(MEM_ACL_TIME_DATA);
9bea1d5b 525 while ((t = strtokFile())) {
526 if (*t < '0' || *t > '9') {
527 /* assume its day-of-week spec */
528 while (*t) {
529 switch (*t++) {
92a6f4b1 530 case 'S':
9bea1d5b 531 q->weekbits |= ACL_SUNDAY;
532 break;
92a6f4b1 533 case 'M':
9bea1d5b 534 q->weekbits |= ACL_MONDAY;
535 break;
92a6f4b1 536 case 'T':
9bea1d5b 537 q->weekbits |= ACL_TUESDAY;
538 break;
92a6f4b1 539 case 'W':
9bea1d5b 540 q->weekbits |= ACL_WEDNESDAY;
541 break;
92a6f4b1 542 case 'H':
9bea1d5b 543 q->weekbits |= ACL_THURSDAY;
544 break;
92a6f4b1 545 case 'F':
9bea1d5b 546 q->weekbits |= ACL_FRIDAY;
547 break;
92a6f4b1 548 case 'A':
9bea1d5b 549 q->weekbits |= ACL_SATURDAY;
550 break;
30a4f2a8 551 case 'D':
9bea1d5b 552 q->weekbits |= ACL_WEEKDAYS;
553 break;
80b4b4d0 554 case '-':
9bea1d5b 555 /* ignore placeholder */
556 break;
92a6f4b1 557 default:
9bea1d5b 558 debug(28, 0) ("%s line %d: %s\n",
559 cfg_filename, config_lineno, config_input_line);
560 debug(28, 0) ("aclParseTimeSpec: Bad Day '%c'\n", *t);
561 break;
92a6f4b1 562 }
563 }
9bea1d5b 564 } else {
565 /* assume its time-of-day spec */
566 if (sscanf(t, "%d:%d-%d:%d", &h1, &m1, &h2, &m2) < 4) {
567 debug(28, 0) ("%s line %d: %s\n",
568 cfg_filename, config_lineno, config_input_line);
569 debug(28, 0) ("aclParseTimeSpec: IGNORING Bad time range\n");
570 memFree(q, MEM_ACL_TIME_DATA);
571 return;
92a6f4b1 572 }
9bea1d5b 573 q->start = h1 * 60 + m1;
574 q->stop = h2 * 60 + m2;
575 if (q->start > q->stop) {
576 debug(28, 0) ("%s line %d: %s\n",
577 cfg_filename, config_lineno, config_input_line);
578 debug(28, 0) ("aclParseTimeSpec: IGNORING Reversed time range\n");
579 memFree(q, MEM_ACL_TIME_DATA);
580 return;
92a6f4b1 581 }
582 }
583 }
9bea1d5b 584 if (q->start == 0 && q->stop == 0)
585 q->stop = 23 * 60 + 59;
586 if (q->weekbits == 0)
587 q->weekbits = ACL_ALLWEEK;
588 *(Tail) = q;
589 Tail = &q->next;
7dd57fa2 590}
591
fda94b88 592void
9bea1d5b 593aclParseRegexList(void *curlist)
594{
595 relist **Tail;
596 relist *q = NULL;
597 char *t = NULL;
598 regex_t comp;
599 int errcode;
600 int flags = REG_EXTENDED | REG_NOSUB;
e6ccf245 601 for (Tail = (relist **)curlist; *Tail; Tail = &((*Tail)->next));
9bea1d5b 602 while ((t = strtokFile())) {
603 if (strcmp(t, "-i") == 0) {
604 flags |= REG_ICASE;
605 continue;
0153d498 606 }
9bea1d5b 607 if (strcmp(t, "+i") == 0) {
608 flags &= ~REG_ICASE;
609 continue;
0153d498 610 }
9bea1d5b 611 if ((errcode = regcomp(&comp, t, flags)) != 0) {
612 char errbuf[256];
613 regerror(errcode, &comp, errbuf, sizeof errbuf);
614 debug(28, 0) ("%s line %d: %s\n",
615 cfg_filename, config_lineno, config_input_line);
616 debug(28, 0) ("aclParseRegexList: Invalid regular expression '%s': %s\n",
617 t, errbuf);
618 continue;
1969665d 619 }
e6ccf245 620 q = (relist *)memAllocate(MEM_RELIST);
9bea1d5b 621 q->pattern = xstrdup(t);
622 q->regex = comp;
623 *(Tail) = q;
624 Tail = &q->next;
7dd57fa2 625 }
7dd57fa2 626}
627
2d72d4fd 628#if SQUID_SNMP
fda94b88 629static void
9bea1d5b 630aclParseWordList(void *curlist)
7dd57fa2 631{
9bea1d5b 632 char *t = NULL;
633 while ((t = strtokFile()))
e6ccf245 634 wordlistAdd((wordlist **)curlist, t);
7dd57fa2 635}
2d72d4fd 636#endif
7dd57fa2 637
0009ba2f 638static void
9bea1d5b 639aclParseUserList(void **current)
640{
641 char *t = NULL;
642 acl_user_data *data;
643 splayNode *Top = NULL;
644
645 debug(28, 2) ("aclParseUserList: parsing user list\n");
646 if (*current == NULL) {
647 debug(28, 3) ("aclParseUserList: current is null. Creating\n");
648 *current = memAllocate(MEM_ACL_USER_DATA);
649 }
e6ccf245 650 data = (acl_user_data*)*current;
9bea1d5b 651 Top = data->names;
652 if ((t = strtokFile())) {
653 debug(28, 5) ("aclParseUserList: First token is %s\n", t);
654 if (strcmp("-i", t) == 0) {
655 debug(28, 5) ("aclParseUserList: Going case-insensitive\n");
656 data->flags.case_insensitive = 1;
657 } else if (strcmp("REQUIRED", t) == 0) {
658 debug(28, 5) ("aclParseUserList: REQUIRED-type enabled\n");
659 data->flags.required = 1;
660 } else {
661 if (data->flags.case_insensitive)
662 Tolower(t);
663 Top = splay_insert(xstrdup(t), Top, (SPLAYCMP *) strcmp);
0009ba2f 664 }
665 }
9bea1d5b 666 debug(28, 3) ("aclParseUserList: Case-insensitive-switch is %d\n",
667 data->flags.case_insensitive);
668 /* we might inherit from a previous declaration */
0009ba2f 669
9bea1d5b 670 debug(28, 4) ("aclParseUserList: parsing user list\n");
671 while ((t = strtokFile())) {
672 debug(28, 6) ("aclParseUserList: Got token: %s\n", t);
673 if (data->flags.case_insensitive)
674 Tolower(t);
675 Top = splay_insert(xstrdup(t), Top, (SPLAYCMP *) strcmp);
0009ba2f 676 }
9bea1d5b 677 data->names = Top;
0009ba2f 678}
679
680
f32789f4 681/**********************/
682/* aclParseDomainList */
683/**********************/
fda94b88 684
f32789f4 685static void
9bea1d5b 686aclParseDomainList(void *curlist)
f32789f4 687{
9bea1d5b 688 char *t = NULL;
e6ccf245 689 splayNode **Top = (splayNode **)curlist;
9bea1d5b 690 while ((t = strtokFile())) {
691 Tolower(t);
692 *Top = splay_insert(xstrdup(t), *Top, aclDomainCompare);
f32789f4 693 }
694}
695
a7ad6e4e 696#if USE_SSL
697static void
698aclParseCertList(void *curlist)
699{
700 acl_cert_data **datap = (acl_cert_data **)curlist;
701 splayNode **Top;
702 char *t;
703 char *attribute = strtokFile();
704 if (!attribute)
705 self_destruct();
706 if (*datap) {
707 if (strcasecmp((*datap)->attribute, attribute) != 0)
708 self_destruct();
709 } else {
710 *datap = (acl_cert_data *)memAllocate(MEM_ACL_CERT_DATA);
711 (*datap)->attribute = xstrdup(attribute);
712 }
713 Top = &(*datap)->values;
714 while ((t = strtokFile())) {
715 *Top = splay_insert(xstrdup(t), *Top, aclDomainCompare);
716 }
717}
718
719static int
4fb35c3c 720aclMatchUserCert(void *data, ACLChecklist * checklist)
a7ad6e4e 721{
722 acl_cert_data *cert_data = (acl_cert_data *)data;
723 const char *value;
724 SSL *ssl = fd_table[checklist->conn->fd].ssl;
725
726 if (!ssl)
727 return 0;
728 value = sslGetUserAttribute(ssl, cert_data->attribute);
729 if (!value)
730 return 0;
731 cert_data->values = splay_splay(value, cert_data->values, (SPLAYCMP *) strcmp);
732 return !splayLastResult;
733}
734
735static int
4fb35c3c 736aclMatchCACert(void *data, ACLChecklist * checklist)
a7ad6e4e 737{
738 acl_cert_data *cert_data = (acl_cert_data *)data;
739 const char *value;
740 SSL *ssl = fd_table[checklist->conn->fd].ssl;
741
742 if (!ssl)
743 return 0;
744 value = sslGetCAAttribute(ssl, cert_data->attribute);
745 if (!value)
746 return 0;
747 cert_data->values = splay_splay(value, cert_data->values, (SPLAYCMP *) strcmp);
748 return !splayLastResult;
749}
750
751static void
752aclDestroyCertList(void *curlist)
753{
754 acl_cert_data **datap = (acl_cert_data **)curlist;
755 if (!*datap)
756 return;
757 splay_destroy((*datap)->values, xfree);
758 memFree(*datap, MEM_ACL_CERT_DATA);
759 *datap = NULL;
760}
761
762static void
763aclDumpCertListWalkee(void *node_data, void *outlist)
764{
765 wordlist **wl = (wordlist **)outlist;
766 wordlistAdd(wl, (const char *)node_data);
767}
768
769static wordlist *
770aclDumpCertList(void *curlist)
771{
772 acl_cert_data *data = (acl_cert_data *)curlist;
773 wordlist *wl = NULL;
774 wordlistAdd(&wl, data->attribute);
775 if (data->values)
776 splay_walk(data->values, aclDumpCertListWalkee, &wl);
777 return wl;
778}
779#endif
780
8203a132 781void
9bea1d5b 782aclParseAclLine(acl ** head)
783{
784 /* we're already using strtok() to grok the line */
785 char *t = NULL;
786 acl *A = NULL;
787 LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
788 squid_acl acltype;
789 int new_acl = 0;
790
791 /* snarf the ACL name */
792 if ((t = strtok(NULL, w_space)) == NULL) {
793 debug(28, 0) ("%s line %d: %s\n",
794 cfg_filename, config_lineno, config_input_line);
795 debug(28, 0) ("aclParseAclLine: missing ACL name.\n");
796 return;
797 }
798 xstrncpy(aclname, t, ACL_NAME_SZ);
799 /* snarf the ACL type */
800 if ((t = strtok(NULL, w_space)) == NULL) {
801 debug(28, 0) ("%s line %d: %s\n",
802 cfg_filename, config_lineno, config_input_line);
803 debug(28, 0) ("aclParseAclLine: missing ACL type.\n");
804 return;
805 }
806 if ((acltype = aclStrToType(t)) == ACL_NONE) {
807 debug(28, 0) ("%s line %d: %s\n",
808 cfg_filename, config_lineno, config_input_line);
809 debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", t);
810 return;
811 }
812 if ((A = aclFindByName(aclname)) == NULL) {
813 debug(28, 3) ("aclParseAclLine: Creating ACL '%s'\n", aclname);
e6ccf245 814 A = (acl *)memAllocate(MEM_ACL);
9bea1d5b 815 xstrncpy(A->name, aclname, ACL_NAME_SZ);
816 A->type = acltype;
817 A->cfgline = xstrdup(config_input_line);
818 new_acl = 1;
819 } else {
820 if (acltype != A->type) {
821 debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different type, skipping.\n", A->name);
822 return;
823 }
824 debug(28, 3) ("aclParseAclLine: Appending to '%s'\n", aclname);
825 new_acl = 0;
826 }
827 /*
828 * Here we set AclMatchedName in case we need to use it in a
829 * warning message in aclDomainCompare().
830 */
831 AclMatchedName = aclname; /* ugly */
832 switch (A->type) {
7dd57fa2 833 case ACL_SRC_IP:
30a4f2a8 834 case ACL_DST_IP:
ae2c08a2 835 case ACL_MY_IP:
9bea1d5b 836 aclParseIpList(&A->data);
837 break;
f88bb09c 838 case ACL_SRC_DOMAIN:
7dd57fa2 839 case ACL_DST_DOMAIN:
9bea1d5b 840 aclParseDomainList(&A->data);
841 break;
7dd57fa2 842 case ACL_TIME:
9bea1d5b 843 aclParseTimeSpec(&A->data);
844 break;
7dd57fa2 845 case ACL_URL_REGEX:
6e40f263 846 case ACL_URLPATH_REGEX:
6b8e7481 847 case ACL_BROWSER:
fc659d9d 848 case ACL_REFERER_REGEX:
b347fea3 849 case ACL_SRC_DOM_REGEX:
850 case ACL_DST_DOM_REGEX:
da0a7726 851 case ACL_REQ_MIME_TYPE:
c4ab8329 852 case ACL_REP_MIME_TYPE:
9bea1d5b 853 aclParseRegexList(&A->data);
854 break;
9fdbeb4f 855 case ACL_SRC_ASN:
9bc73deb 856 case ACL_MAXCONN:
9fdbeb4f 857 case ACL_DST_ASN:
9bea1d5b 858 aclParseIntlist(&A->data);
859 break;
60d096f4 860 case ACL_MAX_USER_IP:
9bea1d5b 861 aclParseUserMaxIP(&A->data);
862 break;
6b5fbfee 863#if SRC_RTT_NOT_YET_FINISHED
bd05e3e3 864 case ACL_NETDB_SRC_RTT:
9bea1d5b 865 aclParseIntlist(&A->data);
866 break;
6b5fbfee 867#endif
8f663d72 868 case ACL_URL_PORT:
7e3ce7b9 869 case ACL_MY_PORT:
9bea1d5b 870 aclParseIntRange(&A->data);
871 break;
3898f57f 872#if USE_IDENT
c68e9c6b 873 case ACL_IDENT:
9bea1d5b 874 aclParseUserList(&A->data);
875 break;
145cf928 876 case ACL_IDENT_REGEX:
9bea1d5b 877 aclParseRegexList(&A->data);
878 break;
3898f57f 879#endif
7dd57fa2 880 case ACL_PROTO:
9bea1d5b 881 aclParseProtoList(&A->data);
882 break;
92a6f4b1 883 case ACL_METHOD:
9bea1d5b 884 aclParseMethodList(&A->data);
885 break;
afe95a7e 886 case ACL_PROXY_AUTH:
9bea1d5b 887 if (authenticateSchemeCount() == 0) {
888 debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
94439e4e 889because no authentication schemes were compiled.\n", A->cfgline);
9bea1d5b 890 } else if (authenticateActiveSchemeCount() == 0) {
891 debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
94439e4e 892because no authentication schemes are fully configured.\n", A->cfgline);
9bea1d5b 893 } else {
894 aclParseUserList(&A->data);
c68e9c6b 895 }
9bea1d5b 896 break;
145cf928 897 case ACL_PROXY_AUTH_REGEX:
9bea1d5b 898 if (authenticateSchemeCount() == 0) {
899 debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
94439e4e 900because no authentication schemes were compiled.\n", A->cfgline);
9bea1d5b 901 } else if (authenticateActiveSchemeCount() == 0) {
902 debug(28, 0) ("aclParseAclLine: IGNORING: Proxy Auth ACL '%s' \
94439e4e 903because no authentication schemes are fully configured.\n", A->cfgline);
9bea1d5b 904 } else {
905 aclParseRegexList(&A->data);
145cf928 906 }
9bea1d5b 907 break;
8c37f54d 908#if SQUID_SNMP
909 case ACL_SNMP_COMMUNITY:
9bea1d5b 910 aclParseWordList(&A->data);
911 break;
227e68b6 912#endif
66c75c41 913#if USE_ARP_ACL
914 case ACL_SRC_ARP:
9bea1d5b 915 aclParseArpList(&A->data);
916 break;
66c75c41 917#endif
d9572179 918 case ACL_EXTERNAL:
919 aclParseExternal(&A->data);
920 break;
a7ad6e4e 921#if USE_SSL
922 case ACL_USER_CERT:
923 case ACL_CA_CERT:
924 aclParseCertList(&A->data);
925 break;
926#endif
7dd57fa2 927 case ACL_NONE:
6b5fbfee 928 case ACL_ENUM_MAX:
9bea1d5b 929 fatal("Bad ACL type");
930 break;
931 }
932 /*
933 * Clear AclMatchedName from our temporary hack
934 */
935 AclMatchedName = NULL; /* ugly */
936 if (!new_acl)
937 return;
938 if (A->data == NULL) {
939 debug(28, 0) ("aclParseAclLine: IGNORING invalid ACL: %s\n",
940 A->cfgline);
941 memFree(A, MEM_ACL);
942 return;
943 }
944 /* append */
945 while (*head)
946 head = &(*head)->next;
947 *head = A;
7dd57fa2 948}
949
02922e76 950/* does name lookup, returns page_id */
1810dde6 951err_type
9bea1d5b 952aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name)
e92d33a5 953{
9bea1d5b 954 acl_deny_info_list *A = NULL;
955 acl_name_list *L = NULL;
e92d33a5 956
9bea1d5b 957 A = *head;
958 if (NULL == *head) /* empty list */
959 return ERR_NONE;
960 while (A) {
961 L = A->acl_list;
962 if (NULL == L) /* empty list should never happen, but in case */
963 continue;
964 while (L) {
965 if (!strcmp(name, L->name))
966 return A->err_page_id;
967 L = L->next;
e92d33a5 968 }
9bea1d5b 969 A = A->next;
e92d33a5 970 }
9bea1d5b 971 return ERR_NONE;
e92d33a5 972}
f32789f4 973
1cfdbcf0 974/* does name lookup, returns if it is a proxy_auth acl */
975int
9bea1d5b 976aclIsProxyAuth(const char *name)
1cfdbcf0 977{
9bea1d5b 978 acl *a;
979 if (NULL == name)
980 return 0;
981 if ((a = aclFindByName(name)))
054aa556 982 return a->type == ACL_PROXY_AUTH || a->type == ACL_PROXY_AUTH_REGEX;
1cfdbcf0 983 return 0;
984}
985
986
e92d33a5 987/* maex@space.net (05.09.96)
5e79098a 988 * get the info for redirecting "access denied" to info pages
989 * TODO (probably ;-)
990 * currently there is no optimization for
991 * - more than one deny_info line with the same url
992 * - a check, whether the given acl really is defined
993 * - a check, whether an acl is added more than once for the same url
e92d33a5 994 */
f32789f4 995
8203a132 996void
9bea1d5b 997aclParseDenyInfoLine(acl_deny_info_list ** head)
998{
999 char *t = NULL;
1000 acl_deny_info_list *A = NULL;
1001 acl_deny_info_list *B = NULL;
1002 acl_deny_info_list **T = NULL;
1003 acl_name_list *L = NULL;
1004 acl_name_list **Tail = NULL;
1005
1006 /* first expect a page name */
1007 if ((t = strtok(NULL, w_space)) == NULL) {
1008 debug(28, 0) ("%s line %d: %s\n",
1009 cfg_filename, config_lineno, config_input_line);
1010 debug(28, 0) ("aclParseDenyInfoLine: missing 'error page' parameter.\n");
1011 return;
1012 }
e6ccf245 1013 A = (acl_deny_info_list *)memAllocate(MEM_ACL_DENY_INFO_LIST);
9bea1d5b 1014 A->err_page_id = errorReservePageId(t);
1015 A->err_page_name = xstrdup(t);
1016 A->next = (acl_deny_info_list *) NULL;
1017 /* next expect a list of ACL names */
1018 Tail = &A->acl_list;
1019 while ((t = strtok(NULL, w_space))) {
e6ccf245 1020 L = (acl_name_list *)memAllocate(MEM_ACL_NAME_LIST);
9bea1d5b 1021 xstrncpy(L->name, t, ACL_NAME_SZ);
1022 *Tail = L;
1023 Tail = &L->next;
1024 }
1025 if (A->acl_list == NULL) {
1026 debug(28, 0) ("%s line %d: %s\n",
1027 cfg_filename, config_lineno, config_input_line);
1028 debug(28, 0) ("aclParseDenyInfoLine: deny_info line contains no ACL's, skipping\n");
1029 memFree(A, MEM_ACL_DENY_INFO_LIST);
1030 return;
1031 }
1032 for (B = *head, T = head; B; T = &B->next, B = B->next); /* find the tail */
1033 *T = A;
e92d33a5 1034}
1035
8203a132 1036void
9bea1d5b 1037aclParseAccessLine(acl_access ** head)
1038{
1039 char *t = NULL;
1040 acl_access *A = NULL;
1041 acl_access *B = NULL;
1042 acl_access **T = NULL;
1043
1044 /* first expect either 'allow' or 'deny' */
1045 if ((t = strtok(NULL, w_space)) == NULL) {
1046 debug(28, 0) ("%s line %d: %s\n",
1047 cfg_filename, config_lineno, config_input_line);
1048 debug(28, 0) ("aclParseAccessLine: missing 'allow' or 'deny'.\n");
1049 return;
1050 }
1051 A = cbdataAlloc(acl_access);
1052
1053 if (!strcmp(t, "allow"))
e6ccf245 1054 A->allow = ACCESS_ALLOWED;
9bea1d5b 1055 else if (!strcmp(t, "deny"))
e6ccf245 1056 A->allow = ACCESS_DENIED;
9bea1d5b 1057 else {
1058 debug(28, 0) ("%s line %d: %s\n",
1059 cfg_filename, config_lineno, config_input_line);
1060 debug(28, 0) ("aclParseAccessLine: expecting 'allow' or 'deny', got '%s'.\n", t);
1061 cbdataFree(A);
1062 return;
1063 }
29b8d8d6 1064 aclParseAclList(&A->aclList);
1065 if (A->aclList == NULL) {
9bea1d5b 1066 debug(28, 0) ("%s line %d: %s\n",
1067 cfg_filename, config_lineno, config_input_line);
1068 debug(28, 0) ("aclParseAccessLine: Access line contains no ACL's, skipping\n");
1069 cbdataFree(A);
1070 return;
1071 }
1072 A->cfgline = xstrdup(config_input_line);
1073 /* Append to the end of this list */
1074 for (B = *head, T = head; B; T = &B->next, B = B->next);
1075 *T = A;
1076 /* We lock _acl_access structures in aclCheck() */
d6827718 1077}
1078
1079void
9bea1d5b 1080aclParseAclList(acl_list ** head)
1081{
1082 acl_list *L = NULL;
1083 acl_list **Tail = head; /* sane name in the use below */
1084 acl *a = NULL;
1085 char *t;
1086
1087 /* next expect a list of ACL names, possibly preceeded
1088 * by '!' for negation */
1089 while ((t = strtok(NULL, w_space))) {
e6ccf245 1090 L = (acl_list *)memAllocate(MEM_ACL_LIST);
9bea1d5b 1091 L->op = 1; /* defaults to non-negated */
1092 if (*t == '!') {
1093 /* negated ACL */
1094 L->op = 0;
1095 t++;
7dd57fa2 1096 }
9bea1d5b 1097 debug(28, 3) ("aclParseAccessLine: looking for ACL name '%s'\n", t);
1098 a = aclFindByName(t);
1099 if (a == NULL) {
1100 debug(28, 0) ("%s line %d: %s\n",
1101 cfg_filename, config_lineno, config_input_line);
1102 debug(28, 0) ("aclParseAccessLine: ACL name '%s' not found.\n", t);
1103 memFree(L, MEM_ACL_LIST);
1104 continue;
7dd57fa2 1105 }
29b8d8d6 1106 L->_acl = a;
9bea1d5b 1107 *Tail = L;
1108 Tail = &L->next;
7dd57fa2 1109 }
7dd57fa2 1110}
1111
f32789f4 1112/**************/
1113/* aclMatchIp */
1114/**************/
1115
f32789f4 1116static int
9bea1d5b 1117aclMatchIp(void *dataptr, struct in_addr c)
f32789f4 1118{
e6ccf245 1119 splayNode **Top = (splayNode **)dataptr;
96da6e88 1120 acl_ip_data x;
1121 /*
1122 * aclIpAddrNetworkCompare() takes two acl_ip_data pointers as
1123 * arguments, so we must create a fake one for the client's IP
1124 * address, and use a /32 netmask. However, the current code
1125 * probably only accesses the addr1 element of this argument,
1126 * so it might be possible to leave addr2 and mask unset.
1127 * XXX Could eliminate these repetitive assignments with a
1128 * static structure.
1129 */
1130 x.addr1 = c;
1131 x.addr2 = any_addr;
1132 x.mask = no_addr;
1133 x.next = NULL;
1134 *Top = splay_splay(&x, *Top, aclIpAddrNetworkCompare);
9bea1d5b 1135 debug(28, 3) ("aclMatchIp: '%s' %s\n",
1136 inet_ntoa(c), splayLastResult ? "NOT found" : "found");
1137 return !splayLastResult;
f32789f4 1138}
1139
f32789f4 1140/**********************/
1141/* aclMatchDomainList */
1142/**********************/
1143
f32789f4 1144static int
9bea1d5b 1145aclMatchDomainList(void *dataptr, const char *host)
f32789f4 1146{
e6ccf245 1147 splayNode **Top = (splayNode **)dataptr;
9bea1d5b 1148 if (host == NULL)
1149 return 0;
1150 debug(28, 3) ("aclMatchDomainList: checking '%s'\n", host);
1151 *Top = splay_splay(host, *Top, aclHostDomainCompare);
1152 debug(28, 3) ("aclMatchDomainList: '%s' %s\n",
1153 host, splayLastResult ? "NOT found" : "found");
1154 return !splayLastResult;
abf6b4de 1155}
1156
33cdd606 1157int
9bea1d5b 1158aclMatchRegex(relist * data, const char *word)
abf6b4de 1159{
9bea1d5b 1160 relist *first, *prev;
1161 if (word == NULL)
1162 return 0;
1163 debug(28, 3) ("aclMatchRegex: checking '%s'\n", word);
1164 first = data;
1165 prev = NULL;
1166 while (data) {
1167 debug(28, 3) ("aclMatchRegex: looking for '%s'\n", data->pattern);
1168 if (regexec(&data->regex, word, 0, 0, 0) == 0) {
1169 if (prev != NULL) {
1170 /* shift the element just found to the second position
1171 * in the list */
1172 prev->next = data->next;
1173 data->next = first->next;
1174 first->next = data;
c10aaf05 1175 }
9bea1d5b 1176 return 1;
c10aaf05 1177 }
9bea1d5b 1178 prev = data;
1179 data = data->next;
abf6b4de 1180 }
9bea1d5b 1181 return 0;
abf6b4de 1182}
30a4f2a8 1183
94103840 1184static int
e6ccf245 1185aclMatchUser(void *proxyauth_acl, char const *user)
94103840 1186{
9bea1d5b 1187 acl_user_data *data = (acl_user_data *) proxyauth_acl;
1188 splayNode *Top = data->names;
0009ba2f 1189
9bea1d5b 1190 debug(28, 7) ("aclMatchUser: user is %s, case_insensitive is %d\n",
1191 user, data->flags.case_insensitive);
1192 debug(28, 8) ("Top is %p, Top->data is %s\n", Top,
84f2d773 1193 (char *) (Top != NULL ? (Top)->data : "Unavailable"));
0009ba2f 1194
9bea1d5b 1195 if (user == NULL)
1196 return 0;
0009ba2f 1197
9bea1d5b 1198 if (data->flags.required) {
1199 debug(28, 7) ("aclMatchUser: user REQUIRED and auth-info present.\n");
1200 return 1;
94103840 1201 }
9bea1d5b 1202 if (data->flags.case_insensitive)
1203 Top = splay_splay(user, Top, (SPLAYCMP *) strcasecmp);
1204 else
1205 Top = splay_splay(user, Top, (SPLAYCMP *) strcmp);
1206 /* Top=splay_splay(user,Top,(SPLAYCMP *)dumping_strcmp); */
1207 debug(28, 7) ("aclMatchUser: returning %d,Top is %p, Top->data is %s\n",
84f2d773 1208 !splayLastResult, Top, (char *) (Top ? Top->data : "Unavailable"));
9bea1d5b 1209 data->names = Top;
1210 return !splayLastResult;
94103840 1211}
1212
94439e4e 1213/* ACL result caching routines */
1214
1215/*
1216 * we lookup an acl's cached results, and if we cannot find the acl being
1217 * checked we check it and cache the result. This function is deliberatly
1218 * generic to support caching of multiple acl types (but it needs to be more
1219 * generic still....
1220 * The Match Param and the cache MUST be tied together by the calling routine.
1221 * You have been warned :-]
1222 * Also only Matchxxx that are of the form (void *, void *) can be used.
1223 * probably some ugly overloading _could_ be done but I'll leave that as an
1224 * exercise for the reader. Note that caching of time based acl's is not
1225 * wise due to no expiry occuring to the cache entries until the user expires
1226 * or a reconfigure takes place.
1227 * RBC
1228 */
afe95a7e 1229static int
9bea1d5b 1230aclCacheMatchAcl(dlink_list * cache, squid_acl acltype, void *data,
e6ccf245 1231 char const *MatchParam)
9bea1d5b 1232{
1233 int matchrv;
1234 acl_proxy_auth_match_cache *auth_match;
1235 dlink_node *link;
1236 link = cache->head;
1237 while (link) {
e6ccf245 1238 auth_match = (acl_proxy_auth_match_cache *)link->data;
9bea1d5b 1239 if (auth_match->acl_data == data) {
04bd8d25 1240 debug(28, 4) ("aclCacheMatchAcl: cache hit on acl '%p'\n", data);
9bea1d5b 1241 return auth_match->matchrv;
1242 }
1243 link = link->next;
1244 }
1245 auth_match = NULL;
1246 /* match the user in the acl. They are not cached. */
1247 switch (acltype) {
94439e4e 1248 case ACL_PROXY_AUTH:
9bea1d5b 1249 matchrv = aclMatchUser(data, MatchParam);
1250 break;
94439e4e 1251 case ACL_PROXY_AUTH_REGEX:
e6ccf245 1252 matchrv = aclMatchRegex((relist *)data, MatchParam);
054aa556 1253 break;
94439e4e 1254 default:
9bea1d5b 1255 /* This is a fatal to ensure that aclCacheMatchAcl calls are _only_
1256 * made for supported acl types */
1257 fatal("aclCacheMatchAcl: unknown or unexpected ACL type");
1258 return 0; /* NOTREACHED */
78385265 1259 }
e6ccf245 1260 auth_match = (acl_proxy_auth_match_cache *)memAllocate(MEM_ACL_PROXY_AUTH_MATCH);
9bea1d5b 1261 auth_match->matchrv = matchrv;
1262 auth_match->acl_data = data;
1263 dlinkAddTail(auth_match, &auth_match->link, cache);
1264 return matchrv;
94439e4e 1265}
1266
1267void
9bea1d5b 1268aclCacheMatchFlush(dlink_list * cache)
94439e4e 1269{
9bea1d5b 1270 acl_proxy_auth_match_cache *auth_match;
1271 dlink_node *link, *tmplink;
1272 link = cache->head;
1273 while (link) {
e6ccf245 1274 auth_match = (acl_proxy_auth_match_cache *)link->data;
9bea1d5b 1275 tmplink = link;
1276 link = link->next;
1277 dlinkDelete(tmplink, cache);
1278 memFree(auth_match, MEM_ACL_PROXY_AUTH_MATCH);
1f38f50a 1279 }
c68e9c6b 1280}
73e67ee0 1281
60d096f4 1282/* aclMatchProxyAuth can return two exit codes:
1283 * 0 : Authorisation for this ACL failed. (Did not match)
1284 * 1 : Authorisation OK. (Matched)
c68e9c6b 1285 */
c68e9c6b 1286static int
030d31a0 1287aclMatchProxyAuth(void *data, auth_user_request_t * auth_user_request,
4fb35c3c 1288 ACLChecklist * checklist, squid_acl acltype)
c68e9c6b 1289{
9bea1d5b 1290 /* checklist is used to register user name when identified, nothing else */
9bea1d5b 1291 /* General program flow in proxy_auth acls
1292 * 1. Consistency checks: are we getting sensible data
1293 * 2. Call the authenticate* functions to establish a authenticated user
1294 * 4. look up the username in acltype (and cache the result against the
1295 * username
1296 */
c68e9c6b 1297
9bea1d5b 1298 /* for completeness */
1299 authenticateAuthUserRequestLock(auth_user_request);
c68e9c6b 1300
9bea1d5b 1301 /* consistent parameters ? */
1302 assert(authenticateUserAuthenticated(auth_user_request));
1303 /* this ACL check completed */
1304 authenticateAuthUserRequestUnlock(auth_user_request);
1305 /* check to see if we have matched the user-acl before */
1306 return aclCacheMatchAcl(&auth_user_request->auth_user->
1307 proxy_match_cache, acltype, data,
1308 authenticateUserRequestUsername(auth_user_request));
60d096f4 1309}
1310
9bea1d5b 1311CBDATA_TYPE(acl_user_ip_data);
60d096f4 1312
1313void
9bea1d5b 1314aclParseUserMaxIP(void *data)
1315{
e6ccf245 1316 acl_user_ip_data **acldata = (acl_user_ip_data **)data;
9bea1d5b 1317 char *t = NULL;
1318 CBDATA_INIT_TYPE(acl_user_ip_data);
1319 if (*acldata) {
1320 debug(28, 1) ("Attempting to alter already set User max IP acl\n");
1321 return;
d35b9a94 1322 }
9bea1d5b 1323 *acldata = cbdataAlloc(acl_user_ip_data);
78e0ce43 1324 t = strtokFile();
1325 if (!t)
1326 goto error;
1327 debug(28, 5) ("aclParseUserMaxIP: First token is %s\n", t);
1328 if (strcmp("-s", t) == 0) {
1329 debug(28, 5) ("aclParseUserMaxIP: Going strict\n");
1330 (*acldata)->flags.strict = 1;
1331 t = strtokFile();
1332 if (!t)
1333 goto error;
1334 }
1335 (*acldata)->max = atoi(t);
1336 debug(28, 5) ("aclParseUserMaxIP: Max IP address's %d\n", (int) (*acldata)->max);
1337 return;
e377501e 1338 error:
78e0ce43 1339 fatal("aclParseUserMaxIP: Malformed ACL %d\n");
60d096f4 1340}
c68e9c6b 1341
60d096f4 1342void
9bea1d5b 1343aclDestroyUserMaxIP(void *data)
60d096f4 1344{
e6ccf245 1345 acl_user_ip_data **acldata = (acl_user_ip_data **)data;
9bea1d5b 1346 if (*acldata)
1347 cbdataFree(*acldata);
1348 *acldata = NULL;
60d096f4 1349}
94439e4e 1350
60d096f4 1351wordlist *
9bea1d5b 1352aclDumpUserMaxIP(void *data)
60d096f4 1353{
e6ccf245 1354 acl_user_ip_data *acldata = (acl_user_ip_data *)data;
9bea1d5b 1355 wordlist *W = NULL;
1356 char buf[128];
1357 if (acldata->flags.strict)
1358 wordlistAdd(&W, "-s");
84f2d773 1359 snprintf(buf, sizeof(buf), "%lu", (unsigned long int) acldata->max);
9bea1d5b 1360 wordlistAdd(&W, buf);
1361 return W;
60d096f4 1362}
1363
e6ccf245 1364/*
de49b4b7 1365 * aclMatchUserMaxIP - check for users logging in from multiple IP's
60d096f4 1366 * 0 : No match
1367 * 1 : Match
1368 */
1369int
9bea1d5b 1370aclMatchUserMaxIP(void *data, auth_user_request_t * auth_user_request,
1371 struct in_addr src_addr)
60d096f4 1372{
de49b4b7 1373 /*
1374 * the logic for flush the ip list when the limit is hit vs keep
1375 * it sorted in most recent access order and just drop the oldest
1376 * one off is currently undecided
1377 */
e6ccf245 1378 acl_user_ip_data *acldata = (acl_user_ip_data *)data;
60d096f4 1379
9bea1d5b 1380 if (authenticateAuthUserRequestIPCount(auth_user_request) <= acldata->max)
1381 return 0;
60d096f4 1382
9bea1d5b 1383 /* this is a match */
1384 if (acldata->flags.strict) {
e6ccf245 1385 /*
de49b4b7 1386 * simply deny access - the user name is already associated with
9bea1d5b 1387 * the request
1388 */
1389 /* remove _this_ ip, as it is the culprit for going over the limit */
1390 authenticateAuthUserRequestRemoveIp(auth_user_request, src_addr);
1391 debug(28, 4) ("aclMatchUserMaxIP: Denying access in strict mode\n");
1392 } else {
e6ccf245 1393 /*
de49b4b7 1394 * non-strict - remove some/all of the cached entries
9bea1d5b 1395 * ie to allow the user to move machines easily
1396 */
1397 authenticateAuthUserRequestClearIp(auth_user_request);
1398 debug(28, 4) ("aclMatchUserMaxIP: Denying access in non-strict mode - flushing the user ip cache\n");
1399 }
9bea1d5b 1400
1401 return 1;
c68e9c6b 1402}
1403
1404static void
4fb35c3c 1405aclLookupProxyAuthStart(ACLChecklist * checklist)
c68e9c6b 1406{
9bea1d5b 1407 auth_user_request_t *auth_user_request;
de49b4b7 1408 /* make sure someone created auth_user_request for us */
1409 assert(checklist->auth_user_request != NULL);
9bea1d5b 1410 auth_user_request = checklist->auth_user_request;
94439e4e 1411
9bea1d5b 1412 assert(authenticateValidateUser(auth_user_request));
1413 authenticateStart(auth_user_request, aclLookupProxyAuthDone, checklist);
afe95a7e 1414}
1415
8203a132 1416static int
9bea1d5b 1417aclMatchInteger(intlist * data, int i)
1418{
1419 intlist *first, *prev;
1420 first = data;
1421 prev = NULL;
1422 while (data) {
1423 if (data->i == i) {
1424 if (prev != NULL) {
1425 /* shift the element just found to the second position
1426 * in the list */
1427 prev->next = data->next;
1428 data->next = first->next;
1429 first->next = data;
c10aaf05 1430 }
9bea1d5b 1431 return 1;
c10aaf05 1432 }
9bea1d5b 1433 prev = data;
1434 data = data->next;
abf6b4de 1435 }
9bea1d5b 1436 return 0;
abf6b4de 1437}
1438
8f663d72 1439static int
9bea1d5b 1440aclMatchIntegerRange(intrange * data, int i)
1441{
1442 intrange *first, *prev;
1443 first = data;
1444 prev = NULL;
1445 while (data) {
1446 if (i < data->i) {
1447 (void) 0;
1448 } else if (i > data->j) {
1449 (void) 0;
1450 } else {
1451 /* matched */
1452 if (prev != NULL) {
1453 /* shift the element just found to the second position
1454 * in the list */
1455 prev->next = data->next;
1456 data->next = first->next;
1457 first->next = data;
8f663d72 1458 }
9bea1d5b 1459 return 1;
8f663d72 1460 }
9bea1d5b 1461 prev = data;
1462 data = data->next;
8f663d72 1463 }
9bea1d5b 1464 return 0;
8f663d72 1465}
1466
8203a132 1467static int
9bea1d5b 1468aclMatchTime(acl_time_data * data, time_t when)
1469{
1470 static time_t last_when = 0;
1471 static struct tm tm;
1472 time_t t;
1473 assert(data != NULL);
1474 if (when != last_when) {
1475 last_when = when;
1476 xmemcpy(&tm, localtime(&when), sizeof(struct tm));
1477 }
1478 t = (time_t) (tm.tm_hour * 60 + tm.tm_min);
1479 debug(28, 3) ("aclMatchTime: checking %d in %d-%d, weekbits=%x\n",
1480 (int) t, (int) data->start, (int) data->stop, data->weekbits);
1481
1482 if (t < data->start || t > data->stop)
1483 return 0;
1484 return data->weekbits & (1 << tm.tm_wday) ? 1 : 0;
92a6f4b1 1485}
1486
9e160ce2 1487#if SQUID_SNMP
dba79ac5 1488static int
9bea1d5b 1489aclMatchWordList(wordlist * w, const char *word)
dba79ac5 1490{
9bea1d5b 1491 debug(28, 3) ("aclMatchWordList: looking for '%s'\n", word);
1492 while (w != NULL) {
1493 debug(28, 3) ("aclMatchWordList: checking '%s'\n", w->key);
1494 if (!strcmp(w->key, word))
1495 return 1;
1496 w = w->next;
dba79ac5 1497 }
9bea1d5b 1498 return 0;
dba79ac5 1499}
9e160ce2 1500#endif
dba79ac5 1501
e377501e 1502int
4fb35c3c 1503aclAuthenticated(ACLChecklist * checklist)
e377501e 1504{
1505 request_t *r = checklist->request;
1506 http_hdr_type headertype;
1507 if (NULL == r) {
1508 return -1;
1509 } else if (!r->flags.accelerated) {
1510 /* Proxy authorization on proxy requests */
1511 headertype = HDR_PROXY_AUTHORIZATION;
1512 } else if (r->flags.internal) {
1513 /* WWW authorization on accelerated internal requests */
1514 headertype = HDR_AUTHORIZATION;
1515 } else {
1516#if AUTH_ON_ACCELERATION
1517 /* WWW authorization on accelerated requests */
1518 headertype = HDR_AUTHORIZATION;
1519#else
1520 debug(28, 1) ("aclAuthenticated: authentication not applicable on accelerated requests.\n");
1521 return -1;
1522#endif
1523 }
1524 /* get authed here */
1525 /* Note: this fills in checklist->auth_user_request when applicable */
0e3be1ea 1526 switch (authenticateTryToAuthenticateAndSetAuthUser(&checklist->auth_user_request, headertype, checklist->request, checklist->conn, checklist->src_addr)) {
e377501e 1527 case AUTH_ACL_CANNOT_AUTHENTICATE:
1528 debug(28, 4) ("aclMatchAcl: returning 0 user authenticated but not authorised.\n");
1529 return 0;
1530 case AUTH_AUTHENTICATED:
1531 return 1;
1532 break;
1533 case AUTH_ACL_HELPER:
1534 debug(28, 4) ("aclMatchAcl: returning 0 sending credentials to helper.\n");
1535 checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_NEEDED;
1536 return 0;
1537 case AUTH_ACL_CHALLENGE:
1538 debug(28, 4) ("aclMatchAcl: returning 0 sending authentication challenge.\n");
1539 checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED;
1540 return 0;
1541 default:
1542 fatal("unexpected authenticateAuthenticate reply\n");
1543 return -1;
1544 }
1545}
1546
669fefd4 1547static int
4fb35c3c 1548aclMatchAcl(acl * ae, ACLChecklist * checklist)
9bea1d5b 1549{
1550 request_t *r = checklist->request;
1551 const ipcache_addrs *ia = NULL;
1552 const char *fqdn = NULL;
1553 char *esc_buf;
1554 const char *header;
1555 const char *browser;
1556 int k, ti;
9bea1d5b 1557 if (!ae)
1558 return 0;
1559 switch (ae->type) {
09817795 1560 case ACL_BROWSER:
fc659d9d 1561 case ACL_REFERER_REGEX:
09817795 1562 case ACL_DST_ASN:
8d14b3de 1563 case ACL_DST_DOMAIN:
1564 case ACL_DST_DOM_REGEX:
09817795 1565 case ACL_DST_IP:
1566 case ACL_MAX_USER_IP:
1567 case ACL_METHOD:
1568 case ACL_PROTO:
1569 case ACL_PROXY_AUTH:
1570 case ACL_PROXY_AUTH_REGEX:
1571 case ACL_REP_MIME_TYPE:
1572 case ACL_REQ_MIME_TYPE:
8d14b3de 1573 case ACL_URLPATH_REGEX:
1574 case ACL_URL_PORT:
09817795 1575 case ACL_URL_REGEX:
9bea1d5b 1576 /* These ACL types require checklist->request */
1577 if (NULL == r) {
1578 debug(28, 1) ("WARNING: '%s' ACL is used but there is no"
1579 " HTTP request -- access denied.\n", ae->name);
1580 return 0;
8d14b3de 1581 }
9bea1d5b 1582 break;
8d14b3de 1583 default:
9bea1d5b 1584 break;
8d14b3de 1585 }
9bea1d5b 1586 debug(28, 3) ("aclMatchAcl: checking '%s'\n", ae->cfgline);
1587 switch (ae->type) {
1969665d 1588 case ACL_SRC_IP:
9bea1d5b 1589 return aclMatchIp(&ae->data, checklist->src_addr);
1590 /* NOTREACHED */
ae2c08a2 1591 case ACL_MY_IP:
9bea1d5b 1592 return aclMatchIp(&ae->data, checklist->my_addr);
1593 /* NOTREACHED */
30a4f2a8 1594 case ACL_DST_IP:
9bea1d5b 1595 ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
1596 if (ia) {
1597 for (k = 0; k < (int) ia->count; k++) {
1598 if (aclMatchIp(&ae->data, ia->in_addrs[k]))
1599 return 1;
665d36de 1600 }
9bea1d5b 1601 return 0;
1602 } else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) {
1603 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
1604 ae->name, r->host);
1605 checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEEDED;
1606 return 0;
1607 } else {
1608 return aclMatchIp(&ae->data, no_addr);
1609 }
1610 /* NOTREACHED */
1969665d 1611 case ACL_DST_DOMAIN:
9bea1d5b 1612 if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
1613 return aclMatchDomainList(&ae->data, r->host);
1614 fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
1615 if (fqdn)
1616 return aclMatchDomainList(&ae->data, fqdn);
1617 if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
1618 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
1619 ae->name, inet_ntoa(ia->in_addrs[0]));
1620 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
1621 return 0;
1622 }
1623 return aclMatchDomainList(&ae->data, "none");
1624 /* NOTREACHED */
f88bb09c 1625 case ACL_SRC_DOMAIN:
9bea1d5b 1626 fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
1627 if (fqdn) {
1628 return aclMatchDomainList(&ae->data, fqdn);
1629 } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
1630 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
1631 ae->name, inet_ntoa(checklist->src_addr));
1632 checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
1633 return 0;
1634 }
1635 return aclMatchDomainList(&ae->data, "none");
1636 /* NOTREACHED */
d0d41f07 1637 case ACL_DST_DOM_REGEX:
9bea1d5b 1638 if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
e6ccf245 1639 return aclMatchRegex((relist *)ae->data, r->host);
9bea1d5b 1640 fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
1641 if (fqdn)
e6ccf245 1642 return aclMatchRegex((relist *)ae->data, fqdn);
9bea1d5b 1643 if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
1644 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
1645 ae->name, inet_ntoa(ia->in_addrs[0]));
1646 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
1647 return 0;
1648 }
e6ccf245 1649 return aclMatchRegex((relist *)ae->data, "none");
9bea1d5b 1650 /* NOTREACHED */
d0d41f07 1651 case ACL_SRC_DOM_REGEX:
9bea1d5b 1652 fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
1653 if (fqdn) {
e6ccf245 1654 return aclMatchRegex((relist *)ae->data, fqdn);
9bea1d5b 1655 } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
1656 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
1657 ae->name, inet_ntoa(checklist->src_addr));
1658 checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
1659 return 0;
1660 }
e6ccf245 1661 return aclMatchRegex((relist *)ae->data, "none");
9bea1d5b 1662 /* NOTREACHED */
1969665d 1663 case ACL_TIME:
e6ccf245 1664 return aclMatchTime((acl_time_data *)ae->data, squid_curtime);
9bea1d5b 1665 /* NOTREACHED */
6e40f263 1666 case ACL_URLPATH_REGEX:
528b2c61 1667 esc_buf = xstrdup(r->urlpath.buf());
9bea1d5b 1668 rfc1738_unescape(esc_buf);
e6ccf245 1669 k = aclMatchRegex((relist *)ae->data, esc_buf);
9bea1d5b 1670 safe_free(esc_buf);
1671 return k;
1672 /* NOTREACHED */
6e40f263 1673 case ACL_URL_REGEX:
9bea1d5b 1674 esc_buf = xstrdup(urlCanonical(r));
1675 rfc1738_unescape(esc_buf);
e6ccf245 1676 k = aclMatchRegex((relist *)ae->data, esc_buf);
9bea1d5b 1677 safe_free(esc_buf);
1678 return k;
1679 /* NOTREACHED */
9bc73deb 1680 case ACL_MAXCONN:
9bea1d5b 1681 k = clientdbEstablished(checklist->src_addr, 0);
1682 return ((k > ((intlist *) ae->data)->i) ? 1 : 0);
1683 /* NOTREACHED */
1969665d 1684 case ACL_URL_PORT:
e6ccf245 1685 return aclMatchIntegerRange((intrange *)ae->data, (int) r->port);
9bea1d5b 1686 /* NOTREACHED */
7e3ce7b9 1687 case ACL_MY_PORT:
e6ccf245 1688 return aclMatchIntegerRange((intrange *)ae->data, (int) checklist->my_port);
9bea1d5b 1689 /* NOTREACHED */
3898f57f 1690#if USE_IDENT
c68e9c6b 1691 case ACL_IDENT:
9bea1d5b 1692 if (checklist->rfc931[0]) {
1693 return aclMatchUser(ae->data, checklist->rfc931);
1694 } else {
1695 checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
1696 return 0;
05832ae1 1697 }
9bea1d5b 1698 /* NOTREACHED */
145cf928 1699 case ACL_IDENT_REGEX:
9bea1d5b 1700 if (checklist->rfc931[0]) {
e6ccf245 1701 return aclMatchRegex((relist *)ae->data, checklist->rfc931);
9bea1d5b 1702 } else {
1703 checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED;
1704 return 0;
145cf928 1705 }
9bea1d5b 1706 /* NOTREACHED */
3898f57f 1707#endif
1969665d 1708 case ACL_PROTO:
e6ccf245 1709 return aclMatchInteger((intlist *)ae->data, r->protocol);
9bea1d5b 1710 /* NOTREACHED */
92a6f4b1 1711 case ACL_METHOD:
e6ccf245 1712 return aclMatchInteger((intlist *)ae->data, r->method);
9bea1d5b 1713 /* NOTREACHED */
d3416189 1714 case ACL_BROWSER:
9bea1d5b 1715 browser = httpHeaderGetStr(&checklist->request->header, HDR_USER_AGENT);
1716 if (NULL == browser)
1717 return 0;
e6ccf245 1718 return aclMatchRegex((relist *)ae->data, browser);
9bea1d5b 1719 /* NOTREACHED */
fc659d9d 1720 case ACL_REFERER_REGEX:
1721 header = httpHeaderGetStr(&checklist->request->header, HDR_REFERER);
1722 if (NULL == header)
1723 return 0;
e6ccf245 1724 return aclMatchRegex((relist *)ae->data, header);
fc659d9d 1725 /* NOTREACHED */
afe95a7e 1726 case ACL_PROXY_AUTH:
145cf928 1727 case ACL_PROXY_AUTH_REGEX:
b593d6e6 1728 if ((ti = aclAuthenticated(checklist)) != 1)
e377501e 1729 return ti;
1730 ti = aclMatchProxyAuth(ae->data, checklist->auth_user_request,
1731 checklist, ae->type);
1732 checklist->auth_user_request = NULL;
1733 return ti;
1734 /* NOTREACHED */
60d096f4 1735 case ACL_MAX_USER_IP:
b593d6e6 1736 if ((ti = aclAuthenticated(checklist)) != 1)
e377501e 1737 return ti;
1738 ti = aclMatchUserMaxIP(ae->data, checklist->auth_user_request,
1739 checklist->src_addr);
9bea1d5b 1740 checklist->auth_user_request = NULL;
e377501e 1741 return ti;
9bea1d5b 1742 /* NOTREACHED */
dba79ac5 1743#if SQUID_SNMP
1744 case ACL_SNMP_COMMUNITY:
e6ccf245 1745 return aclMatchWordList((wordlist *)ae->data, checklist->snmp_community);
e377501e 1746 /* NOTREACHED */
dba79ac5 1747#endif
5d6c7aad 1748 case ACL_SRC_ASN:
9bea1d5b 1749 return asnMatchIp(ae->data, checklist->src_addr);
e377501e 1750 /* NOTREACHED */
5d6c7aad 1751 case ACL_DST_ASN:
9bea1d5b 1752 ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
1753 if (ia) {
1754 for (k = 0; k < (int) ia->count; k++) {
1755 if (asnMatchIp(ae->data, ia->in_addrs[k]))
1756 return 1;
53ad48e6 1757 }
9bea1d5b 1758 return 0;
1759 } else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NONE) {
1760 debug(28, 3) ("asnMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
1761 ae->name, r->host);
1762 checklist->state[ACL_DST_ASN] = ACL_LOOKUP_NEEDED;
1763 } else {
1764 return asnMatchIp(ae->data, no_addr);
53ad48e6 1765 }
9bea1d5b 1766 return 0;
e377501e 1767 /* NOTREACHED */
66c75c41 1768#if USE_ARP_ACL
1769 case ACL_SRC_ARP:
9bea1d5b 1770 return aclMatchArp(&ae->data, checklist->src_addr);
e377501e 1771 /* NOTREACHED */
66c75c41 1772#endif
ba2b31a8 1773 case ACL_REQ_MIME_TYPE:
9bea1d5b 1774 header = httpHeaderGetStr(&checklist->request->header,
1775 HDR_CONTENT_TYPE);
1776 if (NULL == header)
1777 header = "";
e6ccf245 1778 return aclMatchRegex((relist *)ae->data, header);
9bea1d5b 1779 /* NOTREACHED */
c4ab8329 1780 case ACL_REP_MIME_TYPE:
9bea1d5b 1781 if (!checklist->reply)
1782 return 0;
1783 header = httpHeaderGetStr(&checklist->reply->header, HDR_CONTENT_TYPE);
1784 if (NULL == header)
1785 header = "";
e6ccf245 1786 return aclMatchRegex((relist *)ae->data, header);
9bea1d5b 1787 /* NOTREACHED */
d9572179 1788 case ACL_EXTERNAL:
1789 return aclMatchExternal(ae->data, checklist);
1790 /* NOTREACHED */
a7ad6e4e 1791#if USE_SSL
1792 case ACL_USER_CERT:
1793 return aclMatchUserCert(ae->data, checklist);
1794 /* NOTREACHED */
1795 case ACL_CA_CERT:
1796 return aclMatchCACert(ae->data, checklist);
1797 /* NOTREACHED */
1798#endif
1969665d 1799 case ACL_NONE:
6b5fbfee 1800 case ACL_ENUM_MAX:
9bea1d5b 1801 break;
1969665d 1802 }
9bea1d5b 1803 debug(28, 0) ("aclMatchAcl: '%s' has bad type %d\n",
1804 ae->name, ae->type);
1805 return 0;
1969665d 1806}
1807
669fefd4 1808int
4fb35c3c 1809aclMatchAclList(const acl_list * list, ACLChecklist * checklist)
9bea1d5b 1810{
88bfe092 1811 PROF_start(aclMatchAclList);
9bea1d5b 1812 while (list) {
29b8d8d6 1813 AclMatchedName = list->_acl->name;
9bea1d5b 1814 debug(28, 3) ("aclMatchAclList: checking %s%s\n",
29b8d8d6 1815 list->op ? null_string : "!", list->_acl->name);
1816 if (aclMatchAcl(list->_acl, checklist) != list->op) {
9bea1d5b 1817 debug(28, 3) ("aclMatchAclList: returning 0\n");
88bfe092 1818 PROF_stop(aclMatchAclList);
9bea1d5b 1819 return 0;
837dcbb9 1820 }
9bea1d5b 1821 list = list->next;
1969665d 1822 }
9bea1d5b 1823 debug(28, 3) ("aclMatchAclList: returning 1\n");
88bfe092 1824 PROF_stop(aclMatchAclList);
9bea1d5b 1825 return 1;
1969665d 1826}
1827
d9572179 1828static void
4fb35c3c 1829aclCheckCleanup(ACLChecklist * checklist)
d9572179 1830{
1831 /* Cleanup temporary stuff used by the ACL checking */
1832 if (checklist->extacl_entry) {
1833 cbdataReferenceDone(checklist->extacl_entry);
1834 }
1835}
1836
4fb35c3c 1837/* Warning: do not cbdata lock checklist here - it
1838 * may be static or on the stack
1839 */
8203a132 1840int
4fb35c3c 1841aclCheckFast(const acl_access * A, ACLChecklist * checklist)
1969665d 1842{
9bea1d5b 1843 allow_t allow = ACCESS_DENIED;
88bfe092 1844 PROF_start(aclCheckFast);
9bea1d5b 1845 debug(28, 5) ("aclCheckFast: list: %p\n", A);
1846 while (A) {
1847 allow = A->allow;
29b8d8d6 1848 if (aclMatchAclList(A->aclList, checklist)) {
d9572179 1849 aclCheckCleanup(checklist);
88bfe092 1850 PROF_stop(aclCheckFast);
9bea1d5b 1851 return allow == ACCESS_ALLOWED;
d9572179 1852 }
9bea1d5b 1853 A = A->next;
75e88d56 1854 }
9bea1d5b 1855 debug(28, 5) ("aclCheckFast: no matches, returning: %d\n", allow == ACCESS_DENIED);
d9572179 1856 aclCheckCleanup(checklist);
88bfe092 1857 PROF_stop(aclCheckFast);
9bea1d5b 1858 return allow == ACCESS_DENIED;
75e88d56 1859}
1860
1861static void
4fb35c3c 1862aclCheck(ACLChecklist * checklist)
9bea1d5b 1863{
1864 allow_t allow = ACCESS_DENIED;
1865 const acl_access *A;
1866 int match;
1867 ipcache_addrs *ia;
fa80a8ef 1868 /* NOTE: This holds a cbdata reference to the current access_list
1869 * entry, not the whole list.
1870 */
29b8d8d6 1871 while ((A = checklist->accessList) != NULL) {
9bea1d5b 1872 /*
1873 * If the _acl_access is no longer valid (i.e. its been
1874 * freed because of a reconfigure), then bail on this
1875 * access check. For now, return ACCESS_DENIED.
1876 */
fa80a8ef 1877 if (!cbdataReferenceValid(A)) {
29b8d8d6 1878 cbdataReferenceDone(checklist->accessList);
9bea1d5b 1879 break;
d35b9a94 1880 }
9bea1d5b 1881 debug(28, 3) ("aclCheck: checking '%s'\n", A->cfgline);
1882 allow = A->allow;
29b8d8d6 1883 match = aclMatchAclList(A->aclList, checklist);
9bea1d5b 1884 if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NEEDED) {
1885 checklist->state[ACL_DST_IP] = ACL_LOOKUP_PENDING;
1886 ipcache_nbgethostbyname(checklist->request->host,
1887 aclLookupDstIPDone, checklist);
1888 return;
1889 } else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NEEDED) {
1890 checklist->state[ACL_DST_ASN] = ACL_LOOKUP_PENDING;
1891 ipcache_nbgethostbyname(checklist->request->host,
1892 aclLookupDstIPforASNDone, checklist);
1893 return;
1894 } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NEEDED) {
1895 checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_PENDING;
1896 fqdncache_nbgethostbyaddr(checklist->src_addr,
1897 aclLookupSrcFQDNDone, checklist);
1898 return;
1899 } else if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NEEDED) {
1900 ia = ipcacheCheckNumeric(checklist->request->host);
1901 if (ia == NULL) {
1902 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
1903 return;
75e88d56 1904 }
9bea1d5b 1905 checklist->dst_addr = ia->in_addrs[0];
1906 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_PENDING;
1907 fqdncache_nbgethostbyaddr(checklist->dst_addr,
1908 aclLookupDstFQDNDone, checklist);
1909 return;
1910 } else if (checklist->state[ACL_PROXY_AUTH] == ACL_LOOKUP_NEEDED) {
1911 debug(28, 3)
1912 ("aclCheck: checking password via authenticator\n");
1913 aclLookupProxyAuthStart(checklist);
1914 checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_PENDING;
1915 return;
1916 } else if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED) {
1917 /* Client is required to resend the request with correct authentication
1918 * credentials. (This may be part of a stateful auth protocol.
1919 * The request is denied.
1920 */
1921 debug(28, 6) ("aclCheck: requiring Proxy Auth header.\n");
1922 allow = ACCESS_REQ_PROXY_AUTH;
1923 match = -1;
3898f57f 1924 }
1925#if USE_IDENT
9bea1d5b 1926 else if (checklist->state[ACL_IDENT] == ACL_LOOKUP_NEEDED) {
1927 debug(28, 3) ("aclCheck: Doing ident lookup\n");
fa80a8ef 1928 if (checklist->conn && cbdataReferenceValid(checklist->conn)) {
9bea1d5b 1929 identStart(&checklist->conn->me, &checklist->conn->peer,
1930 aclLookupIdentDone, checklist);
1931 checklist->state[ACL_IDENT] = ACL_LOOKUP_PENDING;
1932 return;
1933 } else {
1934 debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n");
fa80a8ef 1935 cbdataReferenceDone(checklist->conn);
621f6df2 1936 allow = ACCESS_DENIED;
9bea1d5b 1937 match = -1;
05832ae1 1938 }
73e67ee0 1939 }
3898f57f 1940#endif
d9572179 1941 else if (checklist->state[ACL_EXTERNAL] == ACL_LOOKUP_NEEDED) {
1942 acl *acl = aclFindByName(AclMatchedName);
1943 externalAclLookup(checklist, acl->data, aclLookupExternalDone, checklist);
1944 return;
1945 }
9bea1d5b 1946 /*
1947 * We are done with this _acl_access entry. Either the request
1948 * is allowed, denied, requires authentication, or we move on to
1949 * the next entry.
1950 */
9bea1d5b 1951 if (match) {
1952 debug(28, 3) ("aclCheck: match found, returning %d\n", allow);
29b8d8d6 1953 cbdataReferenceDone(checklist->accessList); /* A */
4fb35c3c 1954 checklist->checkCallback(allow);
9bea1d5b 1955 return;
1956 }
9bea1d5b 1957 /*
fa80a8ef 1958 * Reference the next _acl_access entry
9bea1d5b 1959 */
29b8d8d6 1960 checklist->accessList = cbdataReference(A->next);
fa80a8ef 1961 cbdataReferenceDone(A);
9bea1d5b 1962 }
1963 debug(28, 3) ("aclCheck: NO match found, returning %d\n", allow != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED);
4fb35c3c 1964 checklist->checkCallback(allow != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED);
75e88d56 1965}
1966
348b2031 1967void
4fb35c3c 1968aclChecklistFree(ACLChecklist * checklist)
75e88d56 1969{
9bea1d5b 1970 if (checklist->request)
1971 requestUnlink(checklist->request);
1972 checklist->request = NULL;
fa80a8ef 1973 cbdataReferenceDone(checklist->conn);
4277be1c 1974 cbdataReferenceDone(checklist->accessList);
d9572179 1975 aclCheckCleanup(checklist);
4fb35c3c 1976 delete checklist;
75e88d56 1977}
1978
4fb35c3c 1979void
1980ACLChecklist::checkCallback(allow_t answer)
9bea1d5b 1981{
4fb35c3c 1982 PF *callback_;
1983 void *cbdata_;
1984 debug(28, 3) ("ACLChecklist::checkCallback: answer=%d\n", answer);
1985 /* During reconfigure, we can end up not finishing call
1986 * sequences into the auth code */
1987 if (auth_user_request) {
9bea1d5b 1988 /* the checklist lock */
4fb35c3c 1989 authenticateAuthUserRequestUnlock(auth_user_request);
9bea1d5b 1990 /* it might have been connection based */
4fb35c3c 1991 assert(conn);
1992 conn->auth_user_request = NULL;
1993 conn->auth_type = AUTH_BROKEN;
1994 auth_user_request = NULL;
9bea1d5b 1995 }
4fb35c3c 1996 callback_ = callback;
1997 callback = NULL;
1998 if (cbdataReferenceValidDone(callback_data, &cbdata_))
1999 callback_(answer, cbdata_);
2000 aclChecklistFree(this);
348b2031 2001}
2002
3898f57f 2003#if USE_IDENT
05832ae1 2004static void
9bea1d5b 2005aclLookupIdentDone(const char *ident, void *data)
05832ae1 2006{
4fb35c3c 2007 ACLChecklist *checklist = (ACLChecklist *)data;
9bea1d5b 2008 if (ident) {
2009 xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
94439e4e 2010#if DONT
9bea1d5b 2011 xstrncpy(checklist->request->authuser, ident, USER_IDENT_SZ);
94439e4e 2012#endif
9bea1d5b 2013 } else {
2014 xstrncpy(checklist->rfc931, dash_str, USER_IDENT_SZ);
05832ae1 2015 }
9bea1d5b 2016 /*
2017 * Cache the ident result in the connection, to avoid redoing ident lookup
2018 * over and over on persistent connections
2019 */
fa80a8ef 2020 if (cbdataReferenceValid(checklist->conn) && !checklist->conn->rfc931[0])
9bea1d5b 2021 xstrncpy(checklist->conn->rfc931, checklist->rfc931, USER_IDENT_SZ);
2022 aclCheck(checklist);
05832ae1 2023}
3898f57f 2024#endif
05832ae1 2025
75e88d56 2026static void
9bea1d5b 2027aclLookupDstIPDone(const ipcache_addrs * ia, void *data)
75e88d56 2028{
4fb35c3c 2029 ACLChecklist *checklist = (ACLChecklist *)data;
9bea1d5b 2030 checklist->state[ACL_DST_IP] = ACL_LOOKUP_DONE;
2031 aclCheck(checklist);
1969665d 2032}
73e67ee0 2033
53ad48e6 2034static void
9bea1d5b 2035aclLookupDstIPforASNDone(const ipcache_addrs * ia, void *data)
53ad48e6 2036{
4fb35c3c 2037 ACLChecklist *checklist = (ACLChecklist *)data;
9bea1d5b 2038 checklist->state[ACL_DST_ASN] = ACL_LOOKUP_DONE;
2039 aclCheck(checklist);
53ad48e6 2040}
92a6f4b1 2041
75e88d56 2042static void
9bea1d5b 2043aclLookupSrcFQDNDone(const char *fqdn, void *data)
75e88d56 2044{
4fb35c3c 2045 ACLChecklist *checklist = (ACLChecklist *)data;
9bea1d5b 2046 checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_DONE;
2047 aclCheck(checklist);
75e88d56 2048}
2049
2050static void
9bea1d5b 2051aclLookupDstFQDNDone(const char *fqdn, void *data)
75e88d56 2052{
4fb35c3c 2053 ACLChecklist *checklist = (ACLChecklist *)data;
9bea1d5b 2054 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
2055 aclCheck(checklist);
75e88d56 2056}
2057
73e67ee0 2058static void
9bea1d5b 2059aclLookupProxyAuthDone(void *data, char *result)
2060{
4fb35c3c 2061 ACLChecklist *checklist = (ACLChecklist *)data;
9bea1d5b 2062 checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE;
2063 if (result != NULL)
2064 fatal("AclLookupProxyAuthDone: Old code floating around somewhere.\nMake clean and if that doesn't work, report a bug to the squid developers.\n");
2065 if (!authenticateValidateUser(checklist->auth_user_request) || checklist->conn == NULL) {
2066 /* credentials could not be checked either way
2067 * restart the whole process */
2068 /* OR the connection was closed, there's no way to continue */
2069 authenticateAuthUserRequestUnlock(checklist->auth_user_request);
2070 if (checklist->conn) {
2071 checklist->conn->auth_user_request = NULL;
2072 checklist->conn->auth_type = AUTH_BROKEN;
bd507204 2073 }
9bea1d5b 2074 checklist->auth_user_request = NULL;
066ed5c1 2075 }
9bea1d5b 2076 aclCheck(checklist);
73e67ee0 2077}
2078
d9572179 2079static void
2080aclLookupExternalDone(void *data, void *result)
2081{
4fb35c3c 2082 ACLChecklist *checklist = (ACLChecklist *)data;
d9572179 2083 checklist->state[ACL_EXTERNAL] = ACL_LOOKUP_DONE;
e6ccf245 2084 checklist->extacl_entry = cbdataReference((external_acl_entry *)result);
d9572179 2085 aclCheck(checklist);
2086}
2087
4fb35c3c 2088CBDATA_CLASS_INIT(ACLChecklist);
2089
2090void *
2091ACLChecklist::operator new (size_t size)
2092{
2093 assert (size == sizeof(ACLChecklist));
2094 CBDATA_INIT_TYPE(ACLChecklist);
2095 ACLChecklist *result = cbdataAlloc(ACLChecklist);
2096 /* Mark result as being owned - we want the refcounter to do the delete
2097 * call */
2098 cbdataReference(result);
2099 return result;
2100}
2101
2102void
2103ACLChecklist::operator delete (void *address)
2104{
2105 ACLChecklist *t = static_cast<ACLChecklist *>(address);
2106 cbdataFree(address);
2107 /* And allow the memory to be freed */
2108 cbdataReferenceDone (t);
2109}
2110
2111void
2112ACLChecklist::deleteSelf() const
2113{
2114 delete this;
2115}
2116
2117ACLChecklist::ACLChecklist() : accessList (NULL), my_port (0), request (NULL),
2118 reply (NULL),
2119 conn (NULL),
2120 auth_user_request (NULL)
2121#if SQUID_SNMP
2122 ,snmp_community(NULL)
2123#endif
2124 , callback (NULL),
2125 callback_data (NULL),
2126 extacl_entry (NULL)
2127{
2128 memset (&src_addr, '\0', sizeof (struct in_addr));
2129 memset (&dst_addr, '\0', sizeof (struct in_addr));
2130 memset (&my_addr, '\0', sizeof (struct in_addr));
2131 rfc931[0] = '\0';
2132 memset (&state, '\0', sizeof (state));
2133}
2134
2135ACLChecklist::~ACLChecklist()
2136{
2137}
2138
68459642 2139/*
4fb35c3c 2140 * Any ACLChecklist created by aclChecklistCreate() must eventually be
68459642 2141 * freed by aclChecklistFree(). There are two common cases:
2142 *
4fb35c3c 2143 * A) Using aclCheckFast(): The caller creates the ACLChecklist using
68459642 2144 * aclChecklistCreate(), checks it using aclCheckFast(), and frees it
2145 * using aclChecklistFree().
2146 *
2147 * B) Using aclNBCheck() and callbacks: The caller creates the
4fb35c3c 2148 * ACLChecklist using aclChecklistCreate(), and passes it to
2149 * aclNBCheck(). Control eventually passes to ACLChecklist::checkCallback(),
68459642 2150 * which will invoke the callback function as requested by the
2151 * original caller of aclNBCheck(). This callback function must
2152 * *not* invoke aclChecklistFree(). After the callback function
4fb35c3c 2153 * returns, ACLChecklist::checkCallback() will free the ACLChecklist using
68459642 2154 * aclChecklistFree().
2155 */
2156
4fb35c3c 2157
2158ACLChecklist *
9bea1d5b 2159aclChecklistCreate(const acl_access * A, request_t * request, const char *ident)
2160{
2161 int i;
4fb35c3c 2162 ACLChecklist *checklist = new ACLChecklist;
29b8d8d6 2163 checklist->accessList = cbdataReference(A);
9bea1d5b 2164 if (request != NULL) {
2165 checklist->request = requestLink(request);
2166 checklist->src_addr = request->client_addr;
2167 checklist->my_addr = request->my_addr;
2168 checklist->my_port = request->my_port;
2169 }
2170 for (i = 0; i < ACL_ENUM_MAX; i++)
2171 checklist->state[i] = ACL_LOOKUP_NONE;
3898f57f 2172#if USE_IDENT
9bea1d5b 2173 if (ident)
2174 xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ);
3898f57f 2175#endif
9bea1d5b 2176 checklist->auth_user_request = NULL;
2177 return checklist;
348b2031 2178}
2179
2180void
4fb35c3c 2181aclNBCheck(ACLChecklist * checklist, PF * callback, void *callback_data)
348b2031 2182{
9bea1d5b 2183 checklist->callback = callback;
fa80a8ef 2184 checklist->callback_data = cbdataReference(callback_data);
9bea1d5b 2185 aclCheck(checklist);
75e88d56 2186}
2187
f32789f4 2188/*********************/
2189/* Destroy functions */
2190/*********************/
2191
8203a132 2192static void
9bea1d5b 2193aclDestroyTimeList(acl_time_data * data)
92a6f4b1 2194{
9bea1d5b 2195 acl_time_data *next = NULL;
2196 for (; data; data = next) {
2197 next = data->next;
2198 memFree(data, MEM_ACL_TIME_DATA);
540830c4 2199 }
92a6f4b1 2200}
2201
33cdd606 2202void
9bea1d5b 2203aclDestroyRegexList(relist * data)
92a6f4b1 2204{
9bea1d5b 2205 relist *next = NULL;
2206 for (; data; data = next) {
2207 next = data->next;
2208 regfree(&data->regex);
2209 safe_free(data->pattern);
2210 memFree(data, MEM_RELIST);
540830c4 2211 }
92a6f4b1 2212}
2213
afe95a7e 2214static void
9bea1d5b 2215aclFreeIpData(void *p)
afe95a7e 2216{
9bea1d5b 2217 memFree(p, MEM_ACL_IP_DATA);
afe95a7e 2218}
2219
0009ba2f 2220static void
9bea1d5b 2221aclFreeUserData(void *data)
0009ba2f 2222{
e6ccf245 2223 acl_user_data *d = (acl_user_data *)data;
9bea1d5b 2224 if (d->names)
2225 splay_destroy(d->names, xfree);
2226 memFree(d, MEM_ACL_USER_DATA);
0009ba2f 2227}
2228
2229
8203a132 2230void
9bea1d5b 2231aclDestroyAcls(acl ** head)
2232{
2233 acl *a = NULL;
2234 acl *next = NULL;
2235 for (a = *head; a; a = next) {
2236 next = a->next;
2237 debug(28, 3) ("aclDestroyAcls: '%s'\n", a->cfgline);
2238 switch (a->type) {
540830c4 2239 case ACL_SRC_IP:
30a4f2a8 2240 case ACL_DST_IP:
ae2c08a2 2241 case ACL_MY_IP:
e6ccf245 2242 splay_destroy((splayNode *)a->data, aclFreeIpData);
9bea1d5b 2243 break;
6b5fbfee 2244#if USE_ARP_ACL
c68e9c6b 2245 case ACL_SRC_ARP:
6b5fbfee 2246#endif
540830c4 2247 case ACL_DST_DOMAIN:
c20e73a0 2248 case ACL_SRC_DOMAIN:
e6ccf245 2249 splay_destroy((splayNode *)a->data, xfree);
9bea1d5b 2250 break;
dba79ac5 2251#if SQUID_SNMP
2252 case ACL_SNMP_COMMUNITY:
9bea1d5b 2253 wordlistDestroy((wordlist **) & a->data);
2254 break;
dba79ac5 2255#endif
3898f57f 2256#if USE_IDENT
c68e9c6b 2257 case ACL_IDENT:
9bea1d5b 2258 aclFreeUserData(a->data);
2259 break;
3898f57f 2260#endif
c68e9c6b 2261 case ACL_PROXY_AUTH:
9bea1d5b 2262 aclFreeUserData(a->data);
2263 break;
540830c4 2264 case ACL_TIME:
e6ccf245 2265 aclDestroyTimeList((acl_time_data *)a->data);
9bea1d5b 2266 break;
145cf928 2267#if USE_IDENT
2268 case ACL_IDENT_REGEX:
2269#endif
2270 case ACL_PROXY_AUTH_REGEX:
540830c4 2271 case ACL_URL_REGEX:
6e40f263 2272 case ACL_URLPATH_REGEX:
6b8e7481 2273 case ACL_BROWSER:
fc659d9d 2274 case ACL_REFERER_REGEX:
71eb5c70 2275 case ACL_SRC_DOM_REGEX:
2276 case ACL_DST_DOM_REGEX:
6b5fbfee 2277 case ACL_REP_MIME_TYPE:
2278 case ACL_REQ_MIME_TYPE:
e6ccf245 2279 aclDestroyRegexList((relist *)a->data);
9bea1d5b 2280 break;
540830c4 2281 case ACL_PROTO:
2282 case ACL_METHOD:
9fdbeb4f 2283 case ACL_SRC_ASN:
2284 case ACL_DST_ASN:
6b5fbfee 2285#if SRC_RTT_NOT_YET_FINISHED
6b8e7481 2286 case ACL_NETDB_SRC_RTT:
6b5fbfee 2287#endif
9bc73deb 2288 case ACL_MAXCONN:
9bea1d5b 2289 intlistDestroy((intlist **) & a->data);
2290 break;
60d096f4 2291 case ACL_MAX_USER_IP:
9bea1d5b 2292 aclDestroyUserMaxIP(&a->data);
2293 break;
8f663d72 2294 case ACL_URL_PORT:
7e3ce7b9 2295 case ACL_MY_PORT:
e6ccf245 2296 aclDestroyIntRange((intrange *)a->data);
9bea1d5b 2297 break;
d9572179 2298 case ACL_EXTERNAL:
2299 aclDestroyExternal(&a->data);
2300 break;
a7ad6e4e 2301#if USE_SSL
2302 case ACL_USER_CERT:
2303 case ACL_CA_CERT:
2304 aclDestroyCertList(&a->data);
2305 break;
2306#endif
540830c4 2307 case ACL_NONE:
6b5fbfee 2308 case ACL_ENUM_MAX:
9bea1d5b 2309 debug(28, 1) ("aclDestroyAcls: no case for ACL type %d\n", a->type);
2310 break;
92a6f4b1 2311 }
9bea1d5b 2312 safe_free(a->cfgline);
2313 memFree(a, MEM_ACL);
540830c4 2314 }
9bea1d5b 2315 *head = NULL;
92a6f4b1 2316}
2317
d6827718 2318void
9bea1d5b 2319aclDestroyAclList(acl_list ** head)
92a6f4b1 2320{
9bea1d5b 2321 acl_list *l;
2322 for (l = *head; l; l = *head) {
2323 *head = l->next;
2324 memFree(l, MEM_ACL_LIST);
540830c4 2325 }
92a6f4b1 2326}
2327
8203a132 2328void
9bea1d5b 2329aclDestroyAccessList(acl_access ** list)
92a6f4b1 2330{
9bea1d5b 2331 acl_access *l = NULL;
2332 acl_access *next = NULL;
2333 for (l = *list; l; l = next) {
2334 debug(28, 3) ("aclDestroyAccessList: '%s'\n", l->cfgline);
2335 next = l->next;
29b8d8d6 2336 aclDestroyAclList(&l->aclList);
9bea1d5b 2337 safe_free(l->cfgline);
2338 cbdataFree(l);
540830c4 2339 }
9bea1d5b 2340 *list = NULL;
92a6f4b1 2341}
e92d33a5 2342
2343/* maex@space.net (06.09.1996)
f4296e99 2344 * destroy an _acl_deny_info_list */
f32789f4 2345
8203a132 2346void
9bea1d5b 2347aclDestroyDenyInfoList(acl_deny_info_list ** list)
2348{
2349 acl_deny_info_list *a = NULL;
2350 acl_deny_info_list *a_next = NULL;
2351 acl_name_list *l = NULL;
2352 acl_name_list *l_next = NULL;
2353
2354 for (a = *list; a; a = a_next) {
2355 for (l = a->acl_list; l; l = l_next) {
2356 l_next = l->next;
2357 safe_free(l);
e92d33a5 2358 }
9bea1d5b 2359 a_next = a->next;
2360 xfree(a->err_page_name);
2361 memFree(a, MEM_ACL_DENY_INFO_LIST);
e92d33a5 2362 }
9bea1d5b 2363 *list = NULL;
e92d33a5 2364}
f32789f4 2365
8f663d72 2366static void
9bea1d5b 2367aclDestroyIntRange(intrange * list)
8f663d72 2368{
9bea1d5b 2369 intrange *w = NULL;
2370 intrange *n = NULL;
2371 for (w = list; w; w = n) {
2372 n = w->next;
2373 safe_free(w);
8f663d72 2374 }
2375}
2376
f32789f4 2377/* general compare functions, these are used for tree search algorithms
2378 * so they return <0, 0 or >0 */
2379
2380/* compare two domains */
2381
f32789f4 2382static int
9bea1d5b 2383aclDomainCompare(const void *a, const void *b)
f32789f4 2384{
9bea1d5b 2385 const char *d1;
2386 const char *d2;
2387 int ret;
e6ccf245 2388 d1 = (const char *)b;
2389 d2 = (const char *)a;
9bea1d5b 2390 ret = aclHostDomainCompare(d1, d2);
2391 if (ret != 0) {
e6ccf245 2392 d1 = (const char *)a;
2393 d2 = (const char *)b;
9bea1d5b 2394 ret = aclHostDomainCompare(d1, d2);
aca95add 2395 }
9bea1d5b 2396 if (ret == 0) {
2397 debug(28, 0) ("WARNING: '%s' is a subdomain of '%s'\n", d1, d2);
84f2d773 2398 debug(28, 0) ("WARNING: because of this '%s' is ignored to keep splay tree searching predictable\n", (char *) a);
9bea1d5b 2399 debug(28, 0) ("WARNING: You should probably remove '%s' from the ACL named '%s'\n", d1, AclMatchedName);
f32789f4 2400 }
9bea1d5b 2401 return ret;
f32789f4 2402}
2403
f32789f4 2404/* compare a host and a domain */
2405
f32789f4 2406static int
9bea1d5b 2407aclHostDomainCompare(const void *a, const void *b)
f32789f4 2408{
e6ccf245 2409 const char *h = (const char *)a;
2410 const char *d = (const char *)b;
9bea1d5b 2411 return matchDomainName(h, d);
f32789f4 2412}
2413
96da6e88 2414/*
2415 * aclIpDataToStr - print/format an acl_ip_data structure for
2416 * debugging output.
f32789f4 2417 */
96da6e88 2418static void
2419aclIpDataToStr(const acl_ip_data * ip, char *buf, int len)
2420{
2421 char b1[20];
2422 char b2[20];
2423 char b3[20];
2424 snprintf(b1, 20, "%s", inet_ntoa(ip->addr1));
2425 if (ip->addr2.s_addr != any_addr.s_addr)
2426 snprintf(b2, 20, "-%s", inet_ntoa(ip->addr2));
2427 else
2428 b2[0] = '\0';
2429 if (ip->mask.s_addr != no_addr.s_addr)
2430 snprintf(b3, 20, "/%s", inet_ntoa(ip->mask));
2431 else
2432 b3[0] = '\0';
2433 snprintf(buf, len, "%s%s%s", b1, b2, b3);
2434}
f32789f4 2435
96da6e88 2436/*
2437 * aclIpNetworkCompare2 - The guts of the comparison for IP ACLs.
2438 * The first argument (a) is a "host" address, i.e. the IP address
2439 * of a cache client. The second argument (b) is a "network" address
2440 * that might have a subnet and/or range. We mask the host address
2441 * bits with the network subnet mask.
2442 */
f32789f4 2443static int
96da6e88 2444aclIpNetworkCompare2(const acl_ip_data * p, const acl_ip_data * q)
9bea1d5b 2445{
96da6e88 2446 struct in_addr A = p->addr1;
9bea1d5b 2447 const struct in_addr B = q->addr1;
2448 const struct in_addr C = q->addr2;
2449 int rc = 0;
2450 A.s_addr &= q->mask.s_addr; /* apply netmask */
2451 if (C.s_addr == 0) { /* single address check */
2452 if (ntohl(A.s_addr) > ntohl(B.s_addr))
2453 rc = 1;
2454 else if (ntohl(A.s_addr) < ntohl(B.s_addr))
2455 rc = -1;
2456 else
2457 rc = 0;
2458 } else { /* range address check */
2459 if (ntohl(A.s_addr) > ntohl(C.s_addr))
2460 rc = 1;
2461 else if (ntohl(A.s_addr) < ntohl(B.s_addr))
2462 rc = -1;
2463 else
2464 rc = 0;
2465 }
2466 return rc;
f32789f4 2467}
f32789f4 2468
96da6e88 2469/*
2470 * aclIpNetworkCompare - Compare two acl_ip_data entries. Strictly
2471 * used by the splay insertion routine. It emits a warning if it
2472 * detects a "collision" or overlap that would confuse the splay
2473 * sorting algorithm. Much like aclDomainCompare.
2474 */
2475static int
2476aclIpNetworkCompare(const void *a, const void *b)
2477{
2478 const acl_ip_data *n1;
2479 const acl_ip_data *n2;
2480 int ret;
e6ccf245 2481 n1 = (const acl_ip_data *)b;
2482 n2 = (const acl_ip_data *)a;
96da6e88 2483 ret = aclIpNetworkCompare2(n1, n2);
2484 if (ret != 0) {
e6ccf245 2485 n1 = (const acl_ip_data *)a;
2486 n2 = (const acl_ip_data *)b;
96da6e88 2487 ret = aclIpNetworkCompare2(n1, n2);
2488 }
2489 if (ret == 0) {
2490 char buf_n1[60];
2491 char buf_n2[60];
2492 char buf_a[60];
2493 aclIpDataToStr(n1, buf_n1, 60);
2494 aclIpDataToStr(n2, buf_n2, 60);
2495 aclIpDataToStr((acl_ip_data *) a, buf_a, 60);
2496 debug(28, 0) ("WARNING: '%s' is a subnetwork of "
2497 "'%s'\n", buf_n1, buf_n2);
2498 debug(28, 0) ("WARNING: because of this '%s' is ignored "
2499 "to keep splay tree searching predictable\n", buf_a);
2500 debug(28, 0) ("WARNING: You should probably remove '%s' "
2501 "from the ACL named '%s'\n", buf_n1, AclMatchedName);
2502 }
2503 return ret;
2504}
2505
2506/*
2507 * aclIpAddrNetworkCompare - The comparison function used for ACL
2508 * matching checks. The first argument (a) is a "host" address,
2509 * i.e. the IP address of a cache client. The second argument (b)
2510 * is an entry in some address-based access control element. This
2511 * function is called via aclMatchIp() and the splay library.
2512 */
2513static int
2514aclIpAddrNetworkCompare(const void *a, const void *b)
2515{
e6ccf245 2516 return aclIpNetworkCompare2((const acl_ip_data *)a, (const acl_ip_data *)b);
96da6e88 2517}
2518
0009ba2f 2519static void
9bea1d5b 2520aclDumpUserListWalkee(void *node_data, void *outlist)
0009ba2f 2521{
9bea1d5b 2522 /* outlist is really a wordlist ** */
e6ccf245 2523 wordlistAdd((wordlist **)outlist, (char const *)node_data);
0009ba2f 2524}
2525
2d72d4fd 2526static wordlist *
9bea1d5b 2527aclDumpUserList(acl_user_data * data)
2528{
2529 wordlist *wl = NULL;
2530 if (data->flags.case_insensitive)
2531 wordlistAdd(&wl, "-i");
2532 /* damn this is VERY inefficient for long ACL lists... filling
2533 * a wordlist this way costs Sum(1,N) iterations. For instance
2534 * a 1000-elements list will be filled in 499500 iterations.
2535 */
2536 if (data->flags.required)
2537 wordlistAdd(&wl, "REQUIRED");
2538 else if (data->names)
2539 splay_walk(data->names, aclDumpUserListWalkee, &wl);
2540 return wl;
0009ba2f 2541}
2542
f084f6af 2543static void
9bea1d5b 2544aclDumpIpListWalkee(void *node, void *state)
f084f6af 2545{
e6ccf245 2546 acl_ip_data *ip = (acl_ip_data *)node;
9bea1d5b 2547 MemBuf mb;
e6ccf245 2548 wordlist **W = (wordlist **)state;
9bea1d5b 2549 memBufDefInit(&mb);
2550 memBufPrintf(&mb, "%s", inet_ntoa(ip->addr1));
2551 if (ip->addr2.s_addr != any_addr.s_addr)
2552 memBufPrintf(&mb, "-%s", inet_ntoa(ip->addr2));
2553 if (ip->mask.s_addr != no_addr.s_addr)
2554 memBufPrintf(&mb, "/%s", inet_ntoa(ip->mask));
2555 wordlistAdd(W, mb.buf);
2556 memBufClean(&mb);
f084f6af 2557}
f32789f4 2558
56b63fa1 2559static wordlist *
9bea1d5b 2560aclDumpIpList(void *data)
56b63fa1 2561{
9bea1d5b 2562 wordlist *w = NULL;
e6ccf245 2563 splay_walk((splayNode *)data, aclDumpIpListWalkee, &w);
9bea1d5b 2564 return w;
f084f6af 2565}
2566
2567static void
9bea1d5b 2568aclDumpDomainListWalkee(void *node, void *state)
f084f6af 2569{
e6ccf245 2570 char *domain = (char *)node;
2571 wordlistAdd((wordlist **)state, domain);
56b63fa1 2572}
2573
2574static wordlist *
9bea1d5b 2575aclDumpDomainList(void *data)
56b63fa1 2576{
9bea1d5b 2577 wordlist *w = NULL;
e6ccf245 2578 splay_walk((splayNode *)data, aclDumpDomainListWalkee, &w);
9bea1d5b 2579 return w;
56b63fa1 2580}
7342cdc8 2581
56b63fa1 2582static wordlist *
9bea1d5b 2583aclDumpTimeSpecList(acl_time_data * t)
2584{
2585 wordlist *W = NULL;
2586 char buf[128];
2587 while (t != NULL) {
2588 snprintf(buf, sizeof(buf), "%c%c%c%c%c%c%c %02d:%02d-%02d:%02d",
2589 t->weekbits & ACL_SUNDAY ? 'S' : '-',
2590 t->weekbits & ACL_MONDAY ? 'M' : '-',
2591 t->weekbits & ACL_TUESDAY ? 'T' : '-',
2592 t->weekbits & ACL_WEDNESDAY ? 'W' : '-',
2593 t->weekbits & ACL_THURSDAY ? 'H' : '-',
2594 t->weekbits & ACL_FRIDAY ? 'F' : '-',
2595 t->weekbits & ACL_SATURDAY ? 'A' : '-',
2596 t->start / 60, t->start % 60, t->stop / 60, t->stop % 60);
2597 wordlistAdd(&W, buf);
2598 t = t->next;
2599 }
2600 return W;
56b63fa1 2601}
7342cdc8 2602
56b63fa1 2603static wordlist *
9bea1d5b 2604aclDumpRegexList(relist * data)
56b63fa1 2605{
9bea1d5b 2606 wordlist *W = NULL;
2607 while (data != NULL) {
2608 wordlistAdd(&W, data->pattern);
2609 data = data->next;
7342cdc8 2610 }
9bea1d5b 2611 return W;
56b63fa1 2612}
7342cdc8 2613
56b63fa1 2614static wordlist *
9bea1d5b 2615aclDumpIntlistList(intlist * data)
56b63fa1 2616{
9bea1d5b 2617 wordlist *W = NULL;
2618 char buf[32];
2619 while (data != NULL) {
2620 snprintf(buf, sizeof(buf), "%d", data->i);
2621 wordlistAdd(&W, buf);
2622 data = data->next;
7342cdc8 2623 }
9bea1d5b 2624 return W;
56b63fa1 2625}
7342cdc8 2626
8f663d72 2627static wordlist *
9bea1d5b 2628aclDumpIntRangeList(intrange * data)
8f663d72 2629{
9bea1d5b 2630 wordlist *W = NULL;
2631 char buf[32];
2632 while (data != NULL) {
2633 if (data->i == data->j)
2634 snprintf(buf, sizeof(buf), "%d", data->i);
2635 else
2636 snprintf(buf, sizeof(buf), "%d-%d", data->i, data->j);
2637 wordlistAdd(&W, buf);
2638 data = data->next;
8f663d72 2639 }
9bea1d5b 2640 return W;
8f663d72 2641}
2642
56b63fa1 2643static wordlist *
9bea1d5b 2644aclDumpProtoList(intlist * data)
56b63fa1 2645{
9bea1d5b 2646 wordlist *W = NULL;
2647 while (data != NULL) {
2648 wordlistAdd(&W, ProtocolStr[data->i]);
2649 data = data->next;
7342cdc8 2650 }
9bea1d5b 2651 return W;
56b63fa1 2652}
7342cdc8 2653
56b63fa1 2654static wordlist *
9bea1d5b 2655aclDumpMethodList(intlist * data)
56b63fa1 2656{
9bea1d5b 2657 wordlist *W = NULL;
2658 while (data != NULL) {
2659 wordlistAdd(&W, RequestMethodStr[data->i]);
2660 data = data->next;
7342cdc8 2661 }
9bea1d5b 2662 return W;
56b63fa1 2663}
7342cdc8 2664
56b63fa1 2665wordlist *
9bea1d5b 2666aclDumpGeneric(const acl * a)
56b63fa1 2667{
9bea1d5b 2668 debug(28, 3) ("aclDumpGeneric: %s type %d\n", a->name, a->type);
2669 switch (a->type) {
56b63fa1 2670 case ACL_SRC_IP:
2671 case ACL_DST_IP:
ae2c08a2 2672 case ACL_MY_IP:
9bea1d5b 2673 return aclDumpIpList(a->data);
56b63fa1 2674 case ACL_SRC_DOMAIN:
2675 case ACL_DST_DOMAIN:
9bea1d5b 2676 return aclDumpDomainList(a->data);
dba79ac5 2677#if SQUID_SNMP
2678 case ACL_SNMP_COMMUNITY:
e6ccf245 2679 return wordlistDup((wordlist *)a->data);
dba79ac5 2680#endif
3898f57f 2681#if USE_IDENT
c68e9c6b 2682 case ACL_IDENT:
621f6df2 2683 return aclDumpUserList((acl_user_data *)a->data);
145cf928 2684 case ACL_IDENT_REGEX:
621f6df2 2685 return aclDumpRegexList((relist *)a->data);
3898f57f 2686#endif
c68e9c6b 2687 case ACL_PROXY_AUTH:
e6ccf245 2688 return aclDumpUserList((acl_user_data *)a->data);
56b63fa1 2689 case ACL_TIME:
e6ccf245 2690 return aclDumpTimeSpecList((acl_time_data *)a->data);
145cf928 2691 case ACL_PROXY_AUTH_REGEX:
56b63fa1 2692 case ACL_URL_REGEX:
2693 case ACL_URLPATH_REGEX:
2694 case ACL_BROWSER:
fc659d9d 2695 case ACL_REFERER_REGEX:
6b8e7481 2696 case ACL_SRC_DOM_REGEX:
2697 case ACL_DST_DOM_REGEX:
6b5fbfee 2698 case ACL_REQ_MIME_TYPE:
2699 case ACL_REP_MIME_TYPE:
e6ccf245 2700 return aclDumpRegexList((relist *)a->data);
56b63fa1 2701 case ACL_SRC_ASN:
9bc73deb 2702 case ACL_MAXCONN:
56b63fa1 2703 case ACL_DST_ASN:
e6ccf245 2704 return aclDumpIntlistList((intlist *)a->data);
60d096f4 2705 case ACL_MAX_USER_IP:
9bea1d5b 2706 return aclDumpUserMaxIP(a->data);
8f663d72 2707 case ACL_URL_PORT:
7e3ce7b9 2708 case ACL_MY_PORT:
e6ccf245 2709 return aclDumpIntRangeList((intrange *)a->data);
56b63fa1 2710 case ACL_PROTO:
e6ccf245 2711 return aclDumpProtoList((intlist *)a->data);
56b63fa1 2712 case ACL_METHOD:
e6ccf245 2713 return aclDumpMethodList((intlist *)a->data);
56b63fa1 2714#if USE_ARP_ACL
2715 case ACL_SRC_ARP:
9bea1d5b 2716 return aclDumpArpList(a->data);
56b63fa1 2717#endif
d9572179 2718 case ACL_EXTERNAL:
2719 return aclDumpExternal(a->data);
a7ad6e4e 2720#if USE_SSL
2721 case ACL_USER_CERT:
2722 case ACL_CA_CERT:
2723 return aclDumpCertList(a->data);
2724#endif
56b63fa1 2725 case ACL_NONE:
6b5fbfee 2726 case ACL_ENUM_MAX:
9bea1d5b 2727 break;
56b63fa1 2728 }
9bea1d5b 2729 debug(28, 1) ("aclDumpGeneric: no case for ACL type %d\n", a->type);
2730 return NULL;
56b63fa1 2731}
2732
53cb32a9 2733/*
2734 * This function traverses all ACL elements referenced
2735 * by an access list (presumably 'http_access'). If
2736 * it finds a PURGE method ACL, then it returns TRUE,
2737 * otherwise FALSE.
2738 */
2739int
9bea1d5b 2740aclPurgeMethodInUse(acl_access * a)
2741{
2742 acl_list *b;
2743 for (; a; a = a->next) {
29b8d8d6 2744 for (b = a->aclList; b; b = b->next) {
2745 if (ACL_METHOD != b->_acl->type)
9bea1d5b 2746 continue;
e6ccf245 2747 if (aclMatchInteger((intlist *)b->_acl->data, METHOD_PURGE))
9bea1d5b 2748 return 1;
53cb32a9 2749 }
2750 }
9bea1d5b 2751 return 0;
53cb32a9 2752}
23351cb2 2753
2754
2755#if USE_ARP_ACL
2756/* ==== BEGIN ARP ACL SUPPORT ============================================= */
2757
2758/*
2759 * From: dale@server.ctam.bitmcnit.bryansk.su (Dale)
2760 * To: wessels@nlanr.net
2761 * Subject: Another Squid patch... :)
2762 * Date: Thu, 04 Dec 1997 19:55:01 +0300
2763 * ============================================================================
2764 *
2765 * Working on setting up a proper firewall for a network containing some
2766 * Win'95 computers at our Univ, I've discovered that some smart students
2767 * avoid the restrictions easily just changing their IP addresses in Win'95
2768 * Contol Panel... It has been getting boring, so I took Squid-1.1.18
2769 * sources and added a new acl type for hard-wired access control:
2770 *
2771 * acl <name> arp <Ethernet address> ...
2772 *
2773 * For example,
2774 *
2775 * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38
bd0c865a 2776 *
2777 * NOTE: Linux code by David Luyer <luyer@ucs.uwa.edu.au>.
2778 * Original (BSD-specific) code no longer works.
aabc40d1 2779 * Solaris code by R. Gancarz <radekg@solaris.elektrownia-lagisza.com.pl>
23351cb2 2780 */
2781
aabc40d1 2782#ifdef _SQUID_SOLARIS_
2783#include <sys/sockio.h>
2784#else
23351cb2 2785#include <sys/sysctl.h>
aabc40d1 2786#endif
a931a29b 2787#ifdef _SQUID_LINUX_
2788#include <net/if_arp.h>
2789#include <sys/ioctl.h>
2790#else
23351cb2 2791#include <net/if_dl.h>
a931a29b 2792#endif
23351cb2 2793#include <net/route.h>
2794#include <net/if.h>
efd900cb 2795#if HAVE_NETINET_IF_ETHER_H
23351cb2 2796#include <netinet/if_ether.h>
efd900cb 2797#endif
23351cb2 2798
2799/*
2800 * Decode an ascii representation (asc) of an ethernet adress, and place
2801 * it in eth[6].
2802 */
2803static int
9bea1d5b 2804decode_eth(const char *asc, char *eth)
23351cb2 2805{
9bea1d5b 2806 int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
2807 if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) {
2808 debug(28, 0) ("decode_eth: Invalid ethernet address '%s'\n", asc);
2809 return 0; /* This is not valid address */
23351cb2 2810 }
9bea1d5b 2811 eth[0] = (u_char) a1;
2812 eth[1] = (u_char) a2;
2813 eth[2] = (u_char) a3;
2814 eth[3] = (u_char) a4;
2815 eth[4] = (u_char) a5;
2816 eth[5] = (u_char) a6;
2817 return 1;
23351cb2 2818}
2819
7342cdc8 2820static acl_arp_data *
9bea1d5b 2821aclParseArpData(const char *t)
23351cb2 2822{
9bea1d5b 2823 LOCAL_ARRAY(char, eth, 256);
dfb22746 2824 acl_arp_data *q = (acl_arp_data *)xcalloc(1, sizeof(acl_arp_data));
9bea1d5b 2825 debug(28, 5) ("aclParseArpData: %s\n", t);
2826 if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) {
2827 debug(28, 0) ("aclParseArpData: Bad ethernet address: '%s'\n", t);
2828 safe_free(q);
2829 return NULL;
23351cb2 2830 }
9bea1d5b 2831 if (!decode_eth(eth, q->eth)) {
2832 debug(28, 0) ("%s line %d: %s\n",
2833 cfg_filename, config_lineno, config_input_line);
2834 debug(28, 0) ("aclParseArpData: Ignoring invalid ARP acl entry: can't parse '%s'\n", eth);
2835 safe_free(q);
2836 return NULL;
23351cb2 2837 }
9bea1d5b 2838 return q;
23351cb2 2839}
2840
2841
2842/*******************/
2843/* aclParseArpList */
2844/*******************/
23351cb2 2845static void
9bea1d5b 2846aclParseArpList(void *curlist)
23351cb2 2847{
9bea1d5b 2848 char *t = NULL;
dfb22746 2849 splayNode **Top = (splayNode **)curlist;
9bea1d5b 2850 acl_arp_data *q = NULL;
2851 while ((t = strtokFile())) {
2852 if ((q = aclParseArpData(t)) == NULL)
2853 continue;
2854 *Top = splay_insert(q, *Top, aclArpCompare);
23351cb2 2855 }
2856}
23351cb2 2857
2858/***************/
2859/* aclMatchArp */
2860/***************/
23351cb2 2861static int
9bea1d5b 2862aclMatchArp(void *dataptr, struct in_addr c)
23351cb2 2863{
aabc40d1 2864#if defined(_SQUID_LINUX_)
9bea1d5b 2865 struct arpreq arpReq;
2866 struct sockaddr_in ipAddr;
2867 unsigned char ifbuffer[sizeof(struct ifreq) * 64];
2868 struct ifconf ifc;
2869 struct ifreq *ifr;
2870 int offset;
dfb22746 2871 splayNode **Top = (splayNode **)dataptr;
9bea1d5b 2872 /*
2873 * The linux kernel 2.2 maintains per interface ARP caches and
2874 * thus requires an interface name when doing ARP queries.
2875 *
2876 * The older 2.0 kernels appear to use a unified ARP cache,
2877 * and require an empty interface name
2878 *
2879 * To support both, we attempt the lookup with a blank interface
2880 * name first. If that does not succeed, the try each interface
2881 * in turn
2882 */
2883 /*
2884 * Set up structures for ARP lookup with blank interface name
2885 */
2886 ipAddr.sin_family = AF_INET;
2887 ipAddr.sin_port = 0;
2888 ipAddr.sin_addr = c;
2889 memset(&arpReq, '\0', sizeof(arpReq));
2890 xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
2891 /* Query ARP table */
2892 if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
2893 /* Skip non-ethernet interfaces */
2894 if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
2895 return 0;
2896 }
2897 debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
2898 arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
2899 arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
2900 arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
2901 /* Do lookup */
2902 *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
2903 debug(28, 3) ("aclMatchArp: '%s' %s\n",
2904 inet_ntoa(c), splayLastResult ? "NOT found" : "found");
2905 return (0 == splayLastResult);
2906 }
2907 /* lookup list of interface names */
2908 ifc.ifc_len = sizeof(ifbuffer);
dfb22746 2909 ifc.ifc_buf = (char *)ifbuffer;
9bea1d5b 2910 if (ioctl(HttpSockets[0], SIOCGIFCONF, &ifc) < 0) {
2911 debug(28, 1) ("Attempt to retrieve interface list failed: %s\n",
2912 xstrerror());
2913 return 0;
2914 }
dfb22746 2915 if (ifc.ifc_len > (int)sizeof(ifbuffer)) {
9bea1d5b 2916 debug(28, 1) ("Interface list too long - %d\n", ifc.ifc_len);
2917 return 0;
2918 }
2919 /* Attempt ARP lookup on each interface */
2920 offset = 0;
2921 while (offset < ifc.ifc_len) {
2922 ifr = (struct ifreq *) (ifbuffer + offset);
2923 offset += sizeof(*ifr);
2924 /* Skip loopback and aliased interfaces */
2925 if (0 == strncmp(ifr->ifr_name, "lo", 2))
2926 continue;
2927 if (NULL != strchr(ifr->ifr_name, ':'))
2928 continue;
2929 debug(28, 4) ("Looking up ARP address for %s on %s\n", inet_ntoa(c),
2930 ifr->ifr_name);
2931 /* Set up structures for ARP lookup */
2932 ipAddr.sin_family = AF_INET;
2933 ipAddr.sin_port = 0;
2934 ipAddr.sin_addr = c;
2935 memset(&arpReq, '\0', sizeof(arpReq));
2936 xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
2937 strncpy(arpReq.arp_dev, ifr->ifr_name, sizeof(arpReq.arp_dev) - 1);
2938 arpReq.arp_dev[sizeof(arpReq.arp_dev) - 1] = '\0';
2939 /* Query ARP table */
2940 if (-1 == ioctl(HttpSockets[0], SIOCGARP, &arpReq)) {
2941 /*
2942 * Query failed. Do not log failed lookups or "device
2943 * not supported"
2944 */
2945 if (ENXIO == errno)
2946 (void) 0;
2947 else if (ENODEV == errno)
2948 (void) 0;
2949 else
2950 debug(28, 1) ("ARP query failed: %s: %s\n",
2951 ifr->ifr_name, xstrerror());
2952 continue;
7e3ce7b9 2953 }
9bea1d5b 2954 /* Skip non-ethernet interfaces */
2955 if (arpReq.arp_ha.sa_family != ARPHRD_ETHER)
2956 continue;
2957 debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x on %s\n",
2958 arpReq.arp_ha.sa_data[0] & 0xff,
2959 arpReq.arp_ha.sa_data[1] & 0xff,
2960 arpReq.arp_ha.sa_data[2] & 0xff,
2961 arpReq.arp_ha.sa_data[3] & 0xff,
2962 arpReq.arp_ha.sa_data[4] & 0xff,
2963 arpReq.arp_ha.sa_data[5] & 0xff, ifr->ifr_name);
2964 /* Do lookup */
2965 *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
2966 /* Return if match, otherwise continue to other interfaces */
2967 if (0 == splayLastResult) {
2968 debug(28, 3) ("aclMatchArp: %s found on %s\n",
2969 inet_ntoa(c), ifr->ifr_name);
2970 return 1;
d35b9a94 2971 }
9bea1d5b 2972 /*
2973 * Should we stop looking here? Can the same IP address
2974 * exist on multiple interfaces?
2975 */
7e3ce7b9 2976 }
aabc40d1 2977#elif defined(_SQUID_SOLARIS_)
9bea1d5b 2978 struct arpreq arpReq;
2979 struct sockaddr_in ipAddr;
2980 unsigned char ifbuffer[sizeof(struct ifreq) * 64];
2981 struct ifconf ifc;
2982 struct ifreq *ifr;
2983 int offset;
2984 splayNode **Top = dataptr;
2985 /*
2986 * Set up structures for ARP lookup with blank interface name
2987 */
2988 ipAddr.sin_family = AF_INET;
2989 ipAddr.sin_port = 0;
2990 ipAddr.sin_addr = c;
2991 memset(&arpReq, '\0', sizeof(arpReq));
2992 xmemcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
2993 /* Query ARP table */
2994 if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) != -1) {
2995 /*
2996 * Solaris (at least 2.6/x86) does not use arp_ha.sa_family -
2997 * it returns 00:00:00:00:00:00 for non-ethernet media
2998 */
2999 if (arpReq.arp_ha.sa_data[0] == 0 &&
3000 arpReq.arp_ha.sa_data[1] == 0 &&
3001 arpReq.arp_ha.sa_data[2] == 0 &&
3002 arpReq.arp_ha.sa_data[3] == 0 &&
3003 arpReq.arp_ha.sa_data[4] == 0 && arpReq.arp_ha.sa_data[5] == 0)
3004 return 0;
3005 debug(28, 4) ("Got address %02x:%02x:%02x:%02x:%02x:%02x\n",
3006 arpReq.arp_ha.sa_data[0] & 0xff, arpReq.arp_ha.sa_data[1] & 0xff,
3007 arpReq.arp_ha.sa_data[2] & 0xff, arpReq.arp_ha.sa_data[3] & 0xff,
3008 arpReq.arp_ha.sa_data[4] & 0xff, arpReq.arp_ha.sa_data[5] & 0xff);
3009 /* Do lookup */
3010 *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
3011 debug(28, 3) ("aclMatchArp: '%s' %s\n",
3012 inet_ntoa(c), splayLastResult ? "NOT found" : "found");
3013 return (0 == splayLastResult);
aabc40d1 3014 }
3015#else
9bea1d5b 3016 WRITE ME;
aabc40d1 3017#endif
9bea1d5b 3018 /*
3019 * Address was not found on any interface
3020 */
3021 debug(28, 3) ("aclMatchArp: %s NOT found\n", inet_ntoa(c));
3022 return 0;
23351cb2 3023}
23351cb2 3024
f084f6af 3025static int
9bea1d5b 3026aclArpCompare(const void *a, const void *b)
f084f6af 3027{
aabc40d1 3028#if defined(_SQUID_LINUX_)
dfb22746 3029 const unsigned short *d1 = (const unsigned short *)a;
3030 const unsigned short *d2 = (const unsigned short *)b;
9bea1d5b 3031 if (d1[0] != d2[0])
3032 return (d1[0] > d2[0]) ? 1 : -1;
3033 if (d1[1] != d2[1])
3034 return (d1[1] > d2[1]) ? 1 : -1;
3035 if (d1[2] != d2[2])
3036 return (d1[2] > d2[2]) ? 1 : -1;
aabc40d1 3037#elif defined(_SQUID_SOLARIS_)
dfb22746 3038 const unsigned char *d1 = (const unsigned char *)a;
3039 const unsigned char *d2 = (const unsigned char *)b;
9bea1d5b 3040 if (d1[0] != d2[0])
3041 return (d1[0] > d2[0]) ? 1 : -1;
3042 if (d1[1] != d2[1])
3043 return (d1[1] > d2[1]) ? 1 : -1;
3044 if (d1[2] != d2[2])
3045 return (d1[2] > d2[2]) ? 1 : -1;
3046 if (d1[3] != d2[3])
3047 return (d1[3] > d2[3]) ? 1 : -1;
3048 if (d1[4] != d2[4])
3049 return (d1[4] > d2[4]) ? 1 : -1;
3050 if (d1[5] != d2[5])
3051 return (d1[5] > d2[5]) ? 1 : -1;
a931a29b 3052#else
9bea1d5b 3053 WRITE ME;
aabc40d1 3054#endif
9bea1d5b 3055 return 0;
f084f6af 3056}
3057
aabc40d1 3058#if UNUSED_CODE
bd0c865a 3059/**********************************************************************
3060* This is from the pre-splay-tree code for BSD
3061* I suspect the Linux approach will work on most O/S and be much
3062* better - <luyer@ucs.uwa.edu.au>
3063***********************************************************************
23351cb2 3064static int
3065checkARP(u_long ip, char *eth)
3066{
3067 int mib[6] =
3068 {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
3069 size_t needed;
3070 char *buf, *next, *lim;
3071 struct rt_msghdr *rtm;
3072 struct sockaddr_inarp *sin;
3073 struct sockaddr_dl *sdl;
3074 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
ee89e05a 3075 debug(28, 0) ("Can't estimate ARP table size!\n");
23351cb2 3076 return 0;
3077 }
ee89e05a 3078 if ((buf = xmalloc(needed)) == NULL) {
3079 debug(28, 0) ("Can't allocate temporary ARP table!\n");
23351cb2 3080 return 0;
3081 }
3082 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
ee89e05a 3083 debug(28, 0) ("Can't retrieve ARP table!\n");
3084 xfree(buf);
23351cb2 3085 return 0;
3086 }
3087 lim = buf + needed;
3088 for (next = buf; next < lim; next += rtm->rtm_msglen) {
3089 rtm = (struct rt_msghdr *) next;
3090 sin = (struct sockaddr_inarp *) (rtm + 1);
3091 sdl = (struct sockaddr_dl *) (sin + 1);
3092 if (sin->sin_addr.s_addr == ip) {
3093 if (sdl->sdl_alen)
ee89e05a 3094 if (!memcmp(LLADDR(sdl), eth, 6)) {
3095 xfree(buf);
23351cb2 3096 return 1;
ee89e05a 3097 }
3098 break;
23351cb2 3099 }
3100 }
ee89e05a 3101 xfree(buf);
23351cb2 3102 return 0;
3103}
bd0c865a 3104**********************************************************************/
a931a29b 3105#endif
23351cb2 3106
bd0c865a 3107static void
9bea1d5b 3108aclDumpArpListWalkee(void *node, void *state)
56b63fa1 3109{
dfb22746 3110 acl_arp_data *arp = (acl_arp_data *)node;
9bea1d5b 3111 static char buf[24];
9bea1d5b 3112 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
3113 arp->eth[0], arp->eth[1], arp->eth[2], arp->eth[3],
3114 arp->eth[4], arp->eth[5]);
dfb22746 3115 wordlistAdd((wordlist **)state, buf);
f084f6af 3116}
3117
3118static wordlist *
9bea1d5b 3119aclDumpArpList(void *data)
f084f6af 3120{
9bea1d5b 3121 wordlist *w = NULL;
dfb22746 3122 splay_walk((splayNode *)data, aclDumpArpListWalkee, &w);
9bea1d5b 3123 return w;
56b63fa1 3124}
3125
23351cb2 3126/* ==== END ARP ACL SUPPORT =============================================== */
2b6662ba 3127#endif /* USE_ARP_ACL */