acl.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:62k
源码类别:

代理服务器

开发平台:

Unix_Linux

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