]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl.cc
2.1 branch merge
[thirdparty/squid.git] / src / acl.cc
CommitLineData
79d39a72 1
8213067d 2/*
c68e9c6b 3 * $Id: acl.cc,v 1.187 1998/11/12 06:27:54 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 28 Access Control
6 * AUTHOR: Duane Wessels
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
e25c139f 13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
8213067d 34 */
7dd57fa2 35
36#include "squid.h"
f32789f4 37#include "splay.h"
f32789f4 38
e924600d 39static int aclFromFile = 0;
40static FILE *aclFile;
c68e9c6b 41static hash_table *proxy_auth_cache = NULL;
7dd57fa2 42
f084f6af 43static void aclParseDomainList(void *curlist);
44static void aclParseIpList(void *curlist);
45static void aclParseIntlist(void *curlist);
46static void aclParseWordList(void *curlist);
47static void aclParseProtoList(void *curlist);
48static void aclParseMethodList(void *curlist);
49static void aclParseTimeSpec(void *curlist);
8f663d72 50static void aclParseIntRange(void *curlist);
f084f6af 51static char *strtokFile(void);
7342cdc8 52static void aclDestroyAclList(acl_list * list);
53static void aclDestroyTimeList(acl_time_data * data);
8f663d72 54static void aclDestroyIntRange(intrange *);
ec878047 55static FREE aclFreeProxyAuthUser;
669fefd4 56static int aclMatchAcl(struct _acl *, aclCheck_t *);
8f663d72 57static int aclMatchIntegerRange(intrange * data, int i);
7342cdc8 58static int aclMatchTime(acl_time_data * data, time_t when);
c68e9c6b 59static int aclMatchUser(wordlist * data, const char *ident);
f5b8bbc4 60static int aclMatchIp(void *dataptr, struct in_addr c);
61static int aclMatchDomainList(void *dataptr, const char *);
8f663d72 62static int aclMatchIntegerRange(intrange * data, int i);
dba79ac5 63static int aclMatchWordList(wordlist *, const char *);
56b63fa1 64static squid_acl aclStrToType(const char *s);
f5b8bbc4 65static int decode_addr(const char *, struct in_addr *, struct in_addr *);
66static void aclCheck(aclCheck_t * checklist);
fc5d6f7f 67static void aclCheckCallback(aclCheck_t * checklist, allow_t answer);
b69f7771 68static IPH aclLookupDstIPDone;
53ad48e6 69static IPH aclLookupDstIPforASNDone;
348b2031 70static FQDNH aclLookupSrcFQDNDone;
71static FQDNH aclLookupDstFQDNDone;
c68e9c6b 72static void aclLookupProxyAuthStart(aclCheck_t * checklist);
73static void aclLookupProxyAuthDone(void *data, char *result);
f084f6af 74static wordlist *aclDumpIpList(void *);
16300b58 75static wordlist *aclDumpDomainList(void *data);
7342cdc8 76static wordlist *aclDumpTimeSpecList(acl_time_data *);
77static wordlist *aclDumpRegexList(relist * data);
78static wordlist *aclDumpIntlistList(intlist * data);
8f663d72 79static wordlist *aclDumpIntRangeList(intrange * data);
7342cdc8 80static wordlist *aclDumpProtoList(intlist * data);
81static wordlist *aclDumpMethodList(intlist * data);
f084f6af 82static SPLAYCMP aclIpNetworkCompare;
83static SPLAYCMP aclHostDomainCompare;
84static SPLAYCMP aclDomainCompare;
85static SPLAYWALKEE aclDumpIpListWalkee;
86static SPLAYWALKEE aclDumpDomainListWalkee;
c68e9c6b 87static SPLAYFREE aclFreeIpData;
f32789f4 88
23351cb2 89#if USE_ARP_ACL
f084f6af 90static void aclParseArpList(void *curlist);
23351cb2 91static int decode_eth(const char *asc, char *eth);
92static int aclMatchArp(void *dataptr, struct in_addr c);
bd0c865a 93static wordlist *aclDumpArpList(void *);
f084f6af 94static SPLAYCMP aclArpCompare;
bd0c865a 95static SPLAYWALKEE aclDumpArpListWalkee;
23351cb2 96#endif
97
e924600d 98static char *
c10aaf05 99strtokFile(void)
100{
101 char *t, *fn;
102 LOCAL_ARRAY(char, buf, 256);
103
e5f6c5c2 104 strtok_again:
c10aaf05 105 if (!aclFromFile) {
106 t = (strtok(NULL, w_space));
107 if (t && (*t == '\"' || *t == '\'')) {
108 /* quote found, start reading from file */
109 fn = ++t;
e5f6c5c2 110 while (*t && *t != '\"' && *t != '\'')
111 t++;
c10aaf05 112 *t = '\0';
113 if ((aclFile = fopen(fn, "r")) == NULL) {
a3d5953d 114 debug(28, 0) ("strtokFile: %s not found\n", fn);
e5f6c5c2 115 return (NULL);
c10aaf05 116 }
117 aclFromFile = 1;
118 } else {
0153d498 119 return t;
c10aaf05 120 }
121 }
122 /* aclFromFile */
123 if (fgets(buf, 256, aclFile) == NULL) {
124 /* stop reading from file */
125 fclose(aclFile);
126 aclFromFile = 0;
127 goto strtok_again;
128 } else {
129 t = buf;
130 /* skip leading and trailing white space */
131 t += strspn(buf, w_space);
132 t[strcspn(t, w_space)] = '\0';
c68e9c6b 133 /* skip comments */
134 if (*t == '#')
135 goto strtok_again;
136 /* skip blank lines */
137 if (!*t)
138 goto strtok_again;
0153d498 139 return t;
c10aaf05 140 }
141}
142
8203a132 143static squid_acl
56b63fa1 144aclStrToType(const char *s)
7dd57fa2 145{
146 if (!strcmp(s, "src"))
147 return ACL_SRC_IP;
30a4f2a8 148 if (!strcmp(s, "dst"))
149 return ACL_DST_IP;
7dd57fa2 150 if (!strcmp(s, "domain"))
151 return ACL_DST_DOMAIN;
f88bb09c 152 if (!strcmp(s, "dstdomain"))
153 return ACL_DST_DOMAIN;
154 if (!strcmp(s, "srcdomain"))
155 return ACL_SRC_DOMAIN;
d0d41f07 156 if (!strcmp(s, "dstdom_regex"))
157 return ACL_DST_DOM_REGEX;
158 if (!strcmp(s, "srcdom_regex"))
159 return ACL_SRC_DOM_REGEX;
7dd57fa2 160 if (!strcmp(s, "time"))
161 return ACL_TIME;
162 if (!strcmp(s, "pattern"))
6e40f263 163 return ACL_URLPATH_REGEX;
164 if (!strcmp(s, "urlpath_regex"))
165 return ACL_URLPATH_REGEX;
166 if (!strcmp(s, "url_regex"))
7dd57fa2 167 return ACL_URL_REGEX;
168 if (!strcmp(s, "port"))
169 return ACL_URL_PORT;
c68e9c6b 170 if (!strcmp(s, "ident"))
171 return ACL_IDENT;
30a4f2a8 172 if (!strncmp(s, "proto", 5))
7dd57fa2 173 return ACL_PROTO;
92a6f4b1 174 if (!strcmp(s, "method"))
175 return ACL_METHOD;
d3416189 176 if (!strcmp(s, "browser"))
177 return ACL_BROWSER;
afe95a7e 178 if (!strcmp(s, "proxy_auth"))
179 return ACL_PROXY_AUTH;
5d6c7aad 180 if (!strcmp(s, "src_as"))
181 return ACL_SRC_ASN;
182 if (!strcmp(s, "dst_as"))
183 return ACL_DST_ASN;
dba79ac5 184#if SQUID_SNMP
43d4303e 185 if (!strcmp(s, "snmp_community"))
dba79ac5 186 return ACL_SNMP_COMMUNITY;
187#endif
bd05e3e3 188 if (!strcmp(s, "src_rtt"))
189 return ACL_NETDB_SRC_RTT;
66c75c41 190#if USE_ARP_ACL
191 if (!strcmp(s, "arp"))
192 return ACL_SRC_ARP;
193#endif
7dd57fa2 194 return ACL_NONE;
195}
196
56b63fa1 197const char *
198aclTypeToStr(squid_acl type)
199{
200 if (type == ACL_SRC_IP)
201 return "src";
202 if (type == ACL_DST_IP)
203 return "dst";
204 if (type == ACL_DST_DOMAIN)
205 return "dstdomain";
206 if (type == ACL_SRC_DOMAIN)
207 return "srcdomain";
d0d41f07 208 if (type == ACL_DST_DOM_REGEX)
209 return "dstdom_regex";
210 if (type == ACL_SRC_DOM_REGEX)
211 return "srcdom_regex";
56b63fa1 212 if (type == ACL_TIME)
213 return "time";
214 if (type == ACL_URLPATH_REGEX)
215 return "urlpath_regex";
216 if (type == ACL_URL_REGEX)
217 return "url_regex";
218 if (type == ACL_URL_PORT)
219 return "port";
c68e9c6b 220 if (type == ACL_IDENT)
221 return "ident";
56b63fa1 222 if (type == ACL_PROTO)
223 return "proto";
224 if (type == ACL_METHOD)
225 return "method";
226 if (type == ACL_BROWSER)
227 return "browser";
228 if (type == ACL_PROXY_AUTH)
229 return "proxy_auth";
230 if (type == ACL_SRC_ASN)
231 return "src_as";
232 if (type == ACL_DST_ASN)
233 return "dst_as";
dba79ac5 234#if SQUID_SNMP
235 if (type == ACL_SNMP_COMMUNITY)
43d4303e 236 return "snmp_community";
dba79ac5 237#endif
bd05e3e3 238 if (type == ACL_NETDB_SRC_RTT)
239 return "src_rtt";
56b63fa1 240#if USE_ARP_ACL
241 if (type == ACL_SRC_ARP)
242 return "arp";
243#endif
244 return "ERROR";
245}
246
7342cdc8 247acl *
0ee4272b 248aclFindByName(const char *name)
7dd57fa2 249{
7342cdc8 250 acl *a;
f1dc9b30 251 for (a = Config.aclList; a; a = a->next)
1969665d 252 if (!strcasecmp(a->name, name))
253 return a;
254 return NULL;
7dd57fa2 255}
256
fda94b88 257static void
258aclParseIntlist(void *curlist)
7dd57fa2 259{
fda94b88 260 intlist **Tail;
7dd57fa2 261 intlist *q = NULL;
262 char *t = NULL;
fda94b88 263 for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
c10aaf05 264 while ((t = strtokFile())) {
c68e9c6b 265 q = memAllocate(MEM_INTLIST);
7dd57fa2 266 q->i = atoi(t);
267 *(Tail) = q;
268 Tail = &q->next;
269 }
7dd57fa2 270}
271
8f663d72 272static void
273aclParseIntRange(void *curlist)
274{
275 intrange **Tail;
276 intrange *q = NULL;
277 char *t = NULL;
278 for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
279 while ((t = strtokFile())) {
280 q = xcalloc(1, sizeof(intrange));
281 q->i = atoi(t);
282 t = strchr(t, '-');
283 if (t && *(++t))
5942e8d4 284 q->j = atoi(t);
8f663d72 285 else
5942e8d4 286 q->j = q->i;
8f663d72 287 *(Tail) = q;
288 Tail = &q->next;
289 }
290}
291
fda94b88 292static void
293aclParseProtoList(void *curlist)
7dd57fa2 294{
fda94b88 295 intlist **Tail;
7dd57fa2 296 intlist *q = NULL;
297 char *t = NULL;
fda94b88 298 for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
c10aaf05 299 while ((t = strtokFile())) {
c68e9c6b 300 q = memAllocate(MEM_INTLIST);
92a6f4b1 301 q->i = (int) urlParseProtocol(t);
1969665d 302 *(Tail) = q;
303 Tail = &q->next;
7dd57fa2 304 }
7dd57fa2 305}
92a6f4b1 306
fda94b88 307static void
308aclParseMethodList(void *curlist)
92a6f4b1 309{
fda94b88 310 intlist **Tail;
92a6f4b1 311 intlist *q = NULL;
312 char *t = NULL;
fda94b88 313 for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
c10aaf05 314 while ((t = strtokFile())) {
c68e9c6b 315 q = memAllocate(MEM_INTLIST);
92a6f4b1 316 q->i = (int) urlParseMethod(t);
a90eae18 317 if (q->i == METHOD_PURGE)
17a0a4ee 318 Config.onoff.enable_purge = 1;
92a6f4b1 319 *(Tail) = q;
320 Tail = &q->next;
321 }
92a6f4b1 322}
323
06e6d12a 324/*
325 * Decode a ascii representation (asc) of a IP adress, and place
30a4f2a8 326 * adress and netmask information in addr and mask.
06e6d12a 327 * This function should NOT be called if 'asc' is a hostname!
30a4f2a8 328 */
8203a132 329static int
0ee4272b 330decode_addr(const char *asc, struct in_addr *addr, struct in_addr *mask)
7dd57fa2 331{
429fdbec 332 u_num32 a;
ef2d27ff 333 int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
30a4f2a8 334
335 switch (sscanf(asc, "%d.%d.%d.%d", &a1, &a2, &a3, &a4)) {
336 case 4: /* a dotted quad */
429fdbec 337 if (!safe_inet_addr(asc, addr)) {
a3d5953d 338 debug(28, 0) ("decode_addr: unsafe IP address: '%s'\n", asc);
429fdbec 339 fatal("decode_addr: unsafe IP address");
30a4f2a8 340 }
341 break;
342 case 1: /* a significant bits value for a mask */
343 if (a1 >= 0 && a1 < 33) {
ca98227c 344 addr->s_addr = a1 ? htonl(0xfffffffful << (32 - a1)) : 0;
30a4f2a8 345 break;
346 }
347 default:
06e6d12a 348 debug(28, 0) ("decode_addr: Invalid IP address '%s'\n", asc);
349 return 0; /* This is not valid address */
30a4f2a8 350 }
351
352 if (mask != NULL) { /* mask == NULL if called to decode a netmask */
353
354 /* Guess netmask */
ff8d0ea6 355 a = (u_num32) ntohl(addr->s_addr);
86ee2017 356 if (!(a & 0xFFFFFFFFul))
357 mask->s_addr = htonl(0x00000000ul);
30a4f2a8 358 else if (!(a & 0x00FFFFFF))
86ee2017 359 mask->s_addr = htonl(0xFF000000ul);
30a4f2a8 360 else if (!(a & 0x0000FFFF))
86ee2017 361 mask->s_addr = htonl(0xFFFF0000ul);
30a4f2a8 362 else if (!(a & 0x000000FF))
86ee2017 363 mask->s_addr = htonl(0xFFFFFF00ul);
30a4f2a8 364 else
86ee2017 365 mask->s_addr = htonl(0xFFFFFFFFul);
30a4f2a8 366 }
367 return 1;
368}
369
75e5a32e 370
371#define SCAN_ACL1 "%[0123456789.]-%[0123456789.]/%[0123456789.]"
372#define SCAN_ACL2 "%[0123456789.]-%[0123456789.]"
373#define SCAN_ACL3 "%[0123456789.]/%[0123456789.]"
374#define SCAN_ACL4 "%[0123456789.]"
375
56b63fa1 376static acl_ip_data *
dfc52ac5 377aclParseIpData(const char *t)
378{
379 LOCAL_ARRAY(char, addr1, 256);
380 LOCAL_ARRAY(char, addr2, 256);
381 LOCAL_ARRAY(char, mask, 256);
c68e9c6b 382 acl_ip_data *q = memAllocate(MEM_ACL_IP_DATA);
06e6d12a 383 acl_ip_data *r;
384 acl_ip_data **Q;
385 struct hostent *hp;
386 char **x;
a3d5953d 387 debug(28, 5) ("aclParseIpData: %s\n", t);
dfc52ac5 388 if (!strcasecmp(t, "all")) {
389 q->addr1.s_addr = 0;
390 q->addr2.s_addr = 0;
391 q->mask.s_addr = 0;
392 return q;
393 }
75e5a32e 394 if (sscanf(t, SCAN_ACL1, addr1, addr2, mask) == 3) {
dfc52ac5 395 (void) 0;
75e5a32e 396 } else if (sscanf(t, SCAN_ACL2, addr1, addr2) == 2) {
dfc52ac5 397 mask[0] = '\0';
75e5a32e 398 } else if (sscanf(t, SCAN_ACL3, addr1, mask) == 2) {
dfc52ac5 399 addr2[0] = '\0';
75e5a32e 400 } else if (sscanf(t, SCAN_ACL4, addr1) == 1) {
dfc52ac5 401 addr2[0] = '\0';
402 mask[0] = '\0';
403 } else if (sscanf(t, "%[^/]/%s", addr1, mask) == 2) {
404 addr2[0] = '\0';
405 } else if (sscanf(t, "%s", addr1) == 1) {
06e6d12a 406 /*
407 * Note, must use plain gethostbyname() here because at startup
408 * ipcache hasn't been initialized
409 */
410 if ((hp = gethostbyname(addr1)) == NULL) {
411 debug(28, 0) ("aclParseIpData: Bad host/IP: '%s'\n", t);
412 safe_free(q);
413 return NULL;
414 }
415 Q = &q;
416 for (x = hp->h_addr_list; x != NULL && *x != NULL; x++) {
417 if ((r = *Q) == NULL)
c68e9c6b 418 r = *Q = memAllocate(MEM_ACL_IP_DATA);
06e6d12a 419 xmemcpy(&r->addr1.s_addr, *x, sizeof(r->addr1.s_addr));
420 r->addr2.s_addr = 0;
e711a2ff 421 r->mask.s_addr = no_addr.s_addr; /* 255.255.255.255 */
06e6d12a 422 Q = &r->next;
423 debug(28, 3) ("%s --> %s\n", addr1, inet_ntoa(r->addr1));
424 }
425 return q;
dfc52ac5 426 } else {
a3d5953d 427 debug(28, 0) ("aclParseIpData: Bad host/IP: '%s'\n", t);
dfc52ac5 428 safe_free(q);
429 return NULL;
430 }
431 /* Decode addr1 */
432 if (!decode_addr(addr1, &q->addr1, &q->mask)) {
a3d5953d 433 debug(28, 0) ("%s line %d: %s\n",
dfc52ac5 434 cfg_filename, config_lineno, config_input_line);
a3d5953d 435 debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown first address '%s'\n", addr1);
dfc52ac5 436 safe_free(q);
437 return NULL;
438 }
439 /* Decode addr2 */
440 if (*addr2 && !decode_addr(addr2, &q->addr2, &q->mask)) {
a3d5953d 441 debug(28, 0) ("%s line %d: %s\n",
dfc52ac5 442 cfg_filename, config_lineno, config_input_line);
a3d5953d 443 debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown second address '%s'\n", addr2);
dfc52ac5 444 safe_free(q);
445 return NULL;
446 }
447 /* Decode mask */
448 if (*mask && !decode_addr(mask, &q->mask, NULL)) {
a3d5953d 449 debug(28, 0) ("%s line %d: %s\n",
dfc52ac5 450 cfg_filename, config_lineno, config_input_line);
a3d5953d 451 debug(28, 0) ("aclParseIpData: Ignoring invalid IP acl entry: unknown netmask '%s'\n", mask);
dfc52ac5 452 safe_free(q);
453 return NULL;
454 }
455 q->addr1.s_addr &= q->mask.s_addr;
456 q->addr2.s_addr &= q->mask.s_addr;
457 /* 1.2.3.4/255.255.255.0 --> 1.2.3.0 */
458 return q;
459}
30a4f2a8 460
f32789f4 461/******************/
462/* aclParseIpList */
463/******************/
8bad0cc5 464
fda94b88 465static void
466aclParseIpList(void *curlist)
30a4f2a8 467{
cb0486c3 468 char *t = NULL;
f32789f4 469 splayNode **Top = curlist;
56b63fa1 470 acl_ip_data *q = NULL;
c10aaf05 471 while ((t = strtokFile())) {
06e6d12a 472 q = aclParseIpData(t);
473 while (q != NULL) {
474 *Top = splay_insert(q, *Top, aclIpNetworkCompare);
475 q = q->next;
476 }
b1ef1220 477 }
8bad0cc5 478}
479
fda94b88 480static void
481aclParseTimeSpec(void *curlist)
7dd57fa2 482{
7342cdc8 483 acl_time_data *q = NULL;
484 acl_time_data **Tail;
92a6f4b1 485 int h1, m1, h2, m2;
486 char *t = NULL;
fda94b88 487 for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
c68e9c6b 488 q = memAllocate(MEM_ACL_TIME_DATA);
c10aaf05 489 while ((t = strtokFile())) {
92a6f4b1 490 if (*t < '0' || *t > '9') {
491 /* assume its day-of-week spec */
492 while (*t) {
493 switch (*t++) {
494 case 'S':
fda94b88 495 q->weekbits |= ACL_SUNDAY;
92a6f4b1 496 break;
497 case 'M':
fda94b88 498 q->weekbits |= ACL_MONDAY;
92a6f4b1 499 break;
500 case 'T':
fda94b88 501 q->weekbits |= ACL_TUESDAY;
92a6f4b1 502 break;
503 case 'W':
fda94b88 504 q->weekbits |= ACL_WEDNESDAY;
92a6f4b1 505 break;
506 case 'H':
fda94b88 507 q->weekbits |= ACL_THURSDAY;
92a6f4b1 508 break;
509 case 'F':
fda94b88 510 q->weekbits |= ACL_FRIDAY;
92a6f4b1 511 break;
512 case 'A':
fda94b88 513 q->weekbits |= ACL_SATURDAY;
92a6f4b1 514 break;
30a4f2a8 515 case 'D':
fda94b88 516 q->weekbits |= ACL_WEEKDAYS;
30a4f2a8 517 break;
80b4b4d0 518 case '-':
519 /* ignore placeholder */
520 break;
92a6f4b1 521 default:
a3d5953d 522 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 523 cfg_filename, config_lineno, config_input_line);
a3d5953d 524 debug(28, 0) ("aclParseTimeSpec: Bad Day '%c'\n",
92a6f4b1 525 *t);
526 break;
527 }
528 }
529 } else {
530 /* assume its time-of-day spec */
531 if (sscanf(t, "%d:%d-%d:%d", &h1, &m1, &h2, &m2) < 4) {
a3d5953d 532 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 533 cfg_filename, config_lineno, config_input_line);
a3d5953d 534 debug(28, 0) ("aclParseTimeSpec: IGNORING Bad time range\n");
fda94b88 535 xfree(q);
536 return;
92a6f4b1 537 }
fda94b88 538 q->start = h1 * 60 + m1;
539 q->stop = h2 * 60 + m2;
540 if (q->start > q->stop) {
a3d5953d 541 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 542 cfg_filename, config_lineno, config_input_line);
a3d5953d 543 debug(28, 0) ("aclParseTimeSpec: IGNORING Reversed time range\n");
fda94b88 544 xfree(q);
545 return;
92a6f4b1 546 }
547 }
548 }
fda94b88 549 if (q->start == 0 && q->stop == 0)
550 q->stop = 23 * 60 + 59;
551 if (q->weekbits == 0)
552 q->weekbits = ACL_ALLWEEK;
553 *(Tail) = q;
554 Tail = &q->next;
7dd57fa2 555}
556
fda94b88 557void
0153d498 558aclParseRegexList(void *curlist)
7dd57fa2 559{
fda94b88 560 relist **Tail;
7dd57fa2 561 relist *q = NULL;
562 char *t = NULL;
1969665d 563 regex_t comp;
008fcc7b 564 int errcode;
565 int flags = REG_EXTENDED | REG_NOSUB;
fda94b88 566 for (Tail = curlist; *Tail; Tail = &((*Tail)->next));
c10aaf05 567 while ((t = strtokFile())) {
0153d498 568 if (strcmp(t, "-i") == 0) {
a47b9029 569 flags |= REG_ICASE;
570 continue;
0153d498 571 }
572 if (strcmp(t, "+i") == 0) {
a47b9029 573 flags &= ~REG_ICASE;
574 continue;
0153d498 575 }
008fcc7b 576 if ((errcode = regcomp(&comp, t, flags)) != 0) {
577 char errbuf[256];
578 regerror(errcode, &comp, errbuf, sizeof errbuf);
a3d5953d 579 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 580 cfg_filename, config_lineno, config_input_line);
a3d5953d 581 debug(28, 0) ("aclParseRegexList: Invalid regular expression '%s': %s\n",
008fcc7b 582 t, errbuf);
1969665d 583 continue;
584 }
c68e9c6b 585 q = memAllocate(MEM_RELIST);
1969665d 586 q->pattern = xstrdup(t);
587 q->regex = comp;
588 *(Tail) = q;
589 Tail = &q->next;
7dd57fa2 590 }
7dd57fa2 591}
592
fda94b88 593static void
594aclParseWordList(void *curlist)
7dd57fa2 595{
7dd57fa2 596 char *t = NULL;
c68e9c6b 597 while ((t = strtokFile()))
598 wordlistAdd(curlist, t);
7dd57fa2 599}
600
f32789f4 601/**********************/
602/* aclParseDomainList */
603/**********************/
fda94b88 604
f32789f4 605static void
606aclParseDomainList(void *curlist)
607{
608 char *t = NULL;
609 splayNode **Top = curlist;
610 while ((t = strtokFile())) {
611 Tolower(t);
612 *Top = splay_insert(xstrdup(t), *Top, aclDomainCompare);
613 }
614}
615
73e67ee0 616/* default proxy_auth timeout is 3600 seconds */
617#define PROXY_AUTH_TIMEOUT 3600
618
afe95a7e 619static void
620aclParseProxyAuth(void *data)
621{
7342cdc8 622 acl_proxy_auth *p;
623 acl_proxy_auth **q = data;
afe95a7e 624 char *t;
73e67ee0 625
626 p = xcalloc(1, sizeof(acl_proxy_auth));
627
628 /* read timeout value (if any) */
afe95a7e 629 t = strtok(NULL, w_space);
73e67ee0 630 if (t == NULL) {
631 p->timeout = PROXY_AUTH_TIMEOUT;
afe95a7e 632 } else {
73e67ee0 633 p->timeout = atoi(t);
634 }
635 /* the minimum timeout is 10 seconds */
636 if (p->timeout < 10)
637 p->timeout = 10;
638
639 /* First time around, 7921 should be big enough */
7812934c 640 p->hash = hash_create((HASHCMP *) strcmp, 7921, hash_string);
641 assert(p->hash);
73e67ee0 642 *q = p;
afe95a7e 643 return;
644}
645
8203a132 646void
a47b9029 647aclParseAclLine(acl ** head)
7dd57fa2 648{
649 /* we're already using strtok() to grok the line */
650 char *t = NULL;
7342cdc8 651 acl *A = NULL;
fda94b88 652 LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
653 squid_acl acltype;
e924600d 654 int new_acl = 0;
7dd57fa2 655
7dd57fa2 656 /* snarf the ACL name */
657 if ((t = strtok(NULL, w_space)) == NULL) {
a3d5953d 658 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 659 cfg_filename, config_lineno, config_input_line);
a3d5953d 660 debug(28, 0) ("aclParseAclLine: missing ACL name.\n");
92a6f4b1 661 return;
662 }
fda94b88 663 xstrncpy(aclname, t, ACL_NAME_SZ);
664 /* snarf the ACL type */
665 if ((t = strtok(NULL, w_space)) == NULL) {
a3d5953d 666 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 667 cfg_filename, config_lineno, config_input_line);
a3d5953d 668 debug(28, 0) ("aclParseAclLine: missing ACL type.\n");
7dd57fa2 669 return;
670 }
56b63fa1 671 if ((acltype = aclStrToType(t)) == ACL_NONE) {
a3d5953d 672 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 673 cfg_filename, config_lineno, config_input_line);
a3d5953d 674 debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", t);
7dd57fa2 675 return;
676 }
9963e5a3 677 if ((A = aclFindByName(aclname)) == NULL) {
a3d5953d 678 debug(28, 3) ("aclParseAclLine: Creating ACL '%s'\n", aclname);
c68e9c6b 679 A = memAllocate(MEM_ACL);
fda94b88 680 xstrncpy(A->name, aclname, ACL_NAME_SZ);
681 A->type = acltype;
52cd89fd 682 A->cfgline = xstrdup(config_input_line);
e924600d 683 new_acl = 1;
fda94b88 684 } else {
52cd89fd 685 if (acltype != A->type) {
a3d5953d 686 debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different type, skipping.\n", A->name);
fda94b88 687 return;
688 }
a3d5953d 689 debug(28, 3) ("aclParseAclLine: Appending to '%s'\n", aclname);
e924600d 690 new_acl = 0;
fda94b88 691 }
692 switch (A->type) {
7dd57fa2 693 case ACL_SRC_IP:
30a4f2a8 694 case ACL_DST_IP:
f3ae9e0d 695 aclParseIpList(&A->data);
7dd57fa2 696 break;
f88bb09c 697 case ACL_SRC_DOMAIN:
7dd57fa2 698 case ACL_DST_DOMAIN:
fda94b88 699 aclParseDomainList(&A->data);
7dd57fa2 700 break;
701 case ACL_TIME:
fda94b88 702 aclParseTimeSpec(&A->data);
7dd57fa2 703 break;
704 case ACL_URL_REGEX:
6e40f263 705 case ACL_URLPATH_REGEX:
b347fea3 706 case ACL_SRC_DOM_REGEX:
707 case ACL_DST_DOM_REGEX:
f1dc9b30 708 aclParseRegexList(&A->data);
7dd57fa2 709 break;
9fdbeb4f 710 case ACL_SRC_ASN:
711 case ACL_DST_ASN:
bd05e3e3 712 case ACL_NETDB_SRC_RTT:
fda94b88 713 aclParseIntlist(&A->data);
7dd57fa2 714 break;
8f663d72 715 case ACL_URL_PORT:
716 aclParseIntRange(&A->data);
717 break;
c68e9c6b 718 case ACL_IDENT:
17a0a4ee 719 Config.onoff.ident_lookup = 1;
fda94b88 720 aclParseWordList(&A->data);
7dd57fa2 721 break;
722 case ACL_PROTO:
fda94b88 723 aclParseProtoList(&A->data);
7dd57fa2 724 break;
92a6f4b1 725 case ACL_METHOD:
fda94b88 726 aclParseMethodList(&A->data);
92a6f4b1 727 break;
d3416189 728 case ACL_BROWSER:
f1dc9b30 729 aclParseRegexList(&A->data);
d3416189 730 break;
afe95a7e 731 case ACL_PROXY_AUTH:
dba79ac5 732 aclParseWordList(&A->data);
c68e9c6b 733 if (!proxy_auth_cache) {
734 /* First time around, 7921 should be big enough */
735 proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
736 assert(proxy_auth_cache);
737 }
43d4303e 738 break;
66c75c41 739#if USE_ARP_ACL
740 case ACL_SRC_ARP:
741 aclParseArpList(&A->data);
742 break;
743#endif
7dd57fa2 744 case ACL_NONE:
745 default:
5d6c7aad 746 fatal("Bad ACL type");
fda94b88 747 break;
7dd57fa2 748 }
e924600d 749 if (!new_acl)
750 return;
751 if (A->data == NULL) {
a3d5953d 752 debug(28, 0) ("aclParseAclLine: IGNORING invalid ACL: %s\n",
e924600d 753 A->cfgline);
754 xfree(A);
755 return;
756 }
f1dc9b30 757 /* append */
758 while (*head)
759 head = &(*head)->next;
760 *head = A;
7dd57fa2 761}
762
02922e76 763/* does name lookup, returns page_id */
764int
765aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name)
e92d33a5 766{
7342cdc8 767 acl_deny_info_list *A = NULL;
768 acl_name_list *L = NULL;
e92d33a5 769
770 A = *head;
771 if (NULL == *head) /* empty list */
02922e76 772 return -1;
e92d33a5 773 while (A) {
774 L = A->acl_list;
775 if (NULL == L) /* empty list should never happen, but in case */
776 continue;
777 while (L) {
778 if (!strcmp(name, L->name))
02922e76 779 return A->err_page_id;
e92d33a5 780 L = L->next;
781 }
782 A = A->next;
783 }
02922e76 784 return -1;
e92d33a5 785}
f32789f4 786
e92d33a5 787/* maex@space.net (05.09.96)
5e79098a 788 * get the info for redirecting "access denied" to info pages
789 * TODO (probably ;-)
790 * currently there is no optimization for
791 * - more than one deny_info line with the same url
792 * - a check, whether the given acl really is defined
793 * - a check, whether an acl is added more than once for the same url
e92d33a5 794 */
f32789f4 795
8203a132 796void
7342cdc8 797aclParseDenyInfoLine(acl_deny_info_list ** head)
e92d33a5 798{
799 char *t = NULL;
7342cdc8 800 acl_deny_info_list *A = NULL;
801 acl_deny_info_list *B = NULL;
802 acl_deny_info_list **T = NULL;
803 acl_name_list *L = NULL;
804 acl_name_list **Tail = NULL;
e92d33a5 805
02922e76 806 /* first expect a page name */
e92d33a5 807 if ((t = strtok(NULL, w_space)) == NULL) {
a3d5953d 808 debug(28, 0) ("%s line %d: %s\n",
e92d33a5 809 cfg_filename, config_lineno, config_input_line);
02922e76 810 debug(28, 0) ("aclParseDenyInfoLine: missing 'error page' parameter.\n");
e92d33a5 811 return;
812 }
7342cdc8 813 A = xcalloc(1, sizeof(acl_deny_info_list));
02922e76 814 A->err_page_id = errorReservePageId(t);
02922e76 815 A->err_page_name = xstrdup(t);
7342cdc8 816 A->next = (acl_deny_info_list *) NULL;
e92d33a5 817 /* next expect a list of ACL names */
818 Tail = &A->acl_list;
819 while ((t = strtok(NULL, w_space))) {
7342cdc8 820 L = xcalloc(1, sizeof(acl_name_list));
d5aa0e3b 821 xstrncpy(L->name, t, ACL_NAME_SZ);
e92d33a5 822 *Tail = L;
823 Tail = &L->next;
824 }
825 if (A->acl_list == NULL) {
a3d5953d 826 debug(28, 0) ("%s line %d: %s\n",
e92d33a5 827 cfg_filename, config_lineno, config_input_line);
a3d5953d 828 debug(28, 0) ("aclParseDenyInfoLine: deny_info line contains no ACL's, skipping\n");
e92d33a5 829 xfree(A);
830 return;
831 }
832 for (B = *head, T = head; B; T = &B->next, B = B->next); /* find the tail */
833 *T = A;
834}
835
8203a132 836void
7342cdc8 837aclParseAccessLine(acl_access ** head)
7dd57fa2 838{
839 char *t = NULL;
7342cdc8 840 acl_access *A = NULL;
841 acl_access *B = NULL;
842 acl_access **T = NULL;
843 acl_list *L = NULL;
844 acl_list **Tail = NULL;
845 acl *a = NULL;
7dd57fa2 846
847 /* first expect either 'allow' or 'deny' */
848 if ((t = strtok(NULL, w_space)) == NULL) {
a3d5953d 849 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 850 cfg_filename, config_lineno, config_input_line);
a3d5953d 851 debug(28, 0) ("aclParseAccessLine: missing 'allow' or 'deny'.\n");
7dd57fa2 852 return;
853 }
c68e9c6b 854 A = memAllocate(MEM_ACL_ACCESS);
bdf18524 855
7dd57fa2 856 if (!strcmp(t, "allow"))
857 A->allow = 1;
858 else if (!strcmp(t, "deny"))
859 A->allow = 0;
860 else {
a3d5953d 861 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 862 cfg_filename, config_lineno, config_input_line);
a3d5953d 863 debug(28, 0) ("aclParseAccessLine: expecting 'allow' or 'deny', got '%s'.\n", t);
7dd57fa2 864 xfree(A);
865 return;
866 }
867
868 /* next expect a list of ACL names, possibly preceeded
869 * by '!' for negation */
8213067d 870 Tail = &A->acl_list;
7dd57fa2 871 while ((t = strtok(NULL, w_space))) {
c68e9c6b 872 L = memAllocate(MEM_ACL_LIST);
1969665d 873 L->op = 1; /* defaults to non-negated */
7dd57fa2 874 if (*t == '!') {
1969665d 875 /* negated ACL */
876 L->op = 0;
877 t++;
7dd57fa2 878 }
a3d5953d 879 debug(28, 3) ("aclParseAccessLine: looking for ACL name '%s'\n", t);
7dd57fa2 880 a = aclFindByName(t);
881 if (a == NULL) {
a3d5953d 882 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 883 cfg_filename, config_lineno, config_input_line);
a3d5953d 884 debug(28, 0) ("aclParseAccessLine: ACL name '%s' not found.\n", t);
1969665d 885 xfree(L);
886 continue;
7dd57fa2 887 }
888 L->acl = a;
889 *Tail = L;
890 Tail = &L->next;
891 }
837dcbb9 892 if (A->acl_list == NULL) {
a3d5953d 893 debug(28, 0) ("%s line %d: %s\n",
b8de7ebe 894 cfg_filename, config_lineno, config_input_line);
a3d5953d 895 debug(28, 0) ("aclParseAccessLine: Access line contains no ACL's, skipping\n");
837dcbb9 896 xfree(A);
897 return;
898 }
3003c0f3 899 A->cfgline = xstrdup(config_input_line);
e71209ce 900 /* Append to the end of this list */
901 for (B = *head, T = head; B; T = &B->next, B = B->next);
92a6f4b1 902 *T = A;
e71209ce 903 /* We lock _acl_access structures in aclCheck() */
c68e9c6b 904 cbdataAdd(A, MEM_ACL_ACCESS);
7dd57fa2 905}
906
f32789f4 907/**************/
908/* aclMatchIp */
909/**************/
910
f32789f4 911static int
912aclMatchIp(void *dataptr, struct in_addr c)
913{
914 splayNode **Top = dataptr;
915 *Top = splay_splay(&c, *Top, aclIpNetworkCompare);
a3d5953d 916 debug(28, 3) ("aclMatchIp: '%s' %s\n",
f32789f4 917 inet_ntoa(c), splayLastResult ? "NOT found" : "found");
918 return !splayLastResult;
919}
920
f32789f4 921/**********************/
922/* aclMatchDomainList */
923/**********************/
924
f32789f4 925static int
926aclMatchDomainList(void *dataptr, const char *host)
927{
928 splayNode **Top = dataptr;
929 if (host == NULL)
930 return 0;
a3d5953d 931 debug(28, 3) ("aclMatchDomainList: checking '%s'\n", host);
f32789f4 932 *Top = splay_splay(host, *Top, aclHostDomainCompare);
a3d5953d 933 debug(28, 3) ("aclMatchDomainList: '%s' %s\n",
f32789f4 934 host, splayLastResult ? "NOT found" : "found");
935 return !splayLastResult;
abf6b4de 936}
937
33cdd606 938int
0ee4272b 939aclMatchRegex(relist * data, const char *word)
abf6b4de 940{
c10aaf05 941 relist *first, *prev;
234967c9 942 if (word == NULL)
943 return 0;
a3d5953d 944 debug(28, 3) ("aclMatchRegex: checking '%s'\n", word);
c10aaf05 945 first = data;
946 prev = NULL;
abf6b4de 947 while (data) {
a3d5953d 948 debug(28, 3) ("aclMatchRegex: looking for '%s'\n", data->pattern);
c10aaf05 949 if (regexec(&data->regex, word, 0, 0, 0) == 0) {
950 if (prev != NULL) {
951 /* shift the element just found to the second position
e5f6c5c2 952 * in the list */
c10aaf05 953 prev->next = data->next;
954 data->next = first->next;
955 first->next = data;
956 }
abf6b4de 957 return 1;
c10aaf05 958 }
959 prev = data;
abf6b4de 960 data = data->next;
961 }
962 return 0;
963}
30a4f2a8 964
94103840 965static int
c68e9c6b 966aclMatchUser(wordlist * data, const char *user)
94103840 967{
c68e9c6b 968 if (user == NULL)
94103840 969 return 0;
c68e9c6b 970 debug(28, 3) ("aclMatchUser: checking '%s'\n", user);
94103840 971 while (data) {
c68e9c6b 972 debug(28, 3) ("aclMatchUser: looking for '%s'\n", data->key);
973 if (strcmp(data->key, "REQUIRED") == 0 && *user != '\0')
94103840 974 return 1;
c68e9c6b 975 if (strcmp(data->key, user) == 0)
94103840 976 return 1;
977 data = data->next;
978 }
979 return 0;
980}
981
afe95a7e 982static int
c68e9c6b 983aclDecodeProxyAuth(const char *proxy_auth, char **user, char **password, char *buf, size_t bufsize)
afe95a7e 984{
afe95a7e 985 char *sent_auth;
c68e9c6b 986 char *cleartext;
987
988 if (proxy_auth == NULL)
afe95a7e 989 return 0;
c68e9c6b 990 if (strlen(proxy_auth) < SKIP_BASIC_SZ)
afe95a7e 991 return 0;
c68e9c6b 992 proxy_auth += SKIP_BASIC_SZ;
993 sent_auth = xstrdup(proxy_auth); /* username and password */
afe95a7e 994 /* Trim trailing \n before decoding */
995 strtok(sent_auth, "\n");
c68e9c6b 996 /* Trim leading whitespace before decoding */
997 while (isspace(*proxy_auth))
998 proxy_auth++;
afe95a7e 999 cleartext = uudecode(sent_auth);
1000 xfree(sent_auth);
c68e9c6b 1001 debug(28, 6) ("aclDecodeProxyAuth: cleartext = '%s'\n", cleartext);
1002 xstrncpy(buf, cleartext, bufsize);
afe95a7e 1003 xfree(cleartext);
c68e9c6b 1004 *user = buf;
1005 if ((*password = strchr(*user, ':')) != NULL)
1006 *(*password)++ = '\0';
1007 if (password == NULL) {
1008 debug(28, 1) ("aclDecodeProxyAuth: no password in proxy authorization header\n");
78385265 1009 return 0;
1010 }
c68e9c6b 1011 return 1;
1012}
73e67ee0 1013
c68e9c6b 1014/* aclMatchProxyAuth can return three exit codes:
1015 * 0 : No such user; invalid Proxy-authorization: header;
1016 * ask for Proxy-Authorization: header
1017 * 1 : user validated OK
1018 * -1 : check the password for this user via an external authenticator
1019 */
1020
1021static int
1022aclMatchProxyAuth(const char *proxy_auth, acl_proxy_auth_user * auth_user, aclCheck_t * checklist)
1023{
1024 /* checklist is used to register user name when identified, nothing else */
1025 LOCAL_ARRAY(char, login_buf, USER_IDENT_SZ);
1026 char *user, *password;
1027
1028 if (!aclDecodeProxyAuth(proxy_auth, &user, &password, login_buf, sizeof(login_buf)))
1029 /* No or invalid Proxy-Auth header */
1030 return 0;
1031
1032 debug(28, 5) ("aclMatchProxyAuth: checking user '%s'\n", user);
1033
1034 if (!auth_user) {
1035 /* see if we already know this user */
1036 auth_user = hash_lookup(proxy_auth_cache, user);
1037 if (!auth_user) {
1038 /* user not yet known, ask external authenticator */
1039 debug(28, 4) ("aclMatchProxyAuth: user '%s' not yet known\n", user);
1040 return -1;
1041 } else if ((0 == strcmp(auth_user->passwd, password)) &&
1042 (auth_user->expiretime > current_time.tv_sec)) {
1043 /* user already known and valid */
73e67ee0 1044 debug(28, 5) ("aclMatchProxyAuth: user '%s' previously validated\n",
c68e9c6b 1045 user);
1046 /* copy username to request for logging on client-side */
1047 xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ);
73e67ee0 1048 return 1;
c68e9c6b 1049 } else {
1050 /* password mismatch/timeout */
1051 debug(28, 4) ("aclMatchProxyAuth: user '%s' password mismatch/timeout\n",
1052 user);
1053 /* remove this user from the hash, making him unknown */
1054 hash_remove_link(proxy_auth_cache, (hash_link *) auth_user);
1055 aclFreeProxyAuthUser(auth_user);
1056 /* copy username to request for logging on client-side unless ident
1057 * is known (do not override ident with false proxy auth names) */
1058 if (!*checklist->request->user_ident)
1059 xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ);
1060 return -1;
73e67ee0 1061 }
c68e9c6b 1062 /* NOTREACHED */
1063 } else {
1064 /* Check result from external validation */
1065 if (checklist->auth_user->passwd_ok != 1) {
1066 /* password was checked but did not match */
1067 assert(checklist->auth_user->passwd_ok == 0);
1068 debug(28, 4) ("aclMatchProxyAuth: authentication failed for user '%s'\n",
1069 user);
1070 return 0;
1071 }
1072 debug(28, 4) ("aclMatchProxyAuth: user '%s' validated OK\n", user);
1073 /* store validated user in hash, after filling in expiretime */
1074 checklist->auth_user->expiretime = current_time.tv_sec + Config.authenticateTTL;
1075 hash_join(proxy_auth_cache, (hash_link *) checklist->auth_user);
1076
1077 return 1;
afe95a7e 1078 }
c68e9c6b 1079
1080 /* NOTREACHED */
1081
1082}
1083
1084static void
1085aclLookupProxyAuthStart(aclCheck_t * checklist)
1086{
1087 LOCAL_ARRAY(char, login_buf, USER_IDENT_SZ);
1088 const char *proxy_auth;
1089 char *user, *password;
1090 int ok;
1091 acl_proxy_auth_user *auth_user;
1092
1093 assert(!checklist->auth_user);
1094
1095 if (!checklist->request->flags.accelerated) {
1096 /* Proxy auth on proxy requests */
1097 proxy_auth = httpHeaderGetStr(&checklist->request->header,
1098 HDR_PROXY_AUTHORIZATION);
1099 } else {
1100 /* WWW auth on accelerated requests */
1101 proxy_auth = httpHeaderGetStr(&checklist->request->header,
1102 HDR_AUTHORIZATION);
afe95a7e 1103 }
c68e9c6b 1104 ok = aclDecodeProxyAuth(proxy_auth, &user, &password, login_buf,
1105 sizeof(login_buf));
1106 assert(ok); /* We should never get here unless the above succeeds in aclMatchProxyAuth */
73e67ee0 1107
c68e9c6b 1108 debug(28, 4) ("aclLookupProxyAuthStart: going to ask authenticator on %s\n", user);
1109 /* we must still check this user's password */
1110 auth_user = memAllocate(MEM_ACL_PROXY_AUTH_USER);
1111 auth_user->user = xstrdup(user);
1112 auth_user->passwd = xstrdup(password);
1113 auth_user->passwd_ok = -1;
1114 auth_user->expiretime = -1;
1115 checklist->auth_user = auth_user;
1116
1117 authenticateStart(checklist->auth_user, aclLookupProxyAuthDone,
1118 checklist);
afe95a7e 1119}
1120
8203a132 1121static int
1122aclMatchInteger(intlist * data, int i)
abf6b4de 1123{
c10aaf05 1124 intlist *first, *prev;
1125 first = data;
1126 prev = NULL;
abf6b4de 1127 while (data) {
c10aaf05 1128 if (data->i == i) {
1129 if (prev != NULL) {
1130 /* shift the element just found to the second position
e5f6c5c2 1131 * in the list */
c10aaf05 1132 prev->next = data->next;
1133 data->next = first->next;
1134 first->next = data;
1135 }
abf6b4de 1136 return 1;
c10aaf05 1137 }
1138 prev = data;
abf6b4de 1139 data = data->next;
1140 }
1141 return 0;
1142}
1143
8f663d72 1144static int
1145aclMatchIntegerRange(intrange * data, int i)
1146{
1147 intrange *first, *prev;
1148 first = data;
1149 prev = NULL;
1150 while (data) {
1151 if (i < data->i) {
5942e8d4 1152 (void) 0;
8f663d72 1153 } else if (i > data->j) {
5942e8d4 1154 (void) 0;
8f663d72 1155 } else {
1156 /* matched */
1157 if (prev != NULL) {
1158 /* shift the element just found to the second position
1159 * in the list */
1160 prev->next = data->next;
1161 data->next = first->next;
1162 first->next = data;
1163 }
1164 return 1;
1165 }
1166 prev = data;
1167 data = data->next;
1168 }
1169 return 0;
1170}
1171
8203a132 1172static int
7342cdc8 1173aclMatchTime(acl_time_data * data, time_t when)
92a6f4b1 1174{
540830c4 1175 static time_t last_when = 0;
1176 static struct tm tm;
1177 time_t t;
fc5d6f7f 1178 assert(data != NULL);
540830c4 1179 if (when != last_when) {
1180 last_when = when;
30a4f2a8 1181 xmemcpy(&tm, localtime(&when), sizeof(struct tm));
540830c4 1182 }
540830c4 1183 t = (time_t) (tm.tm_hour * 60 + tm.tm_min);
a3d5953d 1184 debug(28, 3) ("aclMatchTime: checking %d in %d-%d, weekbits=%x\n",
9bf12439 1185 (int) t, (int) data->start, (int) data->stop, data->weekbits);
1186
540830c4 1187 if (t < data->start || t > data->stop)
1188 return 0;
234967c9 1189 return data->weekbits & (1 << tm.tm_wday) ? 1 : 0;
92a6f4b1 1190}
1191
dba79ac5 1192static int
c68e9c6b 1193aclMatchWordList(wordlist * w, const char *word)
dba79ac5 1194{
c68e9c6b 1195 debug(28, 3) ("aclMatchWordList: looking for '%s'\n", word);
dba79ac5 1196 while (w != NULL) {
1197 debug(28, 3) ("aclMatchWordList: checking '%s'\n", w->key);
c68e9c6b 1198 if (!strcmp(w->key, word))
dba79ac5 1199 return 1;
1200 w = w->next;
1201 }
1202 return 0;
1203}
1204
669fefd4 1205static int
9ef28b60 1206aclMatchAcl(acl * ae, aclCheck_t * checklist)
1969665d 1207{
c1517455 1208 request_t *r = checklist->request;
0ee4272b 1209 const ipcache_addrs *ia = NULL;
1210 const char *fqdn = NULL;
1c73c7e6 1211 char *esc_buf;
30a4f2a8 1212 int k;
9ef28b60 1213 if (!ae)
1969665d 1214 return 0;
9ef28b60 1215 debug(28, 3) ("aclMatchAcl: checking '%s'\n", ae->cfgline);
1216 switch (ae->type) {
1969665d 1217 case ACL_SRC_IP:
9ef28b60 1218 return aclMatchIp(&ae->data, checklist->src_addr);
983061ed 1219 /* NOTREACHED */
30a4f2a8 1220 case ACL_DST_IP:
e5f6c5c2 1221 ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
1222 if (ia) {
1223 for (k = 0; k < (int) ia->count; k++) {
9ef28b60 1224 if (aclMatchIp(&ae->data, ia->in_addrs[k]))
665d36de 1225 return 1;
1226 }
1227 return 0;
1228 } else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) {
a3d5953d 1229 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
9ef28b60 1230 ae->name, r->host);
e7a22b88 1231 checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEEDED;
f88bb09c 1232 return 0;
665d36de 1233 } else {
9ef28b60 1234 return aclMatchIp(&ae->data, no_addr);
30a4f2a8 1235 }
30a4f2a8 1236 /* NOTREACHED */
1969665d 1237 case ACL_DST_DOMAIN:
4d650936 1238 if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
9ef28b60 1239 return aclMatchDomainList(&ae->data, r->host);
4d650936 1240 fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
1241 if (fqdn)
9ef28b60 1242 return aclMatchDomainList(&ae->data, fqdn);
4d650936 1243 if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
a3d5953d 1244 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
9ef28b60 1245 ae->name, inet_ntoa(ia->in_addrs[0]));
e7a22b88 1246 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
4d650936 1247 return 0;
1248 }
9ef28b60 1249 return aclMatchDomainList(&ae->data, "none");
f88bb09c 1250 /* NOTREACHED */
1251 case ACL_SRC_DOMAIN:
1252 fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
665d36de 1253 if (fqdn) {
9ef28b60 1254 return aclMatchDomainList(&ae->data, fqdn);
665d36de 1255 } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
a3d5953d 1256 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
9ef28b60 1257 ae->name, inet_ntoa(checklist->src_addr));
e7a22b88 1258 checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
f88bb09c 1259 return 0;
1260 }
9ef28b60 1261 return aclMatchDomainList(&ae->data, "none");
d0d41f07 1262 /* NOTREACHED */
1263 case ACL_DST_DOM_REGEX:
1264 if ((ia = ipcacheCheckNumeric(r->host)) == NULL)
9ef28b60 1265 return aclMatchRegex(ae->data, r->host);
d0d41f07 1266 fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS);
1267 if (fqdn)
9ef28b60 1268 return aclMatchRegex(ae->data, fqdn);
d0d41f07 1269 if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) {
1270 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
9ef28b60 1271 ae->name, inet_ntoa(ia->in_addrs[0]));
d0d41f07 1272 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEEDED;
1273 return 0;
1274 }
9ef28b60 1275 return aclMatchRegex(ae->data, "none");
d0d41f07 1276 /* NOTREACHED */
1277 case ACL_SRC_DOM_REGEX:
1278 fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS);
1279 if (fqdn) {
9ef28b60 1280 return aclMatchRegex(ae->data, fqdn);
d0d41f07 1281 } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) {
1282 debug(28, 3) ("aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
9ef28b60 1283 ae->name, inet_ntoa(checklist->src_addr));
d0d41f07 1284 checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEEDED;
1285 return 0;
1286 }
9ef28b60 1287 return aclMatchRegex(ae->data, "none");
983061ed 1288 /* NOTREACHED */
1969665d 1289 case ACL_TIME:
9ef28b60 1290 return aclMatchTime(ae->data, squid_curtime);
983061ed 1291 /* NOTREACHED */
6e40f263 1292 case ACL_URLPATH_REGEX:
1c73c7e6 1293 esc_buf = xstrdup(strBuf(r->urlpath));
1294 rfc1738_unescape(esc_buf);
9ef28b60 1295 k = aclMatchRegex(ae->data, esc_buf);
1c73c7e6 1296 safe_free(esc_buf);
1297 return k;
983061ed 1298 /* NOTREACHED */
6e40f263 1299 case ACL_URL_REGEX:
9b5d1d21 1300 esc_buf = xstrdup(urlCanonical(r));
1c73c7e6 1301 rfc1738_unescape(esc_buf);
9ef28b60 1302 k = aclMatchRegex(ae->data, esc_buf);
1c73c7e6 1303 safe_free(esc_buf);
1304 return k;
6e40f263 1305 /* NOTREACHED */
1969665d 1306 case ACL_URL_PORT:
9ef28b60 1307 return aclMatchIntegerRange(ae->data, r->port);
983061ed 1308 /* NOTREACHED */
c68e9c6b 1309 case ACL_IDENT:
1310 return aclMatchUser(ae->data, checklist->ident);
983061ed 1311 /* NOTREACHED */
1969665d 1312 case ACL_PROTO:
9ef28b60 1313 return aclMatchInteger(ae->data, r->protocol);
983061ed 1314 /* NOTREACHED */
92a6f4b1 1315 case ACL_METHOD:
9ef28b60 1316 return aclMatchInteger(ae->data, r->method);
983061ed 1317 /* NOTREACHED */
d3416189 1318 case ACL_BROWSER:
9ef28b60 1319 return aclMatchRegex(ae->data, checklist->browser);
d3416189 1320 /* NOTREACHED */
afe95a7e 1321 case ACL_PROXY_AUTH:
c68e9c6b 1322 if (!r->flags.accelerated) {
1323 /* Proxy authorization on proxy requests */
1324 k = aclMatchProxyAuth(httpHeaderGetStr(&checklist->request->header,
1325 HDR_PROXY_AUTHORIZATION),
1326 checklist->auth_user,
1327 checklist);
1328 } else if (r->flags.internal) {
1329 /* WWW authorization on accelerated internal requests */
1330 k = aclMatchProxyAuth(httpHeaderGetStr(&checklist->request->header,
1331 HDR_AUTHORIZATION),
1332 checklist->auth_user,
1333 checklist);
1334 } else {
1335#if AUTH_ON_ACCELERATION
1336 /* WWW authorization on accelerated requests */
1337 k = aclMatchProxyAuth(httpHeaderGetStr(&checklist->request->header,
1338 HDR_AUTHORIZATION),
1339 checklist->auth_user,
1340 checklist);
1341#else
1342 debug(28, 1) ("aclMatchAcl: proxy_auth %s not applicable on accelerated requests.\n", ae->name);
1343 return -1;
1344#endif
1345 }
73e67ee0 1346 if (k == 0) {
afe95a7e 1347 /* no such user OR we need a proxy authentication header */
73e67ee0 1348 checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED;
c68e9c6b 1349 /*
1350 * XXX This is a bit oddly done.. should perhaps use different
1351 * return codes here
1352 */
afe95a7e 1353 return 0;
73e67ee0 1354 } else if (k == 1) {
c68e9c6b 1355 /*
1356 * Authentication successful. Register that we used the proxy
1357 * authentication header so that it is not forwarded to the
1358 * next proxy
1359 */
92695e5e 1360 r->flags.used_proxy_auth = 1;
afe95a7e 1361 return 1;
73e67ee0 1362 } else if (k == -1) {
c68e9c6b 1363 /*
1364 * we need to validate the password
1365 */
1366 checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_NEEDED;
73e67ee0 1367 return 0;
afe95a7e 1368 }
1369 /* NOTREACHED */
dba79ac5 1370#if SQUID_SNMP
1371 case ACL_SNMP_COMMUNITY:
1372 return aclMatchWordList(ae->data, checklist->snmp_community);
1373#endif
5d6c7aad 1374 case ACL_SRC_ASN:
9ef28b60 1375 return asnMatchIp(ae->data, checklist->src_addr);
5d6c7aad 1376 case ACL_DST_ASN:
53ad48e6 1377 ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS);
1378 if (ia) {
1379 for (k = 0; k < (int) ia->count; k++) {
9ef28b60 1380 if (asnMatchIp(ae->data, ia->in_addrs[k]))
53ad48e6 1381 return 1;
1382 }
1383 return 0;
1384 } else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NONE) {
1385 debug(28, 3) ("asnMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
9ef28b60 1386 ae->name, r->host);
53ad48e6 1387 checklist->state[ACL_DST_ASN] = ACL_LOOKUP_NEEDED;
1388 } else {
9ef28b60 1389 return asnMatchIp(ae->data, no_addr);
53ad48e6 1390 }
5d6c7aad 1391 return 0;
66c75c41 1392#if USE_ARP_ACL
1393 case ACL_SRC_ARP:
9ef28b60 1394 return aclMatchArp(&ae->data, checklist->src_addr);
66c75c41 1395#endif
1969665d 1396 case ACL_NONE:
1397 default:
a3d5953d 1398 debug(28, 0) ("aclMatchAcl: '%s' has bad type %d\n",
9ef28b60 1399 ae->name, ae->type);
1969665d 1400 return 0;
1401 }
30a4f2a8 1402 /* NOTREACHED */
1969665d 1403}
1404
669fefd4 1405int
7342cdc8 1406aclMatchAclList(const acl_list * list, aclCheck_t * checklist)
1969665d 1407{
1969665d 1408 while (list) {
e92d33a5 1409 AclMatchedName = list->acl->name;
a3d5953d 1410 debug(28, 3) ("aclMatchAclList: checking %s%s\n",
ffa8aa23 1411 list->op ? null_string : "!", list->acl->name);
99d829f9 1412 if (aclMatchAcl(list->acl, checklist) != list->op) {
a3d5953d 1413 debug(28, 3) ("aclMatchAclList: returning 0\n");
abf6b4de 1414 return 0;
837dcbb9 1415 }
abf6b4de 1416 list = list->next;
1969665d 1417 }
a3d5953d 1418 debug(28, 3) ("aclMatchAclList: returning 1\n");
1969665d 1419 return 1;
1420}
1421
8203a132 1422int
7342cdc8 1423aclCheckFast(const acl_access * A, aclCheck_t * checklist)
1969665d 1424{
1969665d 1425 int allow = 0;
0c511722 1426 debug(28, 5) ("aclCheckFast: list: %p\n", A);
92a6f4b1 1427 while (A) {
b6c0e933 1428 allow = A->allow;
1429 if (aclMatchAclList(A->acl_list, checklist))
1430 return allow;
1431 A = A->next;
75e88d56 1432 }
0c511722 1433 debug(28, 5) ("aclCheckFast: no matches, returning: %d\n", !allow);
75e88d56 1434 return !allow;
1435}
1436
1437static void
1438aclCheck(aclCheck_t * checklist)
1439{
fc5d6f7f 1440 allow_t allow = ACCESS_DENIED;
7342cdc8 1441 const acl_access *A;
75e88d56 1442 int match;
348b2031 1443 ipcache_addrs *ia;
79d39a72 1444 while ((A = checklist->access_list) != NULL) {
e71209ce 1445 /*
1446 * If the _acl_access is no longer valid (i.e. its been
1447 * freed because of a reconfigure), then bail on this
1448 * access check. For now, return ACCESS_DENIED.
1449 */
1450 if (!cbdataValid(A)) {
1451 cbdataUnlock(A);
1452 break;
1453 }
a3d5953d 1454 debug(28, 3) ("aclCheck: checking '%s'\n", A->cfgline);
1969665d 1455 allow = A->allow;
75e88d56 1456 match = aclMatchAclList(A->acl_list, checklist);
e7a22b88 1457 if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NEEDED) {
b6c0e933 1458 checklist->state[ACL_DST_IP] = ACL_LOOKUP_PENDING;
1459 ipcache_nbgethostbyname(checklist->request->host,
b6c0e933 1460 aclLookupDstIPDone,
8407afee 1461 checklist);
b6c0e933 1462 return;
53ad48e6 1463 } else if (checklist->state[ACL_DST_ASN] == ACL_LOOKUP_NEEDED) {
1464 checklist->state[ACL_DST_ASN] = ACL_LOOKUP_PENDING;
1465 ipcache_nbgethostbyname(checklist->request->host,
1466 aclLookupDstIPforASNDone,
1467 checklist);
1468 return;
e7a22b88 1469 } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NEEDED) {
b6c0e933 1470 checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_PENDING;
1471 fqdncache_nbgethostbyaddr(checklist->src_addr,
b6c0e933 1472 aclLookupSrcFQDNDone,
1473 checklist);
1474 return;
e7a22b88 1475 } else if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NEEDED) {
348b2031 1476 ia = ipcacheCheckNumeric(checklist->request->host);
1477 if (ia == NULL) {
b6c0e933 1478 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
e7a22b88 1479 return;
75e88d56 1480 }
348b2031 1481 checklist->dst_addr = ia->in_addrs[0];
e7a22b88 1482 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_PENDING;
348b2031 1483 fqdncache_nbgethostbyaddr(checklist->dst_addr,
e7a22b88 1484 aclLookupDstFQDNDone,
1485 checklist);
b6c0e933 1486 return;
c68e9c6b 1487 } else if (checklist->state[ACL_PROXY_AUTH] == ACL_LOOKUP_NEEDED) {
73e67ee0 1488 debug(28, 3) ("aclCheck: checking password via authenticator\n");
c68e9c6b 1489 aclLookupProxyAuthStart(checklist);
1490 checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_PENDING;
1491 return;
1492 } else if (checklist->state[ACL_PROXY_AUTH] == ACL_PROXY_AUTH_NEEDED) {
1493 /* Special case. Client is required to resend the request
1494 * with authentication. The request is denied.
1495 */
1496 allow = ACCESS_REQ_PROXY_AUTH;
1497 match = -1;
1498 } else if (checklist->state[ACL_IDENT] == ACL_LOOKUP_NEEDED) {
1499 debug(28, 3) ("aclCheck: Doing ident lookup\n");
1500 /* XXX how to do ident lookup? */
1501 checklist->state[ACL_IDENT] = ACL_LOOKUP_PENDING;
73e67ee0 1502 return;
1503 }
e71209ce 1504 /*
1505 * We are done with this _acl_access entry. Either the request
c68e9c6b 1506 * is allowed, denied, requires authentication, or we move on to
1507 * the next entry.
e71209ce 1508 */
1509 cbdataUnlock(A);
75e88d56 1510 if (match) {
a3d5953d 1511 debug(28, 3) ("aclCheck: match found, returning %d\n", allow);
b6c0e933 1512 aclCheckCallback(checklist, allow);
75e88d56 1513 return;
8213067d 1514 }
b6c0e933 1515 checklist->access_list = A->next;
e71209ce 1516 /*
1517 * Lock the next _acl_access entry
1518 */
1519 if (A->next)
1520 cbdataLock(A->next);
7dd57fa2 1521 }
a3d5953d 1522 debug(28, 3) ("aclCheck: NO match found, returning %d\n", !allow);
75e88d56 1523 aclCheckCallback(checklist, !allow);
1524}
1525
348b2031 1526void
1527aclChecklistFree(aclCheck_t * checklist)
75e88d56 1528{
e7a22b88 1529 if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_PENDING)
b69f7771 1530 fqdncacheUnregister(checklist->src_addr, checklist);
e7a22b88 1531 if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_PENDING)
348b2031 1532 fqdncacheUnregister(checklist->dst_addr, checklist);
8407afee 1533 if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_PENDING)
365e5b34 1534 ipcacheUnregister(checklist->request->host, checklist);
0856c124 1535 if (checklist->request)
2ac76861 1536 requestUnlink(checklist->request);
8407afee 1537 checklist->request = NULL;
1538 cbdataFree(checklist);
75e88d56 1539}
1540
348b2031 1541static void
fc5d6f7f 1542aclCheckCallback(aclCheck_t * checklist, allow_t answer)
348b2031 1543{
a3d5953d 1544 debug(28, 3) ("aclCheckCallback: answer=%d\n", answer);
8407afee 1545 if (cbdataValid(checklist->callback_data))
365e5b34 1546 checklist->callback(answer, checklist->callback_data);
8407afee 1547 cbdataUnlock(checklist->callback_data);
348b2031 1548 checklist->callback = NULL;
1549 checklist->callback_data = NULL;
1550 aclChecklistFree(checklist);
1551}
1552
75e88d56 1553static void
03a1ee42 1554aclLookupDstIPDone(const ipcache_addrs * ia, void *data)
75e88d56 1555{
b6c0e933 1556 aclCheck_t *checklist = data;
1557 checklist->state[ACL_DST_IP] = ACL_LOOKUP_DONE;
1558 aclCheck(checklist);
1969665d 1559}
73e67ee0 1560
53ad48e6 1561static void
1562aclLookupDstIPforASNDone(const ipcache_addrs * ia, void *data)
1563{
1564 aclCheck_t *checklist = data;
1565 checklist->state[ACL_DST_ASN] = ACL_LOOKUP_DONE;
1566 aclCheck(checklist);
1567}
92a6f4b1 1568
75e88d56 1569static void
348b2031 1570aclLookupSrcFQDNDone(const char *fqdn, void *data)
75e88d56 1571{
b6c0e933 1572 aclCheck_t *checklist = data;
1573 checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_DONE;
1574 aclCheck(checklist);
75e88d56 1575}
1576
1577static void
348b2031 1578aclLookupDstFQDNDone(const char *fqdn, void *data)
75e88d56 1579{
b6c0e933 1580 aclCheck_t *checklist = data;
e7a22b88 1581 checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_DONE;
75e88d56 1582 aclCheck(checklist);
1583}
1584
73e67ee0 1585static void
c68e9c6b 1586aclLookupProxyAuthDone(void *data, char *result)
73e67ee0 1587{
1588 aclCheck_t *checklist = data;
1589 checklist->state[ACL_PROXY_AUTH] = ACL_LOOKUP_DONE;
c68e9c6b 1590 debug(28, 4) ("aclLookupProxyAuthDone: result = %s\n",
1591 result ? result : "NULL");
73e67ee0 1592 if (result && (strncasecmp(result, "OK", 2) == 0))
1593 checklist->auth_user->passwd_ok = 1;
1594 else
c68e9c6b 1595 checklist->auth_user->passwd_ok = 0;
73e67ee0 1596 aclCheck(checklist);
1597}
1598
348b2031 1599aclCheck_t *
7342cdc8 1600aclChecklistCreate(const acl_access * A,
b6c0e933 1601 request_t * request,
1602 struct in_addr src_addr,
99edd1c3 1603 const char *user_agent,
1604 const char *ident)
75e88d56 1605{
53ad48e6 1606 int i;
c68e9c6b 1607 aclCheck_t *checklist = memAllocate(MEM_ACLCHECK_T);
1608 cbdataAdd(checklist, MEM_ACLCHECK_T);
b6c0e933 1609 checklist->access_list = A;
e71209ce 1610 /*
1611 * aclCheck() makes sure checklist->access_list is a valid
1612 * pointer, so lock it.
1613 */
1614 cbdataLock(A);
4c8f9e87 1615 if (request != NULL)
2ac76861 1616 checklist->request = requestLink(request);
b6c0e933 1617 checklist->src_addr = src_addr;
53ad48e6 1618 for (i = 0; i < ACL_ENUM_MAX; i++)
1619 checklist->state[i] = ACL_LOOKUP_NONE;
b6c0e933 1620 if (user_agent)
1621 xstrncpy(checklist->browser, user_agent, BROWSERNAMELEN);
1622 if (ident)
def67559 1623 xstrncpy(checklist->ident, ident, USER_IDENT_SZ);
73e67ee0 1624 checklist->auth_user = NULL; /* init to NULL */
348b2031 1625 return checklist;
1626}
1627
1628void
1629aclNBCheck(aclCheck_t * checklist, PF callback, void *callback_data)
1630{
b6c0e933 1631 checklist->callback = callback;
1632 checklist->callback_data = callback_data;
8407afee 1633 cbdataLock(callback_data);
b6c0e933 1634 aclCheck(checklist);
75e88d56 1635}
1636
1637
1638
1639
1640
1641
1642
f32789f4 1643/*********************/
1644/* Destroy functions */
1645/*********************/
1646
8203a132 1647static void
7342cdc8 1648aclDestroyTimeList(acl_time_data * data)
92a6f4b1 1649{
7342cdc8 1650 acl_time_data *next = NULL;
540830c4 1651 for (; data; data = next) {
1652 next = data->next;
c68e9c6b 1653 memFree(MEM_ACL_TIME_DATA, data);
540830c4 1654 }
92a6f4b1 1655}
1656
33cdd606 1657void
7342cdc8 1658aclDestroyRegexList(relist * data)
92a6f4b1 1659{
7342cdc8 1660 relist *next = NULL;
540830c4 1661 for (; data; data = next) {
1662 next = data->next;
1663 regfree(&data->regex);
1664 safe_free(data->pattern);
c68e9c6b 1665 memFree(MEM_RELIST, data);
540830c4 1666 }
92a6f4b1 1667}
1668
ec878047 1669static void
1670aclFreeProxyAuthUser(void *data)
1671{
1672 acl_proxy_auth_user *u = data;
1673 xfree(u->user);
1674 xfree(u->passwd);
1675 memFree(MEM_ACL_PROXY_AUTH_USER, u);
1676}
1677
afe95a7e 1678static void
c68e9c6b 1679aclFreeIpData(void *p)
afe95a7e 1680{
c68e9c6b 1681 memFree(MEM_ACL_IP_DATA, p);
afe95a7e 1682}
1683
8203a132 1684void
a47b9029 1685aclDestroyAcls(acl ** head)
540830c4 1686{
7342cdc8 1687 acl *a = NULL;
1688 acl *next = NULL;
f1dc9b30 1689 for (a = *head; a; a = next) {
540830c4 1690 next = a->next;
a3d5953d 1691 debug(28, 3) ("aclDestroyAcls: '%s'\n", a->cfgline);
540830c4 1692 switch (a->type) {
1693 case ACL_SRC_IP:
30a4f2a8 1694 case ACL_DST_IP:
c68e9c6b 1695 splay_destroy(a->data, aclFreeIpData);
540830c4 1696 break;
c68e9c6b 1697 case ACL_SRC_ARP:
540830c4 1698 case ACL_DST_DOMAIN:
c20e73a0 1699 case ACL_SRC_DOMAIN:
f32789f4 1700 splay_destroy(a->data, xfree);
f32789f4 1701 break;
dba79ac5 1702#if SQUID_SNMP
1703 case ACL_SNMP_COMMUNITY:
1704#endif
c68e9c6b 1705 case ACL_IDENT:
1706 case ACL_PROXY_AUTH:
540830c4 1707 wordlistDestroy((wordlist **) & a->data);
1708 break;
1709 case ACL_TIME:
1710 aclDestroyTimeList(a->data);
1711 break;
1712 case ACL_URL_REGEX:
6e40f263 1713 case ACL_URLPATH_REGEX:
d3416189 1714 case ACL_BROWSER:
540830c4 1715 aclDestroyRegexList(a->data);
1716 break;
540830c4 1717 case ACL_PROTO:
1718 case ACL_METHOD:
9fdbeb4f 1719 case ACL_SRC_ASN:
1720 case ACL_DST_ASN:
540830c4 1721 intlistDestroy((intlist **) & a->data);
1722 break;
8f663d72 1723 case ACL_URL_PORT:
1724 aclDestroyIntRange(a->data);
1725 break;
540830c4 1726 case ACL_NONE:
1727 default:
fc5d6f7f 1728 assert(0);
540830c4 1729 break;
92a6f4b1 1730 }
540830c4 1731 safe_free(a->cfgline);
c68e9c6b 1732 memFree(MEM_ACL, a);
540830c4 1733 }
f1dc9b30 1734 *head = NULL;
92a6f4b1 1735}
1736
8203a132 1737static void
7342cdc8 1738aclDestroyAclList(acl_list * list)
92a6f4b1 1739{
7342cdc8 1740 acl_list *next = NULL;
540830c4 1741 for (; list; list = next) {
1742 next = list->next;
c68e9c6b 1743 memFree(MEM_ACL_LIST, list);
540830c4 1744 }
92a6f4b1 1745}
1746
8203a132 1747void
7342cdc8 1748aclDestroyAccessList(acl_access ** list)
92a6f4b1 1749{
7342cdc8 1750 acl_access *l = NULL;
1751 acl_access *next = NULL;
540830c4 1752 for (l = *list; l; l = next) {
a3d5953d 1753 debug(28, 3) ("aclDestroyAccessList: '%s'\n", l->cfgline);
540830c4 1754 next = l->next;
1755 aclDestroyAclList(l->acl_list);
1756 l->acl_list = NULL;
1757 safe_free(l->cfgline);
e71209ce 1758 cbdataFree(l);
540830c4 1759 }
1760 *list = NULL;
92a6f4b1 1761}
e92d33a5 1762
1763/* maex@space.net (06.09.1996)
f4296e99 1764 * destroy an _acl_deny_info_list */
f32789f4 1765
8203a132 1766void
7342cdc8 1767aclDestroyDenyInfoList(acl_deny_info_list ** list)
e92d33a5 1768{
7342cdc8 1769 acl_deny_info_list *a = NULL;
1770 acl_deny_info_list *a_next = NULL;
1771 acl_name_list *l = NULL;
1772 acl_name_list *l_next = NULL;
e92d33a5 1773
1774 for (a = *list; a; a = a_next) {
1775 for (l = a->acl_list; l; l = l_next) {
1776 l_next = l->next;
1777 safe_free(l);
1778 }
1779 a_next = a->next;
02922e76 1780 xfree(a->err_page_name);
e92d33a5 1781 safe_free(a);
1782 }
f4296e99 1783 *list = NULL;
e92d33a5 1784}
f32789f4 1785
8f663d72 1786static void
5942e8d4 1787aclDestroyIntRange(intrange * list)
8f663d72 1788{
1789 intrange *w = NULL;
1790 intrange *n = NULL;
1791 for (w = list; w; w = n) {
5942e8d4 1792 n = w->next;
1793 safe_free(w);
8f663d72 1794 }
1795}
1796
f32789f4 1797/* general compare functions, these are used for tree search algorithms
1798 * so they return <0, 0 or >0 */
1799
1800/* compare two domains */
1801
f32789f4 1802static int
1803aclDomainCompare(const void *data, splayNode * n)
1804{
1805 const char *d1 = data;
1806 const char *d2 = n->data;
1807 int l1 = strlen(d1);
1808 int l2 = strlen(d2);
1809 while (d1[l1] == d2[l2]) {
1810 if ((l1 == 0) && (l2 == 0))
1811 return 0; /* d1 == d2 */
1812 if (l1-- == 0)
1813 return -1; /* d1 < d2 */
1814 if (l2-- == 0)
1815 return 1; /* d1 > d2 */
1816 }
1817 return (d1[l1] - d2[l2]);
1818}
1819
f32789f4 1820/* compare a host and a domain */
1821
f32789f4 1822static int
1823aclHostDomainCompare(const void *data, splayNode * n)
1824{
1825 const char *h = data;
1826 char *d = n->data;
1827 int l1;
1828 int l2;
1829 if (matchDomainName(d, h))
1830 return 0;
1831 l1 = strlen(h);
1832 l2 = strlen(d);
1833 /* h != d */
1834 while (h[l1] == d[l2]) {
1835 if (l1 == 0)
1836 break;
1837 if (l2 == 0)
1838 break;
1839 l1--;
1840 l2--;
1841 }
1842 /* a '.' is a special case */
1843 if ((h[l1] == '.') || (l1 == 0))
1844 return -1; /* domain(h) < d */
1845 if ((d[l2] == '.') || (l2 == 0))
1846 return 1; /* domain(h) > d */
1847 return (h[l1] - d[l2]);
1848}
1849
f32789f4 1850/* compare two network specs
1851 *
1852 * NOTE: this is very similar to aclIpNetworkCompare and it's not yet
1853 * clear whether this OK. The problem could be with when a network
1854 * is a subset of the other networks:
1855 *
1856 * 128.1.2.0/255.255.255.128 == 128.1.2.0/255.255.255.0 ?
1857 *
1858 * Currently only the first address of the first network is used.
1859 */
1860
f32789f4 1861/* compare an address and a network spec */
1862
f32789f4 1863static int
1864aclIpNetworkCompare(const void *a, splayNode * n)
1865{
429fdbec 1866 struct in_addr A = *(struct in_addr *) a;
56b63fa1 1867 acl_ip_data *q = n->data;
f32789f4 1868 struct in_addr B = q->addr1;
1869 struct in_addr C = q->addr2;
1870 int rc = 0;
429fdbec 1871 A.s_addr &= q->mask.s_addr; /* apply netmask */
f32789f4 1872 if (C.s_addr == 0) { /* single address check */
429fdbec 1873 if (ntohl(A.s_addr) > ntohl(B.s_addr))
f32789f4 1874 rc = 1;
429fdbec 1875 else if (ntohl(A.s_addr) < ntohl(B.s_addr))
f32789f4 1876 rc = -1;
1877 else
1878 rc = 0;
1879 } else { /* range address check */
429fdbec 1880 if (ntohl(A.s_addr) > ntohl(C.s_addr))
f32789f4 1881 rc = 1;
429fdbec 1882 else if (ntohl(A.s_addr) < ntohl(B.s_addr))
f32789f4 1883 rc = -1;
1884 else
1885 rc = 0;
1886 }
1887 return rc;
1888}
f32789f4 1889
f084f6af 1890static void
1891aclDumpIpListWalkee(void *node, void *state)
1892{
1893 acl_ip_data *ip = node;
1894 MemBuf mb;
1895 wordlist **W = state;
f084f6af 1896 memBufDefInit(&mb);
1897 memBufPrintf(&mb, "%s", inet_ntoa(ip->addr1));
1898 if (ip->addr2.s_addr != any_addr.s_addr)
1899 memBufPrintf(&mb, "-%s", inet_ntoa(ip->addr2));
1900 if (ip->mask.s_addr != no_addr.s_addr)
1901 memBufPrintf(&mb, "/%s", inet_ntoa(ip->mask));
c68e9c6b 1902 wordlistAdd(W, mb.buf);
f084f6af 1903 memBufClean(&mb);
1904}
f32789f4 1905
56b63fa1 1906static wordlist *
e82d6d21 1907aclDumpIpList(void *data)
56b63fa1 1908{
f084f6af 1909 wordlist *w = NULL;
1910 splay_walk(data, aclDumpIpListWalkee, &w);
1911 return w;
1912}
1913
1914static void
1915aclDumpDomainListWalkee(void *node, void *state)
1916{
1917 char *domain = node;
c68e9c6b 1918 wordlistAdd(state, domain);
56b63fa1 1919}
1920
1921static wordlist *
1922aclDumpDomainList(void *data)
1923{
f084f6af 1924 wordlist *w = NULL;
1925 splay_walk(data, aclDumpDomainListWalkee, &w);
1926 return w;
56b63fa1 1927}
7342cdc8 1928
56b63fa1 1929static wordlist *
7342cdc8 1930aclDumpTimeSpecList(acl_time_data * t)
f511ab6f 1931{
f511ab6f 1932 wordlist *W = NULL;
f511ab6f 1933 char buf[128];
1934 while (t != NULL) {
137ee196 1935 snprintf(buf, sizeof(buf), "%c%c%c%c%c%c%c %02d:%02d-%02d:%02d",
16300b58 1936 t->weekbits & ACL_SUNDAY ? 'S' : '-',
1937 t->weekbits & ACL_MONDAY ? 'M' : '-',
1938 t->weekbits & ACL_TUESDAY ? 'T' : '-',
1939 t->weekbits & ACL_WEDNESDAY ? 'W' : '-',
1940 t->weekbits & ACL_THURSDAY ? 'H' : '-',
1941 t->weekbits & ACL_FRIDAY ? 'F' : '-',
1942 t->weekbits & ACL_SATURDAY ? 'A' : '-',
1943 t->start / 60,
1944 t->start % 60,
1945 t->stop / 60,
1946 t->stop % 60);
c68e9c6b 1947 wordlistAdd(&W, buf);
f511ab6f 1948 t = t->next;
16300b58 1949 }
1950 return W;
56b63fa1 1951}
7342cdc8 1952
56b63fa1 1953static wordlist *
7342cdc8 1954aclDumpRegexList(relist * data)
56b63fa1 1955{
7342cdc8 1956 wordlist *W = NULL;
7342cdc8 1957 while (data != NULL) {
c68e9c6b 1958 wordlistAdd(&W, data->pattern);
7342cdc8 1959 data = data->next;
1960 }
1961 return W;
56b63fa1 1962}
7342cdc8 1963
56b63fa1 1964static wordlist *
7342cdc8 1965aclDumpIntlistList(intlist * data)
56b63fa1 1966{
7342cdc8 1967 wordlist *W = NULL;
7342cdc8 1968 char buf[32];
1969 while (data != NULL) {
137ee196 1970 snprintf(buf, sizeof(buf), "%d", data->i);
c68e9c6b 1971 wordlistAdd(&W, buf);
7342cdc8 1972 data = data->next;
1973 }
1974 return W;
56b63fa1 1975}
7342cdc8 1976
8f663d72 1977static wordlist *
1978aclDumpIntRangeList(intrange * data)
1979{
1980 wordlist *W = NULL;
8f663d72 1981 char buf[32];
1982 while (data != NULL) {
8f663d72 1983 if (data->i == data->j)
1984 snprintf(buf, sizeof(buf), "%d", data->i);
1985 else
1986 snprintf(buf, sizeof(buf), "%d-%d", data->i, data->j);
c68e9c6b 1987 wordlistAdd(&W, buf);
8f663d72 1988 data = data->next;
1989 }
1990 return W;
1991}
1992
56b63fa1 1993static wordlist *
7342cdc8 1994aclDumpProtoList(intlist * data)
56b63fa1 1995{
7342cdc8 1996 wordlist *W = NULL;
7342cdc8 1997 while (data != NULL) {
c68e9c6b 1998 wordlistAdd(&W, ProtocolStr[data->i]);
7342cdc8 1999 data = data->next;
2000 }
2001 return W;
56b63fa1 2002}
7342cdc8 2003
56b63fa1 2004static wordlist *
7342cdc8 2005aclDumpMethodList(intlist * data)
56b63fa1 2006{
7342cdc8 2007 wordlist *W = NULL;
7342cdc8 2008 while (data != NULL) {
c68e9c6b 2009 wordlistAdd(&W, RequestMethodStr[data->i]);
7342cdc8 2010 data = data->next;
2011 }
2012 return W;
56b63fa1 2013}
7342cdc8 2014
56b63fa1 2015wordlist *
2016aclDumpGeneric(const acl * a)
2017{
c68e9c6b 2018 debug(28, 3) ("aclDumpGeneric: %s type %d\n", a->name, a->type);
56b63fa1 2019 switch (a->type) {
2020 case ACL_SRC_IP:
2021 case ACL_DST_IP:
2022 return aclDumpIpList(a->data);
2023 break;
2024 case ACL_SRC_DOMAIN:
2025 case ACL_DST_DOMAIN:
dba79ac5 2026#if SQUID_SNMP
2027 case ACL_SNMP_COMMUNITY:
2028#endif
c68e9c6b 2029 case ACL_IDENT:
2030 case ACL_PROXY_AUTH:
56b63fa1 2031 return aclDumpDomainList(a->data);
2032 break;
2033 case ACL_TIME:
7342cdc8 2034 return aclDumpTimeSpecList(a->data);
56b63fa1 2035 break;
2036 case ACL_URL_REGEX:
2037 case ACL_URLPATH_REGEX:
2038 case ACL_BROWSER:
2039 return aclDumpRegexList(a->data);
2040 break;
56b63fa1 2041 case ACL_SRC_ASN:
2042 case ACL_DST_ASN:
7342cdc8 2043 return aclDumpIntlistList(a->data);
56b63fa1 2044 break;
8f663d72 2045 case ACL_URL_PORT:
2046 return aclDumpIntRangeList(a->data);
2047 break;
56b63fa1 2048 case ACL_PROTO:
2049 return aclDumpProtoList(a->data);
2050 break;
2051 case ACL_METHOD:
2052 return aclDumpMethodList(a->data);
2053 break;
56b63fa1 2054#if USE_ARP_ACL
2055 case ACL_SRC_ARP:
2056 return aclDumpArpList(a->data);
2057 break;
2058#endif
2059 case ACL_NONE:
2060 default:
2061 break;
2062 }
2063 return NULL;
2064}
2065
23351cb2 2066
2067
2068
2069#if USE_ARP_ACL
2070/* ==== BEGIN ARP ACL SUPPORT ============================================= */
2071
2072/*
2073 * From: dale@server.ctam.bitmcnit.bryansk.su (Dale)
2074 * To: wessels@nlanr.net
2075 * Subject: Another Squid patch... :)
2076 * Date: Thu, 04 Dec 1997 19:55:01 +0300
2077 * ============================================================================
2078 *
2079 * Working on setting up a proper firewall for a network containing some
2080 * Win'95 computers at our Univ, I've discovered that some smart students
2081 * avoid the restrictions easily just changing their IP addresses in Win'95
2082 * Contol Panel... It has been getting boring, so I took Squid-1.1.18
2083 * sources and added a new acl type for hard-wired access control:
2084 *
2085 * acl <name> arp <Ethernet address> ...
2086 *
2087 * For example,
2088 *
2089 * acl students arp 00:00:21:55:ed:22 00:00:21:ff:55:38
bd0c865a 2090 *
2091 * NOTE: Linux code by David Luyer <luyer@ucs.uwa.edu.au>.
2092 * Original (BSD-specific) code no longer works.
23351cb2 2093 */
2094
2095#include "squid.h"
2096
2097#include <sys/sysctl.h>
a931a29b 2098#ifdef _SQUID_LINUX_
2099#include <net/if_arp.h>
2100#include <sys/ioctl.h>
2101#else
23351cb2 2102#include <net/if_dl.h>
a931a29b 2103#endif
23351cb2 2104#include <net/route.h>
2105#include <net/if.h>
2106#include <netinet/if_ether.h>
2107
2108/*
2109 * Decode an ascii representation (asc) of an ethernet adress, and place
2110 * it in eth[6].
2111 */
2112static int
2113decode_eth(const char *asc, char *eth)
2114{
2115 int a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
2116 if (sscanf(asc, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6) {
53ad48e6 2117 debug(28, 0) ("decode_eth: Invalid ethernet address '%s'\n", asc);
23351cb2 2118 return 0; /* This is not valid address */
2119 }
2120 eth[0] = (u_char) a1;
2121 eth[1] = (u_char) a2;
2122 eth[2] = (u_char) a3;
2123 eth[3] = (u_char) a4;
2124 eth[4] = (u_char) a5;
2125 eth[5] = (u_char) a6;
2126 return 1;
2127}
2128
7342cdc8 2129static acl_arp_data *
23351cb2 2130aclParseArpData(const char *t)
2131{
bd0c865a 2132 LOCAL_ARRAY(char, eth, 256);
7342cdc8 2133 acl_arp_data *q = xcalloc(1, sizeof(acl_arp_data));
53ad48e6 2134 debug(28, 5) ("aclParseArpData: %s\n", t);
bd0c865a 2135 if (sscanf(t, "%[0-9a-fA-F:]", eth) != 1) {
53ad48e6 2136 debug(28, 0) ("aclParseArpData: Bad ethernet address: '%s'\n", t);
23351cb2 2137 safe_free(q);
2138 return NULL;
2139 }
2140 if (!decode_eth(eth, q->eth)) {
53ad48e6 2141 debug(28, 0) ("%s line %d: %s\n",
23351cb2 2142 cfg_filename, config_lineno, config_input_line);
bd0c865a 2143 debug(28, 0) ("aclParseArpData: Ignoring invalid ARP acl entry: can't parse '%s'\n", eth);
23351cb2 2144 safe_free(q);
2145 return NULL;
2146 }
2147 return q;
2148}
2149
2150
2151/*******************/
2152/* aclParseArpList */
2153/*******************/
23351cb2 2154static void
2155aclParseArpList(void *curlist)
2156{
2157 char *t = NULL;
2158 splayNode **Top = curlist;
7342cdc8 2159 acl_arp_data *q = NULL;
23351cb2 2160 while ((t = strtokFile())) {
2161 if ((q = aclParseArpData(t)) == NULL)
2162 continue;
f084f6af 2163 *Top = splay_insert(q, *Top, aclArpCompare);
23351cb2 2164 }
2165}
23351cb2 2166
2167/***************/
2168/* aclMatchArp */
2169/***************/
f084f6af 2170#ifdef _SQUID_LINUX_
23351cb2 2171static int
2172aclMatchArp(void *dataptr, struct in_addr c)
2173{
f084f6af 2174 struct arpreq arpReq;
2175 struct sockaddr_in ipAddr;
23351cb2 2176 splayNode **Top = dataptr;
f084f6af 2177 ipAddr.sin_family = AF_INET;
2178 ipAddr.sin_port = 0;
2179 ipAddr.sin_addr = c;
2180 memcpy(&arpReq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
2181 arpReq.arp_dev[0] = '\0';
2182 arpReq.arp_flags = 0;
2183 /* any AF_INET socket will do... gives back hardware type, device, etc */
2184 if (ioctl(HttpSockets[0], SIOCGARP, &arpReq) == -1) {
2185 debug(28, 1) ("ARP query failed - %d", errno);
2186 return 0;
2187 } else if (arpReq.arp_ha.sa_family != ARPHRD_ETHER) {
2188 debug(28, 1) ("Non-ethernet interface returned from ARP query - %d",
2189 arpReq.arp_ha.sa_family);
2190 /* update here and MAC address parsing to handle non-ethernet */
2191 return 0;
2192 } else
2193 *Top = splay_splay(&arpReq.arp_ha.sa_data, *Top, aclArpCompare);
53ad48e6 2194 debug(28, 3) ("aclMatchArp: '%s' %s\n",
23351cb2 2195 inet_ntoa(c), splayLastResult ? "NOT found" : "found");
2196 return !splayLastResult;
2197}
23351cb2 2198
f084f6af 2199static int
2200aclArpCompare(const void *data, splayNode * n)
2201{
2202 const unsigned short *d1 = data;
2203 const unsigned short *d2 = n->data;
e82d6d21 2204 if (d1[0] != d2[0])
2205 return (d1[0] > d2[0]) ? 1 : -1;
2206 if (d1[1] != d2[1])
2207 return (d1[1] > d2[1]) ? 1 : -1;
2208 if (d1[2] != d2[2])
2209 return (d1[2] > d2[2]) ? 1 : -1;
f084f6af 2210 return 0;
2211}
a931a29b 2212#else
f084f6af 2213
2214static int
2215aclMatchArp(void *dataptr, struct in_addr c)
2216{
e82d6d21 2217 WRITE ME;
f084f6af 2218}
2219
2220static int
2221aclArpCompare(const void *data, splayNode * n)
2222{
e82d6d21 2223 WRITE ME;
f084f6af 2224}
2225
bd0c865a 2226/**********************************************************************
2227* This is from the pre-splay-tree code for BSD
2228* I suspect the Linux approach will work on most O/S and be much
2229* better - <luyer@ucs.uwa.edu.au>
2230***********************************************************************
23351cb2 2231static int
2232checkARP(u_long ip, char *eth)
2233{
2234 int mib[6] =
2235 {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
2236 size_t needed;
2237 char *buf, *next, *lim;
2238 struct rt_msghdr *rtm;
2239 struct sockaddr_inarp *sin;
2240 struct sockaddr_dl *sdl;
2241 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
ee89e05a 2242 debug(28, 0) ("Can't estimate ARP table size!\n");
23351cb2 2243 return 0;
2244 }
ee89e05a 2245 if ((buf = xmalloc(needed)) == NULL) {
2246 debug(28, 0) ("Can't allocate temporary ARP table!\n");
23351cb2 2247 return 0;
2248 }
2249 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
ee89e05a 2250 debug(28, 0) ("Can't retrieve ARP table!\n");
2251 xfree(buf);
23351cb2 2252 return 0;
2253 }
2254 lim = buf + needed;
2255 for (next = buf; next < lim; next += rtm->rtm_msglen) {
2256 rtm = (struct rt_msghdr *) next;
2257 sin = (struct sockaddr_inarp *) (rtm + 1);
2258 sdl = (struct sockaddr_dl *) (sin + 1);
2259 if (sin->sin_addr.s_addr == ip) {
2260 if (sdl->sdl_alen)
ee89e05a 2261 if (!memcmp(LLADDR(sdl), eth, 6)) {
2262 xfree(buf);
23351cb2 2263 return 1;
ee89e05a 2264 }
2265 break;
23351cb2 2266 }
2267 }
ee89e05a 2268 xfree(buf);
23351cb2 2269 return 0;
2270}
bd0c865a 2271**********************************************************************/
a931a29b 2272#endif
23351cb2 2273
bd0c865a 2274static void
2275aclDumpArpListWalkee(void *node, void *state)
56b63fa1 2276{
bd0c865a 2277 acl_arp_data *arp = node;
f084f6af 2278 wordlist **W = state;
2279 static char buf[24];
2280 while (*W != NULL)
2281 W = &(*W)->next;
2282 snprintf(buf, sizeof(buf), "%02x:%02x:02x:02x:02x:02x",
bd0c865a 2283 arp->eth[0], arp->eth[1], arp->eth[2], arp->eth[3],
2284 arp->eth[4], arp->eth[5]);
c68e9c6b 2285 wordlistAdd(state, buf);
f084f6af 2286}
2287
2288static wordlist *
e82d6d21 2289aclDumpArpList(void *data)
f084f6af 2290{
2291 wordlist *w = NULL;
2292 splay_walk(data, aclDumpArpListWalkee, &w);
2293 return w;
56b63fa1 2294}
2295
23351cb2 2296/* ==== END ARP ACL SUPPORT =============================================== */
2297#endif /* USE_ARP_ACL */