]>
Commit | Line | Data |
---|---|---|
8213067d | 1 | /* |
b1ef1220 | 2 | * $Id: acl.cc,v 1.78 1997/02/01 00:28:07 wessels Exp $ |
30a4f2a8 | 3 | * |
4 | * DEBUG: section 28 Access Control | |
5 | * AUTHOR: Duane Wessels | |
6 | * | |
42c04c16 | 7 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ |
30a4f2a8 | 8 | * -------------------------------------------------------- |
9 | * | |
10 | * Squid is the result of efforts by numerous individuals from the | |
11 | * Internet community. Development is led by Duane Wessels of the | |
12 | * National Laboratory for Applied Network Research and funded by | |
13 | * the National Science Foundation. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or modify | |
16 | * it under the terms of the GNU General Public License as published by | |
17 | * the Free Software Foundation; either version 2 of the License, or | |
18 | * (at your option) any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
28 | * | |
8213067d | 29 | */ |
7dd57fa2 | 30 | |
31 | #include "squid.h" | |
32 | ||
e92d33a5 | 33 | /* Global */ |
0ee4272b | 34 | const char *AclMatchedName = NULL; |
e92d33a5 | 35 | |
c10aaf05 | 36 | /* for reading ACL's from files */ |
37 | int aclFromFile = 0; | |
38 | FILE *aclFile; | |
39 | ||
e92d33a5 | 40 | /* These three should never be referenced directly in this file! */ |
41 | struct _acl_deny_info_list *DenyInfoList = NULL; | |
92a6f4b1 | 42 | struct _acl_access *HTTPAccessList = NULL; |
43 | struct _acl_access *ICPAccessList = NULL; | |
48270233 | 44 | struct _acl_access *MISSAccessList = NULL; |
caebbe00 | 45 | #if DELAY_HACK |
46 | struct _acl_access *DelayAccessList = NULL; | |
47 | #endif | |
92a6f4b1 | 48 | |
7dd57fa2 | 49 | static struct _acl *AclList = NULL; |
50 | static struct _acl **AclListTail = &AclList; | |
4db43fab | 51 | static const char *const w_space = " \t\n\r"; /* Jasper sez so */ |
7dd57fa2 | 52 | |
67508012 | 53 | static void aclDestroyAclList _PARAMS((struct _acl_list * list)); |
54 | static void aclDestroyIpList _PARAMS((struct _acl_ip_data * data)); | |
b1ef1220 | 55 | static struct _acl_ip_data *aclSplayInsertIp _PARAMS((struct in_addr, struct in_addr, struct in_addr, struct _acl_ip_data *)); |
56 | static struct _acl_ip_data *aclSplayIp _PARAMS((struct in_addr, struct _acl_ip_data *)); | |
67508012 | 57 | static void aclDestroyTimeList _PARAMS((struct _acl_time_data * data)); |
0ee4272b | 58 | static int aclMatchDomainList _PARAMS((wordlist *, const char *)); |
59 | static int aclMatchAclList _PARAMS((const struct _acl_list *, aclCheck_t *)); | |
67508012 | 60 | static int aclMatchInteger _PARAMS((intlist * data, int i)); |
61 | static int aclMatchIp _PARAMS((struct _acl_ip_data * data, struct in_addr c)); | |
67508012 | 62 | static int aclMatchTime _PARAMS((struct _acl_time_data * data, time_t when)); |
94103840 | 63 | static int aclMatchIdent _PARAMS((wordlist * data, const char *ident)); |
0ee4272b | 64 | static squid_acl aclType _PARAMS((const char *s)); |
65 | static int decode_addr _PARAMS((const char *, struct in_addr *, struct in_addr *)); | |
fda94b88 | 66 | static void aclParseIpList _PARAMS((void *curlist)); |
67 | static void aclParseDomainList _PARAMS((void *curlist)); | |
68 | static void aclParseIntlist _PARAMS((void *curlist)); | |
69 | static void aclParseWordList _PARAMS((void *curlist)); | |
70 | static void aclParseProtoList _PARAMS((void *curlist)); | |
71 | static void aclParseMethodList _PARAMS((void *curlist)); | |
72 | static void aclParseTimeSpec _PARAMS((void *curlist)); | |
8203a132 | 73 | |
c10aaf05 | 74 | char * |
75 | strtokFile(void) | |
76 | { | |
77 | char *t, *fn; | |
78 | LOCAL_ARRAY(char, buf, 256); | |
79 | ||
e5f6c5c2 | 80 | strtok_again: |
c10aaf05 | 81 | if (!aclFromFile) { |
82 | t = (strtok(NULL, w_space)); | |
83 | if (t && (*t == '\"' || *t == '\'')) { | |
84 | /* quote found, start reading from file */ | |
85 | fn = ++t; | |
e5f6c5c2 | 86 | while (*t && *t != '\"' && *t != '\'') |
87 | t++; | |
c10aaf05 | 88 | *t = '\0'; |
89 | if ((aclFile = fopen(fn, "r")) == NULL) { | |
90 | debug(28, 0, "strtokFile: %s not found\n", fn); | |
e5f6c5c2 | 91 | return (NULL); |
c10aaf05 | 92 | } |
93 | aclFromFile = 1; | |
94 | } else { | |
e5f6c5c2 | 95 | return (t); |
c10aaf05 | 96 | } |
97 | } | |
98 | /* aclFromFile */ | |
99 | if (fgets(buf, 256, aclFile) == NULL) { | |
100 | /* stop reading from file */ | |
101 | fclose(aclFile); | |
102 | aclFromFile = 0; | |
103 | goto strtok_again; | |
104 | } else { | |
105 | t = buf; | |
106 | /* skip leading and trailing white space */ | |
107 | t += strspn(buf, w_space); | |
108 | t[strcspn(t, w_space)] = '\0'; | |
e5f6c5c2 | 109 | return (t); |
c10aaf05 | 110 | } |
111 | } | |
112 | ||
8203a132 | 113 | static squid_acl |
0ee4272b | 114 | aclType(const char *s) |
7dd57fa2 | 115 | { |
116 | if (!strcmp(s, "src")) | |
117 | return ACL_SRC_IP; | |
30a4f2a8 | 118 | if (!strcmp(s, "dst")) |
119 | return ACL_DST_IP; | |
7dd57fa2 | 120 | if (!strcmp(s, "domain")) |
121 | return ACL_DST_DOMAIN; | |
f88bb09c | 122 | if (!strcmp(s, "dstdomain")) |
123 | return ACL_DST_DOMAIN; | |
124 | if (!strcmp(s, "srcdomain")) | |
125 | return ACL_SRC_DOMAIN; | |
7dd57fa2 | 126 | if (!strcmp(s, "time")) |
127 | return ACL_TIME; | |
128 | if (!strcmp(s, "pattern")) | |
6e40f263 | 129 | return ACL_URLPATH_REGEX; |
130 | if (!strcmp(s, "urlpath_regex")) | |
131 | return ACL_URLPATH_REGEX; | |
132 | if (!strcmp(s, "url_regex")) | |
7dd57fa2 | 133 | return ACL_URL_REGEX; |
134 | if (!strcmp(s, "port")) | |
135 | return ACL_URL_PORT; | |
136 | if (!strcmp(s, "user")) | |
137 | return ACL_USER; | |
30a4f2a8 | 138 | if (!strncmp(s, "proto", 5)) |
7dd57fa2 | 139 | return ACL_PROTO; |
92a6f4b1 | 140 | if (!strcmp(s, "method")) |
141 | return ACL_METHOD; | |
d3416189 | 142 | if (!strcmp(s, "browser")) |
143 | return ACL_BROWSER; | |
7dd57fa2 | 144 | return ACL_NONE; |
145 | } | |
146 | ||
8203a132 | 147 | struct _acl * |
0ee4272b | 148 | aclFindByName(const char *name) |
7dd57fa2 | 149 | { |
1969665d | 150 | struct _acl *a; |
151 | for (a = AclList; a; a = a->next) | |
152 | if (!strcasecmp(a->name, name)) | |
153 | return a; | |
154 | return NULL; | |
7dd57fa2 | 155 | } |
156 | ||
157 | ||
fda94b88 | 158 | static void |
159 | aclParseIntlist(void *curlist) | |
7dd57fa2 | 160 | { |
fda94b88 | 161 | intlist **Tail; |
7dd57fa2 | 162 | intlist *q = NULL; |
163 | char *t = NULL; | |
fda94b88 | 164 | for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); |
c10aaf05 | 165 | while ((t = strtokFile())) { |
30a4f2a8 | 166 | q = xcalloc(1, sizeof(intlist)); |
7dd57fa2 | 167 | q->i = atoi(t); |
168 | *(Tail) = q; | |
169 | Tail = &q->next; | |
170 | } | |
7dd57fa2 | 171 | } |
172 | ||
fda94b88 | 173 | static void |
174 | aclParseProtoList(void *curlist) | |
7dd57fa2 | 175 | { |
fda94b88 | 176 | intlist **Tail; |
7dd57fa2 | 177 | intlist *q = NULL; |
178 | char *t = NULL; | |
fda94b88 | 179 | for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); |
c10aaf05 | 180 | while ((t = strtokFile())) { |
30a4f2a8 | 181 | q = xcalloc(1, sizeof(intlist)); |
92a6f4b1 | 182 | q->i = (int) urlParseProtocol(t); |
1969665d | 183 | *(Tail) = q; |
184 | Tail = &q->next; | |
7dd57fa2 | 185 | } |
7dd57fa2 | 186 | } |
92a6f4b1 | 187 | |
fda94b88 | 188 | static void |
189 | aclParseMethodList(void *curlist) | |
92a6f4b1 | 190 | { |
fda94b88 | 191 | intlist **Tail; |
92a6f4b1 | 192 | intlist *q = NULL; |
193 | char *t = NULL; | |
fda94b88 | 194 | for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); |
c10aaf05 | 195 | while ((t = strtokFile())) { |
30a4f2a8 | 196 | q = xcalloc(1, sizeof(intlist)); |
92a6f4b1 | 197 | q->i = (int) urlParseMethod(t); |
198 | *(Tail) = q; | |
199 | Tail = &q->next; | |
200 | } | |
92a6f4b1 | 201 | } |
202 | ||
30a4f2a8 | 203 | /* Decode a ascii representation (asc) of a IP adress, and place |
204 | * adress and netmask information in addr and mask. | |
205 | */ | |
8203a132 | 206 | static int |
0ee4272b | 207 | decode_addr(const char *asc, struct in_addr *addr, struct in_addr *mask) |
7dd57fa2 | 208 | { |
5ad764e2 | 209 | u_num32 a = 0; |
ef2d27ff | 210 | int a1 = 0, a2 = 0, a3 = 0, a4 = 0; |
5ad764e2 | 211 | struct hostent *hp = NULL; |
30a4f2a8 | 212 | |
213 | switch (sscanf(asc, "%d.%d.%d.%d", &a1, &a2, &a3, &a4)) { | |
214 | case 4: /* a dotted quad */ | |
451bf90b | 215 | if ((a = (u_num32) inet_addr(asc)) != inaddr_none || |
30a4f2a8 | 216 | !strcmp(asc, "255.255.255.255")) { |
217 | addr->s_addr = a; | |
218 | /* inet_addr() outputs in network byte order */ | |
219 | } | |
220 | break; | |
221 | case 1: /* a significant bits value for a mask */ | |
222 | if (a1 >= 0 && a1 < 33) { | |
ca98227c | 223 | addr->s_addr = a1 ? htonl(0xfffffffful << (32 - a1)) : 0; |
30a4f2a8 | 224 | break; |
225 | } | |
226 | default: | |
e668f67c | 227 | /* Note, must use plain gethostbyname() here because at startup |
8eb58c9c | 228 | * ipcache hasn't been initialized */ |
e668f67c | 229 | if ((hp = gethostbyname(asc)) != NULL) { |
230 | *addr = inaddrFromHostent(hp); | |
30a4f2a8 | 231 | } else { |
232 | /* XXX: Here we could use getnetbyname */ | |
e668f67c | 233 | debug(28, 0, "decode_addr: Invalid IP address or hostname '%s'\n", asc); |
30a4f2a8 | 234 | return 0; /* This is not valid address */ |
235 | } | |
236 | break; | |
237 | } | |
238 | ||
239 | if (mask != NULL) { /* mask == NULL if called to decode a netmask */ | |
240 | ||
241 | /* Guess netmask */ | |
ff8d0ea6 | 242 | a = (u_num32) ntohl(addr->s_addr); |
86ee2017 | 243 | if (!(a & 0xFFFFFFFFul)) |
244 | mask->s_addr = htonl(0x00000000ul); | |
30a4f2a8 | 245 | else if (!(a & 0x00FFFFFF)) |
86ee2017 | 246 | mask->s_addr = htonl(0xFF000000ul); |
30a4f2a8 | 247 | else if (!(a & 0x0000FFFF)) |
86ee2017 | 248 | mask->s_addr = htonl(0xFFFF0000ul); |
30a4f2a8 | 249 | else if (!(a & 0x000000FF)) |
86ee2017 | 250 | mask->s_addr = htonl(0xFFFFFF00ul); |
30a4f2a8 | 251 | else |
86ee2017 | 252 | mask->s_addr = htonl(0xFFFFFFFFul); |
30a4f2a8 | 253 | } |
254 | return 1; | |
255 | } | |
256 | ||
dfc52ac5 | 257 | static struct _acl_ip_data * |
258 | aclParseIpData(const char *t) | |
259 | { | |
260 | LOCAL_ARRAY(char, addr1, 256); | |
261 | LOCAL_ARRAY(char, addr2, 256); | |
262 | LOCAL_ARRAY(char, mask, 256); | |
263 | struct _acl_ip_data *q = xcalloc(1, sizeof(struct _acl_ip_data)); | |
264 | if (!strcasecmp(t, "all")) { | |
265 | q->addr1.s_addr = 0; | |
266 | q->addr2.s_addr = 0; | |
267 | q->mask.s_addr = 0; | |
268 | return q; | |
269 | } | |
dfc52ac5 | 270 | if (sscanf(t, "%[0-9.]-%[0-9.]/%[0-9.]", addr1, addr2, mask) == 3) { |
271 | (void) 0; | |
272 | } else if (sscanf(t, "%[0-9.]-%[0-9.]", addr1, addr2) == 2) { | |
273 | mask[0] = '\0'; | |
274 | } else if (sscanf(t, "%[0-9.]/%[0-9.]", addr1, mask) == 2) { | |
275 | addr2[0] = '\0'; | |
276 | } else if (sscanf(t, "%[0-9.]", addr1) == 1) { | |
277 | addr2[0] = '\0'; | |
278 | mask[0] = '\0'; | |
279 | } else if (sscanf(t, "%[^/]/%s", addr1, mask) == 2) { | |
280 | addr2[0] = '\0'; | |
281 | } else if (sscanf(t, "%s", addr1) == 1) { | |
282 | addr2[0] = '\0'; | |
283 | mask[0] = '\0'; | |
284 | } else { | |
fda94b88 | 285 | debug(28, 0, "aclParseIpData: Bad host/IP: '%s'\n", t); |
dfc52ac5 | 286 | safe_free(q); |
287 | return NULL; | |
288 | } | |
289 | /* Decode addr1 */ | |
290 | if (!decode_addr(addr1, &q->addr1, &q->mask)) { | |
291 | debug(28, 0, "%s line %d: %s\n", | |
292 | cfg_filename, config_lineno, config_input_line); | |
fda94b88 | 293 | debug(28, 0, "aclParseIpData: Ignoring invalid IP acl entry: unknown first address '%s'\n", addr1); |
dfc52ac5 | 294 | safe_free(q); |
295 | return NULL; | |
296 | } | |
297 | /* Decode addr2 */ | |
298 | if (*addr2 && !decode_addr(addr2, &q->addr2, &q->mask)) { | |
299 | debug(28, 0, "%s line %d: %s\n", | |
300 | cfg_filename, config_lineno, config_input_line); | |
fda94b88 | 301 | debug(28, 0, "aclParseIpData: Ignoring invalid IP acl entry: unknown second address '%s'\n", addr2); |
dfc52ac5 | 302 | safe_free(q); |
303 | return NULL; | |
304 | } | |
305 | /* Decode mask */ | |
306 | if (*mask && !decode_addr(mask, &q->mask, NULL)) { | |
307 | debug(28, 0, "%s line %d: %s\n", | |
308 | cfg_filename, config_lineno, config_input_line); | |
fda94b88 | 309 | debug(28, 0, "aclParseIpData: Ignoring invalid IP acl entry: unknown netmask '%s'\n", mask); |
dfc52ac5 | 310 | safe_free(q); |
311 | return NULL; | |
312 | } | |
313 | q->addr1.s_addr &= q->mask.s_addr; | |
314 | q->addr2.s_addr &= q->mask.s_addr; | |
315 | /* 1.2.3.4/255.255.255.0 --> 1.2.3.0 */ | |
316 | return q; | |
317 | } | |
30a4f2a8 | 318 | |
fda94b88 | 319 | static void |
320 | aclParseIpList(void *curlist) | |
30a4f2a8 | 321 | { |
cb0486c3 | 322 | char *t = NULL; |
b1ef1220 | 323 | struct _acl_ip_data **ip_data = curlist; |
7dd57fa2 | 324 | struct _acl_ip_data *q = NULL; |
c10aaf05 | 325 | while ((t = strtokFile())) { |
dfc52ac5 | 326 | if ((q = aclParseIpData(t)) == NULL) |
9e205701 | 327 | continue; |
b1ef1220 | 328 | *ip_data = aclSplayInsertIp(q->addr1, q->addr2, q->mask, *ip_data); |
329 | } | |
330 | ||
331 | } | |
332 | ||
333 | static struct _acl_ip_data * | |
334 | aclSplayInsertIp(struct in_addr addr1, struct in_addr addr2, struct in_addr mask, struct _acl_ip_data * t) | |
335 | { | |
336 | struct _acl_ip_data *new; | |
337 | ||
338 | new = xmalloc(sizeof(struct _acl_ip_data)); | |
339 | new->addr1 = addr1; | |
340 | new->addr2 = addr2; | |
341 | new->mask = mask; | |
342 | if (t == NULL) { | |
343 | new->left = new->right = NULL; | |
344 | return new; | |
345 | } | |
346 | t = aclSplayIp(addr1, t); | |
347 | if (addr1.s_addr < t->addr1.s_addr) { | |
348 | new->left = t->left; | |
349 | new->right = t; | |
350 | t->left = NULL; | |
351 | return new; | |
352 | } else if (addr1.s_addr > t->addr1.s_addr) { | |
353 | new->right = t->right; | |
354 | new->left = t; | |
355 | t->right = NULL; | |
356 | return new; | |
357 | } else { | |
358 | debug(28, 0, "aclSplayInsertIp: Address is already in the tree, is this going to be a problem?"); | |
359 | safe_free(new); | |
360 | return t; | |
361 | } | |
362 | } | |
363 | ||
364 | static struct _acl_ip_data * | |
365 | aclSplayIp(struct in_addr addr1, struct _acl_ip_data * t) | |
366 | { | |
367 | struct _acl_ip_data N, *l, *r, *y; | |
368 | if (t == NULL) | |
369 | return t; | |
370 | N.left = N.right = NULL; | |
371 | l = r = &N; | |
372 | ||
373 | for (;;) { | |
374 | if (addr1.s_addr < t->addr1.s_addr) { | |
375 | if (t->left == NULL) | |
376 | break; | |
377 | if (addr1.s_addr < t->left->addr1.s_addr) { | |
378 | y = t->left; /* rotate right */ | |
379 | t->left = y->right; | |
380 | y->right = t; | |
381 | t = y; | |
382 | if (t->left == NULL) | |
383 | break; | |
384 | } | |
385 | r->left = t; /* link right */ | |
386 | r = t; | |
387 | t = t->left; | |
388 | } else if (addr1.s_addr > t->addr1.s_addr) { | |
389 | if (t->right == NULL) | |
390 | break; | |
391 | if (addr1.s_addr > t->right->addr1.s_addr) { | |
392 | y = t->right; /* rotate left */ | |
393 | t->right = y->left; | |
394 | y->left = t; | |
395 | t = y; | |
396 | if (t->right == NULL) | |
397 | break; | |
398 | } | |
399 | l->right = t; /* link left */ | |
400 | l = t; | |
401 | t = t->right; | |
402 | } else { | |
403 | break; | |
404 | } | |
7dd57fa2 | 405 | } |
b1ef1220 | 406 | l->right = t->left; /* assemble */ |
407 | r->left = t->right; | |
408 | t->left = N.right; | |
409 | t->right = N.left; | |
410 | return t; | |
7dd57fa2 | 411 | } |
412 | ||
fda94b88 | 413 | static void |
414 | aclParseTimeSpec(void *curlist) | |
7dd57fa2 | 415 | { |
fda94b88 | 416 | struct _acl_time_data *q = NULL; |
417 | struct _acl_time_data **Tail; | |
92a6f4b1 | 418 | int h1, m1, h2, m2; |
419 | char *t = NULL; | |
fda94b88 | 420 | for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); |
421 | q = xcalloc(1, sizeof(struct _acl_time_data)); | |
c10aaf05 | 422 | while ((t = strtokFile())) { |
92a6f4b1 | 423 | if (*t < '0' || *t > '9') { |
424 | /* assume its day-of-week spec */ | |
425 | while (*t) { | |
426 | switch (*t++) { | |
427 | case 'S': | |
fda94b88 | 428 | q->weekbits |= ACL_SUNDAY; |
92a6f4b1 | 429 | break; |
430 | case 'M': | |
fda94b88 | 431 | q->weekbits |= ACL_MONDAY; |
92a6f4b1 | 432 | break; |
433 | case 'T': | |
fda94b88 | 434 | q->weekbits |= ACL_TUESDAY; |
92a6f4b1 | 435 | break; |
436 | case 'W': | |
fda94b88 | 437 | q->weekbits |= ACL_WEDNESDAY; |
92a6f4b1 | 438 | break; |
439 | case 'H': | |
fda94b88 | 440 | q->weekbits |= ACL_THURSDAY; |
92a6f4b1 | 441 | break; |
442 | case 'F': | |
fda94b88 | 443 | q->weekbits |= ACL_FRIDAY; |
92a6f4b1 | 444 | break; |
445 | case 'A': | |
fda94b88 | 446 | q->weekbits |= ACL_SATURDAY; |
92a6f4b1 | 447 | break; |
30a4f2a8 | 448 | case 'D': |
fda94b88 | 449 | q->weekbits |= ACL_WEEKDAYS; |
30a4f2a8 | 450 | break; |
92a6f4b1 | 451 | default: |
b8de7ebe | 452 | debug(28, 0, "%s line %d: %s\n", |
453 | cfg_filename, config_lineno, config_input_line); | |
92a6f4b1 | 454 | debug(28, 0, "aclParseTimeSpec: Bad Day '%c'\n", |
455 | *t); | |
456 | break; | |
457 | } | |
458 | } | |
459 | } else { | |
460 | /* assume its time-of-day spec */ | |
461 | if (sscanf(t, "%d:%d-%d:%d", &h1, &m1, &h2, &m2) < 4) { | |
b8de7ebe | 462 | debug(28, 0, "%s line %d: %s\n", |
463 | cfg_filename, config_lineno, config_input_line); | |
92a6f4b1 | 464 | debug(28, 0, "aclParseTimeSpec: Bad time range '%s'\n", |
465 | t); | |
fda94b88 | 466 | xfree(q); |
467 | return; | |
92a6f4b1 | 468 | } |
fda94b88 | 469 | q->start = h1 * 60 + m1; |
470 | q->stop = h2 * 60 + m2; | |
471 | if (q->start > q->stop) { | |
b8de7ebe | 472 | debug(28, 0, "%s line %d: %s\n", |
473 | cfg_filename, config_lineno, config_input_line); | |
92a6f4b1 | 474 | debug(28, 0, "aclParseTimeSpec: Reversed time range '%s'\n", |
475 | t); | |
fda94b88 | 476 | xfree(q); |
477 | return; | |
92a6f4b1 | 478 | } |
479 | } | |
480 | } | |
fda94b88 | 481 | if (q->start == 0 && q->stop == 0) |
482 | q->stop = 23 * 60 + 59; | |
483 | if (q->weekbits == 0) | |
484 | q->weekbits = ACL_ALLWEEK; | |
485 | *(Tail) = q; | |
486 | Tail = &q->next; | |
7dd57fa2 | 487 | } |
488 | ||
fda94b88 | 489 | void |
490 | aclParseRegexList(void *curlist, int icase) | |
7dd57fa2 | 491 | { |
fda94b88 | 492 | relist **Tail; |
7dd57fa2 | 493 | relist *q = NULL; |
494 | char *t = NULL; | |
1969665d | 495 | regex_t comp; |
008fcc7b | 496 | int errcode; |
497 | int flags = REG_EXTENDED | REG_NOSUB; | |
fda94b88 | 498 | for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); |
33cdd606 | 499 | if (icase) |
500 | flags |= REG_ICASE; | |
c10aaf05 | 501 | while ((t = strtokFile())) { |
008fcc7b | 502 | if ((errcode = regcomp(&comp, t, flags)) != 0) { |
503 | char errbuf[256]; | |
504 | regerror(errcode, &comp, errbuf, sizeof errbuf); | |
b8de7ebe | 505 | debug(28, 0, "%s line %d: %s\n", |
506 | cfg_filename, config_lineno, config_input_line); | |
008fcc7b | 507 | debug(28, 0, "aclParseRegexList: Invalid regular expression '%s': %s\n", |
508 | t, errbuf); | |
1969665d | 509 | continue; |
510 | } | |
30a4f2a8 | 511 | q = xcalloc(1, sizeof(relist)); |
1969665d | 512 | q->pattern = xstrdup(t); |
513 | q->regex = comp; | |
514 | *(Tail) = q; | |
515 | Tail = &q->next; | |
7dd57fa2 | 516 | } |
7dd57fa2 | 517 | } |
518 | ||
fda94b88 | 519 | static void |
520 | aclParseWordList(void *curlist) | |
7dd57fa2 | 521 | { |
fda94b88 | 522 | wordlist **Tail; |
7dd57fa2 | 523 | wordlist *q = NULL; |
524 | char *t = NULL; | |
fda94b88 | 525 | for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); |
c10aaf05 | 526 | while ((t = strtokFile())) { |
30a4f2a8 | 527 | q = xcalloc(1, sizeof(wordlist)); |
7dd57fa2 | 528 | q->key = xstrdup(t); |
1969665d | 529 | *(Tail) = q; |
530 | Tail = &q->next; | |
7dd57fa2 | 531 | } |
7dd57fa2 | 532 | } |
533 | ||
fda94b88 | 534 | |
535 | static void | |
536 | aclParseDomainList(void *curlist) | |
f88bb09c | 537 | { |
fda94b88 | 538 | wordlist **Tail; |
f88bb09c | 539 | wordlist *q = NULL; |
540 | char *t = NULL; | |
fda94b88 | 541 | for (Tail = curlist; *Tail; Tail = &((*Tail)->next)); |
c10aaf05 | 542 | while ((t = strtokFile())) { |
f88bb09c | 543 | Tolower(t); |
544 | q = xcalloc(1, sizeof(wordlist)); | |
545 | q->key = xstrdup(t); | |
546 | *(Tail) = q; | |
547 | Tail = &q->next; | |
548 | } | |
f88bb09c | 549 | } |
7dd57fa2 | 550 | |
551 | ||
8203a132 | 552 | void |
0673c0ba | 553 | aclParseAclLine(void) |
7dd57fa2 | 554 | { |
555 | /* we're already using strtok() to grok the line */ | |
556 | char *t = NULL; | |
557 | struct _acl *A = NULL; | |
fda94b88 | 558 | LOCAL_ARRAY(char, aclname, ACL_NAME_SZ); |
559 | squid_acl acltype; | |
7dd57fa2 | 560 | |
7dd57fa2 | 561 | /* snarf the ACL name */ |
562 | if ((t = strtok(NULL, w_space)) == NULL) { | |
b8de7ebe | 563 | debug(28, 0, "%s line %d: %s\n", |
564 | cfg_filename, config_lineno, config_input_line); | |
92a6f4b1 | 565 | debug(28, 0, "aclParseAclLine: missing ACL name.\n"); |
92a6f4b1 | 566 | return; |
567 | } | |
fda94b88 | 568 | xstrncpy(aclname, t, ACL_NAME_SZ); |
569 | /* snarf the ACL type */ | |
570 | if ((t = strtok(NULL, w_space)) == NULL) { | |
b8de7ebe | 571 | debug(28, 0, "%s line %d: %s\n", |
572 | cfg_filename, config_lineno, config_input_line); | |
fda94b88 | 573 | debug(28, 0, "aclParseAclLine: missing ACL type.\n"); |
7dd57fa2 | 574 | return; |
575 | } | |
fda94b88 | 576 | if ((acltype = aclType(t)) == ACL_NONE) { |
b8de7ebe | 577 | debug(28, 0, "%s line %d: %s\n", |
578 | cfg_filename, config_lineno, config_input_line); | |
fda94b88 | 579 | debug(28, 0, "aclParseAclLine: Invalid ACL type '%s'\n", t); |
7dd57fa2 | 580 | return; |
581 | } | |
9963e5a3 | 582 | if ((A = aclFindByName(aclname)) == NULL) { |
b1ef1220 | 583 | debug(28, 3, "aclParseAclLine: Creating ACL '%s'\n", aclname); |
52cd89fd | 584 | A = xcalloc(1, sizeof(struct _acl)); |
fda94b88 | 585 | xstrncpy(A->name, aclname, ACL_NAME_SZ); |
586 | A->type = acltype; | |
52cd89fd | 587 | A->cfgline = xstrdup(config_input_line); |
588 | *AclListTail = A; | |
589 | AclListTail = &A->next; | |
fda94b88 | 590 | } else { |
52cd89fd | 591 | if (acltype != A->type) { |
fda94b88 | 592 | debug(28, 0, "aclParseAclLine: ACL '%s' already exists with different type, skipping.\n", A->name); |
593 | return; | |
594 | } | |
9963e5a3 | 595 | debug(28, 3, "aclParseAclLine: Appending to '%s'\n", aclname); |
fda94b88 | 596 | } |
597 | switch (A->type) { | |
7dd57fa2 | 598 | case ACL_SRC_IP: |
30a4f2a8 | 599 | case ACL_DST_IP: |
fda94b88 | 600 | aclParseIpList(&(A->data)); |
7dd57fa2 | 601 | break; |
f88bb09c | 602 | case ACL_SRC_DOMAIN: |
7dd57fa2 | 603 | case ACL_DST_DOMAIN: |
fda94b88 | 604 | aclParseDomainList(&A->data); |
7dd57fa2 | 605 | break; |
606 | case ACL_TIME: | |
fda94b88 | 607 | aclParseTimeSpec(&A->data); |
7dd57fa2 | 608 | break; |
609 | case ACL_URL_REGEX: | |
6e40f263 | 610 | case ACL_URLPATH_REGEX: |
fda94b88 | 611 | aclParseRegexList(&A->data, 0); |
7dd57fa2 | 612 | break; |
613 | case ACL_URL_PORT: | |
fda94b88 | 614 | aclParseIntlist(&A->data); |
7dd57fa2 | 615 | break; |
616 | case ACL_USER: | |
94103840 | 617 | Config.identLookup = 1; |
fda94b88 | 618 | aclParseWordList(&A->data); |
7dd57fa2 | 619 | break; |
620 | case ACL_PROTO: | |
fda94b88 | 621 | aclParseProtoList(&A->data); |
7dd57fa2 | 622 | break; |
92a6f4b1 | 623 | case ACL_METHOD: |
fda94b88 | 624 | aclParseMethodList(&A->data); |
92a6f4b1 | 625 | break; |
d3416189 | 626 | case ACL_BROWSER: |
fda94b88 | 627 | aclParseRegexList(&A->data, 0); |
d3416189 | 628 | break; |
7dd57fa2 | 629 | case ACL_NONE: |
630 | default: | |
fda94b88 | 631 | debug_trap("Bad ACL type"); |
632 | break; | |
7dd57fa2 | 633 | } |
7dd57fa2 | 634 | } |
635 | ||
e92d33a5 | 636 | /* maex@space.net (06.09.96) |
5e79098a | 637 | * get (if any) the URL from deny_info for a certain acl |
e92d33a5 | 638 | */ |
8203a132 | 639 | char * |
0ee4272b | 640 | aclGetDenyInfoUrl(struct _acl_deny_info_list **head, const char *name) |
e92d33a5 | 641 | { |
642 | struct _acl_deny_info_list *A = NULL; | |
643 | struct _acl_name_list *L = NULL; | |
644 | ||
645 | A = *head; | |
646 | if (NULL == *head) /* empty list */ | |
647 | return (NULL); | |
648 | while (A) { | |
649 | L = A->acl_list; | |
650 | if (NULL == L) /* empty list should never happen, but in case */ | |
651 | continue; | |
652 | while (L) { | |
653 | if (!strcmp(name, L->name)) | |
654 | return (A->url); | |
655 | L = L->next; | |
656 | } | |
657 | A = A->next; | |
658 | } | |
659 | return (NULL); | |
660 | } | |
661 | /* maex@space.net (05.09.96) | |
5e79098a | 662 | * get the info for redirecting "access denied" to info pages |
663 | * TODO (probably ;-) | |
664 | * currently there is no optimization for | |
665 | * - more than one deny_info line with the same url | |
666 | * - a check, whether the given acl really is defined | |
667 | * - a check, whether an acl is added more than once for the same url | |
e92d33a5 | 668 | */ |
8203a132 | 669 | void |
670 | aclParseDenyInfoLine(struct _acl_deny_info_list **head) | |
e92d33a5 | 671 | { |
672 | char *t = NULL; | |
673 | struct _acl_deny_info_list *A = NULL; | |
674 | struct _acl_deny_info_list *B = NULL; | |
675 | struct _acl_deny_info_list **T = NULL; | |
676 | struct _acl_name_list *L = NULL; | |
677 | struct _acl_name_list **Tail = NULL; | |
678 | ||
679 | /* first expect an url */ | |
680 | if ((t = strtok(NULL, w_space)) == NULL) { | |
681 | debug(28, 0, "%s line %d: %s\n", | |
682 | cfg_filename, config_lineno, config_input_line); | |
683 | debug(28, 0, "aclParseDenyInfoLine: missing 'url' parameter.\n"); | |
684 | return; | |
685 | } | |
686 | A = xcalloc(1, sizeof(struct _acl_deny_info_list)); | |
d5aa0e3b | 687 | xstrncpy(A->url, t, MAX_URL); |
e92d33a5 | 688 | A->next = (struct _acl_deny_info_list *) NULL; |
689 | /* next expect a list of ACL names */ | |
690 | Tail = &A->acl_list; | |
691 | while ((t = strtok(NULL, w_space))) { | |
692 | L = xcalloc(1, sizeof(struct _acl_name_list)); | |
d5aa0e3b | 693 | xstrncpy(L->name, t, ACL_NAME_SZ); |
e92d33a5 | 694 | *Tail = L; |
695 | Tail = &L->next; | |
696 | } | |
697 | if (A->acl_list == NULL) { | |
698 | debug(28, 0, "%s line %d: %s\n", | |
699 | cfg_filename, config_lineno, config_input_line); | |
700 | debug(28, 0, "aclParseDenyInfoLine: deny_info line contains no ACL's, skipping\n"); | |
701 | xfree(A); | |
702 | return; | |
703 | } | |
704 | for (B = *head, T = head; B; T = &B->next, B = B->next); /* find the tail */ | |
705 | *T = A; | |
706 | } | |
707 | ||
8203a132 | 708 | void |
709 | aclParseAccessLine(struct _acl_access **head) | |
7dd57fa2 | 710 | { |
711 | char *t = NULL; | |
712 | struct _acl_access *A = NULL; | |
92a6f4b1 | 713 | struct _acl_access *B = NULL; |
714 | struct _acl_access **T = NULL; | |
7dd57fa2 | 715 | struct _acl_list *L = NULL; |
8213067d | 716 | struct _acl_list **Tail = NULL; |
7dd57fa2 | 717 | struct _acl *a = NULL; |
718 | ||
719 | /* first expect either 'allow' or 'deny' */ | |
720 | if ((t = strtok(NULL, w_space)) == NULL) { | |
b8de7ebe | 721 | debug(28, 0, "%s line %d: %s\n", |
722 | cfg_filename, config_lineno, config_input_line); | |
92a6f4b1 | 723 | debug(28, 0, "aclParseAccessLine: missing 'allow' or 'deny'.\n"); |
7dd57fa2 | 724 | return; |
725 | } | |
30a4f2a8 | 726 | A = xcalloc(1, sizeof(struct _acl_access)); |
7dd57fa2 | 727 | if (!strcmp(t, "allow")) |
728 | A->allow = 1; | |
729 | else if (!strcmp(t, "deny")) | |
730 | A->allow = 0; | |
731 | else { | |
b8de7ebe | 732 | debug(28, 0, "%s line %d: %s\n", |
733 | cfg_filename, config_lineno, config_input_line); | |
92a6f4b1 | 734 | debug(28, 0, "aclParseAccessLine: expecting 'allow' or 'deny', got '%s'.\n", t); |
7dd57fa2 | 735 | xfree(A); |
736 | return; | |
737 | } | |
738 | ||
739 | /* next expect a list of ACL names, possibly preceeded | |
740 | * by '!' for negation */ | |
8213067d | 741 | Tail = &A->acl_list; |
7dd57fa2 | 742 | while ((t = strtok(NULL, w_space))) { |
30a4f2a8 | 743 | L = xcalloc(1, sizeof(struct _acl_list)); |
1969665d | 744 | L->op = 1; /* defaults to non-negated */ |
7dd57fa2 | 745 | if (*t == '!') { |
1969665d | 746 | /* negated ACL */ |
747 | L->op = 0; | |
748 | t++; | |
7dd57fa2 | 749 | } |
b954a582 | 750 | debug(28, 3, "aclParseAccessLine: looking for ACL name '%s'\n", t); |
7dd57fa2 | 751 | a = aclFindByName(t); |
752 | if (a == NULL) { | |
b8de7ebe | 753 | debug(28, 0, "%s line %d: %s\n", |
754 | cfg_filename, config_lineno, config_input_line); | |
837dcbb9 | 755 | debug(28, 0, "aclParseAccessLine: ACL name '%s' not found.\n", t); |
1969665d | 756 | xfree(L); |
757 | continue; | |
7dd57fa2 | 758 | } |
759 | L->acl = a; | |
760 | *Tail = L; | |
761 | Tail = &L->next; | |
762 | } | |
837dcbb9 | 763 | if (A->acl_list == NULL) { |
b8de7ebe | 764 | debug(28, 0, "%s line %d: %s\n", |
765 | cfg_filename, config_lineno, config_input_line); | |
89b37f2a | 766 | debug(28, 0, "aclParseAccessLine: Access line contains no ACL's, skipping\n"); |
837dcbb9 | 767 | xfree(A); |
768 | return; | |
769 | } | |
3003c0f3 | 770 | A->cfgline = xstrdup(config_input_line); |
540830c4 | 771 | for (B = *head, T = head; B; T = &B->next, B = B->next); /* find the tail */ |
92a6f4b1 | 772 | *T = A; |
7dd57fa2 | 773 | } |
774 | ||
8203a132 | 775 | static int |
b1ef1220 | 776 | aclMatchIp(struct _acl_ip_data * data, struct in_addr c) |
abf6b4de | 777 | { |
778 | struct in_addr h; | |
30a4f2a8 | 779 | unsigned long lh, la1, la2; |
b1ef1220 | 780 | struct _acl_ip_data *root; |
30a4f2a8 | 781 | |
b1ef1220 | 782 | h.s_addr = c.s_addr & data->mask.s_addr; |
783 | debug(28, 3, "aclMatchIp: h = %s\n", inet_ntoa(h)); | |
784 | debug(28, 3, "aclMatchIp: addr1 = %s\n", inet_ntoa(data->addr1)); | |
785 | debug(28, 3, "aclMatchIp: addr2 = %s\n", inet_ntoa(data->addr2)); | |
786 | root = aclSplayIp(h, data); | |
787 | if (h.s_addr == root->addr1.s_addr) { | |
30a4f2a8 | 788 | if (!data->addr2.s_addr) { |
b1ef1220 | 789 | debug(28, 3, "aclMatchIp: returning 1\n"); |
790 | return 1; | |
30a4f2a8 | 791 | } else { |
792 | /* This is a range check */ | |
793 | lh = ntohl(h.s_addr); | |
794 | la1 = ntohl(data->addr1.s_addr); | |
795 | la2 = ntohl(data->addr2.s_addr); | |
796 | if (lh >= la1 && lh <= la2) { | |
797 | debug(28, 3, "aclMatchIp: returning 1\n"); | |
798 | return 1; | |
799 | } | |
837dcbb9 | 800 | } |
abf6b4de | 801 | } |
b954a582 | 802 | debug(28, 3, "aclMatchIp: returning 0\n"); |
abf6b4de | 803 | return 0; |
804 | } | |
805 | ||
8203a132 | 806 | static int |
fe4e214f | 807 | aclMatchDomainList(wordlist * data, const char *host) |
f88bb09c | 808 | { |
c10aaf05 | 809 | wordlist *first, *prev; |
810 | ||
f88bb09c | 811 | if (host == NULL) |
812 | return 0; | |
813 | debug(28, 3, "aclMatchDomainList: checking '%s'\n", host); | |
c10aaf05 | 814 | first = data; |
815 | prev = NULL; | |
f88bb09c | 816 | for (; data; data = data->next) { |
817 | debug(28, 3, "aclMatchDomainList: looking for '%s'\n", data->key); | |
c10aaf05 | 818 | if (matchDomainName(data->key, host)) { |
819 | if (prev != NULL) { | |
820 | /* shift the element just found to the second position | |
e5f6c5c2 | 821 | * in the list */ |
c10aaf05 | 822 | prev->next = data->next; |
823 | data->next = first->next; | |
824 | first->next = data; | |
825 | } | |
f88bb09c | 826 | return 1; |
e5f6c5c2 | 827 | } |
c10aaf05 | 828 | prev = data; |
f88bb09c | 829 | } |
830 | return 0; | |
831 | } | |
30a4f2a8 | 832 | |
33cdd606 | 833 | int |
0ee4272b | 834 | aclMatchRegex(relist * data, const char *word) |
abf6b4de | 835 | { |
c10aaf05 | 836 | relist *first, *prev; |
234967c9 | 837 | if (word == NULL) |
838 | return 0; | |
b954a582 | 839 | debug(28, 3, "aclMatchRegex: checking '%s'\n", word); |
c10aaf05 | 840 | first = data; |
841 | prev = NULL; | |
abf6b4de | 842 | while (data) { |
b954a582 | 843 | debug(28, 3, "aclMatchRegex: looking for '%s'\n", data->pattern); |
c10aaf05 | 844 | if (regexec(&data->regex, word, 0, 0, 0) == 0) { |
845 | if (prev != NULL) { | |
846 | /* shift the element just found to the second position | |
e5f6c5c2 | 847 | * in the list */ |
c10aaf05 | 848 | prev->next = data->next; |
849 | data->next = first->next; | |
850 | first->next = data; | |
851 | } | |
abf6b4de | 852 | return 1; |
c10aaf05 | 853 | } |
854 | prev = data; | |
abf6b4de | 855 | data = data->next; |
856 | } | |
857 | return 0; | |
858 | } | |
30a4f2a8 | 859 | |
94103840 | 860 | static int |
861 | aclMatchIdent(wordlist * data, const char *ident) | |
862 | { | |
863 | if (ident == NULL) | |
864 | return 0; | |
865 | debug(28, 3, "aclMatchIdent: checking '%s'\n", ident); | |
866 | while (data) { | |
867 | debug(28, 3, "aclMatchIdent: looking for '%s'\n", data->key); | |
868 | if (strcmp(data->key, "REQUIRED") == 0 && *ident != '\0') | |
869 | return 1; | |
870 | if (strcmp(data->key, ident) == 0) | |
871 | return 1; | |
872 | data = data->next; | |
873 | } | |
874 | return 0; | |
875 | } | |
876 | ||
8203a132 | 877 | static int |
878 | aclMatchInteger(intlist * data, int i) | |
abf6b4de | 879 | { |
c10aaf05 | 880 | intlist *first, *prev; |
881 | first = data; | |
882 | prev = NULL; | |
abf6b4de | 883 | while (data) { |
c10aaf05 | 884 | if (data->i == i) { |
885 | if (prev != NULL) { | |
886 | /* shift the element just found to the second position | |
e5f6c5c2 | 887 | * in the list */ |
c10aaf05 | 888 | prev->next = data->next; |
889 | data->next = first->next; | |
890 | first->next = data; | |
891 | } | |
abf6b4de | 892 | return 1; |
c10aaf05 | 893 | } |
894 | prev = data; | |
abf6b4de | 895 | data = data->next; |
896 | } | |
897 | return 0; | |
898 | } | |
899 | ||
8203a132 | 900 | static int |
901 | aclMatchTime(struct _acl_time_data *data, time_t when) | |
92a6f4b1 | 902 | { |
540830c4 | 903 | static time_t last_when = 0; |
904 | static struct tm tm; | |
905 | time_t t; | |
92a6f4b1 | 906 | |
540830c4 | 907 | if (when != last_when) { |
908 | last_when = when; | |
30a4f2a8 | 909 | xmemcpy(&tm, localtime(&when), sizeof(struct tm)); |
540830c4 | 910 | } |
540830c4 | 911 | t = (time_t) (tm.tm_hour * 60 + tm.tm_min); |
9bf12439 | 912 | debug(28, 3, "aclMatchTime: checking %d in %d-%d, weekbits=%x\n", |
913 | (int) t, (int) data->start, (int) data->stop, data->weekbits); | |
914 | ||
540830c4 | 915 | if (t < data->start || t > data->stop) |
916 | return 0; | |
234967c9 | 917 | return data->weekbits & (1 << tm.tm_wday) ? 1 : 0; |
92a6f4b1 | 918 | } |
919 | ||
8203a132 | 920 | int |
921 | aclMatchAcl(struct _acl *acl, aclCheck_t * checklist) | |
1969665d | 922 | { |
0ee4272b | 923 | const request_t *r = checklist->request; |
924 | const ipcache_addrs *ia = NULL; | |
925 | const char *fqdn = NULL; | |
30a4f2a8 | 926 | int k; |
1969665d | 927 | if (!acl) |
928 | return 0; | |
b954a582 | 929 | debug(28, 3, "aclMatchAcl: checking '%s'\n", acl->cfgline); |
1969665d | 930 | switch (acl->type) { |
931 | case ACL_SRC_IP: | |
99d829f9 | 932 | return aclMatchIp(acl->data, checklist->src_addr); |
983061ed | 933 | /* NOTREACHED */ |
30a4f2a8 | 934 | case ACL_DST_IP: |
e5f6c5c2 | 935 | ia = ipcache_gethostbyname(r->host, IP_LOOKUP_IF_MISS); |
936 | if (ia) { | |
937 | for (k = 0; k < (int) ia->count; k++) { | |
938 | checklist->dst_addr = ia->in_addrs[k]; | |
665d36de | 939 | if (aclMatchIp(acl->data, checklist->dst_addr)) |
940 | return 1; | |
941 | } | |
942 | return 0; | |
943 | } else if (checklist->state[ACL_DST_IP] == ACL_LOOKUP_NONE) { | |
30a4f2a8 | 944 | debug(28, 3, "aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", |
99d829f9 | 945 | acl->name, r->host); |
665d36de | 946 | checklist->state[ACL_DST_IP] = ACL_LOOKUP_NEED; |
f88bb09c | 947 | return 0; |
665d36de | 948 | } else { |
949 | return aclMatchIp(acl->data, no_addr); | |
30a4f2a8 | 950 | } |
30a4f2a8 | 951 | /* NOTREACHED */ |
1969665d | 952 | case ACL_DST_DOMAIN: |
4d650936 | 953 | if ((ia = ipcacheCheckNumeric(r->host)) == NULL) |
954 | return aclMatchDomainList(acl->data, r->host); | |
955 | fqdn = fqdncache_gethostbyaddr(ia->in_addrs[0], FQDN_LOOKUP_IF_MISS); | |
956 | if (fqdn) | |
957 | return aclMatchDomainList(acl->data, fqdn); | |
958 | if (checklist->state[ACL_DST_DOMAIN] == ACL_LOOKUP_NONE) { | |
959 | debug(28, 3, "aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", | |
960 | acl->name, inet_ntoa(ia->in_addrs[0])); | |
961 | checklist->state[ACL_DST_DOMAIN] = ACL_LOOKUP_NEED; | |
962 | return 0; | |
963 | } | |
964 | return aclMatchDomainList(acl->data, "none"); | |
f88bb09c | 965 | /* NOTREACHED */ |
966 | case ACL_SRC_DOMAIN: | |
967 | fqdn = fqdncache_gethostbyaddr(checklist->src_addr, FQDN_LOOKUP_IF_MISS); | |
665d36de | 968 | if (fqdn) { |
969 | return aclMatchDomainList(acl->data, fqdn); | |
970 | } else if (checklist->state[ACL_SRC_DOMAIN] == ACL_LOOKUP_NONE) { | |
f88bb09c | 971 | debug(28, 3, "aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n", |
972 | acl->name, inet_ntoa(checklist->src_addr)); | |
665d36de | 973 | checklist->state[ACL_SRC_DOMAIN] = ACL_LOOKUP_NEED; |
f88bb09c | 974 | return 0; |
665d36de | 975 | } else { |
9d48b9aa | 976 | return aclMatchDomainList(acl->data, "none"); |
f88bb09c | 977 | } |
983061ed | 978 | /* NOTREACHED */ |
1969665d | 979 | case ACL_TIME: |
b8de7ebe | 980 | return aclMatchTime(acl->data, squid_curtime); |
983061ed | 981 | /* NOTREACHED */ |
6e40f263 | 982 | case ACL_URLPATH_REGEX: |
99d829f9 | 983 | return aclMatchRegex(acl->data, r->urlpath); |
983061ed | 984 | /* NOTREACHED */ |
6e40f263 | 985 | case ACL_URL_REGEX: |
986 | return aclMatchRegex(acl->data, urlCanonical(r, NULL)); | |
987 | /* NOTREACHED */ | |
1969665d | 988 | case ACL_URL_PORT: |
99d829f9 | 989 | return aclMatchInteger(acl->data, r->port); |
983061ed | 990 | /* NOTREACHED */ |
1969665d | 991 | case ACL_USER: |
94103840 | 992 | /* debug(28, 0, "aclMatchAcl: ACL_USER unimplemented\n"); */ |
993 | /* return 0; */ | |
994 | return aclMatchIdent(acl->data, checklist->ident); | |
983061ed | 995 | /* NOTREACHED */ |
1969665d | 996 | case ACL_PROTO: |
99d829f9 | 997 | return aclMatchInteger(acl->data, r->protocol); |
983061ed | 998 | /* NOTREACHED */ |
92a6f4b1 | 999 | case ACL_METHOD: |
99d829f9 | 1000 | return aclMatchInteger(acl->data, r->method); |
983061ed | 1001 | /* NOTREACHED */ |
d3416189 | 1002 | case ACL_BROWSER: |
1003 | return aclMatchRegex(acl->data, checklist->browser); | |
1004 | /* NOTREACHED */ | |
1969665d | 1005 | case ACL_NONE: |
1006 | default: | |
1007 | debug(28, 0, "aclMatchAcl: '%s' has bad type %d\n", | |
1008 | acl->name, acl->type); | |
1009 | return 0; | |
1010 | } | |
30a4f2a8 | 1011 | /* NOTREACHED */ |
1969665d | 1012 | } |
1013 | ||
8203a132 | 1014 | static int |
fe4e214f | 1015 | aclMatchAclList(const struct _acl_list *list, aclCheck_t * checklist) |
1969665d | 1016 | { |
1969665d | 1017 | while (list) { |
e92d33a5 | 1018 | AclMatchedName = list->acl->name; |
f88bb09c | 1019 | debug(28, 3, "aclMatchAclList: checking %s%s\n", |
ffa8aa23 | 1020 | list->op ? null_string : "!", list->acl->name); |
99d829f9 | 1021 | if (aclMatchAcl(list->acl, checklist) != list->op) { |
b954a582 | 1022 | debug(28, 3, "aclMatchAclList: returning 0\n"); |
abf6b4de | 1023 | return 0; |
837dcbb9 | 1024 | } |
abf6b4de | 1025 | list = list->next; |
1969665d | 1026 | } |
b954a582 | 1027 | debug(28, 3, "aclMatchAclList: returning 1\n"); |
1969665d | 1028 | return 1; |
1029 | } | |
1030 | ||
8203a132 | 1031 | int |
fe4e214f | 1032 | aclCheck(const struct _acl_access *A, aclCheck_t * checklist) |
1969665d | 1033 | { |
1969665d | 1034 | int allow = 0; |
7dd57fa2 | 1035 | |
92a6f4b1 | 1036 | while (A) { |
b954a582 | 1037 | debug(28, 3, "aclCheck: checking '%s'\n", A->cfgline); |
1969665d | 1038 | allow = A->allow; |
99d829f9 | 1039 | if (aclMatchAclList(A->acl_list, checklist)) { |
b954a582 | 1040 | debug(28, 3, "aclCheck: match found, returning %d\n", allow); |
1969665d | 1041 | return allow; |
8213067d | 1042 | } |
92a6f4b1 | 1043 | A = A->next; |
7dd57fa2 | 1044 | } |
1969665d | 1045 | return !allow; |
1046 | } | |
92a6f4b1 | 1047 | |
8203a132 | 1048 | static void |
b1ef1220 | 1049 | aclDestroyIpList(struct _acl_ip_data * data) |
92a6f4b1 | 1050 | { |
b1ef1220 | 1051 | if (data == NULL) |
1052 | return; | |
1053 | aclDestroyIpList(data->left); | |
1054 | aclDestroyIpList(data->right); | |
1055 | safe_free(data); | |
92a6f4b1 | 1056 | } |
1057 | ||
8203a132 | 1058 | static void |
1059 | aclDestroyTimeList(struct _acl_time_data *data) | |
92a6f4b1 | 1060 | { |
06c55413 | 1061 | struct _acl_time_data *next = NULL; |
540830c4 | 1062 | for (; data; data = next) { |
1063 | next = data->next; | |
1064 | safe_free(data); | |
1065 | } | |
92a6f4b1 | 1066 | } |
1067 | ||
33cdd606 | 1068 | void |
8203a132 | 1069 | aclDestroyRegexList(struct _relist *data) |
92a6f4b1 | 1070 | { |
06c55413 | 1071 | struct _relist *next = NULL; |
540830c4 | 1072 | for (; data; data = next) { |
1073 | next = data->next; | |
1074 | regfree(&data->regex); | |
1075 | safe_free(data->pattern); | |
1076 | safe_free(data); | |
1077 | } | |
92a6f4b1 | 1078 | } |
1079 | ||
8203a132 | 1080 | void |
0673c0ba | 1081 | aclDestroyAcls(void) |
540830c4 | 1082 | { |
1083 | struct _acl *a = NULL; | |
1084 | struct _acl *next = NULL; | |
1085 | for (a = AclList; a; a = next) { | |
1086 | next = a->next; | |
b954a582 | 1087 | debug(28, 3, "aclDestroyAcls: '%s'\n", a->cfgline); |
540830c4 | 1088 | switch (a->type) { |
1089 | case ACL_SRC_IP: | |
30a4f2a8 | 1090 | case ACL_DST_IP: |
540830c4 | 1091 | aclDestroyIpList(a->data); |
1092 | break; | |
1093 | case ACL_DST_DOMAIN: | |
c20e73a0 | 1094 | case ACL_SRC_DOMAIN: |
540830c4 | 1095 | case ACL_USER: |
1096 | wordlistDestroy((wordlist **) & a->data); | |
1097 | break; | |
1098 | case ACL_TIME: | |
1099 | aclDestroyTimeList(a->data); | |
1100 | break; | |
1101 | case ACL_URL_REGEX: | |
6e40f263 | 1102 | case ACL_URLPATH_REGEX: |
d3416189 | 1103 | case ACL_BROWSER: |
540830c4 | 1104 | aclDestroyRegexList(a->data); |
1105 | break; | |
1106 | case ACL_URL_PORT: | |
1107 | case ACL_PROTO: | |
1108 | case ACL_METHOD: | |
1109 | intlistDestroy((intlist **) & a->data); | |
1110 | break; | |
1111 | case ACL_NONE: | |
1112 | default: | |
1113 | fatal_dump("aclDestroyAcls: Found ACL_NONE?"); | |
1114 | break; | |
92a6f4b1 | 1115 | } |
540830c4 | 1116 | safe_free(a->cfgline); |
1117 | safe_free(a); | |
1118 | } | |
1119 | AclList = NULL; | |
1120 | AclListTail = &AclList; | |
92a6f4b1 | 1121 | } |
1122 | ||
8203a132 | 1123 | static void |
1124 | aclDestroyAclList(struct _acl_list *list) | |
92a6f4b1 | 1125 | { |
540830c4 | 1126 | struct _acl_list *next = NULL; |
1127 | for (; list; list = next) { | |
1128 | next = list->next; | |
1129 | safe_free(list); | |
1130 | } | |
92a6f4b1 | 1131 | } |
1132 | ||
8203a132 | 1133 | void |
1134 | aclDestroyAccessList(struct _acl_access **list) | |
92a6f4b1 | 1135 | { |
540830c4 | 1136 | struct _acl_access *l = NULL; |
1137 | struct _acl_access *next = NULL; | |
1138 | for (l = *list; l; l = next) { | |
b954a582 | 1139 | debug(28, 3, "aclDestroyAccessList: '%s'\n", l->cfgline); |
540830c4 | 1140 | next = l->next; |
1141 | aclDestroyAclList(l->acl_list); | |
1142 | l->acl_list = NULL; | |
1143 | safe_free(l->cfgline); | |
1144 | safe_free(l); | |
1145 | } | |
1146 | *list = NULL; | |
92a6f4b1 | 1147 | } |
e92d33a5 | 1148 | |
1149 | /* maex@space.net (06.09.1996) | |
f4296e99 | 1150 | * destroy an _acl_deny_info_list */ |
8203a132 | 1151 | void |
1152 | aclDestroyDenyInfoList(struct _acl_deny_info_list **list) | |
e92d33a5 | 1153 | { |
1154 | struct _acl_deny_info_list *a = NULL; | |
1155 | struct _acl_deny_info_list *a_next = NULL; | |
1156 | struct _acl_name_list *l = NULL; | |
1157 | struct _acl_name_list *l_next = NULL; | |
1158 | ||
1159 | for (a = *list; a; a = a_next) { | |
1160 | for (l = a->acl_list; l; l = l_next) { | |
1161 | l_next = l->next; | |
1162 | safe_free(l); | |
1163 | } | |
1164 | a_next = a->next; | |
1165 | safe_free(a); | |
1166 | } | |
f4296e99 | 1167 | *list = NULL; |
e92d33a5 | 1168 | } |